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

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

54 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) 

18class SearchScope: 

19 """ 

20 Encapsulates the locations that pip is configured to search. 

21 """ 

22 

23 __slots__ = ["find_links", "index_urls", "no_index"] 

24 

25 find_links: list[str] 

26 index_urls: list[str] 

27 no_index: bool 

28 

29 @classmethod 

30 def create( 

31 cls, 

32 find_links: list[str], 

33 index_urls: list[str], 

34 no_index: bool, 

35 ) -> "SearchScope": 

36 """ 

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

38 """ 

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

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

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

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

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

44 built_find_links: list[str] = [] 

45 for link in find_links: 

46 if link.startswith("~"): 

47 new_link = normalize_path(link) 

48 if os.path.exists(new_link): 

49 link = new_link 

50 built_find_links.append(link) 

51 

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

53 # relies on TLS. 

54 if not has_tls(): 

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

56 parsed = urllib.parse.urlparse(link) 

57 if parsed.scheme == "https": 

58 logger.warning( 

59 "pip is configured with locations that require " 

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

61 "available." 

62 ) 

63 break 

64 

65 return cls( 

66 find_links=built_find_links, 

67 index_urls=index_urls, 

68 no_index=no_index, 

69 ) 

70 

71 def get_formatted_locations(self) -> str: 

72 lines = [] 

73 redacted_index_urls = [] 

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

75 for url in self.index_urls: 

76 redacted_index_url = redact_auth_from_url(url) 

77 

78 # Parse the URL 

79 purl = urllib.parse.urlsplit(redacted_index_url) 

80 

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

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

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

84 # always parse invalid URLs correctly - it should raise 

85 # exceptions for malformed URLs 

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

87 logger.warning( 

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

89 redacted_index_url, 

90 ) 

91 

92 redacted_index_urls.append(redacted_index_url) 

93 

94 lines.append( 

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

96 ) 

97 

98 if self.find_links: 

99 lines.append( 

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

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

102 ) 

103 ) 

104 return "\n".join(lines) 

105 

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

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

108 

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

110 use this url_name to produce all locations 

111 """ 

112 

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

114 loc = posixpath.join( 

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

116 ) 

117 # For maximum compatibility with easy_install, ensure the path 

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

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

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

121 # behavior. 

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

123 loc = loc + "/" 

124 return loc 

125 

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