diff --git a/CHANGELOG b/CHANGELOG index 66ba10cea..4d3f5ab03 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,20 +1,29 @@ -$Id: CHANGELOG 57429 2008-08-18 15:08:39Z hpk $ +$Id: CHANGELOG 57540 2008-08-21 10:18:58Z hpk $ Changes between 0.9.1 and 0.9.2 =============================== * refined installation and metadata, created new setup.py, - now based on setuptools/ez_setup (by flipping a bit you - can use distutils). + now based on setuptools/ez_setup (thanks to Ralf Schmitt + for his support). * improved the way of making py.* scripts available in windows environments, they are now added to the Scripts directory as ".cmd" files. -* improved py.execnet bootstrapping on windows +* py.path.svnwc.status() now is more complete and + uses xml output from the 'svn' command if available + (Guido Wesdorp) + +* fix for py.path.svn* to work with svn 1.5 + (Chris Lamb) + +* fix path.relto(otherpath) method on windows to + use normcase for checking if a path is relative. * py.test's traceback is better parseable from editors (follows the filenames:LINENO: MSG convention) + (thanks to Osmo Salomaa) * fix to javascript-generation, "py.test --runbrowser" should work more reliably now diff --git a/MANIFEST b/MANIFEST index ba6bb5d8d..f377e8d8a 100644 --- a/MANIFEST +++ b/MANIFEST @@ -61,13 +61,20 @@ py/apigen/tracer/testing/test_docgen.py py/apigen/tracer/testing/test_model.py py/apigen/tracer/testing/test_package.py py/apigen/tracer/tracer.py +py/bin/_docgen.py py/bin/_findpy.py +py/bin/_genscripts.py py/bin/py.cleanup py/bin/py.countloc py/bin/py.lookup py/bin/py.rest py/bin/py.test py/bin/py.which +py/bin/win32/py.cleanup.cmd +py/bin/win32/py.countloc.cmd +py/bin/win32/py.lookup.cmd +py/bin/win32/py.rest.cmd +py/bin/win32/py.test.cmd py/builtin/__init__.py py/builtin/enumerate.py py/builtin/exception.py @@ -100,6 +107,14 @@ py/c-extension/greenlet/test_generator_nested.py py/c-extension/greenlet/test_greenlet.py py/c-extension/greenlet/test_remote.py py/c-extension/greenlet/test_throw.py +py/cmdline/__init__.py +py/cmdline/pycleanup.py +py/cmdline/pycountloc.py +py/cmdline/pylookup.py +py/cmdline/pyrest.py +py/cmdline/pytest.py +py/cmdline/testing/__init__.py +py/cmdline/testing/test_generic.py py/code/__init__.py py/code/code.py py/code/excinfo.py @@ -419,4 +434,5 @@ py/xmlobj/testing/test_html.py py/xmlobj/testing/test_xml.py py/xmlobj/visit.py py/xmlobj/xml.py +setup.cfg setup.py \ No newline at end of file diff --git a/_findpy.py b/_findpy.py deleted file mode 100755 index c1e208fae..000000000 --- a/_findpy.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python - -# -# find and import a version of 'py' -# -import sys -import os -from os.path import dirname as opd, exists, join, basename, abspath - -def searchpy(current): - while 1: - last = current - initpy = join(current, '__init__.py') - if not exists(initpy): - pydir = join(current, 'py') - # recognize py-package and ensure it is importable - if exists(pydir) and exists(join(pydir, '__init__.py')): - #for p in sys.path: - # if p == current: - # return True - if current != sys.path[0]: # if we are already first, then ok - print >>sys.stderr, "inserting into sys.path:", current - sys.path.insert(0, current) - return True - current = opd(current) - if last == current: - return False - -if not searchpy(abspath(os.curdir)): - if not searchpy(opd(abspath(sys.argv[0]))): - if not searchpy(opd(__file__)): - pass # let's hope it is just on sys.path - -import py - -if __name__ == '__main__': - print "py lib is at", py.__file__ diff --git a/py/LICENSE b/py/LICENSE index 8bd11cfea..e8f33e450 100644 --- a/py/LICENSE +++ b/py/LICENSE @@ -16,6 +16,7 @@ copyrighted by one or more of the following people and organizations: Contributors include:: Samuele Pedroni + Chris Lamb Harald Armin Massa Ralf Schmitt Ian Bicking diff --git a/py/__init__.py b/py/__init__.py index 9c6fa36a8..1c94272e0 100644 --- a/py/__init__.py +++ b/py/__init__.py @@ -1,9 +1,24 @@ # -*- coding: utf-8 -*- """ -the py lib is a development support library featuring -py.test, ad-hoc distributed execution, micro-threads -and svn abstractions. +The py lib is a development support library featuring these tools and APIs: + +- `py.test`_: cross-project testing tool with many advanced features +- `py.execnet`_: ad-hoc code distribution to SSH, Socket and local sub processes +- `py.magic.greenlet`_: micro-threads on standard CPython ("stackless-light") and PyPy +- `py.path`_: path abstractions over local and subversion files +- `py.code`_: dynamic code compile and traceback printing support + +The py lib and its tools should work well on Linux, Win32, +OSX, Python versions 2.3-2.6. For questions please go to +http://pylib.org/contact.html + +.. _`py.test`: http://pylib.org/test.html +.. _`py.execnet`: http://pylib.org/execnet.html +.. _`py.magic.greenlet`: http://pylib.org/greenlet.html +.. _`py.path`: http://pylib.org/path.html +.. _`py.code`: http://pylib.org/code.html + """ from initpkg import initpkg @@ -11,18 +26,18 @@ version = "1.0.0a1" initpkg(__name__, description = "pylib and py.test: agile development and test support library", - revision = int('$LastChangedRevision: 57529 $'.split(':')[1][:-1]), - lastchangedate = '$LastChangedDate: 2008-08-21 09:48:44 +0200 (Thu, 21 Aug 2008) $', + revision = int('$LastChangedRevision: 57540 $'.split(':')[1][:-1]), + lastchangedate = '$LastChangedDate: 2008-08-21 12:18:58 +0200 (Thu, 21 Aug 2008) $', version = version, url = "http://pylib.org", - download_url = "http://pypi.python.org/pypi?:action=display&name=py", + download_url = "http://codespeak.net/py/0.9.2/download.html", license = "MIT license", platforms = ['unix', 'linux', 'osx', 'cygwin', 'win32'], author = "holger krekel, Guido Wesdorp, Carl Friedrich Bolz, Armin Rigo, Maciej Fijalkowski & others", author_email = "holger at merlinux.eu, py-dev at codespeak.net", long_description = globals()['__doc__'], classifiers = [ - "Development Status :: 3 - Alpha", + "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: POSIX", @@ -38,6 +53,13 @@ initpkg(__name__, # EXPORTED API exportdefs = { + # py lib cmdline tools + 'cmdline.pytest' : ('./cmdline/pytest.py', 'main',), + 'cmdline.pyrest' : ('./cmdline/pyrest.py', 'main',), + 'cmdline.pylookup' : ('./cmdline/pylookup.py', 'main',), + 'cmdline.pycountloc' : ('./cmdline/pycountloc.py', 'main',), + 'cmdline.pycleanup' : ('./cmdline/pycleanup.py', 'main',), + # helpers for use from test functions or collectors 'test.__doc__' : ('./test/__init__.py', '__doc__'), 'test.raises' : ('./test/outcome.py', 'raises'), diff --git a/py/apigen/tracer/docstorage.py b/py/apigen/tracer/docstorage.py index b0d9f31ea..4b7b9650e 100644 --- a/py/apigen/tracer/docstorage.py +++ b/py/apigen/tracer/docstorage.py @@ -21,8 +21,21 @@ def pkg_to_dict(module): for key, value in defs.iteritems(): chain = key.split('.') base = module - for elem in chain: - base = getattr(base, elem) + # XXX generalize this: + # a bit of special casing for greenlets which are + # not available on all the platforms that python/py + # lib runs + try: + for elem in chain: + base = getattr(base, elem) + except RuntimeError, exc: + if elem == "greenlet": + print exc.__class__.__name__, exc + print "Greenlets not supported on this platform. Skipping apigen doc for this module" + continue + else: + raise + if value[1] == '*': d.update(get_star_import_tree(base, key)) else: diff --git a/py/bin/_docgen.py b/py/bin/_docgen.py new file mode 100755 index 000000000..1438efbbc --- /dev/null +++ b/py/bin/_docgen.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +""" quick tool to get documentation + apigen docs generated + + given a certain targetpath, apigen docs will be placed in 'apigen', + + user can choose to only build either docs or apigen docs: in this case, + the navigation bar will be adjusted +""" + +from _findpy import py +pypath = py.__pkg__.getpath() +print "using pypath", pypath +import os + +def run_tests(path, envvars='', args=''): + pytestpath = pypath.join('bin/py.test') + cmd = ('PYTHONPATH="%s" %s python "%s" %s "%s"' % + (pypath.dirpath(), envvars, pytestpath, args, path)) + print cmd + errno = os.system(cmd) + assert not errno + +def build_apigen_docs(targetpath, testargs=''): + run_tests(pypath, + 'APIGEN_TARGET="%s/apigen" APIGEN_DOCRELPATH="../"' % ( + targetpath,), + '%s --apigen="%s/apigen/apigen.py"' % (testargs, pypath)) + +def build_docs(targetpath, testargs): + docpath = pypath.join('doc') + run_tests(docpath, '', + testargs + ' --forcegen --apigen="%s/apigen/apigen.py"' % (pypath,)) + docpath.copy(targetpath) + +def build_nav(targetpath, docs=True, api=True): + pass + +def build(targetpath, docs=True, api=True, testargs=''): + targetpath.ensure(dir=True) + if docs: + print 'building docs' + build_docs(targetpath, testargs) + if api: + print 'building api' + build_apigen_docs(targetpath, testargs) + + +if __name__ == '__main__': + import sys + if len(sys.argv) == 1: + print 'usage: %s [options]' + print + print ' targetdir: a path to a directory (created if it doesn\'t' + print ' exist) where the docs are put' + print ' options: options passed to py.test when running the tests' + sys.exit(1) + targetpath = py.path.local(sys.argv[1]) + args = ' '.join(sys.argv[2:]) + build(targetpath, True, True, args) + diff --git a/py/bin/_genscripts.py b/py/bin/_genscripts.py new file mode 100644 index 000000000..b6a37b85b --- /dev/null +++ b/py/bin/_genscripts.py @@ -0,0 +1,34 @@ +from _findpy import py + +mydir = py.magic.autopath().dirpath() + +def getbasename(name): + assert name[:2] == "py" + return "py." + name[2:] + +def genscript_unix(name): + basename = getbasename(name) + path = mydir.join(basename) + path.write(py.code.Source(""" + #!/usr/bin/env python + from _findpy import py + py.cmdline.%s() + """ % name).strip()) + path.chmod(0755) + +def genscript_windows(name): + basename = getbasename(name) + winbasename = basename + ".cmd" + path = mydir.join("win32").join(winbasename) + path.write(py.code.Source(""" + @echo off + python "%%~dp0\..\%s" %%* + """ % (basename)).strip()) + +if __name__ == "__main__": + for name in dir(py.cmdline): + if name[0] != "_": + genscript_unix(name) + genscript_windows(name) + + diff --git a/py/bin/py.cleanup b/py/bin/py.cleanup index fbb4a593d..b28510028 100755 --- a/py/bin/py.cleanup +++ b/py/bin/py.cleanup @@ -1,24 +1,3 @@ -#!/usr/bin/env python - -"""\ -py.cleanup [PATH] - -Delete pyc file recursively, starting from PATH (which defaults to the current -working directory). Don't follow links and don't recurse into directories with -a ".". -""" -from _findpy import py -import py - -parser = py.compat.optparse.OptionParser(usage=__doc__) - -if __name__ == '__main__': - (options, args) = parser.parse_args() - - if not args: - args = ["."] - for arg in args: - path = py.path.local(arg) - print "cleaning path", path - for x in path.visit('*.pyc', lambda x: x.check(dotfile=0, link=0)): - x.remove() +#!/usr/bin/env python +from _findpy import py +py.cmdline.pycleanup() \ No newline at end of file diff --git a/py/bin/py.countloc b/py/bin/py.countloc index d4bde42d7..cf06529b9 100755 --- a/py/bin/py.countloc +++ b/py/bin/py.countloc @@ -1,23 +1,3 @@ #!/usr/bin/env python - -# hands on script to compute the non-empty Lines of Code -# for tests and non-test code - -"""\ -py.countloc [PATHS] - -Count (non-empty) lines of python code and number of python files recursively -starting from a list of paths given on the command line (starting from the -current working directory). Distinguish between test files and normal ones and -report them separately. -""" -from _findpy import py -import py -from py.compat import optparse -from py.__.misc.cmdline.countloc import countloc - -parser = optparse.OptionParser(usage=__doc__) - -if __name__ == '__main__': - (options, args) = parser.parse_args() - countloc(args) +from _findpy import py +py.cmdline.pycountloc() \ No newline at end of file diff --git a/py/bin/py.lookup b/py/bin/py.lookup index 36aa645b3..c4af1cfbf 100755 --- a/py/bin/py.lookup +++ b/py/bin/py.lookup @@ -1,79 +1,3 @@ -#!/usr/bin/env python - -"""\ -py.lookup SEARCH_STRING [options] - -Looks recursively at Python files for a SEARCH_STRING, starting from the -present working directory. Prints the line, with the filename and line-number -prepended.""" - -import sys, os -sys.path.insert(0, os.path.dirname(__file__)) +#!/usr/bin/env python from _findpy import py -try: - from py.__.io.terminalwriter import ansi_print, terminal_width -except ImportError: - from py.__.misc.terminal_helper import ansi_print, terminal_width -import re - -curdir = py.path.local() -def rec(p): - return p.check(dotfile=0) - -optparse = py.compat.optparse - -parser = optparse.OptionParser(usage=__doc__) -parser.add_option("-i", "--ignore-case", action="store_true", dest="ignorecase", - help="ignore case distinctions") -parser.add_option("-C", "--context", action="store", type="int", dest="context", - default=0, help="How many lines of output to show") - -def find_indexes(search_line, string): - indexes = [] - before = 0 - while 1: - i = search_line.find(string, before) - if i == -1: - break - indexes.append(i) - before = i + len(string) - return indexes - - -if __name__ == '__main__': - (options, args) = parser.parse_args() - string = args[0] - if options.ignorecase: - string = string.lower() - for x in curdir.visit('*.py', rec): - try: - s = x.read() - except py.error.ENOENT: - pass # whatever, probably broken link (ie emacs lock) - searchs = s - if options.ignorecase: - searchs = s.lower() - if s.find(string) != -1: - lines = s.splitlines() - if options.ignorecase: - searchlines = s.lower().splitlines() - else: - searchlines = lines - for i, (line, searchline) in enumerate(zip(lines, searchlines)): - indexes = find_indexes(searchline, string) - if not indexes: - continue - if not options.context: - sys.stdout.write("%s:%d: " %(x.relto(curdir), i+1)) - last_index = 0 - for index in indexes: - sys.stdout.write(line[last_index: index]) - ansi_print(line[index: index+len(string)], - file=sys.stdout, esc=31, newline=False) - last_index = index + len(string) - sys.stdout.write(line[last_index:] + "\n") - else: - context = (options.context)/2 - for count in range(max(0, i-context), min(len(lines) - 1, i+context+1)): - print "%s:%d: %s" %(x.relto(curdir), count+1, lines[count].rstrip()) - print "-" * terminal_width +py.cmdline.pylookup() \ No newline at end of file diff --git a/py/bin/py.rest b/py/bin/py.rest index fbf230874..fb6ee57c2 100755 --- a/py/bin/py.rest +++ b/py/bin/py.rest @@ -1,79 +1,3 @@ #!/usr/bin/env python -""" -invoke - - py.rest filename1.txt directory - -to generate html files from ReST. - -It is also possible to generate pdf files using the --topdf option. - -http://docutils.sourceforge.net/docs/user/rst/quickref.html - -""" - -import os, sys from _findpy import py -from py.__.misc import rest -from py.__.rest import directive -from py.__.rest.latex import process_rest_file, process_configfile - - -if hasattr(sys.stdout, 'fileno') and os.isatty(sys.stdout.fileno()): - def log(msg): - print msg -else: - def log(msg): - pass - -optparse = py.compat.optparse - -parser = optparse.OptionParser(usage=__doc__) -parser.add_option("--topdf", action="store_true", dest="topdf", default=False, - help="generate pdf files") -parser.add_option("--stylesheet", dest="stylesheet", default=None, - help="use specified latex style sheet") -parser.add_option("--debug", action="store_true", dest="debug", - default=False, - help="print debug output and don't delete files") - - -if __name__=='__main__': - (options, args) = parser.parse_args() - - if len(args) == 0: - filenames = [py.path.svnwc()] - else: - filenames = [py.path.svnwc(x) for x in args] - - if options.topdf: - directive.set_backend_and_register_directives("latex") - - for p in filenames: - if not p.check(): - log("path %s not found, ignoring" % p) - continue - def fil(p): - return p.check(fnmatch='*.txt', versioned=True) - def rec(p): - return p.check(dotfile=0) - if p.check(dir=1): - for x in p.visit(fil, rec): - rest.process(x) - elif p.check(file=1): - if p.ext == ".rst2pdfconfig": - directive.set_backend_and_register_directives("latex") - process_configfile(p, options.debug) - else: - if options.topdf: - cfg = p.new(ext=".rst2pdfconfig") - if cfg.check(): - print "using config file %s" % (cfg, ) - process_configfile(cfg, options.debug) - else: - process_rest_file(p.localpath, - options.stylesheet, - options.debug) - else: - rest.process(p) - +py.cmdline.pyrest() \ No newline at end of file diff --git a/py/bin/py.test b/py/bin/py.test index 5c16839f7..81ee54297 100755 --- a/py/bin/py.test +++ b/py/bin/py.test @@ -1,4 +1,3 @@ -#!/usr/bin/env python - -from _findpy import py -py.test.cmdline.main() +#!/usr/bin/env python +from _findpy import py +py.cmdline.pytest() \ No newline at end of file diff --git a/py/bin/win32/py.cleanup.cmd b/py/bin/win32/py.cleanup.cmd new file mode 100644 index 000000000..e5d97b998 --- /dev/null +++ b/py/bin/win32/py.cleanup.cmd @@ -0,0 +1,2 @@ +@echo off +python "%~dp0\..\py.cleanup" %* \ No newline at end of file diff --git a/py/bin/win32/py.countloc.cmd b/py/bin/win32/py.countloc.cmd new file mode 100644 index 000000000..82a1f3239 --- /dev/null +++ b/py/bin/win32/py.countloc.cmd @@ -0,0 +1,2 @@ +@echo off +python "%~dp0\..\py.countloc" %* \ No newline at end of file diff --git a/py/bin/win32/py.lookup.cmd b/py/bin/win32/py.lookup.cmd new file mode 100644 index 000000000..a8fa51728 --- /dev/null +++ b/py/bin/win32/py.lookup.cmd @@ -0,0 +1,2 @@ +@echo off +python "%~dp0\..\py.lookup" %* \ No newline at end of file diff --git a/py/bin/win32/py.rest.cmd b/py/bin/win32/py.rest.cmd new file mode 100644 index 000000000..647e91c56 --- /dev/null +++ b/py/bin/win32/py.rest.cmd @@ -0,0 +1,2 @@ +@echo off +python "%~dp0\..\py.rest" %* \ No newline at end of file diff --git a/py/bin/win32/py.test.cmd b/py/bin/win32/py.test.cmd new file mode 100644 index 000000000..36a1b9dae --- /dev/null +++ b/py/bin/win32/py.test.cmd @@ -0,0 +1,2 @@ +@echo off +python "%~dp0\..\py.test" %* \ No newline at end of file diff --git a/py/cmdline/__init__.py b/py/cmdline/__init__.py new file mode 100644 index 000000000..792d60054 --- /dev/null +++ b/py/cmdline/__init__.py @@ -0,0 +1 @@ +# diff --git a/py/cmdline/pycleanup.py b/py/cmdline/pycleanup.py new file mode 100755 index 000000000..953d28137 --- /dev/null +++ b/py/cmdline/pycleanup.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +"""\ +py.cleanup [PATH] + +Delete pyc file recursively, starting from PATH (which defaults to the current +working directory). Don't follow links and don't recurse into directories with +a ".". +""" +import py + +def main(): + parser = py.compat.optparse.OptionParser(usage=__doc__) + (options, args) = parser.parse_args() + if not args: + args = ["."] + for arg in args: + path = py.path.local(arg) + print "cleaning path", path + for x in path.visit('*.pyc', lambda x: x.check(dotfile=0, link=0)): + x.remove() diff --git a/py/cmdline/pycountloc.py b/py/cmdline/pycountloc.py new file mode 100755 index 000000000..779d4e75a --- /dev/null +++ b/py/cmdline/pycountloc.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +# hands on script to compute the non-empty Lines of Code +# for tests and non-test code + +"""\ +py.countloc [PATHS] + +Count (non-empty) lines of python code and number of python files recursively +starting from a list of paths given on the command line (starting from the +current working directory). Distinguish between test files and normal ones and +report them separately. +""" +from _findpy import py +import py +from py.compat import optparse +from py.__.misc.cmdline.countloc import countloc + +def main(): + parser = optparse.OptionParser(usage=__doc__) + (options, args) = parser.parse_args() + countloc(args) diff --git a/py/cmdline/pylookup.py b/py/cmdline/pylookup.py new file mode 100755 index 000000000..6b20b82a4 --- /dev/null +++ b/py/cmdline/pylookup.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python + +"""\ +py.lookup SEARCH_STRING [options] + +Looks recursively at Python files for a SEARCH_STRING, starting from the +present working directory. Prints the line, with the filename and line-number +prepended.""" + +import sys, os +import py +from py.__.misc.terminal_helper import ansi_print, terminal_width +import re + +curdir = py.path.local() +def rec(p): + return p.check(dotfile=0) + +optparse = py.compat.optparse + +parser = optparse.OptionParser(usage=__doc__) +parser.add_option("-i", "--ignore-case", action="store_true", dest="ignorecase", + help="ignore case distinctions") +parser.add_option("-C", "--context", action="store", type="int", dest="context", + default=0, help="How many lines of output to show") + +def find_indexes(search_line, string): + indexes = [] + before = 0 + while 1: + i = search_line.find(string, before) + if i == -1: + break + indexes.append(i) + before = i + len(string) + return indexes + +def main(): + (options, args) = parser.parse_args() + string = args[0] + if options.ignorecase: + string = string.lower() + for x in curdir.visit('*.py', rec): + try: + s = x.read() + except py.error.ENOENT: + pass # whatever, probably broken link (ie emacs lock) + searchs = s + if options.ignorecase: + searchs = s.lower() + if s.find(string) != -1: + lines = s.splitlines() + if options.ignorecase: + searchlines = s.lower().splitlines() + else: + searchlines = lines + for i, (line, searchline) in enumerate(zip(lines, searchlines)): + indexes = find_indexes(searchline, string) + if not indexes: + continue + if not options.context: + sys.stdout.write("%s:%d: " %(x.relto(curdir), i+1)) + last_index = 0 + for index in indexes: + sys.stdout.write(line[last_index: index]) + ansi_print(line[index: index+len(string)], + file=sys.stdout, esc=31, newline=False) + last_index = index + len(string) + sys.stdout.write(line[last_index:] + "\n") + else: + context = (options.context)/2 + for count in range(max(0, i-context), min(len(lines) - 1, i+context+1)): + print "%s:%d: %s" %(x.relto(curdir), count+1, lines[count].rstrip()) + print "-" * terminal_width diff --git a/py/cmdline/pyrest.py b/py/cmdline/pyrest.py new file mode 100755 index 000000000..1032dc653 --- /dev/null +++ b/py/cmdline/pyrest.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +""" +invoke + + py.rest filename1.txt directory + +to generate html files from ReST. + +It is also possible to generate pdf files using the --topdf option. + +http://docutils.sourceforge.net/docs/user/rst/quickref.html + +""" + +import os, sys +import py + +if hasattr(sys.stdout, 'fileno') and os.isatty(sys.stdout.fileno()): + def log(msg): + print msg +else: + def log(msg): + pass + +optparse = py.compat.optparse + +parser = optparse.OptionParser(usage=__doc__) +parser.add_option("--topdf", action="store_true", dest="topdf", default=False, + help="generate pdf files") +parser.add_option("--stylesheet", dest="stylesheet", default=None, + help="use specified latex style sheet") +parser.add_option("--debug", action="store_true", dest="debug", + default=False, + help="print debug output and don't delete files") + + +def main(): + try: + from py.__.misc import rest + from py.__.rest import directive + from py.__.rest.latex import process_rest_file, process_configfile + except ImportError, e: + print str(e) + sys.exit(1) + + (options, args) = parser.parse_args() + + if len(args) == 0: + filenames = [py.path.svnwc()] + else: + filenames = [py.path.svnwc(x) for x in args] + + if options.topdf: + directive.set_backend_and_register_directives("latex") + + for p in filenames: + if not p.check(): + log("path %s not found, ignoring" % p) + continue + def fil(p): + return p.check(fnmatch='*.txt', versioned=True) + def rec(p): + return p.check(dotfile=0) + if p.check(dir=1): + for x in p.visit(fil, rec): + rest.process(x) + elif p.check(file=1): + if p.ext == ".rst2pdfconfig": + directive.set_backend_and_register_directives("latex") + process_configfile(p, options.debug) + else: + if options.topdf: + cfg = p.new(ext=".rst2pdfconfig") + if cfg.check(): + print "using config file %s" % (cfg, ) + process_configfile(cfg, options.debug) + else: + process_rest_file(p.localpath, + options.stylesheet, + options.debug) + else: + rest.process(p) + diff --git a/py/cmdline/pytest.py b/py/cmdline/pytest.py new file mode 100755 index 000000000..30322a3cf --- /dev/null +++ b/py/cmdline/pytest.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python +import py + +def main(): + py.test.cmdline.main() diff --git a/py/cmdline/testing/__init__.py b/py/cmdline/testing/__init__.py new file mode 100644 index 000000000..16e385321 --- /dev/null +++ b/py/cmdline/testing/__init__.py @@ -0,0 +1 @@ +# diff --git a/py/cmdline/testing/test_generic.py b/py/cmdline/testing/test_generic.py new file mode 100644 index 000000000..8fa58fa7e --- /dev/null +++ b/py/cmdline/testing/test_generic.py @@ -0,0 +1,55 @@ +import py +import sys + +binpath = py.path.local(py.__file__).dirpath("bin") +binwinpath = binpath.join("win32") + +def setup_module(mod): + mod.tmpdir = py.test.ensuretemp(__name__) + mod.iswin32 = sys.platform == "win32" + +def checkmain(name): + main = getattr(py.cmdline, name) + assert callable(main) + assert name[:2] == "py" + scriptname = "py." + name[2:] + assert binpath.join(scriptname).check() + assert binwinpath.join(scriptname + ".cmd").check() + +def checkprocess(script): + assert script.check() + old = tmpdir.ensure(script.basename, dir=1).chdir() + try: + if iswin32: + cmd = script.basename + else: + cmd = "%s" %(script, ) + + if script.basename.startswith("py.lookup"): + cmd += " hello" + print "executing", script + try: + py.process.cmdexec(cmd) + except py.process.cmdexec.Error, e: + if cmd.find("py.rest") != -1 and \ + e.out.find("module named") != -1: + return + raise + + finally: + old.chdir() + +def test_cmdline_namespace(): + for name in dir(py.cmdline): + if name[0] != "_": + yield checkmain, name + +def test_script_invocation(): + if iswin32: + for script in binwinpath.listdir("py.*"): + assert script.ext == ".cmd" + yield checkprocess, script + else: + for script in binpath.listdir("py.*"): + yield checkprocess, script + diff --git a/py/doc/download.txt b/py/doc/download.txt index 346eefd31..9545e567b 100644 --- a/py/doc/download.txt +++ b/py/doc/download.txt @@ -1,104 +1,71 @@ -Download and Installation of the py lib -=============================================== -.. contents:: -.. sectnum:: -Downloading a tar/zip file and installing it +"easy_install py" =================================================== -The latest public release: +With a working `setuptools installation`_ you can install from the command line:: - `download py-0.9.0.tar.gz`_ - `download py-0.9.0.zip`_ + easy_install py -.. _`download py-0.9.0.tar.gz`: http://codespeak.net/download/py/py-0.9.0.tar.gz -.. _`download py-0.9.0.zip`: http://codespeak.net/download/py/py-0.9.0.zip +to get the latest release of the py lib. On non-Windows systems you will +need a working C-compiler in order to successfully complete this step. +The py lib and its tools are expected to work well on Linux, Windows +and OSX, Python versions 2.3, 2.4, 2.5 and 2.6. -The py lib can be `globally installed via setup.py`_ -or `used locally`_. +**IMPORTANT NOTE**: if you are using Windows and have previous +installations of the py lib on your system, please download +and execute http://codespeak.net/svn/py/build/winpathclean.py +This will check that no previous files are getting in the way. +(Unfortunately we don't know about a way to execute this +code automatically during the above install). -WARNING: win32 there is no pre-packaged c-extension -module (greenlet) yet and thus greenlets will not work -out of the box. +.. _`setuptools installation`: http://pypi.python.org/pypi/setuptools -Getting (and updating) via subversion --------------------------------------------- +Downloading a tar/zip archive and installing that +=================================================== -Use Subversion to checkout the latest 0.9.x stable release: +Go to the project pages and download a tar or zip file: - svn co http://codespeak.net/svn/py/release/0.9.x py-0.9.x + http://pypi.python.org/pypi/py/ -to obtain the complete code and documentation source. - -If you experience problems with the subversion checkout e.g. -because you have a http-proxy in between that doesn't proxy -DAV requests you can try to use "codespeak.net:8080" instead -of just "codespeak.net". Alternatively, you may tweak -your local subversion installation. - -If you want to follow stable snapshots -then you may use the equivalent of this invocation: - - svn co http://codespeak.net/svn/py/dist py-dist - - -.. _`globally installed via setup.py`: - -Installation via setup.py ------------------------------- - -Go to your unpacked/checked out directory -and issue: +and unpack it to a directory, where you then type:: python setup.py install +If you don't have a working C-compiler you can do:: -.. _`used locally`: + python setup.py install_lib -Local Installation/Usage ------------------------------- +You will then not be able to use greenlets but otherwise +should be fine. -You need to put the checkout-directory into your ``PYTHONPATH`` -and you want to have the ``py-dist/py/bin/py.test`` script in -your (unixish) system path, which lets you execute test files -and directories. +Installing from subversion / develop mode +============================================ -There is a convenient way for Bash/Shell based systems -to setup the ``PYTHONPATH`` as well as the shell ``PATH``, insert:: +To follow development or help with fixing things +for the next release, checkout the complete code +and documentation source:: - eval `python ~/path/to/py-dist/py/env.py` + svn co http://codespeak.net/svn/py/release/0.9.x py-0.9.x -into your ``.bash_profile``. Of course, you need to -specify your own checkout-directory. +You should then be able to issue:: + python setup.py develop -.. _`svn-external scenario`: +and work with the local version. -The py lib as an svn external -------------------------------------------------------- +If this doesn't work for you then you can also +source (linux) or execute (windows) some scripts +that set environment variables for using your checkout. +You can execute: -Add the py lib as an external to your project `DIRECTORY` -which contains your svn-controlled root package:: + python ~/path/to/checkout/py/env.py - svn propedit 'svn:externals' DIRECTORY +or on windows: -which will open an editor where you can add -the following line: + \\path\\to\\checkout\\py\\env.cmd - py http://codespeak.net/svn/py/dist - -This will make your projcet automatically use the -most recent stable snapshot of the py lib. - -Alternatively you may use this url for -integrating the development version: - - http://codespeak.net/svn/py/trunk - -or the next one for following the e.g. the 0.9 release branch - - http://codespeak.net/svn/py/release/0.9.x +to get settings for PYTHONPATH and PATH. py subversion directory structure diff --git a/py/doc/impl-test.txt b/py/doc/impl-test.txt index c570280e8..ab8c3ec3a 100644 --- a/py/doc/impl-test.txt +++ b/py/doc/impl-test.txt @@ -5,8 +5,6 @@ Implementation and Customization of ``py.test`` .. contents:: .. sectnum:: - - .. _`basicpicture`: @@ -71,6 +69,12 @@ By default all directories not starting with a dot are traversed, looking for ``test_*.py`` and ``*_test.py`` files. Those files are imported under their `package name`_. +The Module collector looks for test functions +and test classes and methods. Test functions and methods +are prefixed ``test`` by default. Test classes must +start with a capitalized ``Test`` prefix. + + .. _`collector API`: test items are collectors as well @@ -84,48 +88,28 @@ it, otherwise we consider the "test" as passed. .. _`package name`: -constructing the package name for modules ------------------------------------------ +constructing the package name for test modules +------------------------------------------------- Test modules are imported under their fully qualified -name. Given a module ``path`` the fully qualified package -name is constructed as follows: +name. Given a filesystem ``fspath`` it is constructed as follows: -* determine the last "upward" directory from ``path`` that - contains an ``__init__.py`` file. Going upwards - means repeatedly calling the ``dirpath()`` method - on a path object (which returns the parent directory - as a path object). +* walk the directories up to the last one that contains + an ``__init__.py`` file. -* insert this base directory into the sys.path list - as its first element +* perform ``sys.path.insert(0, basedir)``. -* import the root package +* import the root package as ``root`` -* determine the fully qualified name for the module located - at ``path`` ... +* determine the fully qualified name for ``fspath`` by either: - * if the imported root package has a __package__ object - then call ``__package__.getimportname(path)`` + * calling ``root.__pkg__.getimportname(fspath)`` if the + ``__pkg__`` exists.` or * otherwise use the relative path of the module path to the base dir and turn slashes into dots and strike the trailing ``.py``. -The Module collector will eventually trigger -``__import__(mod_fqdnname, ...)`` to finally get to -the live module object. - -Side note: this whole logic is performed by local path -object's ``pyimport()`` method. - -Module Collector ------------------ - -The default Module collector looks for test functions -and test classes and methods. Test functions and methods -are prefixed ``test`` by default. Test classes must -start with a capitalized ``Test`` prefix. Customizing the testing process @@ -256,32 +240,27 @@ Customizing the collection process in a module If you have a module where you want to take responsibility for collecting your own test Items and possibly even for executing a test then you can provide `generative tests`_ that yield -callables and possibly arguments as a tuple. This should -serve some immediate purposes like paramtrized tests. +callables and possibly arguments as a tuple. This is especially +useful for calling application test machinery with different +parameter sets but counting each of the calls as a separate +tests. .. _`generative tests`: test.html#generative-tests -The other extension possibility goes deeper into the machinery -and allows you to specify a custom test ``Item`` class which +The other extension possibility is about +specifying a custom test ``Item`` class which is responsible for setting up and executing an underlying -test. [XXX not working: You can integrate your custom ``py.test.collect.Item`` subclass -by binding an ``Item`` name to a test class.] Or you can -extend the collection process for a whole directory tree -by putting Items in a ``conftest.py`` configuration file. -The collection process constantly looks at according names -in the *chain of conftest.py* modules to determine collectors -and items at ``Directory``, ``Module``, ``Class``, ``Function`` -or ``Generator`` level. Note that, right now, except for ``Function`` -items all classes are pure collectors, i.e. will return a list -of names (possibly empty). - -XXX implement doctests as alternatives to ``Function`` items. +test. Or you can extend the collection process for a whole +directory tree by putting Items in a ``conftest.py`` configuration file. +The collection process dynamically consults the *chain of conftest.py* +modules to determine collectors and items at ``Directory``, ``Module``, +``Class``, ``Function`` or ``Generator`` level respectively. Customizing execution of Functions ---------------------------------- -- Function test items allow total control of executing their - contained test method. ``function.run()`` will get called by the +- ``py.test.collect.Function`` test items control execution + of a test function. ``function.run()`` will get called by the session in order to actually run a test. The method is responsible for performing proper setup/teardown ("Test Fixtures") for a Function test. @@ -290,5 +269,4 @@ Customizing execution of Functions the default ``Function.run()`` to actually execute a python function with the given (usually empty set of) arguments. - .. _`py-dev mailing list`: http://codespeak.net/mailman/listinfo/py-dev diff --git a/py/doc/index.txt b/py/doc/index.txt index fad599e33..1408f9b00 100644 --- a/py/doc/index.txt +++ b/py/doc/index.txt @@ -1,13 +1,15 @@ py lib documentation ================================================= - The py lib aims at supporting a decent development process - addressing deployment, versioning, testing and documentation - perspectives. + The py lib is a development support library featuring + py.test, ad-hoc distributed execution, micro-threads + (greenlets) and uniform local path and svn abstractions. + Works on Linux, Windows and OSX, Python versions + 2.3, 2.4, 2.5 and 2.6. `Download and Installation`_ -`0.9.0 release announcement`_ +`0.9.2 release announcement`_ Main tools and API ---------------------- @@ -20,6 +22,8 @@ Main tools and API `py.path`_: local and subversion Path and Filesystem access +`py.code`_: High-level access/manipulation of Python code and traceback objects. + `py lib scripts`_ describe the scripts contained in the ``py/bin`` directory. `apigen`_: a new way to generate rich Python API documentation @@ -27,8 +31,6 @@ Main tools and API support functionality --------------------------------- -`py.code`_: High-level access/manipulation of Python code and traceback objects. - `py.xml`_ for generating in-memory xml/html object trees `py.io`_: Helper Classes for Capturing of Input/Output @@ -59,4 +61,4 @@ Background and Motivation information .. _`Why What how py?`: why_py.html .. _`future`: future.html .. _`miscellaneous features`: misc.html -.. _`0.9.0 release announcement`: release-0.9.0.html +.. _`0.9.2 release announcement`: release-0.9.2.html diff --git a/py/doc/release-0.9.2.txt b/py/doc/release-0.9.2.txt index f3fb7c18b..109488f42 100644 --- a/py/doc/release-0.9.2.txt +++ b/py/doc/release-0.9.2.txt @@ -5,7 +5,7 @@ Welcome to the 0.9.2 py lib and py.test release - mainly fixing Windows issues, providing better packaging and integration with setuptools. -Summary of main feature of the py lib: +Here is a quick summary of what it provides: * py.test: cross-project testing tool with many advanced features * py.execnet: ad-hoc code distribution to SSH, Socket and local sub processes @@ -17,6 +17,7 @@ Summary of main feature of the py lib: See here for more information: Download/Install: http://codespeak.net/py/0.9.2/download.html + Documentation/API: http://codespeak.net/py/0.9.2/index.html best and have fun, diff --git a/py/execnet/inputoutput.py b/py/execnet/inputoutput.py index 4d80b600a..018d3e33e 100644 --- a/py/execnet/inputoutput.py +++ b/py/execnet/inputoutput.py @@ -59,10 +59,6 @@ import sys class Popen2IO: server_stmt = """ import os, sys, StringIO -if sys.platform == "win32": - import msvcrt - msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) - msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) io = Popen2IO(sys.stdout, sys.stdin) sys.stdout = sys.stderr = StringIO.StringIO() #try: @@ -75,6 +71,11 @@ sys.stdout = sys.stderr = StringIO.StringIO() def __init__(self, infile, outfile): self.outfile, self.infile = infile, outfile + if sys.platform == "win32": + import msvcrt + msvcrt.setmode(infile.fileno(), os.O_BINARY) + msvcrt.setmode(outfile.fileno(), os.O_BINARY) + self.readable = self.writeable = True self.lock = thread.allocate_lock() diff --git a/py/execnet/register.py b/py/execnet/register.py index b08fdd6dc..ceca07113 100644 --- a/py/execnet/register.py +++ b/py/execnet/register.py @@ -2,8 +2,12 @@ import os, inspect, socket import sys from py.magic import autopath ; mypath = autopath() - import py +if sys.platform == "win32": + win32 = True + import msvcrt +else: + win32 = False # the list of modules that must be send to the other side # for bootstrapping gateways @@ -51,13 +55,10 @@ class InstallableGateway(gateway.Gateway): class PopenCmdGateway(InstallableGateway): def __init__(self, cmd): infile, outfile = os.popen2(cmd) - if sys.platform == 'win32': - import msvcrt - msvcrt.setmode(infile.fileno(), os.O_BINARY) - msvcrt.setmode(outfile.fileno(), os.O_BINARY) io = inputoutput.Popen2IO(infile, outfile) super(PopenCmdGateway, self).__init__(io=io) + class PopenGateway(PopenCmdGateway): """ This Gateway provides interaction with a newly started python subprocess. diff --git a/py/misc/buildcmodule.py b/py/misc/buildcmodule.py index 211f95b42..e9eef585b 100644 --- a/py/misc/buildcmodule.py +++ b/py/misc/buildcmodule.py @@ -3,6 +3,9 @@ A utility to build a Python extension module from C, wrapping distutils. """ import py +# set to true for automatic re-compilation of extensions +AUTOREGEN = True + # XXX we should distutils in a subprocess, because it messes up the # environment and who knows what else. Currently we just save # and restore os.environ. @@ -32,7 +35,7 @@ def make_module_from_c(cfile): lib = dirpath.join(modname+ext) # XXX argl! we need better "build"-locations alltogether! - if lib.check() and lib.stat().mtime < cfile.stat().mtime: + if lib.check() and AUTOREGEN and lib.stat().mtime < cfile.stat().mtime: try: lib.remove() except EnvironmentError: diff --git a/py/misc/testing/test_oskill.py b/py/misc/testing/test_oskill.py index 7e956a764..4a46a6f33 100644 --- a/py/misc/testing/test_oskill.py +++ b/py/misc/testing/test_oskill.py @@ -8,6 +8,10 @@ def test_win_killsubprocess(): py.test.skip("you\'re using an older version of windows, which " "doesn\'t support 'taskkill' - py.misc.killproc is not " "available") + try: + import subprocess + except ImportError: + py.test.skip("no subprocess module") tmp = py.test.ensuretemp("test_win_killsubprocess") t = tmp.join("t.py") t.write("import time ; time.sleep(100)") diff --git a/setup.py b/setup.py index a371655c9..6afd57bd6 100644 --- a/setup.py +++ b/setup.py @@ -1,25 +1,46 @@ """ setup file for 'py' package based on: - https://codespeak.net/svn/py/trunk, revision=57462 + https://codespeak.net/svn/py/trunk, revision=57536 autogenerated by gensetup.py """ import os, sys -if 1: # set to zero if you want plain distutils - import ez_setup - ez_setup.use_setuptools() - from setuptools import setup, Extension -else: - from distutils.core import setup, Extension +import ez_setup +ez_setup.use_setuptools() +from setuptools import setup, Extension +long_description = """ + +The py lib is a development support library featuring these tools and APIs: + +- `py.test`_: cross-project testing tool with many advanced features +- `py.execnet`_: ad-hoc code distribution to SSH, Socket and local sub processes +- `py.magic.greenlet`_: micro-threads on standard CPython ("stackless-light") and PyPy +- `py.path`_: path abstractions over local and subversion files +- `py.code`_: dynamic code compile and traceback printing support + +The py lib and its tools should work well on Linux, Win32, +OSX, Python versions 2.3-2.6. For questions please go to +http://pylib.org/contact.html + +.. _`py.test`: http://pylib.org/test.html +.. _`py.execnet`: http://pylib.org/execnet.html +.. _`py.magic.greenlet`: http://pylib.org/greenlet.html +.. _`py.path`: http://pylib.org/path.html +.. _`py.code`: http://pylib.org/code.html + + +""" def main(): - setup(cmdclass=cmdclass, + setup( name='py', description='pylib and py.test: agile development and test support library', + long_description = long_description, version='1.0.0a1', url='http://pylib.org', + download_url='http://codespeak.net/py/0.9.2/download.html', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], author='holger krekel, Guido Wesdorp, Carl Friedrich Bolz, Armin Rigo, Maciej Fijalkowski & others', @@ -27,9 +48,13 @@ def main(): ext_modules = [Extension("py.c-extension.greenlet.greenlet", ["py/c-extension/greenlet/greenlet.c"]),], - py_modules=['_findpy'], - long_description='the py lib is a development support library featuring py.test, ad-hoc distributed execution, micro-threads and svn abstractions.', - classifiers=['Development Status :: 3 - Alpha', + entry_points={'console_scripts': ['py.cleanup = py.cmdline:pycleanup', + 'py.countloc = py.cmdline:pycountloc', + 'py.lookup = py.cmdline:pylookup', + 'py.rest = py.cmdline:pyrest', + 'py.test = py.cmdline:pytest', + 'py.which = py.cmdline:pywhich']}, + classifiers=['Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: POSIX', @@ -40,12 +65,6 @@ def main(): 'Topic :: System :: Distributed Computing', 'Topic :: Utilities', 'Programming Language :: Python'], - scripts=['py/bin/py.cleanup', - 'py/bin/py.countloc', - 'py/bin/py.lookup', - 'py/bin/py.rest', - 'py/bin/py.test', - 'py/bin/py.which'], packages=['py', 'py.apigen', 'py.apigen.rest', @@ -61,6 +80,8 @@ def main(): 'py.builtin', 'py.builtin.testing', 'py.c-extension', + 'py.cmdline', + 'py.cmdline.testing', 'py.code', 'py.code.testing', 'py.compat', @@ -117,13 +138,20 @@ def main(): 'apigen/style.css', 'apigen/todo-apigen.txt', 'apigen/todo.txt', + 'bin/_docgen.py', 'bin/_findpy.py', + 'bin/_genscripts.py', 'bin/py.cleanup', 'bin/py.countloc', 'bin/py.lookup', 'bin/py.rest', 'bin/py.test', 'bin/py.which', + 'bin/win32/py.cleanup.cmd', + 'bin/win32/py.countloc.cmd', + 'bin/win32/py.lookup.cmd', + 'bin/win32/py.rest.cmd', + 'bin/win32/py.test.cmd', 'c-extension/greenlet/README.txt', 'c-extension/greenlet/dummy_greenlet.py', 'c-extension/greenlet/greenlet.c', @@ -201,100 +229,6 @@ def main(): zip_safe=False, ) -class Win32PathHandling: - """ a helper to remove things added to system PATHs in previous installations. """ - _winreg = None - def __init__(self): - if sys.platform == 'win32': - try: - import _winreg - except ImportError: - print sys.stderr, "huh could not import _winreg on windows, ignoring" - else: - self._winreg = _winreg - - def remove_pylib_path(self): - reg = self._winreg.ConnectRegistry( - None, self._winreg.HKEY_LOCAL_MACHINE) - key = r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment" - path = self.get_registry_value(reg, key, "Path") - newpath = self.prunepath(path) - if newpath != path: - print "PATH contains old py/bin/win32 scripts:", path - print "pruning and setting a new PATH:", newpath - self.set_registry_value(reg, key, "Path", newpath) - # Propagate changes to current command prompt - os.system("set PATH=%s" % path) - self.try_propagate_system() - - def prunepath(self, path): - basename = os.path.basename - dirname = os.path.dirname - l = [] - for p in path.split(';'): - if basename(p) == "win32" and basename(dirname(p)) == "bin" \ - and basename(dirname(dirname(p))) == "py": - continue # prune this path - l.append(p) - return ";".join(l) - - def try_propagate_system(self): - try: - import win32gui, win32con - except ImportError: - return - # Propagate changes throughout the system - win32gui.SendMessageTimeout(win32con.HWND_BROADCAST, - win32con.WM_SETTINGCHANGE, 0, "Environment", - win32con.SMTO_ABORTIFHUNG, 5000) - - def get_registry_value(self, reg, key, value_name): - k = self._winreg.OpenKey(reg, key) - value = self._winreg.QueryValueEx(k, value_name)[0] - self._winreg.CloseKey(k) - return value - - def set_registry_value(self, reg, key, value_name, value): - k = self._winreg.OpenKey(reg, key, 0, self._winreg.KEY_WRITE) - value_type = self._winreg.REG_SZ - # if we handle the Path value, then set its type to REG_EXPAND_SZ - # so that things like %SystemRoot% get automatically expanded by the - # command prompt - if value_name == "Path": - value_type = self._winreg.REG_EXPAND_SZ - self._winreg.SetValueEx(k, value_name, 0, value_type, value) - self._winreg.CloseKey(k) - -# on windows we need to hack up the to-be-installed scripts -from distutils.command.install_scripts import install_scripts -class my_install_scripts(install_scripts): - def run(self): - install_scripts.run(self) - #print self.outfiles - for fn in self.outfiles: - basename = os.path.basename(fn) - if "." in basename: - #print "tackling", fn - newbasename = basename.replace(".", "_") - newfn = os.path.join(os.path.dirname(fn), newbasename) - if os.path.exists(newfn): - os.remove(newfn) - os.rename(fn, newfn) - newname = fn + ".cmd" - if os.path.exists(newname): - os.remove(newname) - f = open(newname, 'w') - f.write("@echo off\n") - f.write('python "%%~dp0\py_command_trampolin" %s %%*\n' % basename) - f.close() - w32path = Win32PathHandling() - w32path.remove_pylib_path() - -if sys.platform == "win32": - cmdclass = {'install_scripts': my_install_scripts} -else: - cmdclass = {} - if __name__ == '__main__': main() \ No newline at end of file