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:
holger krekel 2010-02-05 22:50:41 +01:00
parent 3234e6e978
commit a3d15b2c60
3 changed files with 133 additions and 37 deletions

View File

@ -1,22 +1,37 @@
Changes between 1.2.1 and 1.2.0 Changes between 1.2.1 and 1.2.0
===================================== =====================================
- add a new option "--funcargs" that shows available funcargs - refined usage and options for "py.cleanup":
and their help strings (docstrings on the factory) for a py.cleanup # remove "*.pyc" and "*$py.class" (jython) files
given test path 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 - display a short and concise traceback if a funcarg lookup fails
- early-load "test*/conftest.py" files, i.e. conftest.py files in - early-load "test*/conftest.py" files, i.e. conftest.py files in
directories starting with 'test'. allows to conveniently keep and access 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. 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 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 - fix issue78: always call python-level teardown functions even if the
according setup failed. This includes refinements for calling setup_module/class functions 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 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 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. 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 - 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 - update apipkg.py to fix an issue where recursive imports might
unnecessarily break importing unnecessarily break importing
- fix plugin links - fix plugin links
Changes between 1.2 and 1.1.1 Changes between 1.2 and 1.1.1

View File

@ -1,47 +1,86 @@
#!/usr/bin/env python #!/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 py
import sys, subprocess
def main(): def main():
parser = py.std.optparse.OptionParser(usage=__doc__) parser = py.std.optparse.OptionParser(usage=__doc__)
parser.add_option("-e", "--remove", dest="ext", default=".pyc", action="store", parser.add_option("-e", metavar="ENDING",
help="remove files with the given comma-separated list of extensions" 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, parser.add_option("-n", "--dryrun", dest="dryrun", default=False,
action="store_true", action="store_true",
help="display would-be-removed filenames" help="don't actually delete but display would-be-removed filenames.")
)
parser.add_option("-d", action="store_true", dest="removedir",
help="remove empty directories")
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
Cleanup(options, args).main()
class Cleanup:
def __init__(self, options, args):
if not args: if not args:
args = ["."] args = ["."]
ext = options.ext.split(",") self.options = options
def shouldremove(p): self.args = [py.path.local(x) for x in args]
return p.ext in ext if options.all:
options.setup = True
options.removedir = True
options.endings.append("pip-log.txt")
for arg in args: def main(self):
path = py.path.local(arg) if self.options.setup:
py.builtin.print_("cleaning path", path, "of extensions", ext) for arg in self.args:
for x in path.visit(shouldremove, lambda x: x.check(dotfile=0, link=0)): self.setupclean(arg)
remove(x, options)
if options.removedir: for path in self.args:
for x in path.visit(lambda x: x.check(dir=1), py.builtin.print_("cleaning path", path,
lambda x: x.check(dotfile=0, link=0)): "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(): if not x.listdir():
remove(x, options) self.remove(x)
def remove(path, options): def shouldremove(self, p):
if options.dryrun: 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) py.builtin.print_("would remove", path)
else: else:
py.builtin.print_("removing", path) py.builtin.print_("removing", path)
path.remove() 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")

View File

@ -45,8 +45,10 @@ class TestPyCleanup:
assert p.check() assert p.check()
pyc = p.new(ext='pyc') pyc = p.new(ext='pyc')
pyc.ensure() pyc.ensure()
pyclass = p.new(basename=p.basename + '$py.class')
result = testdir.runpybin("py.cleanup", tmpdir) result = testdir.runpybin("py.cleanup", tmpdir)
assert not pyc.check() assert not pyc.check()
assert not pyclass.check()
def test_dir_remove_simple(self, testdir, tmpdir): def test_dir_remove_simple(self, testdir, tmpdir):
subdir = tmpdir.mkdir("subdir") subdir = tmpdir.mkdir("subdir")
@ -59,3 +61,43 @@ class TestPyCleanup:
result = testdir.runpybin("py.cleanup", tmpdir, '-d') result = testdir.runpybin("py.cleanup", tmpdir, '-d')
assert result.ret == 0 assert result.ret == 0
assert not subdir.check() 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()