Added PEP 369 and PEP 370
This commit is contained in:
parent
f4064feec0
commit
da08263556
|
@ -94,6 +94,8 @@ Index by Category
|
|||
S 364 Transitioning to the Py3K Standard Library Warsaw
|
||||
S 365 Adding the pkg_resources module Eby
|
||||
S 368 Standard image protocol and class Mastrodomenico
|
||||
S 369 Post import hooks Heimes
|
||||
S 370 Per user site-packages directory Heimes
|
||||
S 3108 Standard Library Reorganization Cannon
|
||||
S 3134 Exception Chaining and Embedded Tracebacks Yee
|
||||
S 3135 New Super Spealman, Delaney
|
||||
|
@ -467,6 +469,8 @@ Numerical Index
|
|||
SF 366 Main module explicit relative imports Coghlan
|
||||
SR 367 New Super Spealman, Delaney
|
||||
S 368 Standard image protocol and class Mastrodomenico
|
||||
S 369 Post import hooks Heimes
|
||||
S 370 Per user site-packages directory Heimes
|
||||
SR 666 Reject Foolish Indentation Creighton
|
||||
SR 754 IEEE 754 Floating Point Special Values Warnes
|
||||
P 3000 Python 3000 GvR
|
||||
|
@ -571,6 +575,7 @@ Owners
|
|||
Griffin, Grant g2@iowegian.com
|
||||
Hammond, Mark mhammond@skippinet.com.au
|
||||
Harris, Peter scav@blueyonder.co.uk
|
||||
Heimes, Christian christian@cheimes.de
|
||||
Heller, Thomas theller@python.net
|
||||
Hetland, Magnus Lie magnus@hetland.org
|
||||
Hettinger, Raymond python@rcn.com
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
PEP: 369
|
||||
Title: Post import hooks
|
||||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: Christian Heimes <christian(at)cheimes(dot)de>
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Content-Type: text/x-rst
|
||||
Created: 02-Jan-2008
|
||||
Python-Version: 2.6, 3.0
|
||||
Post-History:
|
||||
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
This PEP proposes enhancements for the import machinery to add
|
||||
post import hooks. It is intended primarily to support the wider
|
||||
use of abstract base classes that is expected in Python 3.0.
|
||||
|
||||
The PEP originally started as a combined PEP for lazy imports and
|
||||
post import hooks. After some discussion on the python-dev mailing
|
||||
list the PEP was parted in two separate PEPs. [1]_
|
||||
|
||||
|
||||
Rationale
|
||||
=========
|
||||
|
||||
Python has no API to hook into the import machinery and execute code
|
||||
*after* a module is successfully loaded. The import hooks of PEP 302 are
|
||||
about finding modules and loading modules but they were not designed to
|
||||
as post import hooks.
|
||||
|
||||
|
||||
Use cases
|
||||
=========
|
||||
|
||||
A use case for a post import hook is mentioned in Nick Coghlan's initial
|
||||
posting [2]_. about callbacks on module import. It was found during the
|
||||
development of Python 3.0 and its ABCs. We wanted to register classes
|
||||
like decimal.Decimal with an ABC but the module should not be imported
|
||||
on every interpreter startup. Nick came up with this example::
|
||||
|
||||
@imp.when_imported('decimal')
|
||||
def register(decimal):
|
||||
Inexact.register(decimal.Decimal)
|
||||
|
||||
The function ``register`` is registered as callback for the module named
|
||||
'decimal'. When decimal is imported the function is called with the
|
||||
module object as argument.
|
||||
|
||||
While this particular example isn't necessary in practice, (as
|
||||
decimal.Decimal will inherit from the appropriate abstract Number base
|
||||
class in 2.6 and 3.0), it still illustrates the principle.
|
||||
|
||||
|
||||
Existing implementations
|
||||
========================
|
||||
|
||||
PJE's peak.util.imports [3]_ implements post load hooks. My
|
||||
implementation shares a lot with his and it's partly based on his ideas.
|
||||
|
||||
|
||||
Post import hook implementation
|
||||
===============================
|
||||
|
||||
Post import hooks are called after a module has been loaded. The hooks
|
||||
are callable which take one argument, the module instance. They are
|
||||
registered by the dotted name of the module, e.g. 'os' or 'os.path'.
|
||||
|
||||
The callable are stored in the dict ``sys.post_import_hooks`` which
|
||||
is a mapping from names (as string) to a list of callables or None.
|
||||
|
||||
|
||||
States
|
||||
------
|
||||
|
||||
No hook was registered
|
||||
''''''''''''''''''''''
|
||||
|
||||
sys.post_import_hooks contains no entry for the module
|
||||
|
||||
A hook is registered and the module is not loaded yet
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The import hook registry contains an entry
|
||||
sys.post_import_hooks["name"] = [hook1]
|
||||
|
||||
A module is successfully loaded
|
||||
'''''''''''''''''''''''''''''''
|
||||
|
||||
The import machinery checks if sys.post_import_hooks contains post import
|
||||
hooks for the newly loaded module. If hooks are found then the hooks are
|
||||
called in the order they were registered with the module instance as first
|
||||
argument. The processing of the hooks is stopped when a method raises an
|
||||
exception. At the end the entry for the module name is removed from
|
||||
sys.post_import_hooks, even when an error has occured.
|
||||
|
||||
A module can't be loaded
|
||||
''''''''''''''''''''''''
|
||||
|
||||
The import hooks are neither called nor removed from the registry. It
|
||||
may be possible to load the module later.
|
||||
|
||||
A hook is registered but the module is already loaded
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The hook is fired immediately.
|
||||
|
||||
|
||||
C API
|
||||
-----
|
||||
|
||||
New PyImport_* API functions
|
||||
''''''''''''''''''''''''''''
|
||||
|
||||
``PyObject* PyImport_GetPostImportHooks(void)``
|
||||
Returns the dict sys.post_import_hooks or NULL
|
||||
|
||||
``PyObject* PyImport_NotifyModuleLoaded(PyObject *module)``
|
||||
Notify the post import system that a module was requested. Returns the
|
||||
module or NULL if an error has occured.
|
||||
|
||||
``PyObject* PyImport_RegisterPostImportHook(PyObject *callable, PyObject *mod_name)``
|
||||
Register a new hook ``callable`` for the module ``mod_name``
|
||||
|
||||
The ``PyImport_PostImportNotify()`` method is called by
|
||||
``PyImport_ImportModuleLevel()``::
|
||||
|
||||
PyImport_ImportModuleLevel(...)
|
||||
{
|
||||
...
|
||||
result = import_module_level(name, globals, locals, fromlist, level);
|
||||
result = PyImport_PostImportNotify(result);
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
Python API
|
||||
----------
|
||||
|
||||
The import hook registry and two new API methods are exposed through the
|
||||
``sys`` and ``imp`` module.
|
||||
|
||||
sys.post_import_hooks
|
||||
The dict contains the post import hooks: {"name" : [hook1, hook2], ...}
|
||||
|
||||
imp.register_post_import_hook(hook: "callable", name: str)
|
||||
Register a new hook *hook* for the module *name*
|
||||
|
||||
imp.notify_module_loaded(module: "module instance") -> module
|
||||
Notify the system that a module has been loaded. The method is provided
|
||||
for compatibility with existing lazy / deferred import extensions.
|
||||
|
||||
The when_imported function decorator is also in the imp module,
|
||||
which is equivalent to::
|
||||
|
||||
def when_imported(name):
|
||||
def register(hook):
|
||||
register_post_import_hook(hook, name)
|
||||
return register
|
||||
|
||||
imp.when_imported(name) -> decorator function
|
||||
for @when_imported(name) def hook(module): pass
|
||||
|
||||
|
||||
Open issues
|
||||
===========
|
||||
|
||||
The when_imported decorator hasn't been written.
|
||||
|
||||
The code contains several XXX comments. They are mostly about error
|
||||
handling in edge cases.
|
||||
|
||||
|
||||
Backwards Compatibility
|
||||
=======================
|
||||
|
||||
The new features and API don't conflict with old import system of Python
|
||||
and don't cause any backward compatibility issues for most software.
|
||||
However systems like PEAK and Zope which implement their own lazy import
|
||||
magic need to follow some rules.
|
||||
|
||||
The post import hooks carefully designed to cooperate with existing
|
||||
deferred and lazy import systems. It's the suggestion of the PEP author
|
||||
to replace own on-load-hooks with the new hook API. The alternative
|
||||
lazy or deferred imports will still work but the implementations must
|
||||
call the ``imp.notify_module_loaded`` function.
|
||||
|
||||
|
||||
Reference Implementation
|
||||
========================
|
||||
|
||||
A reference implementation is already written and is available in the
|
||||
*py3k-importhook* branch. [4]_ It still requires some cleanups,
|
||||
documentation updates and additional unit tests.
|
||||
|
||||
|
||||
Acknowledgments
|
||||
===============
|
||||
|
||||
Nick Coghlan, for proof reading and the initial discussion
|
||||
Phillip J. Eby, for his implementation in PEAK and help with my own implementation
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
This document has been placed in the public domain.
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] PEP: Lazy module imports and post import hook
|
||||
http://permalink.gmane.org/gmane.comp.python.devel/90949
|
||||
|
||||
.. [2] Interest in PEP for callbacks on module import
|
||||
http://permalink.gmane.org/gmane.comp.python.python-3000.devel/11126
|
||||
|
||||
.. [3] peak.utils.imports
|
||||
http://svn.eby-sarna.com/Importing/peak/util/imports.py?view=markup
|
||||
|
||||
.. [4] py3k-importhook branch
|
||||
http://svn.python.org/view/python/branches/py3k-importhook/
|
||||
|
||||
|
||||
..
|
||||
Local Variables:
|
||||
mode: indented-text
|
||||
indent-tabs-mode: nil
|
||||
sentence-end-double-space: t
|
||||
fill-column: 70
|
||||
coding: utf-8
|
||||
End:
|
|
@ -0,0 +1,229 @@
|
|||
PEP: 370
|
||||
Title: Per user site-packages directory
|
||||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: Christian Heimes <christian(at)cheimes(dot)de>
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Content-Type: text/x-rst
|
||||
Created: 11-Jan-2008
|
||||
Python-Version: 2.6, 3.0
|
||||
Post-History:
|
||||
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
This PEP proposes a new a per user site-packages directory to allow
|
||||
users the local installation of Python packages in their home directory.
|
||||
|
||||
|
||||
Rationale
|
||||
=========
|
||||
|
||||
Current Python versions don't have an unified way to install packages
|
||||
into the home directory of an user (except for Mac Framework
|
||||
builds). Users are either forced to ask the system administrator to
|
||||
install or update a package for them or to use one of the many
|
||||
workaround like Virtual Python [1]_, Working Env [2]_ or
|
||||
Virtual Env [3]_.
|
||||
|
||||
It's not the goal of the PEP to replace the tools or to implement
|
||||
isolated installations of Python. It only implements the most common
|
||||
use case of an additional site-packages directory for each user.
|
||||
|
||||
The feature can't be implemented using the environment variable
|
||||
*PYTHONPATH*. The env var just inserts a new directory to the beginning
|
||||
of *sys.path* but it doesn't parse the pth files in the directory. A
|
||||
full blown site-packages path is required for several applications
|
||||
and Python eggs.
|
||||
|
||||
|
||||
Specification
|
||||
=============
|
||||
|
||||
site directory (site-packages)
|
||||
|
||||
A directory in ``sys.path``. In contrast to ordinary directories the pth
|
||||
files in the directory are processed, too.
|
||||
|
||||
user site directory
|
||||
|
||||
A site directory inside the users' home directory. An user site
|
||||
directory is specific to a Python version. The path contains
|
||||
the version number (major and minor only).
|
||||
|
||||
Mac
|
||||
``~/Library/Python/2.6/site-packages``
|
||||
Unix
|
||||
``~/.local/lib/python2.6/site-packages``
|
||||
|
||||
Windows
|
||||
``%APPDATA%/Python/Python26/site-packages``
|
||||
|
||||
user configuration directory
|
||||
|
||||
Usually the parent directory of the user site directory. It's meant
|
||||
for Python version specific data like config files.
|
||||
|
||||
Mac
|
||||
``~/Library/Python/2.6``
|
||||
Unix
|
||||
``~/.local/lib/python2.6``
|
||||
Windows
|
||||
``%APPDATA%/Python/Python26``
|
||||
|
||||
user base directory
|
||||
|
||||
It's located inside the user's home directory. The user site and
|
||||
use config directory are inside the base directory. On some systems
|
||||
the directory may be shared with 3rd party apps.
|
||||
|
||||
Mac
|
||||
``~/Library/Python``
|
||||
|
||||
Unix
|
||||
``~/.local``
|
||||
Windows
|
||||
``%APPDATA%/Python``
|
||||
|
||||
user script directory
|
||||
|
||||
A directory for binaries and scripts. [10]_ It's shared across Python
|
||||
versions and the destination directory for scripts.
|
||||
|
||||
Mac
|
||||
``~/Library/Python/bin``
|
||||
Unix
|
||||
``~/.local/bin``
|
||||
Windows
|
||||
``%APPDATA%/Python/Scripts``
|
||||
|
||||
|
||||
On Windows ``APPDATA`` was chosen because it is the most logical place for
|
||||
application data. Microsoft recommands that software doesn't write to
|
||||
``USERPROFILE`` [5]_ and ``My Documents`` is not suited for application data,
|
||||
too. [8]_
|
||||
|
||||
On Linux ``~/.local`` was chosen in favor over ``~/.python`` because the
|
||||
directory is already used by several other programs in analogy to
|
||||
``/usr/local``. [7]_
|
||||
|
||||
|
||||
Implementation
|
||||
==============
|
||||
|
||||
The site module gets a new method ``adduserpackage()`` which adds the
|
||||
appropriate directory to the search path. The directory is not added if
|
||||
it doesn't exist when Python is started. However the location of the
|
||||
user site directory and user base directory is stored in an internal
|
||||
variable for distutils.
|
||||
|
||||
The user site directory is added before the system site directories
|
||||
but after Python's search paths and ``PYTHONPATH``. This setup allows
|
||||
the user to install a different version of a package than the system
|
||||
administrator but it prevents the user from accidently overwriting a
|
||||
stdlib module. Stdlib modules can still be overwritten with
|
||||
``PYTHONPATH``.
|
||||
|
||||
For security reasons the user site directory is *not* added to
|
||||
``sys.path`` when the effective user id is not equal to the process
|
||||
user id [9]_. It prevents users from injecting Python code into suid
|
||||
apps.
|
||||
|
||||
The user site directory can be suppressed with a new option ``-s`` or
|
||||
the environment variable ``PYTHONNOUSERSITE``. The feature can be
|
||||
disabled globally by setting ``site.ENABLE_USER_SITE`` to the value
|
||||
``False``. It must be set by editing ``site.py``. It can't be altered
|
||||
``in sitecustomize.py`` or later.
|
||||
|
||||
``distutils.command.install`` (setup.py install) gets a new argument
|
||||
``--user`` to install packages in the user site directory. The required
|
||||
directories are created on demand.
|
||||
|
||||
``distutils.sysconfig`` will get methods to access the private variables
|
||||
of site. (not yet implemented)
|
||||
|
||||
The Windows updater needs to be updated, too. It should create an menu
|
||||
item which opens the user site directory in a new explorer windows.
|
||||
|
||||
|
||||
Backwards Compatibility
|
||||
=======================
|
||||
|
||||
TBD
|
||||
|
||||
|
||||
Open Questions
|
||||
==============
|
||||
|
||||
* Are the directories for Windows, Mac and Unix fine?
|
||||
|
||||
* Mac: Should framework and non-framework builds of Python use the
|
||||
same directories?
|
||||
|
||||
* The patch also adds a usecustomize hook to site. Is it useful and
|
||||
should it stay?
|
||||
|
||||
* Should the site package directory also be ignored if process gid !=
|
||||
effective gid?
|
||||
|
||||
* Should the Windows installer add ``%APPDATA%/Python/Scripts`` to
|
||||
``PATH``?
|
||||
|
||||
|
||||
Reference Implementation
|
||||
========================
|
||||
|
||||
A reference implementation is available in the bug tracker. [4]_
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
This document has been placed in the public domain.
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] Virtual Python
|
||||
http://peak.telecommunity.com/DevCenter/EasyInstall#creating-a-virtual-python
|
||||
|
||||
.. [2] Working Env
|
||||
http://pypi.python.org/pypi/workingenv.py
|
||||
http://blog.ianbicking.org/workingenv-revisited.html
|
||||
|
||||
.. [3] Virtual Env
|
||||
http://pypi.python.org/pypi/virtualenv
|
||||
|
||||
.. [4] reference implementation
|
||||
http://bugs.python.org/issue1799
|
||||
|
||||
.. [5] MSDN: CSIDL
|
||||
http://msdn2.microsoft.com/en-us/library/bb762494.aspx
|
||||
|
||||
.. [6] Initial suggestion for a per user site-packages directory
|
||||
http://permalink.gmane.org/gmane.comp.python.devel/90902
|
||||
|
||||
.. [7] Suggestion of ~/.local/
|
||||
http://permalink.gmane.org/gmane.comp.python.devel/90925
|
||||
|
||||
.. [8] APPDATA discussion
|
||||
http://permalink.gmane.org/gmane.comp.python.devel/90932
|
||||
|
||||
.. [9] Security concerns and -s option
|
||||
http://permalink.gmane.org/gmane.comp.python.devel/91063
|
||||
|
||||
.. [10] Discussion about the bin directory
|
||||
http://permalink.gmane.org/gmane.comp.python.devel/91095
|
||||
|
||||
|
||||
..
|
||||
Local Variables:
|
||||
mode: indented-text
|
||||
indent-tabs-mode: nil
|
||||
sentence-end-double-space: t
|
||||
fill-column: 70
|
||||
coding: utf-8
|
||||
End:
|
Loading…
Reference in New Issue