You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			92 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			92 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Python
		
	
# This file is dual licensed under the terms of the Apache License, Version
 | 
						|
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
 | 
						|
# for complete details.
 | 
						|
from __future__ import annotations
 | 
						|
 | 
						|
from typing import Any, Iterator
 | 
						|
 | 
						|
from ._parser import parse_requirement as _parse_requirement
 | 
						|
from ._tokenizer import ParserSyntaxError
 | 
						|
from .markers import Marker, _normalize_extra_values
 | 
						|
from .specifiers import SpecifierSet
 | 
						|
from .utils import canonicalize_name
 | 
						|
 | 
						|
 | 
						|
class InvalidRequirement(ValueError):
 | 
						|
    """
 | 
						|
    An invalid requirement was found, users should refer to PEP 508.
 | 
						|
    """
 | 
						|
 | 
						|
 | 
						|
class Requirement:
 | 
						|
    """Parse a requirement.
 | 
						|
 | 
						|
    Parse a given requirement string into its parts, such as name, specifier,
 | 
						|
    URL, and extras. Raises InvalidRequirement on a badly-formed requirement
 | 
						|
    string.
 | 
						|
    """
 | 
						|
 | 
						|
    # TODO: Can we test whether something is contained within a requirement?
 | 
						|
    #       If so how do we do that? Do we need to test against the _name_ of
 | 
						|
    #       the thing as well as the version? What about the markers?
 | 
						|
    # TODO: Can we normalize the name and extra name?
 | 
						|
 | 
						|
    def __init__(self, requirement_string: str) -> None:
 | 
						|
        try:
 | 
						|
            parsed = _parse_requirement(requirement_string)
 | 
						|
        except ParserSyntaxError as e:
 | 
						|
            raise InvalidRequirement(str(e)) from e
 | 
						|
 | 
						|
        self.name: str = parsed.name
 | 
						|
        self.url: str | None = parsed.url or None
 | 
						|
        self.extras: set[str] = set(parsed.extras or [])
 | 
						|
        self.specifier: SpecifierSet = SpecifierSet(parsed.specifier)
 | 
						|
        self.marker: Marker | None = None
 | 
						|
        if parsed.marker is not None:
 | 
						|
            self.marker = Marker.__new__(Marker)
 | 
						|
            self.marker._markers = _normalize_extra_values(parsed.marker)
 | 
						|
 | 
						|
    def _iter_parts(self, name: str) -> Iterator[str]:
 | 
						|
        yield name
 | 
						|
 | 
						|
        if self.extras:
 | 
						|
            formatted_extras = ",".join(sorted(self.extras))
 | 
						|
            yield f"[{formatted_extras}]"
 | 
						|
 | 
						|
        if self.specifier:
 | 
						|
            yield str(self.specifier)
 | 
						|
 | 
						|
        if self.url:
 | 
						|
            yield f"@ {self.url}"
 | 
						|
            if self.marker:
 | 
						|
                yield " "
 | 
						|
 | 
						|
        if self.marker:
 | 
						|
            yield f"; {self.marker}"
 | 
						|
 | 
						|
    def __str__(self) -> str:
 | 
						|
        return "".join(self._iter_parts(self.name))
 | 
						|
 | 
						|
    def __repr__(self) -> str:
 | 
						|
        return f"<Requirement('{self}')>"
 | 
						|
 | 
						|
    def __hash__(self) -> int:
 | 
						|
        return hash(
 | 
						|
            (
 | 
						|
                self.__class__.__name__,
 | 
						|
                *self._iter_parts(canonicalize_name(self.name)),
 | 
						|
            )
 | 
						|
        )
 | 
						|
 | 
						|
    def __eq__(self, other: Any) -> bool:
 | 
						|
        if not isinstance(other, Requirement):
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
        return (
 | 
						|
            canonicalize_name(self.name) == canonicalize_name(other.name)
 | 
						|
            and self.extras == other.extras
 | 
						|
            and self.specifier == other.specifier
 | 
						|
            and self.url == other.url
 | 
						|
            and self.marker == other.marker
 | 
						|
        )
 |