[Checkins] SVN: zc.buildout/branches/gary-4/ tests now pass in Windows (and still in Linux)
Gary Poster
gary.poster at canonical.com
Mon Feb 8 16:45:32 EST 2010
Log message for revision 108886:
tests now pass in Windows (and still in Linux)
Changed:
U zc.buildout/branches/gary-4/bootstrap/bootstrap.py
U zc.buildout/branches/gary-4/src/zc/buildout/easy_install.py
U zc.buildout/branches/gary-4/src/zc/buildout/easy_install.txt
U zc.buildout/branches/gary-4/src/zc/buildout/testing.py
U zc.buildout/branches/gary-4/src/zc/buildout/tests.py
U zc.buildout/branches/gary-4/z3c.recipe.scripts_/src/z3c/recipe/scripts/README.txt
U zc.buildout/branches/gary-4/z3c.recipe.scripts_/src/z3c/recipe/scripts/tests.py
-=-
Modified: zc.buildout/branches/gary-4/bootstrap/bootstrap.py
===================================================================
--- zc.buildout/branches/gary-4/bootstrap/bootstrap.py 2010-02-08 16:09:07 UTC (rev 108885)
+++ zc.buildout/branches/gary-4/bootstrap/bootstrap.py 2010-02-08 21:45:32 UTC (rev 108886)
@@ -110,8 +110,10 @@
import setuptools # A flag. Sometimes pkg_resources is installed alone.
import pkg_resources
except ImportError:
+ ez_code = urllib2.urlopen(
+ configuration['--ez_setup-source']).read().replace('\r\n', '\n')
ez = {}
- exec urllib2.urlopen(configuration['--ez_setup-source']).read() in ez
+ exec ez_code in ez
setuptools_args = dict(to_dir=configuration['--eggs'], download_delay=0)
if configuration['--download-base']:
setuptools_args['download_base'] = configuration['--download-base']
Modified: zc.buildout/branches/gary-4/src/zc/buildout/easy_install.py
===================================================================
--- zc.buildout/branches/gary-4/src/zc/buildout/easy_install.py 2010-02-08 16:09:07 UTC (rev 108885)
+++ zc.buildout/branches/gary-4/src/zc/buildout/easy_install.py 2010-02-08 21:45:32 UTC (rev 108886)
@@ -1300,13 +1300,16 @@
cmd.extend([
"-c", "import sys, os;"
"print repr([os.path.normpath(p) for p in sys.path if p])"])
+ # Windows needs some (as yet to be determined) part of the real env.
+ env = os.environ.copy()
+ env.update(kwargs)
_proc = subprocess.Popen(
- cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=kwargs)
+ cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
stdout, stderr = _proc.communicate();
if _proc.returncode:
raise RuntimeError(
'error trying to get system packages:\n%s' % (stderr,))
- res = eval(stdout)
+ res = eval(stdout.strip())
try:
res.remove('.')
except ValueError:
@@ -1506,10 +1509,52 @@
full_name = os.path.join(dest, name)
site_py_dest_string, rpsetup = _relative_path_and_setup(
full_name, [site_py_dest], relative_paths)
+ if sys.platform == 'win32':
+ windows_import = '\nimport subprocess'
+ # os.exec* is a mess on Windows, particularly if the path
+ # to the executable has spaces and the Python is using MSVCRT.
+ # The standard fix is to surround the executable's path with quotes,
+ # but that has been unreliable in testing.
+ #
+ # Here's a demonstration of the problem. Given a Python
+ # compiled with a MSVCRT-based compiler, such as the free Visual
+ # C++ 2008 Express Edition, and an executable path with spaces
+ # in it such as the below, we see the following.
+ #
+ # >>> import os
+ # >>> p0 = 'C:\\Documents and Settings\\Administrator\\My Documents\\Downloads\\Python-2.6.4\\PCbuild\\python.exe'
+ # >>> os.path.exists(p0)
+ # True
+ # >>> os.execv(p0, [])
+ # Traceback (most recent call last):
+ # File "<stdin>", line 1, in <module>
+ # OSError: [Errno 22] Invalid argument
+ #
+ # That seems like a standard problem. The standard solution is
+ # to quote the path (see, for instance
+ # http://bugs.python.org/issue436259). However, this solution,
+ # and other variations, fail:
+ #
+ # >>> p1 = '"C:\\Documents and Settings\\Administrator\\My Documents\\Downloads\\Python-2.6.4\\PCbuild\\python.exe"'
+ # >>> os.execv(p1, [])
+ # Traceback (most recent call last):
+ # File "<stdin>", line 1, in <module>
+ # OSError: [Errno 22] Invalid argument
+ #
+ # We simply use subprocess instead, since it handles everything
+ # nicely, and the transparency of exec* (that is, not running,
+ # perhaps unexpectedly, in a subprocess) is arguably not a
+ # necessity, at least for many use cases.
+ execute = 'subprocess.call(argv, env=environ)'
+ else:
+ windows_import = ''
+ execute = 'os.execve(sys.executable, argv, environ)'
contents = interpreter_template % dict(
- python = _safe_arg(executable),
- site_dest = site_py_dest_string,
- relative_paths_setup = rpsetup,
+ python=_safe_arg(executable),
+ site_dest=site_py_dest_string,
+ relative_paths_setup=rpsetup,
+ windows_import=windows_import,
+ execute=execute,
)
return _write_script(full_name, contents, 'interpreter')
@@ -1517,7 +1562,7 @@
%(relative_paths_setup)s
import os
-import sys
+import sys%(windows_import)s
argv = [sys.executable] + sys.argv[1:]
environ = os.environ.copy()
@@ -1525,7 +1570,7 @@
if environ.get('PYTHONPATH'):
path = os.pathsep.join([path, environ['PYTHONPATH']])
environ['PYTHONPATH'] = path
-os.execve(sys.executable, argv, environ)
+%(execute)s
'''
# End of script generation code.
Modified: zc.buildout/branches/gary-4/src/zc/buildout/easy_install.txt
===================================================================
--- zc.buildout/branches/gary-4/src/zc/buildout/easy_install.txt 2010-02-08 16:09:07 UTC (rev 108885)
+++ zc.buildout/branches/gary-4/src/zc/buildout/easy_install.txt 2010-02-08 21:45:32 UTC (rev 108886)
@@ -1094,12 +1094,11 @@
Here are some examples of the interpreter in use.
- >>> print system(interpreter_path + ' -c "print 16+26"')
+ >>> print call_py(interpreter_path, "print 16+26")
42
<BLANKLINE>
- >>> res = system(interpreter_path +
- ... ' -c "import sys, pprint; pprint.pprint(sys.path)"')
- >>> print res # doctest: +ELLIPSIS
+ >>> res = call_py(interpreter_path, "import sys; print sys.path")
+ >>> print res # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
['',
'/interpreter/eggs/demo-0.3-pyN.N.egg',
'/interpreter/eggs/demoneeded-1.1-pyN.N.egg',
@@ -1129,8 +1128,7 @@
>>> cat(sitecustomize_path)
import os
os.environ['FOO'] = 'bar baz bing shazam'
- >>> print system(interpreter_path +
- ... """ -c 'import os; print os.environ["FOO"]'""")
+ >>> print call_py(interpreter_path, "import os; print os.environ['FOO']")
bar baz bing shazam
<BLANKLINE>
@@ -1182,8 +1180,8 @@
The paths resolve in practice as you would expect.
- >>> print system(interpreter_path +
- ... ' -c "import sys, pprint; pprint.pprint(sys.path)"')
+ >>> print call_py(interpreter_path,
+ ... "import sys, pprint; pprint.pprint(sys.path)")
... # doctest: +ELLIPSIS
['',
'/interpreter/eggs/demo-0.3-py2.4.egg',
@@ -1210,8 +1208,8 @@
'/interpreter/other'
]...
- >>> print system(interpreter_path +
- ... ' -c "import sys, pprint; pprint.pprint(sys.path)"')
+ >>> print call_py(interpreter_path,
+ ... "import sys, pprint; pprint.pprint(sys.path)")
... # doctest: +ELLIPSIS
['',
'/interpreter/eggs/demo-0.3-pyN.N.egg',
@@ -1355,9 +1353,8 @@
this package give the feature a more thorough workout, but this should
give you an idea of the feature.
- >>> res = system(join(interpreter_dir, 'bin', 'py') +
- ... ' -c "import sys, pprint; pprint.pprint(sys.path)"')
- >>> print res # doctest: +ELLIPSIS
+ >>> res = call_py(interpreter_path, "import sys; print sys.path")
+ >>> print res # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
['',
'/interpreter/eggs/demo-0.3-py2.4.egg',
'/interpreter/eggs/demoneeded-1.1-py2.4.egg',
@@ -1434,7 +1431,10 @@
if __name__ == '__main__':
eggrecipedemo.main()
- >>> print system(join(interpreter_bin_dir, 'demo'))
+ >>> demo_call = join(interpreter_bin_dir, 'demo')
+ >>> if sys.platform == 'win32':
+ ... demo_call = '"%s"' % demo_call
+ >>> print system(demo_call)
3 1
<BLANKLINE>
Modified: zc.buildout/branches/gary-4/src/zc/buildout/testing.py
===================================================================
--- zc.buildout/branches/gary-4/src/zc/buildout/testing.py 2010-02-08 16:09:07 UTC (rev 108885)
+++ zc.buildout/branches/gary-4/src/zc/buildout/testing.py 2010-02-08 21:45:32 UTC (rev 108886)
@@ -106,6 +106,16 @@
e.close()
return result
+def call_py(interpreter, cmd, flags=None):
+ if sys.platform == 'win32':
+ args = ['"%s"' % arg for arg in (interpreter, flags, cmd) if arg]
+ args.insert(-1, '"-c"')
+ return system('"%s"' % ' '.join(args))
+ else:
+ cmd = repr(cmd)
+ return system(
+ ' '.join(arg for arg in (interpreter, flags, '-c', cmd) if arg))
+
def get(url):
return urllib2.urlopen(url).read()
@@ -336,6 +346,7 @@
tmpdir = tmpdir,
write = write,
system = system,
+ call_py = call_py,
get = get,
cd = (lambda *path: os.chdir(os.path.join(*path))),
join = os.path.join,
@@ -536,10 +547,14 @@
path = path[1:]
return '/' + path.replace(os.path.sep, '/')
+if sys.platform == 'win32':
+ sep = r'[\\/]' # Windows uses both sometimes.
+else:
+ sep = re.escape(os.path.sep)
normalize_path = (
re.compile(
- r'''[^'" \t\n\r]+\%(sep)s_[Tt][Ee][Ss][Tt]_\%(sep)s([^"' \t\n\r]+)'''
- % dict(sep=os.path.sep)),
+ r'''[^'" \t\n\r]+%(sep)s_[Tt][Ee][Ss][Tt]_%(sep)s([^"' \t\n\r]+)'''
+ % dict(sep=sep)),
_normalize_path,
)
Modified: zc.buildout/branches/gary-4/src/zc/buildout/tests.py
===================================================================
--- zc.buildout/branches/gary-4/src/zc/buildout/tests.py 2010-02-08 16:09:07 UTC (rev 108885)
+++ zc.buildout/branches/gary-4/src/zc/buildout/tests.py 2010-02-08 21:45:32 UTC (rev 108886)
@@ -1794,11 +1794,9 @@
version 0.3 and demoneeded version 1.1.
>>> py_path = make_py_with_system_install(make_py, sample_eggs)
- >>> print system(
- ... py_path + " -c '" +
- ... "import tellmy.version\n" +
- ... "print tellmy.version.__version__\n" +
- ... "'"),
+ >>> print call_py(
+ ... py_path,
+ ... "import tellmy.version; print tellmy.version.__version__"),
1.1
Now here's a setup that would expose the bug, using the
@@ -1832,11 +1830,9 @@
tellmy.version 1.1, and tellmy.fortune 1.0. tellmy.version 1.1 is installed.
>>> py_path = make_py_with_system_install(make_py, sample_eggs)
- >>> print system(
- ... py_path + " -c '" +
- ... "import tellmy.version\n" +
- ... "print tellmy.version.__version__\n" +
- ... "'")
+ >>> print call_py(
+ ... py_path,
+ ... "import tellmy.version; print tellmy.version.__version__")
1.1
<BLANKLINE>
@@ -1895,13 +1891,12 @@
we could not import tellmy.fortune at all. The following are the correct
results for the interpreter and for the script.
- >>> print system(
- ... join('bin', 'py') + " -c '" +
- ... "import tellmy.version\n" +
- ... "print tellmy.version.__version__\n" +
- ... "import tellmy.fortune\n" +
- ... "print tellmy.fortune.__version__\n" +
- ... "'") # doctest: +ELLIPSIS
+ >>> print call_py(
+ ... join('bin', 'py'),
+ ... "import tellmy.version; " +
+ ... "print tellmy.version.__version__; " +
+ ... "import tellmy.fortune; " +
+ ... "print tellmy.fortune.__version__") # doctest: +ELLIPSIS
1.0
1.0...
@@ -1961,11 +1956,9 @@
... zc.buildout.testing.sys_install(tmp, site_packages_path)
... finally:
... shutil.rmtree(tmp)
- >>> print system(
- ... py_path + " -c '" +
- ... "import tellmy.version\n" +
- ... "print tellmy.version.__version__\n" +
- ... "'")
+ >>> print call_py(
+ ... py_path,
+ ... "import tellmy.version; print tellmy.version.__version__")
1.0
<BLANKLINE>
>>> write('buildout.cfg',
@@ -3161,7 +3154,7 @@
'We have a develop egg: zc.buildout X.X.'),
(re.compile(r'\\[\\]?'), '/'),
(re.compile('WindowsError'), 'OSError'),
- (re.compile(r'\[Error 17\] Cannot create a file '
+ (re.compile(r'\[Error \d+\] Cannot create a file '
r'when that file already exists: '),
'[Errno 17] File exists: '
),
@@ -3215,6 +3208,10 @@
(re.compile('[-d] setuptools-\S+[.]egg'), 'setuptools.egg'),
(re.compile(r'\\[\\]?'), '/'),
(re.compile(r'\#!\S+\bpython\S*'), '#!/usr/bin/python'),
+ # Normalize generate_script's Windows interpreter to UNIX:
+ (re.compile(r'\nimport subprocess\n'), '\n'),
+ (re.compile('subprocess\\.call\\(argv, env=environ\\)'),
+ 'os.execve(sys.executable, argv, environ)'),
]+(sys.version_info < (2, 5) and [
(re.compile('.*No module named runpy.*', re.S), ''),
(re.compile('.*usage: pdb.py scriptfile .*', re.S), ''),
Modified: zc.buildout/branches/gary-4/z3c.recipe.scripts_/src/z3c/recipe/scripts/README.txt
===================================================================
--- zc.buildout/branches/gary-4/z3c.recipe.scripts_/src/z3c/recipe/scripts/README.txt 2010-02-08 16:09:07 UTC (rev 108885)
+++ zc.buildout/branches/gary-4/z3c.recipe.scripts_/src/z3c/recipe/scripts/README.txt 2010-02-08 21:45:32 UTC (rev 108886)
@@ -138,7 +138,8 @@
Generated interpreter '/sample-buildout/bin/py'.
In both cases, the bin/py script works by restarting Python after
-specifying a special path in PYTHONPATH.
+specifying a special path in PYTHONPATH. This example shows the UNIX version;
+the Windows version actually uses subprocess instead.
>>> cat(sample_buildout, 'bin', 'py') # doctest: +NORMALIZE_WHITESPACE
#!/usr/bin/python2.4 -S
Modified: zc.buildout/branches/gary-4/z3c.recipe.scripts_/src/z3c/recipe/scripts/tests.py
===================================================================
--- zc.buildout/branches/gary-4/z3c.recipe.scripts_/src/z3c/recipe/scripts/tests.py 2010-02-08 16:09:07 UTC (rev 108885)
+++ zc.buildout/branches/gary-4/z3c.recipe.scripts_/src/z3c/recipe/scripts/tests.py 2010-02-08 21:45:32 UTC (rev 108886)
@@ -270,6 +270,10 @@
(re.compile(r'eggs\\\\demo'), 'eggs/demo'),
(re.compile(r'[a-zA-Z]:\\\\foo\\\\bar'), '/foo/bar'),
(re.compile(r'\#!\S+\bpython\S*'), '#!/usr/bin/python'),
+ # Normalize generate_script's Windows interpreter to UNIX:
+ (re.compile(r'\nimport subprocess\n'), '\n'),
+ (re.compile('subprocess\\.call\\(argv, env=environ\\)'),
+ 'os.execve(sys.executable, argv, environ)'),
])
),
doctest.DocTestSuite(
@@ -279,6 +283,7 @@
zc.buildout.testing.normalize_path,
zc.buildout.testing.normalize_endings,
zc.buildout.testing.normalize_egg_py,
+ (re.compile(r'[a-zA-Z]:\\\\foo\\\\bar'), '/foo/bar'),
]),
),
More information about the checkins
mailing list