-
Notifications
You must be signed in to change notification settings - Fork 255
/
Copy pathlink.py
182 lines (144 loc) · 5.04 KB
/
link.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
import posixpath
import re
import urllib.parse as urlparse
from typing import Any
from typing import Optional
from typing import Tuple
from .utils import path_to_url
from .utils import splitext
class Link:
def __init__(
self,
url: str,
comes_from: Optional[Any] = None,
requires_python: Optional[str] = None,
) -> None:
"""
Object representing a parsed link from https://pypi.python.org/simple/*
url:
url of the resource pointed to (href of the link)
comes_from:
instance of HTMLPage where the link was found, or string.
requires_python:
String containing the `Requires-Python` metadata field, specified
in PEP 345. This may be specified by a data-requires-python
attribute in the HTML link tag, as described in PEP 503.
"""
# url can be a UNC windows share
if url.startswith("\\\\"):
url = path_to_url(url)
self.url = url
self.comes_from = comes_from
self.requires_python = requires_python if requires_python else None
def __str__(self) -> str:
if self.requires_python:
rp = " (requires-python:%s)" % self.requires_python
else:
rp = ""
if self.comes_from:
return "%s (from %s)%s" % (self.url, self.comes_from, rp)
else:
return str(self.url)
def __repr__(self) -> str:
return "<Link %s>" % self
def __eq__(self, other: Any) -> bool:
if not isinstance(other, Link):
return NotImplemented
return self.url == other.url
def __ne__(self, other: Any) -> bool:
if not isinstance(other, Link):
return NotImplemented
return self.url != other.url
def __lt__(self, other: Any) -> bool:
if not isinstance(other, Link):
return NotImplemented
return self.url < other.url
def __le__(self, other: Any) -> bool:
if not isinstance(other, Link):
return NotImplemented
return self.url <= other.url
def __gt__(self, other: Any) -> bool:
if not isinstance(other, Link):
return NotImplemented
return self.url > other.url
def __ge__(self, other: Any) -> bool:
if not isinstance(other, Link):
return NotImplemented
return self.url >= other.url
def __hash__(self) -> int:
return hash(self.url)
@property
def filename(self) -> str:
_, netloc, path, _, _ = urlparse.urlsplit(self.url)
name = posixpath.basename(path.rstrip("/")) or netloc
name = urlparse.unquote(name)
return name
@property
def scheme(self) -> str:
return urlparse.urlsplit(self.url)[0]
@property
def netloc(self) -> str:
return urlparse.urlsplit(self.url)[1]
@property
def path(self) -> str:
return urlparse.unquote(urlparse.urlsplit(self.url)[2])
def splitext(self) -> Tuple[str, str]:
return splitext(posixpath.basename(self.path.rstrip("/")))
@property
def ext(self) -> str:
return self.splitext()[1]
@property
def url_without_fragment(self) -> str:
scheme, netloc, path, query, fragment = urlparse.urlsplit(self.url)
return urlparse.urlunsplit((scheme, netloc, path, query, None))
_egg_fragment_re = re.compile(r"[#&]egg=([^&]*)")
@property
def egg_fragment(self) -> Optional[str]:
match = self._egg_fragment_re.search(self.url)
if not match:
return None
return match.group(1)
_subdirectory_fragment_re = re.compile(r"[#&]subdirectory=([^&]*)")
@property
def subdirectory_fragment(self) -> Optional[str]:
match = self._subdirectory_fragment_re.search(self.url)
if not match:
return None
return match.group(1)
_hash_re = re.compile(r"(sha1|sha224|sha384|sha256|sha512|md5)=([a-f0-9]+)")
@property
def hash(self) -> Optional[str]:
match = self._hash_re.search(self.url)
if match:
return match.group(2)
return None
@property
def hash_name(self) -> Optional[str]:
match = self._hash_re.search(self.url)
if match:
return match.group(1)
return None
@property
def show_url(self) -> str:
return posixpath.basename(self.url.split("#", 1)[0].split("?", 1)[0])
@property
def is_wheel(self) -> bool:
return self.ext == ".whl"
@property
def is_wininst(self) -> bool:
return self.ext == ".exe"
@property
def is_egg(self) -> bool:
return self.ext == ".egg"
@property
def is_sdist(self) -> bool:
return self.ext in {".tar.bz2", ".tar.gz", ".zip"}
@property
def is_artifact(self) -> bool:
"""
Determines if this points to an actual artifact (e.g. a tarball) or if
it points to an "abstract" thing like a path or a VCS location.
"""
if self.scheme in ["ssh", "git", "hg", "bzr", "sftp", "svn"]:
return False
return True