diff --git a/.circleci/config.yml b/.circleci/config.yml index d909d28..e5f49bb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,7 +34,7 @@ jobs: - run: name: Package safety check command: | - bin/dc exec -T shipchain-common safety check + bin/dc exec -T shipchain-common safety check -i 38224 - run: name: PEP8 Lint check command: | diff --git a/README.md b/README.md index 9b93150..8ff1ed6 100644 --- a/README.md +++ b/README.md @@ -192,28 +192,21 @@ This will automatically add the `json_asserter` and set it as a class attribute This allows you to just call `self.json_asserter`, allowing for cleaner unit tests imports. -### HTTPrettyAsserter Usage +### ResponsesAsserter Usage When mocking calls, this can help in ensuring all calls, and only those, were made as expected, with the desired parameters. -In order to use, simply import the HTTPrettyAsserter from test_utils and use it in place of the usual httpretty: -```python -@pytest.yield_fixture -def modified_http_pretty(): - HTTPrettyAsserter.enable(allow_net_connect=False) - yield HTTPrettyAsserter - HTTPrettyAsserter.disable() -``` +In order to use, simply import the `modified_responses` fixture from test_utils. -Then, you just need to register the uris for the calls you want to mock, and ensure that it is returned in the mocking: +Then, you just need to register the uris for the calls you want to mock: ```python @pytest.fixture -def http_pretty_list_mocking(modified_http_pretty): - modified_http_pretty.register_uri(modified_http_pretty.POST, 'http://google.com/path', status=status.HTTP_200_OK) - modified_http_pretty.register_uri(modified_http_pretty.POST, 'http://google.com/other_path', +def responses_list_mocking(modified_responses): + modified_responses.register_uri(modified_responses.POST, 'http://google.com/path', status=status.HTTP_200_OK) + modified_responses.register_uri(modified_responses.POST, 'http://google.com/other_path', status=status.HTTP_200_OK) - modified_http_pretty.register_uri(modified_http_pretty.POST, 'http://bing.com/bing_path', + modified_responses.register_uri(modified_responses.POST, 'http://bing.com/bing_path', status=status.HTTP_200_OK) - return modified_http_pretty + return modified_responses ``` In a test that you want to check the calls on, you simply need to use the mocking fixture and call `.assert_calls(assertions)` on the fixture. diff --git a/bin/docker_tests b/bin/docker_tests index d046541..98db9e1 100755 --- a/bin/docker_tests +++ b/bin/docker_tests @@ -13,7 +13,7 @@ bin/dc up -d bin/dc exec -T shipchain-common /bin/bash -c '! poetry install --dry-run | grep "Warning: The lock file is not up to date" || (echo "poetry.lock does not match pyproject.toml" && exit 1)' -bin/dc exec -T shipchain-common safety check +bin/dc exec -T shipchain-common safety check -i 38224 bin/dc exec -T shipchain-common prospector -o pylint diff --git a/poetry.lock b/poetry.lock index f00dd19..650a840 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,13 @@ [[package]] -category = "dev" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -name = "appdirs" +category = "main" +description = "ASGI specs, helper code, and adapters" +name = "asgiref" optional = false -python-versions = "*" -version = "1.4.3" +python-versions = ">=3.5" +version = "3.2.10" + +[package.extras] +tests = ["pytest", "pytest-asyncio"] [[package]] category = "main" @@ -12,7 +15,7 @@ description = "Fast ASN.1 parser and serializer with definitions for private key name = "asn1crypto" optional = false python-versions = "*" -version = "1.3.0" +version = "1.4.0" [[package]] category = "dev" @@ -34,7 +37,7 @@ description = "Atomic file writes." name = "atomicwrites" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.3.0" +version = "1.4.0" [[package]] category = "dev" @@ -42,13 +45,13 @@ description = "Classes Without Boilerplate" name = "attrs" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "19.3.0" +version = "20.2.0" [package.extras] -azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"] -dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"] -docs = ["sphinx", "zope.interface"] -tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"] +docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] category = "main" @@ -56,7 +59,7 @@ description = "AWS signature version 4 signing process for the python requests m name = "aws-requests-auth" optional = false python-versions = "*" -version = "0.4.2" +version = "0.4.3" [package.dependencies] requests = ">=0.14.0" @@ -115,7 +118,7 @@ description = "Python package for providing Mozilla's CA Bundle." name = "certifi" optional = false python-versions = "*" -version = "2020.4.5.1" +version = "2020.6.20" [[package]] category = "main" @@ -123,7 +126,7 @@ description = "Foreign Function Interface for Python calling C code." name = "cffi" optional = false python-versions = "*" -version = "1.14.0" +version = "1.14.3" [package.dependencies] pycparser = "*" @@ -142,7 +145,7 @@ description = "Composable command line interface toolkit" name = "click" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "7.1.1" +version = "7.1.2" [[package]] category = "dev" @@ -181,25 +184,18 @@ idna = ["idna (>=2.1)"] pep8test = ["flake8", "flake8-import-order", "pep8-naming"] test = ["pytest (>=3.6.0,<3.9.0 || >3.9.0,<3.9.1 || >3.9.1,<3.9.2 || >3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"] -[[package]] -category = "dev" -description = "Distribution utilities" -name = "distlib" -optional = false -python-versions = "*" -version = "0.3.0" - [[package]] category = "main" description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." name = "django" optional = false -python-versions = ">=3.5" -version = "2.2.12" +python-versions = ">=3.6" +version = "3.0.10" [package.dependencies] +asgiref = ">=3.2,<4.0" pytz = "*" -sqlparse = "*" +sqlparse = ">=0.2.2" [package.extras] argon2 = ["argon2-cffi (>=16.1.0)"] @@ -211,7 +207,7 @@ description = "Real Python Enums for Django." name = "django-enumfields" optional = false python-versions = "*" -version = "0.10.1" +version = "2.0.0" [[package]] category = "main" @@ -233,7 +229,10 @@ description = "Web APIs for Django, made easy." name = "djangorestframework" optional = false python-versions = ">=3.5" -version = "3.10.3" +version = "3.11.1" + +[package.dependencies] +django = ">=1.11" [[package]] category = "main" @@ -241,11 +240,11 @@ description = "A Django REST framework API adapter for the JSON API spec." name = "djangorestframework-jsonapi" optional = false python-versions = ">=3.5" -version = "3.1.0" +version = "3.2.0" [package.dependencies] -django = ">=1.11" -djangorestframework = ">=3.10" +django = ">=1.11,<3.1" +djangorestframework = ">=3.10,<3.12" inflection = ">=0.3.0" [package.extras] @@ -297,12 +296,11 @@ category = "dev" description = "A parser for Python dependency files" name = "dparse" optional = false -python-versions = "*" -version = "0.5.0" +python-versions = ">=3.5" +version = "0.5.1" [package.dependencies] packaging = "*" -pipenv = "*" pyyaml = "*" toml = "*" @@ -321,21 +319,13 @@ version = "0.91" Django = ">=1.11" djangorestframework = ">=3.6.0" -[[package]] -category = "dev" -description = "A platform independent file lock." -name = "filelock" -optional = false -python-versions = "*" -version = "3.0.12" - [[package]] category = "dev" description = "Git Object Database" name = "gitdb" optional = false python-versions = ">=3.4" -version = "4.0.4" +version = "4.0.5" [package.dependencies] smmap = ">=3.0.1,<4" @@ -346,29 +336,18 @@ description = "Python Git Library" name = "gitpython" optional = false python-versions = ">=3.4" -version = "3.1.1" +version = "3.1.8" [package.dependencies] gitdb = ">=4.0.1,<5" -[[package]] -category = "dev" -description = "HTTP client mock for Python" -name = "httpretty" -optional = false -python-versions = "*" -version = "0.9.7" - -[package.dependencies] -six = "*" - [[package]] category = "main" description = "Internationalized Domain Names in Applications (IDNA)" name = "idna" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.9" +version = "2.10" [[package]] category = "dev" @@ -377,35 +356,14 @@ marker = "python_version < \"3.8\"" name = "importlib-metadata" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "1.6.0" +version = "1.7.0" [package.dependencies] zipp = ">=0.5" [package.extras] docs = ["sphinx", "rst.linker"] -testing = ["packaging", "importlib-resources"] - -[[package]] -category = "dev" -description = "Read resources from Python packages" -marker = "python_version < \"3.7\"" -name = "importlib-resources" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "1.4.0" - -[package.dependencies] -[package.dependencies.importlib-metadata] -python = "<3.8" -version = "*" - -[package.dependencies.zipp] -python = "<3.8" -version = ">=0.4" - -[package.extras] -docs = ["sphinx", "rst.linker", "jaraco.packaging"] +testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] [[package]] category = "main" @@ -413,7 +371,7 @@ description = "A port of Ruby on Rails inflector to Python" name = "inflection" optional = false python-versions = ">=3.5" -version = "0.4.0" +version = "0.5.1" [[package]] category = "main" @@ -452,16 +410,16 @@ category = "main" description = "JSON Matching Expressions" name = "jmespath" optional = false -python-versions = "*" -version = "0.9.5" +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +version = "0.10.0" [[package]] category = "dev" description = "A fast and thorough lazy object proxy." name = "lazy-object-proxy" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.4.3" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "1.5.1" [[package]] category = "dev" @@ -477,7 +435,7 @@ description = "More routines for operating on iterables, beyond itertools" name = "more-itertools" optional = false python-versions = ">=3.5" -version = "8.2.0" +version = "8.5.0" [[package]] category = "main" @@ -493,7 +451,7 @@ description = "Core utilities for Python packages" name = "packaging" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.3" +version = "20.4" [package.dependencies] pyparsing = ">=2.0.2" @@ -504,8 +462,8 @@ category = "dev" description = "Python Build Reasonableness" name = "pbr" optional = false -python-versions = "*" -version = "5.4.5" +python-versions = ">=2.6" +version = "5.5.0" [[package]] category = "dev" @@ -515,21 +473,6 @@ optional = false python-versions = "*" version = "0.4.1" -[[package]] -category = "dev" -description = "Python Development Workflow for Humans." -name = "pipenv" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "2018.11.26" - -[package.dependencies] -certifi = "*" -pip = ">=9.0.1" -setuptools = ">=36.2.1" -virtualenv = "*" -virtualenv-clone = ">=0.2.5" - [[package]] category = "dev" description = "plugin and hook calling mechanisms for python" @@ -585,10 +528,10 @@ description = "Cross-platform lib for process and system monitoring in Python." name = "psutil" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "5.7.0" +version = "5.7.2" [package.extras] -enum = ["enum34"] +test = ["ipaddress", "mock", "unittest2", "enum34", "pywin32", "wmi"] [[package]] category = "dev" @@ -596,7 +539,7 @@ description = "library with cross-python path, ini-parsing, io, code, log facili name = "py" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.8.1" +version = "1.9.0" [[package]] category = "dev" @@ -620,7 +563,7 @@ description = "Python docstring style checker" name = "pydocstyle" optional = false python-versions = ">=3.5" -version = "5.0.2" +version = "5.1.1" [package.dependencies] snowballstemmer = "*" @@ -742,15 +685,15 @@ category = "dev" description = "Pytest plugin for measuring coverage." name = "pytest-cov" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.8.1" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.9.0" [package.dependencies] coverage = ">=4.4" pytest = ">=3.6" [package.extras] -testing = ["fields", "hunter", "process-tests (2.0.2)", "six", "virtualenv"] +testing = ["fields", "hunter", "process-tests (2.0.2)", "six", "pytest-xdist", "virtualenv"] [[package]] category = "dev" @@ -758,7 +701,7 @@ description = "A Django plugin for pytest." name = "pytest-django" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "3.9.0" +version = "3.10.0" [package.dependencies] pytest = ">=3.6" @@ -809,7 +752,7 @@ description = "World timezone definitions, modern and historical" name = "pytz" optional = false python-versions = "*" -version = "2019.3" +version = "2020.1" [[package]] category = "dev" @@ -825,7 +768,7 @@ description = "Python HTTP for Humans." name = "requests" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.23.0" +version = "2.24.0" [package.dependencies] certifi = ">=2017.4.17" @@ -843,11 +786,27 @@ description = "Python tool to find and list requirements of a Python project" name = "requirements-detector" optional = false python-versions = "*" -version = "0.6" +version = "0.7" [package.dependencies] astroid = ">=1.4" +[[package]] +category = "dev" +description = "A utility library for mocking out the `requests` Python library." +name = "responses" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.12.0" + +[package.dependencies] +requests = ">=2.0" +six = "*" +urllib3 = ">=1.25.10" + +[package.extras] +tests = ["coverage (>=3.7.1,<6.0.0)", "pytest-cov", "pytest-localserver", "flake8", "pytest (>=4.6,<5.0)", "pytest (>=4.6)"] + [[package]] category = "main" description = "An Amazon S3 Transfer Manager" @@ -861,15 +820,15 @@ botocore = ">=1.12.36,<2.0.0" [[package]] category = "dev" -description = "Safety checks your installed dependencies for known security vulnerabilities." +description = "Checks installed dependencies for known vulnerabilities." name = "safety" optional = false -python-versions = "*" -version = "1.8.7" +python-versions = ">=3.5" +version = "1.9.0" [package.dependencies] Click = ">=6.0" -dparse = ">=0.4.1" +dparse = ">=0.5.1" packaging = "*" requests = "*" setuptools = "*" @@ -891,7 +850,7 @@ description = "Python 2 and 3 compatibility utilities" name = "six" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -version = "1.14.0" +version = "1.15.0" [[package]] category = "dev" @@ -899,7 +858,7 @@ description = "A pure Python implementation of a sliding window memory map manag name = "smmap" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "3.0.2" +version = "3.0.4" [[package]] category = "dev" @@ -922,12 +881,15 @@ category = "dev" description = "Manage dynamic plugins for Python applications" name = "stevedore" optional = false -python-versions = "*" -version = "1.32.0" +python-versions = ">=3.6" +version = "3.2.2" [package.dependencies] pbr = ">=2.0.0,<2.1.0 || >2.1.0" -six = ">=1.10.0" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=1.7.0" [[package]] category = "main" @@ -935,7 +897,7 @@ description = "Extract the top-level domain (TLD) from the URL given." name = "tld" optional = false python-versions = ">=2.7, <4" -version = "0.11.11" +version = "0.12.2" [[package]] category = "dev" @@ -943,7 +905,7 @@ description = "Python Library for Tom's Obvious, Minimal Language" name = "toml" optional = false python-versions = "*" -version = "0.10.0" +version = "0.10.1" [[package]] category = "dev" @@ -960,47 +922,13 @@ description = "HTTP library with thread-safe connection pooling, file post, and name = "urllib3" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "1.25.8" +version = "1.25.10" [package.extras] brotli = ["brotlipy (>=0.6.0)"] -secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] -[[package]] -category = "dev" -description = "Virtual Python Environment builder" -name = "virtualenv" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "20.0.17" - -[package.dependencies] -appdirs = ">=1.4.3,<2" -distlib = ">=0.3.0,<1" -filelock = ">=3.0.0,<4" -six = ">=1.9.0,<2" - -[package.dependencies.importlib-metadata] -python = "<3.8" -version = ">=0.12,<2" - -[package.dependencies.importlib-resources] -python = "<3.7" -version = ">=1.0,<2" - -[package.extras] -docs = ["sphinx (>=2.0.0,<3)", "sphinx-argparse (>=0.2.5,<1)", "sphinx-rtd-theme (>=0.4.3,<1)", "towncrier (>=19.9.0rc1)", "proselint (>=0.10.2,<1)"] -testing = ["pytest (>=4.0.0,<6)", "coverage (>=4.5.1,<6)", "pytest-mock (>=2.0.0,<3)", "pytest-env (>=0.6.2,<1)", "pytest-timeout (>=1.3.4,<2)", "packaging (>=20.0)", "xonsh (>=0.9.16,<1)"] - -[[package]] -category = "dev" -description = "script to clone virtualenvs." -name = "virtualenv-clone" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.5.4" - [[package]] category = "dev" description = "Module for decorators, wrappers and monkey patching." @@ -1023,32 +951,33 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["jaraco.itertools", "func-timeout"] [metadata] -content-hash = "24ed707fd79d1bfc37f811ee2de02d7f9294b855720075fde1bf72f93225c069" +content-hash = "5c75a70f94b0ad6eacbac86a0fbd6773387b3bc94915dbf0f078245450b3e632" python-versions = ">=3.6,<3.8" # Compatible python versions must be declared here [metadata.files] -appdirs = [ - {file = "appdirs-1.4.3-py2.py3-none-any.whl", hash = "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"}, - {file = "appdirs-1.4.3.tar.gz", hash = "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92"}, +asgiref = [ + {file = "asgiref-3.2.10-py3-none-any.whl", hash = "sha256:9fc6fb5d39b8af147ba40765234fa822b39818b12cc80b35ad9b0cef3a476aed"}, + {file = "asgiref-3.2.10.tar.gz", hash = "sha256:7e51911ee147dd685c3c8b805c0ad0cb58d360987b56953878f8c06d2d1c6f1a"}, ] asn1crypto = [ - {file = "asn1crypto-1.3.0-py2.py3-none-any.whl", hash = "sha256:831d2710d3274c8a74befdddaf9f17fcbf6e350534565074818722d6d615b315"}, - {file = "asn1crypto-1.3.0.tar.gz", hash = "sha256:5a215cb8dc12f892244e3a113fe05397ee23c5c4ca7a69cd6e69811755efc42d"}, + {file = "asn1crypto-1.4.0-py2.py3-none-any.whl", hash = "sha256:4bcdf33c861c7d40bdcd74d8e4dd7661aac320fcdf40b9a3f95b4ee12fde2fa8"}, + {file = "asn1crypto-1.4.0.tar.gz", hash = "sha256:f4f6e119474e58e04a2b1af817eb585b4fd72bdd89b998624712b5c99be7641c"}, ] astroid = [ {file = "astroid-2.2.5-py3-none-any.whl", hash = "sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4"}, {file = "astroid-2.2.5.tar.gz", hash = "sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4"}, ] atomicwrites = [ - {file = "atomicwrites-1.3.0-py2.py3-none-any.whl", hash = "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4"}, - {file = "atomicwrites-1.3.0.tar.gz", hash = "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"}, + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ - {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, - {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, + {file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"}, + {file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"}, ] aws-requests-auth = [ - {file = "aws-requests-auth-0.4.2.tar.gz", hash = "sha256:112c85fe938a01e28f7e1a87168615b6977b28596362b1dcbafbf4f2cc69f720"}, + {file = "aws-requests-auth-0.4.3.tar.gz", hash = "sha256:33593372018b960a31dbbe236f89421678b885c35f0b6a7abfae35bb77e069b2"}, + {file = "aws_requests_auth-0.4.3-py2.py3-none-any.whl", hash = "sha256:646bc37d62140ea1c709d20148f5d43197e6bd2d63909eb36fa4bb2345759977"}, ] bandit = [ {file = "bandit-1.6.2-py2.py3-none-any.whl", hash = "sha256:336620e220cf2d3115877685e264477ff9d9abaeb0afe3dc7264f55fa17a3952"}, @@ -1063,46 +992,54 @@ botocore = [ {file = "botocore-1.12.253.tar.gz", hash = "sha256:3baf129118575602ada9926f5166d82d02273c250d0feb313fc270944b27c48b"}, ] certifi = [ - {file = "certifi-2020.4.5.1-py2.py3-none-any.whl", hash = "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304"}, - {file = "certifi-2020.4.5.1.tar.gz", hash = "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"}, + {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"}, + {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"}, ] cffi = [ - {file = "cffi-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384"}, - {file = "cffi-1.14.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30"}, - {file = "cffi-1.14.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c"}, - {file = "cffi-1.14.0-cp27-cp27m-win32.whl", hash = "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78"}, - {file = "cffi-1.14.0-cp27-cp27m-win_amd64.whl", hash = "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793"}, - {file = "cffi-1.14.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e"}, - {file = "cffi-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a"}, - {file = "cffi-1.14.0-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff"}, - {file = "cffi-1.14.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f"}, - {file = "cffi-1.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa"}, - {file = "cffi-1.14.0-cp35-cp35m-win32.whl", hash = "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5"}, - {file = "cffi-1.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4"}, - {file = "cffi-1.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d"}, - {file = "cffi-1.14.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc"}, - {file = "cffi-1.14.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac"}, - {file = "cffi-1.14.0-cp36-cp36m-win32.whl", hash = "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f"}, - {file = "cffi-1.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b"}, - {file = "cffi-1.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3"}, - {file = "cffi-1.14.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66"}, - {file = "cffi-1.14.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0"}, - {file = "cffi-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f"}, - {file = "cffi-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26"}, - {file = "cffi-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd"}, - {file = "cffi-1.14.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55"}, - {file = "cffi-1.14.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2"}, - {file = "cffi-1.14.0-cp38-cp38-win32.whl", hash = "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8"}, - {file = "cffi-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b"}, - {file = "cffi-1.14.0.tar.gz", hash = "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6"}, + {file = "cffi-1.14.3-2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3eeeb0405fd145e714f7633a5173318bd88d8bbfc3dd0a5751f8c4f70ae629bc"}, + {file = "cffi-1.14.3-2-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:cb763ceceae04803adcc4e2d80d611ef201c73da32d8f2722e9d0ab0c7f10768"}, + {file = "cffi-1.14.3-2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:44f60519595eaca110f248e5017363d751b12782a6f2bd6a7041cba275215f5d"}, + {file = "cffi-1.14.3-2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c53af463f4a40de78c58b8b2710ade243c81cbca641e34debf3396a9640d6ec1"}, + {file = "cffi-1.14.3-2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:33c6cdc071ba5cd6d96769c8969a0531be2d08c2628a0143a10a7dcffa9719ca"}, + {file = "cffi-1.14.3-2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c11579638288e53fc94ad60022ff1b67865363e730ee41ad5e6f0a17188b327a"}, + {file = "cffi-1.14.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:3cb3e1b9ec43256c4e0f8d2837267a70b0e1ca8c4f456685508ae6106b1f504c"}, + {file = "cffi-1.14.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f0620511387790860b249b9241c2f13c3a80e21a73e0b861a2df24e9d6f56730"}, + {file = "cffi-1.14.3-cp27-cp27m-win32.whl", hash = "sha256:005f2bfe11b6745d726dbb07ace4d53f057de66e336ff92d61b8c7e9c8f4777d"}, + {file = "cffi-1.14.3-cp27-cp27m-win_amd64.whl", hash = "sha256:2f9674623ca39c9ebe38afa3da402e9326c245f0f5ceff0623dccdac15023e05"}, + {file = "cffi-1.14.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:09e96138280241bd355cd585148dec04dbbedb4f46128f340d696eaafc82dd7b"}, + {file = "cffi-1.14.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:3363e77a6176afb8823b6e06db78c46dbc4c7813b00a41300a4873b6ba63b171"}, + {file = "cffi-1.14.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0ef488305fdce2580c8b2708f22d7785ae222d9825d3094ab073e22e93dfe51f"}, + {file = "cffi-1.14.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:0b1ad452cc824665ddc682400b62c9e4f5b64736a2ba99110712fdee5f2505c4"}, + {file = "cffi-1.14.3-cp35-cp35m-win32.whl", hash = "sha256:85ba797e1de5b48aa5a8427b6ba62cf69607c18c5d4eb747604b7302f1ec382d"}, + {file = "cffi-1.14.3-cp35-cp35m-win_amd64.whl", hash = "sha256:e66399cf0fc07de4dce4f588fc25bfe84a6d1285cc544e67987d22663393926d"}, + {file = "cffi-1.14.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:15f351bed09897fbda218e4db5a3d5c06328862f6198d4fb385f3e14e19decb3"}, + {file = "cffi-1.14.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4d7c26bfc1ea9f92084a1d75e11999e97b62d63128bcc90c3624d07813c52808"}, + {file = "cffi-1.14.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:23e5d2040367322824605bc29ae8ee9175200b92cb5483ac7d466927a9b3d537"}, + {file = "cffi-1.14.3-cp36-cp36m-win32.whl", hash = "sha256:a624fae282e81ad2e4871bdb767e2c914d0539708c0f078b5b355258293c98b0"}, + {file = "cffi-1.14.3-cp36-cp36m-win_amd64.whl", hash = "sha256:de31b5164d44ef4943db155b3e8e17929707cac1e5bd2f363e67a56e3af4af6e"}, + {file = "cffi-1.14.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f92cdecb618e5fa4658aeb97d5eb3d2f47aa94ac6477c6daf0f306c5a3b9e6b1"}, + {file = "cffi-1.14.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:22399ff4870fb4c7ef19fff6eeb20a8bbf15571913c181c78cb361024d574579"}, + {file = "cffi-1.14.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f4eae045e6ab2bb54ca279733fe4eb85f1effda392666308250714e01907f394"}, + {file = "cffi-1.14.3-cp37-cp37m-win32.whl", hash = "sha256:b0358e6fefc74a16f745afa366acc89f979040e0cbc4eec55ab26ad1f6a9bfbc"}, + {file = "cffi-1.14.3-cp37-cp37m-win_amd64.whl", hash = "sha256:6642f15ad963b5092d65aed022d033c77763515fdc07095208f15d3563003869"}, + {file = "cffi-1.14.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:2791f68edc5749024b4722500e86303a10d342527e1e3bcac47f35fbd25b764e"}, + {file = "cffi-1.14.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:529c4ed2e10437c205f38f3691a68be66c39197d01062618c55f74294a4a4828"}, + {file = "cffi-1.14.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8f0f1e499e4000c4c347a124fa6a27d37608ced4fe9f7d45070563b7c4c370c9"}, + {file = "cffi-1.14.3-cp38-cp38-win32.whl", hash = "sha256:3b8eaf915ddc0709779889c472e553f0d3e8b7bdf62dab764c8921b09bf94522"}, + {file = "cffi-1.14.3-cp38-cp38-win_amd64.whl", hash = "sha256:bbd2f4dfee1079f76943767fce837ade3087b578aeb9f69aec7857d5bf25db15"}, + {file = "cffi-1.14.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:cc75f58cdaf043fe6a7a6c04b3b5a0e694c6a9e24050967747251fb80d7bce0d"}, + {file = "cffi-1.14.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:bf39a9e19ce7298f1bd6a9758fa99707e9e5b1ebe5e90f2c3913a47bc548747c"}, + {file = "cffi-1.14.3-cp39-cp39-win32.whl", hash = "sha256:d80998ed59176e8cba74028762fbd9b9153b9afc71ea118e63bbf5d4d0f9552b"}, + {file = "cffi-1.14.3-cp39-cp39-win_amd64.whl", hash = "sha256:c150eaa3dadbb2b5339675b88d4573c1be3cb6f2c33a6c83387e10cc0bf05bd3"}, + {file = "cffi-1.14.3.tar.gz", hash = "sha256:f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591"}, ] chardet = [ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, ] click = [ - {file = "click-7.1.1-py2.py3-none-any.whl", hash = "sha256:e345d143d80bf5ee7534056164e5e112ea5e22716bbb1ce727941f4c8b471b9a"}, - {file = "click-7.1.1.tar.gz", hash = "sha256:8a18b4ea89d8820c5d0c7da8a64b2c324b4dabb695804dbfea19b9be9d88c0cc"}, + {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, + {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, ] colorama = [ {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, @@ -1163,26 +1100,24 @@ cryptography = [ {file = "cryptography-2.5-cp37-cp37m-win_amd64.whl", hash = "sha256:31e5637e9036d966824edaa91bf0aa39dc6f525a1c599f39fd5c50340264e079"}, {file = "cryptography-2.5.tar.gz", hash = "sha256:4946b67235b9d2ea7d31307be9d5ad5959d6c4a8f98f900157b47abddf698401"}, ] -distlib = [ - {file = "distlib-0.3.0.zip", hash = "sha256:2e166e231a26b36d6dfe35a48c4464346620f8645ed0ace01ee31822b288de21"}, -] django = [ - {file = "Django-2.2.12-py3-none-any.whl", hash = "sha256:6ecd229e1815d4fc5240fc98f1cca78c41e7a8cd3e3f2eefadc4735031077916"}, - {file = "Django-2.2.12.tar.gz", hash = "sha256:69897097095f336d5aeef45b4103dceae51c00afa6d3ae198a2a18e519791b7a"}, + {file = "Django-3.0.10-py3-none-any.whl", hash = "sha256:313d0b8f96685e99327785cc600a5178ca855f8e6f4ed162e671e8c3cf749739"}, + {file = "Django-3.0.10.tar.gz", hash = "sha256:2d14be521c3ae24960e5e83d4575e156a8c479a75c935224b671b1c6e66eddaf"}, ] django-enumfields = [ - {file = "django-enumfields-0.10.1.tar.gz", hash = "sha256:6a69868afac1ce6153760fdcce74361dac7b74bdf0c5cf58c7456aa731cf2d4b"}, + {file = "django-enumfields-2.0.0.tar.gz", hash = "sha256:e94f6b39de7adc0716130101d75eede3834b42e2a895599c19354eb1bb7fbdd1"}, + {file = "django_enumfields-2.0.0-py3-none-any.whl", hash = "sha256:9bc0e2c410723c9592992155f32adadcedc11c841f6888dcf721f5f638d466e3"}, ] django-influxdb-tagged-metrics = [ {file = "django-influxdb-tagged-metrics-1.3.3.tar.gz", hash = "sha256:f2a7c8dee5b32835b450474cc898e9842a4b9bfe10d8ba9f3f51eba9e45eaa5f"}, ] djangorestframework = [ - {file = "djangorestframework-3.10.3-py3-none-any.whl", hash = "sha256:5488aed8f8df5ec1d70f04b2114abc52ae6729748a176c453313834a9ee179c8"}, - {file = "djangorestframework-3.10.3.tar.gz", hash = "sha256:dc81cbf9775c6898a580f6f1f387c4777d12bd87abf0f5406018d32ccae71090"}, + {file = "djangorestframework-3.11.1-py3-none-any.whl", hash = "sha256:8b1ac62c581dbc5799b03e535854b92fc4053ecfe74bad3f9c05782063d4196b"}, + {file = "djangorestframework-3.11.1.tar.gz", hash = "sha256:6dd02d5a4bd2516fb93f80360673bf540c3b6641fec8766b1da2870a5aa00b32"}, ] djangorestframework-jsonapi = [ - {file = "djangorestframework-jsonapi-3.1.0.tar.gz", hash = "sha256:894826320cc9e06942b3f6e3604fc5c093854275fab498d52de4a3cd24aac58f"}, - {file = "djangorestframework_jsonapi-3.1.0-py2.py3-none-any.whl", hash = "sha256:8d61bb16970e6c4b737b166c3888a319f86dad0321a41d801426d24a6ebd9fc7"}, + {file = "djangorestframework-jsonapi-3.2.0.tar.gz", hash = "sha256:8a438fba41c1ef477a2d6da70224e767528ed116ebc1e219c4ca850460ac7d0a"}, + {file = "djangorestframework_jsonapi-3.2.0-py2.py3-none-any.whl", hash = "sha256:213656fb5d4b336df3ca61bff766d19e926784f9a28c7cc482a7916d335cad40"}, ] djangorestframework-simplejwt = [] docutils = [ @@ -1195,43 +1130,32 @@ dodgy = [ {file = "dodgy-0.2.1.tar.gz", hash = "sha256:28323cbfc9352139fdd3d316fa17f325cc0e9ac74438cbba51d70f9b48f86c3a"}, ] dparse = [ - {file = "dparse-0.5.0-py3-none-any.whl", hash = "sha256:14fed5efc5e98c0a81dfe100c4c2ea0a4c189104e9a9d18b5cfd342a163f97be"}, - {file = "dparse-0.5.0.tar.gz", hash = "sha256:db349e53f6d03c8ee80606c49b35f515ed2ab287a8e1579e2b4bdf52b12b1530"}, + {file = "dparse-0.5.1-py3-none-any.whl", hash = "sha256:e953a25e44ebb60a5c6efc2add4420c177f1d8404509da88da9729202f306994"}, + {file = "dparse-0.5.1.tar.gz", hash = "sha256:a1b5f169102e1c894f9a7d5ccf6f9402a836a5d24be80a986c7ce9eaed78f367"}, ] drf-nested-routers = [ {file = "drf-nested-routers-0.91.tar.gz", hash = "sha256:46e5c3abc15c782cafafd7d75028e8f9121bbc6228e3599bbb48a3daa4585034"}, {file = "drf_nested_routers-0.91-py2.py3-none-any.whl", hash = "sha256:60c1e1f5cc801e757d26a8138e61c44419ef800c213c3640c5b6138e77d46762"}, ] -filelock = [ - {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, - {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, -] gitdb = [ - {file = "gitdb-4.0.4-py3-none-any.whl", hash = "sha256:ba1132c0912e8c917aa8aa990bee26315064c7b7f171ceaaac0afeb1dc656c6a"}, - {file = "gitdb-4.0.4.tar.gz", hash = "sha256:6f0ecd46f99bb4874e5678d628c3a198e2b4ef38daea2756a2bfd8df7dd5c1a5"}, + {file = "gitdb-4.0.5-py3-none-any.whl", hash = "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac"}, + {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, ] gitpython = [ - {file = "GitPython-3.1.1-py3-none-any.whl", hash = "sha256:71b8dad7409efbdae4930f2b0b646aaeccce292484ffa0bc74f1195582578b3d"}, - {file = "GitPython-3.1.1.tar.gz", hash = "sha256:6d4f10e2aaad1864bb0f17ec06a2c2831534140e5883c350d58b4e85189dab74"}, -] -httpretty = [ - {file = "httpretty-0.9.7.tar.gz", hash = "sha256:66216f26b9d2c52e81808f3e674a6fb65d4bf719721394a1a9be926177e55fbe"}, + {file = "GitPython-3.1.8-py3-none-any.whl", hash = "sha256:1858f4fd089abe92ae465f01d5aaaf55e937eca565fb2c1fce35a51b5f85c910"}, + {file = "GitPython-3.1.8.tar.gz", hash = "sha256:080bf8e2cf1a2b907634761c2eaefbe83b69930c94c66ad11b65a8252959f912"}, ] idna = [ - {file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"}, - {file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"}, + {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, + {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, ] importlib-metadata = [ - {file = "importlib_metadata-1.6.0-py2.py3-none-any.whl", hash = "sha256:2a688cbaa90e0cc587f1df48bdc97a6eadccdcd9c35fb3f976a09e3b5016d90f"}, - {file = "importlib_metadata-1.6.0.tar.gz", hash = "sha256:34513a8a0c4962bc66d35b359558fd8a5e10cd472d37aec5f66858addef32c1e"}, -] -importlib-resources = [ - {file = "importlib_resources-1.4.0-py2.py3-none-any.whl", hash = "sha256:dd98ceeef3f5ad2ef4cc287b8586da4ebad15877f351e9688987ad663a0a29b8"}, - {file = "importlib_resources-1.4.0.tar.gz", hash = "sha256:4019b6a9082d8ada9def02bece4a76b131518866790d58fdda0b5f8c603b36c2"}, + {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"}, + {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"}, ] inflection = [ - {file = "inflection-0.4.0-py2.py3-none-any.whl", hash = "sha256:9a15d3598f01220e93f2207c432cfede50daff53137ce660fb8be838ef1ca6cc"}, - {file = "inflection-0.4.0.tar.gz", hash = "sha256:32a5c3341d9583ec319548b9015b7fbdf8c429cbcb575d326c33ae3a0e90d52c"}, + {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}, + {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, ] influxdb = [ {file = "influxdb-5.3.0-py2.py3-none-any.whl", hash = "sha256:b4c034ee9c9ee888d43de547cf40c616bba35f0aa8f11e5a6f056bf5855970ac"}, @@ -1242,39 +1166,40 @@ isort = [ {file = "isort-4.3.21.tar.gz", hash = "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1"}, ] jmespath = [ - {file = "jmespath-0.9.5-py2.py3-none-any.whl", hash = "sha256:695cb76fa78a10663425d5b73ddc5714eb711157e52704d69be03b1a02ba4fec"}, - {file = "jmespath-0.9.5.tar.gz", hash = "sha256:cca55c8d153173e21baa59983015ad0daf603f9cb799904ff057bfb8ff8dc2d9"}, + {file = "jmespath-0.10.0-py2.py3-none-any.whl", hash = "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"}, + {file = "jmespath-0.10.0.tar.gz", hash = "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9"}, ] lazy-object-proxy = [ - {file = "lazy-object-proxy-1.4.3.tar.gz", hash = "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"}, - {file = "lazy_object_proxy-1.4.3-cp27-cp27m-macosx_10_13_x86_64.whl", hash = "sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442"}, - {file = "lazy_object_proxy-1.4.3-cp27-cp27m-win32.whl", hash = "sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4"}, - {file = "lazy_object_proxy-1.4.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a"}, - {file = "lazy_object_proxy-1.4.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d"}, - {file = "lazy_object_proxy-1.4.3-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a"}, - {file = "lazy_object_proxy-1.4.3-cp34-cp34m-win32.whl", hash = "sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e"}, - {file = "lazy_object_proxy-1.4.3-cp34-cp34m-win_amd64.whl", hash = "sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357"}, - {file = "lazy_object_proxy-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50"}, - {file = "lazy_object_proxy-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db"}, - {file = "lazy_object_proxy-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449"}, - {file = "lazy_object_proxy-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156"}, - {file = "lazy_object_proxy-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531"}, - {file = "lazy_object_proxy-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb"}, - {file = "lazy_object_proxy-1.4.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08"}, - {file = "lazy_object_proxy-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383"}, - {file = "lazy_object_proxy-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142"}, - {file = "lazy_object_proxy-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea"}, - {file = "lazy_object_proxy-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62"}, - {file = "lazy_object_proxy-1.4.3-cp38-cp38-win32.whl", hash = "sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd"}, - {file = "lazy_object_proxy-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239"}, + {file = "lazy-object-proxy-1.5.1.tar.gz", hash = "sha256:9723364577b79ad9958a68851fe2acb94da6fd25170c595516a8289e6a129043"}, + {file = "lazy_object_proxy-1.5.1-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:92cedd6e26712505adb1c17fab64651a498cc0102a80ba562ff4a2451088f57a"}, + {file = "lazy_object_proxy-1.5.1-cp27-cp27m-win32.whl", hash = "sha256:ef355fb3802e0fc5a71dadb65a3c317bfc9bdf567d357f8e0b1900b432ffe486"}, + {file = "lazy_object_proxy-1.5.1-cp27-cp27m-win_amd64.whl", hash = "sha256:3e8698dc384857413580012f4ca322d89e63ef20fc3d4635a5b606d6d4b61f6a"}, + {file = "lazy_object_proxy-1.5.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:edbcb4c5efabd93ede05b272296a5a78a67e9b6e82ba7f51a07b8103db06ce01"}, + {file = "lazy_object_proxy-1.5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:33da47ba3a581860ddd3d38c950a5fe950ca389f7123edd0d6ab0bc473499fe7"}, + {file = "lazy_object_proxy-1.5.1-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:c697bd1b333b3e6abdff04ef9f5fb4b1936633d9cc4e28d90606705c9083254c"}, + {file = "lazy_object_proxy-1.5.1-cp35-cp35m-win32.whl", hash = "sha256:8133b63b05f12751cddd8e3e7f02ba39dc7cfa7d2ba99d80d7436f0ba26d6b75"}, + {file = "lazy_object_proxy-1.5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:30ef2068f4f94660144515380ef04b93d15add2214eab8be4cd46ebc900d681c"}, + {file = "lazy_object_proxy-1.5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:042b54fd71c2092e6d10e5e66fa60f65c5954f8145e809f5d9f394c9b13d32ee"}, + {file = "lazy_object_proxy-1.5.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:db2df3eff7ed3e6813638686f1bb5934d1a0662d9d3b4196b5164a86be3a1e8f"}, + {file = "lazy_object_proxy-1.5.1-cp36-cp36m-win32.whl", hash = "sha256:4fdd7113fc5143c72dacf415079eec42fcbe69cc9d3d291b4ca742e3a9455807"}, + {file = "lazy_object_proxy-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:11f87dc06eb5f376cc6d5f0c19a1b4dca202035622777c4ce8e5b72c87b035d6"}, + {file = "lazy_object_proxy-1.5.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:22c1935c6f8e3d6ea2e169eb03928adbdb8a2251d2890f8689368d65e70aa176"}, + {file = "lazy_object_proxy-1.5.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:19ae6f6511a02008ef3554e158c41bb2a8e5c8455935b98d6da076d9f152fd7c"}, + {file = "lazy_object_proxy-1.5.1-cp37-cp37m-win32.whl", hash = "sha256:8d82e27cbbea6edb8821751806f39f5dcfd7b46a5e23d27b98d6d8c8ec751df8"}, + {file = "lazy_object_proxy-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:c484020ad26973a14a7cb1e1d2e0bfe97cf6803273ae9bd154e0213cc74bad49"}, + {file = "lazy_object_proxy-1.5.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:fe2f61fed5817bf8db01d9a72309ed5990c478a077e9585b58740c26774bce39"}, + {file = "lazy_object_proxy-1.5.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:63b6d9a5077d54db271fcc6772440f7380ec3fa559d0e2497dbfae2f47c2c814"}, + {file = "lazy_object_proxy-1.5.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:d0f7e14ff3424639d33e6bc449e77e4b345e52c21bbd6f6004a1d219196e2664"}, + {file = "lazy_object_proxy-1.5.1-cp38-cp38-win32.whl", hash = "sha256:89b8e5780e49753e2b4cd5aab45d3df092ddcbba3de2c4d4492a029588fe1758"}, + {file = "lazy_object_proxy-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:00b78a97a79d0dfefa584d44dd1aba9668d3de7ec82335ba0ff51d53ef107143"}, ] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] more-itertools = [ - {file = "more-itertools-8.2.0.tar.gz", hash = "sha256:b1ddb932186d8a6ac451e1d95844b382f55e12686d51ca0c68b6f61f2ab7a507"}, - {file = "more_itertools-8.2.0-py3-none-any.whl", hash = "sha256:5dd8bcf33e5f9513ffa06d5ad33d78f31e1931ac9a18f33d37e77a180d393a7c"}, + {file = "more-itertools-8.5.0.tar.gz", hash = "sha256:6f83822ae94818eae2612063a5101a7311e68ae8002005b5e05f03fd74a86a20"}, + {file = "more_itertools-8.5.0-py3-none-any.whl", hash = "sha256:9b30f12df9393f0d28af9210ff8efe48d10c94f73e5daf886f10c4b0b0b4f03c"}, ] msgpack = [ {file = "msgpack-0.6.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:3129c355342853007de4a2a86e75eab966119733eb15748819b6554363d4e85c"}, @@ -1296,22 +1221,17 @@ msgpack = [ {file = "msgpack-0.6.1.tar.gz", hash = "sha256:4008c72f5ef2b7936447dcb83db41d97e9791c83221be13d5e19db0796df1972"}, ] packaging = [ - {file = "packaging-20.3-py2.py3-none-any.whl", hash = "sha256:82f77b9bee21c1bafbf35a84905d604d5d1223801d639cf3ed140bd651c08752"}, - {file = "packaging-20.3.tar.gz", hash = "sha256:3c292b474fda1671ec57d46d739d072bfd495a4f51ad01a055121d81e952b7a3"}, + {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, + {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, ] pbr = [ - {file = "pbr-5.4.5-py2.py3-none-any.whl", hash = "sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8"}, - {file = "pbr-5.4.5.tar.gz", hash = "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c"}, + {file = "pbr-5.5.0-py2.py3-none-any.whl", hash = "sha256:5adc0f9fc64319d8df5ca1e4e06eea674c26b80e6f00c530b18ce6a6592ead15"}, + {file = "pbr-5.5.0.tar.gz", hash = "sha256:14bfd98f51c78a3dd22a1ef45cf194ad79eee4a19e8e1a0d5c7f8e81ffe182ea"}, ] pep8-naming = [ {file = "pep8-naming-0.4.1.tar.gz", hash = "sha256:4eedfd4c4b05e48796f74f5d8628c068ff788b9c2b08471ad408007fc6450e5a"}, {file = "pep8_naming-0.4.1-py2.py3-none-any.whl", hash = "sha256:1b419fa45b68b61cd8c5daf4e0c96d28915ad14d3d5f35fcc1e7e95324a33a2e"}, ] -pipenv = [ - {file = "pipenv-2018.11.26-py2-none-any.whl", hash = "sha256:7df8e33a2387de6f537836f48ac6fcd94eda6ed9ba3d5e3fd52e35b5bc7ff49e"}, - {file = "pipenv-2018.11.26-py3-none-any.whl", hash = "sha256:56ad5f5cb48f1e58878e14525a6e3129d4306049cb76d2f6a3e95df0d5fc6330"}, - {file = "pipenv-2018.11.26.tar.gz", hash = "sha256:a673e606e8452185e9817a987572b55360f4d28b50831ef3b42ac3cab3fee846"}, -] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, @@ -1320,21 +1240,21 @@ prospector = [ {file = "prospector-1.1.7.tar.gz", hash = "sha256:aba551e53dc1a5a432afa67385eaa81d7b4cf4c162dc1a4d0ee00b3a0712ad90"}, ] psutil = [ - {file = "psutil-5.7.0-cp27-none-win32.whl", hash = "sha256:298af2f14b635c3c7118fd9183843f4e73e681bb6f01e12284d4d70d48a60953"}, - {file = "psutil-5.7.0-cp27-none-win_amd64.whl", hash = "sha256:75e22717d4dbc7ca529ec5063000b2b294fc9a367f9c9ede1f65846c7955fd38"}, - {file = "psutil-5.7.0-cp35-cp35m-win32.whl", hash = "sha256:f344ca230dd8e8d5eee16827596f1c22ec0876127c28e800d7ae20ed44c4b310"}, - {file = "psutil-5.7.0-cp35-cp35m-win_amd64.whl", hash = "sha256:e2d0c5b07c6fe5a87fa27b7855017edb0d52ee73b71e6ee368fae268605cc3f5"}, - {file = "psutil-5.7.0-cp36-cp36m-win32.whl", hash = "sha256:a02f4ac50d4a23253b68233b07e7cdb567bd025b982d5cf0ee78296990c22d9e"}, - {file = "psutil-5.7.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1413f4158eb50e110777c4f15d7c759521703bd6beb58926f1d562da40180058"}, - {file = "psutil-5.7.0-cp37-cp37m-win32.whl", hash = "sha256:d008ddc00c6906ec80040d26dc2d3e3962109e40ad07fd8a12d0284ce5e0e4f8"}, - {file = "psutil-5.7.0-cp37-cp37m-win_amd64.whl", hash = "sha256:73f35ab66c6c7a9ce82ba44b1e9b1050be2a80cd4dcc3352cc108656b115c74f"}, - {file = "psutil-5.7.0-cp38-cp38-win32.whl", hash = "sha256:60b86f327c198561f101a92be1995f9ae0399736b6eced8f24af41ec64fb88d4"}, - {file = "psutil-5.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:d84029b190c8a66a946e28b4d3934d2ca1528ec94764b180f7d6ea57b0e75e26"}, - {file = "psutil-5.7.0.tar.gz", hash = "sha256:685ec16ca14d079455892f25bd124df26ff9137664af445563c1bd36629b5e0e"}, + {file = "psutil-5.7.2-cp27-none-win32.whl", hash = "sha256:f2018461733b23f308c298653c8903d32aaad7873d25e1d228765e91ae42c3f2"}, + {file = "psutil-5.7.2-cp27-none-win_amd64.whl", hash = "sha256:66c18ca7680a31bf16ee22b1d21b6397869dda8059dbdb57d9f27efa6615f195"}, + {file = "psutil-5.7.2-cp35-cp35m-win32.whl", hash = "sha256:5e9d0f26d4194479a13d5f4b3798260c20cecf9ac9a461e718eb59ea520a360c"}, + {file = "psutil-5.7.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4080869ed93cce662905b029a1770fe89c98787e543fa7347f075ade761b19d6"}, + {file = "psutil-5.7.2-cp36-cp36m-win32.whl", hash = "sha256:d8a82162f23c53b8525cf5f14a355f5d1eea86fa8edde27287dd3a98399e4fdf"}, + {file = "psutil-5.7.2-cp36-cp36m-win_amd64.whl", hash = "sha256:0ee3c36428f160d2d8fce3c583a0353e848abb7de9732c50cf3356dd49ad63f8"}, + {file = "psutil-5.7.2-cp37-cp37m-win32.whl", hash = "sha256:ff1977ba1a5f71f89166d5145c3da1cea89a0fdb044075a12c720ee9123ec818"}, + {file = "psutil-5.7.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a5b120bb3c0c71dfe27551f9da2f3209a8257a178ed6c628a819037a8df487f1"}, + {file = "psutil-5.7.2-cp38-cp38-win32.whl", hash = "sha256:10512b46c95b02842c225f58fa00385c08fa00c68bac7da2d9a58ebe2c517498"}, + {file = "psutil-5.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:68d36986ded5dac7c2dcd42f2682af1db80d4bce3faa126a6145c1637e1b559f"}, + {file = "psutil-5.7.2.tar.gz", hash = "sha256:90990af1c3c67195c44c9a889184f84f5b2320dce3ee3acbd054e3ba0b4a7beb"}, ] py = [ - {file = "py-1.8.1-py2.py3-none-any.whl", hash = "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0"}, - {file = "py-1.8.1.tar.gz", hash = "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa"}, + {file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"}, + {file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"}, ] pycodestyle = [ {file = "pycodestyle-2.4.0-py2.py3-none-any.whl", hash = "sha256:cbc619d09254895b0d12c2c691e237b2e91e9b2ecf5e84c26b35400f93dcfb83"}, @@ -1346,8 +1266,8 @@ pycparser = [ {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, ] pydocstyle = [ - {file = "pydocstyle-5.0.2-py3-none-any.whl", hash = "sha256:da7831660b7355307b32778c4a0dbfb137d89254ef31a2b2978f50fc0b4d7586"}, - {file = "pydocstyle-5.0.2.tar.gz", hash = "sha256:f4f5d210610c2d153fae39093d44224c17429e2ad7da12a8b419aba5c2f614b5"}, + {file = "pydocstyle-5.1.1-py3-none-any.whl", hash = "sha256:aca749e190a01726a4fb472dd4ef23b5c9da7b9205c0a7857c06533de13fd678"}, + {file = "pydocstyle-5.1.1.tar.gz", hash = "sha256:19b86fa8617ed916776a11cd8bc0197e5b9856d5433b777f51a3defe13075325"}, ] pyflakes = [ {file = "pyflakes-1.6.0-py2.py3-none-any.whl", hash = "sha256:08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f"}, @@ -1384,12 +1304,12 @@ pytest = [ {file = "pytest-3.10.1.tar.gz", hash = "sha256:e246cf173c01169b9617fc07264b7b1316e78d7a650055235d6d897bc80d9660"}, ] pytest-cov = [ - {file = "pytest-cov-2.8.1.tar.gz", hash = "sha256:cc6742d8bac45070217169f5f72ceee1e0e55b0221f54bcf24845972d3a47f2b"}, - {file = "pytest_cov-2.8.1-py2.py3-none-any.whl", hash = "sha256:cdbdef4f870408ebdbfeb44e63e07eb18bb4619fae852f6e760645fa36172626"}, + {file = "pytest-cov-2.9.0.tar.gz", hash = "sha256:b6a814b8ed6247bd81ff47f038511b57fe1ce7f4cc25b9106f1a4b106f1d9322"}, + {file = "pytest_cov-2.9.0-py2.py3-none-any.whl", hash = "sha256:c87dfd8465d865655a8213859f1b4749b43448b5fae465cb981e16d52a811424"}, ] pytest-django = [ - {file = "pytest-django-3.9.0.tar.gz", hash = "sha256:664e5f42242e5e182519388f01b9f25d824a9feb7cd17d8f863c8d776f38baf9"}, - {file = "pytest_django-3.9.0-py2.py3-none-any.whl", hash = "sha256:64f99d565dd9497af412fcab2989fe40982c1282d4118ff422b407f3f7275ca5"}, + {file = "pytest-django-3.10.0.tar.gz", hash = "sha256:4de6dbd077ed8606616958f77655fed0d5e3ee45159475671c7fa67596c6dba6"}, + {file = "pytest_django-3.10.0-py2.py3-none-any.whl", hash = "sha256:c33e3d3da14d8409b125d825d4e74da17bb252191bf6fc3da6856e27a8b73ea4"}, ] pytest-mock = [ {file = "pytest-mock-1.13.0.tar.gz", hash = "sha256:e24a911ec96773022ebcc7030059b57cd3480b56d4f5d19b7c370ec635e6aed5"}, @@ -1403,8 +1323,8 @@ python-server-metrics = [ {file = "python-server-metrics-0.2.1.tar.gz", hash = "sha256:da123c526fe7f1cc480797acd279b8c2ab139811b917ce378787fb9bd7f51b33"}, ] pytz = [ - {file = "pytz-2019.3-py2.py3-none-any.whl", hash = "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d"}, - {file = "pytz-2019.3.tar.gz", hash = "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"}, + {file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"}, + {file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"}, ] pyyaml = [ {file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"}, @@ -1420,30 +1340,34 @@ pyyaml = [ {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, ] requests = [ - {file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"}, - {file = "requests-2.23.0.tar.gz", hash = "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"}, + {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, + {file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"}, ] requirements-detector = [ - {file = "requirements-detector-0.6.tar.gz", hash = "sha256:9fbc4b24e8b7c3663aff32e3eba34596848c6b91bd425079b386973bd8d08931"}, + {file = "requirements-detector-0.7.tar.gz", hash = "sha256:0d1e13e61ed243f9c3c86e6cbb19980bcb3a0e0619cde2ec1f3af70fdbee6f7b"}, +] +responses = [ + {file = "responses-0.12.0-py2.py3-none-any.whl", hash = "sha256:0de50fbf600adf5ef9f0821b85cc537acca98d66bc7776755924476775c1989c"}, + {file = "responses-0.12.0.tar.gz", hash = "sha256:e80d5276011a4b79ecb62c5f82ba07aa23fb31ecbc95ee7cad6de250a3c97444"}, ] s3transfer = [ {file = "s3transfer-0.2.1-py2.py3-none-any.whl", hash = "sha256:b780f2411b824cb541dbcd2c713d0cb61c7d1bcadae204cdddda2b35cef493ba"}, {file = "s3transfer-0.2.1.tar.gz", hash = "sha256:6efc926738a3cd576c2a79725fed9afde92378aa5c6a957e3af010cb019fac9d"}, ] safety = [ - {file = "safety-1.8.7-py2.py3-none-any.whl", hash = "sha256:05f77773bbab834502328b29ed013677aa53ed0c22b6e330aef7d2a7e1dfd838"}, - {file = "safety-1.8.7.tar.gz", hash = "sha256:3016631e0dd17193d6cf12e8ed1af92df399585e8ee0e4b1300d9e7e32b54903"}, + {file = "safety-1.9.0-py2.py3-none-any.whl", hash = "sha256:86c1c4a031fe35bd624fce143fbe642a0234d29f7cbf7a9aa269f244a955b087"}, + {file = "safety-1.9.0.tar.gz", hash = "sha256:23bf20690d4400edc795836b0c983c2b4cbbb922233108ff925b7dd7750f00c9"}, ] setoptconf = [ {file = "setoptconf-0.2.0.tar.gz", hash = "sha256:5b0b5d8e0077713f5d5152d4f63be6f048d9a1bb66be15d089a11c898c3cf49c"}, ] six = [ - {file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"}, - {file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"}, + {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, + {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, ] smmap = [ - {file = "smmap-3.0.2-py2.py3-none-any.whl", hash = "sha256:52ea78b3e708d2c2b0cfe93b6fc3fbeec53db913345c26be6ed84c11ed8bebc1"}, - {file = "smmap-3.0.2.tar.gz", hash = "sha256:b46d3fc69ba5f367df96d91f8271e8ad667a198d5a28e215a6c3d9acd133a911"}, + {file = "smmap-3.0.4-py2.py3-none-any.whl", hash = "sha256:54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4"}, + {file = "smmap-3.0.4.tar.gz", hash = "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"}, ] snowballstemmer = [ {file = "snowballstemmer-2.0.0-py2.py3-none-any.whl", hash = "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0"}, @@ -1454,21 +1378,20 @@ sqlparse = [ {file = "sqlparse-0.3.1.tar.gz", hash = "sha256:e162203737712307dfe78860cc56c8da8a852ab2ee33750e33aeadf38d12c548"}, ] stevedore = [ - {file = "stevedore-1.32.0-py2.py3-none-any.whl", hash = "sha256:a4e7dc759fb0f2e3e2f7d8ffe2358c19d45b9b8297f393ef1256858d82f69c9b"}, - {file = "stevedore-1.32.0.tar.gz", hash = "sha256:18afaf1d623af5950cc0f7e75e70f917784c73b652a34a12d90b309451b5500b"}, + {file = "stevedore-3.2.2-py3-none-any.whl", hash = "sha256:5e1ab03eaae06ef6ce23859402de785f08d97780ed774948ef16c4652c41bc62"}, + {file = "stevedore-3.2.2.tar.gz", hash = "sha256:f845868b3a3a77a2489d226568abe7328b5c2d4f6a011cc759dfa99144a521f0"}, ] tld = [ - {file = "tld-0.11.11-py27-none-any.whl", hash = "sha256:d13fe1171c8d9d383ce822c50915d35ba52c3b78fb7caacb10035230e2e113f7"}, - {file = "tld-0.11.11-py35-none-any.whl", hash = "sha256:f466c6eb96e7dbc51817d2dbc9a832e78b0cad6661740334016a79bfdb1477b1"}, - {file = "tld-0.11.11-py36-none-any.whl", hash = "sha256:670f30e23ed35a7f9ee459801950e49b02554477d4d3e72cd2d92d39b2267470"}, - {file = "tld-0.11.11-py37-none-any.whl", hash = "sha256:a31d333253cc3033999ad5e6a2a34e9453bf9ac700de82da5f1e7487e4acbdaa"}, - {file = "tld-0.11.11-py38-none-any.whl", hash = "sha256:fc8267ee1d78ba02b8970199af0c0efb4624ac3e2177e50cbf05916bd5df8b12"}, - {file = "tld-0.11.11.tar.gz", hash = "sha256:72c7170f68ade92a07be43b363afc8e42a98ffa3700d899a984fdbeedb339bac"}, + {file = "tld-0.12.2-py27-none-any.whl", hash = "sha256:afc49c2d8d03ebd3cb686fc958747c03d0db5f51a5c5038c893a44fdae4a1987"}, + {file = "tld-0.12.2-py35-none-any.whl", hash = "sha256:66d1b79284d014a40c36d675c1a56ec22a716d87da2a190b12fe2b267c5a95e9"}, + {file = "tld-0.12.2-py36-none-any.whl", hash = "sha256:3e7ecadbc58632af78b2aa887d6eaf0d20983061720c070e5bd5639c2bcf63cb"}, + {file = "tld-0.12.2-py37-none-any.whl", hash = "sha256:5eb6f39835c286189cd3bab7613e1d611fd03e91a5b1926172020c978881daef"}, + {file = "tld-0.12.2-py38-none-any.whl", hash = "sha256:7a172dc412bb46624f6c61c7afa9ba581a9147699c94386b802830836752ba9f"}, + {file = "tld-0.12.2.tar.gz", hash = "sha256:cf8410a7ed7b9477f563fa158dabef5117d8374cba55f65142ba0af6dcd15d4d"}, ] toml = [ - {file = "toml-0.10.0-py2.7.egg", hash = "sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"}, - {file = "toml-0.10.0-py2.py3-none-any.whl", hash = "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"}, - {file = "toml-0.10.0.tar.gz", hash = "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c"}, + {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, + {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"}, ] typed-ast = [ {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, @@ -1494,16 +1417,8 @@ typed-ast = [ {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, ] urllib3 = [ - {file = "urllib3-1.25.8-py2.py3-none-any.whl", hash = "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc"}, - {file = "urllib3-1.25.8.tar.gz", hash = "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"}, -] -virtualenv = [ - {file = "virtualenv-20.0.17-py2.py3-none-any.whl", hash = "sha256:00cfe8605fb97f5a59d52baab78e6070e72c12ca64f51151695407cc0eb8a431"}, - {file = "virtualenv-20.0.17.tar.gz", hash = "sha256:c8364ec469084046c779c9a11ae6340094e8a0bf1d844330fc55c1cefe67c172"}, -] -virtualenv-clone = [ - {file = "virtualenv-clone-0.5.4.tar.gz", hash = "sha256:665e48dd54c84b98b71a657acb49104c54e7652bce9c1c4f6c6976ed4c827a29"}, - {file = "virtualenv_clone-0.5.4-py2.py3-none-any.whl", hash = "sha256:07e74418b7cc64f4fda987bf5bc71ebd59af27a7bc9e8a8ee9fd54b1f2390a27"}, + {file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"}, + {file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"}, ] wrapt = [ {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, diff --git a/pyproject.toml b/pyproject.toml index 20914b2..6460427 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "shipchain-common" -version = "1.0.21" +version = "1.0.29" description = "A PyPI package containing shared code for ShipChain's Python/Django projects." license = "Apache-2.0" @@ -24,10 +24,10 @@ python = ">=3.6,<3.8" # Compatible python versions must be declared here aws-requests-auth = "~0.4" boto3 = "~1.9" cryptography = "~2.5" -django = "~2.2.12" -django-enumfields = "~0.10.0" -django-influxdb-tagged-metrics = '==1.3.3' -djangorestframework = "~3.10" +django = ">=2.2" +django-enumfields = ">=0.10.0" +django-influxdb-tagged-metrics = '^1.3.3' +djangorestframework = "~3" djangorestframework-jsonapi = "~3" drf-nested-routers = "^0.91.0" python-dateutil = "~2.7.5" @@ -37,13 +37,10 @@ requests = "^2.21" bandit = "^1.5" coverage = "~4.5.1" djangorestframework-simplejwt = {git = "git://github.com/davesque/django-rest-framework-simplejwt.git", rev = "04a4f7f2e045ac4a49542b7e98350e66431adcf5"} -httpretty = "~=0.9" prospector = "~1.1.6.2" pytest = "^3.0" pytest-cov = "^2.6" pytest-django = "^3.6" pytest-mock = "^1.10" +responses = "~0.12" safety = "^1.8" - -[tool.poetry.plugins."pytest11"] -"json_asserter" = "shipchain_common.test_utils.json_asserter" diff --git a/src/shipchain_common/authentication.py b/src/shipchain_common/authentication.py index a57ffb3..6edd7e6 100644 --- a/src/shipchain_common/authentication.py +++ b/src/shipchain_common/authentication.py @@ -43,19 +43,20 @@ def get_jwt_from_request(request): return None -def is_internal_call(request): - return ('X_NGINX_SOURCE' in request.META and request.META['X_NGINX_SOURCE'] == 'internal' - and request.META['X_SSL_CLIENT_VERIFY'] == 'SUCCESS') +def is_internal_call(request, service_name=None): + is_internal = ('X_NGINX_SOURCE' in request.META and request.META['X_NGINX_SOURCE'] == 'internal' + and request.META['X_SSL_CLIENT_VERIFY'] == 'SUCCESS') + if service_name and is_internal: + certificate_cn = parse_dn(request.META['X_SSL_CLIENT_DN'])['CN'] + is_internal = certificate_cn == f'{service_name}.{settings.ENVIRONMENT.lower()}-internal' + return is_internal class InternalRequest(BasePermission): def has_permission(self, request, view): if settings.ENVIRONMENT in ('LOCAL', 'INT'): return True - if is_internal_call(request): - certificate_cn = parse_dn(request.META['X_SSL_CLIENT_DN'])['CN'] - return certificate_cn == f'{self.SERVICE_NAME}.{settings.ENVIRONMENT.lower()}-internal' - return False + return is_internal_call(request, self.SERVICE_NAME) class EngineRequest(InternalRequest): @@ -66,6 +67,10 @@ class TransmissionRequest(InternalRequest): SERVICE_NAME = 'transmission' +class LambdaRequest(InternalRequest): + SERVICE_NAME = 'lambda' + + class PermissionedTokenUser(TokenUser): """ This Requires the JWT from Profiles to have been generated with the `permissions` scope diff --git a/src/shipchain_common/test_utils/__init__.py b/src/shipchain_common/test_utils/__init__.py index b971f94..69e6aad 100644 --- a/src/shipchain_common/test_utils/__init__.py +++ b/src/shipchain_common/test_utils/__init__.py @@ -16,10 +16,7 @@ """ from .json_asserter import \ - json_asserter, \ - AssertionHelper, \ - JsonAsserterMixin - + AssertionHelper from .helpers import\ create_form_content, \ datetimeAlmostEqual, \ diff --git a/src/shipchain_common/test_utils/httpretty_asserter.py b/src/shipchain_common/test_utils/httpretty_asserter.py index d03101a..f84c225 100644 --- a/src/shipchain_common/test_utils/httpretty_asserter.py +++ b/src/shipchain_common/test_utils/httpretty_asserter.py @@ -14,57 +14,100 @@ limitations under the License. """ import pytest -from httpretty import HTTPretty +import responses from urllib.parse import urlparse -from ..utils import parse_urlencoded_data +from ..utils import parse_urlencoded_data, parse_value -class HTTPrettyAsserter(HTTPretty): - @classmethod - def _parse_calls_into_list(cls): - calls_list = [] - assert cls.latest_requests, 'Error: No calls made to be parsed.' - for index, call in enumerate(cls.latest_requests): - if call is None: - # If calling cls.reset(), latest_requests are unable to build. - # Setting the current call to None and iterating through this way ensures that only calls from the - # individual test are set in the call_list. - continue - - url = urlparse(call.path) - if call.headers.get('content-type', '') in ('application/json', 'text/json'): - body = call.parsed_body +class ResponsesHTTPrettyWrapper: + def __init__(self): + self.mock = responses.mock + + def __getattr__(self, item): + return getattr(self.mock, item) + + def register_uri(self, # noqa + method, + uri, + body="HTTPretty :)", + adding_headers=None, + status=200, + match_querystring=False, + **headers + ): + try: + self.mock.replace(method_or_response=method, url=uri, body=body, status=status, + match_querystring=match_querystring, headers=headers) + except ValueError: + self.mock.add(method=method, url=uri, body=body, status=status, + adding_headers=adding_headers, match_querystring=match_querystring, headers=headers) + + class Call: + def __init__(self, responses_call): + self.call = responses_call + self.url = urlparse(self.call.request.url) + + def __getattr__(self, item): + return getattr(self.call, item) + + @property + def parsed_body(self): + body = self.call.request.body or '' + if self.call.request.headers.get('content-type', '') in ('application/json', 'text/json'): + body = parse_value(body) else: - body = parse_urlencoded_data(call.body.decode()) + body = parse_urlencoded_data(body) + + return body + + @property + def querystring(self): + return parse_urlencoded_data(self.url.query) + + @property + def latest_requests(self): + return [self.Call(call) for call in self.mock.calls] + + def last_request(self): + return self.Call(self.mock.calls[-1]) if self.mock.calls else None + + def reset(self): + self.mock._calls.reset() # pylint:disable=protected-access + + +class ResponsesAsserter(ResponsesHTTPrettyWrapper): + def _parse_calls_into_list(self): + calls_list = [] + assert self.latest_requests, 'Error: No calls made to be parsed.' + for call in self.latest_requests: calls_list.append({ - 'path': url.path, - 'query': parse_urlencoded_data(url.query), - 'body': body, - 'host': call.headers.get('host', '') + 'path': call.url.path, + 'query': call.querystring, + 'body': call.parsed_body, + 'host': call.url.hostname }) - cls.latest_requests[index] = None assert calls_list, 'Error: No calls made to be parsed.' return calls_list - @classmethod - def assert_calls(cls, asserted_calls): - calls_list = cls._parse_calls_into_list() - assert isinstance(asserted_calls, list),\ + def assert_calls(self, asserted_calls): + calls_list = self._parse_calls_into_list() + assert isinstance(asserted_calls, list), \ f'Error: asserted calls should be of type `list` not of type `{type(asserted_calls)}`' assert len(calls_list) == len(asserted_calls), f'Difference in expected call count, {len(calls_list)}' \ f' made asserted {len(asserted_calls)}. Calls: {calls_list}' for index, _ in enumerate(calls_list): - cls._assert_call_in_list(calls_list[index], asserted_calls[index]) + self._assert_call_in_list(calls_list[index], asserted_calls[index]) - @classmethod - def _assert_call_in_list(cls, call, assertion): + self.reset_calls() + + def _assert_call_in_list(self, call, assertion): assert 'path' in assertion, 'Error: Must include path in assertion.' - assert assertion["path"] == call['path'],\ + assert assertion["path"] == call['path'], \ f'Error: path mismatch, desired `{assertion["path"]}` returned `{call["path"]}`.' assert 'host' in assertion, 'Error: Must include host in assertion.' - assert call['host'] in assertion["host"],\ + assert call['host'] in assertion["host"], \ f'Error: host mismatch, desired `{assertion["host"]}` returned `{call["host"]}`.' if 'body' in assertion: assert assertion['body'] == call['body'], \ @@ -73,9 +116,23 @@ def _assert_call_in_list(cls, call, assertion): assert assertion['query'] == call['query'], \ f'Error: query mismatch, desired `{assertion["query"]}` returned `{call["query"]}`.' + def reset_calls(self): + self.reset() + + +@pytest.yield_fixture(scope='function') +def modified_responses(): + responses.start() + responses_asserter = ResponsesAsserter() + yield responses_asserter + responses_asserter.reset_calls() + try: + responses.stop() + except RuntimeError: + # Ignore unittest.mock "stop called on unstarted patcher" exception + pass + -@pytest.yield_fixture -def modified_http_pretty(): - HTTPrettyAsserter.enable(allow_net_connect=False) - yield HTTPrettyAsserter - HTTPrettyAsserter.disable() +# Deprecated names for backwards-compatibility +HTTPrettyAsserter = ResponsesAsserter +modified_http_pretty = modified_responses diff --git a/src/shipchain_common/test_utils/json_asserter.py b/src/shipchain_common/test_utils/json_asserter.py index 1f7048c..b120ab4 100644 --- a/src/shipchain_common/test_utils/json_asserter.py +++ b/src/shipchain_common/test_utils/json_asserter.py @@ -14,7 +14,6 @@ limitations under the License. """ -import pytest from rest_framework import status # pylint: disable=too-many-branches @@ -22,11 +21,16 @@ class EntityReferenceClass: - def __init__(self, resource=None, pk=None, attributes=None, relationships=None): + def __init__(self, resource=None, pk=None, attributes=None, relationships=None, meta=None): self.resource = resource self.pk = pk self.attributes = attributes self.relationships = relationships + self.meta = meta + + if self.pk is not None: + # entity_ref.pk can be a CharField or a UUIDField. Force to string for easier comparisons. + self.pk = str(self.pk) def __str__(self): return f'Type: {self.resource}; ID: {self.pk}; ' \ @@ -54,7 +58,7 @@ def _json_has_error(errors, error): assert isinstance(errors, dict), f'Error response not a dict: {errors}' assert 'detail' in errors, f'Malformed error response: {errors}' - assert errors['detail'] == error, f'Error {error} not found in {errors["detail"]}' + assert error in errors['detail'], f'Error {error} not found in {errors["detail"]}' def response_has_error(response, error, pointer=None, vnd=True): @@ -101,7 +105,10 @@ def _vnd_assert_entity_ref_in_list(response_list, entity_ref, skip_attributes_pr f'List Attribute key `{attr_key}` missing in {response_single}' assert response_single['attributes'][attr_key] == attr_value, \ f'List Attribute Value incorrect `{attr_value}` in {response_single}' + if entity_ref.meta: + _vnd_assert_meta(response_single, entity_ref.meta) break + else: single_attribute_failed = False @@ -113,6 +120,9 @@ def _vnd_assert_entity_ref_in_list(response_list, entity_ref, skip_attributes_pr single_attribute_failed = True break + if entity_ref.meta: + _vnd_assert_meta(response_single, entity_ref.meta) + if not single_attribute_failed: found_include = True @@ -159,6 +169,21 @@ def _vnd_assert_relationships(response_data, relationships): f'EntityRef ID `{relationship_ref.pk}` does not match {response_relationships}' +def _vnd_assert_meta(response_data, meta_data): + """ + Scan response data for meta data + """ + assert 'meta' in response_data, f'Meta missing in {response_data}' + assert isinstance(meta_data, dict), f'Invalid format for meta data {type(meta_data)}, must be dict' + + response_meta = response_data['meta'] + + for key, value in meta_data.items(): + assert key in response_meta, f'Meta field `{key}` not found in {response_meta}' + assert response_meta[key] == value,\ + f'Meta field `{key}` had value `{response_meta[key]}` not `{value}` as expected.' + + def _vnd_assert_include(response, included): """ Scan a response for all included resources @@ -188,6 +213,9 @@ def _vnd_assertions(response_data, entity_ref): if entity_ref.relationships: _vnd_assert_relationships(response_data, entity_ref.relationships) + if entity_ref.meta: + _vnd_assert_meta(response_data, entity_ref.meta) + def _plain_assert_attributes_in_response(response, attributes): for key, value in attributes.items(): @@ -401,7 +429,9 @@ def assert_404(response, error='Not found', pointer=None, vnd=True): response_has_error(response, error, pointer, vnd) -def assert_405(response, error='Method not allowed', pointer=None, vnd=True): +def assert_405(response, error=None, pointer=None, vnd=True): + if error is None: + error = f'Method "{response.renderer_context["request"].method}" not allowed.' assert response is not None assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED, f'status_code {response.status_code} != 405' response_has_error(response, error, pointer, vnd) @@ -435,14 +465,3 @@ class AssertionHelper: HTTP_500 = assert_500 HTTP_503 = assert_503 - - -@pytest.fixture(scope='session') -def json_asserter(): - return AssertionHelper - - -class JsonAsserterMixin: - @pytest.fixture(autouse=True) - def set_json_asserter(self, json_asserter): - self.json_asserter = json_asserter diff --git a/src/shipchain_common/utils.py b/src/shipchain_common/utils.py index f7b8cc8..cf2160e 100644 --- a/src/shipchain_common/utils.py +++ b/src/shipchain_common/utils.py @@ -67,7 +67,7 @@ def assertDeepAlmostEqual(test_case, expected, actual, *args, **kwargs): # nope raise exc -def _parse_value(item): +def parse_value(item): if str(item).lower() in ('true', 'false'): # json.loads will parse lowercase booleans item = str(item).lower() @@ -86,9 +86,9 @@ def parse_urlencoded_data(data): body = {} for key, val in parse_qs(data).items(): if len(val) > 1: - body[key] = [_parse_value(el) for el in val] + body[key] = [parse_value(el) for el in val] else: - body[key] = _parse_value(val[0]) + body[key] = parse_value(val[0]) return body diff --git a/tests/test_auth.py b/tests/test_auth.py index 0327eab..22b1dab 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -14,8 +14,8 @@ from rest_framework import exceptions from rest_framework_simplejwt.tokens import UntypedToken -from src.shipchain_common.authentication import EngineRequest, passive_credentials_auth, PermissionedTokenUser,\ - TransmissionRequest +from src.shipchain_common.authentication import EngineRequest, passive_credentials_auth, PermissionedTokenUser, \ + TransmissionRequest, LambdaRequest from src.shipchain_common.test_utils import get_jwt from src.shipchain_common.utils import random_id @@ -43,6 +43,11 @@ def transmission_request(): return TransmissionRequest() +@pytest.fixture() +def lambda_request(): + return LambdaRequest() + + def test_passive_jwt_auth(username): with pytest.raises(exceptions.AuthenticationFailed): passive_credentials_auth('') @@ -118,6 +123,35 @@ def test_transmission_auth_requires_header(transmission_request): assert transmission_request.has_permission(request, {}) +def test_lambda_auth_requires_header(lambda_request): + request = HttpRequest() + + assert not lambda_request.has_permission(request, {}) + + request.META['X_NGINX_SOURCE'] = 'alb' + assert not lambda_request.has_permission(request, {}) + + request.META['X_NGINX_SOURCE'] = 'internal' + with pytest.raises(KeyError): + lambda_request.has_permission(request, {}) + + request.META['X_SSL_CLIENT_VERIFY'] = 'NONE' + assert not lambda_request.has_permission(request, {}) + + request.META['X_SSL_CLIENT_VERIFY'] = 'SUCCESS' + with pytest.raises(KeyError): + lambda_request.has_permission(request, {}) + + request.META['X_SSL_CLIENT_DN'] = '/CN=lambda.h4ck3d' + assert not lambda_request.has_permission(request, {}) + + request.META['X_SSL_CLIENT_DN'] = '/CN=profiles.test-internal' + assert not lambda_request.has_permission(request, {}) + + request.META['X_SSL_CLIENT_DN'] = '/CN=lambda.test-internal' + assert lambda_request.has_permission(request, {}) + + def test_token_user_jti_cache_key(): """By default, the jti is included in get_jwt and is used as cache key""" jwt = get_jwt() diff --git a/tests/test_httpretty_asserter.py b/tests/test_httpretty_asserter.py index 11af1c9..ab3d612 100644 --- a/tests/test_httpretty_asserter.py +++ b/tests/test_httpretty_asserter.py @@ -245,3 +245,12 @@ def test_no_calls_made(self, http_pretty_list_mocking, successful_assertions): with pytest.raises(AssertionError) as err: http_pretty_list_mocking.assert_calls(successful_assertions) assert f'Error: No calls made to be parsed.' in str(err.value) + + def test_reset_between_tests(self, http_pretty_list_mocking, failing_host_assertions): + requests.post('http://google.com/path') + + def test_default_reset_calls(self, http_pretty_list_mocking, query_string, successful_json_body, single_assertions): + requests.post('http://google.com/path?' + query_string, data=successful_json_body, + headers={'content-type': 'application/json'}) + + http_pretty_list_mocking.assert_calls(single_assertions) diff --git a/tests/test_json_asserter.py b/tests/test_json_asserter.py index b375a59..70997eb 100644 --- a/tests/test_json_asserter.py +++ b/tests/test_json_asserter.py @@ -1,8 +1,8 @@ -from unittest.mock import Mock - import pytest +import uuid from rest_framework import status -from shipchain_common.test_utils import AssertionHelper, JsonAsserterMixin +from shipchain_common.test_utils import AssertionHelper +from unittest.mock import Mock EXAMPLE_PLAIN = { 'id': '07b374c3-ed9b-4811-901a-d0c5d746f16a', @@ -105,6 +105,10 @@ def vnd_single(): } ] } + }, + 'meta': { + 'key': 'value', + 'other_key': 'other_value', } }, 'included': [ @@ -141,6 +145,10 @@ def vnd_list(): } ] } + }, + 'meta': { + 'key': 'value', + 'other_key': 'other_value', } }, { @@ -203,38 +211,35 @@ def json_error(): @pytest.fixture -def entity_ref_1(json_asserter): - return json_asserter.EntityRef( +def entity_ref_1(): + return AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE['type'], pk=EXAMPLE_RESOURCE['id'], attributes=EXAMPLE_RESOURCE['attributes'], - relationships={'owner': json_asserter.EntityRef( + relationships={'owner': AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_USER['id'], )}) @pytest.fixture -def entity_ref_3(json_asserter): - return json_asserter.EntityRef( +def entity_ref_3(): + return AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE_3['type'], pk=EXAMPLE_RESOURCE_3['id'], attributes=EXAMPLE_RESOURCE_3['attributes'], - relationships={'owner': json_asserter.EntityRef( + relationships={'owner': AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_USER['id'], )}) -class TestAssertionHelper: - - @pytest.fixture(scope='session') - def json_asserter(self): - return AssertionHelper +class TestAssertionHelper: @pytest.fixture(autouse=True) def make_build_response(self): def _build_response(data, status_code=status.HTTP_200_OK): return Mock(status_code=status_code, json=lambda: data) + self.build_response = _build_response @pytest.fixture @@ -257,215 +262,215 @@ def vnd_error_405(self, vnd_error): vnd_error['errors'][0]['detail'] = 'Method not allowed' return vnd_error - def test_status_200(self, json_asserter, vnd_single, vnd_error_400): + def test_status_200(self, vnd_single, vnd_error_400): response = self.build_response(vnd_single) - json_asserter.HTTP_200(response) + AssertionHelper.HTTP_200(response) with pytest.raises(AssertionError) as err: response = self.build_response(vnd_error_400, status_code=status.HTTP_400_BAD_REQUEST) - json_asserter.HTTP_200(response) + AssertionHelper.HTTP_200(response) assert 'status_code 400 != 200' in str(err.value) - def test_status_201(self, json_asserter, vnd_single, vnd_error_400): + def test_status_201(self, vnd_single, vnd_error_400): response = self.build_response(vnd_single, status_code=status.HTTP_201_CREATED) - json_asserter.HTTP_201(response) + AssertionHelper.HTTP_201(response) with pytest.raises(AssertionError) as err: response = self.build_response(vnd_error_400, status_code=status.HTTP_400_BAD_REQUEST) - json_asserter.HTTP_201(response) + AssertionHelper.HTTP_201(response) assert 'status_code 400 != 201' in str(err.value) - def test_status_202(self, json_asserter, vnd_single, vnd_error_400): + def test_status_202(self, vnd_single, vnd_error_400): response = self.build_response(vnd_single, status_code=status.HTTP_202_ACCEPTED) - json_asserter.HTTP_202(response) + AssertionHelper.HTTP_202(response) with pytest.raises(AssertionError) as err: response = self.build_response(vnd_error_400, status_code=status.HTTP_400_BAD_REQUEST) - json_asserter.HTTP_202(response) + AssertionHelper.HTTP_202(response) assert 'status_code 400 != 202' in str(err.value) - def test_status_204(self, json_asserter, vnd_single, vnd_error_400): + def test_status_204(self, vnd_single, vnd_error_400): response = self.build_response(vnd_single, status_code=status.HTTP_204_NO_CONTENT) - json_asserter.HTTP_204(response) + AssertionHelper.HTTP_204(response) with pytest.raises(AssertionError) as err: response = self.build_response(vnd_error_400, status_code=status.HTTP_400_BAD_REQUEST) - json_asserter.HTTP_204(response) + AssertionHelper.HTTP_204(response) assert 'status_code 400 != 204' in str(err.value) - def test_status_400(self, json_asserter, vnd_single, vnd_error_400): + def test_status_400(self, vnd_single, vnd_error_400): response = self.build_response(vnd_error_400, status_code=status.HTTP_400_BAD_REQUEST) - json_asserter.HTTP_400(response) + AssertionHelper.HTTP_400(response) with pytest.raises(AssertionError) as err: response = self.build_response(vnd_single) - json_asserter.HTTP_400(response) + AssertionHelper.HTTP_400(response) assert 'status_code 200 != 400' in str(err.value) - def test_status_400_custom_message(self, json_asserter, vnd_error_400): + def test_status_400_custom_message(self, vnd_error_400): vnd_error_400['errors'][0]['detail'] = 'custom error message' response = self.build_response(vnd_error_400, status_code=status.HTTP_400_BAD_REQUEST) - json_asserter.HTTP_400(response, error='custom error message') + AssertionHelper.HTTP_400(response, error='custom error message') - def test_status_400_custom_pointer(self, json_asserter, vnd_error_400): + def test_status_400_custom_pointer(self, vnd_error_400): vnd_error_400['errors'][0]['detail'] = 'custom error message' vnd_error_400['errors'][0]['source']['pointer'] = 'pointer' response = self.build_response(vnd_error_400, status_code=status.HTTP_400_BAD_REQUEST) - json_asserter.HTTP_400(response, error='custom error message', pointer='pointer') + AssertionHelper.HTTP_400(response, error='custom error message', pointer='pointer') - def test_status_400_json(self, json_asserter, vnd_single, json_error): + def test_status_400_json(self, vnd_single, json_error): response = self.build_response(json_error, status_code=status.HTTP_400_BAD_REQUEST) - json_asserter.HTTP_400(response, error=json_error['detail'], vnd=False) + AssertionHelper.HTTP_400(response, error=json_error['detail'], vnd=False) with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_200_OK) - json_asserter.HTTP_400(response, error='Different error', vnd=False) + AssertionHelper.HTTP_400(response, error='Different error', vnd=False) assert 'status_code 200 != 400' in str(err.value) with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_400_BAD_REQUEST) - json_asserter.HTTP_400(response, error='Different error', vnd=False) + AssertionHelper.HTTP_400(response, error='Different error', vnd=False) assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) - def test_status_401(self, json_asserter, vnd_single, vnd_error_401): + def test_status_401(self, vnd_single, vnd_error_401): response = self.build_response(vnd_error_401, status_code=status.HTTP_401_UNAUTHORIZED) - json_asserter.HTTP_401(response) + AssertionHelper.HTTP_401(response) with pytest.raises(AssertionError) as err: response = self.build_response(vnd_single) - json_asserter.HTTP_401(response) + AssertionHelper.HTTP_401(response) assert 'status_code 200 != 401' in str(err.value) - def test_status_401_json(self, json_asserter, vnd_single, json_error): + def test_status_401_json(self, vnd_single, json_error): response = self.build_response(json_error, status_code=status.HTTP_401_UNAUTHORIZED) - json_asserter.HTTP_401(response, error=json_error['detail'], vnd=False) + AssertionHelper.HTTP_401(response, error=json_error['detail'], vnd=False) with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_200_OK) - json_asserter.HTTP_401(response, error='Different error', vnd=False) + AssertionHelper.HTTP_401(response, error='Different error', vnd=False) assert 'status_code 200 != 401' in str(err.value) with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_401_UNAUTHORIZED) - json_asserter.HTTP_401(response, error='Different error', vnd=False) + AssertionHelper.HTTP_401(response, error='Different error', vnd=False) assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) - def test_status_403(self, json_asserter, vnd_single, vnd_error_403): + def test_status_403(self, vnd_single, vnd_error_403): response = self.build_response(vnd_error_403, status_code=status.HTTP_403_FORBIDDEN) - json_asserter.HTTP_403(response) + AssertionHelper.HTTP_403(response) with pytest.raises(AssertionError) as err: response = self.build_response(vnd_single) - json_asserter.HTTP_403(response) + AssertionHelper.HTTP_403(response) assert 'status_code 200 != 403' in str(err.value) - def test_status_403_json(self, json_asserter, vnd_single, json_error): + def test_status_403_json(self, vnd_single, json_error): response = self.build_response(json_error, status_code=status.HTTP_403_FORBIDDEN) - json_asserter.HTTP_403(response, error=json_error['detail'], vnd=False) + AssertionHelper.HTTP_403(response, error=json_error['detail'], vnd=False) with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_200_OK) - json_asserter.HTTP_403(response, error='Different error', vnd=False) + AssertionHelper.HTTP_403(response, error='Different error', vnd=False) assert 'status_code 200 != 403' in str(err.value) with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_403_FORBIDDEN) - json_asserter.HTTP_403(response, error='Different error', vnd=False) + AssertionHelper.HTTP_403(response, error='Different error', vnd=False) assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) - def test_status_404(self, json_asserter, vnd_single, vnd_error_404): + def test_status_404(self, vnd_single, vnd_error_404): response = self.build_response(vnd_error_404, status_code=status.HTTP_404_NOT_FOUND) - json_asserter.HTTP_404(response) + AssertionHelper.HTTP_404(response) with pytest.raises(AssertionError) as err: response = self.build_response(vnd_single) - json_asserter.HTTP_404(response) + AssertionHelper.HTTP_404(response) assert 'status_code 200 != 404' in str(err.value) - def test_status_404_json(self, json_asserter, vnd_single, json_error): + def test_status_404_json(self, vnd_single, json_error): response = self.build_response(json_error, status_code=status.HTTP_404_NOT_FOUND) - json_asserter.HTTP_404(response, error=json_error['detail'], vnd=False) + AssertionHelper.HTTP_404(response, error=json_error['detail'], vnd=False) with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_200_OK) - json_asserter.HTTP_404(response, error='Different error', vnd=False) + AssertionHelper.HTTP_404(response, error='Different error', vnd=False) assert 'status_code 200 != 404' in str(err.value) with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_404_NOT_FOUND) - json_asserter.HTTP_404(response, error='Different error', vnd=False) + AssertionHelper.HTTP_404(response, error='Different error', vnd=False) assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) - def test_status_405(self, json_asserter, vnd_single, vnd_error_405): + def test_status_405(self, vnd_single, vnd_error_405): response = self.build_response(vnd_error_405, status_code=status.HTTP_405_METHOD_NOT_ALLOWED) - json_asserter.HTTP_405(response) + AssertionHelper.HTTP_405(response, error='Method not allowed') with pytest.raises(AssertionError) as err: response = self.build_response(vnd_single) - json_asserter.HTTP_405(response) + AssertionHelper.HTTP_405(response, error='Method not allowed') assert 'status_code 200 != 405' in str(err.value) - def test_status_405_json(self, json_asserter, vnd_single, json_error): + def test_status_405_json(self, vnd_single, json_error): response = self.build_response(json_error, status_code=status.HTTP_405_METHOD_NOT_ALLOWED) - json_asserter.HTTP_405(response, error=json_error['detail'], vnd=False) + AssertionHelper.HTTP_405(response, error=json_error['detail'], vnd=False) with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_200_OK) - json_asserter.HTTP_405(response, error='Different error', vnd=False) + AssertionHelper.HTTP_405(response, error='Different error', vnd=False) assert 'status_code 200 != 405' in str(err.value) with pytest.raises(AssertionError) as err: response = self.build_response(json_error, status_code=status.HTTP_405_METHOD_NOT_ALLOWED) - json_asserter.HTTP_405(response, error='Different error', vnd=False) + AssertionHelper.HTTP_405(response, error='Different error', vnd=False) assert f'Error Different error not found in {json_error["detail"]}' in str(err.value) - def test_status_500(self, json_asserter, vnd_single, vnd_error): + def test_status_500(self, vnd_single, vnd_error): vnd_error['errors'][0]['detail'] = 'A server error occurred.' response = self.build_response(vnd_error, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) - json_asserter.HTTP_500(response) + AssertionHelper.HTTP_500(response) with pytest.raises(AssertionError) as err: response = self.build_response(vnd_single) - json_asserter.HTTP_500(response) + AssertionHelper.HTTP_500(response) assert 'status_code 200 != 500' in str(err.value) - def test_status_500_custom_message(self, json_asserter, vnd_error): + def test_status_500_custom_message(self, vnd_error): vnd_error['errors'][0]['detail'] = 'custom error message' response = self.build_response(vnd_error, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) - json_asserter.HTTP_500(response, error='custom error message') + AssertionHelper.HTTP_500(response, error='custom error message') - def test_status_503(self, json_asserter, vnd_single, vnd_error): + def test_status_503(self, vnd_single, vnd_error): vnd_error['errors'][0]['detail'] = 'Service temporarily unavailable, try again later' response = self.build_response(vnd_error, status_code=status.HTTP_503_SERVICE_UNAVAILABLE) - json_asserter.HTTP_503(response) + AssertionHelper.HTTP_503(response) with pytest.raises(AssertionError) as err: response = self.build_response(vnd_single) - json_asserter.HTTP_503(response) + AssertionHelper.HTTP_503(response) assert 'status_code 200 != 503' in str(err.value) - def test_status_503_custom_message(self, json_asserter, vnd_error): + def test_status_503_custom_message(self, vnd_error): vnd_error['errors'][0]['detail'] = 'custom error message' response = self.build_response(vnd_error, status_code=status.HTTP_503_SERVICE_UNAVAILABLE) - json_asserter.HTTP_503(response, error='custom error message') + AssertionHelper.HTTP_503(response, error='custom error message') - def test_status_wrong_message(self, json_asserter, vnd_error_404): + def test_status_wrong_message(self, vnd_error_404): response = self.build_response(vnd_error_404, status_code=status.HTTP_404_NOT_FOUND) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_404(response, error='Not the correct error') + AssertionHelper.HTTP_404(response, error='Not the correct error') assert f'Error `Not the correct error` not found in' in str(err.value) - def test_status_400_wrong_pointer(self, json_asserter, vnd_error_400): + def test_status_400_wrong_pointer(self, vnd_error_400): vnd_error_400['errors'][0]['detail'] = 'custom error message' vnd_error_400['errors'][0]['source']['pointer'] = 'pointer' response = self.build_response(vnd_error_400, status_code=status.HTTP_400_BAD_REQUEST) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_400(response, error='custom error message', pointer='Not the correct pointer') + AssertionHelper.HTTP_400(response, error='custom error message', pointer='Not the correct pointer') assert f'Error `Not the correct pointer` not found in' in str(err.value) - def test_status_404_wrong_pointer(self, json_asserter, vnd_error): + def test_status_404_wrong_pointer(self, vnd_error): vnd_error['errors'][0]['detail'] = 'Not found' vnd_error['errors'][0]['source'] = { 'pointer': 'correct pointer' @@ -473,10 +478,10 @@ def test_status_404_wrong_pointer(self, json_asserter, vnd_error): response = self.build_response(vnd_error, status_code=status.HTTP_404_NOT_FOUND) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_404(response, pointer='Not the correct pointer') + AssertionHelper.HTTP_404(response, pointer='Not the correct pointer') assert f'Error `Not the correct pointer` not found in' in str(err.value) - def test_status_pointer_requires_correct_error(self, json_asserter, vnd_error): + def test_status_pointer_requires_correct_error(self, vnd_error): vnd_error['errors'][0]['detail'] = 'Not found' vnd_error['errors'][0]['source'] = { 'pointer': 'correct pointer' @@ -484,130 +489,130 @@ def test_status_pointer_requires_correct_error(self, json_asserter, vnd_error): response = self.build_response(vnd_error, status_code=status.HTTP_404_NOT_FOUND) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_404(response, error='Not the correct error', pointer='Not the correct pointer') + AssertionHelper.HTTP_404(response, error='Not the correct error', pointer='Not the correct pointer') assert f'Error `Not the correct error` not found in' in str(err.value) - def test_status_in_second_error(self, json_asserter, vnd_error_404): + def test_status_in_second_error(self, vnd_error_404): vnd_error_404['errors'].append({'detail': 'another error'}) response = self.build_response(vnd_error_404, status_code=status.HTTP_404_NOT_FOUND) - json_asserter.HTTP_404(response, error='another error') + AssertionHelper.HTTP_404(response, error='another error') - def test_status_missing_in_multiple_errors(self, json_asserter, vnd_error_404): + def test_status_missing_in_multiple_errors(self, vnd_error_404): vnd_error_404['errors'].append({'detail': 'another error'}) response = self.build_response(vnd_error_404, status_code=status.HTTP_404_NOT_FOUND) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_404(response, error='Not the correct error') + AssertionHelper.HTTP_404(response, error='Not the correct error') assert f'Error `Not the correct error` not found in' in str(err.value) - def test_exclusive_entity_refs_or_fields(self, json_asserter, vnd_single): + def test_exclusive_entity_refs_or_fields(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef(), attributes={'test': 1}) + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef(), attributes={'test': 1}) assert 'Use Only `entity_refs` or explicit `attributes`, `relationships`, `resource`, and `pk` but not both' \ in str(err.value) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef(), relationships={'test': 1}) + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef(), relationships={'test': 1}) assert 'Use Only `entity_refs` or explicit `attributes`, `relationships`, `resource`, and `pk` but not both' \ in str(err.value) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef(), resource='test') + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef(), resource='test') assert 'Use Only `entity_refs` or explicit `attributes`, `relationships`, `resource`, and `pk` but not both' \ in str(err.value) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef(), pk='test') + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef(), pk='test') assert 'Use Only `entity_refs` or explicit `attributes`, `relationships`, `resource`, and `pk` but not both' \ in str(err.value) - def test_vnd_with_non_jsonapi_data(self, json_asserter): + def test_vnd_with_non_jsonapi_data(self): response = self.build_response(EXAMPLE_PLAIN) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, attributes=EXAMPLE_PLAIN) + AssertionHelper.HTTP_200(response, attributes=EXAMPLE_PLAIN) assert f'response does not contain `data` property' in str(err.value) - def test_vnd_is_list(self, json_asserter, vnd_single, vnd_list): + def test_vnd_is_list(self, vnd_single, vnd_list): single_response = self.build_response(vnd_single) list_response = self.build_response(vnd_list) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(single_response, is_list=True) + AssertionHelper.HTTP_200(single_response, is_list=True) assert 'Response should be a list' in str(err.value) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(list_response) + AssertionHelper.HTTP_200(list_response) assert 'Response should not be a list' in str(err.value) - def test_vnd_attributes_match(self, json_asserter, vnd_single): + def test_vnd_attributes_match(self, vnd_single): response = self.build_response(vnd_single) - json_asserter.HTTP_200(response, attributes=EXAMPLE_RESOURCE['attributes']) + AssertionHelper.HTTP_200(response, attributes=EXAMPLE_RESOURCE['attributes']) - def test_vnd_attributes_not_match(self, json_asserter, vnd_single): + def test_vnd_attributes_not_match(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, attributes=EXAMPLE_RESOURCE_2['attributes']) + AssertionHelper.HTTP_200(response, attributes=EXAMPLE_RESOURCE_2['attributes']) assert f'Attribute Value incorrect `{EXAMPLE_RESOURCE_2["attributes"]["name"]}` in ' in str(err.value) - def test_vnd_relationships_should_be_entity_ref(self, json_asserter, vnd_single): + def test_vnd_relationships_should_be_entity_ref(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, relationships={'owner': EXAMPLE_RESOURCE_2}) + AssertionHelper.HTTP_200(response, relationships={'owner': EXAMPLE_RESOURCE_2}) assert f'asserted relationship is not an EntityRef' in str(err.value) - def test_vnd_relationships_match(self, json_asserter, vnd_single): + def test_vnd_relationships_match(self, vnd_single): response = self.build_response(vnd_single) - json_asserter.HTTP_200(response, relationships={'owner': json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, relationships={'owner': AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_USER['id'], )}) - def test_vnd_relationships_match_list(self, json_asserter, vnd_single): + def test_vnd_relationships_match_list(self, vnd_single): response = self.build_response(vnd_single) - json_asserter.HTTP_200(response, relationships={ - 'owner': json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, relationships={ + 'owner': AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_USER['id'], ), 'children': [ - json_asserter.EntityRef( + AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE_2['type'], pk=EXAMPLE_RESOURCE_2['id'], ), - json_asserter.EntityRef( + AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE_4['type'], pk=EXAMPLE_RESOURCE_4['id'], ), ]}) - def test_vnd_relationships_not_match(self, json_asserter, vnd_single): + def test_vnd_relationships_not_match(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, relationships={'owner': json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, relationships={'owner': AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE['type'], pk=EXAMPLE_RESOURCE['id'], )}) assert f'EntityRef resource type `{EXAMPLE_RESOURCE["type"]}` does not match' in str(err.value) - def test_vnd_relationships_not_match_in_list(self, json_asserter, vnd_single): + def test_vnd_relationships_not_match_in_list(self, vnd_single): response = self.build_response(vnd_single) - relationship = json_asserter.EntityRef(resource=EXAMPLE_RESOURCE_3["type"], - pk=EXAMPLE_RESOURCE_3["id"], - attributes={}) + relationship = AssertionHelper.EntityRef(resource=EXAMPLE_RESOURCE_3["type"], + pk=EXAMPLE_RESOURCE_3["id"], + attributes={}) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, relationships={'children': [ - json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, relationships={'children': [ + AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE_2['type'], pk=EXAMPLE_RESOURCE_2['id'], ), @@ -615,362 +620,381 @@ def test_vnd_relationships_not_match_in_list(self, json_asserter, vnd_single): ]}) assert f'{relationship} NOT IN ' in str(err.value) - def test_vnd_included_should_be_entity_ref(self, json_asserter, vnd_single): + def test_vnd_included_should_be_entity_ref(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, included=EXAMPLE_RESOURCE_2) + AssertionHelper.HTTP_200(response, included=EXAMPLE_RESOURCE_2) assert f'asserted includes is not an EntityRef' in str(err.value) - def test_vnd_included_full_match(self, json_asserter, vnd_single): + def test_vnd_included_full_match(self, vnd_single): response = self.build_response(vnd_single) - json_asserter.HTTP_200(response, included=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, included=AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE_2['type'], pk=EXAMPLE_RESOURCE_2['id'], attributes=EXAMPLE_RESOURCE_2['attributes'], )) - def test_vnd_included_full_not_match(self, json_asserter, vnd_single): + def test_vnd_included_full_not_match(self, vnd_single): response = self.build_response(vnd_single) - include = json_asserter.EntityRef( - resource=EXAMPLE_RESOURCE['type'], - pk=EXAMPLE_RESOURCE['id'], - attributes=EXAMPLE_RESOURCE['attributes'], - ) + include = AssertionHelper.EntityRef( + resource=EXAMPLE_RESOURCE['type'], + pk=EXAMPLE_RESOURCE['id'], + attributes=EXAMPLE_RESOURCE['attributes'], + ) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, included=include) + AssertionHelper.HTTP_200(response, included=include) assert f'{include} NOT IN' in str(err.value) - def test_vnd_included_type_pk_match(self, json_asserter, vnd_single): + def test_vnd_included_type_pk_match(self, vnd_single): response = self.build_response(vnd_single) - json_asserter.HTTP_200(response, included=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, included=AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE_2['type'], pk=EXAMPLE_RESOURCE_2['id'], )) - def test_vnd_included_type_pk_not_match(self, json_asserter, vnd_single): + def test_vnd_included_type_pk_not_match(self, vnd_single): response = self.build_response(vnd_single) - include = json_asserter.EntityRef( - resource=EXAMPLE_RESOURCE['type'], - pk=EXAMPLE_RESOURCE['id'], - ) + include = AssertionHelper.EntityRef( + resource=EXAMPLE_RESOURCE['type'], + pk=EXAMPLE_RESOURCE['id'], + ) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, included=include) + AssertionHelper.HTTP_200(response, included=include) assert f'{include} NOT IN' in str(err.value) - def test_vnd_included_attributes_match(self, json_asserter, vnd_single): + def test_vnd_included_attributes_match(self, vnd_single): response = self.build_response(vnd_single) - json_asserter.HTTP_200(response, included=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, included=AssertionHelper.EntityRef( attributes=EXAMPLE_RESOURCE_2['attributes'], )) - def test_vnd_included_attributes_not_match(self, json_asserter, vnd_single): + def test_vnd_included_attributes_not_match(self, vnd_single): response = self.build_response(vnd_single) - include = json_asserter.EntityRef( - attributes=EXAMPLE_RESOURCE['attributes'], - ) + include = AssertionHelper.EntityRef( + attributes=EXAMPLE_RESOURCE['attributes'], + ) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, included=include) + AssertionHelper.HTTP_200(response, included=include) assert f'{include} NOT IN' in str(err.value) - def test_vnd_included_list_all_match(self, json_asserter, vnd_single): + def test_vnd_included_list_all_match(self, vnd_single): response = self.build_response(vnd_single) - json_asserter.HTTP_200(response, included=[ - json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, included=[ + AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE_2['type'], pk=EXAMPLE_RESOURCE_2['id'], attributes=EXAMPLE_RESOURCE_2['attributes']), - json_asserter.EntityRef( + AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_USER['id'], attributes=EXAMPLE_USER['attributes']), - ]) + ]) - def test_vnd_included_list_one_match(self, json_asserter, vnd_single): + def test_vnd_included_list_one_match(self, vnd_single): response = self.build_response(vnd_single) - include_1 = json_asserter.EntityRef( + include_1 = AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE['type'], pk=EXAMPLE_RESOURCE['id'], attributes=EXAMPLE_RESOURCE['attributes']) - include_2 = json_asserter.EntityRef( + include_2 = AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_USER['id'], attributes=EXAMPLE_USER['attributes']) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, included=[include_1, include_2]) + AssertionHelper.HTTP_200(response, included=[include_1, include_2]) assert f'{include_1} NOT IN' in str(err.value) - def test_vnd_included_list_none_match(self, json_asserter, vnd_single): + def test_vnd_included_list_none_match(self, vnd_single): response = self.build_response(vnd_single) - include_1 = json_asserter.EntityRef( + include_1 = AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE['type'], pk=EXAMPLE_RESOURCE['id'], attributes=EXAMPLE_RESOURCE['attributes']) - include_2 = json_asserter.EntityRef( + include_2 = AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE_3['type'], pk=EXAMPLE_RESOURCE_3['id'], attributes=EXAMPLE_RESOURCE_3['attributes']) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, included=[include_1, include_2]) + AssertionHelper.HTTP_200(response, included=[include_1, include_2]) assert f'{include_1} NOT IN' in str(err.value) - def test_entity_list_non_list_response(self, json_asserter, vnd_single): + def test_entity_list_non_list_response(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, entity_refs=[json_asserter.EntityRef()]) + AssertionHelper.HTTP_200(response, entity_refs=[AssertionHelper.EntityRef()]) assert 'entity_refs should not be a list for a non-list response' in str(err.value) - def test_vnd_entity_full_match(self, json_asserter, vnd_single): + def test_vnd_entity_uuid_pk(self, vnd_single): + response = self.build_response(vnd_single) + AssertionHelper.HTTP_200( + response, + entity_refs=AssertionHelper.EntityRef( + resource=EXAMPLE_RESOURCE['type'], + pk=uuid.UUID(EXAMPLE_RESOURCE['id']), + attributes=EXAMPLE_RESOURCE['attributes'], + relationships={'owner': AssertionHelper.EntityRef( + resource=EXAMPLE_USER['type'], + pk=uuid.UUID(EXAMPLE_USER['id']), + )} + ), + included=AssertionHelper.EntityRef( + resource=EXAMPLE_RESOURCE_2['type'], + pk=uuid.UUID(EXAMPLE_RESOURCE_2['id']), + )) + + def test_vnd_entity_full_match(self, vnd_single): response = self.build_response(vnd_single) - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE['type'], pk=EXAMPLE_RESOURCE['id'], attributes=EXAMPLE_RESOURCE['attributes'], - relationships={'owner': json_asserter.EntityRef( + relationships={'owner': AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_USER['id'], )} )) - def test_vnd_entity_full_type_not_match(self, json_asserter, vnd_single): + def test_vnd_entity_full_type_not_match(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_RESOURCE['id'], attributes=EXAMPLE_RESOURCE['attributes'], - relationships={'owner': json_asserter.EntityRef( + relationships={'owner': AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_USER['id'], )} )) assert f'Invalid Resource Type in' in str(err.value) - def test_vnd_entity_full_id_not_match(self, json_asserter, vnd_single): + def test_vnd_entity_full_id_not_match(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE['type'], pk=EXAMPLE_USER['id'], attributes=EXAMPLE_RESOURCE['attributes'], - relationships={'owner': json_asserter.EntityRef( + relationships={'owner': AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_USER['id'], )} )) assert f'Invalid ID in' in str(err.value) - def test_vnd_entity_full_attributes_missing(self, json_asserter, vnd_single): + def test_vnd_entity_full_attributes_missing(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE['type'], pk=EXAMPLE_RESOURCE['id'], attributes=EXAMPLE_USER['attributes'], - relationships={'owner': json_asserter.EntityRef( + relationships={'owner': AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_USER['id'], )} )) assert f'Missing Attribute `username` in' in str(err.value) - def test_vnd_entity_full_attributes_not_match(self, json_asserter, vnd_single): + def test_vnd_entity_full_attributes_not_match(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE['type'], pk=EXAMPLE_RESOURCE['id'], attributes=EXAMPLE_RESOURCE_2['attributes'], - relationships={'owner': json_asserter.EntityRef( + relationships={'owner': AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_USER['id'], )} )) assert f'Attribute Value incorrect `example 2` in' in str(err.value) - def test_vnd_entity_full_relationships_type_not_match(self, json_asserter, vnd_single): + def test_vnd_entity_full_relationships_type_not_match(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE['type'], pk=EXAMPLE_RESOURCE['id'], attributes=EXAMPLE_RESOURCE['attributes'], - relationships={'owner': json_asserter.EntityRef( + relationships={'owner': AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE['type'], pk=EXAMPLE_USER['id'], )} )) assert f'EntityRef resource type `{EXAMPLE_RESOURCE["type"]}` does not match' in str(err.value) - def test_vnd_entity_full_relationships_pk_not_match(self, json_asserter, vnd_single): + def test_vnd_entity_full_relationships_pk_not_match(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE['type'], pk=EXAMPLE_RESOURCE['id'], attributes=EXAMPLE_RESOURCE['attributes'], - relationships={'owner': json_asserter.EntityRef( + relationships={'owner': AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_RESOURCE['id'], )} )) assert f'EntityRef ID `{EXAMPLE_RESOURCE["id"]}` does not match' in str(err.value) - def test_vnd_entity_type_pk_match(self, json_asserter, vnd_single): + def test_vnd_entity_type_pk_match(self, vnd_single): response = self.build_response(vnd_single) - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE['type'], pk=EXAMPLE_RESOURCE['id'], )) - def test_vnd_entity_type_pk_not_match(self, json_asserter, vnd_single): + def test_vnd_entity_type_pk_not_match(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_RESOURCE['id'], )) assert f'Invalid Resource Type in' in str(err.value) - def test_vnd_entity_attribute_only_match(self, json_asserter, vnd_single): + def test_vnd_entity_attribute_only_match(self, vnd_single): response = self.build_response(vnd_single) - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( attributes=EXAMPLE_RESOURCE['attributes'] )) - def test_vnd_entity_attribute_only_not_match(self, json_asserter, vnd_single): + def test_vnd_entity_attribute_only_not_match(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, entity_refs=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( attributes=EXAMPLE_RESOURCE_2['attributes'], )) assert f'Attribute Value incorrect `example 2` in' in str(err.value) - def test_vnd_list_entity_full_match(self, json_asserter, vnd_list): + def test_vnd_list_entity_full_match(self, vnd_list): response = self.build_response(vnd_list) - json_asserter.HTTP_200(response, is_list=True, entity_refs=json_asserter.EntityRef( + AssertionHelper.HTTP_200(response, is_list=True, entity_refs=AssertionHelper.EntityRef( resource=EXAMPLE_RESOURCE['type'], pk=EXAMPLE_RESOURCE['id'], attributes=EXAMPLE_RESOURCE['attributes'], - relationships={'owner': json_asserter.EntityRef( + relationships={'owner': AssertionHelper.EntityRef( resource=EXAMPLE_USER['type'], pk=EXAMPLE_USER['id'], )} )) - def test_vnd_list_entity_list_all_match(self, json_asserter, vnd_list, entity_ref_1, entity_ref_3): + def test_vnd_list_entity_list_all_match(self, vnd_list, entity_ref_1, entity_ref_3): response = self.build_response(vnd_list) - json_asserter.HTTP_200(response, is_list=True, entity_refs=[entity_ref_1, entity_ref_3]) + AssertionHelper.HTTP_200(response, is_list=True, entity_refs=[entity_ref_1, entity_ref_3]) - def test_vnd_list_count(self, json_asserter, vnd_list): + def test_vnd_list_count(self, vnd_list): response = self.build_response(vnd_list) - json_asserter.HTTP_200(response, is_list=True, count=len(vnd_list['data'])) + AssertionHelper.HTTP_200(response, is_list=True, count=len(vnd_list['data'])) - def test_vnd_list_wrong_count(self, json_asserter, vnd_list): + def test_vnd_list_wrong_count(self, vnd_list): list_length = len(vnd_list['data']) response = self.build_response(vnd_list) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, is_list=True, count=list_length - 1) + AssertionHelper.HTTP_200(response, is_list=True, count=list_length - 1) assert f'Difference in count of response_data, got {list_length} expected {list_length - 1}' in str(err.value) - def test_vnd_single_count(self, json_asserter, vnd_single): + def test_vnd_single_count(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, count=1) + AssertionHelper.HTTP_200(response, count=1) assert f'Count is only checked when response is list' in str(err.value) - def test_vnd_list_ordering(self, json_asserter, vnd_list, entity_ref_1, entity_ref_3): + def test_vnd_list_ordering(self, vnd_list, entity_ref_1, entity_ref_3): response = self.build_response(vnd_list) - json_asserter.HTTP_200(response, is_list=True, entity_refs=[entity_ref_1, entity_ref_3], check_ordering=True) + AssertionHelper.HTTP_200(response, is_list=True, entity_refs=[entity_ref_1, entity_ref_3], check_ordering=True) - def test_vnd_list_wrong_ordering(self, json_asserter, vnd_list, entity_ref_1, entity_ref_3): + def test_vnd_list_wrong_ordering(self, vnd_list, entity_ref_1, entity_ref_3): response = self.build_response(vnd_list) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, is_list=True, entity_refs=[entity_ref_3, entity_ref_1], check_ordering=True) + AssertionHelper.HTTP_200(response, is_list=True, entity_refs=[entity_ref_3, entity_ref_1], + check_ordering=True) assert 'Invalid ID in ' in str(err.value) - def test_vnd_list_wrong_ordering_amount(self, json_asserter, vnd_list, entity_ref_1, entity_ref_3): + def test_vnd_list_wrong_ordering_amount(self, vnd_list, entity_ref_1, entity_ref_3): response = self.build_response(vnd_list) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, is_list=True, entity_refs=[entity_ref_1, entity_ref_3, entity_ref_1], - check_ordering=True) + AssertionHelper.HTTP_200(response, is_list=True, entity_refs=[entity_ref_1, entity_ref_3, entity_ref_1], + check_ordering=True) assert 'Error: more entity refs supplied than available in response data. ' in str(err.value) - def test_vnd_single_ordering(self, json_asserter, vnd_single, entity_ref_1): + def test_vnd_single_ordering(self, vnd_single, entity_ref_1): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, entity_refs=entity_ref_1, check_ordering=True) + AssertionHelper.HTTP_200(response, entity_refs=entity_ref_1, check_ordering=True) assert f'Ordering is only checked when response is list' in str(err.value) - def test_vnd_list_entity_list_one_not_match(self, json_asserter, vnd_list, entity_ref_1, entity_ref_3): + def test_vnd_list_entity_list_one_not_match(self, vnd_list, entity_ref_1, entity_ref_3): response = self.build_response(vnd_list) entity_ref_3.pk = EXAMPLE_RESOURCE_2['id'] with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, is_list=True, entity_refs=[entity_ref_1, entity_ref_3]) + AssertionHelper.HTTP_200(response, is_list=True, entity_refs=[entity_ref_1, entity_ref_3]) assert f'{entity_ref_3} NOT IN' in str(err.value) - def test_plain_json_valid_parameters(self, json_asserter): + def test_plain_json_valid_parameters(self): response = self.build_response(EXAMPLE_PLAIN) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, vnd=False, entity_refs={json_asserter.EntityRef()}) + AssertionHelper.HTTP_200(response, vnd=False, entity_refs={AssertionHelper.EntityRef()}) assert f'entity_refs not valid when vnd=False' in str(err.value) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, vnd=False, relationships=json_asserter.EntityRef()) + AssertionHelper.HTTP_200(response, vnd=False, relationships=AssertionHelper.EntityRef()) assert f'relationships not valid when vnd=False' in str(err.value) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, vnd=False, included=json_asserter.EntityRef()) + AssertionHelper.HTTP_200(response, vnd=False, included=AssertionHelper.EntityRef()) assert f'included not valid when vnd=False' in str(err.value) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, vnd=False) + AssertionHelper.HTTP_200(response, vnd=False) assert f'attributes must be provided when vnd=False' in str(err.value) - def test_plain_json_attributes(self, json_asserter): + def test_plain_json_attributes(self): response = self.build_response(EXAMPLE_PLAIN) - json_asserter.HTTP_200(response, vnd=False, attributes=EXAMPLE_PLAIN) + AssertionHelper.HTTP_200(response, vnd=False, attributes=EXAMPLE_PLAIN) - def test_plain_json_attributes_top_level_missing(self, json_asserter): + def test_plain_json_attributes_top_level_missing(self): response = self.build_response(EXAMPLE_PLAIN) invalid_attributes = EXAMPLE_PLAIN.copy() invalid_attributes['new_field'] = 1 with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, vnd=False, attributes=invalid_attributes) + AssertionHelper.HTTP_200(response, vnd=False, attributes=invalid_attributes) assert f'Missing Attribute `new_field` in ' in str(err.value) - def test_plain_json_attributes_top_level_mismatch(self, json_asserter): + def test_plain_json_attributes_top_level_mismatch(self): response = self.build_response(EXAMPLE_PLAIN) invalid_attributes = EXAMPLE_PLAIN.copy() invalid_attributes['id'] = 1 with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, vnd=False, attributes=invalid_attributes) + AssertionHelper.HTTP_200(response, vnd=False, attributes=invalid_attributes) assert f'Attribute Value incorrect `1` in ' in str(err.value) - def test_plain_json_attributes_nested_missing(self, json_asserter): + def test_plain_json_attributes_nested_missing(self): response = self.build_response(EXAMPLE_PLAIN) invalid_attributes = EXAMPLE_PLAIN.copy() @@ -978,10 +1002,10 @@ def test_plain_json_attributes_nested_missing(self, json_asserter): invalid_attributes['owner']['new_field'] = 'test' with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, vnd=False, attributes=invalid_attributes) + AssertionHelper.HTTP_200(response, vnd=False, attributes=invalid_attributes) assert f'Missing Attribute `new_field` in ' in str(err.value) - def test_plain_json_attributes_nested_mismatch(self, json_asserter): + def test_plain_json_attributes_nested_mismatch(self): response = self.build_response(EXAMPLE_PLAIN) invalid_attributes = EXAMPLE_PLAIN.copy() @@ -989,61 +1013,61 @@ def test_plain_json_attributes_nested_mismatch(self, json_asserter): invalid_attributes['owner']['id'] = 'test' with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, vnd=False, attributes=invalid_attributes) + AssertionHelper.HTTP_200(response, vnd=False, attributes=invalid_attributes) assert f'Missing Attribute `id` in ' in str(err.value) - def test_plain_json_attributes_list_assertions(self, json_asserter): + def test_plain_json_attributes_list_assertions(self): single_response = self.build_response(EXAMPLE_PLAIN) list_response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(single_response, vnd=False, is_list=True, attributes=EXAMPLE_PLAIN) + AssertionHelper.HTTP_200(single_response, vnd=False, is_list=True, attributes=EXAMPLE_PLAIN) assert f'Response should be a list' in str(err.value) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(list_response, vnd=False, attributes=EXAMPLE_PLAIN) + AssertionHelper.HTTP_200(list_response, vnd=False, attributes=EXAMPLE_PLAIN) assert f'Response should not be a list' in str(err.value) - def test_plain_json_attributes_list_single_match(self, json_asserter): + def test_plain_json_attributes_list_single_match(self): response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) - json_asserter.HTTP_200(response, vnd=False, is_list=True, attributes=EXAMPLE_PLAIN) + AssertionHelper.HTTP_200(response, vnd=False, is_list=True, attributes=EXAMPLE_PLAIN) - def test_plain_json_attributes_list_both_match(self, json_asserter): + def test_plain_json_attributes_list_both_match(self): response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) - json_asserter.HTTP_200(response, vnd=False, is_list=True, attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) + AssertionHelper.HTTP_200(response, vnd=False, is_list=True, attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) - def test_plain_json_attributes_list_one_missing(self, json_asserter): + def test_plain_json_attributes_list_one_missing(self): response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, vnd=False, is_list=True, attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_3]) + AssertionHelper.HTTP_200(response, vnd=False, is_list=True, attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_3]) assert f'{EXAMPLE_PLAIN_3} NOT IN ' in str(err.value) - def test_plain_json_attributes_list_ordering(self, json_asserter): + def test_plain_json_attributes_list_ordering(self): response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) - json_asserter.HTTP_200(response, vnd=False, is_list=True, attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_2], - check_ordering=True) + AssertionHelper.HTTP_200(response, vnd=False, is_list=True, attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_2], + check_ordering=True) - def test_plain_json_attributes_list_wrong_ordering(self, json_asserter): + def test_plain_json_attributes_list_wrong_ordering(self): response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, vnd=False, is_list=True, attributes=[EXAMPLE_PLAIN_2, EXAMPLE_PLAIN], - check_ordering=True) + AssertionHelper.HTTP_200(response, vnd=False, is_list=True, attributes=[EXAMPLE_PLAIN_2, EXAMPLE_PLAIN], + check_ordering=True) assert f'Attribute Value incorrect ' in str(err.value) - def test_plain_json_attributes_list_wrong_ordering_size(self, json_asserter): + def test_plain_json_attributes_list_wrong_ordering_size(self): response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, vnd=False, is_list=True, check_ordering=True, - attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_2, EXAMPLE_PLAIN]) + AssertionHelper.HTTP_200(response, vnd=False, is_list=True, check_ordering=True, + attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_2, EXAMPLE_PLAIN]) assert 'Error: more attributes supplied than available in response. 3 found asserted 2' in str(err.value) - def test_plain_json_attributes_list_nested_missing(self, json_asserter): + def test_plain_json_attributes_list_nested_missing(self): response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) invalid_attributes = EXAMPLE_PLAIN.copy() @@ -1051,10 +1075,10 @@ def test_plain_json_attributes_list_nested_missing(self, json_asserter): invalid_attributes['owner']['new_field'] = 'test' with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, vnd=False, is_list=True, attributes=invalid_attributes) + AssertionHelper.HTTP_200(response, vnd=False, is_list=True, attributes=invalid_attributes) assert f'{invalid_attributes} NOT IN ' in str(err.value) - def test_plain_json_attributes_list_nested_mismatch(self, json_asserter): + def test_plain_json_attributes_list_nested_mismatch(self): response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) invalid_attributes = EXAMPLE_PLAIN.copy() @@ -1062,42 +1086,123 @@ def test_plain_json_attributes_list_nested_mismatch(self, json_asserter): invalid_attributes['owner']['id'] = 'test' with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, vnd=False, is_list=True, attributes=invalid_attributes) + AssertionHelper.HTTP_200(response, vnd=False, is_list=True, attributes=invalid_attributes) assert f'{invalid_attributes} NOT IN ' in str(err.value) - def test_plain_json_list_count(self, json_asserter): + def test_plain_json_list_count(self): response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) - json_asserter.HTTP_200(response, vnd=False, is_list=True, count=2, attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) + AssertionHelper.HTTP_200(response, vnd=False, is_list=True, count=2, + attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) - def test_plain_json_list_wrong_count(self, json_asserter): + def test_plain_json_list_wrong_count(self): response = self.build_response([EXAMPLE_PLAIN, EXAMPLE_PLAIN_2]) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, vnd=False, attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_2], is_list=True, - count=1) + AssertionHelper.HTTP_200(response, vnd=False, attributes=[EXAMPLE_PLAIN, EXAMPLE_PLAIN_2], is_list=True, + count=1) assert 'Difference in count of response_data, got 2 expected 1' in str(err.value) - def test_plain_json_single_count(self, json_asserter, vnd_single): + def test_plain_json_single_count(self, vnd_single): response = self.build_response(vnd_single) with pytest.raises(AssertionError) as err: - json_asserter.HTTP_200(response, count=1) + AssertionHelper.HTTP_200(response, count=1) assert f'Count is only checked when response is list' in str(err.value) + def test_vnd_meta(self, vnd_single): + response = self.build_response(vnd_single) + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( + resource=EXAMPLE_RESOURCE['type'], + meta={ + 'key': 'value', + 'other_key': 'other_value' + }, + )) + + def test_vnd_meta_mismatch(self, vnd_single): + response = self.build_response(vnd_single) + with pytest.raises(AssertionError) as err: + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( + resource=EXAMPLE_RESOURCE['type'], + meta={ + 'key': 'different value' + }, + )) + assert f'Meta field `key` had value `value` not `different value` as expected.' in str(err.value) -class TestJsonAsserterMixin(JsonAsserterMixin): - def test_has_asserter(self): - assert hasattr(self, 'json_asserter') + def test_vnd_meta_invalid_key(self, vnd_single): + response = self.build_response(vnd_single) + with pytest.raises(AssertionError) as err: + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( + resource=EXAMPLE_RESOURCE['type'], + meta={ + 'invalid_key': 'value' + }, + )) + assert f'Meta field `invalid_key` not found' in str(err.value) - @pytest.fixture(autouse=True) - def make_build_response(self): - def _build_response(data, status_code=status.HTTP_200_OK): - return Mock(status_code=status_code, json=lambda: data) - self.build_response = _build_response + def test_vnd_no_meta(self, vnd_single): + vnd_single['data'].pop('meta') + response = self.build_response(vnd_single) + with pytest.raises(AssertionError) as err: + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( + resource=EXAMPLE_RESOURCE['type'], + meta={ + 'key': 'value' + }, + )) + assert 'Meta missing' in str(err.value) - def test_status_200(self, vnd_single, vnd_error_400): + def test_vnd_invalid_meta_format(self, vnd_single): response = self.build_response(vnd_single) - self.json_asserter.HTTP_200(response) + with pytest.raises(AssertionError) as err: + AssertionHelper.HTTP_200(response, entity_refs=AssertionHelper.EntityRef( + resource=EXAMPLE_RESOURCE['type'], + meta=[{ + 'key': 'value' + }], + )) + assert 'Invalid format for meta data , must be dict' in str(err.value) + + def test_vnd_meta_list(self, vnd_list, entity_ref_1): + entity_ref_1.meta = { + 'key': 'value', + 'other_key': 'other_value' + } + response = self.build_response(vnd_list) + AssertionHelper.HTTP_200(response, entity_refs=entity_ref_1, is_list=True) + def test_vnd_list_meta_mismatch(self, vnd_list, entity_ref_1): + response = self.build_response(vnd_list) + entity_ref_1.meta = { + 'key': 'different value' + } with pytest.raises(AssertionError) as err: - response = self.build_response(vnd_error_400, status_code=status.HTTP_400_BAD_REQUEST) - self.json_asserter.HTTP_200(response) - assert 'status_code 400 != 200' in str(err.value) + AssertionHelper.HTTP_200(response, entity_refs=entity_ref_1, is_list=True) + assert f'Meta field `key` had value `value` not `different value` as expected.' in str(err.value) + + def test_vnd_list_meta_invalid_key(self, vnd_list, entity_ref_1): + entity_ref_1.meta = { + 'invalid_key': 'value' + } + response = self.build_response(vnd_list) + with pytest.raises(AssertionError) as err: + AssertionHelper.HTTP_200(response, entity_refs=entity_ref_1, is_list=True) + assert f'Meta field `invalid_key` not found' in str(err.value) + + def test_vnd_list_no_meta(self, vnd_list, entity_ref_3): + entity_ref_3.meta = { + 'key': 'value', + 'other_key': 'other_value' + } + response = self.build_response(vnd_list) + with pytest.raises(AssertionError) as err: + AssertionHelper.HTTP_200(response, entity_refs=entity_ref_3, is_list=True) + assert 'Meta missing' in str(err.value) + + def test_vnd_list_invalid_meta_format(self, vnd_list, entity_ref_1): + entity_ref_1.meta = [{ + 'invalid_key': 'value' + }] + response = self.build_response(vnd_list) + with pytest.raises(AssertionError) as err: + AssertionHelper.HTTP_200(response, entity_refs=entity_ref_1, is_list=True) + assert 'Invalid format for meta data , must be dict' in str(err.value)