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
=====================================
- 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

View File

@ -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)
Cleanup(options, args).main()
def remove(path, options):
if options.dryrun:
py.builtin.print_("would remove", path)
else:
py.builtin.print_("removing", path)
path.remove()
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")

View File

@ -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()