#!/usr/bin/env python
def cleanpycs(root, exclude='CVS .svn .git .hg .bzr'.split()):
'''Deletes .pyc files and empty directories under this directory.
Directories in ``exclude`` are not traversed.
'''
from os.path import join, normpath
from os import listdir, remove, rmdir
exclude = frozenset(exclude)
for dir, subdirs, files, top in walk2(root):
if top:
for f in files:
if f.endswith('.pyc'):
remove(join(dir,f))
subdirs[:] = [d for d in subdirs if d not in exclude]
elif not listdir(dir):
rmdir(dir)
def walk2(top, onerror=None, followlinks=False):
'''Simultaneous topdown and bottomup version of os.walk.
For each directory in the directory tree rooted at top (including top
itself, but excluding '.' and '..'), yields a 4-tuple::
dirpath, dirnames, filenames, top
The triples (``dirpath``, ``dirnames``, ``filenames``) are the same yielded
by os.walk, however each such triple is yielded twice, once before the
subtree rooted at ``dirpath`` is visited (``top=True``) and once after
(``top=False``).
As with os.walk with ``topdown=True``, the caller can modify the dirnames
list in-place when ``top=True`` (e.g., via del or slice assignment),
and walk will only recurse into the subdirectories whose names remain in
dirnames. Modifying dirnames when ``top=False``is ineffective, since
the directories in dirnames have already been generated.
'''
from os import listdir, error
from os.path import join, isdir, islink
try:
names = listdir(top)
except error, err:
if onerror is not None:
onerror(err)
return
dirs, nondirs = [], []
for name in names:
if isdir(join(top, name)):
dirs.append(name)
else:
nondirs.append(name)
yield top, dirs, nondirs, True
for name in dirs:
path = join(top, name)
if followlinks or not islink(path):
for x in walk2(path, onerror, followlinks):
yield x
yield top, dirs, nondirs, False
if __name__ == '__main__':
import sys
cleanpycs(sys.argv[1] if len(sys.argv) > 1 else '.')