[Python-checkins] python/nondist/sandbox/setuptools api_tests.txt, 1.5, 1.6 pkg_resources.py, 1.64, 1.65 pkg_resources.txt, 1.4, 1.5
pje@users.sourceforge.net
pje at users.sourceforge.net
Sun Aug 14 01:04:19 CEST 2005
Update of /cvsroot/python/python/nondist/sandbox/setuptools
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14936
Modified Files:
api_tests.txt pkg_resources.py pkg_resources.txt
Log Message:
Added docs for main EntryPoint APIs, and cleaned up the API itself a bit.
Also fixed a few bugs.
Index: api_tests.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/api_tests.txt,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- api_tests.txt 6 Aug 2005 20:54:01 -0000 1.5
+++ api_tests.txt 13 Aug 2005 23:04:08 -0000 1.6
@@ -138,7 +138,7 @@
['http://example.com/something']
>>> dist in ws
True
- >>> Distribution('foo') in ws
+ >>> Distribution('foo',version="") in ws
False
And you can iterate over its distributions::
Index: pkg_resources.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v
retrieving revision 1.64
retrieving revision 1.65
diff -u -d -r1.64 -r1.65
--- pkg_resources.py 11 Aug 2005 00:37:37 -0000 1.64
+++ pkg_resources.py 13 Aug 2005 23:04:08 -0000 1.65
@@ -1598,7 +1598,7 @@
class EntryPoint(object):
- """Object representing an importable location"""
+ """Object representing an advertised importable object"""
def __init__(self, name, module_name, attrs=(), extras=(), dist=None):
if not MODULE(module_name):
@@ -1680,35 +1680,37 @@
#@classmethod
- def parse_list(cls, section, contents, dist=None):
- if not MODULE(section):
- raise ValueError("Invalid section name", section)
+ def parse_group(cls, group, lines, dist=None):
+ """Parse an entry point group"""
+ if not MODULE(group):
+ raise ValueError("Invalid group name", group)
this = {}
- for line in yield_lines(contents):
+ for line in yield_lines(lines):
ep = cls.parse(line, dist)
if ep.name in this:
- raise ValueError("Duplicate entry point",section,ep.name)
+ raise ValueError("Duplicate entry point", group, ep.name)
this[ep.name]=ep
return this
- parse_list = classmethod(parse_list)
+ parse_group = classmethod(parse_group)
#@classmethod
def parse_map(cls, data, dist=None):
+ """Parse a map of entry point groups"""
if isinstance(data,dict):
data = data.items()
else:
data = split_sections(data)
maps = {}
- for section, contents in data:
- if section is None:
- if not contents:
+ for group, lines in data:
+ if group is None:
+ if not lines:
continue
- raise ValueError("Entry points must be listed in sections")
- section = section.strip()
- if section in maps:
- raise ValueError("Duplicate section name", section)
- maps[section] = cls.parse_list(section, contents, dist)
+ raise ValueError("Entry points must be listed in groups")
+ group = group.strip()
+ if group in maps:
+ raise ValueError("Duplicate group name", group)
+ maps[group] = cls.parse_group(group, lines, dist)
return maps
parse_map = classmethod(parse_map)
@@ -1718,8 +1720,6 @@
-
-
class Distribution(object):
"""Wrap an actual or potential sys.path entry w/metadata"""
def __init__(self,
@@ -1862,7 +1862,9 @@
return str(self)
def __str__(self):
- version = getattr(self,'version',None) or "[unknown version]"
+ try: version = getattr(self,'version',None)
+ except ValueError: version = None
+ version = version or "[unknown version]"
return "%s %s" % (self.project_name,version)
def __getattr__(self,attr):
@@ -1882,8 +1884,6 @@
return Requirement.parse('%s==%s' % (self.project_name, self.version))
-
-
def load_entry_point(self, group, name):
"""Return the `name` entry point of `group` or raise ImportError"""
ep = self.get_entry_info(group,name)
Index: pkg_resources.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.txt,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- pkg_resources.txt 7 Aug 2005 20:54:10 -0000 1.4
+++ pkg_resources.txt 13 Aug 2005 23:04:08 -0000 1.5
@@ -46,11 +46,12 @@
API Reference
-------------
+ 'require', 'run_script',
Namespace Package Support
=========================
-XXX
+declare_namespace, fixup_namespace_packages, register_namespace_handler
``WorkingSet`` Objects
@@ -65,24 +66,188 @@
XXX
-``EntryPoint`` Objects
-======================
-
-XXX
-
-
``Requirement`` Objects
=======================
XXX Syntax, parse_requirments, Requirement.parse, etc.
+
+
+Entry Points
+============
+
+Entry points are a simple way for distributions to "advertise" Python objects
+(such as functions or classes) for use by other distributions. Extensible
+applications and frameworks can search for entry points with a particular name
+or group, either from a specific distribution or from all active distributions
+on sys.path, and then inspect or load the advertised objects at will.
+
+Entry points belong to "groups" which are named with a dotted name similar to
+a Python package or module name. For example, the ``setuptools`` package uses
+an entry point named ``distutils.commands`` in order to find commands defined
+by distutils extensions. ``setuptools`` treats the names of entry points
+defined in that group as the acceptable commands for a setup script.
+
+In a similar way, other packages can define their own entry point groups,
+either using dynamic names within the group (like ``distutils.commands``), or
+possibly using predefined names within the group. For example, a blogging
+framework that offers various pre- or post-publishing hooks might define an
+entry point group and look for entry points named "pre_process" and
+"post_process" within that group.
+
+To advertise an entry point, a project needs to use ``setuptools`` and provide
+an ``entry_points`` argument to ``setup()`` in its setup script, so that the
+entry points will be included in the distribution's metadata. For more
+details, see the ``setuptools`` documentation. (XXX link here to setuptools)
+
+Each project distribution can advertise at most one entry point of a given
+name within the same entry point group. For example, a distutils extension
+could advertise two different ``distutils.commands`` entry points, as long as
+they had different names. However, there is nothing that prevents *different*
+projects from advertising entry points of the same name in the same group. In
+some cases, this is a desirable thing, since the application or framework that
+uses the entry points may be calling them as hooks, or in some other way
+combining them. It is up to the application or framework to decide what to do
+if multiple distributions advertise an entry point; some possibilities include
+using both entry points, displaying an error message, using the first one found
+in sys.path order, etc.
+
+
+Convenience API
+---------------
+
+In the following functions, the `dist` argument can be a ``Distribution``
+instance, a ``Requirement`` instance, or a string specifying a requirement
+(i.e. project name, version, etc.). If the argument is a string or
+``Requirement``, the specified distribution is located (and added to sys.path
+if not already present). An error will be raised if a matching distribution is
+not available.
+
+The `group` argument should be a string containing a dotted identifier,
+identifying an entry point group. If you are defining an entry point group,
+you should include some portion of your package's name in the group name so as
+to avoid collision with other packages' entry point groups.
+
+``load_entry_point(dist, group, name)``
+ Load the named entry point from the specified distribution, or raise
+ ``ImportError``.
+
+``get_entry_info(dist, group, name)``
+ Return an ``EntryPoint`` object for the given `group` and `name` from
+ the specified distribution. Returns ``None`` if the distribution has not
+ advertised a matching entry point.
+
+``get_entry_map(dist, group=None)
+ Return the distribution's entry point map for `group`, or the full entry
+ map for the distribution. This function always returns a dictionary,
+ even if the distribution advertises no entry points. If `group` is given,
+ the dictionary maps entry point names to the corresponding ``EntryPoint``
+ object. If `group` is None, the dictionary maps group names to
+ dictionaries that then map entry point names to the corresponding
+ ``EntryPoint`` instance in that group.
+
+``iter_entry_points(group, name=None)``
+ Yield entry point objects from `group` matching `name`
+
+ If `name` is None, yields all entry points in `group` from all
+ distributions in the working set on sys.path, otherwise only ones matching
+ both `group` and `name` are yielded. Entry points are yielded from
+ the active distributions in the order that the distributions appear on
+ sys.path. (Within entry points for a particular distribution, however,
+ there is no particular ordering.)
+
+
+Creating and Parsing
+--------------------
+
+``EntryPoint(name, module_name, attrs=(), extras=(), dist=None)``
+ Create an ``EntryPoint`` instance. `name` is the entry point name. The
+ `module_name` is the (dotted) name of the module containing the advertised
+ object. `attrs` is an optional tuple of names to look up from the
+ module to obtain the advertised object. For example, an `attrs` of
+ ``("foo","bar")`` and a `module_name` of ``"baz"`` would mean that the
+ advertised object could be obtained by the following code::
+
+ import baz
+ advertised_object = baz.foo.bar
+
+ The `extras` are an optional tuple of "extra feature" names that the
+ distribution needs in order to provide this entry point. When the
+ entry point is loaded, these extra features are looked up in the `dist`
+ argument to find out what other distributions may need to be activated
+ on sys.path; see the ``load()`` method for more details. The `extras`
+ argument is only meaningful if `dist` is specified. `dist` must be
+ a ``Distribution`` instance.
+
+``EntryPoint.parse(src, dist=None)`` (classmethod)
+ Parse a single entry point from string `src`
+
+ Entry point syntax follows the form::
+
+ name = some.module:some.attr [extra1,extra2]
+
+ The entry name and module name are required, but the ``:attrs`` and
+ ``[extras]`` parts are optional, as is the whitespace shown between
+ some of the items. The `dist` argument is passed through to the
+ ``EntryPoint()`` constructor, along with the other values parsed from
+ `src`.
+
+``EntryPoint.parse_group(group, lines, dist=None)`` (classmethod)
+ Parse `lines` (a string or sequence of lines) to create a dictionary
+ mapping entry point names to ``EntryPoint`` objects. ``ValueError`` is
+ raised if entry point names are duplicated, if `group` is not a valid
+ entry point group name, or if there are any syntax errors. (Note: the
+ `group` parameter is used only for validation and to create more
+ informative error messages.) If `dist` is provided, it will be used to
+ set the ``dist`` attribute of the created ``EntryPoint`` objects.
+
+``EntryPoint.parse_map(data, dist=None)`` (classmethod)
+ Parse `data` into a dictionary mapping group names to dictionaries mapping
+ entry point names to ``EntryPoint`` objects. If `data` is a dictionary,
+ then the keys are used as group names and the values are passed to
+ ``parse_group()`` as the `lines` argument. If `data` is a string or
+ sequence of lines, it is first split into .ini-style sections (using
+ the ``split_sections()`` utility function) and the section names are used
+ as group names. In either case, the `dist` argument is passed through to
+ ``parse_group()`` so that the entry points will be linked to the specified
+ distribution.
+
+
+``EntryPoint`` Objects
+----------------------
+
+For simple introspection, ``EntryPoint`` objects have attributes that
+correspond exactly to the constructor argument names: ``name``,
+``module_name``, ``attrs``, ``extras``, and ``dist`` are all available. In
+addition, the following methods are provided:
+
+``load(require=True, env=None, installer=None)``
+ Load the entry point, returning the advertised Python object, or raise
+ ``ImportError`` if it cannot be obtained. If `require` is a true value,
+ then ``require(env, installer)`` is called before attempting the import.
+
+``require(env=None, installer=None)``
+ Ensure that any "extras" needed by the entry point are available on
+ sys.path. ``UnknownExtra`` is raised if the ``EntryPoint`` has ``extras``,
+ but no ``dist``, or if the named extras are not defined by the
+ distribution. If `env` is supplied, it must be an ``Environment``, and it
+ will be used to search for needed distributions if they are not already
+ present on sys.path. If `installer` is supplied, it must be a callable
+ taking a ``Requirement`` instance and returning a matching importable
+ ``Distribution`` instance or None.
+
+
``Distribution`` Objects
========================
Factories: get_provider, get_distribution, find_distributions; see also
WorkingSet and Environment APIs.
+register_finder
+register_loader_type
+'load_entry_point', 'get_entry_map', 'get_entry_info'
+
``ResourceManager`` API
=======================
@@ -459,6 +624,21 @@
set.
+PEP 302 Utilities
+-----------------
+
+``get_importer(path_item)``
+ Retrieve a PEP 302 "importer" for the given path item (which need not
+ actually be on ``sys.path``). This routine simulates the PEP 302 protocol
+ for obtaining an "importer" object. It first checks for an importer for
+ the path item in ``sys.path_importer_cache``, and if not found it calls
+ each of the ``sys.path_hooks`` and caches the result if a good importer is
+ found. If no importer is found, this routine returns an ``ImpWrapper``
+ instance that wraps the builtin import machinery as a PEP 302-compliant
+ "importer" object. This ``ImpWrapper`` is *not* cached; instead a new
+ instance is returned each time.
+
+
File/Path Utilities
-------------------
More information about the Python-checkins
mailing list