text: # -*- coding: utf-8 -*-
  # Copyright (c) 2017 Ian 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,
          )
  