| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- # encoding: utf-8
- """
- This module provides the base definition for patterns.
- """
- import re
- from .compat import unicode
- class Pattern(object):
- """
- The :class:`Pattern` class is the abstract definition of a pattern.
- """
- # Make the class dict-less.
- __slots__ = ('include',)
- def __init__(self, include):
- """
- Initializes the :class:`Pattern` instance.
- *include* (:class:`bool` or :data:`None`) is whether the matched
- files should be included (:data:`True`), excluded (:data:`False`),
- or is a null-operation (:data:`None`).
- """
- self.include = include
- """
- *include* (:class:`bool` or :data:`None`) is whether the matched
- files should be included (:data:`True`), excluded (:data:`False`),
- or is a null-operation (:data:`None`).
- """
- def match(self, files):
- """
- Matches this pattern against the specified files.
- *files* (:class:`~collections.abc.Iterable` of :class:`str`) contains
- each file relative to the root directory (e.g., ``"relative/path/to/file"``).
- Returns an :class:`~collections.abc.Iterable` yielding each matched
- file path (:class:`str`).
- """
- raise NotImplementedError("{}.{} must override match().".format(self.__class__.__module__, self.__class__.__name__))
- class RegexPattern(Pattern):
- """
- The :class:`RegexPattern` class is an implementation of a pattern
- using regular expressions.
- """
- # Make the class dict-less.
- __slots__ = ('regex',)
- def __init__(self, pattern, include=None):
- """
- Initializes the :class:`RegexPattern` instance.
- *pattern* (:class:`unicode`, :class:`bytes`, :class:`re.RegexObject`,
- or :data:`None`) is the pattern to compile into a regular
- expression.
- *include* (:class:`bool` or :data:`None`) must be :data:`None`
- unless *pattern* is a precompiled regular expression (:class:`re.RegexObject`)
- in which case it is whether matched files should be included
- (:data:`True`), excluded (:data:`False`), or is a null operation
- (:data:`None`).
- .. NOTE:: Subclasses do not need to support the *include*
- parameter.
- """
- self.regex = None
- """
- *regex* (:class:`re.RegexObject`) is the regular expression for the
- pattern.
- """
- if isinstance(pattern, (unicode, bytes)):
- assert include is None, "include:{!r} must be null when pattern:{!r} is a string.".format(include, pattern)
- regex, include = self.pattern_to_regex(pattern)
- # NOTE: Make sure to allow a null regular expression to be
- # returned for a null-operation.
- if include is not None:
- regex = re.compile(regex)
- elif pattern is not None and hasattr(pattern, 'match'):
- # Assume pattern is a precompiled regular expression.
- # - NOTE: Used specified *include*.
- regex = pattern
- elif pattern is None:
- # NOTE: Make sure to allow a null pattern to be passed for a
- # null-operation.
- assert include is None, "include:{!r} must be null when pattern:{!r} is null.".format(include, pattern)
- else:
- raise TypeError("pattern:{!r} is not a string, RegexObject, or None.".format(pattern))
- super(RegexPattern, self).__init__(include)
- self.regex = regex
- def __eq__(self, other):
- """
- Tests the equality of this regex pattern with *other* (:class:`RegexPattern`)
- by comparing their :attr:`~Pattern.include` and :attr:`~RegexPattern.regex`
- attributes.
- """
- if isinstance(other, RegexPattern):
- return self.include == other.include and self.regex == other.regex
- else:
- return NotImplemented
- def match(self, files):
- """
- Matches this pattern against the specified files.
- *files* (:class:`~collections.abc.Iterable` of :class:`str`)
- contains each file relative to the root directory (e.g., "relative/path/to/file").
- Returns an :class:`~collections.abc.Iterable` yielding each matched
- file path (:class:`str`).
- """
- if self.include is not None:
- for path in files:
- if self.regex.match(path) is not None:
- yield path
- @classmethod
- def pattern_to_regex(cls, pattern):
- """
- Convert the pattern into an uncompiled regular expression.
- *pattern* (:class:`str`) is the pattern to convert into a regular
- expression.
- Returns the uncompiled regular expression (:class:`str` or :data:`None`),
- and whether matched files should be included (:data:`True`),
- excluded (:data:`False`), or is a null-operation (:data:`None`).
- .. NOTE:: The default implementation simply returns *pattern* and
- :data:`True`.
- """
- return pattern, True
|