Skip to content

Commit ada433f

Browse files
authored
Merge branch 'master' into travis-lint
2 parents d6c070f + ba695fb commit ada433f

7 files changed

Lines changed: 121 additions & 21 deletions

File tree

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ matrix:
3030
env: TOXENV=test-pypy3,codecov
3131
- python: "2.7"
3232
env: TOXENV=packaging-py27
33+
- python: "3.8"
34+
env: TOXENV=docs
3335

3436

3537
install:

README.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,24 @@
22

33
*Cool URLs that don't change.*
44

5-
<a href="https://hyperlink.readthedocs.io/en/latest/"><img src="https://img.shields.io/badge/docs-latest-brightgreen.svg?style=flat"></a>
6-
<a href="https://pypi.python.org/pypi/hyperlink"><img src="https://img.shields.io/pypi/v/boltons.svg"></a>
7-
<a href="http://calver.org"><img src="https://img.shields.io/badge/calver-YY.MINOR.MICRO-22bfda.svg"></a>
5+
<a href="https://hyperlink.readthedocs.io/en/latest/">
6+
<img src="https://img.shields.io/badge/docs-latest-brightgreen.svg?style=flat" alt="Documentation">
7+
</a>
8+
<a href="https://pypi.org/project/hyperlink/">
9+
<img src="https://img.shields.io/pypi/v/boltons.svg" alt="PyPI">
10+
</a>
11+
<a href="http://calver.org">
12+
<img src="https://img.shields.io/badge/calver-YY.MINOR.MICRO-22bfda.svg" alt="Calendar Versioning">
13+
</a>
14+
<a href="https://pypi.org/project/hyperlink/">
15+
<img src="https://img.shields.io/pypi/pyversions/hyperlink.svg" alt="Python Version Compatibility">
16+
</a>
17+
<a href="https://https://codecov.io/github/python-hyper/hyperlink?branch=master">
18+
<img src="https://codecov.io/github/python-hyper/hyperlink/coverage.svg?branch=master" alt="Code Coverage">
19+
</a>
20+
<a href="https://requires.io/github/python-hyper/hyperlink/requirements/?branch=master">
21+
<img src="https://requires.io/github/python-hyper/hyperlink/requirements.svg?branch=master" alt="Requirements Status">
22+
</a>
823

924
Hyperlink provides a pure-Python implementation of immutable
1025
URLs. Based on [RFC 3986][rfc3986] and [3987][rfc3987], the Hyperlink URL

docs/api.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ URLs have many parts, and URL objects have many attributes to represent them.
6161
.. autoattribute:: hyperlink.URL.userinfo
6262
.. autoattribute:: hyperlink.URL.user
6363
.. autoattribute:: hyperlink.URL.rooted
64-
.. autoattribute:: hyperlink.URL.family
6564

6665
Low-level functions
6766
-------------------
@@ -70,6 +69,6 @@ A couple of notable helpers used by the :class:`~hyperlink.URL` type.
7069

7170
.. autoclass:: hyperlink.URLParseError
7271
.. autofunction:: hyperlink.register_scheme
73-
.. autofunction:: hyperlink.parse_host
72+
.. autofunction:: hyperlink.parse
7473

7574
.. TODO: run doctests in docs?

src/hyperlink/__init__.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1+
from ._url import (
2+
parse,
3+
register_scheme,
4+
URL,
5+
EncodedURL,
6+
DecodedURL,
7+
URLParseError,
8+
)
19

2-
from ._url import (URL,
3-
parse,
4-
EncodedURL,
5-
DecodedURL,
6-
URLParseError,
7-
register_scheme)
8-
9-
__all__ = [
10-
"URL",
10+
__all__ = (
1111
"parse",
12+
"register_scheme",
13+
"URL",
1214
"EncodedURL",
1315
"DecodedURL",
1416
"URLParseError",
15-
"register_scheme",
16-
]
17+
)

src/hyperlink/_url.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,9 @@ class URL(object):
761761
query (tuple): The query parameters, as a dictionary or
762762
as an iterable of key-value pairs.
763763
fragment (unicode): The fragment part of the URL.
764-
rooted (bool): Whether or not the path begins with a slash.
764+
rooted (bool): A rooted URL is one which indicates an absolute path.
765+
This is True on any URL that includes a host, or any relative URL
766+
that starts with a slash.
765767
userinfo (unicode): The username or colon-separated
766768
username:password pair.
767769
uses_netloc (bool): Indicates whether two slashes appear
@@ -823,8 +825,12 @@ def __init__(self, scheme=None, host=None, path=(), query=(), fragment=u'',
823825
uses_netloc = scheme_uses_netloc(self._scheme, uses_netloc)
824826
self._uses_netloc = _typecheck("uses_netloc",
825827
uses_netloc, bool, NoneType)
826-
827-
return
828+
# fixup for rooted consistency
829+
if self._host:
830+
self._rooted = True
831+
if (not self._rooted) and self._path and self._path[0] == '':
832+
self._rooted = True
833+
self._path = self._path[1:]
828834

829835
def get_decoded_url(self, lazy=False):
830836
try:
@@ -985,7 +991,7 @@ def __eq__(self, other):
985991
if not isinstance(other, self.__class__):
986992
return NotImplemented
987993
for attr in ['scheme', 'userinfo', 'host', 'query',
988-
'fragment', 'port', 'uses_netloc']:
994+
'fragment', 'port', 'uses_netloc', 'rooted']:
989995
if getattr(self, attr) != getattr(other, attr):
990996
return False
991997
if (

src/hyperlink/test/test_url.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,42 @@ def test_netloc_slashes(self):
10811081

10821082
return
10831083

1084+
def test_rooted_to_relative(self):
1085+
# type: () -> None
1086+
"""
1087+
On host-relative URLs, the C{rooted} flag can be updated to indicate
1088+
that the path should no longer be treated as absolute.
1089+
"""
1090+
a = URL(path=['hello'])
1091+
self.assertEqual(a.to_text(), 'hello')
1092+
b = a.replace(rooted=True)
1093+
self.assertEqual(b.to_text(), '/hello')
1094+
self.assertNotEqual(a, b)
1095+
1096+
def test_autorooted(self):
1097+
# type: () -> None
1098+
"""
1099+
The C{rooted} flag can be updated in some cases, but it cannot be made
1100+
to conflict with other facts surrounding the URL; for example, all URLs
1101+
involving an authority (host) are inherently rooted because it is not
1102+
syntactically possible to express otherwise; also, once an unrooted URL
1103+
gains a path that starts with an empty string, that empty string is
1104+
elided and it becomes rooted, because these cases are syntactically
1105+
indistinguisable in real URL text.
1106+
"""
1107+
relative_path_rooted = URL(path=['', 'foo'], rooted=False)
1108+
self.assertEqual(relative_path_rooted.rooted, True)
1109+
relative_flag_rooted = URL(path=['foo'], rooted=True)
1110+
self.assertEqual(relative_flag_rooted.rooted, True)
1111+
self.assertEqual(relative_path_rooted, relative_flag_rooted)
1112+
1113+
attempt_unrooted_absolute = URL(host="foo", path=['bar'], rooted=False)
1114+
normal_absolute = URL(host="foo", path=["bar"])
1115+
attempted_rooted_replacement = normal_absolute.replace(rooted=True)
1116+
self.assertEqual(attempt_unrooted_absolute, normal_absolute)
1117+
self.assertEqual(normal_absolute.rooted, True)
1118+
self.assertEqual(attempt_unrooted_absolute.rooted, True)
1119+
10841120
def test_wrong_constructor(self):
10851121
# type: () -> None
10861122
with self.assertRaises(ValueError):

tox.ini

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ envlist =
55
test-py{26,27,34,35,36,37,38,py,py3}
66
coverage_report
77
packaging
8+
docs
89

910
skip_missing_interpreters = {tty:True:False}
1011

@@ -141,7 +142,7 @@ basepython = python3.8
141142
skip_install = True
142143

143144
deps =
144-
mypy==0.740
145+
mypy==0.750
145146

146147
commands =
147148
mypy \
@@ -230,6 +231,46 @@ commands =
230231
APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED
231232

232233

234+
##
235+
# Documentation
236+
##
237+
238+
[testenv:docs]
239+
240+
description = build documentation
241+
242+
basepython = python3.8
243+
244+
deps =
245+
Sphinx==2.2.2
246+
sphinx-rtd-theme==0.4.3
247+
248+
commands =
249+
sphinx-build \
250+
-b html -d "{envtmpdir}/doctrees" \
251+
"{toxinidir}/docs" \
252+
"{toxworkdir}/docs/html"
253+
254+
255+
[testenv:docs-auto]
256+
257+
description = build documentation and rebuild automatically
258+
259+
basepython = python3.8
260+
261+
deps =
262+
Sphinx==2.2.2
263+
sphinx-rtd-theme==0.4.3
264+
sphinx-autobuild==0.7.1
265+
266+
commands =
267+
sphinx-autobuild \
268+
-b html -d "{envtmpdir}/doctrees" \
269+
--host=localhost \
270+
"{toxinidir}/docs" \
271+
"{toxworkdir}/docs/html"
272+
273+
233274
##
234275
# Packaging
235276
##

0 commit comments

Comments
 (0)