Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-purl for openSUSE:Factory checked in at 2022-10-18 12:44:40 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-purl (Old) and /work/SRC/openSUSE:Factory/.python-purl.new.2275 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-purl" Tue Oct 18 12:44:40 2022 rev:4 rq:1018091 version:1.6 Changes: -------- --- /work/SRC/openSUSE:Factory/python-purl/python-purl.changes 2020-05-04 18:34:08.840272246 +0200 +++ /work/SRC/openSUSE:Factory/.python-purl.new.2275/python-purl.changes 2022-10-18 12:44:58.001719201 +0200 @@ -1,0 +2,9 @@ +Mon Oct 17 10:46:23 UTC 2022 - pgaj...@suse.com + +- version update to 1.6 + * Use `pytest` insteed of `nose`. + * Fix warning around regex string. +- deleted patches + - use_pytest.patch (upstreamed) + +------------------------------------------------------------------- Old: ---- 1.5.tar.gz use_pytest.patch New: ---- 1.6.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-purl.spec ++++++ --- /var/tmp/diff_new_pack.WeG1Re/_old 2022-10-18 12:44:58.445720212 +0200 +++ /var/tmp/diff_new_pack.WeG1Re/_new 2022-10-18 12:44:58.449720221 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-purl # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,15 +18,13 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-purl -Version: 1.5 +Version: 1.6 Release: 0 Summary: An immutable URL class for URL building and manipulation License: MIT Group: Development/Languages/Python URL: https://github.com/codeinthehole/purl Source: https://github.com/codeinthehole/purl/archive/%{version}.tar.gz -# https://github.com/codeinthehole/purl/pull/42 -Patch0: use_pytest.patch BuildRequires: %{python_module pytest} BuildRequires: %{python_module setuptools} BuildRequires: %{python_module six} @@ -41,7 +39,6 @@ %prep %setup -q -n purl-%{version} -%patch0 -p1 %build %python_build @@ -51,7 +48,9 @@ %python_expand %fdupes %{buildroot}%{$python_sitelib} %check -%pytest tests/utils_tests.py tests/expansion_tests.py tests/template_tests.py tests/url_tests.py +pushd tests +%pytest +popd %files %{python_files} %doc README.rst ++++++ 1.5.tar.gz -> 1.6.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/.travis.yml new/purl-1.6/.travis.yml --- old/purl-1.5/.travis.yml 2019-03-10 21:51:02.000000000 +0100 +++ new/purl-1.6/.travis.yml 2021-05-15 23:00:41.000000000 +0200 @@ -1,9 +1,11 @@ language: python python: - 2.7 - - 3.3 - - 3.4 + - 3.6 + - 3.7 + - 3.8 - pypy + - pypy3 install: - make install script: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/README.rst new/purl-1.6/README.rst --- old/purl-1.5/README.rst 2019-03-10 21:51:02.000000000 +0100 +++ new/purl-1.6/README.rst 2021-05-15 23:00:41.000000000 +0200 @@ -3,7 +3,7 @@ ================================ A simple, immutable URL class with a clean API for interrogation and -manipulation. Supports Pythons 2.7, 3.3, 3.4, 3.5, 3.6 and pypy. +manipulation. Supports Pythons 2.7, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8 and pypy. Also supports template URLs as per `RFC 6570`_ @@ -166,6 +166,12 @@ Changelog --------- +v1.6 - 2021-05-15 +~~~~~~~~~~~~~~~~~ + +* Use `pytest` insteed of `nose`. +* Fix warning around regex string. + v1.5 - 2019-03-10 ~~~~~~~~~~~~~~~~~ @@ -283,7 +289,7 @@ Ensure tests pass using:: - (purl) $ ./runtests.sh + (purl) $ pytest or:: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/docs/conf.py new/purl-1.6/docs/conf.py --- old/purl-1.5/docs/conf.py 2019-03-10 21:51:02.000000000 +0100 +++ new/purl-1.6/docs/conf.py 2021-05-15 23:00:41.000000000 +0200 @@ -120,11 +120,6 @@ # pixels large. #html_favicon = None -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/makefile new/purl-1.6/makefile --- old/purl-1.5/makefile 2019-03-10 21:51:02.000000000 +0100 +++ new/purl-1.6/makefile 2021-05-15 23:00:41.000000000 +0200 @@ -3,7 +3,7 @@ python setup.py develop test: - nosetests + pytest package: clean # Test these packages in a fresh virtualenvs: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/purl/__init__.py new/purl-1.6/purl/__init__.py --- old/purl-1.5/purl/__init__.py 2019-03-10 21:51:02.000000000 +0100 +++ new/purl-1.6/purl/__init__.py 2021-05-15 23:00:41.000000000 +0200 @@ -1,4 +1,6 @@ from .url import URL # noqa from .template import expand, Template # noqa +__version__ = '1.6' + __all__ = ['URL', 'expand', 'Template'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/purl/template.py new/purl-1.6/purl/template.py --- old/purl-1.5/purl/template.py 2019-03-10 21:51:02.000000000 +0100 +++ new/purl-1.6/purl/template.py 2021-05-15 23:00:41.000000000 +0200 @@ -13,7 +13,7 @@ __all__ = ['Template', 'expand'] -patterns = re.compile("{([^\}]+)}") +patterns = re.compile(r"{([^\}]+)}") class Template(object): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/pytest.ini new/purl-1.6/pytest.ini --- old/purl-1.5/pytest.ini 1970-01-01 01:00:00.000000000 +0100 +++ new/purl-1.6/pytest.ini 2021-05-15 23:00:41.000000000 +0200 @@ -0,0 +1,3 @@ +[pytest] +addopts = -vv --doctest-modules --doctest-glob='*.rst' +doctest_optionflags=ALLOW_UNICODE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/requirements.txt new/purl-1.6/requirements.txt --- old/purl-1.5/requirements.txt 2019-03-10 21:51:02.000000000 +0100 +++ new/purl-1.6/requirements.txt 2021-05-15 23:00:41.000000000 +0200 @@ -4,5 +4,5 @@ wheel==0.33.1 # Testing -nose==1.3.7 +pytest tox==3.7.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/runtests.sh new/purl-1.6/runtests.sh --- old/purl-1.5/runtests.sh 2019-03-10 21:51:02.000000000 +0100 +++ new/purl-1.6/runtests.sh 1970-01-01 01:00:00.000000000 +0100 @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -# The doctests only work in Python2.* due to unicode issues that I -#??don't know how to solve. -nosetests --with-doctest --doctest-extension=rst -s $@ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/setup.py new/purl-1.6/setup.py --- old/purl-1.5/setup.py 2019-03-10 21:51:02.000000000 +0100 +++ new/purl-1.6/setup.py 2021-05-15 23:00:41.000000000 +0200 @@ -3,7 +3,7 @@ setup( name='purl', - version='1.5', + version='1.6', description=( "An immutable URL class for easy URL-building and manipulation"), long_description=open('README.rst').read(), @@ -23,10 +23,10 @@ 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries :: Python Modules', ], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/tests/expansion_tests.py new/purl-1.6/tests/expansion_tests.py --- old/purl-1.5/tests/expansion_tests.py 2019-03-10 21:51:02.000000000 +0100 +++ new/purl-1.6/tests/expansion_tests.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,129 +0,0 @@ -# -*- coding: utf-8 -*- -import collections - -from nose.tools import eq_ - -from purl.template import expand - -# Define variables as in the RFC (http://tools.ietf.org/html/rfc6570) -level1_vars = { - 'var': 'value', - 'hello': 'Hello World!', -} -level2_vars = level1_vars.copy() -level2_vars.update({ - 'path': '/foo/bar' -}) -level3_vars = level2_vars.copy() -level3_vars.update({ - 'empty': '', - 'x': '1024', - 'y': '768' -}) -level4_vars = level2_vars.copy() -level4_vars.update({ - 'list': ['red', 'green', 'blue'], - 'keys': [('semi', ';'), ('dot', '.'), ('comma', ',')] -}) - -data = [ - # Level 1 - ('{var}', level1_vars, 'value'), - ('{hello}', level1_vars, 'Hello%20World%21'), - # Level 2 - reserved expansion - ('{+var}', level2_vars, 'value'), - ('{+hello}', level2_vars, 'Hello%20World!'), - ('{+path}/here', level2_vars, '/foo/bar/here'), - ('here?ref={+path}', level2_vars, 'here?ref=/foo/bar'), - # Level 2 - fragment expansion - ('X{#var}', level2_vars, 'X#value'), - ('X{#hello}', level2_vars, 'X#Hello%20World!'), - # Level 3 - string expansion with multiple variables - ('map?{x,y}', level3_vars, 'map?1024,768'), - ('{x,hello,y}', level3_vars, '1024,Hello%20World%21,768'), - # Level 3 - reserved expansion with multiple variables - ('{+x,hello,y}', level3_vars, '1024,Hello%20World!,768'), - ('{+path,x}/here', level3_vars, '/foo/bar,1024/here'), - # Level 3 - fragment expansion with multiple variables - ('{#x,hello,y}', level3_vars, '#1024,Hello%20World!,768'), - ('{#path,x}/here', level3_vars, '#/foo/bar,1024/here'), - # Level 3 - label expansion - ('X{.var}', level3_vars, 'X.value'), - ('X{.x,y}', level3_vars, 'X.1024.768'), - # Level 3 - path segments, slash prefixed - ('{/var}', level3_vars, '/value'), - ('{/nokey}', level3_vars, ''), - ('{/var,x}/here', level3_vars, '/value/1024/here'), - # Level 3 - path segments, semi-colon prefixed - ('{;x,y}', level3_vars, ';x=1024;y=768'), - ('{;x,y,empty}', level3_vars, ';x=1024;y=768;empty'), - # Level 3 - form-style query, ampersand-separated - ('{?x,y}', level3_vars, '?x=1024&y=768'), - ('{?x,y,empty}', level3_vars, '?x=1024&y=768&empty='), - # Level 3 - form-style query continuation - ('?fixed=yes{&x}', level3_vars, '?fixed=yes&x=1024'), - ('{&x,y,empty}', level3_vars, '&x=1024&y=768&empty='), - # Level 4 - string expansion with value modifiers - ('{var:3}', level4_vars, 'val'), - ('{var:30}', level4_vars, 'value'), - ('{list}', level4_vars, 'red,green,blue'), - ('{list*}', level4_vars, 'red,green,blue'), - ('{keys}', level4_vars, 'semi,%3B,dot,.,comma,%2C'), - ('{keys*}', level4_vars, 'semi=%3B,dot=.,comma=%2C'), - # Level 4 - reserved expansion with value modifiers - ('{+path:6}/here', level4_vars, '/foo/b/here'), - ('{+list}', level4_vars, 'red,green,blue'), - ('{+list*}', level4_vars, 'red,green,blue'), - ('{+keys}', level4_vars, 'semi,;,dot,.,comma,,'), - ('{+keys*}', level4_vars, 'semi=;,dot=.,comma=,'), - # Level 4 - fragment expansion with value modifiers - ('{#path:6}/here', level4_vars, '#/foo/b/here'), - ('{#list}', level4_vars, '#red,green,blue'), - ('{#list*}', level4_vars, '#red,green,blue'), - ('{#keys}', level4_vars, '#semi,;,dot,.,comma,,'), - ('{#keys*}', level4_vars, '#semi=;,dot=.,comma=,'), - # Level 4 - label expansion, dot-prefixed - ('X{.var:3}', level4_vars, 'X.val'), - ('X{.list}', level4_vars, 'X.red,green,blue'), - ('X{.list*}', level4_vars, 'X.red.green.blue'), - ('X{.keys}', level4_vars, 'X.semi,%3B,dot,.,comma,%2C'), - ('X{.keys*}', level4_vars, 'X.semi=%3B.dot=..comma=%2C'), - # Level 4 - path segments, slash-prefixed - ('{/var:1,var}', level4_vars, '/v/value'), - ('{/list}', level4_vars, '/red,green,blue'), - ('{/list*}', level4_vars, '/red/green/blue'), - ('{/list*,path:4}', level4_vars, '/red/green/blue/%2Ffoo'), - ('{/keys}', level4_vars, '/semi,%3B,dot,.,comma,%2C'), - ('{/keys*}', level4_vars, '/semi=%3B/dot=./comma=%2C'), - # Level 4 - path-style parameters, semicolon-prefixed - ('{;hello:5}', level4_vars, ';hello=Hello'), - ('{;list}', level4_vars, ';list=red,green,blue'), - ('{;list*}', level4_vars, ';list=red;list=green;list=blue'), - ('{;keys}', level4_vars, ';keys=semi,%3B,dot,.,comma,%2C'), - ('{;keys*}', level4_vars, ';semi=%3B;dot=.;comma=%2C'), - # Level 4 - form-style query, ampersand-separated - ('{?var:3}', level4_vars, '?var=val'), - ('{?list}', level4_vars, '?list=red,green,blue'), - ('{?list*}', level4_vars, '?list=red&list=green&list=blue'), - ('{?keys}', level4_vars, '?keys=semi,%3B,dot,.,comma,%2C'), - ('{?keys*}', level4_vars, '?semi=%3B&dot=.&comma=%2C'), - # Level 4 - form-sytyle query continuation - ('{&var:3}', level4_vars, '&var=val'), - ('{&list}', level4_vars, '&list=red,green,blue'), - ('{&list*}', level4_vars, '&list=red&list=green&list=blue'), - ('{&keys}', level4_vars, '&keys=semi,%3B,dot,.,comma,%2C'), - ('{&keys*}', level4_vars, '&semi=%3B&dot=.&comma=%2C'), -] - - -def assert_expansion(template, fields, expected): - eq_(expand(template, fields), expected) - - -def test_expansion(): - for template, fields, expected in data: - yield assert_expansion, template, fields, expected - -def test_unicode(): - expand('{/name}', {'name': u'??? hello'}) - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/tests/template_tests.py new/purl-1.6/tests/template_tests.py --- old/purl-1.5/tests/template_tests.py 2019-03-10 21:51:02.000000000 +0100 +++ new/purl-1.6/tests/template_tests.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,20 +0,0 @@ -from unittest import TestCase - -import purl - - -class TemplateTests(TestCase): - - def test_basic_expansion(self): - template = purl.Template('http://example.com{+path,x}/here') - url = template.expand({'path': '/foo/bar', 'x': 1024}) - self.assertEquals('http://example.com/foo/bar,1024/here', - url.as_string()) - - def test_github_api_expansion(self): - template = purl.Template( - 'https://api.github.com/repos/codeinthehole/purl/labels{/name}') - url = template.expand() - self.assertEquals( - 'https://api.github.com/repos/codeinthehole/purl/labels', - url.as_string()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/tests/test_expansion.py new/purl-1.6/tests/test_expansion.py --- old/purl-1.5/tests/test_expansion.py 1970-01-01 01:00:00.000000000 +0100 +++ new/purl-1.6/tests/test_expansion.py 2021-05-15 23:00:41.000000000 +0200 @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- +import collections + +import pytest + +from purl.template import expand + +# Define variables as in the RFC (http://tools.ietf.org/html/rfc6570) +level1_vars = { + 'var': 'value', + 'hello': 'Hello World!', +} +level2_vars = level1_vars.copy() +level2_vars.update({ + 'path': '/foo/bar' +}) +level3_vars = level2_vars.copy() +level3_vars.update({ + 'empty': '', + 'x': '1024', + 'y': '768' +}) +level4_vars = level2_vars.copy() +level4_vars.update({ + 'list': ['red', 'green', 'blue'], + 'keys': [('semi', ';'), ('dot', '.'), ('comma', ',')] +}) + +data = [ + # Level 1 + ('{var}', level1_vars, 'value'), + ('{hello}', level1_vars, 'Hello%20World%21'), + # Level 2 - reserved expansion + ('{+var}', level2_vars, 'value'), + ('{+hello}', level2_vars, 'Hello%20World!'), + ('{+path}/here', level2_vars, '/foo/bar/here'), + ('here?ref={+path}', level2_vars, 'here?ref=/foo/bar'), + # Level 2 - fragment expansion + ('X{#var}', level2_vars, 'X#value'), + ('X{#hello}', level2_vars, 'X#Hello%20World!'), + # Level 3 - string expansion with multiple variables + ('map?{x,y}', level3_vars, 'map?1024,768'), + ('{x,hello,y}', level3_vars, '1024,Hello%20World%21,768'), + # Level 3 - reserved expansion with multiple variables + ('{+x,hello,y}', level3_vars, '1024,Hello%20World!,768'), + ('{+path,x}/here', level3_vars, '/foo/bar,1024/here'), + # Level 3 - fragment expansion with multiple variables + ('{#x,hello,y}', level3_vars, '#1024,Hello%20World!,768'), + ('{#path,x}/here', level3_vars, '#/foo/bar,1024/here'), + # Level 3 - label expansion + ('X{.var}', level3_vars, 'X.value'), + ('X{.x,y}', level3_vars, 'X.1024.768'), + # Level 3 - path segments, slash prefixed + ('{/var}', level3_vars, '/value'), + ('{/nokey}', level3_vars, ''), + ('{/var,x}/here', level3_vars, '/value/1024/here'), + # Level 3 - path segments, semi-colon prefixed + ('{;x,y}', level3_vars, ';x=1024;y=768'), + ('{;x,y,empty}', level3_vars, ';x=1024;y=768;empty'), + # Level 3 - form-style query, ampersand-separated + ('{?x,y}', level3_vars, '?x=1024&y=768'), + ('{?x,y,empty}', level3_vars, '?x=1024&y=768&empty='), + # Level 3 - form-style query continuation + ('?fixed=yes{&x}', level3_vars, '?fixed=yes&x=1024'), + ('{&x,y,empty}', level3_vars, '&x=1024&y=768&empty='), + # Level 4 - string expansion with value modifiers + ('{var:3}', level4_vars, 'val'), + ('{var:30}', level4_vars, 'value'), + ('{list}', level4_vars, 'red,green,blue'), + ('{list*}', level4_vars, 'red,green,blue'), + ('{keys}', level4_vars, 'semi,%3B,dot,.,comma,%2C'), + ('{keys*}', level4_vars, 'semi=%3B,dot=.,comma=%2C'), + # Level 4 - reserved expansion with value modifiers + ('{+path:6}/here', level4_vars, '/foo/b/here'), + ('{+list}', level4_vars, 'red,green,blue'), + ('{+list*}', level4_vars, 'red,green,blue'), + ('{+keys}', level4_vars, 'semi,;,dot,.,comma,,'), + ('{+keys*}', level4_vars, 'semi=;,dot=.,comma=,'), + # Level 4 - fragment expansion with value modifiers + ('{#path:6}/here', level4_vars, '#/foo/b/here'), + ('{#list}', level4_vars, '#red,green,blue'), + ('{#list*}', level4_vars, '#red,green,blue'), + ('{#keys}', level4_vars, '#semi,;,dot,.,comma,,'), + ('{#keys*}', level4_vars, '#semi=;,dot=.,comma=,'), + # Level 4 - label expansion, dot-prefixed + ('X{.var:3}', level4_vars, 'X.val'), + ('X{.list}', level4_vars, 'X.red,green,blue'), + ('X{.list*}', level4_vars, 'X.red.green.blue'), + ('X{.keys}', level4_vars, 'X.semi,%3B,dot,.,comma,%2C'), + ('X{.keys*}', level4_vars, 'X.semi=%3B.dot=..comma=%2C'), + # Level 4 - path segments, slash-prefixed + ('{/var:1,var}', level4_vars, '/v/value'), + ('{/list}', level4_vars, '/red,green,blue'), + ('{/list*}', level4_vars, '/red/green/blue'), + ('{/list*,path:4}', level4_vars, '/red/green/blue/%2Ffoo'), + ('{/keys}', level4_vars, '/semi,%3B,dot,.,comma,%2C'), + ('{/keys*}', level4_vars, '/semi=%3B/dot=./comma=%2C'), + # Level 4 - path-style parameters, semicolon-prefixed + ('{;hello:5}', level4_vars, ';hello=Hello'), + ('{;list}', level4_vars, ';list=red,green,blue'), + ('{;list*}', level4_vars, ';list=red;list=green;list=blue'), + ('{;keys}', level4_vars, ';keys=semi,%3B,dot,.,comma,%2C'), + ('{;keys*}', level4_vars, ';semi=%3B;dot=.;comma=%2C'), + # Level 4 - form-style query, ampersand-separated + ('{?var:3}', level4_vars, '?var=val'), + ('{?list}', level4_vars, '?list=red,green,blue'), + ('{?list*}', level4_vars, '?list=red&list=green&list=blue'), + ('{?keys}', level4_vars, '?keys=semi,%3B,dot,.,comma,%2C'), + ('{?keys*}', level4_vars, '?semi=%3B&dot=.&comma=%2C'), + # Level 4 - form-style query continuation + ('{&var:3}', level4_vars, '&var=val'), + ('{&list}', level4_vars, '&list=red,green,blue'), + ('{&list*}', level4_vars, '&list=red&list=green&list=blue'), + ('{&keys}', level4_vars, '&keys=semi,%3B,dot,.,comma,%2C'), + ('{&keys*}', level4_vars, '&semi=%3B&dot=.&comma=%2C'), +] + + +@pytest.mark.parametrize("template, fields, expected", data) +def test_assert_expansion(template, fields, expected): + assert expand(template, fields) == expected + +def test_unicode(): + expand('{/name}', {'name': u'??? hello'}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/tests/test_template.py new/purl-1.6/tests/test_template.py --- old/purl-1.5/tests/test_template.py 1970-01-01 01:00:00.000000000 +0100 +++ new/purl-1.6/tests/test_template.py 2021-05-15 23:00:41.000000000 +0200 @@ -0,0 +1,15 @@ +import purl + + +class TestTemplate: + + def test_basic_expansion(self): + template = purl.Template('http://example.com{+path,x}/here') + url = template.expand({'path': '/foo/bar', 'x': 1024}) + assert 'http://example.com/foo/bar,1024/here' == url.as_string() + + def test_github_api_expansion(self): + template = purl.Template( + 'https://api.github.com/repos/codeinthehole/purl/labels{/name}') + url = template.expand() + assert 'https://api.github.com/repos/codeinthehole/purl/labels' == url.as_string() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/tests/test_url.py new/purl-1.6/tests/test_url.py --- old/purl-1.5/tests/test_url.py 1970-01-01 01:00:00.000000000 +0100 +++ new/purl-1.6/tests/test_url.py 2021-05-15 23:00:41.000000000 +0200 @@ -0,0 +1,463 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals +from purl import URL +import pytest + +import pickle + +try: + from urllib.parse import quote +except ImportError: + from urllib import quote + + +class TestConstructor: + def test_url_can_be_created_with_just_host(self): + u = URL(host="google.com") + assert "http://google.com/" == str(u) + + def test_url_can_be_created_with_host_and_schema(self): + u = URL(host="google.com", scheme="https") + assert "https://google.com/" == str(u) + + def test_url_can_be_created_with_host_and_post(self): + u = URL(host="localhost", port=8000) + assert "http://localhost:8000/" == str(u) + + def test_url_can_be_created_with_username_only(self): + u = URL( + scheme="postgres", + username="user", + host="127.0.0.1", + port="5432", + path="/db_name", + ) + assert "postgres://user@127.0.0.1:5432/db_name" == str(u) + + def test_no_args_to_constructor(self): + u = URL() + assert "/" == str(u) + + def test_as_string(self): + assert "/" == URL().as_string() + + def test_full_url_can_be_used_as_first_param(self): + u = URL("https://github.com") + assert "https://github.com" == u.as_string() + + def test_kwargs_take_priority_when_used_with_full_url(self): + u = URL("https://github.com", scheme="http") + assert "http://github.com" == u.as_string() + + def test_creation_with_host_and_path(self): + u = URL(host="localhost", path="boo") + assert "http://localhost/boo" == str(u) + + def test_creation_with_host_and_path_2(self): + u = URL(host="localhost").add_path_segment("boo") + assert "http://localhost/boo" == str(u) + + +class TestMoreFactory: + def test_extracting_query_param(self): + url_str = "https://www.sandbox.paypal.com/webscr?cmd=_express-checkout&token=EC-6469953681606921P&AMT=200&CURRENCYCODE=GBP&RETURNURL=http%3A%2F%2Fexample.com%2Fcheckout%2Fpaypal%2Fresponse%2Fsuccess%2F&CANCELURL=http%3A%2F%2Fexample.com%2Fcheckout%2Fpaypal%2Fresponse%2Fcancel%2F" + url = URL.from_string(url_str) + return_url = url.query_param("RETURNURL") + assert "http://example.com/checkout/paypal/response/success/" == return_url + + +class TestFactory: + + url_str = "http://www.google.com/search/?q=testing#fragment" + url = URL.from_string(url_str) + + def test_scheme(self): + assert "http" == self.url.scheme() + + def test_fragment(self): + assert "fragment" == self.url.fragment() + + def test_path(self): + assert "/search/" == self.url.path() + + def test_host(self): + assert "www.google.com" == self.url.host() + + def test_string_version(self): + assert self.url_str == str(self.url) + + +class TestEdgeCaseExtraction: + def test_no_equals_sign_means_empty_string(self): + url = URL.from_string("http://www.google.com/blog/article/1?q") + assert "" == url.query_param("q") + + def test_list_extraction(self): + url = URL.from_string("http://www.google.com/?q=1&q=2&q=3") + assert ["1" == "2", "3"], url.query_param("q") + + def test_username_extraction(self): + url = URL.from_string("ftp://user:p...@ftp.host") + assert "user" == url.username() + assert "pw" == url.password() + + def test_username_in_unicode_repr(self): + u = "ftp://user:p...@ftp.host" + url = URL.from_string(u) + assert u == str(url) + + def test_auth_in_netloc(self): + url = URL.from_string("ftp://user:p...@ftp.host") + assert "user:p...@ftp.host" == url.netloc() + + def test_auth_with_special_char(self): + url = URL.from_string("ftp://user:b@z...@ftp.host") + assert "user" == url.username() + assert "b@z" == url.password() + + def test_port_in_netloc(self): + url = URL.from_string("http://localhost:5000") + assert "localhost" == url.host() + assert 5000 == url.port() + + def test_passwordless_netloc(self): + url = URL.from_string("postgres://user@127.0.0.1:5432/db_name") + assert "user" == url.username() + assert url.password() is None + + def test_unicode_username_and_password(self): + url = URL.from_string("postgres://je????:nieje????@127.0.0.1:5432/db_name") + assert "je????" == url.username() + assert "nieje????" == url.password() + + def test_unicode_username_only(self): + url = URL.from_string("postgres://je????@127.0.0.1:5432/db_name") + assert "je????" == url.username() + assert url.password() is None + + def test_port_for_https_url(self): + url = URL.from_string("https://github.com") + assert None == url.port() + + +class TestSimpleExtraction: + url = URL.from_string("http://www.google.com/blog/article/1?q=testing") + + def test_has_actual_param(self): + assert self.url.has_query_param("q") is True + + def test_remove_query_param(self): + new_url = self.url.remove_query_param("q") + assert "http://www.google.com/blog/article/1" == new_url.as_string() + + def test_has_query_params(self): + assert self.url.has_query_params(["q"]) is True + + def test_has_query_params_negative(self): + assert self.url.has_query_params(["q", "r"]) is False + + def test_netloc(self): + assert "www.google.com" == self.url.netloc() + + def test_path_extraction(self): + assert "1" == self.url.path_segment(2) + + def test_port_defaults_to_none(self): + assert self.url.port() is None + + def test_scheme(self): + assert "http" == self.url.scheme() + + def test_host(self): + assert "www.google.com" == self.url.host() + + def test_domain(self): + assert "www.google.com" == self.url.domain() + + def test_subdomains(self): + assert ["www" == "google", "com"], self.url.subdomains() + + def test_subdomain(self): + assert "www" == self.url.subdomain(0) + + def test_invalid_subdomain_raises_indexerror(self): + with pytest.raises(IndexError): + self.url.subdomain(10) + + def test_path(self): + assert "/blog/article/1" == self.url.path() + + def test_query(self): + assert "q=testing" == self.url.query() + + def test_query_param_as_list(self): + assert ["testing"] == self.url.query_param("q", as_list=True) + + def test_query_params(self): + assert {"q": ["testing"]} == self.url.query_params() + + def test_path_extraction_returns_none_if_index_too_large(self): + assert self.url.path_segment(14) is None + + def test_path_extraction_can_take_default_value(self): + assert "hello" == self.url.path_segment(3, default="hello") + + def test_parameter_extraction(self): + assert "testing" == self.url.query_param("q") + + def test_parameter_extraction_with_default(self): + assert "eggs" == self.url.query_param("p", default="eggs") + + def test_parameter_extraction_is_none_if_not_found(self): + assert self.url.query_param("p") is None + + def test_path_segments(self): + assert ("blog", "article", "1") == self.url.path_segments() + + def test_relative(self): + assert "/blog/article/1?q=testing" == str(self.url.relative()) + + +class TestNoTrailingSlash: + def test_path_extraction_without_trailing_slash(self): + u = URL(host="google.com", path="/blog/article/1") + assert "1" == u.path_segment(2) + + +class TestBuilder: + def test_setting_list_as_query_params(self): + first = URL.from_string("?q=testing") + second = URL().query_params(first.query_params()) + assert first.query() == second.query() + + def test_add_path_segment(self): + url = ( + URL("http://example.com") + .add_path_segment("one") + .add_path_segment("two") + .add_path_segment("three") + ) + assert "/one/two/three" == url.path() + + def test_setting_single_item_list_as_query_param(self): + url = URL().query_param("q", ["testing"]) + assert "testing" == url.query_param("q") + + def test_setting_list_as_query_param(self): + url = URL().query_param("q", ["testing", "eggs"]) + assert ["testing" == "eggs"], url.query_param("q", as_list=True) + + def test_build_relative_url(self): + url = URL().path("searching") + assert "/searching" == str(url) + + def test_build_relative_url_with_params(self): + URL().path("/searching").query_param("q", "testing") + + def test_build_with_path_segments(self): + u = URL().path_segments(["path", "to", "page"]) + assert "/path/to/page" == u.as_string() + + def test_set_fragment(self): + url = URL.from_string("http://www.google.com/").fragment("hello") + assert "hello" == url.fragment() + + def test_set_scheme(self): + url = URL.from_string("http://www.google.com/").scheme("https") + assert "https" == url.scheme() + + def test_set_host(self): + url = URL.from_string("http://www.google.com/").host("maps.google.com") + assert "maps.google.com" == url.host() + + def test_set_path(self): + url = URL.from_string("http://www.google.com/").path("search") + assert "/search" == url.path() + + def test_set_path_with_special_chars(self): + url = URL.from_string("http://www.google.com/").path("search something") + assert "/search%20something" == url.path() + + def test_set_query(self): + url = URL.from_string("http://www.google.com/").query("q=testing") + assert "testing" == url.query_param("q") + + def test_set_port(self): + url = URL.from_string("http://www.google.com/").port(8000) + assert 8000 == url.port() + + def test_set_path_segment(self): + url = URL.from_string("http://www.google.com/a/b/c/").path_segment(1, "d") + assert "/a/d/c/" == url.path() + + def test_set_query_param(self): + url = URL.from_string("http://www.google.com/search").query_param( + "q", "testing" + ) + assert "testing" == url.query_param("q") + + def test_set_query_params(self): + url = URL.from_string("http://www.google.com/search").query_params( + {"q": "testing"} + ) + assert "testing" == url.query_param("q") + + def test_set_subdomain(self): + url = URL.from_string("http://www.google.com/search").subdomain(0, "www2") + assert "www2" == url.subdomain(0) + + def test_set_subdomains(self): + url = URL().subdomains(["www", "google", "com"]) + assert "http://www.google.com/" == str(url) + + def test_remove_domain(self): + url = URL("https://example.com/hello?x=100") + new = url.domain("") + assert "/hello?x=100" == str(new) + + def test_remove_port(self): + url = URL("https://example.com/hello?x=100") + new = url.port("") + assert "https://example.com/hello?x=100" == str(new) + + +class TestMisc: + def test_url_can_be_used_as_key_in_dict(self): + u = URL.from_string("http://google.com") + {u: 0} + + def test_equality_comparison(self): + assert URL.from_string("http://google.com") == URL.from_string( + "http://google.com" + ) + + def test_negative_equality_comparison(self): + assert URL.from_string("http://google.com") != URL.from_string( + "https://google.com" + ) + + def test_urls_are_hashable(self): + u = URL.from_string("http://google.com") + hash(u) + + def test_urls_can_be_pickled(self): + u = URL.from_string("http://google.com") + pickle.dumps(u) + + def test_urls_can_be_pickled_and_restored(self): + u = URL.from_string("http://google.com") + pickled = pickle.dumps(u) + v = pickle.loads(pickled) + assert u == v + + +class TestQueryParamList: + def test_set_list(self): + base = URL("http://127.0.0.1/") + url = base.query_param("q", ["something", "else"]) + values = url.query_param("q", as_list=True) + assert ["something" == "else"], values + + def test_remove_item_from_list(self): + base = URL("http://127.0.0.1/?q=a&q=b") + url = base.remove_query_param("q", "a") + values = url.query_param("q", as_list=True) + assert ["b"] == values + + def test_append_to_existing_list(self): + base = URL("http://127.0.0.1/?q=a&q=b") + url = base.append_query_param("q", "c") + values = url.query_param("q", as_list=True) + assert ["a", "b", "c"] == values + + def test_append_to_nonexistant_list(self): + base = URL("http://127.0.0.1/?q=a&q=b") + url = base.append_query_param("p", "c") + values = url.query_param("p", as_list=True) + assert ["c"] == values + + +class TestUnicodeExtraction: + def test_get_query_param_ascii_url(self): + unicode_param = "????????????????" + + # Python 2.6 requires bytes for quote + urlencoded_param = quote(unicode_param.encode("utf8")) + url = "http://www.google.com/blog/article/1?q=" + urlencoded_param + + ascii_url = URL.from_string(url.encode("ascii")) + param = ascii_url.query_param("q") + assert param == unicode_param + + def test_get_query_param_unicode_url(self): + unicode_param = "????????????????" + + # Python 2.6 requires bytes for quote + urlencoded_param = quote(unicode_param.encode("utf8")) + url = "http://www.google.com/blog/article/1?q=" + urlencoded_param + + # django request.get_full_path() returns url as unicode + unicode_url = URL.from_string(url) + + param = unicode_url.query_param("q") + assert param == unicode_param + + +class TestUnicode: + base = URL("http://127.0.0.1/") + text = "??" + bytes = text.encode("utf8") + + def test_set_unicode_query_param_value(self): + url = self.base.query_param("q", self.text) + assert self.text == url.query_param("q") + + def test_set_bytestring_query_param_value(self): + url = self.base.query_param("q", self.bytes) + assert self.text == url.query_param("q") + + def test_set_unicode_query_param_key(self): + url = self.base.query_param(self.text, "value") + assert "value" == url.query_param(self.text) + + def test_set_bytestring_query_param_key(self): + url = self.base.query_param(self.bytes, "value") + assert "value" == url.query_param(self.text) + + def test_append_unicode_query_param(self): + url = self.base.append_query_param("q", self.text) + assert self.text == url.query_param("q") + + def test_append_bytestring_query_param(self): + url = self.base.append_query_param("q", self.bytes) + assert self.text == url.query_param("q") + + def test_set_unicode_query_params(self): + url = self.base.query_params({"q": self.text}) + assert self.text == url.query_param("q") + + def test_set_bytestring_query_params(self): + url = self.base.query_params({"q": self.bytes}) + assert self.text == url.query_param("q") + + def test_add_unicode_path_segment(self): + url = self.base.add_path_segment(self.text) + assert self.text == url.path_segment(0) + + def test_add_bytestring_path_segment(self): + url = self.base.add_path_segment(self.bytes) + assert self.text == url.path_segment(0) + + def test_add_unicode_fragment(self): + url = self.base.fragment(self.text) + assert self.text == url.fragment() + + +class QuotedSlashesTests: + def test_slashes_in_path(self): + u = URL().add_path_segment("test/egg") + assert u.as_string() == "/test%2Fegg" + + def test_slashes_in_path(self): + u = URL("/something").path_segment(0, "test/egg") + assert u.as_string() == "/test%2Fegg" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/tests/test_utils.py new/purl-1.6/tests/test_utils.py --- old/purl-1.5/tests/test_utils.py 1970-01-01 01:00:00.000000000 +0100 +++ new/purl-1.6/tests/test_utils.py 2021-05-15 23:00:41.000000000 +0200 @@ -0,0 +1,10 @@ +from purl.url import to_utf8, to_unicode + + +class TestUnicodeHelper: + + def test_convert_int_to_bytes(self): + assert '1024' == to_utf8(1024) + + def test_convert_int_to_unicode(self): + assert u'1024' == to_unicode(1024) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/tests/url_tests.py new/purl-1.6/tests/url_tests.py --- old/purl-1.5/tests/url_tests.py 2019-03-10 21:51:02.000000000 +0100 +++ new/purl-1.6/tests/url_tests.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,457 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals -from purl import URL -from unittest import TestCase - -import pickle - -try: - from urllib.parse import quote -except ImportError: - from urllib import quote - - -class ConstructorTests(TestCase): - - def test_url_can_be_created_with_just_host(self): - u = URL(host='google.com') - self.assertEqual('http://google.com/', str(u)) - - def test_url_can_be_created_with_host_and_schema(self): - u = URL(host='google.com', scheme='https') - self.assertEqual('https://google.com/', str(u)) - - def test_url_can_be_created_with_host_and_post(self): - u = URL(host='localhost', port=8000) - self.assertEqual('http://localhost:8000/', str(u)) - - def test_url_can_be_created_with_username_only(self): - u = URL(scheme='postgres', username='user', host='127.0.0.1', port='5432', path='/db_name') - self.assertEqual('postgres://user@127.0.0.1:5432/db_name', str(u)) - - def test_no_args_to_constructor(self): - u = URL() - self.assertEqual('/', str(u)) - - def test_as_string(self): - self.assertEqual('/', URL().as_string()) - - def test_full_url_can_be_used_as_first_param(self): - u = URL('https://github.com') - self.assertEqual('https://github.com', u.as_string()) - - def test_kwargs_take_priority_when_used_with_full_url(self): - u = URL('https://github.com', scheme='http') - self.assertEqual('http://github.com', u.as_string()) - - def test_creation_with_host_and_path(self): - u = URL(host='localhost', path="boo") - self.assertEqual('http://localhost/boo', str(u)) - - def test_creation_with_host_and_path_2(self): - u = URL(host='localhost').add_path_segment('boo') - self.assertEqual('http://localhost/boo', str(u)) - - -class MoreFactoryTests(TestCase): - - def setUp(self): - self.url_str = 'https://www.sandbox.paypal.com/webscr?cmd=_express-checkout&token=EC-6469953681606921P&AMT=200&CURRENCYCODE=GBP&RETURNURL=http%3A%2F%2Fexample.com%2Fcheckout%2Fpaypal%2Fresponse%2Fsuccess%2F&CANCELURL=http%3A%2F%2Fexample.com%2Fcheckout%2Fpaypal%2Fresponse%2Fcancel%2F' - self.url = URL.from_string(self.url_str) - - def test_extracting_query_param(self): - return_url = self.url.query_param('RETURNURL') - self.assertEqual('http://example.com/checkout/paypal/response/success/', - return_url) - - -class FactoryTests(TestCase): - - def setUp(self): - self.url_str = 'http://www.google.com/search/?q=testing#fragment' - self.url = URL.from_string(self.url_str) - - def test_scheme(self): - self.assertEqual('http', self.url.scheme()) - - def test_fragment(self): - self.assertEqual('fragment', self.url.fragment()) - - def test_path(self): - self.assertEqual('/search/', self.url.path()) - - def test_host(self): - self.assertEqual('www.google.com', self.url.host()) - - def test_string_version(self): - self.assertEqual(self.url_str, str(self.url)) - - -class EdgeCaseExtractionTests(TestCase): - - def test_no_equals_sign_means_empty_string(self): - url = URL.from_string('http://www.google.com/blog/article/1?q') - self.assertEqual('', url.query_param('q')) - - def test_list_extraction(self): - url = URL.from_string('http://www.google.com/?q=1&q=2&q=3') - self.assertEqual(['1', '2', '3'], url.query_param('q')) - - def test_username_extraction(self): - url = URL.from_string('ftp://user:p...@ftp.host') - self.assertEqual('user', url.username()) - self.assertEqual('pw', url.password()) - - def test_username_in_unicode_repr(self): - u = 'ftp://user:p...@ftp.host' - url = URL.from_string(u) - self.assertEqual(u, str(url)) - - def test_auth_in_netloc(self): - url = URL.from_string('ftp://user:p...@ftp.host') - self.assertEqual('user:p...@ftp.host', url.netloc()) - - def test_auth_with_special_char(self): - url = URL.from_string('ftp://user:b@z...@ftp.host') - self.assertEqual('user', url.username()) - self.assertEqual('b@z', url.password()) - - def test_port_in_netloc(self): - url = URL.from_string('http://localhost:5000') - self.assertEqual('localhost', url.host()) - self.assertEqual(5000, url.port()) - - def test_passwordless_netloc(self): - url = URL.from_string('postgres://user@127.0.0.1:5432/db_name') - self.assertEqual('user', url.username()) - self.assertTrue(url.password() is None) - - def test_unicode_username_and_password(self): - url = URL.from_string('postgres://je????:nieje????@127.0.0.1:5432/db_name') - self.assertEqual('je????', url.username()) - self.assertEqual('nieje????', url.password()) - - def test_unicode_username_only(self): - url = URL.from_string('postgres://je????@127.0.0.1:5432/db_name') - self.assertEqual('je????', url.username()) - self.assertTrue(url.password() is None) - - def test_port_for_https_url(self): - url = URL.from_string('https://github.com') - self.assertEqual(None, url.port()) - - -class SimpleExtractionTests(TestCase): - - def setUp(self): - self.url = URL.from_string('http://www.google.com/blog/article/1?q=testing') - - def test_has_actual_param(self): - self.assertTrue(self.url.has_query_param('q')) - - def test_remove_query_param(self): - new_url = self.url.remove_query_param('q') - self.assertEqual('http://www.google.com/blog/article/1', - new_url.as_string()) - - def test_has_query_params(self): - self.assertTrue(self.url.has_query_params(['q'])) - - def test_has_query_params_negative(self): - self.assertFalse(self.url.has_query_params(['q', 'r'])) - - def test_netloc(self): - self.assertEqual('www.google.com', self.url.netloc()) - - def test_path_extraction(self): - self.assertEqual('1', self.url.path_segment(2)) - - def test_port_defaults_to_none(self): - self.assert_(self.url.port() is None) - - def test_scheme(self): - self.assertEqual('http', self.url.scheme()) - - def test_host(self): - self.assertEqual('www.google.com', self.url.host()) - - def test_domain(self): - self.assertEqual('www.google.com', self.url.domain()) - - def test_subdomains(self): - self.assertEqual(['www', 'google', 'com'], self.url.subdomains()) - - def test_subdomain(self): - self.assertEqual('www', self.url.subdomain(0)) - - def test_invalid_subdomain_raises_indexerror(self): - self.assertRaises(IndexError, self.url.subdomain, 10) - - def test_path(self): - self.assertEqual('/blog/article/1', self.url.path()) - - def test_query(self): - self.assertEqual('q=testing', self.url.query()) - - def test_query_param_as_list(self): - self.assertEqual(['testing'], self.url.query_param('q', as_list=True)) - - def test_query_params(self): - self.assertEqual({'q': ['testing']}, self.url.query_params()) - - def test_path_extraction_returns_none_if_index_too_large(self): - self.assert_(self.url.path_segment(14) is None) - - def test_path_extraction_can_take_default_value(self): - self.assertEqual('hello', self.url.path_segment(3, default='hello')) - - def test_parameter_extraction(self): - self.assertEqual('testing', self.url.query_param('q')) - - def test_parameter_extraction_with_default(self): - self.assertEqual('eggs', self.url.query_param('p', default='eggs')) - - def test_parameter_extraction_is_none_if_not_found(self): - self.assert_(self.url.query_param('p') is None) - - def test_path_segments(self): - self.assertEqual(('blog', 'article', '1'), self.url.path_segments()) - - def test_relative(self): - self.assertEqual('/blog/article/1?q=testing', str(self.url.relative())) - - -class NoTrailingSlashTests(TestCase): - - def test_path_extraction_without_trailing_slash(self): - u = URL(host='google.com', path='/blog/article/1') - self.assertEqual('1', u.path_segment(2)) - - -class BuilderTests(TestCase): - - def test_setting_list_as_query_params(self): - first = URL.from_string('?q=testing') - second = URL().query_params(first.query_params()) - self.assertEqual(first.query(), second.query()) - - def test_add_path_segment(self): - url = URL('http://example.com').add_path_segment('one')\ - .add_path_segment('two')\ - .add_path_segment('three') - self.assertEqual('/one/two/three', url.path()) - - def test_setting_single_item_list_as_query_param(self): - url = URL().query_param('q', ['testing']) - self.assertEqual('testing', url.query_param('q')) - - def test_setting_list_as_query_param(self): - url = URL().query_param('q', ['testing', 'eggs']) - self.assertEqual(['testing', 'eggs'], url.query_param('q', as_list=True)) - - def test_build_relative_url(self): - url = URL().path('searching') - self.assertEqual('/searching', str(url)) - - def test_build_relative_url_with_params(self): - URL().path('/searching').query_param('q', 'testing') - - def test_build_with_path_segments(self): - u = URL().path_segments(['path', 'to', 'page']) - self.assertEqual('/path/to/page', u.as_string()) - - def test_set_fragment(self): - url = URL.from_string('http://www.google.com/').fragment('hello') - self.assertEqual('hello', url.fragment()) - - def test_set_scheme(self): - url = URL.from_string('http://www.google.com/').scheme('https') - self.assertEqual('https', url.scheme()) - - def test_set_host(self): - url = URL.from_string('http://www.google.com/').host('maps.google.com') - self.assertEqual('maps.google.com', url.host()) - - def test_set_path(self): - url = URL.from_string('http://www.google.com/').path('search') - self.assertEqual('/search', url.path()) - - def test_set_path_with_special_chars(self): - url = URL.from_string('http://www.google.com/').path('search something') - self.assertEqual('/search%20something', url.path()) - - def test_set_query(self): - url = URL.from_string('http://www.google.com/').query('q=testing') - self.assertEqual('testing', url.query_param('q')) - - def test_set_port(self): - url = URL.from_string('http://www.google.com/').port(8000) - self.assertEqual(8000, url.port()) - - def test_set_path_segment(self): - url = URL.from_string('http://www.google.com/a/b/c/').path_segment(1, 'd') - self.assertEqual('/a/d/c/', url.path()) - - def test_set_query_param(self): - url = URL.from_string('http://www.google.com/search').query_param('q', 'testing') - self.assertEqual('testing', url.query_param('q')) - - def test_set_query_params(self): - url = URL.from_string('http://www.google.com/search').query_params({'q': 'testing'}) - self.assertEqual('testing', url.query_param('q')) - - def test_set_subdomain(self): - url = URL.from_string('http://www.google.com/search').subdomain(0, 'www2') - self.assertEqual('www2', url.subdomain(0)) - - def test_set_subdomains(self): - url = URL().subdomains(['www', 'google', 'com']) - self.assertEqual('http://www.google.com/', str(url)) - - def test_remove_domain(self): - url = URL('https://example.com/hello?x=100') - new = url.domain('') - self.assertEqual('/hello?x=100', str(new)) - - def test_remove_port(self): - url = URL('https://example.com/hello?x=100') - new = url.port('') - self.assertEqual('https://example.com/hello?x=100', str(new)) - - -class MiscTests(TestCase): - - def test_url_can_be_used_as_key_in_dict(self): - u = URL.from_string('http://google.com') - {u: 0} - - def test_equality_comparison(self): - self.assertEqual(URL.from_string('http://google.com'), - URL.from_string('http://google.com')) - - def test_negative_equality_comparison(self): - self.assertNotEqual(URL.from_string('http://google.com'), - URL.from_string('https://google.com')) - - def test_urls_are_hashable(self): - u = URL.from_string('http://google.com') - hash(u) - - def test_urls_can_be_pickled(self): - u = URL.from_string('http://google.com') - pickle.dumps(u) - - def test_urls_can_be_pickled_and_restored(self): - u = URL.from_string('http://google.com') - pickled = pickle.dumps(u) - v = pickle.loads(pickled) - self.assertEqual(u, v) - - -class QueryParamListTests(TestCase): - - def test_set_list(self): - base = URL('http://127.0.0.1/') - url = base.query_param('q', ['something', 'else']) - values = url.query_param('q', as_list=True) - self.assertEqual(['something', 'else'], values) - - def test_remove_item_from_list(self): - base = URL('http://127.0.0.1/?q=a&q=b') - url = base.remove_query_param('q', 'a') - values = url.query_param('q', as_list=True) - self.assertEqual(['b'], values) - - def test_append_to_existing_list(self): - base = URL('http://127.0.0.1/?q=a&q=b') - url = base.append_query_param('q', 'c') - values = url.query_param('q', as_list=True) - self.assertEqual(['a', 'b', 'c'], values) - - def test_append_to_nonexistant_list(self): - base = URL('http://127.0.0.1/?q=a&q=b') - url = base.append_query_param('p', 'c') - values = url.query_param('p', as_list=True) - self.assertEqual(['c'], values) - - -class UnicodeExtractionTests(TestCase): - def setUp(self): - self.unicode_param = '????????????????' - # Python 2.6 requires bytes for quote - self.urlencoded_param = quote(self.unicode_param.encode('utf8')) - url = 'http://www.google.com/blog/article/1?q=' + self.urlencoded_param - self.ascii_url = URL.from_string(url.encode('ascii')) - # django request.get_full_path() returns url as unicode - self.unicode_url = URL.from_string(url) - - def test_get_query_param_ascii_url(self): - param = self.ascii_url.query_param('q') - self.assertEqual(param, self.unicode_param) - - def test_get_query_param_unicode_url(self): - param = self.unicode_url.query_param('q') - self.assertEqual(param, self.unicode_param) - - -class UnicodeTests(TestCase): - - def setUp(self): - self.base = URL('http://127.0.0.1/') - self.text = u'??' - self.bytes = self.text.encode('utf8') - - def test_set_unicode_query_param_value(self): - url = self.base.query_param('q', self.text) - self.assertEqual(self.text, url.query_param('q')) - - def test_set_bytestring_query_param_value(self): - url = self.base.query_param('q', self.bytes) - self.assertEqual(self.text, url.query_param('q')) - - def test_set_unicode_query_param_key(self): - url = self.base.query_param(self.text, 'value') - self.assertEqual('value', url.query_param(self.text)) - - def test_set_bytestring_query_param_key(self): - url = self.base.query_param(self.bytes, 'value') - self.assertEqual('value', url.query_param(self.text)) - - def test_append_unicode_query_param(self): - url = self.base.append_query_param('q', self.text) - self.assertEqual(self.text, url.query_param('q')) - - def test_append_bytestring_query_param(self): - url = self.base.append_query_param('q', self.bytes) - self.assertEqual(self.text, url.query_param('q')) - - def test_set_unicode_query_params(self): - url = self.base.query_params({'q': self.text}) - self.assertEqual(self.text, url.query_param('q')) - - def test_set_bytestring_query_params(self): - url = self.base.query_params({'q': self.bytes}) - self.assertEqual(self.text, url.query_param('q')) - - def test_add_unicode_path_segment(self): - url = self.base.add_path_segment(self.text) - self.assertEqual(self.text, url.path_segment(0)) - - def test_add_bytestring_path_segment(self): - url = self.base.add_path_segment(self.bytes) - self.assertEqual(self.text, url.path_segment(0)) - - def test_add_unicode_fragment(self): - url = self.base.fragment(self.text) - self.assertEqual(self.text, url.fragment()) - - -class QuotedSlashesTests(TestCase): - - def test_slashes_in_path(self): - u = URL().add_path_segment('test/egg') - self.assertEqual(u.as_string(), '/test%2Fegg') - - def test_slashes_in_path(self): - u = URL('/something').path_segment(0, 'test/egg') - self.assertEqual(u.as_string(), '/test%2Fegg') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/tests/utils_tests.py new/purl-1.6/tests/utils_tests.py --- old/purl-1.5/tests/utils_tests.py 2019-03-10 21:51:02.000000000 +0100 +++ new/purl-1.6/tests/utils_tests.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,12 +0,0 @@ -from unittest import TestCase - -from purl.url import to_utf8, to_unicode - - -class TestUnicodeHelper(TestCase): - - def test_convert_int_to_bytes(self): - self.assertEqual('1024', to_utf8(1024)) - - def test_convert_int_to_unicode(self): - self.assertEqual(u'1024', to_unicode(1024)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/purl-1.5/tox.ini new/purl-1.6/tox.ini --- old/purl-1.5/tox.ini 2019-03-10 21:51:02.000000000 +0100 +++ new/purl-1.6/tox.ini 2021-05-15 23:00:41.000000000 +0200 @@ -4,8 +4,8 @@ # and then run "tox" from this directory. [tox] -envlist = py26, py27, py34, pypy +envlist = py26, py27, py36, py37, py38, pypy, pypy3 [testenv] -commands = nosetests [] +commands = pytest deps = -r{toxinidir}/requirements.txt