diff options
author | PJ Eby <distutils-sig@python.org> | 2005-07-25 03:12:51 +0000 |
---|---|---|
committer | PJ Eby <distutils-sig@python.org> | 2005-07-25 03:12:51 +0000 |
commit | 54bb8e4003534a9af54028ef719eda5ba6088bac (patch) | |
tree | bdae8c0810e7a1a4ecf7e93669cbba45f0de9fcb | |
parent | 1c40632b88d76aea178e751483645ec3d32c81d9 (diff) | |
download | external_python_setuptools-54bb8e4003534a9af54028ef719eda5ba6088bac.tar.gz external_python_setuptools-54bb8e4003534a9af54028ef719eda5ba6088bac.tar.bz2 external_python_setuptools-54bb8e4003534a9af54028ef719eda5ba6088bac.zip |
Misc. bug fixes and doc additions. Add 'iter_entry_points()' API.
--HG--
branch : setuptools
extra : convert_revision : svn%3A6015fed2-1504-0410-9fe1-9d1591cc4771/sandbox/trunk/setuptools%4041153
-rwxr-xr-x | EasyInstall.txt | 2 | ||||
-rw-r--r-- | pkg_resources.py | 114 | ||||
-rwxr-xr-x | setuptools.txt | 8 | ||||
-rw-r--r-- | setuptools/dist.py | 20 | ||||
-rw-r--r-- | setuptools/tests/test_resources.py | 12 |
5 files changed, 81 insertions, 75 deletions
diff --git a/EasyInstall.txt b/EasyInstall.txt index a5605fbe..e4ce4265 100755 --- a/EasyInstall.txt +++ b/EasyInstall.txt @@ -647,7 +647,7 @@ Command-Line Options "site" directory, he or she should create an ``altinstall.pth`` file in the normal site-packages directory, containing this:: - import os; addsitedir(os.path.expanduser('~/lib/python2.3')) + import os, site; site.addsitedir(os.path.expanduser('~/lib/python2.3')) and a ``distutils.cfg`` file inside the ``distutils`` package directory, containing this:: diff --git a/pkg_resources.py b/pkg_resources.py index 1171b761..8cff9a8a 100644 --- a/pkg_resources.py +++ b/pkg_resources.py @@ -42,7 +42,7 @@ from sets import ImmutableSet __all__ = [ # Basic resource access and distribution/entry point discovery 'require', 'run_script', 'get_provider', 'get_distribution', - 'load_entry_point', 'get_entry_map', 'get_entry_info', + 'load_entry_point', 'get_entry_map', 'get_entry_info', 'iter_entry_points', 'resource_string', 'resource_stream', 'resource_filename', 'resource_listdir', 'resource_exists', 'resource_isdir', @@ -231,17 +231,17 @@ def get_distribution(dist): raise TypeError("Expected string, Requirement, or Distribution", dist) return dist -def load_entry_point(dist, kind, name): - """Return the `name` entry point of `kind` for dist or raise ImportError""" - return get_distribution(dist).load_entry_point(dist, kind, name) +def load_entry_point(dist, group, name): + """Return `name` entry point of `group` for `dist` or raise ImportError""" + return get_distribution(dist).load_entry_point(group, name) -def get_entry_map(dist, kind=None): - """Return the entry point map for `kind`, or the full entry map""" - return get_distribution(dist).get_entry_map(dist, kind) +def get_entry_map(dist, group=None): + """Return the entry point map for `group`, or the full entry map""" + return get_distribution(dist).get_entry_map(group) -def get_entry_info(dist, kind, name): - """Return the EntryPoint object for `kind`+`name`, or ``None``""" - return get_distribution(dist).get_entry_info(dist, kind, name) +def get_entry_info(dist, group, name): + """Return the EntryPoint object for `group`+`name`, or ``None``""" + return get_distribution(dist).get_entry_info(group, name) class IMetadataProvider: @@ -377,7 +377,6 @@ class WorkingSet(object): for key in self.entry_keys[item]: yield self.by_key[key] - def find(self, req): """Find a distribution matching requirement `req` @@ -394,19 +393,20 @@ class WorkingSet(object): else: return dist + def iter_entry_points(self, 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, otherwise only ones matching + both `group` and `name` are yielded (in distribution order). + """ + for dist in self: + entries = dist.get_entry_map(group) + if name is None: + for ep in entries.values(): + yield ep + elif name in entries: + yield entries[name] def add(self, dist, entry=None): """Add `dist` to working set, associated with `entry` @@ -1600,7 +1600,7 @@ def parse_version(s): class EntryPoint(object): """Object representing an importable location""" - def __init__(self, name, module_name, attrs=(), extras=()): + def __init__(self, name, module_name, attrs=(), extras=(), dist=None): if not MODULE(module_name): raise ValueError("Invalid module name", module_name) self.name = name @@ -1609,6 +1609,7 @@ class EntryPoint(object): self.extras = Requirement.parse( ("x[%s]" % ','.join(extras)).lower() ).extras + self.dist = dist def __str__(self): s = "%s = %s" % (self.name, self.module_name) @@ -1621,7 +1622,8 @@ class EntryPoint(object): def __repr__(self): return "EntryPoint.parse(%r)" % str(self) - def load(self): + def load(self, require=True): + if require: self.require() entry = __import__(self.module_name, globals(),globals(), ['__name__']) for attr in self.attrs: try: @@ -1630,16 +1632,14 @@ class EntryPoint(object): raise ImportError("%r has no %r attribute" % (entry,attr)) return entry - - - - - - - - + def require(self): + if self.extras and not self.dist: + raise UnknownExtra("Can't require() without a distribution", self) + map(working_set.add, + working_set.resolve(self.dist.requires(self.extras))) + #@classmethod - def parse(cls, src): + def parse(cls, src, dist=None): """Parse a single entry point from string `src` Entry point syntax follows the form:: @@ -1668,7 +1668,7 @@ class EntryPoint(object): src ) else: - return cls(name.strip(), value.lstrip(), attrs, extras) + return cls(name.strip(), value.lstrip(), attrs, extras, dist) parse = classmethod(parse) @@ -1680,11 +1680,12 @@ class EntryPoint(object): #@classmethod - def parse_list(cls, section, contents): + def parse_list(cls, section, contents, dist=None): if not MODULE(section): raise ValueError("Invalid section name", section) this = {} - for ep in map(cls.parse, yield_lines(contents)): + for line in yield_lines(contents): + ep = cls.parse(line, dist) if ep.name in this: raise ValueError("Duplicate entry point",section,ep.name) this[ep.name]=ep @@ -1693,7 +1694,7 @@ class EntryPoint(object): parse_list = classmethod(parse_list) #@classmethod - def parse_map(cls, data): + def parse_map(cls, data, dist=None): if isinstance(data,dict): data = data.items() else: @@ -1707,7 +1708,7 @@ class EntryPoint(object): section = section.strip() if section in maps: raise ValueError("Duplicate section name", section) - maps[section] = cls.parse_list(section, contents) + maps[section] = cls.parse_list(section, contents, dist) return maps parse_map = classmethod(parse_map) @@ -1719,9 +1720,6 @@ class EntryPoint(object): - - - class Distribution(object): """Wrap an actual or potential sys.path entry w/metadata""" def __init__(self, @@ -1886,31 +1884,31 @@ class Distribution(object): - def load_entry_point(self, kind, name): - """Return the `name` entry point of `kind` or raise ImportError""" - ep = self.get_entry_info(kind,name) + def load_entry_point(self, group, name): + """Return the `name` entry point of `group` or raise ImportError""" + ep = self.get_entry_info(group,name) if ep is None: - raise ImportError("Entry point %r not found" % ((kind,name),)) - if ep.extras: - # Ensure any needed extras get added to the working set - map(working_set.add, working_set.resolve(self.requires(ep.extras))) + raise ImportError("Entry point %r not found" % ((group,name),)) return ep.load() - def get_entry_map(self,kind=None): - """Return the entry point map for `kind`, or the full entry map""" + def get_entry_map(self, group=None): + """Return the entry point map for `group`, or the full entry map""" try: ep_map = self._ep_map except AttributeError: ep_map = self._ep_map = EntryPoint.parse_map( - self._get_metadata('entry_points.txt') + self._get_metadata('entry_points.txt'), self ) - if kind is not None: - return ep_map.get(kind,{}) + if group is not None: + return ep_map.get(group,{}) return ep_map - def get_entry_info(self, kind, name): - """Return the EntryPoint object for `kind`+`name`, or ``None``""" - return self.get_entry_map(kind).get(name) + def get_entry_info(self, group, name): + """Return the EntryPoint object for `group`+`name`, or ``None``""" + return self.get_entry_map(group).get(name) + + + @@ -2147,6 +2145,7 @@ _initialize(globals()) working_set = WorkingSet() require = working_set.require +iter_entry_points = working_set.iter_entry_points add_activation_listener = working_set.subscribe # Activate all distributions already on sys.path, and ensure that @@ -2172,4 +2171,3 @@ add_activation_listener(lambda dist: dist.activate()) - diff --git a/setuptools.txt b/setuptools.txt index 50bc3b11..b9911703 100755 --- a/setuptools.txt +++ b/setuptools.txt @@ -72,6 +72,14 @@ You may receive a message telling you about an obsolete version of setuptools being present; if so, you must be sure to delete it entirely, along with the old ``pkg_resources`` module if it's present on ``sys.path``. +To get the in-development version of setuptools, run:: + + cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/python login + cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/python \ + co -d setuptools python/nondist/sandbox/setuptools + +You can then install it using the usual "setup.py install" incantation. + Basic Use ========= diff --git a/setuptools/dist.py b/setuptools/dist.py index a603ade0..40234b4e 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -16,20 +16,17 @@ def get_command_class(self, command): if command in self.cmdclass: return self.cmdclass[command] - for dist in pkg_resources.working_set: - if dist.get_entry_info('distutils.commands',command): - cmdclass = dist.load_entry_point('distutils.commands',command) - self.cmdclass[command] = cmdclass - return cmdclass + for ep in pkg_resources.iter_entry_points('distutils.commands',command): + self.cmdclass[command] = cmdclass = ep.load() + return cmdclass else: return _old_get_command_class(self, command) def print_commands(self): - for dist in pkg_resources.working_set: - for cmd,ep in dist.get_entry_map('distutils.commands').items(): - if cmd not in self.cmdclass: - cmdclass = ep.load() # don't require extras, we're not running - self.cmdclass[cmd] = cmdclass + for ep in pkg_resources.iter_entry_points('distutils.commands'): + if ep.name not in self.cmdclass: + cmdclass = ep.load(False) # don't require extras, we're not running + self.cmdclass[ep.name] = cmdclass return _old_print_commands(self) for meth in 'print_commands', 'get_command_class': @@ -39,6 +36,9 @@ for meth in 'print_commands', 'get_command_class': sequence = tuple, list + + + class Distribution(_Distribution): """Distribution with support for features, tests, and package data diff --git a/setuptools/tests/test_resources.py b/setuptools/tests/test_resources.py index 5392e59f..865065c2 100644 --- a/setuptools/tests/test_resources.py +++ b/setuptools/tests/test_resources.py @@ -216,16 +216,20 @@ class EntryPointTests(TestCase): "foo = setuptools.tests.test_resources:EntryPointTests [x]" ) + def setUp(self): + self.dist = Distribution.from_filename( + "FooPkg-1.2-py2.4.egg", metadata=Metadata(('requires.txt','[x]'))) + def testBasics(self): ep = EntryPoint( "foo", "setuptools.tests.test_resources", ["EntryPointTests"], - ["x"] + ["x"], self.dist ) self.assertfields(ep) def testParse(self): s = "foo = setuptools.tests.test_resources:EntryPointTests [x]" - ep = EntryPoint.parse(s) + ep = EntryPoint.parse(s, self.dist) self.assertfields(ep) ep = EntryPoint.parse("bar baz= spammity[PING]") @@ -240,10 +244,6 @@ class EntryPointTests(TestCase): self.assertEqual(ep.attrs, ("foo",)) self.assertEqual(ep.extras, ()) - - - - def testRejects(self): for ep in [ "foo", "x=1=2", "x=a:b:c", "q=x/na", "fez=pish:tush-z", "x=f[a]>2", |