Index: Doc/library/filecmp.rst =================================================================== --- Doc/library/filecmp.rst (revision 62288) +++ Doc/library/filecmp.rst (working copy) @@ -59,12 +59,14 @@ :class:`dircmp` instances are built using this constructor: -.. class:: dircmp(a, b[, ignore[, hide]]) +.. class:: dircmp(a, b [, ignore][, hide][, match]) Construct a new directory comparison object, to compare the directories *a* and - *b*. *ignore* is a list of names to ignore, and defaults to ``['RCS', 'CVS', - 'tags']``. *hide* is a list of names to hide, and defaults to ``[os.curdir, - os.pardir]``. + *b*. *ignore* is a list of patterns for names to ignore, and defaults to + ``['RCS', 'CVS', 'tags']``. *hide* is a list of patterns for names to hide, + and defaults to ``[os.curdir, os.pardir]``. *match* is a function used to + compare names to the patterns provided in `ignore` and `hide`, and defaults + to function `fnmatch` imported from module `fnmatch`. The :class:`dircmp` class provides the following methods: @@ -150,4 +152,3 @@ .. attribute:: dircmp.subdirs A dictionary mapping names in :attr:`common_dirs` to :class:`dircmp` objects. - Index: Lib/filecmp.py =================================================================== --- Lib/filecmp.py (revision 62288) +++ Lib/filecmp.py (working copy) @@ -13,6 +13,7 @@ import stat import warnings from itertools import ifilter, ifilterfalse, imap, izip +from fnmatch import fnmatch __all__ = ["cmp","dircmp","cmpfiles"] @@ -78,12 +79,15 @@ class dircmp: """A class that manages the comparison of 2 directories. - dircmp(a,b,ignore=None,hide=None) + dircmp(a,b,ignore=None,hide=None,match=fnmatch) A and B are directories. - IGNORE is a list of names to ignore, + IGNORE is a list of patterns for names to ignore, defaults to ['RCS', 'CVS', 'tags']. - HIDE is a list of names to hide, + HIDE is a list of pattern for names to hide, defaults to [os.curdir, os.pardir]. + MATCH is a function used to compare names to the patterns provided in + IGNORE and HIDE, defaults to function 'fnmatch' imported from + module 'fnmatch'. High level usage: x = dircmp(dir1, dir2) @@ -109,23 +113,19 @@ subdirs: a dictionary of dircmp objects, keyed by names in common_dirs. """ - def __init__(self, a, b, ignore=None, hide=None): # Initialize + def __init__(self, a, b, ignore=['RCS', 'CVS', 'tags'], + hide=[os.curdir, os.pardir], match=fnmatch): self.left = a self.right = b - if hide is None: - self.hide = [os.curdir, os.pardir] # Names never to be shown - else: - self.hide = hide - if ignore is None: - self.ignore = ['RCS', 'CVS', 'tags'] # Names ignored in comparison - else: - self.ignore = ignore + self.ignore = ignore + self.hide = hide + self.match = match def phase0(self): # Compare everything except common subdirectories self.left_list = _filter(os.listdir(self.left), - self.hide+self.ignore) + self.hide+self.ignore, self.match) self.right_list = _filter(os.listdir(self.right), - self.hide+self.ignore) + self.hide+self.ignore, self.match) self.left_list.sort() self.right_list.sort() @@ -273,10 +273,15 @@ return 2 -# Return a copy with items that occur in skip removed. +# Return a copy with items that match a pattern in skip removed. # -def _filter(flist, skip): - return list(ifilterfalse(skip.__contains__, flist)) +def _filter(flist, skip, match): + def _match_any(name): + for pattern in skip: + if match(name, pattern): + return True + return False + return list(ifilterfalse(_match_any, flist)) # Demonstration and testing. Index: Lib/test/test_filecmp.py =================================================================== --- Lib/test/test_filecmp.py (revision 62288) +++ Lib/test/test_filecmp.py (working copy) @@ -52,12 +52,19 @@ shutil.rmtree(dir, True) os.mkdir(dir) if self.caseinsensitive and dir is self.dir_same: - fn = 'FiLe' # Verify case-insensitive comparison + fn1 = 'FiLe' # Verify case-insensitive comparison + fn2 = fn1 + '.TMP' + dir_ign = os.path.join(dir, 'Dir-Ignore') else: - fn = 'file' - output = open(os.path.join(dir, fn), 'w') - output.write(data) - output.close() + fn1 = 'file' + fn2 = fn1 + '.tmp' + dir_ign = os.path.join(dir, 'dir-ignore') + os.mkdir(dir_ign) + for dn in [dir, dir_ign]: + for fn in [fn1, fn2]: + output = open(os.path.join(dn, fn), 'w') + output.write(data) + output.close() output = open(os.path.join(self.dir_diff, 'file2'), 'w') output.write('An extra file.\n') @@ -98,7 +105,8 @@ def test_dircmp(self): # Check attributes for comparison of two identical directories - d = filecmp.dircmp(self.dir, self.dir_same) + ignore = ['*ignore*', '*.tmp'] + d = filecmp.dircmp(self.dir, self.dir_same, ignore=ignore) if self.caseinsensitive: self.assertEqual([d.left_list, d.right_list],[['file'], ['FiLe']]) else: @@ -109,7 +117,7 @@ self.failUnless(d.diff_files == []) # Check attributes for comparison of two different directories - d = filecmp.dircmp(self.dir, self.dir_diff) + d = filecmp.dircmp(self.dir, self.dir_diff, ignore=ignore) self.failUnless(d.left_list == ['file']) self.failUnless(d.right_list == ['file', 'file2']) self.failUnless(d.common == ['file']) @@ -122,7 +130,7 @@ output = open(os.path.join(self.dir, 'file2'), 'w') output.write('Different contents.\n') output.close() - d = filecmp.dircmp(self.dir, self.dir_diff) + d = filecmp.dircmp(self.dir, self.dir_diff, ignore=ignore) self.failUnless(d.same_files == ['file']) self.failUnless(d.diff_files == ['file2'])