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
--HG--
branch : trunk
			
			
This commit is contained in:
		
							parent
							
								
									3234e6e978
								
							
						
					
					
						commit
						a3d15b2c60
					
				
							
								
								
									
										21
									
								
								CHANGELOG
								
								
								
								
							
							
						
						
									
										21
									
								
								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 | ||||
|  |  | |||
|  | @ -1,47 +1,86 @@ | |||
| #!/usr/bin/env python  | ||||
| 
 | ||||
| """\ | ||||
| py.cleanup [PATH] | ||||
| py.cleanup [PATH] ... | ||||
| 
 | ||||
| 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.  | ||||
| 
 | ||||
| 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 | ||||
| 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 | ||||
|          | ||||
|     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) | ||||
| 
 | ||||
| def remove(path, options): | ||||
|     if options.dryrun: | ||||
|         py.builtin.print_("would remove", path) | ||||
|     else: | ||||
|         py.builtin.print_("removing", path) | ||||
|         path.remove() | ||||
|                  | ||||
|     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 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 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") | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue