Skip to content

Commit 6dd3272

Browse files
committed
DecodedURL: address most of the comments about docstrings
1 parent dd8248c commit 6dd3272

File tree

1 file changed

+42
-79
lines changed

1 file changed

+42
-79
lines changed

hyperlink/_url.py

Lines changed: 42 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,13 +1517,17 @@ class DecodedURL(object):
15171517
handled automatically.
15181518
15191519
Where applicable, a UTF-8 encoding is presumed. Be advised that
1520-
some interactions, can raise UnicodeEncodeErrors and
1521-
UnicodeDecodeErrors, just like when working with
1522-
bytestrings.
1520+
some interactions, can raise :exc:`UnicodeEncodeErrors` and
1521+
:exc:`UnicodeDecodeErrors`, just like when working with
1522+
bytestrings. Examples of such interactions include handling query
1523+
strings encoding binary data, and paths containing segments with
1524+
special characters encoded with codecs other than UTF-8.
1525+
1526+
Args:
1527+
url (URL): A :class:`URL` object to wrap.
1528+
lazy (bool): Whether to pre-decode all parts of the URL to
1529+
check for validity. Defaults to True.
15231530
1524-
Examples of such interactions include handling query strings
1525-
encoding binary data, and paths containing segments with special
1526-
characters encoded with codecs other than UTF-8.
15271531
"""
15281532
def __init__(self, url, lazy=False):
15291533
self._url = url
@@ -1536,7 +1540,7 @@ def __init__(self, url, lazy=False):
15361540
@classmethod
15371541
def from_text(cls, text, lazy=False):
15381542
"""\
1539-
Make a DecodedURL instance from any text string containing a URL.
1543+
Make a `DecodedURL` instance from any text string containing a URL.
15401544
15411545
Args:
15421546
text (unicode): Text containing the URL
@@ -1567,28 +1571,28 @@ def to_iri(self, *a, **kw):
15671571

15681572
def click(self, href=u''):
15691573
"Return a new DecodedURL wrapping the result of :meth:`~hyperlink.URL.click()`"
1570-
return type(self)(self._url.click(href=href))
1574+
return self.__class__(self._url.click(href=href))
15711575

15721576
def sibling(self, segment):
15731577
"""Automatically encode any reserved characters in *segment* and
1574-
return a new DecodedURL wrapping the result of
1578+
return a new `DecodedURL` wrapping the result of
15751579
:meth:`~hyperlink.URL.sibling()`
15761580
"""
1577-
return type(self)(self._url.sibling(_encode_reserved(segment)))
1581+
return self.__class__(self._url.sibling(_encode_reserved(segment)))
15781582

15791583
def child(self, *segments):
15801584
"""Automatically encode any reserved characters in *segments* and
1581-
return a new DecodedURL wrapping the result of
1585+
return a new `DecodedURL` wrapping the result of
15821586
:meth:`~hyperlink.URL.child()`.
15831587
"""
15841588
if not segments:
15851589
return self
15861590
new_segs = [_encode_reserved(s) for s in segments]
1587-
return type(self)(self._url.child(*new_segs))
1591+
return self.__class__(self._url.child(*new_segs))
15881592

15891593
def normalize(self, *a, **kw):
1590-
"Return a new DecodedURL wrapping the result of :meth:`~hyperlink.URL.normalize()`"
1591-
return type(self)(self._url.normalize(*a, **kw))
1594+
"Return a new `DecodedURL` wrapping the result of :meth:`~hyperlink.URL.normalize()`"
1595+
return self.__class__(self._url.normalize(*a, **kw))
15921596

15931597
@property
15941598
def absolute(self):
@@ -1668,11 +1672,13 @@ def uses_netloc(self):
16681672
def replace(self, scheme=_UNSET, host=_UNSET, path=_UNSET, query=_UNSET,
16691673
fragment=_UNSET, port=_UNSET, rooted=_UNSET, userinfo=_UNSET,
16701674
uses_netloc=_UNSET):
1671-
"""While the signature is the same, this `replace()` differs a little from
1672-
URL.replace. For instance, it accepts userinfo as a tuple, not
1673-
as a string. As with the rest of the methods on DecodedURL, if
1674-
you pass a reserved character, it will be automatically
1675-
encoded instead of an error being raised.
1675+
"""While the signature is the same, this `replace()` differs a little
1676+
from URL.replace. For instance, it accepts userinfo as a
1677+
tuple, not as a string, handling the case of having a username
1678+
containing a `:`. As with the rest of the methods on
1679+
DecodedURL, if you pass a reserved character, it will be
1680+
automatically encoded instead of an error being raised.
1681+
16761682
"""
16771683
if path is not _UNSET:
16781684
path = [_encode_reserved(p) for p in path]
@@ -1695,7 +1701,7 @@ def replace(self, scheme=_UNSET, host=_UNSET, path=_UNSET, query=_UNSET,
16951701
rooted=rooted,
16961702
userinfo=userinfo,
16971703
uses_netloc=uses_netloc)
1698-
return type(self)(url=new_url)
1704+
return self.__class__(url=new_url)
16991705

17001706
def get(self, name):
17011707
"Get the value of all query parameters whose name matches *name*"
@@ -1766,67 +1772,24 @@ def __dir__(self):
17661772

17671773

17681774
def parse(url, decoded=True, lazy=False):
1775+
"""Automatically turn text into a structured URL object.
1776+
1777+
Args:
1778+
1779+
decoded (bool): Whether or not to return a :class:`DecodedURL`,
1780+
which automatically handles all
1781+
encoding/decoding/quoting/unquoting for all the various
1782+
accessors of parts of the URL, or an :class:`EncodedURL`,
1783+
which has the same API, but requires handling of special
1784+
characters for different parts of the URL.
1785+
1786+
lazy (bool): In the case of `decoded=True`, this controls
1787+
whether the URL is decoded immediately or as accessed. The
1788+
default, `lazy=False`, checks all encoded parts of the URL
1789+
for decodability.
1790+
"""
17691791
enc_url = EncodedURL.from_text(url)
17701792
if not decoded:
17711793
return enc_url
17721794
dec_url = DecodedURL(enc_url, lazy=lazy)
17731795
return dec_url
1774-
1775-
1776-
"""Probably turn the properties into normal attributes now that they
1777-
raise exceptions, or at least cachedproperties.
1778-
1779-
* Decode
1780-
* host
1781-
* userinfo
1782-
* user
1783-
* path
1784-
* query
1785-
* fragment
1786-
* Wrap in encoder
1787-
* replace
1788-
* add()
1789-
* set()
1790-
* child (split and encode?)
1791-
* sibling
1792-
* remove()
1793-
* Passthrough
1794-
* __eq__ / __ne__ / __hash__
1795-
* absolute()
1796-
* Return new DecodedURL with new ._url (the other kind of passthrough)
1797-
* normalize()
1798-
* click()
1799-
* Strict passthrough (doesn't return a DecodedURL)
1800-
* to_uri()
1801-
* to_iri()
1802-
1803-
# Factoring
1804-
1805-
Should DecodedURL be a subclass of URL? Inheritance isn't cool
1806-
anymore, so obviously not right? But seriously, it could be:
1807-
1808-
* Every single method of URL is wrapped with almost an identical API,
1809-
except for __init__
1810-
* A DecodedURL is as much a URL as both `bytes` and `unicode` are
1811-
strings
1812-
1813-
On the arguments against:
1814-
1815-
* __init__ differs
1816-
* No real benefit to calling super()
1817-
* Only a few duplicate methods could be reused (Twisted compat,
1818-
.get(), a couple others)
1819-
* Complicates the relationship, as every DecodedURL has an underlying
1820-
EncodedURL and every EncodedURL _may_ have a DecodedURL. Values
1821-
stored within each are actually different, so it's not just
1822-
different methods
1823-
1824-
# Remaining design questions
1825-
1826-
* Should _encode_reserved(maximal=False) be used instead?
1827-
* If yes, should the underlying URL have .to_iri() applied to it?
1828-
* Right now DecodedURL needs each part to encode then decode, because
1829-
percent_decode doesn't even try to percent decode if there are any
1830-
non-ascii characters in its argument.
1831-
1832-
"""

0 commit comments

Comments
 (0)