From c979628097baf12233e0cee05bbeb5074153070f Mon Sep 17 00:00:00 2001 From: Matthew Hughes Date: Thu, 7 Jul 2022 19:51:55 +0100 Subject: [PATCH] Drop unsupported pythons Drop support for pythons <3.7 (including python 2). Since this makes it part of the standard library, replace `mock` with `unittest.mock` in tests. I also bumped the ubuntu version used in CI to one that has python3.10 installable. This also required replacing `nose` with `pytest` in tests This is because `nose` is not under active development[1], and the version specified fails to run on python3 (and newer versions fail to run on python3.10[2]): $ python -m nose Traceback (most recent call last): File "/usr/lib/python3.10/runpy.py", line 187, in _run_module_as_main mod_name, mod_spec, code = _get_module_details(mod_name, _Error) File "/usr/lib/python3.10/runpy.py", line 146, in _get_module_details return _get_module_details(pkg_main_name, error) File "/usr/lib/python3.10/runpy.py", line 110, in _get_module_details __import__(pkg_name) File "/home/mjh/src/pystatsd/.venv/lib/python3.10/site-packages/nose/__init__.py", line 1, in from nose.core import collector, main, run, run_exit, runmodule File "/home/mjh/src/pystatsd/.venv/lib/python3.10/site-packages/nose/core.py", line 143 print "%s version %s" % (os.path.basename(sys.argv[0]), __version__) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)? `pytest` is pinned at the lowest version supporting python3.10[3], similarly for coverage[4], `flake8` was also bump to a more recent version. [1] https://nose.readthedocs.io/en/latest/#note-to-users [2] https://github.com/nose-devs/nose/issues/1122 [3] https://docs.pytest.org/en/7.1.x/changelog.html#pytest-6-2-5-2021-08-29 [4] https://coverage.readthedocs.io/en/6.4.1/changes.html#version-6-0-2021-10-03 --- .travis.yml | 11 +++++------ docs/contributing.rst | 4 ++-- requirements.txt | 5 ++--- setup.py | 9 +++++---- statsd/tests.py | 37 ++++++++++++++++--------------------- tox.ini | 7 +++---- 6 files changed, 33 insertions(+), 40 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2ff0fc06f..98c59ec1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,13 @@ language: python python: - - "2.7" - - "3.5" - - "3.6" - "3.7" - "3.8" - - "pypy" + - "3.9" + - "3.10" - "pypy3" +dist: focal install: - - pip install -q "flake8" + - pip install -r requirements.txt script: - - nosetests --with-coverage --cover-package=statsd + - pytest statsd/tests.py - flake8 statsd/ diff --git a/docs/contributing.rst b/docs/contributing.rst index 63639a597..1c6d12c5a 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -36,8 +36,8 @@ You can also run the tests with tox:: $ tox -Tox will run the tests in Pythons 2.5, 2.6, 2.7, 3.2, 3.3, 3.4, and -PyPy, if they're available. +Tox will run the tests in Pythons 3.7, 3.8, 3.9, 3.10 and +PyPy3, if they're available. Writing Tests diff --git a/requirements.txt b/requirements.txt index 6aa9af6b5..cc825cac3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,2 @@ -mock==1.0.1 -nose==1.2.1 -flake8==1.7.0 +flake8>=4.0 +pytest>=6.2.5 diff --git a/setup.py b/setup.py index 197757f58..4e75d41b5 100644 --- a/setup.py +++ b/setup.py @@ -14,6 +14,7 @@ include_package_data=True, package_data={'': ['README.rst']}, test_suite='nose.collector', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', @@ -21,13 +22,13 @@ 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries :: Python Modules', ], ) diff --git a/statsd/tests.py b/statsd/tests.py index 12fc410cd..a92f83be4 100644 --- a/statsd/tests.py +++ b/statsd/tests.py @@ -5,9 +5,7 @@ import socket from datetime import timedelta from unittest import SkipTest - -import mock -from nose.tools import eq_ +from unittest import mock from statsd import StatsClient from statsd import TCPStatsClient @@ -66,7 +64,7 @@ def _unix_socket_client(prefix=None, socket_path=None): def _timer_check(sock, count, proto, start, end): send = send_method[proto](sock) - eq_(send.call_count, count) + assert send.call_count == count value = send.call_args[0][0].decode('ascii') exp = re.compile(r'^%s:\d+|%s$' % (start, end)) assert exp.match(value) @@ -74,14 +72,11 @@ def _timer_check(sock, count, proto, start, end): def _sock_check(sock, count, proto, val=None, addr=None): send = send_method[proto](sock) - eq_(send.call_count, count) + assert send.call_count == count if not addr: addr = ADDR if val is not None: - eq_( - send.call_args, - make_val[proto](val, addr), - ) + assert send.call_args == make_val[proto](val, addr) class assert_raises(object): @@ -443,7 +438,7 @@ def _test_prepare(cl, proto): def _check(o, s, v, r): with mock.patch.object(random, 'random', lambda: -1): - eq_(o, cl._prepare(s, v, r)) + assert o == cl._prepare(s, v, r) for o, (s, v, r) in tests: _check(o, s, v, r) @@ -519,13 +514,13 @@ def bar(a, b): # make sure it works with more than one decorator, called multiple # times, and that parameters are handled correctly - eq_([4, 2], foo(4, 2)) + assert [4, 2] == foo(4, 2) _timer_check(cl._sock, 1, proto, 'foo', 'ms') - eq_([2, 4], bar(4, 2)) + assert [2, 4] == bar(4, 2) _timer_check(cl._sock, 2, proto, 'bar', 'ms') - eq_([6, 5], bar(5, 6)) + assert [6, 5] == bar(5, 6) _timer_check(cl._sock, 3, proto, 'bar', 'ms') @@ -543,7 +538,7 @@ def test_timer_decorator_tcp(): def _test_timer_capture(cl, proto): with cl.timer('woo') as result: - eq_(result.ms, None) + assert result.ms is None assert isinstance(result.ms, float) @@ -587,7 +582,7 @@ def test_timer_decorator_partial_function(): foo = functools.partial(lambda x: x * x, 2) func = cl.timer('foo')(foo) - eq_(4, func()) + assert 4 == func() _timer_check(cl._sock, 1, 'tcp', 'foo', 'ms|@0.1') @@ -601,10 +596,10 @@ def foo(a, b): def bar(a, b=2, c=3): return [c, b, a] - eq_([2, 4], foo(4, 2)) + assert [2, 4] == foo(4, 2) _timer_check(cl._sock, 1, proto, 'foo', 'ms|@0.1') - eq_([3, 2, 5], bar(5)) + assert [3, 2, 5] == bar(5) _timer_check(cl._sock, 2, proto, 'bar', 'ms|@0.2') @@ -906,8 +901,8 @@ def test_pipeline_timer_object_tcp(): def _test_pipeline_empty(cl): with cl.pipeline() as pipe: pipe.incr('foo') - eq_(1, len(pipe._stats)) - eq_(0, len(pipe._stats)) + assert 1 == len(pipe._stats) + assert 0 == len(pipe._stats) def test_pipeline_empty_udp(): @@ -1006,7 +1001,7 @@ def test_pipeline_packet_size(): # 32 * 16 = 512, so this will need 2 packets. pipe.incr('sixteen_char_str') pipe.send() - eq_(2, sc._sock.sendto.call_count) + assert 2 == sc._sock.sendto.call_count assert len(sc._sock.sendto.call_args_list[0][0][0]) <= 512 assert len(sc._sock.sendto.call_args_list[1][0][0]) <= 512 @@ -1017,7 +1012,7 @@ def test_tcp_raises_exception_to_user(mock_socket): addr = ('127.0.0.1', 1234) cl = _tcp_client(addr=addr[0], port=addr[1]) cl.incr('foo') - eq_(1, cl._sock.sendall.call_count) + assert 1 == cl._sock.sendall.call_count cl._sock.sendall.side_effect = socket.error with assert_raises(socket.error): cl.incr('foo') diff --git a/tox.ini b/tox.ini index f75a9787b..f992052a6 100644 --- a/tox.ini +++ b/tox.ini @@ -3,9 +3,8 @@ envlist = py27,pypy,py34,py35,py36,py37 [testenv] deps= - mock==1.0.1 - nose==1.2.1 - coverage==3.5.2 + coverage>=6.0 + pytest>=6.2.5 commands= - nosetests statsd --with-coverage --cover-package=statsd [] + pytest statsd/tests.py