From 36288223b4c65511e003a26a842e3f52c1744eee Mon Sep 17 00:00:00 2001 From: holger krekel Date: Wed, 19 Aug 2009 17:12:02 +0200 Subject: [PATCH] [mq]: 101-prep --HG-- branch : 1.0.x --- MANIFEST | 8 +- bin-for-dist/all-plat.sh | 6 + {py/bin => bin-for-dist}/gendoc.py | 2 + .../genscripts.py | 7 +- bin-for-dist/gensetup.py | 342 ++++++++++++++++++ .../makepluginlist.py | 0 doc/contact.txt | 10 +- doc/faq.txt | 12 +- setup.py | 2 - 9 files changed, 369 insertions(+), 20 deletions(-) create mode 100644 bin-for-dist/all-plat.sh rename {py/bin => bin-for-dist}/gendoc.py (99%) rename py/bin/_genscripts.py => bin-for-dist/genscripts.py (80%) create mode 100644 bin-for-dist/gensetup.py rename makepluginlist.py => bin-for-dist/makepluginlist.py (100%) diff --git a/MANIFEST b/MANIFEST index 712cc2266..5b74398e4 100644 --- a/MANIFEST +++ b/MANIFEST @@ -3,6 +3,11 @@ LICENSE MANIFEST README.txt _findpy.py +bin-for-dist/all-plat.sh +bin-for-dist/gendoc.py +bin-for-dist/genscripts.py +bin-for-dist/gensetup.py +bin-for-dist/makepluginlist.py doc/announce/release-0.9.0.txt doc/announce/release-0.9.2.txt doc/announce/release-1.0.0.txt @@ -87,13 +92,10 @@ example/funcarg/test_simpleprovider.py example/genhtml.py example/genhtmlcss.py example/genxml.py -makepluginlist.py py/LICENSE py/__init__.py py/_com.py py/bin/_findpy.py -py/bin/_genscripts.py -py/bin/gendoc.py py/bin/py.cleanup py/bin/py.countloc py/bin/py.lookup diff --git a/bin-for-dist/all-plat.sh b/bin-for-dist/all-plat.sh new file mode 100644 index 000000000..db7b454ce --- /dev/null +++ b/bin-for-dist/all-plat.sh @@ -0,0 +1,6 @@ + + +py.test --dist=each $* \ + --tx 'popen//python=python2.6' \ + --tx 'ssh=noco//python=/usr/local/bin/python2.4//chdir=/tmp/pytest-python2.4' \ + --tx 'socket=192.168.1.106:8888' diff --git a/py/bin/gendoc.py b/bin-for-dist/gendoc.py similarity index 99% rename from py/bin/gendoc.py rename to bin-for-dist/gendoc.py index 140bd39f2..e5c69865e 100755 --- a/py/bin/gendoc.py +++ b/bin-for-dist/gendoc.py @@ -1,5 +1,7 @@ #!/usr/bin/env python +XXX + import sys import os from _findpy import py diff --git a/py/bin/_genscripts.py b/bin-for-dist/genscripts.py similarity index 80% rename from py/bin/_genscripts.py rename to bin-for-dist/genscripts.py index b6a37b85b..1ffcb11e1 100644 --- a/py/bin/_genscripts.py +++ b/bin-for-dist/genscripts.py @@ -1,6 +1,7 @@ from _findpy import py -mydir = py.magic.autopath().dirpath() +bindir = py.magic.autopath().dirpath().dirpath("py").join("bin") +assert bindir.check(), bindir def getbasename(name): assert name[:2] == "py" @@ -8,7 +9,7 @@ def getbasename(name): def genscript_unix(name): basename = getbasename(name) - path = mydir.join(basename) + path = bindir.join(basename) path.write(py.code.Source(""" #!/usr/bin/env python from _findpy import py @@ -19,7 +20,7 @@ def genscript_unix(name): def genscript_windows(name): basename = getbasename(name) winbasename = basename + ".cmd" - path = mydir.join("win32").join(winbasename) + path = bindir.join("win32").join(winbasename) path.write(py.code.Source(""" @echo off python "%%~dp0\..\%s" %%* diff --git a/bin-for-dist/gensetup.py b/bin-for-dist/gensetup.py new file mode 100644 index 000000000..574585868 --- /dev/null +++ b/bin-for-dist/gensetup.py @@ -0,0 +1,342 @@ +import sys + +sys.path.insert(0, sys.argv[1]) +import py + +toolpath = py.magic.autopath() +binpath = py.path.local(py.__file__).dirpath('bin') + +def error(msg): + print >>sys.stderr, msg + raise SystemExit, 1 + +def reformat(text): + return " ".join(text.split()) + +class SetupWriter(object): + EXCLUDES = ("MANIFEST.in", "contrib") + + def __init__(self, basedir, pkg, setuptools=False): + self.basedir = basedir + self.setuptools = setuptools + assert self.basedir.check() + self.pkg = pkg + self.meta = pkg.__pkg__ + self.lines = [] + self.allpaths = self.getallpath(self.basedir) + + def getallpath(self, basedir): + contrib = self.basedir.join("contrib") + allpath = [] + lines = py.process.cmdexec("hg st -mcan").split("\n") + for path in lines: + p = basedir.join(path) + assert p.check(), p + if not p.relto(contrib) and p != contrib and not self.isexcluded(p): + allpath.append(p) + return allpath + + def append(self, string): + lines = string.split("\n") + while lines: + if not lines[0].strip(): + lines.pop(0) + continue + break + if not lines: + self.lines.append("") + return + line = lines[0] + indent = len(line) - len(line.lstrip()) + for line in lines: + if line.strip(): + assert not line[:indent].strip(), line + line = line[indent:] + self.lines.append(line) + + def write_winfuncs(self): + self.append(''' + ''') + + def tip_info(self, indent=8): + old = self.basedir.chdir() + indent = " " * indent + try: + info = [] + output = py.process.cmdexec( + "hg tip --template '" # tags: {tags}\n" + #"branch: {branches}\n" + "revision: {rev}:{node}\n'" + ) + for line in output.split("\n"): + info.append("%s %s" %(indent, line.strip())) + return "\n".join(info) + finally: + old.chdir() + + def setup_header(self): + #tooltime = "%s %s" %(py.std.time.asctime(), py.std.time.tzname[0]) + toolname = toolpath.basename + #toolrevision = py.path.svnwc(toolpath).info().rev + + pkgname = self.pkg.__name__ + info = self.tip_info() + self.append(''' + """ + py lib / py.test setup.py file, autogenerated by %(toolname)s + ''' % locals()) + #self.append(info) + self.append(''' + """ + import os, sys + ''') + + if self.setuptools: + #import ez_setup + #ez_setup.use_setuptools() + self.append(""" + from setuptools import setup + """) + else: + self.append(""" + from distutils.core import setup + """) + + def setup_trailer(self): + self.append(''' + if __name__ == '__main__': + main() + ''') + + def setup_function(self): + params = self.__dict__.copy() + params.update(self.meta.__dict__) + #params['url'] = self.wcinfo.url + #params['rev'] = self.wcinfo.rev + #params['long_description'] = reformat(params['long_description']) + #print py.std.pprint.pprint(params) + self.append('long_description = """') + for line in params['long_description'].split('\n'): + self.append(line) + self.append('"""') + trunk = None + if params['version'] == 'trunk': + trunk = 'trunk' + self.append('trunk = %r' % trunk) + self.append(''' + def main(): + setup( + name=%(name)r, + description=%(description)r, + long_description = long_description, + version= trunk or %(version)r, + url=%(url)r, + license=%(license)r, + platforms=%(platforms)r, + author=%(author)r, + author_email=%(author_email)r, + ''' % params) + indent = " " * 8 + #self.append_pprint(indent, py_modules=['_findpy',]), + #self.append_pprint(indent, scripts=self.getscripts()) + self.append_pprint(indent, entry_points={'console_scripts':self.getconsolescripts()}) + self.append_pprint(indent, classifiers=self.meta.classifiers) + self.append_pprint(indent, packages=self.getpackages()) + #self.append_pprint(indent, data_files=self.getdatafiles()) + self.append_pprint(indent, package_data=self.getpackagedata()) + #self.append_pprint(indent, package_dir={'py': 'py'}) + #self.append_pprint(indent, packages=self.getpackages()) + if self.setuptools: + self.append_pprint(indent, zip_safe=False) + self.lines.append(indent[4:] + ")\n") + + def setup_scripts(self): + # XXX this was used for a different approach + not used + self.append(""" + def getscripts(): + if sys.platform == "win32": + base = "py/bin/win32/" + ext = ".cmd" + else: + base = "py/bin/" + ext = "" + l = [] + for name in %r: + l.append(base + name + ext) + return l + """ % ([script.basename for script in binpath.listdir("py.*")])) + + def append_pprint(self, indent, append=",", **kw): + for name, value in kw.items(): + stringio = py.std.StringIO.StringIO() + value = py.std.pprint.pprint(value, stream=stringio) + stringio.seek(0) + lines = stringio.readlines() + line = lines.pop(0).rstrip() + self.lines.append(indent + "%s=%s" %(name, line)) + indent = indent + " " * (len(name)+1) + for line in lines: + self.lines.append(indent + line.rstrip()) + self.lines[-1] = self.lines[-1] + append + + def getconsolescripts(self): + bindir = self.basedir.join('py', 'bin') + scripts = [] + for p in self.allpaths: + if p.dirpath() == bindir: + if p.basename.startswith('py.'): + shortname = "py" + p.basename[3:] + scripts.append("%s = py.cmdline:%s" % + (p.basename, shortname)) + return scripts + + def getscripts(self): + bindir = self.basedir.join('py', 'bin') + scripts = [] + for p in self.allpaths: + if p.dirpath() == bindir: + if p.basename.startswith('py.'): + scripts.append(p.relto(self.basedir)) + return scripts + + def getpackages(self): + packages = [] + for p in self.allpaths: # contains no directories! + #if p.basename == "py": + # continue + if p.dirpath('__init__.py').check(): + modpath = p.dirpath().relto(self.basedir).replace(p.sep, '.') + if modpath != "py" and not modpath.startswith("py."): + continue + if modpath in packages: + continue + for exclude in self.EXCLUDES: + if modpath.startswith(exclude): + print "EXCLUDING", modpath + break + else: + packages.append(modpath) + packages.sort() + return packages + + def getpackagedata(self): + datafiles = [] + pkgbase = self.basedir.join(self.pkg.__name__) + for p in self.allpaths: + if p.check(file=1) and (not p.dirpath("__init__.py").check() + or p.ext != ".py"): + if p.dirpath() != self.basedir: + x = p.relto(pkgbase) + if x: + datafiles.append(p.relto(pkgbase)) + return {'py': datafiles} + + def getdatafiles(self): + datafiles = [] + for p in self.allpaths: + if p.check(file=1) and not p.ext == ".py": + if p.dirpath() != self.basedir: + datafiles.append(p.relto(self.basedir)) + return datafiles + + def setup_win32(self): + import winpath + self.append(py.std.inspect.getsource(winpath)) + self.append(""" + from distutils.command.install import install + class my_install(install): + def finalize_other(self): + install.finalize_other(self) + on_win32_add_to_PATH() + cmdclass = {'install': my_install} + """) + + def setup_win32(self): + self.append(r''' + # scripts for windows: turn "py.SCRIPT" into "py_SCRIPT" and create + # "py.SCRIPT.cmd" files invoking "py_SCRIPT" + 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 basename.startswith("py.") and not basename.endswith(".cmd"): + newbasename = basename.replace(".", "_") + newfn = os.path.join(os.path.dirname(fn), newbasename) + if os.path.exists(newfn): + os.remove(newfn) + os.rename(fn, newfn) + fncmd = fn + ".cmd" + if os.path.exists(fncmd): + os.remove(fncmd) + f = open(fncmd, 'w') + f.write("@echo off\n") + f.write('python "%%~dp0\%s" %%*' %(newbasename)) + f.close() + if sys.platform == "win32": + cmdclass = {'install_scripts': my_install_scripts} + else: + cmdclass = {} + ''') + + def write_setup(self): + self.setup_header() + self.setup_function() + #self.setup_scripts() + #self.setup_win32() + self.setup_trailer() + targetfile = self.basedir.join("setup.py") + targetfile.write("\n".join(self.lines)) + print "wrote", targetfile + + def isexcluded(self, wcpath): + return wcpath.basename[0] == "." + rel = wcpath.relto(self.basedir) + if rel.find("testing") != -1: + return True + + def write_manifest(self): + lines = [] + for p in self.allpaths: + if p.check(dir=1): + continue + toadd = p.relto(self.basedir) + if toadd: + for exclude in self.EXCLUDES: + if toadd.startswith(exclude): + break + assert toadd.find(exclude) == -1, (toadd, exclude) + else: + lines.append("%s" %(toadd)) + lines.sort() + targetfile = self.basedir.join("MANIFEST") + targetfile.write("\n".join(lines)) + print "wrote", targetfile + + def write_all(self): + self.write_manifest() + self.write_setup() + +def parseargs(): + basedir = py.path.local(sys.argv[1]) + if not basedir.check(): + error("basedir not found: %s" %(basedir,)) + pydir = basedir.join('py') + if not pydir.check(): + error("no 'py' directory found in: %s" %(pydir,)) + actualpydir = py.path.local(py.__file__).dirpath() + if pydir != actualpydir: + error("package dir conflict, %s != %s" %(pydir, actualpydir)) + return basedir + +def main(basedir=None): + if basedir is None: + basedir = parseargs() + writer = SetupWriter(basedir, py, setuptools=True) + writer.write_all() + +if __name__ == "__main__": + main() diff --git a/makepluginlist.py b/bin-for-dist/makepluginlist.py similarity index 100% rename from makepluginlist.py rename to bin-for-dist/makepluginlist.py diff --git a/doc/contact.txt b/doc/contact.txt index 6e9d8d551..1e79902df 100644 --- a/doc/contact.txt +++ b/doc/contact.txt @@ -10,9 +10,7 @@ Contact and Communication points - `Testing In Python`_: a mailing list for testing tools and discussion. -- `py-svn general commit mailing list`_ to follow development commits, - -- http://twitter.com/pylibcommit for following commits via twitter +- `commit mailing list`_ or `@pylibcommit`_ to follow development commits, - `bitbucket issue tracker`_ use this bitbucket issue tracker to report bugs or request features. @@ -27,6 +25,8 @@ Contact and Communication points .. _tetamap: http://tetamap.wordpress.com +.. _`@pylibcommit`: http://twitter.com/pylibcommit + .. get an account on codespeak @@ -45,8 +45,6 @@ Contact and Communication points .. _`py-dev`: .. _`development mailing list`: .. _`py-dev developers list`: http://codespeak.net/mailman/listinfo/py-dev -.. _`subversion commit mailing list`: .. _`py-svn`: -.. _`py-svn general commit mailing list`: http://codespeak.net/mailman/listinfo/py-svn -.. _`development bug/feature tracker`: https://codespeak.net/issue/py-dev/ +.. _`commit mailing list`: http://codespeak.net/mailman/listinfo/py-svn diff --git a/doc/faq.txt b/doc/faq.txt index bb324d67f..1e5da4d7e 100644 --- a/doc/faq.txt +++ b/doc/faq.txt @@ -6,7 +6,7 @@ Frequently Asked Questions :local: :depth: 2 -naming, nose and magic +On naming, nose and magic ============================ Why the ``py`` naming? what is it? @@ -34,7 +34,7 @@ for the ``py.test`` command line tool is: in the What's the relation to ``nosetests``? ---------------------------------------- -py.test and nose_ share some basic philosophy when it comes +py.test and nose_ share basic philosophy when it comes to running Python tests. In fact, with py.test-1.0.1 it is easy to run many test suites that currently work with ``nosetests``. nose_ was created @@ -51,13 +51,13 @@ What's all this "magic" with py.test? "All this magic" usually boils down to two issues: * There is a special tweak to importing: `py/__init__.py`_ contains - contains a dictionary which maps the ``py.*`` namespaces - to objects in files. When looking at the project source code + a dictionary which maps the importable ``py.*`` namespaces to + objects in files. When looking at the project source code you see imports like ``from py.__.test.session import Session``. The the double ``__`` underscore indicates the "normal" python filesystem/namespace coupled import, i.e. it points to ``py/test/session.py``'s ``Session`` object. However, - normal usage happens through the clean exported `py namespaces`_ + from the outside you use the "non-underscore" `py namespaces`_ so this distinction usually only shows up if you hack on internal code or see internal tracebacks. @@ -72,7 +72,7 @@ What's all this "magic" with py.test? off assert re-intepretation. Other than that, ``py.test`` has bugs or quirks like any other computer -software although it has a *strong* focus on running robustly and has +software. In fact, it has a *strong* focus on running robustly and has over a thousand automated tests for its own code base. .. _`py namespaces`: index.html diff --git a/setup.py b/setup.py index 612037db7..a9da10816 100644 --- a/setup.py +++ b/setup.py @@ -105,8 +105,6 @@ def main(): 'py.xmlobj.testing'], package_data={'py': ['LICENSE', 'bin/_findpy.py', - 'bin/_genscripts.py', - 'bin/gendoc.py', 'bin/py.cleanup', 'bin/py.countloc', 'bin/py.lookup',