Skip to content

Commit 686152f

Browse files
authored
Merge branch 'master' into requires-io-master
2 parents 9bf0e08 + 86c7051 commit 686152f

4 files changed

Lines changed: 94 additions & 29 deletions

File tree

docs/api.rst

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,43 @@ Hyperlink API
55

66
.. automodule:: hyperlink._url
77

8+
.. contents::
9+
:local:
10+
811
Creation
912
--------
1013

11-
Before you can work with URLs, you must create URLs. There are two
12-
ways to create URLs, from parts and from text.
14+
Before you can work with URLs, you must create URLs.
15+
16+
Parsing Text
17+
^^^^^^^^^^^^
18+
19+
If you already have a textual URL, the easiest way to get URL objects
20+
is with the :func:`parse()` function:
21+
22+
.. autofunction:: hyperlink.parse
23+
24+
By default, :func:`~hyperlink.parse()` returns an instance of
25+
:class:`DecodedURL`, a URL type that handles all encoding for you, by
26+
wrapping the lower-level :class:`URL`.
27+
28+
DecodedURL
29+
^^^^^^^^^^
30+
31+
.. autoclass:: hyperlink.DecodedURL
32+
.. automethod:: hyperlink.DecodedURL.from_text
33+
34+
The Encoded URL
35+
^^^^^^^^^^^^^^^
36+
37+
The lower-level :class:`URL` looks very similar to the
38+
:class:`DecodedURL`, but does not handle all encoding cases for
39+
you. Use with caution.
40+
41+
.. note::
42+
43+
:class:`URL` is also available as an alias,
44+
``hyperlink.EncodedURL`` for more explicit usage.
1345

1446
.. autoclass:: hyperlink.URL
1547
.. automethod:: hyperlink.URL.from_text

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
pygments_style = 'sphinx'
7777

7878
# Example configuration for intersphinx: refer to the Python standard library.
79-
intersphinx_mapping = {'python': ('https://docs.python.org/2.7', None)}
79+
intersphinx_mapping = {'python': ('https://docs.python.org/3.7', None)}
8080

8181

8282
# -- Options for HTML output ----------------------------------------------

docs/index.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,17 @@ library. The easiest way to install is with pip::
3939

4040
Then, URLs are just an import away::
4141

42-
from hyperlink import URL
42+
import hyperlink
4343

44-
url = URL.from_text(u'http://github.com/python-hyper/hyperlink?utm_source=readthedocs')
44+
url = hyperlink.parse(u'http://github.com/python-hyper/hyperlink?utm_source=readthedocs')
4545

4646
better_url = url.replace(scheme=u'https', port=443)
4747
org_url = better_url.click(u'.')
4848

4949
print(org_url.to_text())
5050
# prints: https://github.com/python-hyper/
5151

52-
print(better_url.get(u'utm_source'))
52+
print(better_url.get(u'utm_source')[0])
5353
# prints: readthedocs
5454

5555
See :ref:`the API docs <hyperlink_api>` for more usage examples.

src/hyperlink/_url.py

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@
33
44
Usage is straightforward::
55
6-
>>> from hyperlink import URL
7-
>>> url = URL.from_text(u'http://github.com/mahmoud/hyperlink?utm_source=docs')
6+
>>> import hyperlink
7+
>>> url = hyperlink.parse(u'http://github.com/mahmoud/hyperlink?utm_source=docs')
88
>>> url.host
99
u'github.com'
1010
>>> secure_url = url.replace(scheme=u'https')
1111
>>> secure_url.get('utm_source')[0]
1212
u'docs'
1313
14-
As seen here, the API revolves around the lightweight and immutable
15-
:class:`URL` type, documented below.
14+
Hyperlink's API centers on the :class:`DecodedURL` type, which wraps
15+
the lower-level :class:`URL`, both of which can be returned by the
16+
:func:`parse()` convenience function.
17+
1618
""" # noqa: E501
1719

1820
import re
@@ -1964,13 +1966,25 @@ def remove(
19641966

19651967
EncodedURL = URL # An alias better describing what the URL really is
19661968

1969+
_EMPTY_URL = URL()
1970+
19671971

19681972
class DecodedURL(object):
1969-
"""DecodedURL is a type meant to act as a higher-level interface to
1970-
the URL. It is the `unicode` to URL's `bytes`. `DecodedURL` has
1971-
almost exactly the same API as `URL`, but everything going in and
1972-
out is in its maximally decoded state. All percent decoding is
1973-
handled automatically.
1973+
"""
1974+
:class:`DecodedURL` is a type designed to act as a higher-level
1975+
interface to :class:`URL` and the recommended type for most
1976+
operations. By analogy, :class:`DecodedURL` is the
1977+
:class:`unicode` to URL's :class:`bytes`.
1978+
1979+
:class:`DecodedURL` automatically handles encoding and decoding
1980+
all its components, such that all inputs and outputs are in a
1981+
maximally-decoded state. Note that this means, for some special
1982+
cases, a URL may not "roundtrip" character-for-character, but this
1983+
is considered a good tradeoff for the safety of automatic
1984+
encoding.
1985+
1986+
Otherwise, :class:`DecodedURL` has almost exactly the same API as
1987+
:class:`URL`.
19741988
19751989
Where applicable, a UTF-8 encoding is presumed. Be advised that
19761990
some interactions can raise :exc:`UnicodeEncodeErrors` and
@@ -1985,9 +1999,20 @@ class DecodedURL(object):
19851999
validity.
19862000
Defaults to False.
19872001
2002+
.. note::
2003+
2004+
The :class:`DecodedURL` initializer takes a :class:`URL` object,
2005+
not URL components, like :class:`URL`. To programmatically
2006+
construct a :class:`DecodedURL`, you can use this pattern:
2007+
2008+
>>> print(DecodedURL().replace(scheme=u'https',
2009+
... host=u'pypi.org', path=(u'projects', u'hyperlink')).to_text())
2010+
https://pypi.org/projects/hyperlink
2011+
2012+
.. versionadded:: 18.0.0
19882013
"""
19892014

1990-
def __init__(self, url, lazy=False):
2015+
def __init__(self, url=_EMPTY_URL, lazy=False):
19912016
# type: (URL, bool) -> None
19922017
self._url = url
19932018
if not lazy:
@@ -2348,21 +2373,29 @@ def __dir__(self):
23482373

23492374
def parse(url, decoded=True, lazy=False):
23502375
# type: (Text, bool, bool) -> Union[URL, DecodedURL]
2351-
"""Automatically turn text into a structured URL object.
2376+
"""
2377+
Automatically turn text into a structured URL object.
2378+
2379+
>>> url = parse(u"https://github.com/python-hyper/hyperlink")
2380+
>>> print(url.to_text())
2381+
https://github.com/python-hyper/hyperlink
23522382
23532383
Args:
2354-
url: A string representation of a URL.
2355-
2356-
decoded: Whether or not to return a :class:`DecodedURL`, which
2357-
automatically handles all encoding/decoding/quoting/unquoting for
2358-
all the various accessors of parts of the URL, or an
2359-
:class:`EncodedURL`, which has the same API, but requires handling
2360-
of special characters for different parts of the URL.
2361-
2362-
lazy: In the case of `decoded=True`, this controls whether the URL is
2363-
decoded immediately or as accessed.
2364-
The default, `lazy=False`, checks all encoded parts of the URL for
2365-
decodability.
2384+
url: A text string representation of a URL.
2385+
2386+
decoded: Whether or not to return a :class:`DecodedURL`,
2387+
which automatically handles all
2388+
encoding/decoding/quoting/unquoting for all the various
2389+
accessors of parts of the URL, or a :class:`URL`,
2390+
which has the same API, but requires handling of special
2391+
characters for different parts of the URL.
2392+
2393+
lazy: In the case of `decoded=True`, this controls
2394+
whether the URL is decoded immediately or as accessed. The
2395+
default, `lazy=False`, checks all encoded parts of the URL
2396+
for decodability.
2397+
2398+
.. versionadded:: 18.0.0
23662399
"""
23672400
enc_url = EncodedURL.from_text(url)
23682401
if not decoded:

0 commit comments

Comments
 (0)