Fix errors with 3.6, tidy
This commit is contained in:
parent
7d2181a31a
commit
a15b4c50ce
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@
|
|||||||
build
|
build
|
||||||
dist
|
dist
|
||||||
MANIFEST
|
MANIFEST
|
||||||
|
.tox
|
||||||
.eggs
|
.eggs
|
||||||
*.egg
|
*.egg
|
||||||
# Testing
|
# Testing
|
||||||
|
|||||||
@ -4,15 +4,14 @@ python:
|
|||||||
- "3.5"
|
- "3.5"
|
||||||
- "3.6"
|
- "3.6"
|
||||||
- "3.7"
|
- "3.7"
|
||||||
- "3.8"
|
|
||||||
install:
|
install:
|
||||||
- pip install requests
|
- pip install requests
|
||||||
- pip install python-dateutil
|
- pip install python-dateutil
|
||||||
- pip install coveralls pep8 pep257 restructuredtext_lint testfixtures
|
- pip install coveralls pycodestyle pep257 restructuredtext_lint testfixtures
|
||||||
- python setup.py install
|
- python setup.py install
|
||||||
script:
|
script:
|
||||||
- python setup.py test
|
- python setup.py test
|
||||||
- pep8 --ignore=E501 resync tests bin/resync bin/resync-explorer
|
- pycodestyle --ignore=E501,W503 resync tests bin/resync bin/resync-explorer
|
||||||
- pep257 resync tests bin/resync bin/resync-explorer
|
- pep257 resync tests bin/resync bin/resync-explorer
|
||||||
- rst-lint README
|
- rst-lint README
|
||||||
- coverage run --source=resync setup.py test
|
- coverage run --source=resync setup.py test
|
||||||
|
|||||||
@ -6,9 +6,11 @@ core specification version. Versions 1.0.x implement the v1.0
|
|||||||
ResourceSync specification which was standardized as ANSI/NISO Z39.99-2014
|
ResourceSync specification which was standardized as ANSI/NISO Z39.99-2014
|
||||||
<http://www.openarchives.org/rs/1.0/toc>.
|
<http://www.openarchives.org/rs/1.0/toc>.
|
||||||
|
|
||||||
=======
|
|
||||||
v1.0.10 ???
|
v1.0.10 ???
|
||||||
* Drop Pyhton 3.3 & 3.4 from tests, add 3.7 & 3.8
|
* 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)
|
||||||
|
* Switch from pep8 to pycodestyle in tests
|
||||||
|
* Move libraries to support tests into test/testlib
|
||||||
|
|
||||||
v1.0.9 2018-10-23
|
v1.0.9 2018-10-23
|
||||||
* Add -t/--tries and -T/--timeout options (https://github.com/resync/resync/issues/34)
|
* Add -t/--tries and -T/--timeout options (https://github.com/resync/resync/issues/34)
|
||||||
|
|||||||
10
README
10
README
@ -23,16 +23,16 @@ Client usage
|
|||||||
Typical client usage to synchronize from a source at
|
Typical client usage to synchronize from a source at
|
||||||
``http://source.example.com/`` to a set of local files would be::
|
``http://source.example.com/`` to a set of local files would be::
|
||||||
|
|
||||||
resync http://source.example.com/
|
resync.py http://source.example.com/
|
||||||
|
|
||||||
which will create or update a local directory ``./source.example.com``.
|
which will create or update a local directory ``./source.example.com``.
|
||||||
Alternatively, the destination directory may be specified explicitly::
|
Alternatively, the destination directory may be specified explicitly::
|
||||||
|
|
||||||
resync http://source.example.com/ /tmp/my_copy
|
resync.py http://source.example.com/ /tmp/my_copy
|
||||||
|
|
||||||
Option details and a number of different modes are described with::
|
Option details and a number of different modes are described with::
|
||||||
|
|
||||||
resync -h
|
resync.py -h
|
||||||
|
|
||||||
Library usage
|
Library usage
|
||||||
-------------
|
-------------
|
||||||
@ -59,7 +59,7 @@ Typical library use in a destination (get and examine a Capability List)::
|
|||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
|
|
||||||
The client and library are designed to work with Python 2.7, 3.5, 3.6, 3.7 and 3.8.
|
The client and library are designed to work with Python 2.7, 3.5, 3.6 and 3.7.
|
||||||
|
|
||||||
**Automatic installation**::
|
**Automatic installation**::
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ rsync is listed in `PyPI
|
|||||||
sudo python setup.py install
|
sudo python setup.py install
|
||||||
|
|
||||||
This will install the library code in the appropriate place within
|
This will install the library code in the appropriate place within
|
||||||
your python setup, and the client ``resync`` in an appropriate system
|
your python setup, and the client ``resync.py`` in an appropriate system
|
||||||
path (perhaps ``/usr/local/bin`` or ``/usr/bin`` depending on your system).
|
path (perhaps ``/usr/local/bin`` or ``/usr/bin`` depending on your system).
|
||||||
|
|
||||||
The source code is maintained on `Github
|
The source code is maintained on `Github
|
||||||
|
|||||||
@ -125,5 +125,6 @@ def main():
|
|||||||
except ClientFatalError as e:
|
except ClientFatalError as e:
|
||||||
sys.stderr.write("\nFatalError: " + str(e) + "\n")
|
sys.stderr.write("\nFatalError: " + str(e) + "\n")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
@ -184,10 +184,10 @@ def main():
|
|||||||
|
|
||||||
# Implement exclusive arguments and default --baseline (support for exclusive
|
# Implement exclusive arguments and default --baseline (support for exclusive
|
||||||
# groups in argparse is incomplete is python2.6)
|
# groups in argparse is incomplete is python2.6)
|
||||||
if (not args.baseline and not args.incremental and not args.audit and
|
if (not args.baseline and not args.incremental and not args.audit
|
||||||
not args.parse and not args.write_resourcelist and not args.write_changelist and
|
and not args.parse and not args.write_resourcelist and not args.write_changelist
|
||||||
not args.write_capabilitylist and not args.write_sourcedescription and
|
and not args.write_capabilitylist and not args.write_sourcedescription
|
||||||
not args.write_resourcedump and not args.write_changedump):
|
and not args.write_resourcedump and not args.write_changedump):
|
||||||
if (len(map) == 0):
|
if (len(map) == 0):
|
||||||
p.error("No arguments specified (use -h for help)")
|
p.error("No arguments specified (use -h for help)")
|
||||||
return
|
return
|
||||||
@ -241,9 +241,9 @@ def main():
|
|||||||
# Links apply to anything that writes sitemaps
|
# Links apply to anything that writes sitemaps
|
||||||
links = parse_links(args.link)
|
links = parse_links(args.link)
|
||||||
# Add specific links is appropriate cases
|
# Add specific links is appropriate cases
|
||||||
if (args.capabilitylist_link and
|
if (args.capabilitylist_link
|
||||||
not args.write_capabilitylist and
|
and not args.write_capabilitylist
|
||||||
not args.write_sourcedescription):
|
and not args.write_sourcedescription):
|
||||||
# rel="up" to Capability List in all but Capability List
|
# rel="up" to Capability List in all but Capability List
|
||||||
# and Source Description
|
# and Source Description
|
||||||
links.insert(0, {'rel': 'up', 'href': args.capabilitylist_link})
|
links.insert(0, {'rel': 'up', 'href': args.capabilitylist_link})
|
||||||
@ -299,5 +299,6 @@ def main():
|
|||||||
except ClientFatalError as e:
|
except ClientFatalError as e:
|
||||||
sys.stderr.write("\nFatalError: " + str(e) + "\n")
|
sys.stderr.write("\nFatalError: " + str(e) + "\n")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
@ -1,15 +1,15 @@
|
|||||||
"""Module config for resync."""
|
"""Module config for resync."""
|
||||||
|
|
||||||
from resync._version import __version__
|
from ._version import __version__
|
||||||
|
|
||||||
# Enable easy import for core classes, e.g.
|
# Enable easy import for core classes, e.g.
|
||||||
# from resync import Resource
|
# from resync import Resource
|
||||||
from resync.source_description import SourceDescription
|
from .source_description import SourceDescription
|
||||||
from resync.capability_list import CapabilityList
|
from .capability_list import CapabilityList
|
||||||
from resync.resource_list import ResourceList
|
from .resource_list import ResourceList
|
||||||
from resync.change_list import ChangeList
|
from .change_list import ChangeList
|
||||||
from resync.resource_dump import ResourceDump
|
from .resource_dump import ResourceDump
|
||||||
from resync.resource_dump_manifest import ResourceDumpManifest
|
from .resource_dump_manifest import ResourceDumpManifest
|
||||||
from resync.change_dump import ChangeDump
|
from .change_dump import ChangeDump
|
||||||
from resync.archives import ResourceListArchive, ResourceDumpArchive, ChangeListArchive, ChangeDumpArchive
|
from .archives import ResourceListArchive, ResourceDumpArchive, ChangeListArchive, ChangeDumpArchive
|
||||||
from resync.resource import Resource
|
from .resource import Resource
|
||||||
|
|||||||
@ -107,7 +107,7 @@ class ListBase(ResourceContainer):
|
|||||||
# Legacy support for str argument, see
|
# Legacy support for str argument, see
|
||||||
# https://github.com/resync/resync/pull/21
|
# https://github.com/resync/resync/pull/21
|
||||||
# One test for this in tests/test_list_base.py
|
# One test for this in tests/test_list_base.py
|
||||||
self.logger.warn(
|
self.logger.warning(
|
||||||
"Legacy parse(str=...), use parse(str_data=...) instead")
|
"Legacy parse(str=...), use parse(str_data=...) instead")
|
||||||
fh = io.StringIO(kwargs['str'])
|
fh = io.StringIO(kwargs['str'])
|
||||||
if (fh is None):
|
if (fh is None):
|
||||||
|
|||||||
@ -43,25 +43,25 @@ class Mapper():
|
|||||||
source base URI. In the case that the source base URI is a local
|
source base URI. In the case that the source base URI is a local
|
||||||
path already then an indentity mapping is used.
|
path already then an indentity mapping is used.
|
||||||
"""
|
"""
|
||||||
if (use_default_path and
|
if (use_default_path
|
||||||
len(mappings) == 1 and
|
and len(mappings) == 1
|
||||||
re.search(r"=", mappings[0]) is None):
|
and re.search(r"=", mappings[0]) is None):
|
||||||
path = self.path_from_uri(mappings[0])
|
path = self.path_from_uri(mappings[0])
|
||||||
self.logger.warning("Using URI mapping: %s -> %s" %
|
self.logger.warning("Using URI mapping: %s -> %s" %
|
||||||
(mappings[0], path))
|
(mappings[0], path))
|
||||||
self.mappings.append(Map(mappings[0], path))
|
self.mappings.append(Map(mappings[0], path))
|
||||||
elif (len(mappings) == 2 and
|
elif (len(mappings) == 2
|
||||||
re.search(r"=", mappings[0]) is None and
|
and re.search(r"=", mappings[0]) is None
|
||||||
re.search(r"=", mappings[1]) is None):
|
and re.search(r"=", mappings[1]) is None):
|
||||||
self.mappings.append(Map(mappings[0], mappings[1]))
|
self.mappings.append(Map(mappings[0], mappings[1]))
|
||||||
else:
|
else:
|
||||||
for mapping in mappings:
|
for mapping in mappings:
|
||||||
l = mapping.split('=')
|
entry = mapping.split('=')
|
||||||
if (len(l) != 2):
|
if (len(entry) != 2):
|
||||||
raise MapperError(
|
raise MapperError(
|
||||||
"Bad mapping argument (%s), got %s" %
|
"Bad mapping argument (%s), got %s" %
|
||||||
(mapping, str(l)))
|
(mapping, str(entry)))
|
||||||
(src_uri, dst_path) = l
|
(src_uri, dst_path) = entry
|
||||||
# Check for dupes
|
# Check for dupes
|
||||||
for map in self.mappings:
|
for map in self.mappings:
|
||||||
if (src_uri == map.src_uri):
|
if (src_uri == map.src_uri):
|
||||||
@ -129,10 +129,10 @@ class Mapper():
|
|||||||
if (netloc == ''):
|
if (netloc == ''):
|
||||||
return(uri)
|
return(uri)
|
||||||
path = '/'.join([netloc, path])
|
path = '/'.join([netloc, path])
|
||||||
path = re.sub('[^\w\-\.]', '_', path)
|
path = re.sub(r'[^\w\-\.]', '_', path)
|
||||||
path = re.sub('__+', '_', path)
|
path = re.sub(r'__+', '_', path)
|
||||||
path = re.sub('[_\.]+$', '', path)
|
path = re.sub(r'[_\.]+$', '', path)
|
||||||
path = re.sub('^[_\.]+', '', path)
|
path = re.sub(r'^[_\.]+', '', path)
|
||||||
return(path)
|
return(path)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
import re
|
import re
|
||||||
try: # python3
|
try: # python3
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
except: # python2
|
except ImportError: # python2
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
from posixpath import basename
|
from posixpath import basename
|
||||||
from .w3c_datetime import str_to_datetime, datetime_to_str
|
from .w3c_datetime import str_to_datetime, datetime_to_str
|
||||||
@ -149,8 +149,8 @@ class Resource(object):
|
|||||||
the idea of extra properties.
|
the idea of extra properties.
|
||||||
"""
|
"""
|
||||||
# Add validity check for self.change
|
# Add validity check for self.change
|
||||||
if (prop == 'change' and Resource.CHANGE_TYPES and
|
if (prop == 'change' and Resource.CHANGE_TYPES
|
||||||
value is not None and value not in Resource.CHANGE_TYPES):
|
and value is not None and value not in Resource.CHANGE_TYPES):
|
||||||
raise ChangeTypeError(value)
|
raise ChangeTypeError(value)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
@ -422,15 +422,15 @@ class Resource(object):
|
|||||||
return(False)
|
return(False)
|
||||||
if (self.timestamp is not None or other.timestamp is not None):
|
if (self.timestamp is not None or other.timestamp is not None):
|
||||||
# not equal if only one timestamp specified
|
# not equal if only one timestamp specified
|
||||||
if (self.timestamp is None or
|
if (self.timestamp is None
|
||||||
other.timestamp is None or
|
or other.timestamp is None
|
||||||
abs(self.timestamp - other.timestamp) >= delta):
|
or abs(self.timestamp - other.timestamp) >= delta):
|
||||||
return(False)
|
return(False)
|
||||||
if ((self.md5 is not None and other.md5 is not None) and
|
if ((self.md5 is not None and other.md5 is not None)
|
||||||
self.md5 != other.md5):
|
and self.md5 != other.md5):
|
||||||
return(False)
|
return(False)
|
||||||
if ((self.length is not None and other.length is not None) and
|
if ((self.length is not None and other.length is not None)
|
||||||
self.length != other.length):
|
and self.length != other.length):
|
||||||
return(False)
|
return(False)
|
||||||
return(True)
|
return(True)
|
||||||
|
|
||||||
|
|||||||
@ -114,8 +114,7 @@ class ResourceContainer(object):
|
|||||||
def link(self, rel):
|
def link(self, rel):
|
||||||
"""Look for link with specified rel, return else None."""
|
"""Look for link with specified rel, return else None."""
|
||||||
for link in self.ln:
|
for link in self.ln:
|
||||||
if ('rel' in link and
|
if ('rel' in link and link['rel'] == rel):
|
||||||
link['rel'] == rel):
|
|
||||||
return(link)
|
return(link)
|
||||||
return(None)
|
return(None)
|
||||||
|
|
||||||
|
|||||||
@ -50,7 +50,7 @@ class ResourceListBuilder():
|
|||||||
self.set_path = set_path
|
self.set_path = set_path
|
||||||
self.set_hashes = set_hashes if (set_hashes and len(set_hashes) > 0) else None
|
self.set_hashes = set_hashes if (set_hashes and len(set_hashes) > 0) else None
|
||||||
self.set_length = set_length
|
self.set_length = set_length
|
||||||
self.exclude_files = ['sitemap\d{0,5}.xml']
|
self.exclude_files = [r'sitemap\d{0,5}.xml']
|
||||||
self.exclude_dirs = ['CVS', '.git']
|
self.exclude_dirs = ['CVS', '.git']
|
||||||
self.include_symlinks = False
|
self.include_symlinks = False
|
||||||
# Used internally only:
|
# Used internally only:
|
||||||
|
|||||||
@ -270,8 +270,7 @@ class Sitemap(object):
|
|||||||
md = Element('rs:md', md_atts)
|
md = Element('rs:md', md_atts)
|
||||||
e.append(md)
|
e.append(md)
|
||||||
# add any <rs:ln>
|
# add any <rs:ln>
|
||||||
if (hasattr(resource, 'ln') and
|
if (hasattr(resource, 'ln') and resource.ln is not None):
|
||||||
resource.ln is not None):
|
|
||||||
for ln in resource.ln:
|
for ln in resource.ln:
|
||||||
self.add_element_with_atts_to_etree(e, 'rs:ln', ln)
|
self.add_element_with_atts_to_etree(e, 'rs:ln', ln)
|
||||||
if (self.pretty_xml):
|
if (self.pretty_xml):
|
||||||
|
|||||||
@ -70,8 +70,7 @@ class UrlAuthority(object):
|
|||||||
# Maybe should allow parallel for 3+ components, eg. a.example.org,
|
# Maybe should allow parallel for 3+ components, eg. a.example.org,
|
||||||
# b.example.org
|
# b.example.org
|
||||||
path = os.path.dirname(s.path)
|
path = os.path.dirname(s.path)
|
||||||
if (self.strict and
|
if (self.strict and path != self.master_path
|
||||||
path != self.master_path and
|
and not path.startswith(self.master_path)):
|
||||||
not path.startswith(self.master_path)):
|
|
||||||
return(False)
|
return(False)
|
||||||
return(True)
|
return(True)
|
||||||
|
|||||||
@ -102,7 +102,7 @@ def str_to_datetime(s, context='datetime'):
|
|||||||
# with dt.tzinfo module but this has variation in behavior
|
# with dt.tzinfo module but this has variation in behavior
|
||||||
# between python 2.6 and 2.7... so do here for now
|
# between python 2.6 and 2.7... so do here for now
|
||||||
m = re.match(r"(\d\d\d\d\-\d\d\-\d\dT\d\d:\d\d(:\d\d)?)(Z|([+-])"
|
m = re.match(r"(\d\d\d\d\-\d\d\-\d\dT\d\d:\d\d(:\d\d)?)(Z|([+-])"
|
||||||
"(\d\d):(\d\d))$", s)
|
r"(\d\d):(\d\d))$", s)
|
||||||
if (m is None):
|
if (m is None):
|
||||||
raise ValueError("Bad datetime format (%s)" % s)
|
raise ValueError("Bad datetime format (%s)" % s)
|
||||||
str = m.group(1) + 'Z'
|
str = m.group(1) + 'Z'
|
||||||
|
|||||||
5
setup.py
5
setup.py
@ -40,17 +40,16 @@ setup(
|
|||||||
name='resync',
|
name='resync',
|
||||||
version=version,
|
version=version,
|
||||||
packages=['resync'],
|
packages=['resync'],
|
||||||
scripts=['bin/resync','bin/resync-explorer'],
|
scripts=['resync.py','resync-explorer.py'],
|
||||||
classifiers=["Development Status :: 4 - Beta",
|
classifiers=["Development Status :: 4 - Beta",
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"License :: OSI Approved :: Apache Software License",
|
"License :: OSI Approved :: Apache Software License",
|
||||||
"Operating System :: OS Independent", #is this true? know Linux & OS X ok
|
"Operating System :: OS Independent", #is this true? know Linux & OS X ok
|
||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
"Programming Language :: Python :: 2.7",
|
"Programming Language :: Python :: 2.7",
|
||||||
"Programming Language :: Python :: 3.3",
|
|
||||||
"Programming Language :: Python :: 3.4",
|
|
||||||
"Programming Language :: Python :: 3.5",
|
"Programming Language :: Python :: 3.5",
|
||||||
"Programming Language :: Python :: 3.6",
|
"Programming Language :: Python :: 3.6",
|
||||||
|
"Programming Language :: Python :: 3.7",
|
||||||
"Topic :: Internet :: WWW/HTTP",
|
"Topic :: Internet :: WWW/HTTP",
|
||||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||||
"Environment :: Web Environment"],
|
"Environment :: Web Environment"],
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
from tests.testcase_with_tmpdir import TestCase
|
from .testlib import TestCase, capture_stdout, webserver
|
||||||
from tests.capture_stdout import capture_stdout
|
|
||||||
from tests.webserver_context import webserver
|
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import re
|
import re
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import subprocess
|
|||||||
|
|
||||||
|
|
||||||
def run_resync(args):
|
def run_resync(args):
|
||||||
args.insert(0, 'bin/resync')
|
args.insert(0, './resync.py')
|
||||||
proc = subprocess.Popen(args, stdout=subprocess.PIPE)
|
proc = subprocess.Popen(args, stdout=subprocess.PIPE)
|
||||||
(out, err) = proc.communicate()
|
(out, err) = proc.communicate()
|
||||||
return(out)
|
return(out)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from tests.testcase_with_tmpdir import TestCase
|
from .testlib import TestCase
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import unittest
|
|
||||||
from resync.client_state import ClientState
|
from resync.client_state import ClientState
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from tests.testcase_with_tmpdir import TestCase
|
from .testlib import TestCase
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
from tests.testcase_with_tmpdir import TestCase
|
from .testlib import TestCase
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import unittest
|
|
||||||
import sys
|
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
from resync.dump import Dump, DumpError
|
from resync.dump import Dump, DumpError
|
||||||
|
|||||||
@ -169,11 +169,8 @@ class TestExamplesFromSpec(unittest.TestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
cl1.describedby, 'http://example.com/info_about_set1_of_resources.xml')
|
cl1.describedby, 'http://example.com/info_about_set1_of_resources.xml')
|
||||||
|
|
||||||
|
|
||||||
# BUILD EXAMPLES ---------------------------
|
|
||||||
|
|
||||||
def test_build_ex_01(self):
|
def test_build_ex_01(self):
|
||||||
"""Simple Resource List document """
|
"""Simple Resource List document"""
|
||||||
rl = ResourceList()
|
rl = ResourceList()
|
||||||
rl.md_at = '2013-01-03T09:00:00Z'
|
rl.md_at = '2013-01-03T09:00:00Z'
|
||||||
rl.add(Resource('http://example.com/res1'))
|
rl.add(Resource('http://example.com/res1'))
|
||||||
@ -182,7 +179,7 @@ class TestExamplesFromSpec(unittest.TestCase):
|
|||||||
self._assert_xml_equal(rl.as_xml(), ex_xml)
|
self._assert_xml_equal(rl.as_xml(), ex_xml)
|
||||||
|
|
||||||
def test_build_ex_02(self):
|
def test_build_ex_02(self):
|
||||||
"""Slightly more complex Resource List document """
|
"""Slightly more complex Resource List document"""
|
||||||
rl = ResourceList()
|
rl = ResourceList()
|
||||||
rl.md_at = '2013-01-03T09:00:00Z'
|
rl.md_at = '2013-01-03T09:00:00Z'
|
||||||
rl.add(Resource(uri='http://example.com/res1',
|
rl.add(Resource(uri='http://example.com/res1',
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from tests.capture_stdout import capture_stdout
|
from .testlib import capture_stdout
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import re
|
import re
|
||||||
|
|||||||
@ -10,7 +10,7 @@ except ImportError: # python3
|
|||||||
|
|
||||||
|
|
||||||
def run_resync_explorer(args):
|
def run_resync_explorer(args):
|
||||||
args.insert(0, 'bin/resync-explorer')
|
args.insert(0, './resync-explorer.py')
|
||||||
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
(out, err) = proc.communicate()
|
(out, err) = proc.communicate()
|
||||||
return(out, err)
|
return(out, err)
|
||||||
@ -21,7 +21,7 @@ class TestClientLinkOptions(unittest.TestCase):
|
|||||||
def test01_help(self):
|
def test01_help(self):
|
||||||
"""Check that it runs with -h."""
|
"""Check that it runs with -h."""
|
||||||
txt = run_resync_explorer(['-h'])[0]
|
txt = run_resync_explorer(['-h'])[0]
|
||||||
self.assertTrue(txt.startswith(b'Usage: resync-explorer [options] uri'))
|
self.assertTrue(txt.startswith(b'Usage: resync-explorer.py [options] uri'))
|
||||||
|
|
||||||
def test02_error(self):
|
def test02_error(self):
|
||||||
"""Bad parameter."""
|
"""Bad parameter."""
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from tests.testcase_with_tmpdir import TestCase
|
from .testlib import TestCase
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os.path
|
import os.path
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
"""Tests for resync.resource_dump."""
|
"""Tests for resync.resource_dump."""
|
||||||
from tests.testcase_with_tmpdir import TestCase
|
from .testlib import TestCase
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
try: # python2
|
try: # python2
|
||||||
# Must try this first as io also exists in python2
|
# Must try this first as io also exists in python2
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
from tests.testcase_with_tmpdir import TestCase
|
from .testlib import TestCase
|
||||||
import os.path
|
import os.path
|
||||||
try: # python2
|
try: # python2
|
||||||
# Must try this first as io also exists in python2
|
# Must try this first as io also exists in python2
|
||||||
# but in the wrong one!
|
# but is the wrong one!
|
||||||
import StringIO as io
|
import StringIO as io
|
||||||
except ImportError: # python3
|
except ImportError: # python3
|
||||||
import io
|
import io
|
||||||
|
|||||||
@ -65,37 +65,37 @@ class TestResourceListMultifile(unittest.TestCase):
|
|||||||
# check the two component sitemaps
|
# check the two component sitemaps
|
||||||
rl1 = ResourceList()
|
rl1 = ResourceList()
|
||||||
rl1.read(os.path.join(tempdir, 'sitemap00000.xml'))
|
rl1.read(os.path.join(tempdir, 'sitemap00000.xml'))
|
||||||
self.assertEquals(len(rl1), 2)
|
self.assertEqual(len(rl1), 2)
|
||||||
self.assertEquals(rl1.capability, 'resourcelist')
|
self.assertEqual(rl1.capability, 'resourcelist')
|
||||||
self.assertFalse(rl1.sitemapindex)
|
self.assertFalse(rl1.sitemapindex)
|
||||||
i = iter(rl1)
|
i = iter(rl1)
|
||||||
self.assertEquals(next(i).uri, 'http://localhost/a')
|
self.assertEqual(next(i).uri, 'http://localhost/a')
|
||||||
self.assertEquals(next(i).uri, 'http://localhost/b')
|
self.assertEqual(next(i).uri, 'http://localhost/b')
|
||||||
rl2 = ResourceList()
|
rl2 = ResourceList()
|
||||||
rl2.read(os.path.join(tempdir, 'sitemap00001.xml'))
|
rl2.read(os.path.join(tempdir, 'sitemap00001.xml'))
|
||||||
self.assertEquals(len(rl2), 2)
|
self.assertEqual(len(rl2), 2)
|
||||||
i = iter(rl2)
|
i = iter(rl2)
|
||||||
self.assertEquals(next(i).uri, 'http://localhost/c')
|
self.assertEqual(next(i).uri, 'http://localhost/c')
|
||||||
self.assertEquals(next(i).uri, 'http://localhost/d')
|
self.assertEqual(next(i).uri, 'http://localhost/d')
|
||||||
# check the sitemapindex (read just as index)
|
# check the sitemapindex (read just as index)
|
||||||
rli = ResourceList()
|
rli = ResourceList()
|
||||||
rli.read(os.path.join(tempdir, 'sitemap.xml'), index_only=True)
|
rli.read(os.path.join(tempdir, 'sitemap.xml'), index_only=True)
|
||||||
self.assertEquals(len(rli), 2)
|
self.assertEqual(len(rli), 2)
|
||||||
i = iter(rli)
|
i = iter(rli)
|
||||||
self.assertEquals(rli.capability, 'resourcelist')
|
self.assertEqual(rli.capability, 'resourcelist')
|
||||||
self.assertTrue(rli.sitemapindex)
|
self.assertTrue(rli.sitemapindex)
|
||||||
self.assertEquals(next(i).uri, 'http://localhost/sitemap00000.xml')
|
self.assertEqual(next(i).uri, 'http://localhost/sitemap00000.xml')
|
||||||
self.assertEquals(next(i).uri, 'http://localhost/sitemap00001.xml')
|
self.assertEqual(next(i).uri, 'http://localhost/sitemap00001.xml')
|
||||||
# check the sitemapindex and components
|
# check the sitemapindex and components
|
||||||
rli = ResourceList(mapper=rl.mapper)
|
rli = ResourceList(mapper=rl.mapper)
|
||||||
rli.read(os.path.join(tempdir, 'sitemap.xml'))
|
rli.read(os.path.join(tempdir, 'sitemap.xml'))
|
||||||
self.assertEquals(len(rli), 4)
|
self.assertEqual(len(rli), 4)
|
||||||
self.assertEquals(rli.capability, 'resourcelist')
|
self.assertEqual(rli.capability, 'resourcelist')
|
||||||
self.assertFalse(rli.sitemapindex)
|
self.assertFalse(rli.sitemapindex)
|
||||||
i = iter(rli)
|
i = iter(rli)
|
||||||
self.assertEquals(next(i).uri, 'http://localhost/a')
|
self.assertEqual(next(i).uri, 'http://localhost/a')
|
||||||
self.assertEquals(next(i).uri, 'http://localhost/b')
|
self.assertEqual(next(i).uri, 'http://localhost/b')
|
||||||
self.assertEquals(next(i).uri, 'http://localhost/c')
|
self.assertEqual(next(i).uri, 'http://localhost/c')
|
||||||
self.assertEquals(next(i).uri, 'http://localhost/d')
|
self.assertEqual(next(i).uri, 'http://localhost/d')
|
||||||
# cleanup tempdir
|
# cleanup tempdir
|
||||||
shutil.rmtree(tempdir)
|
shutil.rmtree(tempdir)
|
||||||
|
|||||||
4
tests/testlib/__init__.py
Normal file
4
tests/testlib/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
"""Test support libraries for resync tests."""
|
||||||
|
from .testcase_with_tmpdir import TestCase
|
||||||
|
from .capture_stdout_context import capture_stdout
|
||||||
|
from .webserver_context import webserver
|
||||||
@ -1,4 +1,4 @@
|
|||||||
"""Provide capture_stdout as contect manager."""
|
"""Provide capture_stdout as context manager."""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import contextlib
|
import contextlib
|
||||||
@ -19,7 +19,7 @@ class TestCase(unittest.TestCase):
|
|||||||
raise Exception("Failed to create tempdir to use for dump tests")
|
raise Exception("Failed to create tempdir to use for dump tests")
|
||||||
try:
|
try:
|
||||||
cls.extraSetUpClass()
|
cls.extraSetUpClass()
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -30,7 +30,7 @@ class TestCase(unittest.TestCase):
|
|||||||
shutil.rmtree(cls._tmpdir)
|
shutil.rmtree(cls._tmpdir)
|
||||||
try:
|
try:
|
||||||
cls.extraTearUpClass()
|
cls.extraTearUpClass()
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -1,4 +1,5 @@
|
|||||||
"""Provides content manager that runs local webserver."""
|
"""Provides context manager that runs local webserver."""
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
@ -8,7 +9,7 @@ import time
|
|||||||
from multiprocessing import Process
|
from multiprocessing import Process
|
||||||
try: # python3
|
try: # python3
|
||||||
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
||||||
except:
|
except ImportError: # python2
|
||||||
from BaseHTTPServer import HTTPServer
|
from BaseHTTPServer import HTTPServer
|
||||||
from SimpleHTTPServer import SimpleHTTPRequestHandler
|
from SimpleHTTPServer import SimpleHTTPRequestHandler
|
||||||
try: # python3
|
try: # python3
|
||||||
13
tox.ini
Normal file
13
tox.ini
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# tox (https://tox.readthedocs.io/) is a tool for running tests
|
||||||
|
# in multiple virtualenvs. This configuration file will run the
|
||||||
|
# test suite on all supported python versions. To use it, "pip install tox"
|
||||||
|
# and then run "tox" from this directory.
|
||||||
|
|
||||||
|
[tox]
|
||||||
|
envlist = py36
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
deps =
|
||||||
|
|
||||||
|
commands =
|
||||||
|
python setup.py test
|
||||||
Loading…
Reference in New Issue
Block a user