[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