Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py: 18%

51 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:35 +0000

1# This file is dual licensed under the terms of the Apache License, Version 

2# 2.0, and the BSD License. See the LICENSE file in the root of this repository 

3# for complete details. 

4 

5import urllib.parse 

6from typing import Any, List, Optional, Set 

7 

8from ._parser import parse_requirement 

9from ._tokenizer import ParserSyntaxError 

10from .markers import Marker, _normalize_extra_values 

11from .specifiers import SpecifierSet 

12 

13 

14class InvalidRequirement(ValueError): 

15 """ 

16 An invalid requirement was found, users should refer to PEP 508. 

17 """ 

18 

19 

20class Requirement: 

21 """Parse a requirement. 

22 

23 Parse a given requirement string into its parts, such as name, specifier, 

24 URL, and extras. Raises InvalidRequirement on a badly-formed requirement 

25 string. 

26 """ 

27 

28 # TODO: Can we test whether something is contained within a requirement? 

29 # If so how do we do that? Do we need to test against the _name_ of 

30 # the thing as well as the version? What about the markers? 

31 # TODO: Can we normalize the name and extra name? 

32 

33 def __init__(self, requirement_string: str) -> None: 

34 try: 

35 parsed = parse_requirement(requirement_string) 

36 except ParserSyntaxError as e: 

37 raise InvalidRequirement(str(e)) from e 

38 

39 self.name: str = parsed.name 

40 if parsed.url: 

41 parsed_url = urllib.parse.urlparse(parsed.url) 

42 if parsed_url.scheme == "file": 

43 if urllib.parse.urlunparse(parsed_url) != parsed.url: 

44 raise InvalidRequirement("Invalid URL given") 

45 elif not (parsed_url.scheme and parsed_url.netloc) or ( 

46 not parsed_url.scheme and not parsed_url.netloc 

47 ): 

48 raise InvalidRequirement(f"Invalid URL: {parsed.url}") 

49 self.url: Optional[str] = parsed.url 

50 else: 

51 self.url = None 

52 self.extras: Set[str] = set(parsed.extras if parsed.extras else []) 

53 self.specifier: SpecifierSet = SpecifierSet(parsed.specifier) 

54 self.marker: Optional[Marker] = None 

55 if parsed.marker is not None: 

56 self.marker = Marker.__new__(Marker) 

57 self.marker._markers = _normalize_extra_values(parsed.marker) 

58 

59 def __str__(self) -> str: 

60 parts: List[str] = [self.name] 

61 

62 if self.extras: 

63 formatted_extras = ",".join(sorted(self.extras)) 

64 parts.append(f"[{formatted_extras}]") 

65 

66 if self.specifier: 

67 parts.append(str(self.specifier)) 

68 

69 if self.url: 

70 parts.append(f"@ {self.url}") 

71 if self.marker: 

72 parts.append(" ") 

73 

74 if self.marker: 

75 parts.append(f"; {self.marker}") 

76 

77 return "".join(parts) 

78 

79 def __repr__(self) -> str: 

80 return f"<Requirement('{self}')>" 

81 

82 def __hash__(self) -> int: 

83 return hash((self.__class__.__name__, str(self))) 

84 

85 def __eq__(self, other: Any) -> bool: 

86 if not isinstance(other, Requirement): 

87 return NotImplemented 

88 

89 return ( 

90 self.name == other.name 

91 and self.extras == other.extras 

92 and self.specifier == other.specifier 

93 and self.url == other.url 

94 and self.marker == other.marker 

95 )