|
- # -*- coding: utf-8 -*-
- # Copyright (c) 2017 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.
- """Module containing the logic for the URIBuilder object."""
- from . import compat
- from . import normalizers
- from . import uri
-
-
- class URIBuilder(object):
- """Object to aid in building up a URI Reference from parts.
-
- .. note::
-
- This object should be instantiated by the user, but it's recommended
- that it is not provided with arguments. Instead, use the available
- method to populate the fields.
-
- """
-
- def __init__(self, scheme=None, userinfo=None, host=None, port=None,
- path=None, query=None, fragment=None):
- """Initialize our URI builder.
-
- :param str scheme:
- (optional)
- :param str userinfo:
- (optional)
- :param str host:
- (optional)
- :param int port:
- (optional)
- :param str path:
- (optional)
- :param str query:
- (optional)
- :param str fragment:
- (optional)
- """
- self.scheme = scheme
- self.userinfo = userinfo
- self.host = host
- self.port = port
- self.path = path
- self.query = query
- self.fragment = fragment
-
- def __repr__(self):
- """Provide a convenient view of our builder object."""
- formatstr = ('URIBuilder(scheme={b.scheme}, userinfo={b.userinfo}, '
- 'host={b.host}, port={b.port}, path={b.path}, '
- 'query={b.query}, fragment={b.fragment})')
- return formatstr.format(b=self)
-
- def add_scheme(self, scheme):
- """Add a scheme to our builder object.
-
- After normalizing, this will generate a new URIBuilder instance with
- the specified scheme and all other attributes the same.
-
- .. code-block:: python
-
- >>> URIBuilder().add_scheme('HTTPS')
- URIBuilder(scheme='https', userinfo=None, host=None, port=None,
- path=None, query=None, fragment=None)
-
- """
- scheme = normalizers.normalize_scheme(scheme)
- return URIBuilder(
- scheme=scheme,
- userinfo=self.userinfo,
- host=self.host,
- port=self.port,
- path=self.path,
- query=self.query,
- fragment=self.fragment,
- )
-
- def add_credentials(self, username, password):
- """Add credentials as the userinfo portion of the URI.
-
- .. code-block:: python
-
- >>> URIBuilder().add_credentials('root', 's3crete')
- URIBuilder(scheme=None, userinfo='root:s3crete', host=None,
- port=None, path=None, query=None, fragment=None)
-
- >>> URIBuilder().add_credentials('root', None)
- URIBuilder(scheme=None, userinfo='root', host=None,
- port=None, path=None, query=None, fragment=None)
- """
- if username is None:
- raise ValueError('Username cannot be None')
- userinfo = normalizers.normalize_username(username)
-
- if password is not None:
- userinfo = '{}:{}'.format(
- userinfo,
- normalizers.normalize_password(password),
- )
-
- return URIBuilder(
- scheme=self.scheme,
- userinfo=userinfo,
- host=self.host,
- port=self.port,
- path=self.path,
- query=self.query,
- fragment=self.fragment,
- )
-
- def add_host(self, host):
- """Add hostname to the URI.
-
- .. code-block:: python
-
- >>> URIBuilder().add_host('google.com')
- URIBuilder(scheme=None, userinfo=None, host='google.com',
- port=None, path=None, query=None, fragment=None)
-
- """
- return URIBuilder(
- scheme=self.scheme,
- userinfo=self.userinfo,
- host=normalizers.normalize_host(host),
- port=self.port,
- path=self.path,
- query=self.query,
- fragment=self.fragment,
- )
-
- def add_port(self, port):
- """Add port to the URI.
-
- .. code-block:: python
-
- >>> URIBuilder().add_port(80)
- URIBuilder(scheme=None, userinfo=None, host=None, port='80',
- path=None, query=None, fragment=None)
-
- >>> URIBuilder().add_port(443)
- URIBuilder(scheme=None, userinfo=None, host=None, port='443',
- path=None, query=None, fragment=None)
-
- """
- port_int = int(port)
- if port_int < 0:
- raise ValueError(
- 'ports are not allowed to be negative. You provided {}'.format(
- port_int,
- )
- )
- if port_int > 65535:
- raise ValueError(
- 'ports are not allowed to be larger than 65535. '
- 'You provided {}'.format(
- port_int,
- )
- )
-
- return URIBuilder(
- scheme=self.scheme,
- userinfo=self.userinfo,
- host=self.host,
- port='{}'.format(port_int),
- path=self.path,
- query=self.query,
- fragment=self.fragment,
- )
-
- def add_path(self, path):
- """Add a path to the URI.
-
- .. code-block:: python
-
- >>> URIBuilder().add_path('sigmavirus24/rfc3985')
- URIBuilder(scheme=None, userinfo=None, host=None, port=None,
- path='/sigmavirus24/rfc3986', query=None, fragment=None)
-
- >>> URIBuilder().add_path('/checkout.php')
- URIBuilder(scheme=None, userinfo=None, host=None, port=None,
- path='/checkout.php', query=None, fragment=None)
-
- """
- if not path.startswith('/'):
- path = '/{}'.format(path)
-
- return URIBuilder(
- scheme=self.scheme,
- userinfo=self.userinfo,
- host=self.host,
- port=self.port,
- path=normalizers.normalize_path(path),
- query=self.query,
- fragment=self.fragment,
- )
-
- def add_query_from(self, query_items):
- """Generate and add a query a dictionary or list of tuples.
-
- .. code-block:: python
-
- >>> URIBuilder().add_query_from({'a': 'b c'})
- URIBuilder(scheme=None, userinfo=None, host=None, port=None,
- path=None, query='a=b+c', fragment=None)
-
- >>> URIBuilder().add_query_from([('a', 'b c')])
- URIBuilder(scheme=None, userinfo=None, host=None, port=None,
- path=None, query='a=b+c', fragment=None)
-
- """
- query = normalizers.normalize_query(compat.urlencode(query_items))
-
- return URIBuilder(
- scheme=self.scheme,
- userinfo=self.userinfo,
- host=self.host,
- port=self.port,
- path=self.path,
- query=query,
- fragment=self.fragment,
- )
-
- def add_query(self, query):
- """Add a pre-formated query string to the URI.
-
- .. code-block:: python
-
- >>> URIBuilder().add_query('a=b&c=d')
- URIBuilder(scheme=None, userinfo=None, host=None, port=None,
- path=None, query='a=b&c=d', fragment=None)
-
- """
- return URIBuilder(
- scheme=self.scheme,
- userinfo=self.userinfo,
- host=self.host,
- port=self.port,
- path=self.path,
- query=normalizers.normalize_query(query),
- fragment=self.fragment,
- )
-
- def add_fragment(self, fragment):
- """Add a fragment to the URI.
-
- .. code-block:: python
-
- >>> URIBuilder().add_fragment('section-2.6.1')
- URIBuilder(scheme=None, userinfo=None, host=None, port=None,
- path=None, query=None, fragment='section-2.6.1')
-
- """
- return URIBuilder(
- scheme=self.scheme,
- userinfo=self.userinfo,
- host=self.host,
- port=self.port,
- path=self.path,
- query=self.query,
- fragment=normalizers.normalize_fragment(fragment),
- )
-
- def finalize(self):
- """Create a URIReference from our builder.
-
- .. code-block:: python
-
- >>> URIBuilder().add_scheme('https').add_host('github.com'
- ... ).add_path('sigmavirus24/rfc3986').finalize().unsplit()
- 'https://github.com/sigmavirus24/rfc3986'
-
- >>> URIBuilder().add_scheme('https').add_host('github.com'
- ... ).add_path('sigmavirus24/rfc3986').add_credentials(
- ... 'sigmavirus24', 'not-re@l').finalize().unsplit()
- 'https://sigmavirus24:not-re%40l@github.com/sigmavirus24/rfc3986'
-
- """
- return uri.URIReference(
- self.scheme,
- normalizers.normalize_authority(
- (self.userinfo, self.host, self.port)
- ),
- self.path,
- self.query,
- self.fragment,
- )
|