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

54 statements  

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

1import itertools 

2import logging 

3import os 

4import posixpath 

5import urllib.parse 

6from typing import List 

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 

17class SearchScope: 

18 

19 """ 

20 Encapsulates the locations that pip is configured to search. 

21 """ 

22 

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

24 

25 @classmethod 

26 def create( 

27 cls, 

28 find_links: List[str], 

29 index_urls: List[str], 

30 no_index: bool, 

31 ) -> "SearchScope": 

32 """ 

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

34 """ 

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

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

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

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

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

40 built_find_links: List[str] = [] 

41 for link in find_links: 

42 if link.startswith("~"): 

43 new_link = normalize_path(link) 

44 if os.path.exists(new_link): 

45 link = new_link 

46 built_find_links.append(link) 

47 

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

49 # relies on TLS. 

50 if not has_tls(): 

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

52 parsed = urllib.parse.urlparse(link) 

53 if parsed.scheme == "https": 

54 logger.warning( 

55 "pip is configured with locations that require " 

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

57 "available." 

58 ) 

59 break 

60 

61 return cls( 

62 find_links=built_find_links, 

63 index_urls=index_urls, 

64 no_index=no_index, 

65 ) 

66 

67 def __init__( 

68 self, 

69 find_links: List[str], 

70 index_urls: List[str], 

71 no_index: bool, 

72 ) -> None: 

73 self.find_links = find_links 

74 self.index_urls = index_urls 

75 self.no_index = no_index 

76 

77 def get_formatted_locations(self) -> str: 

78 lines = [] 

79 redacted_index_urls = [] 

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

81 for url in self.index_urls: 

82 redacted_index_url = redact_auth_from_url(url) 

83 

84 # Parse the URL 

85 purl = urllib.parse.urlsplit(redacted_index_url) 

86 

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

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

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

90 # always parse invalid URLs correctly - it should raise 

91 # exceptions for malformed URLs 

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

93 logger.warning( 

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

95 redacted_index_url, 

96 ) 

97 

98 redacted_index_urls.append(redacted_index_url) 

99 

100 lines.append( 

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

102 ) 

103 

104 if self.find_links: 

105 lines.append( 

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

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

108 ) 

109 ) 

110 return "\n".join(lines) 

111 

112 def get_index_urls_locations(self, project_name: str) -> List[str]: 

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

114 

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

116 use this url_name to produce all locations 

117 """ 

118 

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

120 loc = posixpath.join( 

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

122 ) 

123 # For maximum compatibility with easy_install, ensure the path 

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

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

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

127 # behavior. 

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

129 loc = loc + "/" 

130 return loc 

131 

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