xpybuild.utils.antglob

Ant-style **/* globbing functionality, as used by xpybuild.pathsets.FindPaths.

GlobPatternSet

class xpybuild.utils.antglob.GlobPatternSet(patterns)[source]

Bases: object

Holds a set of one or more ant-style glob patterns, which can be used to filter a set of paths based on whether each path matches any of the specified patterns.

Typically there will be one GlobPatternSet for includes and another for excludes.

This object is immutable and thread-safe.

Glob patterns may contain ‘*’ (indicating zero or more non-slash characters) or ‘**’ (indicating zero or more characters including slashes). The ‘?’ character is not supported.

Do not call the GlobPatternSet() constructor - use create instead of constructing directly.

static create(patterns)[source]

Create a new GlobPatternSet for matching any of the specified patterns.

Patterns ending with a ‘/’ can only match directories, and patterns without can only match files.

Parameters

patterns – a string, or a list of one or more pattern strings. Glob patterns may contain ‘*’ (indicating zero or more non-slash characters) or ‘**’ (indicating zero or more characters including slashes). Backslashes are not permitted. Empty pattern strings are ignored.

getPathMatches(rootdir, filenames=None, dirnames=None, unusedPatternsTracker=None)[source]

Check these patterns against one or more basenames (dir names and filenames) within a single root directory and return the list which match at least one pattern.

Using this method is a lot more efficient than checking each file in a directory independently, especially when there are many files.

Parameters
  • rootdir – The parent of the file/dir names to be matched. Must use forward slashes not backslashes, and must end with a slash. Can be empty but not None.

  • filenames – A list of base file names within the rootdir, to be matched. There must be no empty names in the list, but an empty/None list can be specified. No slash characters may be present in the names.

  • dirnames

    A list of base directory names within the rootdir, to be

    matched. There must be no empty names in the list, but an empty/None list can be specified.

    No slash characters may be present in the names, except optionally as a suffix.

  • unusedPatternsTracker – Optionally specify an instance of GlobUnusedPatternTracker which will be notified of the patterns that are used, allow an error to be produced for any that are not used.

Returns

If either filenames or dirnames is None then the result is a single list of basenames. If both filenames and dirnames are lists (even if empty) the result is a tuple (filenames, dirnames). Directory entries will have a trailing slash only if they did in the input dirnames list.

removeUnmatchableDirectories(rootdir, dirnames)[source]

Modifies the specifies list of dirnames, removing any which cannot possibly match this include pattern. This is a useful optimization for os.walk.

As this function is intended as a quick optimization it may leave in some dirs that could not match, but will definitely not remove any that could.

Parameters
  • rootdir – The parent of the file/dir names to be matched. Must use forward slashes not backslashes, and must end with a slash. Can be empty but not None.

  • dirnames – a list of directory basenames contained in rootdir

Returns

the same dirnames instance passed in (with any modifications made).

>>> GlobPatternSet.create(['**']).removeUnmatchableDirectories('abc/def/', ['dir1', 'dir2'])
['dir1', 'dir2']
>>> GlobPatternSet.create(['**/']).removeUnmatchableDirectories('abc/def/', ['dir1', 'dir2'])
['dir1', 'dir2']
>>> GlobPatternSet.create(['**/foo']).removeUnmatchableDirectories('abc/def/', ['dir1', 'dir2'])
['dir1', 'dir2']
>>> GlobPatternSet.create(['a/b/c/d/**']).removeUnmatchableDirectories('abc/def/', ['dir1', 'dir2'])
[]
>>> GlobPatternSet.create(['abc/def/dir1/d/**']).removeUnmatchableDirectories('abc/def/', ['dir1', 'dir2'])
['dir1']
>>> GlobPatternSet.create(['abc/def/dir1/d/**/']).removeUnmatchableDirectories('abc/def/', ['dir1', 'dir2'])
['dir1']
matches(path)[source]

Returns True if the specified path matches any of the patterns in this set or False if not.

Note that getPathMatches is considerably more efficient than this method when there are several paths to be matched in the same directory.

Parameters

path – A path string. Must not be empty, must not contains backslashes, and must end with a slash if it is a directory.

GlobUnusedPatternTracker

class xpybuild.utils.antglob.GlobUnusedPatternTracker(patternSet)[source]

Bases: object

Class for recording which patterns have successfully been used in a match, in order to provide error messages or warnings listing unused patterns.

This object should not be shared between threads.

getUnusedPatterns()[source]

Returns a list of the patterns that have not been used.

antGlobMatch

xpybuild.utils.antglob.antGlobMatch(pattern, path)[source]

Matches a path against an ant-style glob pattern which may contain * or **.

If the path is a directory, it must end with a slash. Patterns ending with a / can only match directories, and patterns without can only match files.

>>> antGlobMatch('', '')
True
>>> antGlobMatch('*', 'a')
True
>>> antGlobMatch('*.b', 'a')
False
>>> antGlobMatch('*.b', 'a.b')
True
>>> antGlobMatch('b.*', 'b')
False
>>> antGlobMatch('b.*', 'b.a')
True
>>> antGlobMatch('a*b', 'ab')
True
>>> antGlobMatch('a*b', '')
False
>>> antGlobMatch('a*b', 'axxxb')
True
>>> antGlobMatch('a*b', 'axxx')
False
>>> antGlobMatch('a*b', 'xxxb')
False
>>> antGlobMatch('a/b.*/c', 'a/b.x/c')
True
>>> antGlobMatch('a/b.*/c', 'a/b/c')
False
>>> antGlobMatch('**', 'a')
True
>>> antGlobMatch('**', 'a/b/c')
True
>>> antGlobMatch('**/c', 'a/b/c')
True
>>> antGlobMatch('**/*c', 'c')
True
>>> antGlobMatch('**/b/c', 'a/b/c')
True
>>> antGlobMatch('**/d', 'a/b/c')
False
>>> antGlobMatch('a/**/b', 'a/b/c')
False
>>> antGlobMatch('a/b/**', 'a/b/c/d')
True
>>> antGlobMatch('a/b/**/*', 'a/b/c/d')
True
>>> antGlobMatch('a/**/b', 'a/b')
True
>>> antGlobMatch('a/b/**', 'a/b')
True
>>> antGlobMatch('a/b', 'a/b/c/d')
False
>>> antGlobMatch('a/**/d/e', 'a/b/c/d/e')
True
>>> antGlobMatch('*x/**/', 'x/a/b/')
True
>>> antGlobMatch('*x/**', 'x/a/b')
True
>>> antGlobMatch('*x/**/', 'x/a/b')
False
>>> antGlobMatch('*x/**', 'x/a/b/')
False
>>> antGlobMatch('*[[*', '[[') and antGlobMatch('*[[*', 'xx[[') and antGlobMatch('*ab*', 'abxx')
True
>>> antGlobMatch('*[]*', '[')
False
>>> antGlobMatch('aa*.b*c*/', 'aa.bc/') and antGlobMatch('aa*.b*c*/', 'aaxxx.bxcxx/')
True
>>> antGlobMatch('aa*b*c*', 'xaabc')
False
>>> antGlobMatch('aa*.*c*', 'aaYc')
False
>>> antGlobMatch('**/*.x', 'a/b.x/c.x')
True
>>> antGlobMatch('**/*.x', 'a/b.x/c.x/d.x')
True
>>> antGlobMatch('**/*.x', 'a/c.x/y/d.x')
True
>>> antGlobMatch('**/*.x', 'a/y/c.x/d.x')
True
>>> antGlobMatch('**/**/*.x', 'a/y/c.x/d.x')
True
>>> antGlobMatch('**/*.x/', 'a/y/c.x/d.x/')
True
>>> antGlobMatch('a/b/c/d/e/**', 'a/b/c')
False
>>> antGlobMatch('**/PPP/**/*.e', 'a/b/c/d/e/f/PPP/g/h/i/foo.e')
True
>>> antGlobMatch('**/PPP/**/*.e', 'PPP/g/h/i/foo.e')
True
>>> antGlobMatch('**/PPP/**/*.e', 'a/b/c/d/e/f/PPP/foo.e')
True
>>> antGlobMatch('**/PPP/**/*.e', 'a/b/PPP/g/h/i/j/k/l/m/n/o/foo.e')
True
>>> antGlobMatch('**/PPP/**/*.e', 'a/b/c/d/e/f/g/h/i/foo.e')
False
>>> antGlobMatch('**/PPP/**/**/**/PPP/**/**/*.e', 'f/PPP/x/PPP/foo.e')
True
>>> antGlobMatch('**/PPP/f/*.e', 'f/PPP/a/b/c/d/e/PPP/f/foo.e') # this one is debatable (could decide not to match first PPP to allow second to match, but in general hard to reliably detect that condition given any later **s would invalidate any attempt to do it by counting); this behaviour is simpler to describe and more efficient to implement
False
>>> antGlobMatch('*/**/f/*.e', 'f/PPP/a/b/c/d/e/PPP/f/foo.e') 
True