Hello community,

here is the log from the commit of package python-furl for openSUSE:Leap:15.2 
checked in at 2020-03-16 12:21:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Leap:15.2/python-furl (Old)
 and      /work/SRC/openSUSE:Leap:15.2/.python-furl.new.3160 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-furl"

Mon Mar 16 12:21:00 2020 rev:2 rq:782048 version:2.1.0

Changes:
--------
--- /work/SRC/openSUSE:Leap:15.2/python-furl/python-furl.changes        
2020-02-22 18:50:34.760493588 +0100
+++ /work/SRC/openSUSE:Leap:15.2/.python-furl.new.3160/python-furl.changes      
2020-03-16 12:21:01.431708180 +0100
@@ -1,0 +2,20 @@
+Thu Mar  5 12:33:35 UTC 2020 - [email protected]
+
+- version update to 2.1.0
+    Added: a dont_quote= parameter to Query.encode() and a
+    query_dont_quote= parameter to furl.tostr() that exempt valid query
+    characters from being percent-encoded, either in their entirety with
+    dont_quote=True, or selectively with dont_quote=<string>, like
+    dont_quote='/?@_'.
+
+    Changed: Move package info from __init__.py into the more standard
+    __version__.py.
+
+    Fixed: Support Unicode usernames and passwords in Python 2.
+
+    Fixed: Update orderedmultdict to v1.0.1 to resolve a DeprecationWarning.
+
+    Fixed: Encode '/' consistently in query strings across both
+    quote_plus=True and quote_plus=False.
+
+-------------------------------------------------------------------

Old:
----
  furl-2.0.0.tar.gz

New:
----
  furl-2.1.0.tar.gz

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

Other differences:
------------------
++++++ python-furl.spec ++++++
--- /var/tmp/diff_new_pack.EQTc88/_old  2020-03-16 12:21:01.691708223 +0100
+++ /var/tmp/diff_new_pack.EQTc88/_new  2020-03-16 12:21:01.695708223 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-furl
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-furl
-Version:        2.0.0
+Version:        2.1.0
 Release:        0
 Summary:        A Python URL manipulation library
 License:        Unlicense

++++++ furl-2.0.0.tar.gz -> furl-2.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/furl-2.0.0/API.md new/furl-2.1.0/API.md
--- old/furl-2.0.0/API.md       2018-09-26 03:53:12.000000000 +0200
+++ new/furl-2.1.0/API.md       2019-05-26 23:41:16.000000000 +0200
@@ -198,6 +198,7 @@
 
 ```python
 >>> from __future__ import division  # For Python 2.x.
+>>>
 >>> f = furl('path')
 >>> f.path /= 'with'
 >>> f.path = f.path / 'more' / 'path segments/'
@@ -326,11 +327,11 @@
 'http://sprop.su/?param'
 ```
 
-__encode(delimiter='&', quote_plus=True)__ can be used to encode query strings
-with delimiters like `;` and encode key-value pairs with standard
-percent-encoding (i.e. `%20` not `+`). The default delimiter is `&` and the
-default key-value encoding is application/x-www-form-urlencoded (i.e. `+` not
-`%20`).
+__encode(delimiter='&', quote_plus=True, dont_quote='')__ can be used to encode
+query strings with delimiters like `;`, encode spaces as `+` instead of `%20`
+(i.e. application/x-www-form-urlencoded encoded), or avoid percent-encoding
+valid query charactes entirely (valid query characters are
+`/?:@-._~!$&'()*+,;=`).
 
 ```python
 >>> f.query = 'space=jams&woofs=squeeze+dog'
@@ -342,6 +343,20 @@
 'space=jams&woofs=squeeze%20dog'
 ```
 
+`dont_quote` accepts `True`, `False`, or a string of valid query characters to
+not percent-enode. If `True`, all valid query characters `/?:@-._~!$&'()*+,;=`
+aren't percent-encoded.
+
+```python
+>>> f.query = 'one,two/three'
+>>> f.query.encode()
+'one%2Ctwo%2Fthree'
+>>> f.query.encode(dont_quote=True)
+'one,two/three'
+>>> f.query.encode(dont_quote=',')
+'one,two%2Fthree'
+```
+
 For a dictionary representation of a query, use __asdict()__.
 
 ```python
@@ -592,16 +607,19 @@
 'http://www.google.com/path/add/seg%20ments/?example=arg#frag'
 ```
 
-__tostr(query_delimiter='&', query_quote_plus=True)__ creates and returns a URL
-string. `query_delimiter` and `query_quote_plus` are passed unmodified to
-`Query.encode()`.
+__tostr(query_delimiter='&', query_quote_plus=True, query_dont_quote='')__
+creates and returns a URL string. `query_delimiter`, `query_quote_plus`, and
+`query_dont_quote` are passed unmodified to `Query.encode()` as `delimiter`,
+`quote_plus`, and `dont_quote` respectively.
 
 ```python
 >>> f = furl('http://spep.ru/?a+b=c+d&two%20tap=cat%20nap%24')
 >>> f.tostr()
 'http://spep.ru/?a+b=c+d&two+tap=cat+nap$'
->> f.tostr(query_delimiter=';', query_quote_plus=False)
+>>> f.tostr(query_delimiter=';', query_quote_plus=False)
 'http://spep.ru/?a%20b=c%20d;two%20tap=cat%20nap$'
+>>> f.tostr(query_dont_quote='$')
+'http://spep.ru/?a+b=c+d&two+tap=cat+nap$'
 ```
 
 `furl.url` is a shortcut for `furl.tostr()`.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/furl-2.0.0/PKG-INFO new/furl-2.1.0/PKG-INFO
--- old/furl-2.0.0/PKG-INFO     2018-10-02 23:55:01.000000000 +0200
+++ new/furl-2.1.0/PKG-INFO     2019-09-20 22:58:29.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: furl
-Version: 2.0.0
+Version: 2.1.0
 Summary: URL manipulation made simple.
 Home-page: https://github.com/gruns/furl
 Author: Ansgar Grunseid
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/furl-2.0.0/README.md new/furl-2.1.0/README.md
--- old/furl-2.0.0/README.md    2018-09-29 06:46:48.000000000 +0200
+++ new/furl-2.1.0/README.md    2019-05-26 23:45:22.000000000 +0200
@@ -23,15 +23,16 @@
 and supports\
 Python 2, Python 3, PyPy2, and PyPy3.
 
-Code time: Query arguments are easy. Really easy.
+Code time: Paths and query arguments are easy. Really easy.
 
 ```python
 >>> from furl import furl
 >>> f = furl('http://www.google.com/?one=1&two=2')
+>>> f /= 'path'
 >>> f.args['three'] = '3'
 >>> del f.args['one']
 >>> f.url
-'http://www.google.com/?two=2&three=3'
+'http://www.google.com/path?two=2&three=3'
 ```
 
 Or use furl's inline modification methods.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/furl-2.0.0/furl/__init__.py 
new/furl-2.1.0/furl/__init__.py
--- old/furl-2.0.0/furl/__init__.py     2018-10-02 00:34:01.000000000 +0200
+++ new/furl-2.1.0/furl/__init__.py     2018-12-06 00:12:55.000000000 +0100
@@ -11,10 +11,3 @@
 #
 
 from .furl import *  # noqa
-
-__title__ = 'furl'
-__version__ = '2.0.0'
-__license__ = 'Unlicense'
-__author__ = 'Ansgar Grunseid'
-__contact__ = '[email protected]'
-__url__ = 'https://github.com/gruns/furl'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/furl-2.0.0/furl/__version__.py 
new/furl-2.1.0/furl/__version__.py
--- old/furl-2.0.0/furl/__version__.py  1970-01-01 01:00:00.000000000 +0100
+++ new/furl-2.1.0/furl/__version__.py  2019-09-20 22:51:26.000000000 +0200
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+
+#
+# furl - URL manipulation made simple.
+#
+# Ansgar Grunseid
+# grunseid.com
+# [email protected]
+#
+# License: Build Amazing Things (Unlicense)
+#
+
+__title__ = 'furl'
+__version__ = '2.1.0'
+__license__ = 'Unlicense'
+__author__ = 'Ansgar Grunseid'
+__contact__ = '[email protected]'
+__url__ = 'https://github.com/gruns/furl'
+__description__ = 'URL manipulation made simple.'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/furl-2.0.0/furl/furl.py new/furl-2.1.0/furl/furl.py
--- old/furl-2.0.0/furl/furl.py 2018-09-30 08:54:35.000000000 +0200
+++ new/furl-2.1.0/furl/furl.py 2019-04-26 08:14:17.000000000 +0200
@@ -114,6 +114,27 @@
     return decorator
 
 
+def create_quote_fn(safe_charset, quote_plus):
+    def quote_fn(s, dont_quote):
+        if dont_quote is True:
+            safe = safe_charset
+        elif dont_quote is False:
+            safe = ''
+        else:  # <dont_quote> is expected to be a string.
+            safe = dont_quote
+
+        # Prune duplicates and characters not in <safe_charset>.
+        safe = ''.join(set(safe) & set(safe_charset))  # E.g. '?^#?' -> '?'.
+
+        quoted = quote(s, safe)
+        if quote_plus:
+            quoted = quoted.replace('%20', '+')
+
+        return quoted
+
+    return quote_fn
+
+
 #
 # TODO(grun): Update some of the regex functions below to reflect the fact that
 # the valid encoding of Path segments differs slightly from the valid encoding
@@ -430,13 +451,12 @@
         take such strings, like load(), add(), set(), remove(), etc.
     """
 
-    # RFC 3986:
-    #
-    # segment       = *pchar
-    # pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
-    # unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
-    # sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
-    #                     / "*" / "+" / "," / ";" / "="
+    # From RFC 3986:
+    #   segment       = *pchar
+    #   pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
+    #   unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
+    #   sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
+    #                       / "*" / "+" / "," / ";" / "="
     SAFE_SEGMENT_CHARS = ":@-._~!$&'()*+,;="
 
     def __init__(self, path='', force_absolute=lambda _: False, strict=False):
@@ -846,6 +866,15 @@
         take such strings, like load(), add(), set(), remove(), etc.
     """
 
+    # From RFC 3986:
+    #   query       = *( pchar / "/" / "?" )
+    #   pchar       = unreserved / pct-encoded / sub-delims / ":" / "@"
+    #   unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+    #   sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
+    #                     / "*" / "+" / "," / ";" / "="
+    SAFE_KEY_CHARS = "/?:@-._~!$'()*+,;"
+    SAFE_VALUE_CHARS = SAFE_KEY_CHARS + '='
+
     def __init__(self, query='', strict=False):
         self.strict = strict
 
@@ -918,42 +947,59 @@
         for key, value in items:
             self._params.add(key, value)
 
-    def encode(self, delimiter='&', quote_plus=True, delimeter=_absent):
+    def encode(self, delimiter='&', quote_plus=True, dont_quote='',
+               delimeter=_absent):
         """
         Examples:
+
           Query('a=a&b=#').encode() == 'a=a&b=%23'
           Query('a=a&b=#').encode(';') == 'a=a;b=%23'
-          Query('a+b=c+d').encode(quote_plus=False) == 'a%20b=c%20d'
+          Query('a+b=c@d').encode(dont_quote='@') == 'a+b=c@d'
+          Query('a+b=c@d').encode(quote_plus=False) == 'a%20b=c%40d'
 
         Until furl v0.4.6, the 'delimiter' argument was incorrectly
         spelled 'delimeter'. For backwards compatibility, accept both
         the correct 'delimiter' and the old, mispelled 'delimeter'.
 
+        Keys and values are encoded application/x-www-form-urlencoded if
+        <quote_plus> is True, percent-encoded otherwise.
+
+        <dont_quote> exempts valid query characters from being
+        percent-encoded, either in their entirety with dont_quote=True,
+        or selectively with dont_quote=<string>, like
+        dont_quote='/?@_'. Invalid query characters -- those not in
+        self.SAFE_KEY_CHARS, like '#' and '^' -- are always encoded,
+        even if included in <dont_quote>. For example:
+
+          Query('#=^').encode(dont_quote='#^') == '%23=%5E'.
+
+
         Returns: A URL encoded query string using <delimiter> as the
         delimiter separating key:value pairs. The most common and
         default delimiter is '&', but ';' can also be specified. ';' is
-        W3C recommended. Parameter keys and values are encoded
-        application/x-www-form-urlencoded if <quote_plus> is True,
-        percent-encoded otherwise.
+        W3C recommended.
         """
         if delimeter is not _absent:
             delimiter = delimeter
 
+        quote_key = create_quote_fn(self.SAFE_KEY_CHARS, quote_plus)
+        quote_value = create_quote_fn(self.SAFE_VALUE_CHARS, quote_plus)
+
         pairs = []
-        sixurl = urllib.parse  # six.moves.urllib.parse
-        quote_fn = sixurl.quote_plus if quote_plus else sixurl.quote
         for key, value in self.params.iterallitems():
             utf8key = utf8(key, utf8(attemptstr(key)))
-            utf8value = utf8(value, utf8(attemptstr(value)))
-
-            quoted_key = quote_fn(utf8key)
-            safe_value_chars = '=' if not quoted_key else ''
-            quoted_value = quote_fn(utf8value, safe_value_chars)
+            quoted_key = quote_key(utf8key, dont_quote)
 
-            if value is None:  # Example: http://sprop.su/?param.
+            if value is None:  # Example: http://sprop.su/?key.
                 pair = quoted_key
-            else:
-                pair = '='.join([quoted_key, quoted_value])
+            else:  # Example: http://sprop.su/?key=value.
+                utf8value = utf8(value, utf8(attemptstr(value)))
+                quoted_value = quote_value(utf8value, dont_quote)
+
+                if not quoted_key:  # Unquote '=' to allow queries like '?==='.
+                    quoted_value = quoted_value.replace('%3D', '=')
+
+                pair = '%s=%s' % (quoted_key, quoted_value)
 
             pairs.append(pair)
 
@@ -1300,15 +1346,15 @@
                  query=_absent, query_params=_absent, username=_absent,
                  password=_absent, strict=False):
         """
-        Raises: ValueError on invalid url.
+        Raises: ValueError on invalid URL or invalid URL component(s) provided.
         """
         URLPathCompositionInterface.__init__(self, strict=strict)
         QueryCompositionInterface.__init__(self, strict=strict)
         FragmentCompositionInterface.__init__(self, strict=strict)
         self.strict = strict
 
-        self.load(url)  # Raises ValueError on invalid url.
-        self.set(
+        self.load(url)  # Raises ValueError on invalid URL.
+        self.set(  # Raises ValueError on invalid URL component(s).
             args=args, path=path, fragment=fragment, scheme=scheme,
             netloc=netloc, origin=origin, fragment_path=fragment_path,
             fragment_args=fragment_args, fragment_separator=fragment_separator,
@@ -1406,9 +1452,9 @@
 
     @property
     def netloc(self):
-        userpass = quote(self.username or '', safe='')
+        userpass = quote(utf8(self.username) or '', safe='')
         if self.password is not None:
-            userpass += ':' + quote(self.password, safe='')
+            userpass += ':' + quote(utf8(self.password), safe='')
         if userpass or self.username is not None:
             userpass += '@'
 
@@ -1551,7 +1597,8 @@
             fragment_args=_absent, fragment_separator=_absent, host=_absent,
             port=_absent, query=_absent, query_params=_absent,
             username=_absent, password=_absent):
-        """Set components of a url and return this furl instance, <self>.
+        """
+        Set components of a url and return this furl instance, <self>.
 
         If any overlapping, and hence possibly conflicting, parameters
         are provided, appropriate UserWarning's will be raised. The
@@ -1734,12 +1781,15 @@
 
         return self
 
-    def tostr(self, query_delimiter='&', query_quote_plus=True):
+    def tostr(self, query_delimiter='&', query_quote_plus=True,
+              query_dont_quote=''):
+        encoded_query = self.query.encode(
+            query_delimiter, query_quote_plus, query_dont_quote)
         url = urllib.parse.urlunsplit((
             self.scheme or '',  # Must be text type in Python 3.
             self.netloc,
             str(self.path),
-            self.query.encode(query_delimiter, query_quote_plus),
+            encoded_query,
             str(self.fragment),
         ))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/furl-2.0.0/furl.egg-info/PKG-INFO 
new/furl-2.1.0/furl.egg-info/PKG-INFO
--- old/furl-2.0.0/furl.egg-info/PKG-INFO       2018-10-02 23:55:01.000000000 
+0200
+++ new/furl-2.1.0/furl.egg-info/PKG-INFO       2019-09-20 22:58:29.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: furl
-Version: 2.0.0
+Version: 2.1.0
 Summary: URL manipulation made simple.
 Home-page: https://github.com/gruns/furl
 Author: Ansgar Grunseid
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/furl-2.0.0/furl.egg-info/SOURCES.txt 
new/furl-2.1.0/furl.egg-info/SOURCES.txt
--- old/furl-2.0.0/furl.egg-info/SOURCES.txt    2018-10-02 23:55:01.000000000 
+0200
+++ new/furl-2.1.0/furl.egg-info/SOURCES.txt    2019-09-20 22:58:29.000000000 
+0200
@@ -5,6 +5,7 @@
 setup.cfg
 setup.py
 furl/__init__.py
+furl/__version__.py
 furl/common.py
 furl/compat.py
 furl/furl.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/furl-2.0.0/furl.egg-info/requires.txt 
new/furl-2.1.0/furl.egg-info/requires.txt
--- old/furl-2.0.0/furl.egg-info/requires.txt   2018-10-02 23:55:01.000000000 
+0200
+++ new/furl-2.1.0/furl.egg-info/requires.txt   2019-09-20 22:58:29.000000000 
+0200
@@ -1,2 +1,2 @@
 six>=1.8.0
-orderedmultidict>=1.0
+orderedmultidict>=1.0.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/furl-2.0.0/setup.py new/furl-2.1.0/setup.py
--- old/furl-2.0.0/setup.py     2018-09-11 08:02:01.000000000 +0200
+++ new/furl-2.1.0/setup.py     2019-09-20 22:48:05.000000000 +0200
@@ -12,16 +12,15 @@
 #
 
 import os
-import re
 import sys
 from os.path import dirname, join as pjoin
 from setuptools import setup, find_packages, Command
 from setuptools.command.test import test as TestCommand
 
 
-with open(pjoin(dirname(__file__), 'furl', '__init__.py')) as fo:
-    regex = r".*__version__ = '(.*?)'"
-    VERSION = re.compile(regex, re.S).match(fo.read()).group(1)
+meta = {}
+with open(pjoin('furl', '__version__.py')) as f:
+    exec(f.read(), meta)
 
 
 class Publish(Command):
@@ -37,8 +36,8 @@
     def run(self):
         os.system('python setup.py sdist bdist_wheel')
 
-        sdist = 'dist/furl-%s.tar.gz' % VERSION
-        wheel = 'dist/furl-%s-py2.py3-none-any.whl' % VERSION
+        sdist = 'dist/furl-%s.tar.gz' % meta['__version__']
+        wheel = 'dist/furl-%s-py2.py3-none-any.whl' % meta['__version__']
         rc = os.system('twine upload "%s" "%s"' % (sdist, wheel))
 
         sys.exit(rc)
@@ -49,9 +48,9 @@
     Run the unit tests.
 
     By default, `python setup.py test` fails if tests/ isn't a Python
-    module (that is, if the tests/ directory doesn't contain an
-    __init__.py file). But the tests/ directory shouldn't contain an
-    __init__.py file and tests/ shouldn't be a Python module. See
+    module; i.e. if the tests/ directory doesn't contain an __init__.py
+    file). But the tests/ directory shouldn't contain an __init__.py
+    file and tests/ shouldn't be a Python module. See
 
       http://doc.pytest.org/en/latest/goodpractices.html
 
@@ -60,20 +59,20 @@
     """
     def run_tests(self):
         from unittest import TestLoader, TextTestRunner
-        tests_dir = pjoin(dirname(__file__), 'tests')
+        tests_dir = pjoin(dirname(__file__), 'tests/')
         suite = TestLoader().discover(tests_dir)
         result = TextTestRunner().run(suite)
         sys.exit(0 if result.wasSuccessful() else -1)
 
 
 setup(
-    name='furl',
-    version=VERSION,
-    author='Ansgar Grunseid',
-    author_email='[email protected]',
-    url='https://github.com/gruns/furl',
-    license='Unlicense',
-    description='URL manipulation made simple.',
+    name=meta['__title__'],
+    license=meta['__license__'],
+    version=meta['__version__'],
+    author=meta['__author__'],
+    author_email=meta['__contact__'],
+    url=meta['__url__'],
+    description=meta['__description__'],
     long_description=(
         'Information and documentation can be found at '
         'https://github.com/gruns/furl.'),
@@ -97,13 +96,16 @@
         'Programming Language :: Python :: Implementation :: PyPy',
         'Programming Language :: Python :: Implementation :: CPython',
     ],
+    tests_require=[
+        'flake8',
+        'six>=1.8.0',
+    ],
     install_requires=[
         'six>=1.8.0',
-        'orderedmultidict>=1.0',
+        'orderedmultidict>=1.0.1',
     ],
     cmdclass={
         'test': RunTests,
         'publish': Publish,
     },
-    tests_require=['flake8', 'six>=1.8.0'],
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/furl-2.0.0/tests/test_furl.py 
new/furl-2.1.0/tests/test_furl.py
--- old/furl-2.0.0/tests/test_furl.py   2018-10-02 00:51:06.000000000 +0200
+++ new/furl-2.1.0/tests/test_furl.py   2019-02-06 23:19:04.000000000 +0100
@@ -834,6 +834,19 @@
         assert query.encode(';') == 'a=b+c;d=e+f'
         assert query.encode(';', quote_plus=False) == 'a=b%20c;d=e%20f'
 
+        # Encode '/' consistently across quote_plus=True and quote_plus=False.
+        query = furl.Query('a /b')
+        assert query.encode(quote_plus=True) == 'a+%2Fb'
+        assert query.encode(quote_plus=False) == 'a%20%2Fb'
+
+        # dont_quote= accepts both True and a string of safe characters not to
+        # percent-encode. Unsafe query characters, like '^' and '#', are always
+        # percent-encoded.
+        query = furl.Query('a %2B/b?#')
+        assert query.encode(dont_quote='^') == 'a+%2B%2Fb%3F%23'
+        assert query.encode(quote_plus=True, dont_quote=True) == 'a++/b?%23'
+        assert query.encode(quote_plus=False, dont_quote=True) == 'a%20+/b?%23'
+
     def test_asdict(self):
         pairs = [('a', '1'), ('ロリポップ', 'testä')]
         key_encoded = '%E3%83%AD%E3%83%AA%E3%83%9D%E3%83%83%E3%83%97'
@@ -1386,6 +1399,13 @@
         f.password = ''
         assert f.username is None and f.password == '' and f.url == '//:@'
 
+        # Unicode.
+        username = u'kødp'
+        password = u'ålæg'
+        f = furl.furl(u'https://%s:%[email protected]/' % (username, password))
+        assert f.username == username and f.password == password
+        assert f.url == 'https://k%C3%B8dp:%c3%a5l%c3%[email protected]/'
+
     def test_basics(self):
         url = 'hTtP://www.pumps.com/'
         f = furl.furl(url)
@@ -2026,14 +2046,27 @@
         assert f.url == 'foo:blah'
 
     def test_tostr(self):
-        f = furl.furl('http://blast.off/?a+b=c+d&two%20tap=cat%20nap%24')
+        f = furl.furl('http://blast.off/?a+b=c+d&two%20tap=cat%20nap%24%21')
         assert f.tostr() == f.url
         assert (f.tostr(query_delimiter=';') ==
-                'http://blast.off/?a+b=c+d;two+tap=cat+nap%24')
+                'http://blast.off/?a+b=c+d;two+tap=cat+nap%24%21')
         assert (f.tostr(query_quote_plus=False) ==
-                'http://blast.off/?a%20b=c%20d&two%20tap=cat%20nap%24')
+                'http://blast.off/?a%20b=c%20d&two%20tap=cat%20nap%24%21')
         assert (f.tostr(query_delimiter=';', query_quote_plus=False) ==
-                'http://blast.off/?a%20b=c%20d;two%20tap=cat%20nap%24')
+                'http://blast.off/?a%20b=c%20d;two%20tap=cat%20nap%24%21')
+        assert (f.tostr(query_quote_plus=False, query_dont_quote=True) ==
+                'http://blast.off/?a%20b=c%20d&two%20tap=cat%20nap$!')
+        # query_dont_quote ignores invalid query characters, like '$'.
+        assert (f.tostr(query_quote_plus=False, query_dont_quote='$') ==
+                'http://blast.off/?a%20b=c%20d&two%20tap=cat%20nap$%21')
+
+        url = 'https://klugg.com/?hi=*'
+        url_encoded = 'https://klugg.com/?hi=%2A&url='
+        f = furl.furl(url).set(args=[('hi', '*'), ('url', url)])
+        assert f.tostr() == url_encoded + quote_plus(url)
+        assert f.tostr(query_dont_quote=True) == url + '&url=' + url
+        assert f.tostr(query_dont_quote='*') == (
+            url + '&url=' + quote_plus(url, '*'))
 
     def test_equality(self):
         assert furl.furl() is not furl.furl() and furl.furl() == furl.furl()


Reply via email to