[Checkins] SVN: zc.buildout/trunk/src/zc/buildout/easy_install.
Added support for extra paths in generated scripts.
Jim Fulton
jim at zope.com
Tue Sep 5 18:55:56 EDT 2006
Log message for revision 69991:
Added support for extra paths in generated scripts.
Added ability to supply entry points directly. This is useful for
packages that don't declare their entry points.
No longer generate "py-" scripts implicitly. Added a new option,
interpreter, to request such scripts and specifu their names.
Changed:
U zc.buildout/trunk/src/zc/buildout/easy_install.py
U zc.buildout/trunk/src/zc/buildout/easy_install.txt
-=-
Modified: zc.buildout/trunk/src/zc/buildout/easy_install.py
===================================================================
--- zc.buildout/trunk/src/zc/buildout/easy_install.py 2006-09-05 22:55:53 UTC (rev 69990)
+++ zc.buildout/trunk/src/zc/buildout/easy_install.py 2006-09-05 22:55:55 UTC (rev 69991)
@@ -24,10 +24,7 @@
import pkg_resources, setuptools.command.setopt, setuptools.package_index
import zc.buildout
-# XXX we could potentially speed this up quite a bit by keeping our
-# own PackageIndex to analyse whether there are newer dists. A hitch
-# is that the package index seems to go out of its way to only handle
-# one Python version at a time. :(
+default_index_url = os.environ.get('buildout-testing-index-url')
logger = logging.getLogger('zc.buildout.easy_install')
@@ -70,6 +67,9 @@
return index
if index_url is None:
+ index_url = default_index_url
+
+ if index_url is None:
index = setuptools.package_index.PackageIndex(
python=_get_version(executable)
)
@@ -151,7 +151,7 @@
return best_we_have
else:
# Let's find out if we already have the best available:
- if best_we_have >= best_available:
+ if best_we_have.parsed_version >= best_available.parsed_version:
# Yup. Use it.
logger.debug('We have the best distributon that satisfies\n%s', req)
return best_we_have
@@ -218,6 +218,8 @@
if dist is None:
if dest is not None:
+ logger.info("Getting new distribution for %s", requirement)
+
# May need a new one. Call easy_install
_call_easy_install(str(requirement), dest, links, index,
executable, always_unzip)
@@ -228,8 +230,10 @@
# and either firgure out the distribution added, or
# only rescan if any files have been added.
env.scan([dest])
-
- dist = env.best_match(requirement, ws)
+ dist = env.best_match(requirement, ws)
+ logger.info("Got %s", dist)
+ else:
+ dist = env.best_match(requirement, ws)
if dist is None:
raise ValueError("Couldn't find", requirement)
@@ -246,12 +250,12 @@
def install(specs, dest,
links=(), index=None,
executable=sys.executable, always_unzip=False,
- path=None):
+ path=None, working_set=None):
logger.debug('Installing %r', specs)
path = path and path[:] or []
- if dest is not None:
+ if dest is not None and dest not in path:
path.insert(0, dest)
path += buildout_and_setuptools_path
@@ -265,7 +269,10 @@
env = pkg_resources.Environment(path, python=_get_version(executable))
requirements = [pkg_resources.Requirement.parse(spec) for spec in specs]
- ws = pkg_resources.WorkingSet([])
+ if working_set is None:
+ ws = pkg_resources.WorkingSet([])
+ else:
+ ws = working_set
for requirement in requirements:
ws.add(_get_dist(requirement, env, ws,
@@ -368,46 +375,51 @@
scripts=None,
extra_paths=(),
arguments='',
+ interpreter=None,
):
- reqs = [pkg_resources.Requirement.parse(r) for r in reqs]
- projects = [r.project_name for r in reqs]
+
path = [dist.location for dist in working_set]
path.extend(extra_paths)
path = repr(path)[1:-1].replace(', ', ',\n ')
generated = []
- for dist in working_set:
- if dist.project_name in projects:
+ if isinstance(reqs, str):
+ raise TypeError('Expected iterable of requirements or entry points,'
+ ' got string.')
+
+ entry_points = []
+ for req in reqs:
+ if isinstance(req, str):
+ req = pkg_resources.Requirement.parse(req)
+ dist = working_set.find(req)
for name in pkg_resources.get_entry_map(dist, 'console_scripts'):
- if scripts is not None:
- sname = scripts.get(name)
- if sname is None:
- continue
- else:
- sname = name
-
- sname = os.path.join(dest, sname)
- generated.extend(
- _script(dist, 'console_scripts', name, path, sname,
- executable, arguments)
+ entry_point = dist.get_entry_info('console_scripts', name)
+ entry_points.append(
+ (name, entry_point.module_name, '.'.join(entry_point.attrs))
)
+ else:
+ entry_points.append(req)
+
+ for name, module_name, attrs in entry_points:
+ if scripts is not None:
+ sname = scripts.get(name)
+ if sname is None:
+ continue
+ else:
+ sname = name
- name = 'py-'+dist.project_name
- if scripts is not None:
- sname = scripts.get(name)
- else:
- sname = name
+ sname = os.path.join(dest, sname)
+ generated.extend(
+ _script(module_name, attrs, path, sname, executable, arguments)
+ )
- if sname is not None:
- sname = os.path.join(dest, sname)
- generated.extend(
- _pyscript(path, sname, executable)
- )
+ if interpreter:
+ sname = os.path.join(dest, interpreter)
+ generated.extend(_pyscript(path, sname, executable))
return generated
-def _script(dist, group, name, path, dest, executable, arguments):
- entry_point = dist.get_entry_info(group, name)
+def _script(module_name, attrs, path, dest, executable, arguments):
generated = []
if sys.platform == 'win32':
# generate exe file and give the script a magic name:
@@ -420,10 +432,8 @@
open(dest, 'w').write(script_template % dict(
python = executable,
path = path,
- project = dist.project_name,
- name = name,
- module_name = entry_point.module_name,
- attrs = '.'.join(entry_point.attrs),
+ module_name = module_name,
+ attrs = attrs,
arguments = arguments,
))
try:
@@ -438,7 +448,7 @@
import sys
sys.path[0:0] = [
- %(path)s
+ %(path)s,
]
import %(module_name)s
@@ -474,7 +484,7 @@
import sys
sys.path[0:0] = [
- %(path)s
+ %(path)s,
]
_interactive = True
Modified: zc.buildout/trunk/src/zc/buildout/easy_install.txt
===================================================================
--- zc.buildout/trunk/src/zc/buildout/easy_install.txt 2006-09-05 22:55:53 UTC (rev 69990)
+++ zc.buildout/trunk/src/zc/buildout/easy_install.txt 2006-09-05 22:55:55 UTC (rev 69991)
@@ -188,7 +188,7 @@
from the demo egg:
>>> scripts = zc.buildout.easy_install.scripts(
- ... ['demo==0.1'], ws, python2_4_executable, bin)
+ ... ['demo'], ws, python2_4_executable, bin)
the four arguments we passed were:
@@ -202,25 +202,26 @@
3. The destination directory.
-The bin directory now contains 2 generated scripts:
+The bin directory now contains a generated script:
>>> ls(bin)
- demo
- - py-demo
The return value is a list of the scripts generated:
>>> import os, sys
>>> if sys.platform == 'win32':
... scripts == [os.path.join(bin, 'demo.exe'),
- ... os.path.join(bin, 'demo-script.py'),
- ... os.path.join(bin, 'py-demo.exe'),
- ... os.path.join(bin, 'py-demo-script.py')]
+ ... os.path.join(bin, 'demo-script.py')]
... else:
- ... scripts == [os.path.join(bin, 'demo'),
- ... os.path.join(bin, 'py-demo')]
+ ... scripts == [os.path.join(bin, 'demo')]
True
+Note that in Windows, 2 files are generated for each script. A script
+file, ending in '-script.py', and an exe file that allows the script
+to be invoked directly without having to specify the Python
+interpreter and without having to provide a '.py' suffix.
+
The demo script run the entry point defined in the demo egg:
>>> cat(bin, 'demo') # doctest: +NORMALIZE_WHITESPACE
@@ -229,7 +230,7 @@
import sys
sys.path[0:0] = [
'/tmp/xyzsample-install/demo-0.3-py2.3.egg',
- '/tmp/xyzsample-install/demoneeded-1.1-py2.3.egg'
+ '/tmp/xyzsample-install/demoneeded-1.1-py2.3.egg',
]
<BLANKLINE>
import eggrecipedemo
@@ -244,16 +245,73 @@
- The module for the script entry point is imported and the entry
point, in this case, 'main', is run.
-The py-demo script simply run the Python interactive interpreter with
+Rather than requirement strings, you can pass tuples containing 3
+strings:
+
+ - A script name,
+
+ - A module,
+
+ - An attribute expression for an entry point within the module.
+
+For example, we could have passed antry point information directly
+rather than passing a requirement:
+
+ >>> scripts = zc.buildout.easy_install.scripts(
+ ... [('demo', 'eggrecipedemo', 'main')],
+ ... ws, python2_4_executable, bin)
+
+ >>> cat(bin, 'demo') # doctest: +NORMALIZE_WHITESPACE
+ #!/usr/local/bin/python2.3
+ <BLANKLINE>
+ import sys
+ sys.path[0:0] = [
+ '/tmp/xyzsample-install/demo-0.3-py2.3.egg',
+ '/tmp/xyzsample-install/demoneeded-1.1-py2.3.egg',
+ ]
+ <BLANKLINE>
+ import eggrecipedemo
+ <BLANKLINE>
+ if __name__ == '__main__':
+ eggrecipedemo.main()
+
+Passing entry-point information directly is handy when using eggs (or
+distributions) that don't declare their entry points, such as
+distributions that aren't based on setuptools.
+
+The interpreter keyword argument can be used to generate a script that can
+be used to invoke the Python interactive interpreter with the path set
+based on the working set. This generated script can also be used to
+run other scripts with the path set on the working set:
+
+ >>> scripts = zc.buildout.easy_install.scripts(
+ ... ['demo'], ws, python2_4_executable, bin, interpreter='py')
+
+
+ >>> ls(bin)
+ - demo
+ - py
+
+ >>> if sys.platform == 'win32':
+ ... scripts == [os.path.join(bin, 'demo.exe'),
+ ... os.path.join(bin, 'demo-script.py'),
+ ... os.path.join(bin, 'py.exe'),
+ ... os.path.join(bin, 'py-script.py')]
+ ... else:
+ ... scripts == [os.path.join(bin, 'demo'),
+ ... os.path.join(bin, 'py')]
+ True
+
+The py script simply runs the Python interactive interpreter with
the path set:
- >>> cat(bin, 'py-demo') # doctest: +NORMALIZE_WHITESPACE
+ >>> cat(bin, 'py') # doctest: +NORMALIZE_WHITESPACE
#!/usr/local/bin/python2.4
import sys
<BLANKLINE>
sys.path[0:0] = [
'/tmp/tmp5zS2Afsample-install/demo-0.3-py2.4.egg',
- '/tmp/tmp5zS2Afsample-install/demoneeded-1.1-py2.4.egg'
+ '/tmp/tmp5zS2Afsample-install/demoneeded-1.1-py2.4.egg',
]
<BLANKLINE>
_interactive = True
@@ -278,12 +336,12 @@
If invoked with a script name and arguments, it will run that script, instead.
An additional argumnet can be passed to define which scripts to install
-and to provie script names. The argument is a dictionary mapping
+and to provide script names. The argument is a dictionary mapping
original script names to new script names.
>>> bin = mkdtemp()
>>> scripts = zc.buildout.easy_install.scripts(
- ... ['demo==0.1'], ws, python2_4_executable, bin, dict(demo='run'))
+ ... ['demo'], ws, python2_4_executable, bin, dict(demo='run'))
>>> if sys.platform == 'win32':
... scripts == [os.path.join(bin, 'run.exe'),
@@ -304,7 +362,7 @@
to be included in the a generated script:
>>> scripts = zc.buildout.easy_install.scripts(
- ... ['demo==0.1'], ws, python2_4_executable, bin, dict(demo='run'),
+ ... ['demo'], ws, python2_4_executable, bin, dict(demo='run'),
... extra_paths=['/foo/bar'])
>>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE
@@ -314,7 +372,7 @@
sys.path[0:0] = [
'/tmp/xyzsample-install/demo-0.3-py2.3.egg',
'/tmp/xyzsample-install/demoneeded-1.1-py2.3.egg',
- '/foo/bar'
+ '/foo/bar',
]
<BLANKLINE>
import eggrecipedemo
@@ -330,7 +388,7 @@
parentheses in the call:
>>> scripts = zc.buildout.easy_install.scripts(
- ... ['demo==0.1'], ws, python2_4_executable, bin, dict(demo='run'),
+ ... ['demo'], ws, python2_4_executable, bin, dict(demo='run'),
... arguments='1, 2')
>>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE
@@ -338,7 +396,7 @@
import sys
sys.path[0:0] = [
'/tmp/xyzsample-install/demo-0.3-py2.3.egg',
- '/tmp/xyzsample-install/demoneeded-1.1-py2.3.egg'
+ '/tmp/xyzsample-install/demoneeded-1.1-py2.3.egg',
]
<BLANKLINE>
import eggrecipedemo
More information about the Checkins
mailing list