Drop python 2.7

This commit is contained in:
Simeon Warner 2020-12-10 13:00:32 -05:00
parent 0756441d05
commit 3b61c37778
16 changed files with 44 additions and 62 deletions

View File

@ -1,6 +1,5 @@
language: python
python:
- "2.7"
- "3.5"
- "3.6"
- "3.7"

View File

@ -6,9 +6,10 @@ core specification version. Versions 1.0.x implement the v1.0
ResourceSync specification which was standardized as ANSI/NISO Z39.99-2014
<http://www.openarchives.org/rs/1.0/toc>.
v1.0.10 ???
* Move and rename command line clients: bin/resync -> resync.pl and bin/resync-explorer -> resync-explorer.py
* Drop Python 3.3 & 3.4 from tests, add 3.7. Fix various new warnings from 3.7 (more work is required to support 3.8)
v2.0.0 ???
* Drop support Python 2.7
* Rename command line clients: bin/resync -> resync.pl and bin/resync-explorer -> resync-explorer.py
* Drop Python 2.7, 3.3 & 3.4 from tests, add 3.7. Fix various new warnings from 3.7 (more work is required to support 3.8)
* Switch from pep8 to pycodestyle in tests
* Move libraries to support tests into test/testlib

4
README
View File

@ -59,7 +59,9 @@ Typical library use in a destination (get and examine a Capability List)::
Installation
------------
The client and library are designed to work with Python 2.7, 3.5, 3.6 and 3.7.
The client and library are designed to work with Python 3.5 and up. (The
last version supporting Python 2.7 was `1.0.9, also on PyPI
<https://pypi.org/project/resync/1.0.9/>`_.)
**Automatic installation**::

View File

@ -5,7 +5,7 @@ each capability. The Capability List object may also contain metadata
and links like other lists.
"""
import collections
import collections.abc
from .resource import Resource
from .resource_set import ResourceSet
@ -88,7 +88,7 @@ class CapabilityList(ListBase):
See add_capability() for normal method of adding capabilities.
"""
if isinstance(resource, collections.Iterable):
if isinstance(resource, collections.abc.Iterable):
for r in resource:
self.resources.add(r, replace)
else:

View File

@ -15,7 +15,7 @@ ChangeList containing descriptions pertaining to that
particular resource.
"""
import collections
import collections.abc
from .list_base_with_index import ListBaseWithIndex
from .resource import Resource, ChangeTypeError
@ -45,7 +45,7 @@ class ChangeList(ListBaseWithIndex):
Allows multiple resource_change objects for the same
resource (ie. URI) and preserves the order of addition.
"""
if isinstance(resource, collections.Iterable):
if isinstance(resource, collections.abc.Iterable):
for r in resource:
self.add_if_changed(r)
else:

View File

@ -25,8 +25,9 @@ from .resource import Resource
from .url_authority import UrlAuthority
from .hashes import Hashes
from .client_state import ClientState
from .client_utils import ClientFatalError, ClientError, url_or_file_open
from .client_utils import ClientFatalError, ClientError
from .list_base_with_index import ListBaseIndexError
from .url_or_file_open import url_or_file_open
from .w3c_datetime import str_to_datetime, datetime_to_str

View File

@ -1,21 +1,6 @@
"""ResourceSync Client Utilities.
Factor out code shared by both the resync and resync-explorer
clients.
Copyright 2012-2018 Simeon Warner
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License
Code shared by both the resync and resync-explorer clients.
"""
try: # python3
@ -178,10 +163,3 @@ def parse_capability_lists(cls_str):
Input string of the form: uri,uri
"""
return(cls_str.split(','))
def url_or_file_open(uri):
"""Wrapper around urlopen() to prepend file: if no scheme provided."""
if (not re.match(r'''\w+:''', uri)):
uri = 'file:' + uri
return(urlopen(uri))

View File

@ -23,8 +23,9 @@ from .mapper import Mapper
from .sitemap import Sitemap
from .client import Client, ClientFatalError
from .client_state import ClientState
from .client_utils import ClientFatalError, url_or_file_open
from .client_utils import ClientFatalError
from .resource import Resource
from .url_or_file_open import url_or_file_open
from .w3c_datetime import str_to_datetime, datetime_to_str

View File

@ -5,25 +5,16 @@ intended as the base class for ResourceList, ChangeList,
CapabilityList etc.. Adds common read() and write() methods.
"""
import collections
import os
from datetime import datetime
import io
import os
import re
import sys
try: # python2
# Must try this first as io also exists in python2
# but in the wrong one!
import StringIO as io
except ImportError: # python3
import io
import logging
try: # python3
from urllib.request import URLopener
except ImportError: # pragma: no cover python2
from urllib import URLopener # pragma: no cover
from .resource_container import ResourceContainer
from .sitemap import Sitemap
from .url_or_file_open import url_or_file_open
class ListBase(ResourceContainer):
@ -96,7 +87,7 @@ class ListBase(ResourceContainer):
"""
if (uri is not None):
try:
fh = URLopener().open(uri)
fh = url_or_file_open(uri)
except IOError as e:
raise Exception(
"Failed to load sitemap/sitemapindex from %s (%s)" %

View File

@ -11,17 +11,14 @@ from datetime import datetime
import re
import sys
import itertools
try: # python3
from urllib.request import URLopener
except ImportError: # python2
from urllib import URLopener
from .hashes import Hashes
from .list_base import ListBase
from .mapper import Mapper, MapperError
from .resource import Resource
from .sitemap import Sitemap
from .mapper import Mapper, MapperError
from .url_authority import UrlAuthority
from .hashes import Hashes
from .url_or_file_open import url_or_file_open
class ListBaseWithIndex(ListBase):
@ -84,7 +81,7 @@ class ListBaseWithIndex(ListBase):
are mapped to the filesystem also.
"""
try:
fh = URLopener().open(uri)
fh = url_or_file_open(uri)
self.num_files += 1
except IOError as e:
raise IOError(
@ -156,7 +153,7 @@ class ListBaseWithIndex(ListBase):
"The sitemapindex (%s) refers to sitemap at a location it does not have authority over (%s)" %
(sitemapindex_uri, sitemap_uri))
try:
fh = URLopener().open(sitemap_uri)
fh = url_or_file_open(sitemap_uri)
self.num_files += 1
except IOError as e:
raise ListBaseIndexError(

View File

@ -10,7 +10,7 @@ base class for ResourceList, ChangeList, etc. This class provides
only the data storage and manipulation, the ListBase class
adds IO.
"""
import collections
import collections.abc
from .w3c_datetime import datetime_to_str
@ -189,7 +189,7 @@ class ResourceContainer(object):
Must be implemented in derived class.
"""
if isinstance(resource, collections.Iterable):
if isinstance(resource, collections.abc.Iterable):
for r in resource:
self.resources.append(r)
else:

View File

@ -17,7 +17,7 @@ Described in specification at:
http://www.openarchives.org/rs/resourcesync#DescResources
"""
import collections
import collections.abc
import os
from datetime import datetime
import re
@ -153,7 +153,7 @@ class ResourceList(ListBaseWithIndex):
Will throw a ValueError if the resource (ie. same uri) already
exists in the ResourceList, unless replace=True.
"""
if isinstance(resource, collections.Iterable):
if isinstance(resource, collections.abc.Iterable):
for r in resource:
self.resources.add(r, replace)
else:

View File

@ -21,7 +21,7 @@ documents.
See: http://www.openarchives.org/rs/resourcesync#SourceDesc
"""
import collections
import collections.abc
from resync.resource import Resource
from resync.resource_set import ResourceSet
@ -51,7 +51,7 @@ class SourceDescription(ListBaseWithIndex):
Will throw a ValueError if the resource (ie. same uri) already
exists in the capability_list, unless replace=True.
"""
if isinstance(resource, collections.Iterable):
if isinstance(resource, collections.abc.Iterable):
for r in resource:
self.resources.add(r, replace)
else:

View File

@ -0,0 +1,11 @@
"""Local version of urlopen that supports files+web and auth."""
import re
from urllib.request import urlopen
def url_or_file_open(uri):
"""Wrapper around urlopen() to prepend file: if no scheme provided."""
if (not re.match(r'''\w+:''', uri)):
uri = 'file:' + uri
return(urlopen(uri))

View File

@ -34,6 +34,7 @@ class TestCapabilityList(unittest.TestCase):
caps.add_capability(rl, "http://example.org/resourcelist.xml")
caps.md['from'] = "2013-02-07T22:39:00"
self.assertEqual(len(caps), 1)
print(caps.as_xml())
self.assertEqual(caps.as_xml(), '<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:rs="http://www.openarchives.org/rs/terms/"><rs:md capability="capabilitylist" from="2013-02-07T22:39:00" /><url><loc>http://example.org/resourcelist.xml</loc><rs:md capability="resourcelist" /></url></urlset>')
def test03_multiple(self):

View File

@ -26,4 +26,4 @@ class TestClientLinkOptions(unittest.TestCase):
def test02_error(self):
"""Bad parameter."""
err = run_resync_explorer([])[1]
self.assertRegexpMatches(err, b'FatalError: No source information')
self.assertRegex(err, b'FatalError: No source information')