Hello community,

here is the log from the commit of package python-rfc3986 for openSUSE:Factory 
checked in at 2017-08-13 14:57:45
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-rfc3986 (Old)
 and      /work/SRC/openSUSE:Factory/.python-rfc3986.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-rfc3986"

Sun Aug 13 14:57:45 2017 rev:4 rq:515844 version:1.1.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-rfc3986/python-rfc3986.changes    
2017-06-18 13:51:01.481463552 +0200
+++ /work/SRC/openSUSE:Factory/.python-rfc3986.new/python-rfc3986.changes       
2017-08-13 14:57:46.484707568 +0200
@@ -1,0 +2,18 @@
+Thu Aug 10 07:22:30 UTC 2017 - [email protected]
+
+- update to 1.1.0:
+  * Bump version to 1.1.0
+  * Fix theme setting for documentation
+  * Exclude solitary line from coverage
+  * Note the version we added Validator in
+  * Fix documentation builds on RTD
+  * Add check_validity_of to vaildator docs
+  * Add some chars (!, =, etc) as allowed to the userinfo part of authority
+  * Add release notes for v1.1.0
+  * Add a separate testcase for special chars in userinfo and revert changes 
to other tests
+  * Add validation to eliminate URIReference.is_valid
+  * Add deprecation notices to old URIReference methods
+  * Make tests fail: add "%20!=" part to userinfo which is allowed as per 
RFC3986
+- Convert to singlespec
+
+-------------------------------------------------------------------

Old:
----
  rfc3986-1.0.0.tar.gz

New:
----
  rfc3986-1.1.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-rfc3986.spec ++++++
--- /var/tmp/diff_new_pack.uzsf3h/_old  2017-08-13 14:57:47.476568376 +0200
+++ /var/tmp/diff_new_pack.uzsf3h/_new  2017-08-13 14:57:47.488566692 +0200
@@ -16,22 +16,22 @@
 #
 
 
+%{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-rfc3986
-Version:        1.0.0
+Version:        1.1.0
 Release:        0
 Summary:        Validating URI References per RFC 3986
 License:        Apache-2.0
 Group:          Development/Languages/Python
 Url:            https://rfc3986.rtfd.org
 Source:         
https://pypi.io/packages/source/r/rfc3986/rfc3986-%{version}.tar.gz
-BuildRequires:  python-devel
-BuildRequires:  python-setuptools
+BuildRequires:  %{python_module devel}
+BuildRequires:  %{python_module setuptools}
+BuildRequires:  python-rpm-macros
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
-%if 0%{?suse_version} && 0%{?suse_version} <= 1110
-%{!?python_sitelib: %global python_sitelib %(python -c "from 
distutils.sysconfig import get_python_lib; print get_python_lib()")}
-%else
 BuildArch:      noarch
-%endif
+
+%python_subpackages
 
 %description
 A Python implementation of `RFC 3986`_ including validation and authority 
@@ -41,12 +41,12 @@
 %setup -q -n rfc3986-%{version}
 
 %build
-python setup.py build
+%python_build
 
 %install
-python setup.py install --prefix=%{_prefix} --root=%{buildroot}
+%python_install
 
-%files
+%files %{python_files}
 %defattr(-,root,root,-)
 %doc AUTHORS.rst LICENSE README.rst
 %{python_sitelib}/*

++++++ rfc3986-1.0.0.tar.gz -> rfc3986-1.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/PKG-INFO new/rfc3986-1.1.0/PKG-INFO
--- old/rfc3986-1.0.0/PKG-INFO  2017-05-10 13:59:35.000000000 +0200
+++ new/rfc3986-1.1.0/PKG-INFO  2017-07-18 14:18:10.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: rfc3986
-Version: 1.0.0
+Version: 1.1.0
 Summary: Validating URI References per RFC 3986
 Home-page: http://rfc3986.readthedocs.io
 Author: Ian Cordasco
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/docs/source/api-ref/uri.rst 
new/rfc3986-1.1.0/docs/source/api-ref/uri.rst
--- old/rfc3986-1.0.0/docs/source/api-ref/uri.rst       2017-05-10 
13:58:27.000000000 +0200
+++ new/rfc3986-1.1.0/docs/source/api-ref/uri.rst       2017-07-18 
13:35:25.000000000 +0200
@@ -17,3 +17,19 @@
 .. automethod:: rfc3986.uri.URIReference.is_absolute
 
 .. automethod:: rfc3986.uri.URIReference.authority_info
+
+
+Deprecated Methods
+==================
+
+.. automethod:: rfc3986.uri.URIReference.is_valid
+
+.. automethod:: rfc3986.uri.URIReference.authority_is_valid
+
+.. automethod:: rfc3986.uri.URIReference.scheme_is_valid
+
+.. automethod:: rfc3986.uri.URIReference.path_is_valid
+
+.. automethod:: rfc3986.uri.URIReference.query_is_valid
+
+.. automethod:: rfc3986.uri.URIReference.fragment_is_valid
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/docs/source/api-ref/validators.rst 
new/rfc3986-1.1.0/docs/source/api-ref/validators.rst
--- old/rfc3986-1.0.0/docs/source/api-ref/validators.rst        2017-05-10 
13:58:27.000000000 +0200
+++ new/rfc3986-1.1.0/docs/source/api-ref/validators.rst        2017-07-17 
23:55:18.000000000 +0200
@@ -12,6 +12,8 @@
 
 .. automethod:: rfc3986.validators.Validator.allow_use_of_password
 
+.. automethod:: rfc3986.validators.Validator.check_validity_of
+
 .. automethod:: rfc3986.validators.Validator.forbid_use_of_password
 
 .. automethod:: rfc3986.validators.Validator.require_presence_of
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/docs/source/conf.py 
new/rfc3986-1.1.0/docs/source/conf.py
--- old/rfc3986-1.0.0/docs/source/conf.py       2017-05-10 13:58:27.000000000 
+0200
+++ new/rfc3986-1.1.0/docs/source/conf.py       2017-05-10 14:06:41.000000000 
+0200
@@ -91,7 +91,7 @@
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
 #
-html_theme = 'alabaster'
+html_theme = 'sphinx_rtd_theme'
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/docs/source/release-notes/1.1.0.rst 
new/rfc3986-1.1.0/docs/source/release-notes/1.1.0.rst
--- old/rfc3986-1.0.0/docs/source/release-notes/1.1.0.rst       1970-01-01 
01:00:00.000000000 +0100
+++ new/rfc3986-1.1.0/docs/source/release-notes/1.1.0.rst       2017-07-18 
13:58:28.000000000 +0200
@@ -0,0 +1,15 @@
+1.1.0 -- 2017-07-18
+-------------------
+
+- Correct the regular expression for the User Information sub-component of the 
+  Authority Component.
+
+  See also `GitHub #26`_
+
+- :meth:`~rfc3986.validators.Validator.check_validity_of` to the
+  :class:`~rfc3986.validators.Validator` class. See
+  :ref:`Validating URIs <validating>` documentation for more information.
+
+.. links
+.. _GitHub #26:
+    https://github.com/sigmavirus24/rfc3986/pull/26
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/docs/source/release-notes/index.rst 
new/rfc3986-1.1.0/docs/source/release-notes/index.rst
--- old/rfc3986-1.0.0/docs/source/release-notes/index.rst       2017-05-10 
13:58:27.000000000 +0200
+++ new/rfc3986-1.1.0/docs/source/release-notes/index.rst       2017-07-18 
13:54:44.000000000 +0200
@@ -10,6 +10,7 @@
 
 .. toctree::
 
+    1.1.0
     1.0.0
 
 0.x Release Series
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/docs/source/user/validating.rst 
new/rfc3986-1.1.0/docs/source/user/validating.rst
--- old/rfc3986-1.0.0/docs/source/user/validating.rst   2017-05-10 
13:58:27.000000000 +0200
+++ new/rfc3986-1.1.0/docs/source/user/validating.rst   2017-07-18 
13:58:33.000000000 +0200
@@ -1,3 +1,5 @@
+.. _validating:
+
 =================
  Validating URIs
 =================
@@ -7,6 +9,7 @@
 sometimes overlap and othertimes they don't and it's not very convenient.
 Luckily, |rfc3986| makes validating URIs far simpler.
 
+
 Example Usage
 =============
 
@@ -14,7 +17,10 @@
 :class:`~rfc3986.validators.Validator` which takes no parameters. After that
 we can call methods on the instance to indicate what we want to validate.
 
-Let's assume that we're building something that takes user input for a URl and
+Allowing Only Trusted Domains and Schemes
+-----------------------------------------
+
+Let's assume that we're building something that takes user input for a URL and
 we want to ensure that URL is only ever using a specific domain with https. In
 that case, our code would look like this:
 
@@ -52,6 +58,9 @@
 fail the third. This is specifically because we only allow URLs using
 ``https`` as a scheme and ``github.com`` as the domain name.
 
+Preventing Leaks of User Credentials
+------------------------------------
+
 Next, let's imagine that we want to prevent leaking user credentials. In that
 case, we want to ensure that there is no password in the user information
 portion of the authority. In that case, our new validator would look like this:
@@ -87,6 +96,9 @@
     ...
     rfc3986.exceptions.PasswordForbidden
 
+Requiring the Presence of Components
+------------------------------------
+
 Up until now, we have assumed that we will get a URL that has the appropriate
 components for validation. For example, we assume that we will have a URL that
 has a scheme and hostname. However, our current validation doesn't require
@@ -134,7 +146,42 @@
     ...     'https://github.com/sigmavirus24/rfc3986'
     ... ))
 
-.. links
 
+Checking the Validity of Components
+-----------------------------------
+
+As of version 1.1.0, |rfc3986| allows users to check the validity of a URI
+Reference using a :class:`~rfc3986.validators.Validator`. Along with the above 
+examples we can also check that a URI is valid per :rfc:`3986`. The validation
+of the components is pre-determined so all we need to do is specify which 
+components we want to validate:
+
+.. doctest::
+
+    >>> from rfc3986 import validators, uri_reference
+    >>> valid_uri = uri_reference('https://github.com/')
+    >>> validator = validators.Validator().allow_schemes(
+    ...     'https',
+    ... ).allow_hosts(
+    ...     'github.com',
+    ... ).forbid_use_of_password(
+    ... ).require_presence_of(
+    ...     'scheme', 'host',
+    ... ).check_validity_of(
+    ...     'scheme', 'host', 'path',
+    ... )
+    >>> validator.validate(valid_uri)
+    >>> invalid_uri = valid_uri.copy_with(path='/#invalid/path')
+    >>> validator.validate(invalid_uri)
+    Traceback (most recent call last):
+    ...
+    rfc3986.exceptions.InvalidComponentsError
+
+Paths are not allowed to contain a ``#`` character unless it's
+percent-encoded. This is why our ``invalid_uri`` raises an exception when we
+attempt to validate it.
+
+
+.. links
 .. _validating an email address:
     
http://haacked.com/archive/2007/08/21/i-knew-how-to-validate-an-email-address-until-i.aspx/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/src/rfc3986/__init__.py 
new/rfc3986-1.1.0/src/rfc3986/__init__.py
--- old/rfc3986-1.0.0/src/rfc3986/__init__.py   2017-05-10 13:58:27.000000000 
+0200
+++ new/rfc3986-1.1.0/src/rfc3986/__init__.py   2017-07-18 14:16:53.000000000 
+0200
@@ -34,7 +34,7 @@
 __author_email__ = '[email protected]'
 __license__ = 'Apache v2.0'
 __copyright__ = 'Copyright 2014 Rackspace'
-__version__ = '1.0.0'
+__version__ = '1.1.0'
 
 __all__ = (
     'ParseResult',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/src/rfc3986/abnf_regexp.py 
new/rfc3986-1.1.0/src/rfc3986/abnf_regexp.py
--- old/rfc3986-1.0.0/src/rfc3986/abnf_regexp.py        2017-05-10 
13:58:27.000000000 +0200
+++ new/rfc3986-1.1.0/src/rfc3986/abnf_regexp.py        2017-07-17 
23:21:23.000000000 +0200
@@ -132,7 +132,9 @@
     IPv4_RE,
     IP_LITERAL_RE,
 )
-USERINFO_RE = '^[A-Za-z0-9_.~\-%:]+'
+USERINFO_RE = '^([' + UNRESERVED_RE + SUB_DELIMITERS_RE + ':]|%s)+' % (
+    PCT_ENCODED
+)
 PORT_RE = '[0-9]{1,5}'
 
 # ####################
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/src/rfc3986/exceptions.py 
new/rfc3986-1.1.0/src/rfc3986/exceptions.py
--- old/rfc3986-1.0.0/src/rfc3986/exceptions.py 2017-05-10 13:58:27.000000000 
+0200
+++ new/rfc3986-1.1.0/src/rfc3986/exceptions.py 2017-07-17 23:21:23.000000000 
+0200
@@ -90,3 +90,22 @@
             )
         )
         self.uri = uri
+
+
+class InvalidComponentsError(ValidationError):
+    """Exception raised when one or more components are invalid."""
+
+    def __init__(self, uri, *component_names):
+        """Initialize the error with the invalid component name(s)."""
+        verb = 'was'
+        if len(component_names) > 1:
+            verb = 'were'
+
+        self.uri = uri
+        self.components = sorted(component_names)
+        components = ', '.join(self.components)
+        super(InvalidComponentsError, self).__init__(
+            "{} {} found to be invalid".format(components, verb),
+            uri,
+            self.components,
+        )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/src/rfc3986/uri.py 
new/rfc3986-1.1.0/src/rfc3986/uri.py
--- old/rfc3986-1.0.0/src/rfc3986/uri.py        2017-05-10 13:58:27.000000000 
+0200
+++ new/rfc3986-1.1.0/src/rfc3986/uri.py        2017-07-18 13:36:32.000000000 
+0200
@@ -15,6 +15,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 from collections import namedtuple
+import warnings
 
 from . import compat
 from . import exceptions as exc
@@ -210,6 +211,10 @@
     def is_valid(self, **kwargs):
         """Determine if the URI is valid.
 
+        .. deprecated:: 1.1.0
+
+            Use the :class:`~rfc3986.validators.Validator` object instead.
+
         :param bool require_scheme: Set to ``True`` if you wish to require the
             presence of the scheme component.
         :param bool require_authority: Set to ``True`` if you wish to require
@@ -223,6 +228,9 @@
         :returns: ``True`` if the URI is valid. ``False`` otherwise.
         :rtype: bool
         """
+        warnings.warn("Please use rfc3986.validators.Validator instead. "
+                      "This method will be eventually removed.",
+                      DeprecationWarning)
         validators = [
             (self.scheme_is_valid, kwargs.get('require_scheme', False)),
             (self.authority_is_valid, kwargs.get('require_authority', False)),
@@ -235,6 +243,10 @@
     def authority_is_valid(self, require=False):
         """Determine if the authority component is valid.
 
+        .. deprecated:: 1.1.0
+
+            Use the :class:`~rfc3986.validators.Validator` object instead.
+
         :param bool require:
             Set to ``True`` to require the presence of this component.
         :returns:
@@ -242,6 +254,9 @@
         :rtype:
             bool
         """
+        warnings.warn("Please use rfc3986.validators.Validator instead. "
+                      "This method will be eventually removed.",
+                      DeprecationWarning)
         try:
             self.authority_info()
         except exc.InvalidAuthority:
@@ -256,41 +271,69 @@
     def scheme_is_valid(self, require=False):
         """Determine if the scheme component is valid.
 
+        .. deprecated:: 1.1.0
+
+            Use the :class:`~rfc3986.validators.Validator` object instead.
+
         :param str require: Set to ``True`` to require the presence of this
             component.
         :returns: ``True`` if the scheme is valid. ``False`` otherwise.
         :rtype: bool
         """
+        warnings.warn("Please use rfc3986.validators.Validator instead. "
+                      "This method will be eventually removed.",
+                      DeprecationWarning)
         return validators.scheme_is_valid(self.scheme, require)
 
     def path_is_valid(self, require=False):
         """Determine if the path component is valid.
 
+        .. deprecated:: 1.1.0
+
+            Use the :class:`~rfc3986.validators.Validator` object instead.
+
         :param str require: Set to ``True`` to require the presence of this
             component.
         :returns: ``True`` if the path is valid. ``False`` otherwise.
         :rtype: bool
         """
+        warnings.warn("Please use rfc3986.validators.Validator instead. "
+                      "This method will be eventually removed.",
+                      DeprecationWarning)
         return validators.path_is_valid(self.path, require)
 
     def query_is_valid(self, require=False):
         """Determine if the query component is valid.
 
+        .. deprecated:: 1.1.0
+
+            Use the :class:`~rfc3986.validators.Validator` object instead.
+
         :param str require: Set to ``True`` to require the presence of this
             component.
         :returns: ``True`` if the query is valid. ``False`` otherwise.
         :rtype: bool
         """
+        warnings.warn("Please use rfc3986.validators.Validator instead. "
+                      "This method will be eventually removed.",
+                      DeprecationWarning)
         return validators.query_is_valid(self.query, require)
 
     def fragment_is_valid(self, require=False):
         """Determine if the fragment component is valid.
 
+        .. deprecated:: 1.1.0
+
+            Use the Validator object instead.
+
         :param str require: Set to ``True`` to require the presence of this
             component.
         :returns: ``True`` if the fragment is valid. ``False`` otherwise.
         :rtype: bool
         """
+        warnings.warn("Please use rfc3986.validators.Validator instead. "
+                      "This method will be eventually removed.",
+                      DeprecationWarning)
         return validators.fragment_is_valid(self.fragment, require)
 
     def normalize(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/src/rfc3986/validators.py 
new/rfc3986-1.1.0/src/rfc3986/validators.py
--- old/rfc3986-1.0.0/src/rfc3986/validators.py 2017-05-10 13:58:27.000000000 
+0200
+++ new/rfc3986-1.1.0/src/rfc3986/validators.py 2017-07-17 23:21:23.000000000 
+0200
@@ -21,6 +21,8 @@
 class Validator(object):
     """Object used to configure validation of all objects in rfc3986.
 
+    .. versionadded:: 1.0
+
     Example usage::
 
          >>> from rfc3986 import api, validators
@@ -68,10 +70,13 @@
             'query': False,
             'fragment': False,
         }
+        self.validated_components = self.required_components.copy()
 
     def allow_schemes(self, *schemes):
         """Require the scheme to be one of the provided schemes.
 
+        .. versionadded:: 1.0
+
         :param schemes:
             Schemes, without ``://`` that are allowed.
         :returns:
@@ -86,6 +91,8 @@
     def allow_hosts(self, *hosts):
         """Require the host to be one of the provided hosts.
 
+        .. versionadded:: 1.0
+
         :param hosts:
             Hosts that are allowed.
         :returns:
@@ -100,6 +107,8 @@
     def allow_ports(self, *ports):
         """Require the port to be one of the provided ports.
 
+        .. versionadded:: 1.0
+
         :param ports:
             Ports that are allowed.
         :returns:
@@ -114,18 +123,63 @@
         return self
 
     def allow_use_of_password(self):
-        """Allow passwords to be present in the URI."""
+        """Allow passwords to be present in the URI.
+
+        .. versionadded:: 1.0
+
+        :returns:
+            The validator instance.
+        :rtype:
+            Validator
+        """
         self.allow_password = True
         return self
 
     def forbid_use_of_password(self):
-        """Prevent passwords from being included in the URI."""
+        """Prevent passwords from being included in the URI.
+
+        .. versionadded:: 1.0
+
+        :returns:
+            The validator instance.
+        :rtype:
+            Validator
+        """
         self.allow_password = False
         return self
 
+    def check_validity_of(self, *components):
+        """Check the validity of the components provided.
+
+        This can be specified repeatedly.
+
+        .. versionadded:: 1.1
+
+        :param components:
+            Names of components from :attr:`Validator.COMPONENT_NAMES`.
+        :returns:
+            The validator instance.
+        :rtype:
+            Validator
+        """
+        components = [c.lower() for c in components]
+        for component in components:
+            if component not in self.COMPONENT_NAMES:
+                raise ValueError(
+                    '"{}" is not a valid component'.format(component)
+                )
+        self.validated_components.update({
+            component: True for component in components
+        })
+        return self
+
     def require_presence_of(self, *components):
         """Require the components provided.
 
+        This can be specified repeatedly.
+
+        .. versionadded:: 1.0
+
         :param components:
             Names of components from :attr:`Validator.COMPONENT_NAMES`.
         :returns:
@@ -147,6 +201,8 @@
     def validate(self, uri):
         """Check a URI for conditions specified on this validator.
 
+        .. versionadded:: 1.0
+
         :param uri:
             Parsed URI to validate.
         :type uri:
@@ -158,6 +214,8 @@
         :raises PasswordForbidden:
             When a password is present in the userinfo component but is
             not permitted by configuration.
+        :raises InvalidComponentsError:
+            When a component was found to be invalid.
         """
         if not self.allow_password:
             check_password(uri)
@@ -167,8 +225,15 @@
             for component, required in self.required_components.items()
             if required
         ]
+        validated_components = [
+            component
+            for component, required in self.validated_components.items()
+            if required
+        ]
         if required_components:
             ensure_required_components_exist(uri, required_components)
+        if validated_components:
+            ensure_components_are_valid(uri, validated_components)
 
         ensure_one_of(self.allowed_schemes, uri, 'scheme')
         ensure_one_of(self.allowed_hosts, uri, 'host')
@@ -309,3 +374,55 @@
     # If the host exists, and it might be IPv4, check each byte in the
     # address.
     return all([0 <= int(byte, base=10) <= 255 for byte in host.split('.')])
+
+
+_COMPONENT_VALIDATORS = {
+    'scheme': scheme_is_valid,
+    'path': path_is_valid,
+    'query': query_is_valid,
+    'fragment': fragment_is_valid,
+}
+
+_SUBAUTHORITY_VALIDATORS = set(['userinfo', 'host', 'port'])
+
+
+def subauthority_component_is_valid(uri, component):
+    """Determine if the userinfo, host, and port are valid."""
+    try:
+        subauthority_dict = uri.authority_info()
+    except exceptions.InvalidAuthority:
+        return False
+
+    # If we can parse the authority into sub-components and we're not
+    # validating the port, we can assume it's valid.
+    if component != 'port':
+        return True
+
+    try:
+        port = int(subauthority_dict['port'])
+    except TypeError:
+        # If the port wasn't provided it'll be None and int(None) raises a
+        # TypeError
+        return True
+
+    return (0 <= port <= 65535)
+
+
+def ensure_components_are_valid(uri, validated_components):
+    """Assert that all components are valid in the URI."""
+    invalid_components = set([])
+    for component in validated_components:
+        if component in _SUBAUTHORITY_VALIDATORS:
+            if not subauthority_component_is_valid(uri, component):
+                invalid_components.add(component)
+            # Python's peephole optimizer means that while this continue *is*
+            # actually executed, coverage.py cannot detect that. See also,
+            # 
https://bitbucket.org/ned/coveragepy/issues/198/continue-marked-as-not-covered
+            continue  # nocov: Python 2.7, 3.3, 3.4
+
+        validator = _COMPONENT_VALIDATORS[component]
+        if not validator(getattr(uri, component)):
+            invalid_components.add(component)
+
+    if invalid_components:
+        raise exceptions.InvalidComponentsError(uri, *invalid_components)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/src/rfc3986.egg-info/PKG-INFO 
new/rfc3986-1.1.0/src/rfc3986.egg-info/PKG-INFO
--- old/rfc3986-1.0.0/src/rfc3986.egg-info/PKG-INFO     2017-05-10 
13:59:35.000000000 +0200
+++ new/rfc3986-1.1.0/src/rfc3986.egg-info/PKG-INFO     2017-07-18 
14:18:10.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: rfc3986
-Version: 1.0.0
+Version: 1.1.0
 Summary: Validating URI References per RFC 3986
 Home-page: http://rfc3986.readthedocs.io
 Author: Ian Cordasco
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/src/rfc3986.egg-info/SOURCES.txt 
new/rfc3986-1.1.0/src/rfc3986.egg-info/SOURCES.txt
--- old/rfc3986-1.0.0/src/rfc3986.egg-info/SOURCES.txt  2017-05-10 
13:59:35.000000000 +0200
+++ new/rfc3986-1.1.0/src/rfc3986.egg-info/SOURCES.txt  2017-07-18 
14:18:10.000000000 +0200
@@ -23,6 +23,7 @@
 docs/source/release-notes/0.4.1.rst
 docs/source/release-notes/0.4.2.rst
 docs/source/release-notes/1.0.0.rst
+docs/source/release-notes/1.1.0.rst
 docs/source/release-notes/index.rst
 docs/source/user/building.rst
 docs/source/user/parsing.rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/tests/base.py 
new/rfc3986-1.1.0/tests/base.py
--- old/rfc3986-1.0.0/tests/base.py     2017-01-19 15:23:04.000000000 +0100
+++ new/rfc3986-1.1.0/tests/base.py     2017-07-17 23:21:23.000000000 +0200
@@ -58,6 +58,23 @@
         assert uri.fragment is None
         assert uri.userinfo == 'user:pass'
 
+    def test_handles_tricky_userinfo(
+            self, uri_with_port_and_tricky_userinfo):
+        """
+        Test that self.test_class can handle a URI with unusual
+        (non a-z) chars in userinfo.
+        """
+        uri = self.test_class.from_string(uri_with_port_and_tricky_userinfo)
+        assert uri.scheme == 'ssh'
+        # 6 == len('ftp://')
+        assert uri.authority == uri_with_port_and_tricky_userinfo[6:]
+        assert uri.host != uri.authority
+        assert str(uri.port) == '22'
+        assert uri.path is None
+        assert uri.query is None
+        assert uri.fragment is None
+        assert uri.userinfo == 'user%20!=:pass'
+
     def test_handles_basic_uri_with_path(self, basic_uri_with_path):
         """Test that self.test_class can handle a URI with a path."""
         uri = self.test_class.from_string(basic_uri_with_path)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/tests/conftest.py 
new/rfc3986-1.1.0/tests/conftest.py
--- old/rfc3986-1.0.0/tests/conftest.py 2017-05-10 13:58:27.000000000 +0200
+++ new/rfc3986-1.1.0/tests/conftest.py 2017-07-17 23:21:23.000000000 +0200
@@ -81,6 +81,11 @@
 
 
 @pytest.fixture(params=valid_hosts)
+def uri_with_port_and_tricky_userinfo(request):
+    return 'ssh://%s@%s:22' % ('user%20!=:pass', request.param)
+
+
[email protected](params=valid_hosts)
 def basic_uri_with_path(request):
     return 'http://%s/path/to/resource' % request.param
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rfc3986-1.0.0/tests/test_validators.py 
new/rfc3986-1.1.0/tests/test_validators.py
--- old/rfc3986-1.0.0/tests/test_validators.py  2017-05-10 13:58:27.000000000 
+0200
+++ new/rfc3986-1.1.0/tests/test_validators.py  2017-07-17 23:21:23.000000000 
+0200
@@ -52,6 +52,12 @@
         validators.Validator().require_presence_of('frob')
 
 
+def test_checking_validity_of_component():
+    """Verify that we validate components we're validating."""
+    with pytest.raises(ValueError):
+        validators.Validator().check_validity_of('frob')
+
+
 def test_use_of_password():
     """Verify the behaviour of {forbid,allow}_use_of_password."""
     validator = validators.Validator()
@@ -182,6 +188,22 @@
     rfc3986.uri_reference('ssh://git.openstack.org/sigmavirus24'),
     rfc3986.uri_reference('ssh://[email protected]:22/sigmavirus24'),
     rfc3986.uri_reference('https://git.openstack.org:443/sigmavirus24'),
+    rfc3986.uri_reference(
+        'ssh://[email protected]:22/sigmavirus24?foo=bar#fragment'
+    ),
+    rfc3986.uri_reference(
+        'ssh://git.openstack.org:22/sigmavirus24?foo=bar#fragment'
+    ),
+    rfc3986.uri_reference('ssh://git.openstack.org:22/?foo=bar#fragment'),
+    rfc3986.uri_reference('ssh://git.openstack.org:22/sigmavirus24#fragment'),
+    rfc3986.uri_reference('ssh://git.openstack.org:22/#fragment'),
+    rfc3986.uri_reference('ssh://git.openstack.org:22/'),
+    rfc3986.uri_reference('ssh://[email protected]:22/?foo=bar#fragment'),
+    rfc3986.uri_reference(
+        'ssh://[email protected]:22/sigmavirus24#fragment'
+    ),
+    rfc3986.uri_reference('ssh://[email protected]:22/#fragment'),
+    rfc3986.uri_reference('ssh://[email protected]:22/'),
 ])
 def test_successful_complex_validation(uri):
     """Verify we do not raise ValidationErrors for good URIs."""
@@ -193,4 +215,23 @@
         '22', '443',
     ).require_presence_of(
         'scheme', 'host', 'path',
+    ).check_validity_of(
+        'scheme', 'userinfo', 'host', 'port', 'path', 'query', 'fragment',
     ).validate(uri)
+
+
+def test_invalid_uri_generates_error(invalid_uri):
+    """Verify we catch invalid URIs."""
+    uri = rfc3986.uri_reference(invalid_uri)
+    with pytest.raises(exceptions.InvalidComponentsError):
+        validators.Validator().check_validity_of('host').validate(uri)
+
+
+def test_invalid_uri_with_invalid_path(invalid_uri):
+    """Verify we catch multiple invalid components."""
+    uri = rfc3986.uri_reference(invalid_uri)
+    uri = uri.copy_with(path='#foobar')
+    with pytest.raises(exceptions.InvalidComponentsError):
+        validators.Validator().check_validity_of(
+            'host', 'path',
+        ).validate(uri)


Reply via email to