Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
glob.py117 linesDownload Raw Back to zipp
1import os2import re3 4from .compat.py313 import legacy_end_marker5 6_default_seps = os.sep + str(os.altsep) * bool(os.altsep)7 8 9class Translator:10    """11    >>> Translator('xyz')12    Traceback (most recent call last):13    ...14    AssertionError: Invalid separators15 16    >>> Translator('')17    Traceback (most recent call last):18    ...19    AssertionError: Invalid separators20    """21 22    seps: str23 24    def __init__(self, seps: str = _default_seps):25        assert seps and set(seps) <= set(_default_seps), "Invalid separators"26        self.seps = seps27 28    def translate(self, pattern):29        """30        Given a glob pattern, produce a regex that matches it.31        """32        return self.extend(self.match_dirs(self.translate_core(pattern)))33 34    @legacy_end_marker35    def extend(self, pattern):36        r"""37        Extend regex for pattern-wide concerns.38 39        Apply '(?s:)' to create a non-matching group that40        matches newlines (valid on Unix).41 42        Append '\z' to imply fullmatch even when match is used.43        """44        return rf'(?s:{pattern})\z'45 46    def match_dirs(self, pattern):47        """48        Ensure that zipfile.Path directory names are matched.49 50        zipfile.Path directory names always end in a slash.51        """52        return rf'{pattern}[/]?'53 54    def translate_core(self, pattern):55        r"""56        Given a glob pattern, produce a regex that matches it.57 58        >>> t = Translator()59        >>> t.translate_core('*.txt').replace('\\\\', '')60        '[^/]*\\.txt'61        >>> t.translate_core('a?txt')62        'a[^/]txt'63        >>> t.translate_core('**/*').replace('\\\\', '')64        '.*/[^/][^/]*'65        """66        self.restrict_rglob(pattern)67        return ''.join(map(self.replace, separate(self.star_not_empty(pattern))))68 69    def replace(self, match):70        """71        Perform the replacements for a match from :func:`separate`.72        """73        return match.group('set') or (74            re.escape(match.group(0))75            .replace('\\*\\*', r'.*')76            .replace('\\*', rf'[^{re.escape(self.seps)}]*')77            .replace('\\?', r'[^/]')78        )79 80    def restrict_rglob(self, pattern):81        """82        Raise ValueError if ** appears in anything but a full path segment.83 84        >>> Translator().translate('**foo')85        Traceback (most recent call last):86        ...87        ValueError: ** must appear alone in a path segment88        """89        seps_pattern = rf'[{re.escape(self.seps)}]+'90        segments = re.split(seps_pattern, pattern)91        if any('**' in segment and segment != '**' for segment in segments):92            raise ValueError("** must appear alone in a path segment")93 94    def star_not_empty(self, pattern):95        """96        Ensure that * will not match an empty segment.97        """98 99        def handle_segment(match):100            segment = match.group(0)101            return '?*' if segment == '*' else segment102 103        not_seps_pattern = rf'[^{re.escape(self.seps)}]+'104        return re.sub(not_seps_pattern, handle_segment, pattern)105 106 107def separate(pattern):108    """109    Separate out character sets to avoid translating their contents.110 111    >>> [m.group(0) for m in separate('*.txt')]112    ['*.txt']113    >>> [m.group(0) for m in separate('a[?]txt')]114    ['a', '[?]', 'txt']115    """116    return re.finditer(r'([^\[]+)|(?P<set>[\[].*?[\]])|([\[][^\]]*$)', pattern)117 
codekingpro/portable-devtools · Team Ai