# Public API

The only public yarl class is `URL`:

    >>> from yarl import URL

class yarl.URL(arg, *, encoded=False)

Represents URL as

    [scheme:]//[user[:password]@]host[:port][/path][?query][#fragment]

for absolute URLs and

    [/path][?query][#fragment]

for relative ones (Absolute and relative URLs).

The URL structure is:

     http://user:pass@example.com:8042/over/there?name=ferret#nose
     \__/   \__/ \__/ \_________/ \__/\_________/ \_________/ \__/
      |      |    |        |       |      |           |        |
    scheme  user password host    port   path       query   fragment

Internally all data are stored as percent-encoded strings for user, path, query and fragment URL parts and IDNA-encoded (RFC 5891) for host.

Constructor and modification operators perform encoding for all parts automatically. The library assumes all data uses UTF-8 for percent-encoded tokens.

    >>> URL('http://example.com/path/to/?arg1=a&arg2=b#fragment')
    URL('http://example.com/path/to/?arg1=a&arg2=b#fragment')

Unless URL contain the only ascii characters there is no differences.

But for non-ascii case encoding is applied.

    >>> str(URL('http://εμπορικόσήμα.eu/шлях/這裡'))
    'http://xn--jxagkqfkduily1i.eu/%D1%88%D0%BB%D1%8F%D1%85/%E9%80%99%E8%A3%A1'

The same is true for user, password, query and fragment parts of URL.

Already encoded URL is not changed:

    >>> URL('http://xn--jxagkqfkduily1i.eu')
    URL('http://xn--jxagkqfkduily1i.eu')

Use `human_repr()` for getting human readable representation:

    >>> url = URL('http://εμπορικόσήμα.eu/шлях/這裡')
    >>> str(url)
    'http://xn--jxagkqfkduily1i.eu/%D1%88%D0%BB%D1%8F%D1%85/%E9%80%99%E8%A3%A1'
    >>> url.human_repr()
    'http://εμπορικόσήμα.eu/шлях/這裡'

Note

Sometimes encoding performed by yarl is not acceptable for certain WEB server.

Passing `encoded=True` parameter prevents URL auto-encoding, user is responsible about URL correctness.

Don’t use this option unless there is no other way for keeping URL attributes not touched.

Any URL manipulations don’t guarantee correct encoding, URL parts could be re-quoted even if encoded parameter was explicitly set.

## URL properties

There are two kinds of properties: decoded and encoded (with `raw_` prefix):

URL.scheme

  Scheme for absolute URLs, empty string for relative URLs or URLs starting with `'//'` (Absolute and relative URLs).

      >>> URL('http://example.com').scheme
      'http'
      >>> URL('//example.com').scheme
      ''
      >>> URL('page.html').scheme
      ''

URL.user

  Decoded user part of URL, `None` if user is missing.

      >>> URL('http://john@example.com').user
      'john'
      >>> URL('http://бажан@example.com').user
      'бажан'
      >>> URL('http://example.com').user is None
      True

URL.raw_user

  Encoded user part of URL, `None` if user is missing.

      >>> URL('http://довбуш@example.com').raw_user
      '%D0%B4%D0%BE%D0%B2%D0%B1%D1%83%D1%88'
      >>> URL('http://example.com').raw_user is None
      True

URL.password

  Decoded password part of URL, `None` if user is missing.

      >>> URL('http://john:pass@example.com').password
      'pass'
      >>> URL('http://степан:пароль@example.com').password
      'пароль'
      >>> URL('http://example.com').password is None
      True

URL.raw_password

  Encoded password part of URL, `None` if user is missing.

      >>> URL('http://user:пароль@example.com').raw_password
      '%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C'

URL.host

  Encoded host part of URL, `None` for relative URLs (Absolute and relative URLs).

  Brackets are stripped for IPv6. Host is converted to lowercase, address is validated and converted to compressed form.

      >>> URL('http://example.com').host
      'example.com'
      >>> URL('http://хост.домен').host
      'хост.домен'
      >>> URL('page.html').host is None
      True
      >>> URL('http://[::1]').host
      '::1'

URL.raw_host

  IDNA decoded host part of URL, `None` for relative URLs (Absolute and relative URLs).

      >>> URL('http://хост.домен').raw_host
      'xn--n1agdj.xn--d1acufc'
      >>> URL('http://[::1]').raw_host
      '::1'

URL.host_subcomponent

  RFC 3986 Section 3.2.2 host subcomponent part of URL, `None` for relative URLs (Absolute and relative URLs).

      >>> URL('http://хост.домен').host_subcomponent
      'xn--n1agdj.xn--d1acufc'
      >>> URL('http://[::1]').host_subcomponent
      '[::1]'

  Added in version 1.13.

URL.host_port_subcomponent

  RFC 3986 Section 3.2.2 host and RFC 3986 Section 3.2.3 port subcomponent part of URL, `None` for relative URLs (Absolute and relative URLs).

  Trailing dots are stripped from the host to ensure this value can be used for an HTTP Host header.

  The port is omitted if it is the default port for the scheme.

      >>> URL('http://хост.домен:81').host_port_subcomponent
      'xn--n1agdj.xn--d1acufc:81'
      >>> URL('https://[::1]:8443').host_port_subcomponent
      '[::1]:8443'
      >>> URL('http://example.com./').host_port_subcomponent
      'example.com'
      >>> URL('http://[::1]').host_port_subcomponent
      '[::1]'

  Added in version 1.17.

URL.port

  port part of URL, with scheme-based fallback.

  `None` for relative URLs (Absolute and relative URLs) or for URLs without explicit port and `URL.scheme` without default port substitution.

      >>> URL('http://example.com:8080').port
      8080
      >>> URL('http://example.com').port
      80
      >>> URL('page.html').port is None
      True

URL.explicit_port

  explicit_port part of URL, without scheme-based fallback.

  `None` for relative URLs (Absolute and relative URLs) or for URLs without explicit port.

      >>> URL('http://example.com:8080').explicit_port
      8080
      >>> URL('http://example.com').explicit_port is None
      True
      >>> URL('page.html').explicit_port is None
      True

  Added in version 1.3.

URL.authority

  Decoded authority part of URL, a combination of user, password, host, and port.

  `authority = [ user [ ":" password ] "@" ] host [ ":" port ]`.

  authority is empty string if all parts are missing.

      >>> URL('http://john:pass@example.com:8000').authority
      'john:pass@example.com:8000'

  Added in version 1.5.

URL.raw_authority

  Encoded authority part of URL, a combination of user, password, host, and port. empty string if all parts are missing.

      >>> URL('http://john:pass@хост.домен:8000').raw_authority
      'john:pass@xn--n1agdj.xn--d1acufc:8000'

  Added in version 1.5.

URL.path

  Decoded path part of URL, `'/'` for absolute URLs without path part.

      >>> URL('http://example.com/path/to').path
      '/path/to'
      >>> URL('http://example.com/шлях/сюди').path
      '/шлях/сюди'
      >>> URL('http://example.com').path
      '/'

  Warning

  In many situations it is important to distinguish between path separators (a literal `/`) and other forward slashes (a literal `%2F`). Use `URL.path_safe` for these cases.

URL.path_safe

  Similar to `URL.path` except it doesn’t decode `%2F` or `%25`. This allows to distinguish between path separators (`/`) and encoded slashes (`%2F`).

  Note that `%25` is also not decoded to avoid issues with double unquoting of values. e.g. You can unquote the value with `URL.path_safe.replace("%2F", "/").replace("%25", %")` to get the same result as `URL.path()`. If the `%25` was unquoted, it would be impossible to tell the difference between `%2F` and `%252F`.

  Added in version 1.12.

URL.path_qs

  Decoded path part of URL and query string, `'/'` for absolute URLs without path part.

      >>> URL('http://example.com/path/to?a1=a&a2=b').path_qs
      '/path/to?a1=a&a2=b'

URL.raw_path_qs

  Encoded path part of URL and query string, `'/'` for absolute URLs without path part.

      >>> URL('http://example.com/шлях/сюди?ключ=знач').raw_path_qs
      '/%D1%88%D0%BB%D1%8F%D1%85/%D1%81%D1%8E%D0%B4%D0%B8?%D0%BA%D0%BB%D1%8E%D1%87=%D0%B7%D0%BD%D0%B0%D1%87'

  Added in version 0.15.

URL.raw_path

  Encoded path part of URL, `'/'` for absolute URLs without path part.

      >>> URL('http://example.com/шлях/сюди').raw_path
      '/%D1%88%D0%BB%D1%8F%D1%85/%D1%81%D1%8E%D0%B4%D0%B8'

URL.query_string

  Decoded query part of URL, empty string if query is missing.

      >>> URL('http://example.com/path?a1=a&a2=b').query_string
      'a1=a&a2=b'
      >>> URL('http://example.com/path?ключ=знач').query_string
      'ключ=знач'
      >>> URL('http://example.com/path').query_string
      ''

URL.raw_query_string

  Encoded query part of URL, empty string if query is missing.

      >>> URL('http://example.com/path?ключ=знач').raw_query_string
      '%D0%BA%D0%BB%D1%8E%D1%87=%D0%B7%D0%BD%D0%B0%D1%87'

URL.fragment

  Encoded fragment part of URL, empty string if fragment is missing.

      >>> URL('http://example.com/path#fragment').fragment
      'fragment'
      >>> URL('http://example.com/path#якір').fragment
      'якір'
      >>> URL('http://example.com/path').fragment
      ''

URL.raw_fragment

  Decoded fragment part of URL, empty string if fragment is missing.

      >>> URL('http://example.com/path#якір').raw_fragment
      '%D1%8F%D0%BA%D1%96%D1%80'

For path and query yarl supports additional helpers:

URL.parts

  A `tuple` containing decoded path parts, `('/',)` for absolute URLs if path is missing.

      >>> URL('http://example.com/path/to').parts
      ('/', 'path', 'to')
      >>> URL('http://example.com/шлях/сюди').parts
      ('/', 'шлях', 'сюди')
      >>> URL('http://example.com').parts
      ('/',)

URL.raw_parts

  A `tuple` containing encoded path parts, `('/',)` for absolute URLs if path is missing.

      >>> URL('http://example.com/шлях/сюди').raw_parts
      ('/', '%D1%88%D0%BB%D1%8F%D1%85', '%D1%81%D1%8E%D0%B4%D0%B8')

URL.name

  The last part of `parts`.

      >>> URL('http://example.com/path/to').name
      'to'
      >>> URL('http://example.com/шлях/сюди').name
      'сюди'
      >>> URL('http://example.com/path/').name
      ''

URL.raw_name

  The last part of `raw_parts`.

      >>> URL('http://example.com/шлях/сюди').raw_name
      '%D1%81%D1%8E%D0%B4%D0%B8'

URL.suffix

  The file extension of `name`.

      >>> URL('http://example.com/path/to.txt').suffix
      '.txt'
      >>> URL('http://example.com/шлях.сюди').suffix
      '.сюди'
      >>> URL('http://example.com/path').suffix
      ''

URL.raw_suffix

  The file extension of `raw_name`.

      >>> URL('http://example.com/шлях.сюди').raw_suffix
      '.%D1%81%D1%8E%D0%B4%D0%B8'

URL.suffixes

  A list of `name`’s file extensions.

      >>> URL('http://example.com/path/to.tar.gz').suffixes
      ('.tar', '.gz')
      >>> URL('http://example.com/шлях.тут.ось').suffixes
      ('.тут', '.ось')
      >>> URL('http://example.com/path').suffixes
      ()

URL.raw_suffixes

  A list of `raw_name`’s file extensions.

      >>> URL('http://example.com/шлях.тут.ось').raw_suffixes
      ('.%D1%82%D1%83%D1%82', '.%D0%BE%D1%81%D1%8C')

URL.query

  A `multidict.MultiDictProxy` representing parsed query parameters in decoded representation. Empty value if URL has no query part.

      >>> URL('http://example.com/path?a1=a&a2=b').query
      <MultiDictProxy('a1': 'a', 'a2': 'b')>
      >>> URL('http://example.com/path?ключ=знач').query
      <MultiDictProxy('ключ': 'знач')>
      >>> URL('http://example.com/path').query
      <MultiDictProxy()>

## Absolute and relative URLs

The module supports both absolute and relative URLs.

Absolute URL should start from either scheme or `'//'`.

URL.absolute

  > A check for absolute URLs.

  > Return `True` for absolute ones (having scheme or starting with `'//'`), `False` otherwise.

      >>> URL('http://example.com').absolute
      True
      >>> URL('//example.com').absolute
      True
      >>> URL('/path/to').absolute
      False
      >>> URL('path').absolute
      False

  Changed in version 1.9.10: The `absolute` property is preferred over the `is_absolute()` method.

## New URL generation

URL is an immutable object, every operation described in the section generates a new `URL` instance.

classmethod URL.build(*, scheme=..., authority=..., user=..., password=..., host=..., port=..., path=..., query=..., query_string=..., fragment=..., encoded=False)

  Creates and returns a new URL:

      >>> URL.build(scheme="http", host="example.com")
      URL('http://example.com')

      >>> URL.build(scheme="http", host="example.com", query={"a": "b"})
      URL('http://example.com/?a=b')

      >>> URL.build(scheme="http", host="example.com", query_string="a=b")
      URL('http://example.com/?a=b')

      >>> URL.build()
      URL('')

  Calling `build` method without arguments is equal to calling `__init__` without arguments.

  Note

  Only one of `query` or `query_string` should be passed then ValueError will be raised.

URL.with_scheme(scheme)

  Return a new URL with scheme replaced:

      >>> URL('http://example.com').with_scheme('https')
      URL('https://example.com')

  Returned URL may have a different `port` (default port substitution).

URL.with_user(user)

  Return a new URL with user replaced, auto-encode user if needed.

  Clear user/password if user is `None`.

      >>> URL('http://user:pass@example.com').with_user('new_user')
      URL('http://new_user:pass@example.com')
      >>> URL('http://user:pass@example.com').with_user('олекса')
      URL('http://%D0%BE%D0%BB%D0%B5%D0%BA%D1%81%D0%B0:pass@example.com')
      >>> URL('http://user:pass@example.com').with_user(None)
      URL('http://example.com')

URL.with_password(password)

  Return a new URL with password replaced, auto-encode password if needed.

  Clear password if `None` is passed.

      >>> URL('http://user:pass@example.com').with_password('пароль')
      URL('http://user:%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C@example.com')
      >>> URL('http://user:pass@example.com').with_password(None)
      URL('http://user@example.com')

URL.with_host(host)

  Return a new URL with host replaced, auto-encode host if needed.

  Changing host for relative URLs is not allowed, use `URL.join()` instead.

      >>> URL('http://example.com/path/to').with_host('python.org')
      URL('http://python.org/path/to')
      >>> URL('http://example.com/path').with_host('хост.домен')
      URL('http://xn--n1agdj.xn--d1acufc/path')

URL.with_port(port)

  Return a new URL with port replaced.

  Clear port to default if `None` is passed.

      >>> URL('http://example.com:8888').with_port(9999)
      URL('http://example.com:9999')
      >>> URL('http://example.com:8888').with_port(None)
      URL('http://example.com')

URL.with_path(path, *, keep_query=False, keep_fragment=False)

  Return a new URL with path replaced, encode path if needed.

  If `keep_query=True` or `keep_fragment=True` it retains the existing query or fragment in the URL.

  Changed in version 1.18: Added keep_query and keep_fragment parameters.

      >>> URL('http://example.com/').with_path('/path/to')
      URL('http://example.com/path/to')

URL.with_query(query)
URL.with_query(**kwargs)

  Return a new URL with query part replaced.

  Unlike `update_query()` the method replaces all query parameters.

  Accepts any `Mapping` (e.g. `dict`, `MultiDict` instances) or `str`, auto-encode the argument if needed.

  A sequence of `(key, value)` pairs is supported as well.

  Also it can take an arbitrary number of keyword arguments.

  Clear query if `None` is passed.

  Note

  The library accepts `str`, `float`, `int` and their subclasses except `bool` as query argument values.

  If a mapping such as `dict` is used, the values may also be `list` or `tuple` to represent a key has many values.

  Please see Why isn’t boolean supported by the URL query API? for the reason why `bool` is not supported out-of-the-box.

      >>> URL('http://example.com/path?a=b').with_query('c=d')
      URL('http://example.com/path?c=d')
      >>> URL('http://example.com/path?a=b').with_query({'c': 'd'})
      URL('http://example.com/path?c=d')
      >>> URL('http://example.com/path?a=b').with_query({'c': [1, 2]})
      URL('http://example.com/path?c=1&c=2')
      >>> URL('http://example.com/path?a=b').with_query({'кл': 'зн'})
      URL('http://example.com/path?%D0%BA%D0%BB=%D0%B7%D0%BD')
      >>> URL('http://example.com/path?a=b').with_query(None)
      URL('http://example.com/path')
      >>> URL('http://example.com/path?a=b&b=1').with_query(b='2')
      URL('http://example.com/path?b=2')
      >>> URL('http://example.com/path?a=b&b=1').with_query([('b', '2')])
      URL('http://example.com/path?b=2')

  Changed in version 1.5: Support `list` and `tuple` as a query parameter value.

  Changed in version 1.6: Support subclasses of `int` (except `bool`) and `float` as a query parameter value.

URL.extend_query(query)
URL.extend_query(**kwargs)

  Returns a new URL with query part extended.

  Unlike `update_query()`, this method keeps duplicate keys.

  Returned `URL` object will contain query string which extends parts from passed query parts (or parts of parsed query string).

  Accepts any `Mapping` (e.g. `dict`, `MultiDict` instances) or `str`, auto-encode the argument if needed.

  A sequence of `(key, value)` pairs is supported as well.

  Also it can take an arbitrary number of keyword arguments.

  Returns the same `URL` if query of `None` is passed.

  Note

  The library accepts `str`, `float`, `int` and their subclasses except `bool` as query argument values.

  If a mapping such as `dict` is used, the values may also be `list` or `tuple` to represent a key has many values.

  Please see Why isn’t boolean supported by the URL query API? for the reason why `bool` is not supported out-of-the-box.

      >>> URL('http://example.com/path?a=b&b=1').extend_query(b='2')
      URL('http://example.com/path?a=b&b=1&b=2')
      >>> URL('http://example.com/path?a=b&b=1').extend_query([('b', '2')])
      URL('http://example.com/path?a=b&b=1&b=2')
      >>> URL('http://example.com/path?a=b&c=e&c=f').extend_query(c='d')
      URL('http://example.com/path?a=b&c=e&c=f&c=d')

  Added in version 1.11.0.

URL.update_query(query)
URL.update_query(**kwargs)

  Returns a new URL with query part updated.

  Unlike `with_query()` the method does not replace query completely.

  Returned `URL` object will contain query string which updated parts from passed query parts (or parts of parsed query string).

  Accepts any `Mapping` (e.g. `dict`, `MultiDict` instances) or `str`, auto-encode the argument if needed.

  A sequence of `(key, value)` pairs is supported as well.

  Also it can take an arbitrary number of keyword arguments.

  Clear query if `None` is passed.

  Mod operator (`%`) can be used as alternative to the direct call of `URL.update_query()`.

  Note

  The library accepts `str`, `float`, `int` and their subclasses except `bool` as query argument values.

  If a mapping such as `dict` is used, the values may also be `list` or `tuple` to represent a key has many values.

  Please see Why isn’t boolean supported by the URL query API? for the reason why `bool` is not supported out-of-the-box.

      >>> URL('http://example.com/path?a=b').update_query('c=d')
      URL('http://example.com/path?a=b&c=d')
      >>> URL('http://example.com/path?a=b').update_query({'c': 'd'})
      URL('http://example.com/path?a=b&c=d')
      >>> URL('http://example.com/path?a=b').update_query({'c': [1, 2]})
      URL('http://example.com/path?a=b&c=1&c=2')
      >>> URL('http://example.com/path?a=b').update_query({'кл': 'зн'})
      URL('http://example.com/path?a=b&%D0%BA%D0%BB=%D0%B7%D0%BD')
      >>> URL('http://example.com/path?a=b&b=1').update_query(b='2')
      URL('http://example.com/path?a=b&b=2')
      >>> URL('http://example.com/path?a=b&b=1').update_query([('b', '2')])
      URL('http://example.com/path?a=b&b=2')
      >>> URL('http://example.com/path?a=b&c=e&c=f').update_query(c='d')
      URL('http://example.com/path?a=b&c=d')
      >>> URL('http://example.com/path?a=b').update_query('c=d&c=f')
      URL('http://example.com/path?a=b&c=d&c=f')
      >>> URL('http://example.com/path?a=b') % {'c': 'd'}
      URL('http://example.com/path?a=b&c=d')

  Changed in version 1.0: All multiple key/value pairs are applied to the multi-dictionary.

  Added in version 1.5: Support for mod operator (`%`) to update the URL’s query part.

  Changed in version 1.5: Support `list` and `tuple` as a query parameter value.

  Changed in version 1.6: Support subclasses of `int` (except `bool`) and `float` as a query parameter value.

URL.without_query_params(*query_params)

  Return a new URL whose query part does not contain specified `query_params`.

  Accepts `str` for `query_params`.

  It does nothing if none of specified `query_params` are present in the query.

  Added in version 1.10.0.

URL.with_fragment(fragment)

  Return a new URL with fragment replaced, auto-encode fragment if needed.

  Clear fragment to default if `None` is passed.

      >>> URL('http://example.com/path#frag').with_fragment('anchor')
      URL('http://example.com/path#anchor')
      >>> URL('http://example.com/path#frag').with_fragment('якір')
      URL('http://example.com/path#%D1%8F%D0%BA%D1%96%D1%80')
      >>> URL('http://example.com/path#frag').with_fragment(None)
      URL('http://example.com/path')

URL.with_name(name, *, keep_query=False, keep_fragment=False)

  Return a new URL with name (last part of path) replaced and cleaned up query and fragment parts.

  Name is encoded if needed.

  If `keep_query=True` or `keep_fragment=True` it retains the existing query or fragment in the URL.

  Changed in version 1.18: Added keep_query and keep_fragment parameters.

      >>> URL('http://example.com/path/to?arg#frag').with_name('new')
      URL('http://example.com/path/new')
      >>> URL('http://example.com/path/to').with_name("ім'я")
      URL('http://example.com/path/%D1%96%D0%BC%27%D1%8F')

URL.with_suffix(suffix, *, keep_query=False, keep_fragment=False)

  Return a new URL with suffix (file extension of name) replaced and cleaned up query and fragment parts.

  Name is encoded if needed.

  If `keep_query=True` or `keep_fragment=True` it retains the existing query or fragment in the URL.

  Changed in version 1.18: Added keep_query and keep_fragment parameters.

      >>> URL('http://example.com/path/to?arg#frag').with_suffix('.doc')
      URL('http://example.com/path/to.doc')
      >>> URL('http://example.com/path/to').with_suffix('.cуфікс')
      URL('http://example.com/path/to.c%D1%83%D1%84%D1%96%D0%BA%D1%81')

URL.parent

  A new URL with last part of path removed and cleaned up query and fragment parts.

      >>> URL('http://example.com/path/to?arg#frag').parent
      URL('http://example.com/path')

URL.origin()

  A new URL with scheme, host and port parts only. user, password, path, query and fragment are removed.

      >>> URL('http://example.com/path/to?arg#frag').origin()
      URL('http://example.com')
      >>> URL('http://user:pass@example.com/path').origin()
      URL('http://example.com')

URL.relative()

  A new relative URL with path, query and fragment parts only. scheme, user, password, host and port are removed.

      >>> URL('http://example.com/path/to?arg#frag').relative()
      URL('/path/to?arg#frag')

Division (`/`) operator creates a new URL with appended path parts and cleaned up query and fragment parts.

The path is encoded if needed.

>     >>> url = URL('http://example.com/path?arg#frag') / 'to/subpath'
>     >>> url
>     URL('http://example.com/path/to/subpath')
>     >>> url.parts
>     ('/', 'path', 'to', 'subpath')
>     >>> url = URL('http://example.com/path?arg#frag') / 'сюди'
>     >>> url
>     URL('http://example.com/path/%D1%81%D1%8E%D0%B4%D0%B8')

URL.joinpath(*other, encoded=False)

  Construct a new URL by with all `other` elements appended to path, and cleaned up query and fragment parts.

  Passing `encoded=True` parameter prevents path element auto-encoding, the caller is responsible for taking care of URL correctness.

      >>> url = URL('http://example.com/path?arg#frag').joinpath('to', 'subpath')
      >>> url
      URL('http://example.com/path/to/subpath')
      >>> url.parts
      ('/', 'path', 'to', 'subpath')
      >>> url = URL('http://example.com/path?arg#frag').joinpath('сюди')
      >>> url
      URL('http://example.com/path/%D1%81%D1%8E%D0%B4%D0%B8')
      >>> url = URL('http://example.com/path').joinpath('%D1%81%D1%8E%D0%B4%D0%B8', encoded=True)
      >>> url
      URL('http://example.com/path/%D1%81%D1%8E%D0%B4%D0%B8')

  Added in version 1.9.

URL.__truediv__(url)

  Shortcut for `URL.joinpath()` with a single element and `encoded=False`.

      >>> url = URL('http://example.com/path?arg#frag') / 'to'
      >>> url
      URL('http://example.com/path/to')
      >>> url.parts
      ('/', 'path', 'to')

  Added in version 0.9.

URL.join(url)

  Construct a full (“absolute”) URL by combining a “base URL” (`self`) with another URL (`url`). Informally, this uses components of the base URL, in particular the addressing scheme, the network location and (part of) the path, to provide missing components in the relative URL, e.g.:

      >>> base = URL('http://example.com/path/index.html')
      >>> base.join(URL('page.html'))
      URL('http://example.com/path/page.html')

  Note

  If `url` is an absolute URL (that is, starting with `//` or `scheme://`), the URL‘s host name and/or scheme will be present in the result, e.g.:

      >>> base = URL('http://example.com/path/index.html')
      >>> base.join(URL('//python.org/page.html'))
      URL('http://python.org/page.html')

## Human readable representation

All URL data is stored in encoded form internally. It’s pretty good for passing `str(url)` everywhere URL string is accepted but quite bad for memorizing by humans.

URL.human_repr()

  Return decoded human readable string for URL representation.

      >>> url = URL('http://εμπορικόσήμα.eu/這裡')
      >>> str(url)
      'http://xn--jxagkqfkduily1i.eu/%E9%80%99%E8%A3%A1'
      >>> url.human_repr()
      'http://εμπορικόσήμα.eu/這裡'

## Default port substitution

`yarl` is aware about the following scheme -> port translations:

scheme | port
--- | ---
`'http'` | 80
`'https'` | 443
`'ws'` | 80
`'wss'` | 443

URL.is_default_port()

  > A check for default port.

  > Return `True` if URL’s `port` is default for used `scheme`, `False` otherwise.

  > Relative URLs have no default port.

      >>> URL('http://example.com').is_default_port()
      True
      >>> URL('http://example.com:80').is_default_port()
      True
      >>> URL('http://example.com:8080').is_default_port()
      False
      >>> URL('/path/to').is_default_port()
      False

## Cache control

IDNA conversion and host encoding are quite expensive operations, that’s why the `yarl` library caches these calls by storing results in the global LRU cache.

yarl.cache_clear()

  Clear IDNA and host encoding cache.

yarl.cache_info()

  Return a dictionary with `"idna_encode"`, `"idna_decode"`, and `"encode_host"` keys, each value points to corresponding `CacheInfo` structure (see `functools.lru_cache()` for details):

      >>> yarl.cache_info()
      {'idna_encode': CacheInfo(hits=5, misses=5, maxsize=256, currsize=5),
       'idna_decode': CacheInfo(hits=24, misses=15, maxsize=256, currsize=15),
       'encode_host': CacheInfo(hits=0, misses=0, maxsize=512, currsize=0)}

  Changed in version 1.16: `ip_address`, and `host_validate` are deprecated in favor of a single `encode_host` cache.

yarl.cache_configure(*, idna_encode_size=256, idna_decode_size=256, encode_host_size=512)

  Set the IDNA encode, IDNA decode, and host encode cache sizes.

  Pass `None` to make the corresponding cache unbounded (may speed up host encoding operation a little but the memory footprint can be very high, please use with caution).

  Changed in version 1.16: `ip_address_size` and `host_validate_size` are deprecated in favor of a single `encode_host` cache.

## References

`yarl` stays on shoulders of giants: several RFC documents and low-level `urllib.parse` which performs almost all gory work.

The module borrowed design from `pathlib` in any place where it was possible.

See also

RFC 5891 - Internationalized Domain Names in Applications (IDNA): Protocol

  Document describing non-ASCII domain name encoding.

RFC 3987 - Internationalized Resource Identifiers

  This specifies conversion rules for non-ASCII characters in URL.

RFC 3986 - Uniform Resource Identifiers

  This is the current standard (STD66). Any changes to `yarl` module should conform to this. Certain deviations could be observed, which are mostly for backward compatibility purposes and for certain de-facto parsing requirements as commonly observed in major browsers.

RFC 2732 - Format for Literal IPv6 Addresses in URL’s.

  This specifies the parsing requirements of IPv6 URLs.

RFC 2396 - Uniform Resource Identifiers (URI): Generic Syntax

  Document describing the generic syntactic requirements for both Uniform Resource Names (URNs) and Uniform Resource Locators (URLs).

RFC 2368 - The mailto URL scheme.

  Parsing requirements for mailto URL schemes.

RFC 1808 - Relative Uniform Resource Locators This Request For

  Comments includes the rules for joining an absolute and a relative URL, including a fair number of “Abnormal Examples” which govern the treatment of border cases.

RFC 1738 - Uniform Resource Locators (URL)

  This specifies the formal syntax and semantics of absolute URLs.