Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pip/_internal/models/search_scope.py: 38%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

53 statements  

1import itertools 

2import logging 

3import os 

4import posixpath 

5import urllib.parse 

6from dataclasses import dataclass 

7 

8from pip._vendor.packaging.utils import canonicalize_name 

9 

10from pip._internal.models.index import PyPI 

11from pip._internal.utils.compat import has_tls 

12from pip._internal.utils.misc import normalize_path, redact_auth_from_url 

13 

14logger = logging.getLogger(__name__) 

15 

16 

17@dataclass(frozen=True, slots=True) 

18class SearchScope: 

19 """ 

20 Encapsulates the locations that pip is configured to search. 

21 """ 

22 

23 find_links: list[str] 

24 index_urls: list[str] 

25 no_index: bool 

26 

27 @classmethod 

28 def create( 

29 cls, 

30 find_links: list[str], 

31 index_urls: list[str], 

32 no_index: bool, 

33 ) -> "SearchScope": 

34 """ 

35 Create a SearchScope object after normalizing the `find_links`. 

36 """ 

37 # Build find_links. If an argument starts with ~, it may be 

38 # a local file relative to a home directory. So try normalizing 

39 # it and if it exists, use the normalized version. 

40 # This is deliberately conservative - it might be fine just to 

41 # blindly normalize anything starting with a ~... 

42 built_find_links: list[str] = [] 

43 for link in find_links: 

44 if link.startswith("~"): 

45 new_link = normalize_path(link) 

46 if os.path.exists(new_link): 

47 link = new_link 

48 built_find_links.append(link) 

49 

50 # If we don't have TLS enabled, then WARN if anyplace we're looking 

51 # relies on TLS. 

52 if not has_tls(): 

53 for link in itertools.chain(index_urls, built_find_links): 

54 parsed = urllib.parse.urlparse(link) 

55 if parsed.scheme == "https": 

56 logger.warning( 

57 "pip is configured with locations that require " 

58 "TLS/SSL, however the ssl module in Python is not " 

59 "available." 

60 ) 

61 break 

62 

63 return cls( 

64 find_links=built_find_links, 

65 index_urls=index_urls, 

66 no_index=no_index, 

67 ) 

68 

69 def get_formatted_locations(self) -> str: 

70 lines = [] 

71 redacted_index_urls = [] 

72 if self.index_urls and self.index_urls != [PyPI.simple_url]: 

73 for url in self.index_urls: 

74 redacted_index_url = redact_auth_from_url(url) 

75 

76 # Parse the URL 

77 purl = urllib.parse.urlsplit(redacted_index_url) 

78 

79 # URL is generally invalid if scheme and netloc is missing 

80 # there are issues with Python and URL parsing, so this test 

81 # is a bit crude. See bpo-20271, bpo-23505. Python doesn't 

82 # always parse invalid URLs correctly - it should raise 

83 # exceptions for malformed URLs 

84 if not purl.scheme and not purl.netloc: 

85 logger.warning( 

86 'The index url "%s" seems invalid, please provide a scheme.', 

87 redacted_index_url, 

88 ) 

89 

90 redacted_index_urls.append(redacted_index_url) 

91 

92 lines.append( 

93 "Looking in indexes: {}".format(", ".join(redacted_index_urls)) 

94 ) 

95 

96 if self.find_links: 

97 lines.append( 

98 "Looking in links: {}".format( 

99 ", ".join(redact_auth_from_url(url) for url in self.find_links) 

100 ) 

101 ) 

102 return "\n".join(lines) 

103 

104 def get_index_urls_locations(self, project_name: str) -> list[str]: 

105 """Returns the locations found via self.index_urls 

106 

107 Checks the url_name on the main (first in the list) index and 

108 use this url_name to produce all locations 

109 """ 

110 

111 def mkurl_pypi_url(url: str) -> str: 

112 loc = posixpath.join( 

113 url, urllib.parse.quote(canonicalize_name(project_name)) 

114 ) 

115 # For maximum compatibility with easy_install, ensure the path 

116 # ends in a trailing slash. Although this isn't in the spec 

117 # (and PyPI can handle it without the slash) some other index 

118 # implementations might break if they relied on easy_install's 

119 # behavior. 

120 if not loc.endswith("/"): 

121 loc = loc + "/" 

122 return loc 

123 

124 return [mkurl_pypi_url(url) for url in self.index_urls]