161 lines
5.1 KiB
Python
161 lines
5.1 KiB
Python
|
"""Module containing the implementation of the URIReference class."""
|
||
|
# Copyright (c) 2014 Rackspace
|
||
|
# Copyright (c) 2015 Ian Stapleton Cordasco
|
||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
# you may not use this file except in compliance with the License.
|
||
|
# You may obtain a copy of the License at
|
||
|
#
|
||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||
|
#
|
||
|
# Unless required by applicable law or agreed to in writing, software
|
||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||
|
# implied.
|
||
|
# See the License for the specific language governing permissions and
|
||
|
# limitations under the License.
|
||
|
from collections import namedtuple
|
||
|
|
||
|
from . import compat
|
||
|
from . import misc
|
||
|
from . import normalizers
|
||
|
from ._mixin import URIMixin
|
||
|
|
||
|
|
||
|
class URIReference(namedtuple("URIReference", misc.URI_COMPONENTS), URIMixin):
|
||
|
"""Immutable object representing a parsed URI Reference.
|
||
|
|
||
|
.. note::
|
||
|
|
||
|
This class is not intended to be directly instantiated by the user.
|
||
|
|
||
|
This object exposes attributes for the following components of a
|
||
|
URI:
|
||
|
|
||
|
- scheme
|
||
|
- authority
|
||
|
- path
|
||
|
- query
|
||
|
- fragment
|
||
|
|
||
|
.. attribute:: scheme
|
||
|
|
||
|
The scheme that was parsed for the URI Reference. For example,
|
||
|
``http``, ``https``, ``smtp``, ``imap``, etc.
|
||
|
|
||
|
.. attribute:: authority
|
||
|
|
||
|
Component of the URI that contains the user information, host,
|
||
|
and port sub-components. For example,
|
||
|
``google.com``, ``127.0.0.1:5000``, ``username@[::1]``,
|
||
|
``username:password@example.com:443``, etc.
|
||
|
|
||
|
.. attribute:: path
|
||
|
|
||
|
The path that was parsed for the given URI Reference. For example,
|
||
|
``/``, ``/index.php``, etc.
|
||
|
|
||
|
.. attribute:: query
|
||
|
|
||
|
The query component for a given URI Reference. For example, ``a=b``,
|
||
|
``a=b%20c``, ``a=b+c``, ``a=b,c=d,e=%20f``, etc.
|
||
|
|
||
|
.. attribute:: fragment
|
||
|
|
||
|
The fragment component of a URI. For example, ``section-3.1``.
|
||
|
|
||
|
This class also provides extra attributes for easier access to information
|
||
|
like the subcomponents of the authority component.
|
||
|
|
||
|
.. attribute:: userinfo
|
||
|
|
||
|
The user information parsed from the authority.
|
||
|
|
||
|
.. attribute:: host
|
||
|
|
||
|
The hostname, IPv4, or IPv6 address parsed from the authority.
|
||
|
|
||
|
.. attribute:: port
|
||
|
|
||
|
The port parsed from the authority.
|
||
|
"""
|
||
|
|
||
|
slots = ()
|
||
|
|
||
|
def __new__(
|
||
|
cls, scheme, authority, path, query, fragment, encoding="utf-8"
|
||
|
):
|
||
|
"""Create a new URIReference."""
|
||
|
ref = super().__new__(
|
||
|
cls,
|
||
|
scheme or None,
|
||
|
authority or None,
|
||
|
path or None,
|
||
|
query,
|
||
|
fragment,
|
||
|
)
|
||
|
ref.encoding = encoding
|
||
|
return ref
|
||
|
|
||
|
__hash__ = tuple.__hash__
|
||
|
|
||
|
def __eq__(self, other):
|
||
|
"""Compare this reference to another."""
|
||
|
other_ref = other
|
||
|
if isinstance(other, tuple):
|
||
|
other_ref = URIReference(*other)
|
||
|
elif not isinstance(other, URIReference):
|
||
|
try:
|
||
|
other_ref = URIReference.from_string(other)
|
||
|
except TypeError:
|
||
|
raise TypeError(
|
||
|
"Unable to compare URIReference() to {}()".format(
|
||
|
type(other).__name__
|
||
|
)
|
||
|
)
|
||
|
|
||
|
# See http://tools.ietf.org/html/rfc3986#section-6.2
|
||
|
naive_equality = tuple(self) == tuple(other_ref)
|
||
|
return naive_equality or self.normalized_equality(other_ref)
|
||
|
|
||
|
def normalize(self):
|
||
|
"""Normalize this reference as described in Section 6.2.2.
|
||
|
|
||
|
This is not an in-place normalization. Instead this creates a new
|
||
|
URIReference.
|
||
|
|
||
|
:returns: A new reference object with normalized components.
|
||
|
:rtype: URIReference
|
||
|
"""
|
||
|
# See http://tools.ietf.org/html/rfc3986#section-6.2.2 for logic in
|
||
|
# this method.
|
||
|
return URIReference(
|
||
|
normalizers.normalize_scheme(self.scheme or ""),
|
||
|
normalizers.normalize_authority(
|
||
|
(self.userinfo, self.host, self.port)
|
||
|
),
|
||
|
normalizers.normalize_path(self.path or ""),
|
||
|
normalizers.normalize_query(self.query),
|
||
|
normalizers.normalize_fragment(self.fragment),
|
||
|
self.encoding,
|
||
|
)
|
||
|
|
||
|
@classmethod
|
||
|
def from_string(cls, uri_string, encoding="utf-8"):
|
||
|
"""Parse a URI reference from the given unicode URI string.
|
||
|
|
||
|
:param str uri_string: Unicode URI to be parsed into a reference.
|
||
|
:param str encoding: The encoding of the string provided
|
||
|
:returns: :class:`URIReference` or subclass thereof
|
||
|
"""
|
||
|
uri_string = compat.to_str(uri_string, encoding)
|
||
|
|
||
|
split_uri = misc.URI_MATCHER.match(uri_string).groupdict()
|
||
|
return cls(
|
||
|
split_uri["scheme"],
|
||
|
split_uri["authority"],
|
||
|
normalizers.encode_component(split_uri["path"], encoding),
|
||
|
normalizers.encode_component(split_uri["query"], encoding),
|
||
|
normalizers.encode_component(split_uri["fragment"], encoding),
|
||
|
encoding,
|
||
|
)
|