Drop python 2.7
This commit is contained in:
parent
0756441d05
commit
3b61c37778
@ -1,6 +1,5 @@
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.5"
|
||||
- "3.6"
|
||||
- "3.7"
|
||||
|
||||
@ -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
4
README
@ -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**::
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
|
||||
@ -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)" %
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
11
resync/url_or_file_open.py
Normal file
11
resync/url_or_file_open.py
Normal 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))
|
||||
@ -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):
|
||||
|
||||
@ -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')
|
||||
|
||||
Loading…
Reference in New Issue
Block a user