diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..838a86c --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.coverage* +.eggs/ +.tox/ +bin/ +htmlcov/ +lib/ +pip-selfcheck.json +pyvenv.cfg diff --git a/.travis.yml b/.travis.yml index d2a7ab3..f3592f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,15 @@ language: python python: - - 2.6 - 2.7 - - 3.2 - - 3.3 + - 3.4 + - 3.5 + - 3.6 - pypy + - pypy3 +matrix: + fast_finish: true + allow_failures: + - python: pypy install: - pip install -r requirements/development.txt -r requirements/production.txt - python setup.py install diff --git a/CHANGELOG b/CHANGELOG index 4d11279..a3ad182 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ Next release 1.7 ```````````````` * Improved warning message when closing magic.Magic at garbage collection. * Published Python wheel packages to PyPI to improve install times. +* Update Python versions, provide Tox runner 1.6 (2013-05-29) ```````````````` diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 16857ca..6d0d22a 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -6,3 +6,7 @@ erhudy `````` * added a small patch to correct import behavior on Solaris, where ctypes.util.find_library does not function correctly. + +gyst +```` +* Update Python versions, provide Tox runner \ No newline at end of file diff --git a/magic/__init__.py b/magic/__init__.py index 4ed7f0b..bb53b91 100644 --- a/magic/__init__.py +++ b/magic/__init__.py @@ -14,6 +14,6 @@ See http://filemagic.readthedocs.org for detailed documentation. """ -from magic.flags import * -from magic.identify import Magic, MagicError -from magic.version import __version__ +from magic.flags import * # flake8:noqa +from magic.identify import Magic, MagicError # flake8:noqa +from magic.version import __version__ # flake8:noqa diff --git a/magic/api.py b/magic/api.py index 2021b1b..cf74977 100644 --- a/magic/api.py +++ b/magic/api.py @@ -9,7 +9,8 @@ import platform import warnings -libname = ctypes.util.find_library('magic') or ctypes.util.find_library('magic1') +libname = (ctypes.util.find_library('magic') + or ctypes.util.find_library('magic1')) if not libname: if platform.system() == 'SunOS': libname = 'libmagic.so' @@ -31,6 +32,7 @@ class Cookie(ctypes.Structure): "Magic data structure" + c_cookie_p = ctypes.POINTER(Cookie) @@ -58,6 +60,7 @@ def errcheck_null(result, func, arguments): raise MagicError(errno, error) return result + # dynamically load library lib.magic_open.argtypes = [ctypes.c_int] lib.magic_open.restype = c_cookie_p diff --git a/magic/command.py b/magic/command.py index 97a1679..e85a591 100644 --- a/magic/command.py +++ b/magic/command.py @@ -57,9 +57,9 @@ def parse_command_line(arguments): usage = "usage: python -m magic [options] file ..." parser = OptionParser(usage=usage) parser.add_option("-m", "--magic", dest="paths", - help="A colon separated list of magic files to use") + help="A colon separated list of magic files to use") parser.add_option("--json", action="store_true", default=False, - help="Format output in JSON") + help="Format output in JSON") return parser.parse_args(arguments) diff --git a/magic/compatability.py b/magic/compatability.py index 9c49800..2b62a75 100644 --- a/magic/compatability.py +++ b/magic/compatability.py @@ -7,7 +7,7 @@ bytes_t = bytes decode_result = True else: - unicode_t = unicode + unicode_t = unicode # flake8:noqa bytes_t = str decode_result = False @@ -19,6 +19,7 @@ def byte_args(positions): """ def decorator(func): ordinals = set(positions) + @wraps(func) def wrapper(*args, **kwargs): def encoder(args): @@ -50,6 +51,7 @@ def str_return(func): """ if not decode_result: return func + @wraps(func) def wrapper(*args, **kwargs): value = func(*args, **kwargs) diff --git a/magic/identify.py b/magic/identify.py index c75a10b..6f5d3e5 100644 --- a/magic/identify.py +++ b/magic/identify.py @@ -57,11 +57,12 @@ def __init__(self, paths=None, flags=MAGIC_NONE): """ self._repr = "Magic(paths={0!r}, flags={1!r})".format(paths, flags) cookie = api.magic_open(flags) + def cleanup(_): warnings.warn("magic.Magic() not closed before being garbage " - "collected. Magic.close() should be called when finished" - "with", - CleanupWarning) + "collected. Magic.close() should be called when " + "finished with", + CleanupWarning) api.magic_close(cookie) self.weakref = weakref.ref(self, cleanup) self.cookie = cookie @@ -103,8 +104,8 @@ def consistent(self): def id_buffer(self, buffer): "Return a textual description of the contents of buffer" return api.magic_buffer(self.cookie, - api.ctypes.c_char_p(buffer), - len(buffer)) + api.ctypes.c_char_p(buffer), + len(buffer)) @raise_if_none('cookie', MagicError, 'object has already been closed') @byte_args(positions=[1]) diff --git a/setup.py b/setup.py index 4fb1ac2..6b7dd2d 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,8 @@ def load_rst(filename='docs/source/guide_content'): author="Aaron Iles", author_email="aaron.iles@gmail.com", url="http://filemagic.readthedocs.org", - description="A Python API for libmagic, the library behind the Unix file command", + description="A Python API for libmagic, the library behind the " + "Unix file command", long_description=load_rst(), license="ASL", classifiers=[ @@ -43,14 +44,15 @@ def load_rst(filename='docs/source/guide_content'): 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries :: Python Modules' ], - tests_require=['mock'] + [] if PYTHON3K else ['unittest2'], + tests_require=['mock'] if PYTHON3K else ['mock', 'unittest2'], test_suite="tests" if PYTHON3K else "unittest2.collector" ) diff --git a/tests/test_magic.py b/tests/test_magic.py index 2853346..8620686 100644 --- a/tests/test_magic.py +++ b/tests/test_magic.py @@ -22,7 +22,7 @@ def test_consistent_database(self): def test_invalid_database(self): self.assertRaises(magic.MagicError, magic.Magic, - paths=['test/magic/_false_']) + paths=['test/magic/_false_']) def test_use_after_closed(self): with magic.Magic() as m: @@ -41,43 +41,47 @@ def test_id_buffer(self): def test_mime_type_file(self): with magic.Magic(paths=['tests/magic/python'], - flags=magic.MAGIC_MIME_TYPE) as m: + flags=magic.MAGIC_MIME_TYPE) as m: id = m.id_filename('setup.py') self.assertEqual(id, 'text/x-python') def test_mime_type_desc(self): with magic.Magic(paths=['tests/magic/python'], - flags=magic.MAGIC_MIME_TYPE) as m: + flags=magic.MAGIC_MIME_TYPE) as m: id = m.id_buffer('#!/usr/bin/env python\n') self.assertEqual(id, 'text/x-python') def test_mime_encoding_file(self): with magic.Magic(paths=['tests/magic/python'], - flags=magic.MAGIC_MIME_ENCODING) as m: + flags=magic.MAGIC_MIME_ENCODING) as m: id = m.id_filename('setup.py') self.assertEqual(id, 'us-ascii') def test_mime_encoding_desc(self): with magic.Magic(paths=['tests/magic/python'], - flags=magic.MAGIC_MIME_ENCODING) as m: + flags=magic.MAGIC_MIME_ENCODING) as m: id = m.id_buffer('#!/usr/bin/env python\n') self.assertEqual(id, 'us-ascii') def test_repr(self): with magic.Magic(paths=['tests/magic/python'], - flags=magic.MAGIC_MIME_ENCODING) as m: + flags=magic.MAGIC_MIME_ENCODING) as m: n = eval(repr(m), {'Magic': magic.Magic}) n.close() + @unittest.skipIf(hasattr(sys, 'pypy_version_info'), + 'garbarge collection on PyPy is not deterministic') + @unittest.skipIf(sys.version_info[0] == 2 or sys.version_info[1] < 2, + 'ResourceWarning was introduced in python 3.2') @unittest.skipIf(not hasattr(unittest.TestCase, 'assertWarns'), - 'unittest does not support assertWarns') + 'unittest does not support assertWarns') def test_resource_warning(self): with self.assertWarns(ResourceWarning): m = magic.Magic() del m @unittest.skipIf(hasattr(sys, 'pypy_version_info'), - 'garbarge collection on PyPy is not deterministic') + 'garbarge collection on PyPy is not deterministic') def test_weakref(self): magic_close = magic.api.magic_close with mock.patch('magic.api.magic_close') as close_mock: @@ -87,7 +91,7 @@ def test_weakref(self): m = magic.Magic() del m gc.collect() - self.assertEqual(close_mock.call_count, 1) + self.assertEqual(close_mock.call_count, 1) if __name__ == '__main__': diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..123cea3 --- /dev/null +++ b/tox.ini @@ -0,0 +1,39 @@ +[tox] +envlist = + coverage-clean, + py27, + py34, + py35, + py36, + pypy, + pypy3, + coverage-report + + +[testenv] +commands = + coverage run setup.py test +setenv = + COVERAGE_FILE=.coverage.{envname} +deps = + .[test] + zope.testrunner + coverage + +[testenv:coverage-clean] +deps = coverage +setenv = + COVERAGE_FILE=.coverage +skip_install = true +commands = coverage erase + +[testenv:coverage-report] +deps = coverage +setenv = + COVERAGE_FILE=.coverage +skip_install = true +commands = + coverage combine + coverage report + coverage html + coverage