"""Module containing the implementation of the URIReference class.""" # -*- coding: utf-8 -*- # 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 adddres 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(URIReference, cls).__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 {0}()'.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, )