Split a PEP 508 requirement into its canonical name and whether it dev-pins its floor. Uses ``packaging`` to parse the requirement and its version specifiers rather than ad hoc string handling, so name normalization, extras, markers and PEP 440 version semantics are all handled by the s
(requirement: str)
| 81 | |
| 82 | |
| 83 | def _parse_requirement(requirement: str) -> tuple[str, bool]: |
| 84 | """Split a PEP 508 requirement into its canonical name and whether it dev-pins its floor. |
| 85 | |
| 86 | Uses ``packaging`` to parse the requirement and its version specifiers rather than ad hoc |
| 87 | string handling, so name normalization, extras, markers and PEP 440 version semantics are |
| 88 | all handled by the standard implementation. |
| 89 | |
| 90 | Args: |
| 91 | requirement: A dependency string such as ``"reflex-base >= 0.9.5.dev1"``. |
| 92 | |
| 93 | Returns: |
| 94 | A ``(canonical_name, is_dev_pinned)`` tuple. ``is_dev_pinned`` is ``True`` only when a |
| 95 | development release (unpublished by convention) appears as a lower bound — under a |
| 96 | ``>=``, ``>``, ``==``, ``===`` or ``~=`` operator. A dev release in an upper-bound or |
| 97 | ``!=`` clause (e.g. ``reflex-base >=1.0,!=2.0.dev1``) stays resolvable from PyPI and |
| 98 | does not count. An unparsable requirement is reported as ``("", False)``. |
| 99 | """ |
| 100 | try: |
| 101 | parsed = Requirement(requirement) |
| 102 | except InvalidRequirement: |
| 103 | return "", False |
| 104 | name = canonicalize_name(parsed.name) |
| 105 | for specifier in parsed.specifier: |
| 106 | if specifier.operator not in _LOWER_BOUND_OPERATORS: |
| 107 | continue |
| 108 | try: |
| 109 | if Version(specifier.version).is_devrelease: |
| 110 | return name, True |
| 111 | except InvalidVersion: |
| 112 | # A prefix match such as ``==1.2.*`` has no concrete version to inspect. |
| 113 | continue |
| 114 | return name, False |
| 115 | |
| 116 | |
| 117 | @dataclass(frozen=True) |
no outgoing calls
no test coverage detected