[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