diff --git a/CHANGES b/CHANGES index 0a992cf85..5f3890bd9 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,15 @@ $ pip install --user --upgrade --pre libvcs - _Add your latest changes from PRs here_ +### Breaking changes + +URL renamings (#417): + +- `Matcher` -> `Rule`, `MatcherRegistry` -> `Rules` +- `matches` -> `rule_map` +- `default_patterns` -> `patterns` +- `MATCHERS` -> `RULES` + ## libvcs 0.16.5 (2022-09-21) ### Bug fixes diff --git a/README.md b/README.md index 7ffd24ee8..4a06c9408 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ GitURL(url=git@github.com:vcs-python/libvcs.git, hostname=github.com, path=vcs-python/libvcs, suffix=.git, - matcher=core-git-scp) + rule=core-git-scp) ``` Switch repo libvcs -> vcspull: diff --git a/src/libvcs/url/base.py b/src/libvcs/url/base.py index d79545b75..de316daa0 100644 --- a/src/libvcs/url/base.py +++ b/src/libvcs/url/base.py @@ -23,8 +23,8 @@ def is_valid(self, url: str, is_explicit: Optional[bool] = None) -> bool: @dataclasses.dataclass(repr=False) -class Matcher(SkipDefaultFieldsReprMixin): - """Structure for a matcher""" +class Rule(SkipDefaultFieldsReprMixin): + """A Rule represents an eligible pattern mapping to URL.""" label: str """Computer readable name / ID""" @@ -32,18 +32,18 @@ class Matcher(SkipDefaultFieldsReprMixin): """Human readable description""" pattern: Pattern[str] """Regex pattern""" - pattern_defaults: dict[str, str] = dataclasses.field(default_factory=dict) + defaults: dict[str, str] = dataclasses.field(default_factory=dict) """Is the match unambiguous with other VCS systems? e.g. git+ prefix""" is_explicit: bool = False @dataclasses.dataclass(repr=False) -class MatcherRegistry(SkipDefaultFieldsReprMixin): +class RuleMap(SkipDefaultFieldsReprMixin): """Pattern matching and parsing capabilities for URL parsers, e.g. GitURL""" - _matchers: dict[str, Matcher] = dataclasses.field(default_factory=dict) + _rule_map: dict[str, Rule] = dataclasses.field(default_factory=dict) - def register(self, cls: Matcher) -> None: + def register(self, cls: Rule) -> None: r""" .. currentmodule:: libvcs.url.git @@ -72,7 +72,7 @@ def register(self, cls: Matcher) -> None: GitURL(url=github:org/repo, hostname=github, path=org/repo, - matcher=core-git-scp) + rule=core-git-scp) >>> GitURL(url="github:org/repo").to_url() 'git@github:org/repo' @@ -84,11 +84,11 @@ def register(self, cls: Matcher) -> None: **Extending matching capability:** - >>> class GitHubPrefix(Matcher): + >>> class GitHubPrefix(Rule): ... label = 'gh-prefix' ... description ='Matches prefixes like github:org/repo' ... pattern = r'^github:(?P.*)$' - ... pattern_defaults = { + ... defaults = { ... 'hostname': 'github.com', ... 'scheme': 'https' ... } @@ -97,8 +97,8 @@ def register(self, cls: Matcher) -> None: >>> @dataclasses.dataclass(repr=False) ... class GitHubURL(GitURL): - ... matchers: MatcherRegistry = MatcherRegistry( - ... _matchers={'github_prefix': GitHubPrefix} + ... rule_map: RuleMap = RuleMap( + ... _rule_map={'github_prefix': GitHubPrefix} ... ) >>> GitHubURL.is_valid(url='github:vcs-python/libvcs') @@ -107,14 +107,14 @@ def register(self, cls: Matcher) -> None: >>> GitHubURL.is_valid(url='github:vcs-python/libvcs', is_explicit=True) True - Notice how ``pattern_defaults`` neatly fills the values for us. + Notice how ``defaults`` neatly fills the values for us. >>> GitHubURL(url='github:vcs-python/libvcs') GitHubURL(url=github:vcs-python/libvcs, scheme=https, hostname=github.com, path=vcs-python/libvcs, - matcher=gh-prefix) + rule=gh-prefix) >>> GitHubURL(url='github:vcs-python/libvcs').to_url() 'https://github.com/vcs-python/libvcs' @@ -122,7 +122,7 @@ def register(self, cls: Matcher) -> None: >>> GitHubURL.is_valid(url='gitlab:vcs-python/libvcs') False - ``GitHubURL`` sees this as invalid since it only has one matcher, + ``GitHubURL`` sees this as invalid since it only has one rule, ``GitHubPrefix``. >>> GitURL.is_valid(url='gitlab:vcs-python/libvcs') @@ -130,25 +130,25 @@ def register(self, cls: Matcher) -> None: Same story, getting caught in ``git(1)``'s own liberal scp-style URL: - >>> GitURL(url='gitlab:vcs-python/libvcs').matcher + >>> GitURL(url='gitlab:vcs-python/libvcs').rule 'core-git-scp' - >>> class GitLabPrefix(Matcher): + >>> class GitLabPrefix(Rule): ... label = 'gl-prefix' ... description ='Matches prefixes like gitlab:org/repo' ... pattern = r'^gitlab:(?P)' - ... pattern_defaults = { + ... defaults = { ... 'hostname': 'gitlab.com', ... 'scheme': 'https', ... 'suffix': '.git' ... } - Option 1: Create a brand new matcher + Option 1: Create a brand new rule >>> @dataclasses.dataclass(repr=False) ... class GitLabURL(GitURL): - ... matchers: MatcherRegistry = MatcherRegistry( - ... _matchers={'gitlab_prefix': GitLabPrefix} + ... rule_map: RuleMap = RuleMap( + ... _rule_map={'gitlab_prefix': GitLabPrefix} ... ) >>> GitLabURL.is_valid(url='gitlab:vcs-python/libvcs') @@ -161,30 +161,30 @@ def register(self, cls: Matcher) -> None: Are we home free, though? Remember our issue with vague matches. - >>> GitURL(url='gitlab:vcs-python/libvcs').matcher + >>> GitURL(url='gitlab:vcs-python/libvcs').rule 'core-git-scp' Register: - >>> GitURL.matchers.register(GitLabPrefix) + >>> GitURL.rule_map.register(GitLabPrefix) >>> GitURL.is_valid(url='gitlab:vcs-python/libvcs') True **Example: git URLs + pip-style git URLs:** - This is already in :class:`GitURL` via :data:`PIP_DEFAULT_MATCHERS`. For the + This is already in :class:`GitURL` via :data:`PIP_DEFAULT_RULES`. For the sake of showing how extensibility works, here is a recreation based on :class:`GitBaseURL`: >>> from libvcs.url.git import GitBaseURL - >>> from libvcs.url.git import DEFAULT_MATCHERS, PIP_DEFAULT_MATCHERS + >>> from libvcs.url.git import DEFAULT_RULES, PIP_DEFAULT_RULES >>> @dataclasses.dataclass(repr=False) ... class GitURLWithPip(GitBaseURL): - ... matchers: MatcherRegistry = MatcherRegistry( - ... _matchers={m.label: m for m in [*DEFAULT_MATCHERS, *PIP_DEFAULT_MATCHERS]} + ... rule_map: RuleMap = RuleMap( + ... _rule_map={m.label: m for m in [*DEFAULT_RULES, *PIP_DEFAULT_RULES]} ... ) >>> GitURLWithPip.is_valid(url="git+ssh://git@github.com/tony/AlgoXY.git") @@ -197,19 +197,19 @@ def register(self, cls: Matcher) -> None: hostname=github.com, path=tony/AlgoXY, suffix=.git, - matcher=pip-url) + rule=pip-url) """ # NOQA: E501 - if cls.label not in self._matchers: - self._matchers[cls.label] = cls + if cls.label not in self._rule_map: + self._rule_map[cls.label] = cls def unregister(self, label: str) -> None: - if label in self._matchers: - del self._matchers[label] + if label in self._rule_map: + del self._rule_map[label] def __iter__(self) -> Iterator[str]: - return self._matchers.__iter__() + return self._rule_map.__iter__() def values( self, # https://github.com/python/typing/discussions/1033 - ) -> "dict_values[str, Matcher]": - return self._matchers.values() + ) -> "dict_values[str, Rule]": + return self._rule_map.values() diff --git a/src/libvcs/url/git.py b/src/libvcs/url/git.py index 76636cda0..470ea7b45 100644 --- a/src/libvcs/url/git.py +++ b/src/libvcs/url/git.py @@ -12,8 +12,8 @@ - Strict ``git(1)`` compatibility: :class:`GitBaseURL`. - Output ``git(1)`` URL: :meth:`GitBaseURL.to_url()` -- Extendable via :class:`~libvcs.url.base.MatcherRegistry`, - :class:`~libvcs.url.base.Matcher` +- Extendable via :class:`~libvcs.url.base.RuleMap`, + :class:`~libvcs.url.base.Rule` """ import dataclasses @@ -22,7 +22,7 @@ from libvcs._internal.dataclasses import SkipDefaultFieldsReprMixin -from .base import Matcher, MatcherRegistry, URLProtocol +from .base import Rule, RuleMap, URLProtocol # Credit, pip (license: MIT): # https://github.com/pypa/pip/blob/22.1.2/src/pip/_internal/vcs/git.py#L39-L52 @@ -60,8 +60,8 @@ # Some https repos have .git at the end, e.g. https://github.com/org/repo.git -DEFAULT_MATCHERS: list[Matcher] = [ - Matcher( +DEFAULT_RULES: list[Rule] = [ + Rule( label="core-git-https", description="Vanilla git pattern, URL ending with optional .git suffix", pattern=re.compile( @@ -76,7 +76,7 @@ ), # ends with .git. Including ones starting with https:// # e.g. https://github.com/vcs-python/libvcs.git - Matcher( + Rule( label="core-git-scp", description="Vanilla scp(1) / ssh(1) type URL", pattern=re.compile( @@ -87,7 +87,7 @@ """, re.VERBOSE, ), - pattern_defaults={"username": "git"}, + defaults={"username": "git"}, ), # SCP-style URLs, e.g. git@ ] @@ -125,8 +125,8 @@ """ -PIP_DEFAULT_MATCHERS: list[Matcher] = [ - Matcher( +PIP_DEFAULT_RULES: list[Rule] = [ + Rule( label="pip-url", description="pip-style git URL", pattern=re.compile( @@ -141,7 +141,7 @@ ), is_explicit=True, ), - Matcher( + Rule( label="pip-scp-url", description="pip-style git ssh/scp URL", pattern=re.compile( @@ -156,7 +156,7 @@ is_explicit=True, ), # file://, RTC 8089, File:// https://datatracker.ietf.org/doc/html/rfc8089 - Matcher( + Rule( label="pip-file-url", description="pip-style git+file:// URL", pattern=re.compile( @@ -191,7 +191,7 @@ - https://pip.pypa.io/en/stable/topics/vcs-support/ """ # NOQA: E501 -NPM_DEFAULT_MATCHERS: list[Matcher] = [] +NPM_DEFAULT_RULES: list[Rule] = [] """NPM-style git URLs. Git URL pattern (from docs.npmjs.com):: @@ -224,7 +224,7 @@ class GitBaseURL(URLProtocol, SkipDefaultFieldsReprMixin): hostname=github.com, path=vcs-python/libvcs, suffix=.git, - matcher=core-git-https) + rule=core-git-https) >>> myrepo = GitBaseURL(url='https://github.com/myproject/myrepo.git') @@ -240,15 +240,15 @@ class GitBaseURL(URLProtocol, SkipDefaultFieldsReprMixin): hostname=github.com, path=vcs-python/libvcs, suffix=.git, - matcher=core-git-scp) + rule=core-git-scp) - Compatibility checking: :meth:`GitBaseURL.is_valid()` - URLs compatible with ``git(1)``: :meth:`GitBaseURL.to_url()` Attributes ---------- - matcher : str - name of the :class:`~libvcs.url.base.Matcher` + rule : str + name of the :class:`~libvcs.url.base.Rule` """ url: str @@ -261,25 +261,23 @@ class GitBaseURL(URLProtocol, SkipDefaultFieldsReprMixin): # Decoration suffix: Optional[str] = None - matcher: Optional[str] = None - matchers: MatcherRegistry = MatcherRegistry( - _matchers={m.label: m for m in DEFAULT_MATCHERS} - ) + rule: Optional[str] = None + rule_map: RuleMap = RuleMap(_rule_map={m.label: m for m in DEFAULT_RULES}) def __post_init__(self) -> None: url = self.url - for matcher in self.matchers.values(): - match = re.match(matcher.pattern, url) + for rule in self.rule_map.values(): + match = re.match(rule.pattern, url) if match is None: continue groups = match.groupdict() - setattr(self, "matcher", matcher.label) + setattr(self, "rule", rule.label) for k, v in groups.items(): setattr(self, k, v) - for k, v in matcher.pattern_defaults.items(): + for k, v in rule.defaults.items(): if getattr(self, k, None) is None: - setattr(self, k, matcher.pattern_defaults[k]) + setattr(self, k, rule.defaults[k]) @classmethod def is_valid(cls, url: str, is_explicit: Optional[bool] = None) -> bool: @@ -312,11 +310,11 @@ def is_valid(cls, url: str, is_explicit: Optional[bool] = None) -> bool: """ if is_explicit is not None: return any( - re.search(matcher.pattern, url) - for matcher in cls.matchers.values() - if matcher.is_explicit == is_explicit + re.search(rule.pattern, url) + for rule in cls.rule_map.values() + if rule.is_explicit == is_explicit ) - return any(re.search(matcher.pattern, url) for matcher in cls.matchers.values()) + return any(re.search(rule.pattern, url) for rule in cls.rule_map.values()) def to_url(self) -> str: """Return a ``git(1)``-compatible URL. Can be used with ``git clone``. @@ -332,7 +330,7 @@ def to_url(self) -> str: hostname=github.com, path=vcs-python/libvcs, suffix=.git, - matcher=core-git-scp) + rule=core-git-scp) Switch repo libvcs -> vcspull: @@ -372,9 +370,7 @@ class GitPipURL(GitBaseURL, URLProtocol, SkipDefaultFieldsReprMixin): # commit-ish (rev): tag, branch, ref rev: Optional[str] = None - matchers: MatcherRegistry = MatcherRegistry( - _matchers={m.label: m for m in PIP_DEFAULT_MATCHERS} - ) + rule_map: RuleMap = RuleMap(_rule_map={m.label: m for m in PIP_DEFAULT_RULES}) def to_url(self) -> str: """Exports a pip-compliant URL. @@ -394,7 +390,7 @@ def to_url(self) -> str: port=7999, path=PROJ/repo, suffix=.git, - matcher=pip-url) + rule=pip-url) >>> git_url.path = 'libvcs/vcspull' @@ -413,7 +409,7 @@ def to_url(self) -> str: hostname=github.com, path=vcs-python/libvcs, suffix=.git, - matcher=pip-url, + rule=pip-url, rev=v0.10.0) >>> git_url.path = 'libvcs/vcspull' @@ -456,7 +452,7 @@ def is_valid(cls, url: str, is_explicit: Optional[bool] = None) -> bool: **Explicit VCS detection** - Pip-style URLs are prefixed with the VCS name in front, so its matchers can + Pip-style URLs are prefixed with the VCS name in front, so its rule_map can unambigously narrow the type of VCS: >>> GitPipURL.is_valid( @@ -482,13 +478,13 @@ class GitURL(GitPipURL, GitBaseURL, URLProtocol, SkipDefaultFieldsReprMixin): - :meth:`GitBaseURL.to_url` """ - matchers: MatcherRegistry = MatcherRegistry( - _matchers={m.label: m for m in [*DEFAULT_MATCHERS, *PIP_DEFAULT_MATCHERS]} + rule_map: RuleMap = RuleMap( + _rule_map={m.label: m for m in [*DEFAULT_RULES, *PIP_DEFAULT_RULES]} ) @classmethod def is_valid(cls, url: str, is_explicit: Optional[bool] = None) -> bool: - r"""Whether URL is compatible included Git URL matchers or not. + r"""Whether URL is compatible included Git URL rule_map or not. Examples -------- @@ -514,7 +510,7 @@ def is_valid(cls, url: str, is_explicit: Optional[bool] = None) -> bool: **Explicit VCS detection** - Pip-style URLs are prefixed with the VCS name in front, so its matchers can + Pip-style URLs are prefixed with the VCS name in front, so its rule_map can unambigously narrow the type of VCS: >>> GitURL.is_valid( @@ -530,12 +526,12 @@ def is_valid(cls, url: str, is_explicit: Optional[bool] = None) -> bool: ... ) False - You could create a GitHub matcher that consider github.com hostnames to be + You could create a GitHub rule that consider github.com hostnames to be exclusively git: - >>> GitHubMatcher = Matcher( + >>> GitHubRule = Rule( ... # Since github.com exclusively serves git repos, make explicit - ... label='gh-matcher', + ... label='gh-rule', ... description='Matches github.com https URLs, exact VCS match', ... pattern=re.compile( ... rf''' @@ -548,26 +544,26 @@ def is_valid(cls, url: str, is_explicit: Optional[bool] = None) -> bool: ... re.VERBOSE, ... ), ... is_explicit=True, - ... pattern_defaults={ + ... defaults={ ... 'hostname': 'github.com' ... } ... ) - >>> GitURL.matchers.register(GitHubMatcher) + >>> GitURL.rule_map.register(GitHubRule) >>> GitURL.is_valid( ... url='git@github.com:vcs-python/libvcs.git', is_explicit=True ... ) True - >>> GitURL(url='git@github.com:vcs-python/libvcs.git').matcher - 'gh-matcher' + >>> GitURL(url='git@github.com:vcs-python/libvcs.git').rule + 'gh-rule' This is just us cleaning up: - >>> GitURL.matchers.unregister('gh-matcher') + >>> GitURL.rule_map.unregister('gh-rule') - >>> GitURL(url='git@github.com:vcs-python/libvcs.git').matcher + >>> GitURL(url='git@github.com:vcs-python/libvcs.git').rule 'core-git-scp' """ return super().is_valid(url=url, is_explicit=is_explicit) diff --git a/src/libvcs/url/hg.py b/src/libvcs/url/hg.py index 412f1cee6..74917b2d9 100644 --- a/src/libvcs/url/hg.py +++ b/src/libvcs/url/hg.py @@ -6,8 +6,8 @@ compare to :class:`urllib.parse.ParseResult` - Output ``hg(1)`` URL: :meth:`HgURL.to_url()` -- Extendable via :class:`~libvcs.url.base.MatcherRegistry`, - :class:`~libvcs.url.base.Matcher` +- Extendable via :class:`~libvcs.url.base.RuleMap`, + :class:`~libvcs.url.base.Rule` .. Note:: @@ -23,7 +23,7 @@ from libvcs._internal.dataclasses import SkipDefaultFieldsReprMixin -from .base import Matcher, MatcherRegistry, URLProtocol +from .base import Rule, RuleMap, URLProtocol RE_PATH = r""" ((?P\w+)@)? @@ -43,8 +43,8 @@ ) """ -DEFAULT_MATCHERS: list[Matcher] = [ - Matcher( +DEFAULT_RULES: list[Rule] = [ + Rule( label="core-hg", description="Vanilla hg pattern", pattern=re.compile( @@ -74,8 +74,8 @@ ) """ -PIP_DEFAULT_MATCHERS: list[Matcher] = [ - Matcher( +PIP_DEFAULT_RULES: list[Rule] = [ + Rule( label="pip-url", description="pip-style hg URL", pattern=re.compile( @@ -88,7 +88,7 @@ ), ), # file://, RTC 8089, File:// https://datatracker.ietf.org/doc/html/rfc8089 - Matcher( + Rule( label="pip-file-url", description="pip-style hg+file:// URL", pattern=re.compile( @@ -129,8 +129,8 @@ class HgURL(URLProtocol, SkipDefaultFieldsReprMixin): Attributes ---------- - matcher : str - name of the :class:`~libvcs.url.base.Matcher` + rule : str + name of the :class:`~libvcs.url.base.Rule` Examples -------- @@ -139,7 +139,7 @@ class HgURL(URLProtocol, SkipDefaultFieldsReprMixin): scheme=https, hostname=hg.mozilla.org, path=mozilla-central/, - matcher=core-hg) + rule=core-hg) >>> myrepo = HgURL(url='https://hg.mozilla.org/mozilla-central/') @@ -155,7 +155,7 @@ class HgURL(URLProtocol, SkipDefaultFieldsReprMixin): user=username, hostname=machinename, path=path/to/repo, - matcher=core-hg) + rule=core-hg) - Compatibility checking: :meth:`HgURL.is_valid()` - URLs compatible with ``hg(1)``: :meth:`HgURL.to_url()` @@ -174,26 +174,24 @@ class HgURL(URLProtocol, SkipDefaultFieldsReprMixin): # ref: Optional[str] = None - matcher: Optional[str] = None - # name of the :class:`Matcher` - matchers: MatcherRegistry = MatcherRegistry( - _matchers={m.label: m for m in DEFAULT_MATCHERS} - ) + rule: Optional[str] = None + # name of the :class:`Rule` + rule_map: RuleMap = RuleMap(_rule_map={m.label: m for m in DEFAULT_RULES}) def __post_init__(self) -> None: url = self.url - for matcher in self.matchers.values(): - match = re.match(matcher.pattern, url) + for rule in self.rule_map.values(): + match = re.match(rule.pattern, url) if match is None: continue groups = match.groupdict() - setattr(self, "matcher", matcher.label) + setattr(self, "rule", rule.label) for k, v in groups.items(): setattr(self, k, v) - for k, v in matcher.pattern_defaults.items(): + for k, v in rule.defaults.items(): if getattr(self, k, None) is None: - setattr(self, k, matcher.pattern_defaults[k]) + setattr(self, k, rule.defaults[k]) @classmethod def is_valid(cls, url: str, is_explicit: Optional[bool] = False) -> bool: @@ -213,7 +211,7 @@ def is_valid(cls, url: str, is_explicit: Optional[bool] = False) -> bool: >>> HgURL.is_valid(url='notaurl') False """ - return any(re.search(matcher.pattern, url) for matcher in cls.matchers.values()) + return any(re.search(rule.pattern, url) for rule in cls.rule_map.values()) def to_url(self) -> str: """Return a ``hg(1)``-compatible URL. Can be used with ``hg clone``. @@ -228,7 +226,7 @@ def to_url(self) -> str: scheme=https, hostname=hg.mozilla.org, path=mozilla-central, - matcher=core-hg) + rule=core-hg) Switch repo libvcs -> vcspull: @@ -255,7 +253,7 @@ def to_url(self) -> str: hostname=hugin.hg.sourceforge.net, port=8000, path=hgroot/hugin/hugin, - matcher=core-hg) + rule=core-hg) >>> hugin.to_url() 'http://hugin.hg.sourceforge.net:8000/hgroot/hugin/hugin' @@ -272,7 +270,7 @@ def to_url(self) -> str: user=yourid, hostname=hg.GraphicsMagick.org, path=/hg/GraphicsMagick, - matcher=core-hg) + rule=core-hg) >>> graphicsmagick.to_url() 'ssh://yourid@hg.GraphicsMagick.org//hg/GraphicsMagick' diff --git a/src/libvcs/url/svn.py b/src/libvcs/url/svn.py index ddafb3a8d..1e32a8772 100644 --- a/src/libvcs/url/svn.py +++ b/src/libvcs/url/svn.py @@ -6,8 +6,8 @@ compare to :class:`urllib.parse.ParseResult` - Output ``svn(1)`` URL: :meth:`SvnURL.to_url()` -- Extendable via :class:`~libvcs.url.base.MatcherRegistry`, - :class:`~libvcs.url.base.Matcher` +- Extendable via :class:`~libvcs.url.base.RuleMap`, + :class:`~libvcs.url.base.Rule` .. Note:: @@ -24,7 +24,7 @@ from libvcs._internal.dataclasses import SkipDefaultFieldsReprMixin -from .base import Matcher, MatcherRegistry, URLProtocol +from .base import Rule, RuleMap, URLProtocol RE_PATH = r""" ((?P.*)@)? @@ -47,8 +47,8 @@ ) """ -DEFAULT_MATCHERS: list[Matcher] = [ - Matcher( +DEFAULT_RULES: list[Rule] = [ + Rule( label="core-svn", description="Vanilla svn pattern", pattern=re.compile( @@ -78,8 +78,8 @@ ) """ -PIP_DEFAULT_MATCHERS: list[Matcher] = [ - Matcher( +PIP_DEFAULT_RULES: list[Rule] = [ + Rule( label="pip-url", description="pip-style svn URL", pattern=re.compile( @@ -92,7 +92,7 @@ ), ), # file://, RTC 8089, File:// https://datatracker.ietf.org/doc/html/rfc8089 - Matcher( + Rule( label="pip-file-url", description="pip-style svn+file:// URL", pattern=re.compile( @@ -135,7 +135,7 @@ class SvnURL(URLProtocol, SkipDefaultFieldsReprMixin): scheme=svn+ssh, hostname=svn.debian.org, path=svn/aliothproj/path/in/project/repository, - matcher=core-svn) + rule=core-svn) >>> myrepo = SvnURL( ... url='svn+ssh://svn.debian.org/svn/aliothproj/path/in/project/repository' @@ -152,8 +152,8 @@ class SvnURL(URLProtocol, SkipDefaultFieldsReprMixin): Attributes ---------- - matcher : str - name of the :class:`~libvcs.url.base.Matcher` + rule : str + name of the :class:`~libvcs.url.base.Rule` """ url: str @@ -169,25 +169,23 @@ class SvnURL(URLProtocol, SkipDefaultFieldsReprMixin): # ref: Optional[str] = None - matcher: Optional[str] = None - matchers: MatcherRegistry = MatcherRegistry( - _matchers={m.label: m for m in DEFAULT_MATCHERS} - ) + rule: Optional[str] = None + rule_map: RuleMap = RuleMap(_rule_map={m.label: m for m in DEFAULT_RULES}) def __post_init__(self) -> None: url = self.url - for matcher in self.matchers.values(): - match = re.match(matcher.pattern, url) + for rule in self.rule_map.values(): + match = re.match(rule.pattern, url) if match is None: continue groups = match.groupdict() - setattr(self, "matcher", matcher.label) + setattr(self, "rule", rule.label) for k, v in groups.items(): setattr(self, k, v) - for k, v in matcher.pattern_defaults.items(): + for k, v in rule.defaults.items(): if getattr(self, k, None) is None: - setattr(self, k, matcher.pattern_defaults[k]) + setattr(self, k, rule.defaults[k]) @classmethod def is_valid(cls, url: str, is_explicit: Optional[bool] = False) -> bool: @@ -204,7 +202,7 @@ def is_valid(cls, url: str, is_explicit: Optional[bool] = False) -> bool: >>> SvnURL.is_valid(url='notaurl') False """ - return any(re.search(matcher.pattern, url) for matcher in cls.matchers.values()) + return any(re.search(rule.pattern, url) for rule in cls.rule_map.values()) def to_url(self) -> str: """Return a ``svn(1)``-compatible URL. Can be used with ``svn checkout``. @@ -222,7 +220,7 @@ def to_url(self) -> str: user=my-username, hostname=my-server, path=vcs-python/libvcs, - matcher=core-svn) + rule=core-svn) Switch repo libvcs -> vcspull: diff --git a/tests/url/test_git.py b/tests/url/test_git.py index 76102863d..ebf1397a8 100644 --- a/tests/url/test_git.py +++ b/tests/url/test_git.py @@ -3,8 +3,8 @@ import pytest from libvcs.sync.git import GitSync -from libvcs.url.base import MatcherRegistry -from libvcs.url.git import DEFAULT_MATCHERS, PIP_DEFAULT_MATCHERS, GitBaseURL, GitURL +from libvcs.url.base import RuleMap +from libvcs.url.git import DEFAULT_RULES, PIP_DEFAULT_RULES, GitBaseURL, GitURL class GitURLFixture(typing.NamedTuple): @@ -142,8 +142,8 @@ def test_git_url_extension_pip( git_repo: GitSync, ) -> None: class GitURLWithPip(GitBaseURL): - matchers: MatcherRegistry = MatcherRegistry( - _matchers={m.label: m for m in [*DEFAULT_MATCHERS, *PIP_DEFAULT_MATCHERS]} + rule_map: RuleMap = RuleMap( + _rule_map={m.label: m for m in [*DEFAULT_RULES, *PIP_DEFAULT_RULES]} ) git_url_kwargs["url"] = git_url_kwargs["url"].format(local_repo=git_repo.dir) @@ -255,8 +255,8 @@ def test_git_revs( git_url_kwargs: GitURLKwargs, ) -> None: class GitURLWithPip(GitURL): - matchers: MatcherRegistry = MatcherRegistry( - _matchers={m.label: m for m in [*DEFAULT_MATCHERS, *PIP_DEFAULT_MATCHERS]} + rule_map: RuleMap = RuleMap( + _rule_map={m.label: m for m in [*DEFAULT_RULES, *PIP_DEFAULT_RULES]} ) git_url = GitURLWithPip(**git_url_kwargs) diff --git a/tests/url/test_hg.py b/tests/url/test_hg.py index 283a4e1a5..6de7c64b9 100644 --- a/tests/url/test_hg.py +++ b/tests/url/test_hg.py @@ -3,8 +3,8 @@ import pytest from libvcs.sync.hg import HgSync -from libvcs.url.base import MatcherRegistry -from libvcs.url.hg import DEFAULT_MATCHERS, PIP_DEFAULT_MATCHERS, HgURL +from libvcs.url.base import RuleMap +from libvcs.url.hg import DEFAULT_RULES, PIP_DEFAULT_RULES, HgURL class HgURLFixture(typing.NamedTuple): @@ -107,8 +107,8 @@ def test_hg_url_extension_pip( hg_repo: HgSync, ) -> None: class HgURLWithPip(HgURL): - matchers: MatcherRegistry = MatcherRegistry( - _matchers={m.label: m for m in [*DEFAULT_MATCHERS, *PIP_DEFAULT_MATCHERS]} + rule_map: RuleMap = RuleMap( + _rule_map={m.label: m for m in [*DEFAULT_RULES, *PIP_DEFAULT_RULES]} ) hg_url_kwargs["url"] = hg_url_kwargs["url"].format(local_repo=hg_repo.dir) diff --git a/tests/url/test_svn.py b/tests/url/test_svn.py index 0a607c7a6..d86a33125 100644 --- a/tests/url/test_svn.py +++ b/tests/url/test_svn.py @@ -3,8 +3,8 @@ import pytest from libvcs.sync.svn import SvnSync -from libvcs.url.base import MatcherRegistry -from libvcs.url.svn import DEFAULT_MATCHERS, PIP_DEFAULT_MATCHERS, SvnURL +from libvcs.url.base import RuleMap +from libvcs.url.svn import DEFAULT_RULES, PIP_DEFAULT_RULES, SvnURL class SvnURLFixture(typing.NamedTuple): @@ -124,8 +124,8 @@ def test_svn_url_extension_pip( svn_repo: SvnSync, ) -> None: class SvnURLWithPip(SvnURL): - matchers: MatcherRegistry = MatcherRegistry( - _matchers={m.label: m for m in [*DEFAULT_MATCHERS, *PIP_DEFAULT_MATCHERS]} + rule_map: RuleMap = RuleMap( + _rule_map={m.label: m for m in [*DEFAULT_RULES, *PIP_DEFAULT_RULES]} ) svn_url_kwargs["url"] = svn_url_kwargs["url"].format(local_repo=svn_repo.dir)