Fix errors with 3.6, tidy

This commit is contained in:
Simeon Warner 2020-12-10 07:24:00 -05:00
parent 7d2181a31a
commit a15b4c50ce
33 changed files with 120 additions and 108 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@
build build
dist dist
MANIFEST MANIFEST
.tox
.eggs .eggs
*.egg *.egg
# Testing # Testing

View File

@ -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

View File

@ -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
View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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):

View File

@ -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):

View File

@ -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)

View File

@ -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)

View File

@ -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:

View File

@ -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):

View File

@ -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)

View File

@ -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'

View File

@ -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"],

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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',

View File

@ -1,4 +1,4 @@
from tests.capture_stdout import capture_stdout from .testlib import capture_stdout
import unittest import unittest
import re import re

View File

@ -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."""

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View 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

View File

@ -1,4 +1,4 @@
"""Provide capture_stdout as contect manager.""" """Provide capture_stdout as context manager."""
import sys import sys
import contextlib import contextlib

View File

@ -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

View File

@ -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
View 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