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
|
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
|
||||||
|
|
|
@ -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()
|
||||||
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):
|
Cleanup(options, args).main()
|
||||||
if options.dryrun:
|
|
||||||
py.builtin.print_("would remove", path)
|
class Cleanup:
|
||||||
else:
|
def __init__(self, options, args):
|
||||||
py.builtin.print_("removing", path)
|
if not args:
|
||||||
path.remove()
|
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()
|
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()
|
||||||
|
|
Loading…
Reference in New Issue