Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

link.py 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import posixpath
  2. import re
  3. from pip._vendor.six.moves.urllib import parse as urllib_parse
  4. from pip._internal.download import path_to_url
  5. from pip._internal.utils.misc import splitext
  6. from pip._internal.utils.models import KeyBasedCompareMixin
  7. from pip._internal.wheel import wheel_ext
  8. class Link(KeyBasedCompareMixin):
  9. """Represents a parsed link from a Package Index's simple URL
  10. """
  11. def __init__(self, url, comes_from=None, requires_python=None):
  12. """
  13. url:
  14. url of the resource pointed to (href of the link)
  15. comes_from:
  16. instance of HTMLPage where the link was found, or string.
  17. requires_python:
  18. String containing the `Requires-Python` metadata field, specified
  19. in PEP 345. This may be specified by a data-requires-python
  20. attribute in the HTML link tag, as described in PEP 503.
  21. """
  22. # url can be a UNC windows share
  23. if url.startswith('\\\\'):
  24. url = path_to_url(url)
  25. self.url = url
  26. self.comes_from = comes_from
  27. self.requires_python = requires_python if requires_python else None
  28. super(Link, self).__init__(
  29. key=(self.url),
  30. defining_class=Link
  31. )
  32. def __str__(self):
  33. if self.requires_python:
  34. rp = ' (requires-python:%s)' % self.requires_python
  35. else:
  36. rp = ''
  37. if self.comes_from:
  38. return '%s (from %s)%s' % (self.url, self.comes_from, rp)
  39. else:
  40. return str(self.url)
  41. def __repr__(self):
  42. return '<Link %s>' % self
  43. @property
  44. def filename(self):
  45. _, netloc, path, _, _ = urllib_parse.urlsplit(self.url)
  46. name = posixpath.basename(path.rstrip('/')) or netloc
  47. name = urllib_parse.unquote(name)
  48. assert name, ('URL %r produced no filename' % self.url)
  49. return name
  50. @property
  51. def scheme(self):
  52. return urllib_parse.urlsplit(self.url)[0]
  53. @property
  54. def netloc(self):
  55. return urllib_parse.urlsplit(self.url)[1]
  56. @property
  57. def path(self):
  58. return urllib_parse.unquote(urllib_parse.urlsplit(self.url)[2])
  59. def splitext(self):
  60. return splitext(posixpath.basename(self.path.rstrip('/')))
  61. @property
  62. def ext(self):
  63. return self.splitext()[1]
  64. @property
  65. def url_without_fragment(self):
  66. scheme, netloc, path, query, fragment = urllib_parse.urlsplit(self.url)
  67. return urllib_parse.urlunsplit((scheme, netloc, path, query, None))
  68. _egg_fragment_re = re.compile(r'[#&]egg=([^&]*)')
  69. @property
  70. def egg_fragment(self):
  71. match = self._egg_fragment_re.search(self.url)
  72. if not match:
  73. return None
  74. return match.group(1)
  75. _subdirectory_fragment_re = re.compile(r'[#&]subdirectory=([^&]*)')
  76. @property
  77. def subdirectory_fragment(self):
  78. match = self._subdirectory_fragment_re.search(self.url)
  79. if not match:
  80. return None
  81. return match.group(1)
  82. _hash_re = re.compile(
  83. r'(sha1|sha224|sha384|sha256|sha512|md5)=([a-f0-9]+)'
  84. )
  85. @property
  86. def hash(self):
  87. match = self._hash_re.search(self.url)
  88. if match:
  89. return match.group(2)
  90. return None
  91. @property
  92. def hash_name(self):
  93. match = self._hash_re.search(self.url)
  94. if match:
  95. return match.group(1)
  96. return None
  97. @property
  98. def show_url(self):
  99. return posixpath.basename(self.url.split('#', 1)[0].split('?', 1)[0])
  100. @property
  101. def is_wheel(self):
  102. return self.ext == wheel_ext
  103. @property
  104. def is_artifact(self):
  105. """
  106. Determines if this points to an actual artifact (e.g. a tarball) or if
  107. it points to an "abstract" thing like a path or a VCS location.
  108. """
  109. from pip._internal.vcs import vcs
  110. if self.scheme in vcs.all_schemes:
  111. return False
  112. return True