diff --git a/.github/workflows/ci-gh-actions.yml b/.github/workflows/ci-gh-actions.yml index 433a38d..0c28174 100644 --- a/.github/workflows/ci-gh-actions.yml +++ b/.github/workflows/ci-gh-actions.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: true matrix: - python-version: [3.9] + python-version: [3.12] steps: - uses: actions/checkout@v2 with: @@ -27,7 +27,7 @@ jobs: strategy: fail-fast: true matrix: - python-version: [3.6, 3.7, 3.8, 3.9] + python-version: [3.8, 3.9, 3.10.13, 3.11, 3.12] steps: - uses: actions/checkout@v2 with: @@ -47,7 +47,7 @@ jobs: strategy: fail-fast: true matrix: - python-version: [3.9] + python-version: [3.12] steps: - uses: actions/checkout@v2 with: diff --git a/README.rst b/README.rst index 0704187..eee9a80 100644 --- a/README.rst +++ b/README.rst @@ -28,6 +28,9 @@ Installation is simple: pip install stackinabox +.. note:: Python 2.7 is no longer supported. Pypy implements Python2.7 compatibility, however, the `setuptools` package + may cause issues if you cannot install a version that supports Python2.7. + ===== Goals ===== @@ -40,7 +43,7 @@ Goals - you should not necessarily need to know the ins and outs of each service - you should be able to register what you need (f.e authentication, storage) and have it just work -- should be useable on systems like Travis (https://travis-ci.org/) +- should be useable on systems like Travis (https://travis-ci.org/), GitHub Actions, etc - should be light on requirements - we do not want to bloat your testing to fit our needs diff --git a/setup.cfg b/setup.cfg index a8f6a7d..225f0d9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,3 +7,33 @@ cover-erase=1 cover-inclusive=true cover-branches=true cover-min-percentage=92 + +[metadata] +name = stackinabox +url = https://github.com/TestInABox/stackInABox +version = attr: stackinabox.version +author = Benjamen R. Meyer +author_email = bm_witness@yahoo.com +description = RESTful API Testing Suite +long_description = file: README.rst, LICENSE, CONTRIBUTING.rst +license = Apache License 2.0 +classifiers = + Intended Audience :: Developers + License :: OSI Approved :: Apache Software License + Topic :: Software Development :: Testing + +[options] +zip_safe = True +packages = find: +install_requires = + six + +[options.extras_require] +httpretty = httpretty==1.1.4 +requests-mock = requests-mock +responses = responses>=0.4.0 + +[options.packages.find] +exclude = + test* + stackinabox/tests diff --git a/setup.py b/setup.py index 3aa0fca..6068493 100644 --- a/setup.py +++ b/setup.py @@ -1,27 +1,3 @@ -import sys -from setuptools import setup, find_packages +from setuptools import setup -REQUIRES = ['six'] -EXTRA_REQUIRES = { - 'httpretty': ['httpretty==0.8.6'], - 'requests-mock': ['requests-mock'], - 'responses': ['responses>=0.4.0'] -} - -setup( - name='stackinabox', - version='0.13', - description='RESTful API Testing Suite', - license='Apache License 2.0', - url='https://github.com/TestInABox/stackInABox', - author='Benjamen R. Meyer', - author_email='bm_witness@yahoo.com', - install_requires=REQUIRES, - extras_require=EXTRA_REQUIRES, - test_suite='stackinabox', - packages=find_packages(exclude=['tests*', 'stackinabox/tests']), - zip_safe=True, - classifiers=["Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Topic :: Software Development :: Testing"], -) +setup() diff --git a/stackinabox/util/httpretty/decorator.py b/stackinabox/util/httpretty/decorator.py index 5281982..f195a49 100644 --- a/stackinabox/util/httpretty/decorator.py +++ b/stackinabox/util/httpretty/decorator.py @@ -4,7 +4,6 @@ try: import collections.abc as collections except ImportError: - # Py2.7 Support import collections import functools import logging diff --git a/stackinabox/util/requests_mock/decorator.py b/stackinabox/util/requests_mock/decorator.py index b74f793..cf5e773 100644 --- a/stackinabox/util/requests_mock/decorator.py +++ b/stackinabox/util/requests_mock/decorator.py @@ -4,7 +4,6 @@ try: import collections.abc as collections except ImportError: - # Py2.7 Support import collections import functools import logging diff --git a/stackinabox/util/responses/core.py b/stackinabox/util/responses/core.py index 6435392..712e837 100644 --- a/stackinabox/util/responses/core.py +++ b/stackinabox/util/responses/core.py @@ -75,7 +75,8 @@ def registration(uri): for method in METHODS: responses.add_callback(method, regex, - callback=responses_callback) + callback=responses_callback, + content_type=None) @deprecator.DeprecatedInterface("responses_registration", "registration") diff --git a/stackinabox/util/responses/decorator.py b/stackinabox/util/responses/decorator.py index 22ca346..793129c 100644 --- a/stackinabox/util/responses/decorator.py +++ b/stackinabox/util/responses/decorator.py @@ -4,7 +4,6 @@ try: import collections.abc as collections except ImportError: - # Py2.7 Support import collections import functools diff --git a/tests/test_version.py b/tests/test_version.py index 87078fe..45922ae 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -1,5 +1,6 @@ import os import os.path +import subprocess import sys import stackinabox @@ -11,7 +12,6 @@ class TestVersionMatch(base.TestCase): def setUp(self): super(TestVersionMatch, self).setUp() self.local_directory = os.path.dirname(__file__) - self.setup_py = '{0}/../setup.py'.format(self.local_directory) self.doc_conf = '{0}/../../docs/conf.py'.format(self.local_directory) def tearDown(self): @@ -27,14 +27,25 @@ def make_version_source(): def test_version_match(self): version_source = self.make_version_source() + # read the data from `pip show ` to get the version + # as seen by the installer version_setup = None - with open(self.setup_py, 'rt') as input_data: - for line in input_data: - ln = line.strip() - if ln.startswith('version='): - ln_parts = ln.replace("'", '', 2).replace(',', '') - version_setup = ln_parts.split('=')[1] + cmd = ["pip", "show", "stackinabox"] + pip_freeze = subprocess.Popen(cmd, stdout=subprocess.PIPE) + output, error = pip_freeze.communicate() + if error is None: + output_lines = output.decode('utf-8').split("\n") + print(f"Read pip freeze data:\n{output_lines}\n") + for line in output_lines: + line_data = line.split(':') + key = line_data[0] + value = ':'.join(line_data[1:]).strip() + print(f"\tLine Key: {key} - Value: {value}") + if key.lower() == "version": + version_setup = value break + else: + self.fail(f"Unable to retrieve version data - error: {error}") self.assertEqual(version_source, version_setup) diff --git a/tests/util/httpretty/test_decorator.py b/tests/util/httpretty/test_decorator.py index d2ccd74..545fa36 100644 --- a/tests/util/httpretty/test_decorator.py +++ b/tests/util/httpretty/test_decorator.py @@ -1,7 +1,10 @@ """ Stack-In-A-Box: Basic Test """ -import collections +try: + import collections.abc as collections +except ImportError: + import collections import sys import types import unittest diff --git a/tests/util/requests_mock/test_core.py b/tests/util/requests_mock/test_core.py index 67b8ef4..f8e56f1 100644 --- a/tests/util/requests_mock/test_core.py +++ b/tests/util/requests_mock/test_core.py @@ -149,8 +149,9 @@ def test_basic(self): 'alice': 'alice: Good-Bye bob', 'joe': 'joe: Good-Bye jane' } - res = self.session.get('http://localhost/advanced/g?bob=alice;' - 'alice=bob&joe=jane') + res = self.session.get( + 'http://localhost/advanced/g?bob=alice&alice=bob&joe=jane' + ) self.assertEqual(res.status_code, 200) self.assertEqual(res.json(), expected_result) @@ -185,8 +186,9 @@ def test_context_requests_mock(self): 'alice': 'alice: Good-Bye bob', 'joe': 'joe: Good-Bye jane' } - res = requests.get('http://localhost/advanced/g?bob=alice;' - 'alice=bob&joe=jane') + res = requests.get( + 'http://localhost/advanced/g?bob=alice&alice=bob&joe=jane' + ) self.assertEqual(res.status_code, 200) self.assertEqual(res.json(), expected_result) diff --git a/tests/util/requests_mock/test_decorator.py b/tests/util/requests_mock/test_decorator.py index 806d0ae..a869c17 100644 --- a/tests/util/requests_mock/test_decorator.py +++ b/tests/util/requests_mock/test_decorator.py @@ -1,7 +1,10 @@ """ Stack-In-A-Box: Basic Test """ -import collections +try: + import collections.abc as collections +except ImportError: + import collections import json import logging import types @@ -91,8 +94,9 @@ def test_basic(self, session): 'alice': 'alice: Good-Bye bob', 'joe': 'joe: Good-Bye jane' } - res = session.get('http://localhost/advanced/g?bob=alice;' - 'alice=bob&joe=jane') + res = session.get( + 'http://localhost/advanced/g?bob=alice&alice=bob&joe=jane' + ) self.assertEqual(res.status_code, 200) self.assertEqual(res.json(), expected_result) diff --git a/tests/util/response/test_core.py b/tests/util/response/test_core.py index d41c05c..3b6ff36 100644 --- a/tests/util/response/test_core.py +++ b/tests/util/response/test_core.py @@ -56,8 +56,9 @@ def run(use_deprecated): 'alice': 'alice: Good-Bye bob', 'joe': 'joe: Good-Bye jane' } - res = requests.get('http://localhost/advanced/g?bob=alice;' - 'alice=bob&joe=jane') + res = requests.get( + 'http://localhost/advanced/g?bob=alice&alice=bob&joe=jane' + ) assert res.status_code == 200 assert res.json() == expected_result diff --git a/tests/util/response/test_decorator.py b/tests/util/response/test_decorator.py index 0957f6a..01714b5 100644 --- a/tests/util/response/test_decorator.py +++ b/tests/util/response/test_decorator.py @@ -1,7 +1,11 @@ """ Stack-In-A-Box: Basic Test """ -import collections +try: + import collections.abc as collections +except ImportError: + import collections + import json import logging import types @@ -168,8 +172,9 @@ def test_advanced_responses(): 'alice': 'alice: Good-Bye bob', 'joe': 'joe: Good-Bye jane' } - res = requests.get('http://localhost/advanced/g?bob=alice;' - 'alice=bob&joe=jane') + res = requests.get( + 'http://localhost/advanced/g?bob=alice&alice=bob&joe=jane' + ) assert res.status_code == 200 assert res.json() == expected_result diff --git a/tools/docs-requirements.txt b/tools/docs-requirements.txt index 38a7f26..a6d2cdb 100644 --- a/tools/docs-requirements.txt +++ b/tools/docs-requirements.txt @@ -1,7 +1,7 @@ -doc8==0.8.1 -httpretty==1.0.5 -requests==2.25.1 -requests-mock==1.8.0 +doc8==1.1.1 +httpretty==1.1.4 +requests==2.31.0 +requests-mock==1.11.0 responses>=0.12.1 -six==1.15.0 -sphinx==3.4.2 +six==1.16.0 +sphinx==7.2.6 diff --git a/tools/pep8-requirements.txt b/tools/pep8-requirements.txt index 3af653e..c1d5188 100644 --- a/tools/pep8-requirements.txt +++ b/tools/pep8-requirements.txt @@ -1,2 +1,2 @@ setuptools>=1.1.6 -pycodestyle==2.6.0 +pycodestyle==2.11.1 diff --git a/tools/py2-test-requirements.txt b/tools/py2-test-requirements.txt index 66e3bd4..4b2f060 100644 --- a/tools/py2-test-requirements.txt +++ b/tools/py2-test-requirements.txt @@ -1,12 +1,13 @@ -coverage==4.5.4 -ddt==1.2.1 -httpretty==0.8.6 -mock==3.0.5 -pytest==3.3.2 -pytest-cov==2.5.1 -requests==2.22.0 -requests-mock==1.7.0 -responses>=0.10.6 -six==1.12.0 -pycodestyle==2.5.0 -attrs==17.2.0 +coverage==7.4.1 +ddt==1.7.1 +httpretty==1.1.4 +mock==5.1.0 +pytest==8.0.0 +pytest-cov==4.1.0 +requests==2.31.0 +requests-mock==1.11.0 +responses>=0.12.1 +six==1.16.0 +pycodestyle==2.11.1 +attrs==23.2.0 +setuptools<=44.1.1 diff --git a/tools/test-requirements.txt b/tools/test-requirements.txt index 4de3a66..628986f 100644 --- a/tools/test-requirements.txt +++ b/tools/test-requirements.txt @@ -1,12 +1,12 @@ -coverage==5.3.1 -ddt==1.4.1 -httpretty==1.0.5 -mock==4.0.3 -pytest==6.2.1 -pytest-cov==2.10.1 -requests==2.25.1 -requests-mock==1.8.0 +coverage==7.4.1 +ddt==1.7.1 +httpretty==1.1.4 +mock==5.1.0 +pytest==8.0.0 +pytest-cov==4.1.0 +requests==2.31.0 +requests-mock==1.11.0 responses>=0.12.1 -six==1.15.0 -pycodestyle==2.6.0 +six==1.16.0 +pycodestyle==2.11.1 importlib-metadata==3.3.0 ;python_version<"3.8" diff --git a/tox.ini b/tox.ini index 4000bbd..3be5df9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,64 +1,48 @@ [tox] minversion=1.8 -envlist = {py3.6,py3.7,py3.8,py3.9},py3-httpretty,py3-requests-mock,py3-responses,pep8,docs +envlist = {py3.8,py3.9,py3.10,py3.11,py3.12},py3-httpretty,py3-requests-mock,py3-responses,pep8,docs skip_missing_interpreters=True [testenv] basepython = - py27: python2.7 pypy: pypy pypy3: pypy3 - py35: python3.5 - py3.6: python3.6 - py3.7: python3.7 py3.8: python3.8 py3.9: python3.9 + py3.10: python3.10 + py3.11: python3.11 + py3.12: python3.12 pep8: python3 docs: python3 deps = - py27,pypy: -r{toxinidir}/tools/py2-test-requirements.txt - pypy3,py35,py3.6,py3.7,py3.8,py3.9,docs: -r{toxinidir}/tools/test-requirements.txt + pypy: -r{toxinidir}/tools/py2-test-requirements.txt + pypy3,py3.8,py3.9,py3.10,py3.11,py3.12,docs: -r{toxinidir}/tools/test-requirements.txt pep8: -r{toxinidir}/tools/pep8-requirements.txt docs: -r{toxinidir}/tools/docs-requirements.txt commands = - py27,pypy,pypy3,py35,py3.6,py3.7,py3.8,py3.9: pytest {toxinidir}/tests --cov-config=.coveragerc --cov=stackinabox {posargs} + pypy,pypy3,py3.8,py3.9,py3.10,py3.11,py3.12: pytest {toxinidir}/tests --cov-config=.coveragerc --cov=stackinabox {posargs} pep8: pycodestyle --exclude=.tox,dist,doc,docs,*env*,.*env*,build --ignore=E128,W504 docs: sphinx-build -b html -d {envtmpdir}/doctrees docs docs/_build/html docs: sphinx-build -b latex -d {envtmpdir}/doctrees docs docs/_build/latex docs: sphinx-build -b doctest -d {envtmpdir}/doctrees docs docs/_build/html docs: doc8 --allow-long-titles docs/ setenv = - pypy3,py35,py3.6,py3.7,py3.8,py3.9,py3-httpretty,py3-requests-mock,py3-responses: VIRTUAL_ENV={envdir} LC_ALL = en_US.utf-8 + pypy3,py3.8,py3.9,py3.10,py3.11,py3.12,py3-httpretty,py3-requests-mock,py3-responses: VIRTUAL_ENV={envdir} LC_ALL = en_US.utf-8 # Unfortunately the below doesn't seem to integrate well into the form above # but it's valuable for testing the setup with extra dependencies to make sure things install right -[testenv:py27-httpretty] -basepython = python2.7 -deps = .[httpretty] -commands = python -c "import stackinabox.util.httpretty" - [testenv:py3-httpretty] basepython = python3 deps = .[httpretty] commands = python -c "import stackinabox.util.httpretty" setenv ={envdir} LC_ALL = en_US.utf-8 -[testenv:py27-requests-mock] -basepython = python2.7 -deps = .[requests-mock] -commands = python -c "import stackinabox.util.requests_mock" - [testenv:py3-requests-mock] basepython = python3 deps = .[requests-mock] commands = python -c "import stackinabox.util.requests_mock" setenv ={envdir} LC_ALL = en_US.utf-8 -[testenv:py27-responses] -basepython = python2.7 -deps = .[responses] -commands = python -c "import stackinabox.util.responses" - [testenv:py3-responses] basepython = python3 deps = .[responses]