[py-svn] py-trunk commit cd736fb48fe1: refined usage and options for "py.cleanup":
commits-noreply at bitbucket.org
commits-noreply at bitbucket.org
Fri Feb 5 22:51:24 CET 2010
# HG changeset patch -- Bitbucket.org
# Project py-trunk
# URL http://bitbucket.org/hpk42/py-trunk/overview/
# User holger krekel <holger at merlinux.eu>
# Date 1265406641 -3600
# Node ID cd736fb48fe11cf57270096d78da29124ebf0e8b
# Parent da57b132ee9db9e8d91326e33c681dbe55cb1c4e
refined usage and options for "py.cleanup":
py.cleanup # remove "*.pyc" and "*$py.class" (jython) files
py.cleanup -e .swp -e .cache # also remove files with these extensions
py.cleanup -s # remove "build" and "dist" directory next to setup.py files
py.cleanup -d # also remove empty directories
py.cleanup -a # synonym for "-s -d -e 'pip-log.txt'"
py.cleanup -n # dry run, only show what would be removed
--- a/py/_cmdline/pycleanup.py
+++ b/py/_cmdline/pycleanup.py
@@ -1,47 +1,86 @@
#!/usr/bin/env python
"""\
-py.cleanup [PATH]
+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 ".".
+Delete typical python development related files recursively under the specified PATH (which defaults to the current working directory). Don't follow links and don't recurse into directories with a dot. Optionally remove setup.py related files and empty
+directories.
+
"""
import py
+import sys, subprocess
def main():
parser = py.std.optparse.OptionParser(usage=__doc__)
- parser.add_option("-e", "--remove", dest="ext", default=".pyc", action="store",
- help="remove files with the given comma-separated list of extensions"
- )
+ parser.add_option("-e", metavar="ENDING",
+ dest="endings", default=[".pyc", "$py.class"], action="append",
+ help=("(multi) recursively remove files with the given ending."
+ " '.pyc' and '$py.class' are in the default list."))
+ parser.add_option("-d", action="store_true", dest="removedir",
+ help="remove empty directories.")
+ parser.add_option("-s", action="store_true", dest="setup",
+ help="remove 'build' and 'dist' directories next to setup.py files")
+ parser.add_option("-a", action="store_true", dest="all",
+ help="synonym for '-S -d -e pip-log.txt'")
parser.add_option("-n", "--dryrun", dest="dryrun", default=False,
action="store_true",
- help="display would-be-removed filenames"
- )
- parser.add_option("-d", action="store_true", dest="removedir",
- help="remove empty directories")
+ help="don't actually delete but display would-be-removed filenames.")
(options, args) = parser.parse_args()
- if not args:
- args = ["."]
- ext = options.ext.split(",")
- def shouldremove(p):
- return p.ext in ext
+
+ Cleanup(options, args).main()
+
+class Cleanup:
+ def __init__(self, options, args):
+ if not args:
+ args = ["."]
+ self.options = options
+ self.args = [py.path.local(x) for x in args]
+ if options.all:
+ options.setup = True
+ options.removedir = True
+ options.endings.append("pip-log.txt")
+
+ def main(self):
+ if self.options.setup:
+ for arg in self.args:
+ self.setupclean(arg)
- for arg in args:
- path = py.path.local(arg)
- py.builtin.print_("cleaning path", path, "of extensions", ext)
- for x in path.visit(shouldremove, lambda x: x.check(dotfile=0, link=0)):
- remove(x, options)
- if options.removedir:
- for x in path.visit(lambda x: x.check(dir=1),
- lambda x: x.check(dotfile=0, link=0)):
- if not x.listdir():
- remove(x, options)
+ for path in self.args:
+ py.builtin.print_("cleaning path", path,
+ "of extensions", self.options.endings)
+ for x in path.visit(self.shouldremove, self.recursedir):
+ self.remove(x)
+ if self.options.removedir:
+ for x in path.visit(lambda x: x.check(dir=1), self.recursedir):
+ if not x.listdir():
+ self.remove(x)
-def remove(path, options):
- if options.dryrun:
- py.builtin.print_("would remove", path)
- else:
- py.builtin.print_("removing", path)
- path.remove()
-
+ def shouldremove(self, p):
+ for ending in self.options.endings:
+ if p.basename.endswith(ending):
+ return True
+
+ def recursedir(self, path):
+ return path.check(dotfile=0, link=0)
+
+ def remove(self, path):
+ if not path.check():
+ return
+ if self.options.dryrun:
+ py.builtin.print_("would remove", path)
+ else:
+ py.builtin.print_("removing", path)
+ path.remove()
+
+ def XXXcallsetup(self, setup, *args):
+ old = setup.dirpath().chdir()
+ try:
+ subprocess.call([sys.executable, str(setup)] + list(args))
+ finally:
+ old.chdir()
+
+ def setupclean(self, path):
+ for x in path.visit("setup.py", self.recursedir):
+ basepath = x.dirpath()
+ self.remove(basepath / "build")
+ self.remove(basepath / "dist")
--- a/testing/cmdline/test_cmdline.py
+++ b/testing/cmdline/test_cmdline.py
@@ -45,8 +45,10 @@ class TestPyCleanup:
assert p.check()
pyc = p.new(ext='pyc')
pyc.ensure()
+ pyclass = p.new(basename=p.basename + '$py.class')
result = testdir.runpybin("py.cleanup", tmpdir)
assert not pyc.check()
+ assert not pyclass.check()
def test_dir_remove_simple(self, testdir, tmpdir):
subdir = tmpdir.mkdir("subdir")
@@ -59,3 +61,43 @@ class TestPyCleanup:
result = testdir.runpybin("py.cleanup", tmpdir, '-d')
assert result.ret == 0
assert not subdir.check()
+
+ @py.test.mark.multi(opt=["-s"])
+ def test_remove_setup_simple(self, testdir, tmpdir, opt):
+ subdir = tmpdir.mkdir("subdir")
+ p = subdir.ensure("setup.py")
+ subdir.mkdir("build").ensure("hello", "world.py")
+ egg1 = subdir.mkdir("something.egg-info")
+ egg1.mkdir("whatever")
+ okbuild = subdir.mkdir("preserved1").mkdir("build")
+ egg2 = subdir.mkdir("preserved2").mkdir("other.egg-info")
+ subdir.mkdir("dist")
+ result = testdir.runpybin("py.cleanup", opt, subdir)
+ assert result.ret == 0
+ assert okbuild.check()
+ assert egg1.check()
+ assert egg2.check()
+ assert subdir.join("preserved1").check()
+ assert subdir.join("preserved2").check()
+ assert not subdir.join("build").check()
+ assert not subdir.join("dist").check()
+
+ def test_remove_all(self, testdir, tmpdir):
+ tmpdir.ensure("setup.py")
+ tmpdir.ensure("build", "xyz.py")
+ tmpdir.ensure("dist", "abc.py")
+ piplog = tmpdir.ensure("preserved2", "pip-log.txt")
+ tmpdir.ensure("hello.egg-info")
+ setup = tmpdir.ensure("setup.py")
+ tmpdir.ensure("src/a/b")
+ x = tmpdir.ensure("src/x.py")
+ x2 = tmpdir.ensure("src/x.pyc")
+ x3 = tmpdir.ensure("src/x$py.class")
+ result = testdir.runpybin("py.cleanup", "-a", tmpdir)
+ assert result.ret == 0
+ assert len(tmpdir.listdir()) == 3
+ assert setup.check()
+ assert x.check()
+ assert not x2.check()
+ assert not x3.check()
+ assert not piplog.check()
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,22 +1,37 @@
Changes between 1.2.1 and 1.2.0
=====================================
-- add a new option "--funcargs" that shows available funcargs
- and their help strings (docstrings on the factory) for a
- given test path
+- refined usage and options for "py.cleanup":
+ py.cleanup # remove "*.pyc" and "*$py.class" (jython) files
+ py.cleanup -e .swp -e .cache # also remove files with these extensions
+ py.cleanup -s # remove "build" and "dist" directory next to setup.py files
+ py.cleanup -d # also remove empty directories
+ py.cleanup -a # synonym for "-s -d -e 'pip-log.txt'"
+ py.cleanup -n # dry run, only show what would be removed
+
+- add a new option "py.test --funcargs" which shows available funcargs
+ and their help strings (docstrings on their respective factory function)
+ for a given test path
+
- display a short and concise traceback if a funcarg lookup fails
+
- early-load "test*/conftest.py" files, i.e. conftest.py files in
directories starting with 'test'. allows to conveniently keep and access
test-related options without having to put a conftest.py into the package root dir.
+
- fix issue67: new super-short traceback-printing option: "--tb=line" will print a single line for each failing (python) test indicating its filename, lineno and the failure value
+
- fix issue78: always call python-level teardown functions even if the
according setup failed. This includes refinements for calling setup_module/class functions
which will now only be called once instead of the previous behaviour where they'd be called
multiple times if they raise an exception (including a Skipped exception). Any exception
will be re-corded and associated with all tests in the according module/class scope.
+
- fix issue63: assume <40 columns to be a bogus terminal width, default to 80
+
- update apipkg.py to fix an issue where recursive imports might
unnecessarily break importing
+
- fix plugin links
Changes between 1.2 and 1.1.1
More information about the pytest-commit
mailing list