G_cF dZddlZddlZddlZddlZddlmZmZ ddlmZddl m Z m Z m Z mZmZmZmZmZmZmZmZmZmZmZmZddlmZddlmZ dd lmZdd l!m"Z#m$Z%ejLdd k(Z' e(e+dZ,eeeeefd fZ-eeeeefe-eeeeeffZ.ed Z/ddZ0e0dxZ1Z2e3dZ4ejjdZ6ejjdZ7ejjdZ8e9ejtDcgc]H}ejtD]7}||zjEde(e ||zdjEdf9Jc}}Z;ejjdZ<e3dZ=e3dZ>e=e>zZ?e4e>ze@dzZAe?eAz ZBeAe@dzZCe?eCz ZDeCe@dz ZEe?eEz ZFe4eCze@dzZGe?eGz ZHe4eGe@dz zZIe?eIz ZJe4eIe@dz zZKe?eKz ZLdd!ZMd"ZNeNeAZOeMeBZPeNeCZQeNeEZReMeDZSeNeKZTeMeLZUeNeIZVeMeJZWeNeGZXeMeHZYeNe4ZZe9e;jDcgc]\}}|jIdd#e4vr||fc}}Z\e3d$Z]dd%Z^dd&Z_dd'Z` dd(Zadd)Zbdd*Zcdd+Zddd,Zeid-d.d/d0d1d2d3d4d5dd6d7d8d9d:d;dd?d@dAdBdCdDdCdEdFdGdHdIdJdKdLidMdNdOdPdQddRdSdTdUdVdWdXdYdZd[d\d]d^d_d`dadbdcdddedfdgdhdidjdkdldmdiddndodpdqdrd=d?dds Zfe@gdtZge@Zh dduZiddvZjGdwdxekZldyZmdzZne3d fd{Zod|Zpdd}Zq dd~ZrddZsddZt ddZu ddZvd dd d e;fdZwdZxdZydZzGdde{Z|e|Z}e|Z~dZdZGdde{ZddZy#e$re ZYwxYw#e$r dd l mZYwxYw#e)$re*Z(YwxYwcc}}wcc}}w)aHyperlink provides Pythonic URL parsing, construction, and rendering. Usage is straightforward:: >>> import hyperlink >>> url = hyperlink.parse(u'http://github.com/mahmoud/hyperlink?utm_source=docs') >>> url.host u'github.com' >>> secure_url = url.replace(scheme=u'https') >>> secure_url.get('utm_source')[0] u'docs' Hyperlink's API centers on the :class:`DecodedURL` type, which wraps the lower-level :class:`URL`, both of which can be returned by the :func:`parse()` convenience function. N)AF_INETAF_INET6) AddressFamily)AnyCallableDictIterableIteratorListMappingOptionalSequenceTextTupleTypeTypeVarUnioncast) normalize) inet_pton)r )encodedecode.Tc8Gfddt}|S)aCreates and returns a new **instance** of a new class, suitable for usage as a "sentinel", a kind of singleton often used to indicate a value is missing when ``None`` is a valid input. Args: name: Name of the Sentinel var_name: Set this name to the name of the variable in its respective module enable pickle-ability. >>> make_sentinel(var_name='_MISSING') _MISSING The most common use cases here in boltons are as default values for optional function arguments, partly because of its less-confusing appearance in automatically generated documentation. Sentinels also function well as placeholders in queues and linked lists. .. note:: By design, additional calls to ``make_sentinel`` with the same values will not produce equivalent objects. >>> make_sentinel('TEST') == make_sentinel('TEST') False >>> type(make_sentinel('TEST')) == type(make_sentinel('TEST')) False c6eZdZfdZdZWrdZdZeZy)make_sentinel..Sentinelc"|_|_yNnamevar_name)selfr"r#s 0/usr/lib/python3/dist-packages/hyperlink/_url.py__init__z(make_sentinel..Sentinel.__init__jsDI$DMc~|jr |jS|jjd|jdS)N())r# __class____name__r"r$s r%__repr__z(make_sentinel..Sentinel.__repr__os,}}}}$#~~66 B Br'c|jSr )r#r-s r% __reduce__z*make_sentinel..Sentinel.__reduce__xs }}$r'cy)NFr-s r% __nonzero__z+make_sentinel..Sentinel.__nonzero__|sr'N)r, __module__ __qualname__r&r.r0r3__bool__r!sr%Sentinelris$ %  C  % r'r7)object)r"r#r7s`` r% make_sentinelr9Js>62 :r'_UNSETzB~-._0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzz^((?P[^:/?#]+):)?((?P<_netloc_sep>//)(?P[^/?#]*))?(?P[^?#]*)(\?(?P[^#]*))?(#(?P.*))?$z^[a-zA-Z0-9+-.]*$z^(?:(?P[^@/?#]*)@)?(?P(?:\[(?P[^[\]/?#]*)\])|(?P[^:/?#[\]]*)|(?P.*?))?(?::(?P.*))?$asciicharmapz([-]+)z:/?#[]@z !$&'()*+,;=%z:@:z/?&=Fc(tt}|st|tdgz}|D]c}djt |j d}|j }|j|||k7sS|j|e|S)Nr>z{0:02X}r;)dict _HEX_CHAR_MAPsetformatordrlowerpop)delims allow_percentretdelim_hexord _hexord_lowers r%_make_decode_maprPs } C VsD6{*#""3u:.55g>    m # GGM " # Jr'ci}ttdtdD]8\}}t|}||vr |x||<||< dj|x||<||<:|S)Nz%{0:02X})ziprangechrrF) safe_charsrLivcs r%_make_quote_maprZsq CE#Jc +31 F ? CFSV(//2 2CFSV 3 Jr'replace)r2c|rAtd|jd}dj|Dcgc] }t| c}Sdj|Dcgc]}|tvr t|n|c}Scc}wcc}w)zA very comprehensive percent encoding for encoding all delimiters. Used for arguments to DecodedURL, where a % means a percent sign, and not the character used by URLs for escaping bytes. NFCutf8r])rrjoin_UNRESERVED_QUOTE_MAP_UNRESERVED_CHARStextmaximalbytestrbts r%_encode_reservedrjsE4(//7xx7Ca.q1CDD 88 )*->(> !! $A E  D A4A9c|rAtd|jd}dj|Dcgc] }t| c}Sdj|Dcgc]}|tvr t|n|c}Scc}wcc}w)z.Percent-encode a single segment of a URL path.r_r`r])rrra_PATH_PART_QUOTE_MAP _PATH_DELIMSrds r%_encode_path_partrosxE4(//7xx'BQ-a0BCC 88FJKA$5 a 1 <K CKrkc|rAtd|jd}dj|Dcgc] }t| c}Sdj|Dcgc]}|tvr t|n|c}Scc}wcc}w)z]Percent-encode the first segment of a URL path for a URL without a scheme specified. r_r`r])rrra_SCHEMELESS_PATH_PART_QUOTE_MAP_SCHEMELESS_PATH_DELIMSrds r%_encode_schemeless_path_partrss E4(//7xxWM8;MNN 88   ++ ,A .   N rkc ,|sy|rdt|z}g}|r)|Dcgc]}|r t||n|}}t|St|dg}|j|ddDcgc]}|r t||n|c}t|Scc}wcc}w)aL Percent-encode a tuple of path parts into a complete path. Setting *maximal* to False percent-encodes only the reserved characters that are syntactically necessary for serialization, preserving any IRI-style textual data. Leaving *maximal* set to its default True percent-encodes everything required to convert a portion of an IRI to a portion of a URI. RFC 3986 3.3: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character. If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//"). In addition, a URI reference (Section 4.1) may be a relative-path reference, in which case the first path segment cannot contain a colon (":") character. r2r\rfrrN)tuplerorsextend) text_partsrooted has_scheme has_authorityrf encoded_partsparts r%_encode_path_partsr~"s8  eJ// M# 9= dG 4$ F    6jmDE 'qrN =A!$8dJ     s B "Bc|rAtd|jd}dj|Dcgc] }t| c}Sdj|Dcgc]}|tvr t|n|c}Scc}wcc}wz< Percent-encode a single query string key or value. r_r`r])rrra_QUERY_KEY_QUOTE_MAP_QUERY_KEY_DELIMSrds r%_encode_query_keyrUsy E4(//7xx'BQ-a0BCC 88KOPaA):$: a  AP CPrkc|rAtd|jd}dj|Dcgc] }t| c}Sdj|Dcgc]}|tvr t|n|c}Scc}wcc}wr)rrra_QUERY_VALUE_QUOTE_MAP_QUERY_VALUE_DELIMSrds r%_encode_query_valuerbs E4(//7xxGDq/2DEE 88 *+.A)A "1 %q H  E rkc|rAtd|jd}dj|Dcgc] }t| c}Sdj|Dcgc]}|tvr t|n|c}Scc}wcc}w)zyQuote the fragment part of the URL. Fragments don't have subdelimiters, so the whole URL fragment can be passed. r_r`r])rrra_FRAGMENT_QUOTE_MAP_FRAGMENT_DELIMSrds r%_encode_fragment_partrrsy E4(//7xxAA,Q/ABB 88IMNA1(8#8 Q a ?N BNrkc|rAtd|jd}dj|Dcgc] }t| c}Sdj|Dcgc]}|tvr t|n|c}Scc}wcc}w)zXQuote special characters in either the username or password section of the URL. r_r`r])rrra_USERINFO_PART_QUOTE_MAP_USERINFO_DELIMSrds r%_encode_userinfo_partrs E4(//7xxgF1!4FGG 88 ,-0@+@ $Q 'a G  G rkacapiafpi$rCiD dns5fileftpgiti$gopherFhttpPhttpsiimapippiwippsircircsi)ldapildapsi|mmsimsrpi' msrpsmtqpinfsonntpwnntpsi3rInprosperoiredisirsynciirtspi*rtspsiBrtspuisftpsmbisnmpijii ) sshsteamsvntelnetventrilovncwaiswswssxmpp) urnaboutbitcoinblobdatageomagnetmailtonewspkcs11sipsipstelc<|j}| t|}|dur |t|<n8|dur&|td|zt j |ntd|z|stj |y#ttf$rtd|wxYw)aRegisters new scheme information, resulting in correct port and slash behavior from the URL object. There are dozens of standard schemes preregistered, so this function is mostly meant for proprietary internal customizations or stopgaps on missing standards information. If a scheme seems to be missing, please `file an issue`_! Args: text: A string representation of the scheme. (the 'http' in 'http://hatnote.com') uses_netloc: Does the scheme support specifying a network host? For instance, "http" does, "mailto" does not. Defaults to True. default_port: The default port, if any, for netloc-using schemes. query_plus_is_space: If true, a "+" in the query string should be decoded as a space by DecodedURL. .. _file an issue: https://github.com/mahmoud/hyperlink/issues Nz+default_port expected integer or None, not TFz>unexpected default port while specifying non-netloc scheme: %rz"uses_netloc expected bool, not: %r)rHint ValueError TypeErrorSCHEME_PORT_MAPNO_NETLOC_SCHEMESaddNO_QUERY_PLUS_SCHEMES)re uses_netloc default_portquery_plus_is_spaces r%register_schemers0 ::># >r'c(t|||tSNnormalize_caseencode_stray_percents _decode_map)_percent_decode_UNRESERVED_DECODE_MAPrerrs r%_decode_unreservedr ms  %3*  r'c(t|||tSr)r _USERINFO_DECODE_MAPr s r%_decode_userinfo_partrw  %3(  r'c(t|||tS)z >>> _decode_path_part(u'%61%77%2f%7a') u'aw%2fz' >>> _decode_path_part(u'%61%77%2f%7a', normalize_case=True) u'aw%2Fz' r)r _PATH_DECODE_MAPr s r%_decode_path_partrs  %3$  r'c(t|||tSr)r _QUERY_KEY_DECODE_MAPr s r%_decode_query_keyrs  %3)  r'c(t|||tSr)r _QUERY_VALUE_DECODE_MAPr s r%_decode_query_valuers  %3+  r'c(t|||tSr)r _FRAGMENT_DECODE_MAPr s r%_decode_fragment_partrrr'zutf-8c |j|}|jd}t|dk(r|S|dg}|j} |ddD] } | dd| dd} } | || | | "dj|} |j|S#t$r|cYSwxYw#t $rK| t v} | s|s | dn| d|r!| r| | j| | n| | YwxYw#t$r|r|cYSwxYw)aConvert percent-encoded text characters to their normal, human-readable equivalents. All characters in the input text must be encodable by *subencoding*. All special characters underlying the values in the percent-encoding must be decodable as *subencoding*. If a non-*subencoding*-valid string is passed, the original text is returned with no changes applied. Only called by field-tailored variants, e.g., :func:`_decode_path_part`, as every percent-encodable part of the URL has characters which should not be percent decoded. >>> _percent_decode(u'abc%20def') u'abc def' Args: text: Text with percent-encoding present. normalize_case: Whether undecoded percent segments, such as encoded delimiters, should be uppercased, per RFC 3986 Section 2.1. See :func:`_decode_path_part` for an example. subencoding: The name of the encoding underlying the percent-encoding. raise_subencoding_exc: Whether an error in decoding the bytes underlying the percent-decoding should be raised. Returns: Text: The percent-decoded version of *text*, decoded by *subencoding*. %rrNrs%25r') rUnicodeEncodeErrorrlenappendKeyErrorrDupperrarUnicodeDecodeError)rer subencodingraise_subencoding_excrr quoted_bytesbitsresr!itemhexpairrest pair_is_hexunquoted_bytess r%r r s8J{{;/    d #D 4yA~ 7)C ZZFQRRa$qr(  ;w' ( 4L *XXc]N$$[11E   !]2K"7t v+w}}'t t  (   s6BB"C9 BB"AC65C69D  D c|sy |jd} t|d}|S#t$r|}Y|SwxYw#t$r|}Y|SwxYw)uDecode a host from ASCII-encodable text to IDNA-decoded text. If the host text is not ASCII, it is returned unchanged, as it is presumed that it is already IDNA-decoded. Some technical details: _decode_host is built on top of the "idna" package, which has some quirks: Capital letters are not valid IDNA2008. The idna package will raise an exception like this on capital letters: > idna.core.InvalidCodepoint: Codepoint U+004B at position 1 ... not allowed However, if a segment of a host (i.e., something in url.host.split('.')) is already ASCII, idna doesn't perform its usual checks. In fact, for capital letters it automatically lowercases them. This check and some other functionality can be bypassed by passing uts46=True to idna.encode/decode. This allows a more permissive and convenient interface. So far it seems like the balanced approach. Example output (from idna==2.6): >> idna.encode(u'mahmöud.io') 'xn--mahmud-zxa.io' >> idna.encode(u'Mahmöud.io') Traceback (most recent call last): File "", line 1, in File "/home/mahmoud/virtualenvs/hyperlink/local/lib/python2.7/site-packages/idna/core.py", line 355, in encode result.append(alabel(label)) File "/home/mahmoud/virtualenvs/hyperlink/local/lib/python2.7/site-packages/idna/core.py", line 276, in alabel check_label(label) File "/home/mahmoud/virtualenvs/hyperlink/local/lib/python2.7/site-packages/idna/core.py", line 253, in check_label raise InvalidCodepoint('Codepoint {0} at position {1} of {2} not allowed'.format(_unot(cp_value), pos+1, repr(label))) idna.core.InvalidCodepoint: Codepoint U+004D at position 1 of u'Mahmöud' not allowed >> idna.encode(u'Mahmoud.io') 'Mahmoud.io' # Similar behavior for decodes below >> idna.decode(u'Mahmoud.io') u'mahmoud.io >> idna.decode(u'Méhmoud.io', uts46=True) u'méhmoud.io' r]r;Tuts46)r idna_decoderr)host host_bytes host_texts r% _decode_hostr6sr\  [[)  #Jd;I    I      s8 & 55 AAcg}|D]2}|dk(r |dk(r|s|j"|j|4t|dddgdgfvr|jd|S)aNormalize the URL path by resolving segments of '.' and '..'. For more details, see `RFC 3986 section 5.2.4, Remove Dot Segments`_. Args: path: sequence of path segments in text form Returns: A new sequence of path segments with the '.' and '..' elements removed and resolved. .. _RFC 3986 section 5.2.4, Remove Dot Segments: https://tools.ietf.org/html/rfc3986#section-5.2.4 .z..rNr])rIr!list)pathsegssegs r%_resolve_dot_segmentsr=Eso D $;  E\ KK  DID6E7++ C Kr'c8|syd|vr tt|t}||fS tt |t }||fS#tj$r}t d|d|dd}~wt $rY|fSwxYw#tjt f$rd}Y||fSwxYw)aHParse the host into a tuple of ``(family, host)``, where family is the appropriate :mod:`socket` module constant when the host is an IP address. Family is ``None`` when the host is not an IP. Will raise :class:`URLParseError` on invalid IPv6 constants. Returns: family (socket constant or None), host (string) >>> import socket >>> parse_host('googlewebsite.com') == (None, 'googlewebsite.com') True >>> parse_host('::1') == (socket.AF_INET6, '::1') True >>> parse_host('192.168.1.1') == (socket.AF_INET, '192.168.1.1') True )Nr]r?zinvalid IPv6 host: z (r*N)rrsocketerrorrrr)r3familyses r% parse_hostrCds&  t|  h % F 4<  gt $F 4<|| Kb IJ J!   4<  01 F 4<  s,>A8A5A## A54A58BBc eZdZdZ d&dZd'dZedZedZedZ edZ ed Z ed Z ed Z ed Zed ZedZd'dZdZdZdZedZeeeeeeeeef dZedZ d(dZdZdZd)dZdZdZd'dZ dZ!dZ"e#re"Z$e Z%ne"Z&e Z$eZ'eZ(edZ)d'd Z*d!Z+d*d"Z,d*d#Z-d$Z.edfd%Z/y)+URLa From blogs to billboards, URLs are so common, that it's easy to overlook their complexity and power. With hyperlink's :class:`URL` type, working with URLs doesn't have to be hard. URLs are made of many parts. Most of these parts are officially named in `RFC 3986`_ and this diagram may prove handy in identifying them:: foo://user:pass@example.com:8042/over/there?name=ferret#nose \_/ \_______/ \_________/ \__/\_________/ \_________/ \__/ | | | | | | | scheme userinfo host port path query fragment While :meth:`~URL.from_text` is used for parsing whole URLs, the :class:`URL` constructor builds a URL from the individual components, like so:: >>> from hyperlink import URL >>> url = URL(scheme=u'https', host=u'example.com', path=[u'hello', u'world']) >>> print(url.to_text()) https://example.com/hello/world The constructor runs basic type checks. All strings are expected to be text (:class:`str` in Python 3, :class:`unicode` in Python 2). All arguments are optional, defaulting to appropriately empty values. A full list of constructor arguments is below. Args: scheme: The text name of the scheme. host: The host portion of the network location port: The port part of the network location. If ``None`` or no port is passed, the port will default to the default port of the scheme, if it is known. See the ``SCHEME_PORT_MAP`` and :func:`register_default_port` for more info. path: A tuple of strings representing the slash-separated parts of the path, each percent-encoded. query: The query parameters, as a dictionary or as an sequence of percent-encoded key-value pairs. fragment: The fragment part of the URL. rooted: A rooted URL is one which indicates an absolute path. This is True on any URL that includes a host, or any relative URL that starts with a slash. userinfo: The username or colon-separated username:password pair. uses_netloc: Indicates whether ``://`` (the "netloc separator") will appear to separate the scheme from the *path* in cases where no host is present. Setting this to ``True`` is a non-spec-compliant affordance for the common practice of having URIs that are *not* URLs (cannot have a 'host' part) but nevertheless use the common ``://`` idiom that most people associate with URLs; e.g. ``message:`` URIs like ``message://message-id`` being equivalent to ``message:message-id``. This may be inferred based on the scheme depending on whether :func:`register_scheme` has been used to register the scheme and should not be passed directly unless you know the scheme works like this and you know it has not been registered. All of these parts are also exposed as read-only attributes of :class:`URL` instances, along with several useful methods. .. _RFC 3986: https://tools.ietf.org/html/rfc3986 .. _RFC 3987: https://tools.ietf.org/html/rfc3987 Nc ||d}||tj|}|r|r|sd}|d}|d}| t|}td||_|jrOt j |js0td|jd|jjdttd|d \} |_ t|trtd |td |D|_td t#|D|_td ||_t)d|t*t,|_t)d|t|_td|d |_| t5|j| } t)d| tt,|_|jxs0|j.xr"|j.tj|k7} | rd|_d|_|j0s-|j8dddk(rd|_|j dd|_| s"|j r|j0sd|_yyyy)Nrr\r]rzinvalid scheme: zF. Only alphanumeric, "+", "-", and "." allowed. Did you meant to call z .from_text()?r3z/?#@z)expected iterable of text for path, not: c36K|]}td|dyw) path segmentz/?#Nr).0segments r% zURL.__init__..s LGZ 7 Lc3ZK|]#\}}td|dtd|ddf%yw)zquery parameter namez&=#zquery parameter valuez&#T)rNrIrJkrXs r%rLzURL.__init__..s< 111e<2AtdK  s)+fragmentportryuserinforTrF)rgetboolr_scheme _SCHEME_REmatchrr+r,rC_hostrrrrv_pathr_query _fragmentrrNoneType_port_rooted _userinfor _uses_netlocr:) r$rr3r:queryrQrRryrSr_will_have_authoritys r%r&z URL.__init__s+  F F <D >$ZF"(F3 <<##DLL1 +/,,8O8OQ #:fdF#CD 4: dD !AEG  Lt L   #5)    $J9c8< !(FD9 #J&A  ,T\\;GK& ;h #jj JJ D4::)<)>> URL.from_text(u'http://example.com/pa/th').port 80 >>> URL.from_text(u'foo://example.com/pa/th').port >>> URL.from_text(u'foo://example.com:8042/pa/th').port 8042 .. note:: Per the standard, when the port is the same as the schemes default port, it will be omitted in the text URL. )r^r-s r%rRzURL.port@s,zzr'c|jS)zA tuple of strings, created by splitting the slash-separated hierarchical path. Started by the first slash after the host, terminated by a "?", which indicates the start of the :attr:`~hyperlink.URL.query` string. )rZr-s r%r:zURL.pathXror'c|jS)aTuple of pairs, created by splitting the ampersand-separated mapping of keys and optional values representing non-hierarchical data used to identify the resource. Keys are always strings. Values are strings when present, or None when missing. For more operations on the mapping, see :meth:`~hyperlink.URL.get()`, :meth:`~hyperlink.URL.add()`, :meth:`~hyperlink.URL.set()`, and :meth:`~hyperlink.URL.delete()`. )r[r-s r%rbz URL.querybs{{r'c|jS)aA string, the last part of the URL, indicated by the first "#" after the :attr:`~hyperlink.URL.path` or :attr:`~hyperlink.URL.query`. Enables indirect identification of a secondary resource, like an anchor within an HTML page. )r\r-s r%rQz URL.fragmentrs~~r'c|jS)awWhether or not the path starts with a forward slash (``/``). This is taken from the terminology in the BNF grammar, specifically the "path-rootless", rule, since "absolute path" and "absolute URI" are somewhat ambiguous. :attr:`path` does not contain the implicit prefixed ``"/"`` since that is somewhat awkward to work with. )r_r-s r%ryz URL.rooted|s||r'c|jS)zVThe colon-separated string forming the username-password combination. )r`r-s r%rSz URL.userinfos ~~r'c|jS)z Indicates whether ``://`` (the "netloc separator") will appear to separate the scheme from the *path* in cases where no host is present. )rar-s r%rzURL.uses_netlocs   r'c>|jjddS)zF The user portion of :attr:`~hyperlink.URL.userinfo`. r?r)rSrr-s r%userzURL.users }}""4(++r'c B|jd|}|rtd|jz|j}d|vr d|zdzg}n |jg}|jt j |jk7r$|jt|jg}|jr:|j}|sd|vr|d|jddz}|j||jdj|dj|S) aPCompute and return the appropriate host/port/userinfo combination. >>> url = URL.from_text(u'http://user:pass@localhost:8080/a/b?x=y') >>> url.authority() u'user:@localhost:8080' >>> url.authority(with_password=True) u'user:pass@localhost:8080' Args: with_password: Whether the return value of this method include the password in the URL, if it is set. Defaults to False. Returns: Text: The authority (network location and user information) portion of the URL. includeSecretsz$got unexpected keyword arguments: %rr?[]Nr@) rIrkeysr3rRrrTrr!rrSindexra)r$ with_passwordkwr3hostport authorityrSs r%rz URL.authoritys(/? BRWWYNO Oyy $;d S()H {H 99++DKK8 8 OODO , ==}}H TX%5#$>hnnT&:Q&>?   X &8,-yy##r'ct||jstSdD]}t||t||k7sy|j|jk(s$|jt vr|jt vryy)N)rrSr3rbrQrRrryFT)rr+NotImplementedgetattrr: _ROOT_PATHS)r$otherattrs r%__eq__z URL.__eq__sq%0! !  DtT"geT&::  99 " II ${)Br'c^t||jstS|j| Sr rr+rrr$rs r%__ne__z URL.__ne__(%0! !;;u%%%r'c t|j|j|j|j|j |j |j|j|j|jf Sr hashr+rrSr3r:rbrQrRryrr-s r%__hash__z URL.__hash__\             r'cHt|jxr |jS)aoWhether or not the URL is "absolute". Absolute URLs are complete enough to resolve to a network resource without being relative to a base URI. >>> URL.from_text(u'http://wikipedia.org/').absolute True >>> URL.from_text(u'?a=b&c=d').absolute False Absolute URLs must have both a scheme and a host set. )rUrr3r-s r%absolutez URL.absolutesDKK-DII..r'c |tur||jk7rd} |jt||jt||jt||j t||j t||jt||jt||jt||jt| |j S)a:class:`URL` objects are immutable, which means that attributes are designed to be set only once, at construction. Instead of modifying an existing URL, one simply creates a copy with the desired changes. If any of the following arguments is omitted, it defaults to the value on the current URL. Args: scheme: The text name of the scheme. host: The host portion of the network location. path: A tuple of strings representing the slash-separated parts of the path. query: The query parameters, as a dictionary or as an sequence of key-value pairs. fragment: The fragment part of the URL. port: The port part of the network location. rooted: Whether or not the path begins with a slash. userinfo: The username or colon-separated username:password pair. uses_netloc: Indicates whether ``://`` (the "netloc separator") will appear to separate the scheme from the *path* in cases where no host is present. Setting this to ``True`` is a non-spec-compliant affordance for the common practice of having URIs that are *not* URLs (cannot have a 'host' part) but nevertheless use the common ``://`` idiom that most people associate with URLs; e.g. ``message:`` URIs like ``message://message-id`` being equivalent to ``message:message-id``. This may be inferred based on the scheme depending on whether :func:`register_scheme` has been used to register the scheme and should not be passed directly unless you know the scheme works like this and you know it has not been registered. Returns: URL: A copy of the current :class:`URL`, with new values for parameters passed. N rr3r:rbrQrRryrSr) r:rr+rr3r:rbrQrRryrSr) r$rr3r:rbrQrRryrSrs r%r[z URL.replacesd  Fdkk$9K~~VT[[14+4+E4::.x74+VT[[1x7!+t/?/?@  r'c tjtd|}|td|z|j }|dxsd}t j|}|td|d||j }|drtd |dd||d xsd}|d xs|d }|d } | t | } |dxsd} |dxsd} t|d} |dr-t|djd} | ds| dd} d}nd}n d} t|}|dr%td|djdD}nd}|| || || | ||| S#t$r| std|ztd| zwxYw)aFWhereas the :class:`URL` constructor is useful for constructing URLs from parts, :meth:`~URL.from_text` supports parsing whole URLs from their string form:: >>> URL.from_text(u'http://example.com') URL.from_text(u'http://example.com') >>> URL.from_text(u'?a=b&x=y') URL.from_text(u'?a=b&x=y') As you can see above, it's also used as the :func:`repr` of :class:`URL` objects. The natural counterpart to :func:`~URL.to_text()`. This method only accepts *text*, so be sure to decode those bytestrings. Args: text: A valid URL string. Returns: URL: The structured object version of the parsed string. .. note:: Somewhat unexpectedly, URLs are a far more permissive format than most would assume. Many strings which don't look like URLs are still valid URLs. As a result, this method only raises :class:`URLParseError` on invalid port and IPv6 values in the host portion of the URL. reNzcould not parse url: %rrr]zinvalid authority z in url: bad_hostz invalid host rS ipv6_host plain_hostrRzport must not be empty: %rz!expected integer for port, not %rrrQ _netloc_sepr:/rrTFr2rbc3PK|]}d|vr|jddn|df yw)rArN)r)rJqes r%rLz URL.from_text..s: rzHHT1%d$s$&r@) _URL_RErXrr groupdict _AUTHORITY_RErrrUrvr)clsreumgsau_textau_mau_gsrSr3rRrrQrr:ryrbs r% from_textz URL.from_textHs>]]:fd3 4 : 9D @A A \\^[/(S""7+ <5(S2m,- f:F))$/0D7ABxD']F g; W+++D1 EE           = P'(Dw(NOO#$G$$NOO Ps 7 E(Fcti}|r|jj|d<|r|jj|d<fd} |r>|jr-t |jD cgc] } | |  c} |d<nd|d<|r4|j D cgc]\} } | | | r| | n| fc} } |d<|r| |j |d<|rBdj|jjdd D cgc] } | |  c} |d <|jd i|Scc} wcc} } wcc} w) aReturn a new URL object with several standard normalizations applied: * Decode unreserved characters (`RFC 3986 2.3`_) * Uppercase remaining percent-encoded octets (`RFC 3986 2.1`_) * Convert scheme and host casing to lowercase (`RFC 3986 3.2.2`_) * Resolve any "." and ".." references in the path (`RFC 3986 6.2.2.3`_) * Ensure an ending slash on URLs with an empty path (`RFC 3986 6.2.3`_) * Encode any stray percent signs (`%`) in percent-encoded fields (path, query, fragment, userinfo) (`RFC 3986 2.4`_) All are applied by default, but normalizations can be disabled per-part by passing `False` for that part's corresponding name. Args: scheme: Convert the scheme to lowercase host: Convert the host to lowercase path: Normalize the path (see above for details) query: Normalize the query string fragment: Normalize the fragment userinfo: Normalize the userinfo percents: Encode isolated percent signs for any percent-encoded fields which are being normalized (defaults to `True`). >>> url = URL.from_text(u'Http://example.COM/a/../b/./c%2f?%61%') >>> print(url.normalize().to_text()) http://example.com/b/c%2F?a%25 .. _RFC 3986 3.2.2: https://tools.ietf.org/html/rfc3986#section-3.2.2 .. _RFC 3986 2.3: https://tools.ietf.org/html/rfc3986#section-2.3 .. _RFC 3986 2.1: https://tools.ietf.org/html/rfc3986#section-2.1 .. _RFC 3986 6.2.2.3: https://tools.ietf.org/html/rfc3986#section-6.2.2.3 .. _RFC 3986 6.2.3: https://tools.ietf.org/html/rfc3986#section-6.2.3 .. _RFC 3986 2.4: https://tools.ietf.org/html/rfc3986#section-2.4 rr3c t|dS)NT)rr)r )targetpercentss r% _dec_unresz!URL.normalize.._dec_unress%t8 r'r:r\rbrQr?rrSr2) rrHr3r:r=rbrQrarSrr[) r$rr3r:rbrQrSrrrprPrXs ` r%rz URL.normalizes,^ ;;,,.BxL *BvJ  yy+@+K&'JqM6 $6 !JJAqA 1 :BwK ' 6BzN !YY(, (;(;C(CD1ADBzNt||!b!!# Es,D*D/?D5c |s|S|Dcgc]}td|}}t|j}|jr|jddk(r|dd}|tt|dz }|j |Scc}w)aMake a new :class:`URL` where the given path segments are a child of this URL, preserving other parts of the URL, including the query string and fragment. For example:: >>> url = URL.from_text(u'http://localhost/a/b?x=y') >>> child_url = url.child(u"c", u"d") >>> child_url.to_text() u'http://localhost/a/b/c/d?x=y' Args: segments: Additional parts to be joined and added to the path, like :func:`os.path.join`. Special characters in segments will be percent encoded. Returns: URL: A copy of the current URL with the extra path segments. rHrr]NFrur:)rrvr:r~r[)r$segmentssnew_paths r%childz URL.childs*K4< ./J~q )  # 992#-}HE,XuEFF|||** sBctd|t|jddt|fz}|j |S)amMake a new :class:`URL` with a single path segment that is a sibling of this URL path. Args: segment: A single path segment. Returns: URL: A copy of the current URL with the last path segment replaced by *segment*. Special characters such as ``/?#`` will be percent encoded. rHNrr)rrvr:ror[)r$rKrs r%siblingz URL.siblingsB >7+#CR(,=g,F+HH|||**r'c|rBt|tr|}n!td|tj|}|jr|S|}|j }|j r|jstd||jr |j}nU|jr/t|jddt|jz}n|j}|s |j }|j|j xs |j |jxs |j|jxs |jt|||jS)a7Resolve the given URL relative to this URL. The resulting URI should match what a web browser would generate if you visited the current URL and clicked on *href*. >>> url = URL.from_text(u'http://blog.hatnote.com/') >>> url.click(u'/post/155074058790').to_text() u'http://blog.hatnote.com/post/155074058790' >>> url = URL.from_text(u'http://localhost/a/b/c/') >>> url.click(u'../d/./e').to_text() u'http://localhost/a/b/d/e' Args (Text): href: A string representing a clicked URL. Return: A copy of the current URL with navigation logic applied. For more information, see `RFC 3986 section 5`_. .. _RFC 3986 section 5: https://tools.ietf.org/html/rfc3986#section-5 z relative URLz!absolute URI with rootless path: Nr)rr3rRr:rbrQ)rrErrrrbrryNotImplementedErrorr:rvr[r3rRr=rQ)r$hrefclickedrbr:s r%clickz URL.click+s0 $$ >40---G  >>'..&9=? ~~||TYY',uW\\/BByy JJE||>>0T[[**&t,%%   r'cJdj|jjddDcgc] }t|c}}t |j t |jdd}|js |jn%t|jdjd}|j|||t|jDcgc]#\}}t|d| t|dnd f%c}}t!|j"d Scc}wcc}}w) uDMake a new :class:`URL` instance with all non-ASCII characters appropriately percent-encoded. This is useful to do in preparation for sending a :class:`URL` over a network protocol. For example:: >>> URL.from_text(u'https://ايران.com/foo⇧bar/').to_uri() URL.from_text(u'https://xn--mgba3a4fra.com/foo%E2%87%A7bar/') Returns: URL: A new instance with its path segments, query parameters, and hostname encoded, so that they are all in the standard US-ASCII range. r?rFT)rzryrfr0r;ruNrSr3r:rbrQ)rarSrrr~r:rUrr3 idna_encoderr[rvrbrrrrQ)r$r new_userinfornew_hostrPrXs r%to_uriz URL.to_uriks yy/3}}/B/B3/J K! "1 % K & II$t{{"3E4  99 IITYYd3::7C  ||!!% 1 *!T:=,At<!  +4==$G   Ls D(Dc dj|jjddDcgc] }t|c}}t |j }|j |||jDcgc] }t|c}td|jDt|jScc}wcc}w)uMake a new :class:`URL` instance with all but a few reserved characters decoded into human-readable format. Percent-encoded Unicode and IDNA-encoded hostnames are decoded, like so:: >>> url = URL.from_text(u'https://xn--mgba3a4fra.example.com/foo%E2%87%A7bar/') >>> print(url.to_iri().to_text()) https://ايران.example.com/foo⇧bar/ .. note:: As a general Python issue, "narrow" (UCS-2) builds of Python may not be able to fully decode certain URLs, and the in those cases, this method will return a best-effort, partially-decoded, URL which is still valid. This issue does not affect any Python builds 3.4+. Returns: URL: A new instance with its path segments, query parameters, and hostname decoded for display purposes. r?rc3VK|]!\}}t|| t|ndf#ywr )rrrOs r%rLzURL.to_iri..s7 Aq&a(./m'*s')r) rarSrrr6r3r[r:rrvrbrrQ)r$rrr5rKs r%to_iriz URL.to_iris0yy/3}}/B/B3/J K! "1 % K !+ ||!<@IIF#G,F !JJ +4==9  LGs B<3C c "|j}|j|}djt|j|j t |t |d}g}|jD]\\}}||jt|d%|jdjt|dt|df^dj|}|j} g} | j} |r| || d|r| d | |n|r|dd d k7r|jr| d |r|r|r|dd dk7r| d| ||r| d | || r| d | | dj| S)aRender this URL to its textual representation. By default, the URL text will *not* include a password, if one is set. RFC 3986 considers using URLs to represent such sensitive information as deprecated. Quoting from RFC 3986, `section 3.2.1`: "Applications should not render as clear text any data after the first colon (":") character found within a userinfo subcomponent unless the data after the colon is the empty string (indicating no password)." Args (bool): with_password: Whether or not to include the password in the URL text. Defaults to False. Returns: Text: The serialized textual representation of this URL, such as ``u"http://example.com/some/path?some=query"``. The natural counterpart to :class:`URL.from_text()`. .. _section 3.2.1: https://tools.ietf.org/html/rfc3986#section-3.2.1 rF)ryrzr{rfNrurAr@r?z//rr?#r]) rrrar~r:ryrUrbr!rrrQr) r$rrrr: query_partsrPrX query_stringrQparts_adds r%to_textz URL.to_textsw4NN=1 xx  {{<"9o    JJ DAqy""#4Q#FG""II-a?/5A yy- ==||  L I  J O RaD(T-=-= J )RaCS J  I    I Nxxr'cV|jjd|jdS)zConvert this URL to an representation that shows all of its constituent parts, as well as being a valid argument to :func:`eval`. z .from_text(r*)r+r,rr-s r%r.z URL.__repr__s &*^^%<%>> URL.from_text(u'https://example.com/?x=y').add(u'x') URL.from_text(u'https://example.com/?x=y&x') >>> URL.from_text(u'https://example.com/?x=y').add(u'x', u'z') URL.from_text(u'https://example.com/?x=y&x=z') Args: name: The name of the query parameter to add. The part before the ``=``. value: The value of the query parameter to add. The part after the ``=``. Defaults to ``None``, meaning no value. Returns: URL: A new :class:`URL` instance with the parameter added. rbr[rbr$r"rs r%rzURL.add@s%(||$**u /?"?|@@r'c|jDcgc]\}}|k7s ||f}}}tfdt|jDd}|fg||||j|Scc}}w)aMake a new :class:`URL` instance with the query parameter *name* set to *value*. All existing occurences, if any are replaced by the single name-value pair. >>> URL.from_text(u'https://example.com/?x=y').set(u'x') URL.from_text(u'https://example.com/?x') >>> URL.from_text(u'https://example.com/?x=y').set(u'x', u'z') URL.from_text(u'https://example.com/?x=z') Args: name: The name of the query parameter to set. The part before the ``=``. value: The value of the query parameter to set. The part after the ``=``. Defaults to ``None``, meaning no value. Returns: URL: A new :class:`URL` instance with the parameter set. c3:K|]\}\}}|k(s|ywr r2rJrWrPrXr"s r%rLzURL.set..ns E;Av119Q Errrbnext enumerater[)r$r"rrPrXqidxs ` r%rEzURL.setVsp,#'** :AT aV : : E)DJJ"7 Er Um_#c ||!|$$ ;s A*A*cX|jDcgc] \}}||k(s |c}}Scc}}w)a5Get a list of values for the given query parameter, *name*:: >>> url = URL.from_text(u'?x=1&x=2') >>> url.get('x') [u'1', u'2'] >>> url.get('y') [] If the given *name* is not set, an empty list is returned. A list is always returned, and this method raises no exceptions. Args: name: The name of the query parameter to get. Returns: List[Optional[Text]]: A list of all the values associated with the key, in string form. r)r$r"keyrs r%rTzURL.getss&(+/**D,3 DDD &&c|Z|tur'|jDcgc]\}}||k7s ||f}}}ns|jDcgc]\}}||k(r||k(s||f}}}nHgd}}|jD]5\}}||k(r|tus||k(r ||kr|dz }#|j||f7|j|Scc}}wcc}}w)aMake a new :class:`URL` instance with occurrences of the query parameter *name* removed, or, if *value* is set, parameters matching *name* and *value*. No exception is raised if the parameter is not already set. Args: name: The name of the query parameter to remove. value: Optional value to additionally filter on. Setting this removes query parameters which match both name and value. limit: Optional maximum number of parameters to remove. Returns: URL: A new :class:`URL` instance with the parameter removed. rrrr:rbr!r[r$r"rlimitrPrXnq removed_counts r%removez URL.removes, =+/::C!Qdq!fCC#'**AI!u*F !#A B  &1I&AJ%-!Q&MIIq!f% &||"|%%)D B7B7B=) NNr2r2r]NNr]NFTTTTTTTr\r )0r,r4r5rr&rlpropertyrr3rRr:rbrQryrSrrxrrrrrr:r[ classmethodrrrrrrrrr.rr__str__ __unicode__ __bytes__rrrrrrrErTrr2r'r%rErEs =B   S&j!.    !!,,%$N,&  " / /"   @ D^ ^ D  N"`+B+"> @+ Z) VJXN7    E E  :A,%:E2 ,&r'rEc&|jddS)Nrz%20)r[res r% _replace_plusrs <<U ##r'c|Sr r2rs r%_no_opr s Kr'c eZdZdZeddfdZed'dZedZ d(dZ dZ d Z d Z d)d Zd Zd Z d*dZedZedZedZedZedZedZedZedZedZedZedZeeeeeeeeef dZdZd+dZ d+dZ!edfdZ"dZ#d Z$d!Z%d"Z&d#Z'e Z(e Z)ed(d$Z*d(d%Z+d&Z,y),rkaI :class:`DecodedURL` is a type designed to act as a higher-level interface to :class:`URL` and the recommended type for most operations. By analogy, :class:`DecodedURL` is the :class:`unicode` to URL's :class:`bytes`. :class:`DecodedURL` automatically handles encoding and decoding all its components, such that all inputs and outputs are in a maximally-decoded state. Note that this means, for some special cases, a URL may not "roundtrip" character-for-character, but this is considered a good tradeoff for the safety of automatic encoding. Otherwise, :class:`DecodedURL` has almost exactly the same API as :class:`URL`. Where applicable, a UTF-8 encoding is presumed. Be advised that some interactions can raise :exc:`UnicodeEncodeErrors` and :exc:`UnicodeDecodeErrors`, just like when working with bytestrings. Examples of such interactions include handling query strings encoding binary data, and paths containing segments with special characters encoded with codecs other than UTF-8. Args: url: A :class:`URL` object to wrap. lazy: Set to True to avoid pre-decode all parts of the URL to check for validity. Defaults to False. query_plus_is_space: + characters in the query string should be treated as spaces when decoding. If unspecified, the default is taken from the scheme. .. note:: The :class:`DecodedURL` initializer takes a :class:`URL` object, not URL components, like :class:`URL`. To programmatically construct a :class:`DecodedURL`, you can use this pattern: >>> print(DecodedURL().replace(scheme=u'https', ... host=u'pypi.org', path=(u'projects', u'hyperlink')).to_text()) https://pypi.org/projects/hyperlink .. versionadded:: 18.0.0 FNc||_||jtv}||_|s9|j|j |j |j|jfyr ) _urlrr_query_plus_is_spacer3rSr:rbrQ)r$urlrhrs r%r&zDecodedURL.__init__sQ  &"%**4I"I $7! IIt}}diiT]] Jr'cBtj|}||||S)a  Make a `DecodedURL` instance from any text string containing a URL. Args: text: Text containing the URL lazy: Whether to pre-decode all parts of the URL to check for validity. Defaults to True. )rhr)rEr)rrerhrr s r%rzDecodedURL.from_texts"}}T"4d8KLLr'c|jS)zeAccess the underlying :class:`URL` object, which has any special characters encoded. )r r-s r% encoded_urlzDecodedURL.encoded_urls yyr'c8|jj|S)z/Passthrough to :meth:`~hyperlink.URL.to_text()`)r r)r$rs r%rzDecodedURL.to_textsyy  //r'c6|jjS)z.Passthrough to :meth:`~hyperlink.URL.to_uri()`)r rr-s r%rzDecodedURL.to_uriyy!!r'c6|jjS)z.Passthrough to :meth:`~hyperlink.URL.to_iri()`)r rr-s r%rzDecodedURL.to_iri"rr'c<|j||jS)N)r)r+r)r$rs r%_clonezDecodedURL._clone's$~~  $ 9 9  r'ct|tr |j}|j|jj |S)z^Return a new DecodedURL wrapping the result of :meth:`~hyperlink.URL.click()` )r)rrkr rr)r$rs r%rzDecodedURL.click/s: dJ '99D{{ IIOOO &  r'ch|j|jjt|S)zAutomatically encode any reserved characters in *segment* and return a new `DecodedURL` wrapping the result of :meth:`~hyperlink.URL.sibling()` )rr rrj)r$rKs r%rzDecodedURL.sibling:s- {{ II  .w7 8  r'c|s|S|Dcgc] }t|}}|j|jj|Scc}w)zAutomatically encode any reserved characters in *segments* and return a new `DecodedURL` wrapping the result of :meth:`~hyperlink.URL.child()`. )rjrr r)r$rrnew_segss r%rzDecodedURL.childDsH K19:A$Q'::{{?499??H566;sAc b|j|jj|||||||S)zdReturn a new `DecodedURL` wrapping the result of :meth:`~hyperlink.URL.normalize()` )rr r)r$rr3r:rbrQrSrs r%rzDecodedURL.normalizeOs6{{ II  dE8Xx   r'c.|jjSr )r rr-s r%rzDecodedURL.absolutecsyy!!!r'c.|jjSr )r rr-s r%rzDecodedURL.schemehyyr'c@t|jjSr )r6r r3r-s r%r3zDecodedURL.hostmsDIINN++r'c.|jjSr )r rRr-s r%rRzDecodedURL.portrsyy~~r'c.|jjSr )r ryr-s r%ryzDecodedURL.rootedwr r'c t|ds=t|jjDcgc]}t |dc}|_|j Scc}w)NrZTr&)hasattrrvr r:r rZ)r$rs r%r:zDecodedURL.path|sRtW%"YY^^$ATBDJ zz sAct|dsT|jrtntt t t fd|jjD|_ |jS)Nr[c3PK|]\}}tfd||fDyw)c3LK|]}|t|dndyw)NTr%r )rJx predecodes r%rLz-DecodedURL.query...s: =(%aL" "s!$Nrv)rJrPrXr,s r%rLz#DecodedURL.query..s7 1 #$Q  s#&) r&rrr r QueryPairsrvr rbr[)r$r,s @r%rbzDecodedURL.querys\tX&(() "  !%    DK{{r'ct|ds(|jj}t|d|_|jS)Nr\Tr%)r&r rQr r\)r$frags r%rQzDecodedURL.fragments5t[)99%%D,TNDN~~r'c t|dsstttttttfft t d|j jjddD|_ |jS)Nr`c36K|]}t|dyw)Tr%Nr*rJrs r%rLz&DecodedURL.userinfo..s"(FFrMr?r) r&rrrrrvr rSrr`r-s r%rSzDecodedURL.userinfosst[)!eCj%S/12!%!3!3!9!9#q!ADN~~r'c |jdS)Nr)rSr-s r%rxzDecodedURL.users}}Qr'c.|jjSr )r rr-s r%rzDecodedURL.uses_netlocsyy$$$r'c |turtd|D}|tur)tttdt |D}|turEt |dkDrt d|dj|D cgc] } t| c} } nt} |jj|||||||| |  } |j| Scc} w)aWhile the signature is the same, this `replace()` differs a little from URL.replace. For instance, it accepts userinfo as a tuple, not as a string, handling the case of having a username containing a `:`. As with the rest of the methods on DecodedURL, if you pass a reserved character, it will be automatically encoded instead of an error being raised. c32K|]}t|ywr rjr3s r%rLz%DecodedURL.replace..s;)!,;sc3JK|]\}}td||fDyw)c3:K|]}| t|ndywr r8)rJr+s r%rLz/DecodedURL.replace...s'01}(+$FsNr-rOs r%rLz%DecodedURL.replace..s4 1 "#Qs!#rzDuserinfo expected sequence of ["user"] or ["user", "password"], got r?r)r) r:rvrr.rr rrarjr r[r) r$rr3r:rbrQrRryrSrr userinfo_textnew_urls r%r[zDecodedURL.replaces( v ;d;;D   !+5 1  E 6 !8}q  7?B!IIH&Mq'7':&MNM"M))##"#$  {{w{'''Ns?CcX|jDcgc] \}}||k(s |c}}Scc}}w)z?Get the value of all query parameters whose name matches *name*r)r$r"rPrXs r%rTzDecodedURL.gets&!% 8fq!dai888rcF|j|j||ffzS)zRReturn a new DecodedURL with the query parameter *name* and *value* added.rrrs r%rzDecodedURL.adds%||$**u /?"?|@@r'c|j}|Dcgc]\}}|k7s ||f}}}tfdt|Dd}|fg||||j|Scc}}w)zBReturn a new DecodedURL with query parameter *name* set to *value*c3:K|]\}\}}|k(s|ywr r2rs r%rLz!DecodedURL.set.. sG+1fq!Q$YAGrrrr)r$r"rrbrPrXrrs ` r%rEzDecodedURL.set sm "' 5A19aV 5 5G5)9GLUm_#c ||!|$$ 6s A"A"c|Z|tur'|jDcgc]\}}||k7s ||f}}}ns|jDcgc]\}}||k(r||k(s||f}}}nHgd}}|jD]5\}}||k(r|tus||k(r ||kr|dz }#|j||f7|j|Scc}}wcc}}w)zReturn a new DecodedURL with query parameter *name* removed. Optionally also filter for *value*, as well as cap the number of parameters removed with *limit*. rrrrrs r%rzDecodedURL.remove s =+/::C!Qdq!fCC#'**AI!u*F !#A B  &1I&AJ%-!Q&MIIq!f% &||"|%%'DrcR|jj}|d|jdS)Nz(url=r*)r+r,r )r$cns r%r.zDecodedURL.__repr__0 s ^^ $ $!499--r'c,t|jSr )rr r-s r%rzDecodedURL.__str__5 s499~r'ct||jstS|jj |jj k(Sr )rr+rrrrs r%rzDecodedURL.__eq__; sA%0! !~~&&(EOO,=,D,D,FFFr'c^t||jstS|j| Sr rrs r%rzDecodedURL.__ne__A rr'c t|j|j|j|j|j |j |j|j|j|jf Sr rr-s r%rzDecodedURL.__hash__G rr'c(|j||Srfr)rrrhs r%rzDecodedURL.fromText\ s}}QT}**r'c&|j|Srrrs r%rzDecodedURL.asTexta rr'c tj|}tt|tgdz }|S#t$r<t|jt |j jz}YhwxYwrrrs r%rzDecodedURL.__dir__e rr)FNrr\rr )-r,r4r5r _EMPTY_URLr&rrrrrrrrrrrrrrr3rRryr:rbrQrSrxrr:r[rTrrErr.rrrrrrrrrr2r'r%rkrks+Z&Et  M M0 " "      7   (""  ,,    0    %%    5(n9 A % !&F.  G &  $ E E++:r'rkcRtj|}|s|St||}|S)a~ Automatically turn text into a structured URL object. >>> url = parse(u"https://github.com/python-hyper/hyperlink") >>> print(url.to_text()) https://github.com/python-hyper/hyperlink Args: url: A text string representation of a URL. decoded: Whether or not to return a :class:`DecodedURL`, which automatically handles all encoding/decoding/quoting/unquoting for all the various accessors of parts of the URL, or a :class:`URL`, which has the same API, but requires handling of special characters for different parts of the URL. lazy: In the case of `decoded=True`, this controls whether the URL is decoded immediately or as accessed. The default, `lazy=False`, checks all encoded parts of the URL for decodability. .. versionadded:: 18.0.0 rg) EncodedURLrrk)rdecodedrhenc_urldec_urls r%parserQr s-4""3'G t,G Nr')_MISSINGr]r)T)FTTT)TNTr )FF)TF)rresysstringr?rrr ImportErrorrtypingrrrr r r r r rrrrrrr unicodedatar_socketrcollections.abcr collectionsidnarrrr2 version_inforunichr NameErrorrUtyper]r.QueryParametersrr9 _unspecifiedr: frozensetrccompilerrWrrC hexdigitsrD _ASCII_RE _GEN_DELIMS _SUB_DELIMS _ALL_DELIMSrE_USERINFO_SAFEr _PATH_SAFErn_SCHEMELESS_PATH_SAFErr_FRAGMENT_SAFEr_QUERY_VALUE_SAFEr_QUERY_KEY_SAFErrPrZrrrmrqrrrrrrrrbrr rrjrorsr~rrrrrrrrrrrrrrrr rrrrrr r6r=rCr8rErMrKrr rkrQ)arhrPrXs0000r%rqs$ $$""25> qQ  : 5x~-.3 4  D(4. ! U4$' ()+  CL8v&h// v K "** RZZ, -   !! !!  a% &QUB"8"?"? "JKK  BJJ' (  # ' K' "[03t9</ c%j ( Z' "SX-%(=="Z/#e*</%T(BB!$55#&7#d)&CC/1  +>:'(89&z2"12G"H#L1&7():;():;*+>?%n5'(89'(9:"'') Aq 88GY '+< < A % $(   0 f    (- C- 3- D- 2 -  D -  2 - 4- b- B- S- C- 3- C- 3- D-  C!-" S#-$ 4%-& D'-( T)-* D+-, 3--. C/-0 S1-2 33-45-6 T7-8 S9-: C;-< S=-> T?-@ BA-B 3C-D CE-F       Y-`&DH1 h@ J   $-;$ 7<   7< 7<  M`=@>'Tg&&g&T! U $  ffV mJM02112 FNJsBO O2O, A O: /"P OO O)(O),O76O7