Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hhhrrrttt222111
GitHub Repository: hhhrrrttt222111/Dorkify
Path: blob/master/venv/Lib/site-packages/pip/_internal/models/link.py
811 views
1
import os
2
import posixpath
3
import re
4
5
from pip._vendor.six.moves.urllib import parse as urllib_parse
6
7
from pip._internal.utils.filetypes import WHEEL_EXTENSION
8
from pip._internal.utils.misc import (
9
redact_auth_from_url,
10
split_auth_from_netloc,
11
splitext,
12
)
13
from pip._internal.utils.models import KeyBasedCompareMixin
14
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
15
from pip._internal.utils.urls import path_to_url, url_to_path
16
17
if MYPY_CHECK_RUNNING:
18
from typing import Optional, Text, Tuple, Union
19
from pip._internal.index.collector import HTMLPage
20
from pip._internal.utils.hashes import Hashes
21
22
23
class Link(KeyBasedCompareMixin):
24
"""Represents a parsed link from a Package Index's simple URL
25
"""
26
27
def __init__(
28
self,
29
url, # type: str
30
comes_from=None, # type: Optional[Union[str, HTMLPage]]
31
requires_python=None, # type: Optional[str]
32
yanked_reason=None, # type: Optional[Text]
33
cache_link_parsing=True, # type: bool
34
):
35
# type: (...) -> None
36
"""
37
:param url: url of the resource pointed to (href of the link)
38
:param comes_from: instance of HTMLPage where the link was found,
39
or string.
40
:param requires_python: String containing the `Requires-Python`
41
metadata field, specified in PEP 345. This may be specified by
42
a data-requires-python attribute in the HTML link tag, as
43
described in PEP 503.
44
:param yanked_reason: the reason the file has been yanked, if the
45
file has been yanked, or None if the file hasn't been yanked.
46
This is the value of the "data-yanked" attribute, if present, in
47
a simple repository HTML link. If the file has been yanked but
48
no reason was provided, this should be the empty string. See
49
PEP 592 for more information and the specification.
50
:param cache_link_parsing: A flag that is used elsewhere to determine
51
whether resources retrieved from this link
52
should be cached. PyPI index urls should
53
generally have this set to False, for
54
example.
55
"""
56
57
# url can be a UNC windows share
58
if url.startswith('\\\\'):
59
url = path_to_url(url)
60
61
self._parsed_url = urllib_parse.urlsplit(url)
62
# Store the url as a private attribute to prevent accidentally
63
# trying to set a new value.
64
self._url = url
65
66
self.comes_from = comes_from
67
self.requires_python = requires_python if requires_python else None
68
self.yanked_reason = yanked_reason
69
70
super(Link, self).__init__(key=url, defining_class=Link)
71
72
self.cache_link_parsing = cache_link_parsing
73
74
def __str__(self):
75
# type: () -> str
76
if self.requires_python:
77
rp = ' (requires-python:{})'.format(self.requires_python)
78
else:
79
rp = ''
80
if self.comes_from:
81
return '{} (from {}){}'.format(
82
redact_auth_from_url(self._url), self.comes_from, rp)
83
else:
84
return redact_auth_from_url(str(self._url))
85
86
def __repr__(self):
87
# type: () -> str
88
return '<Link {}>'.format(self)
89
90
@property
91
def url(self):
92
# type: () -> str
93
return self._url
94
95
@property
96
def filename(self):
97
# type: () -> str
98
path = self.path.rstrip('/')
99
name = posixpath.basename(path)
100
if not name:
101
# Make sure we don't leak auth information if the netloc
102
# includes a username and password.
103
netloc, user_pass = split_auth_from_netloc(self.netloc)
104
return netloc
105
106
name = urllib_parse.unquote(name)
107
assert name, (
108
'URL {self._url!r} produced no filename'.format(**locals()))
109
return name
110
111
@property
112
def file_path(self):
113
# type: () -> str
114
return url_to_path(self.url)
115
116
@property
117
def scheme(self):
118
# type: () -> str
119
return self._parsed_url.scheme
120
121
@property
122
def netloc(self):
123
# type: () -> str
124
"""
125
This can contain auth information.
126
"""
127
return self._parsed_url.netloc
128
129
@property
130
def path(self):
131
# type: () -> str
132
return urllib_parse.unquote(self._parsed_url.path)
133
134
def splitext(self):
135
# type: () -> Tuple[str, str]
136
return splitext(posixpath.basename(self.path.rstrip('/')))
137
138
@property
139
def ext(self):
140
# type: () -> str
141
return self.splitext()[1]
142
143
@property
144
def url_without_fragment(self):
145
# type: () -> str
146
scheme, netloc, path, query, fragment = self._parsed_url
147
return urllib_parse.urlunsplit((scheme, netloc, path, query, None))
148
149
_egg_fragment_re = re.compile(r'[#&]egg=([^&]*)')
150
151
@property
152
def egg_fragment(self):
153
# type: () -> Optional[str]
154
match = self._egg_fragment_re.search(self._url)
155
if not match:
156
return None
157
return match.group(1)
158
159
_subdirectory_fragment_re = re.compile(r'[#&]subdirectory=([^&]*)')
160
161
@property
162
def subdirectory_fragment(self):
163
# type: () -> Optional[str]
164
match = self._subdirectory_fragment_re.search(self._url)
165
if not match:
166
return None
167
return match.group(1)
168
169
_hash_re = re.compile(
170
r'(sha1|sha224|sha384|sha256|sha512|md5)=([a-f0-9]+)'
171
)
172
173
@property
174
def hash(self):
175
# type: () -> Optional[str]
176
match = self._hash_re.search(self._url)
177
if match:
178
return match.group(2)
179
return None
180
181
@property
182
def hash_name(self):
183
# type: () -> Optional[str]
184
match = self._hash_re.search(self._url)
185
if match:
186
return match.group(1)
187
return None
188
189
@property
190
def show_url(self):
191
# type: () -> str
192
return posixpath.basename(self._url.split('#', 1)[0].split('?', 1)[0])
193
194
@property
195
def is_file(self):
196
# type: () -> bool
197
return self.scheme == 'file'
198
199
def is_existing_dir(self):
200
# type: () -> bool
201
return self.is_file and os.path.isdir(self.file_path)
202
203
@property
204
def is_wheel(self):
205
# type: () -> bool
206
return self.ext == WHEEL_EXTENSION
207
208
@property
209
def is_vcs(self):
210
# type: () -> bool
211
from pip._internal.vcs import vcs
212
213
return self.scheme in vcs.all_schemes
214
215
@property
216
def is_yanked(self):
217
# type: () -> bool
218
return self.yanked_reason is not None
219
220
@property
221
def has_hash(self):
222
# type: () -> bool
223
return self.hash_name is not None
224
225
def is_hash_allowed(self, hashes):
226
# type: (Optional[Hashes]) -> bool
227
"""
228
Return True if the link has a hash and it is allowed.
229
"""
230
if hashes is None or not self.has_hash:
231
return False
232
# Assert non-None so mypy knows self.hash_name and self.hash are str.
233
assert self.hash_name is not None
234
assert self.hash is not None
235
236
return hashes.is_hash_allowed(self.hash_name, hex_digest=self.hash)
237
238