From 69585dddfdfb56783ef2d5aa77a71c61f5a29fb3 Mon Sep 17 00:00:00 2001 From: michaelboulton Date: Sun, 14 May 2023 10:32:30 +0100 Subject: [PATCH 01/25] Fix deprecated flask function (#865) --- constraints.txt | 9 +++------ example/mqtt/server.py | 2 +- pyproject.toml | 2 +- requirements.txt | 13 +++++-------- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/constraints.txt b/constraints.txt index 31c54de5..aa0cb0dd 100644 --- a/constraints.txt +++ b/constraints.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.9 +# This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile --all-extras --output-file=constraints.txt --resolver=backtracking --strip-extras pyproject.toml @@ -78,7 +78,7 @@ filelock==3.8.2 # via # tox # virtualenv -flask==2.2.2 +flask==2.2.5 # via tavern (pyproject.toml) flit==3.8.0 # via tavern (pyproject.toml) @@ -92,7 +92,6 @@ idna==3.4 # via requests importlib-metadata==5.2.0 # via - # flask # keyring # twine iniconfig==1.1.1 @@ -271,9 +270,7 @@ twine==4.0.2 types-pyyaml==6.0.12.2 # via tavern (pyproject.toml) typing-extensions==4.4.0 - # via - # black - # mypy + # via mypy urllib3==1.26.13 # via # docker diff --git a/example/mqtt/server.py b/example/mqtt/server.py index 55210119..c74e2a0c 100644 --- a/example/mqtt/server.py +++ b/example/mqtt/server.py @@ -42,7 +42,6 @@ def get_cached_db(): return db -@app.before_first_request def setup_logging(): log_cfg = """ version: 1 @@ -208,5 +207,6 @@ def attempt(query): if __name__ == "__main__": + setup_logging() db = get_db() _reset_db(db) diff --git a/pyproject.toml b/pyproject.toml index d982b6d5..aa0ba20b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ dev = [ "bump2version", "colorlog", "docker-compose", - "flask", + "flask>=2.2.3", "fluent-logger", "itsdangerous", "mypy", diff --git a/requirements.txt b/requirements.txt index 93c6cc83..9baaa0ae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.9 +# This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile --all-extras --generate-hashes --output-file=requirements.txt --resolver=backtracking pyproject.toml @@ -304,9 +304,9 @@ filelock==3.8.2 \ # via # tox # virtualenv -flask==2.2.2 \ - --hash=sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b \ - --hash=sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526 +flask==2.2.5 \ + --hash=sha256:58107ed83443e86067e41eff4631b058178191a355886f8e479e347fa1285fdf \ + --hash=sha256:edee9b0a7ff26621bd5a8c10ff484ae28737a2410d99b0bb9a6850c7fb977aa0 # via tavern (pyproject.toml) flit==3.8.0 \ --hash=sha256:5ee0f88fd1cfa4160d1a8fa01237e96d06d677ae0403a0bbabbb277cb37c5e9c \ @@ -332,7 +332,6 @@ importlib-metadata==5.2.0 \ --hash=sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f \ --hash=sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd # via - # flask # keyring # twine iniconfig==1.1.1 \ @@ -860,9 +859,7 @@ types-pyyaml==6.0.12.2 \ typing-extensions==4.4.0 \ --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e - # via - # black - # mypy + # via mypy urllib3==1.26.13 \ --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc \ --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8 From b3e8827b7fcb3719c64a80c97f59f21105735111 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 27 May 2023 14:19:43 +0100 Subject: [PATCH 02/25] Bump requests from 2.28.1 to 2.31.0 (#867) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- constraints.txt | 2 +- requirements.txt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/constraints.txt b/constraints.txt index aa0cb0dd..29af6d2b 100644 --- a/constraints.txt +++ b/constraints.txt @@ -209,7 +209,7 @@ pyyaml==5.4.1 # tavern (pyproject.toml) readme-renderer==37.3 # via twine -requests==2.28.1 +requests==2.31.0 # via # docker # docker-compose diff --git a/requirements.txt b/requirements.txt index 9baaa0ae..eb58c878 100644 --- a/requirements.txt +++ b/requirements.txt @@ -714,9 +714,9 @@ readme-renderer==37.3 \ --hash=sha256:cd653186dfc73055656f090f227f5cb22a046d7f71a841dfa305f55c9a513273 \ --hash=sha256:f67a16caedfa71eef48a31b39708637a6f4664c4394801a7b0d6432d13907343 # via twine -requests==2.28.1 \ - --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \ - --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349 +requests==2.31.0 \ + --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ + --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 # via # docker # docker-compose From c34b70320251c4368c969a5bf02ad4fee8e6adba Mon Sep 17 00:00:00 2001 From: michaelboulton Date: Sun, 4 Jun 2023 11:17:11 +0100 Subject: [PATCH 03/25] Allow multi part file uploads (#870) --- constraints.txt | 6 + pyproject.toml | 3 + requirements.txt | 12 ++ scripts/smoke.bash | 3 +- tavern/_core/schema/extensions.py | 11 +- tavern/_core/schema/tests.jsonschema.yaml | 4 +- tavern/_plugins/rest/files.py | 189 ++++++++++++++++++++++ tavern/_plugins/rest/request.py | 129 ++------------- tests/integration/server.py | 67 ++++++-- tests/integration/test_files.tavern.yaml | 56 +++++++ tests/unit/test_request.py | 60 ++++++- tox-integration.ini | 2 +- 12 files changed, 407 insertions(+), 135 deletions(-) create mode 100644 tavern/_plugins/rest/files.py diff --git a/constraints.txt b/constraints.txt index 29af6d2b..7d1fd467 100644 --- a/constraints.txt +++ b/constraints.txt @@ -269,6 +269,12 @@ twine==4.0.2 # via tavern (pyproject.toml) types-pyyaml==6.0.12.2 # via tavern (pyproject.toml) +types-requests==2.31.0.0 + # via tavern (pyproject.toml) +types-setuptools==67.8.0.0 + # via tavern (pyproject.toml) +types-urllib3==1.26.25.13 + # via types-requests typing-extensions==4.4.0 # via mypy urllib3==1.26.13 diff --git a/pyproject.toml b/pyproject.toml index aa0ba20b..edd3a318 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,6 +80,8 @@ dev = [ "tox-travis", "twine", "wheel", + "types-setuptools", + "types-requests", # This has to be installed separately, otherwise you can't upload to pypi # "tbump@https://github.com/michaelboulton/tbump/archive/714ba8957a3c84b625608ceca39811ebe56229dc.zip", ] @@ -132,6 +134,7 @@ addopts = [ "--strict-markers", "-p", "no:logging", "--tb=short", + "--color=yes" ] norecursedirs = [ ".git", diff --git a/requirements.txt b/requirements.txt index eb58c878..54015fc6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -856,6 +856,18 @@ types-pyyaml==6.0.12.2 \ --hash=sha256:1e94e80aafee07a7e798addb2a320e32956a373f376655128ae20637adb2655b \ --hash=sha256:6840819871c92deebe6a2067fb800c11b8a063632eb4e3e755914e7ab3604e83 # via tavern (pyproject.toml) +types-requests==2.31.0.0 \ + --hash=sha256:7c5cea7940f8e92ec560bbc468f65bf684aa3dcf0554a6f8c4710f5f708dc598 \ + --hash=sha256:c1c29d20ab8d84dff468d7febfe8e0cb0b4664543221b386605e14672b44ea25 + # via tavern (pyproject.toml) +types-setuptools==67.8.0.0 \ + --hash=sha256:6df73340d96b238a4188b7b7668814b37e8018168aef1eef94a3b1872e3f60ff \ + --hash=sha256:95c9ed61871d6c0e258433373a4e1753c0a7c3627a46f4d4058c7b5a08ab844f + # via tavern (pyproject.toml) +types-urllib3==1.26.25.13 \ + --hash=sha256:3300538c9dc11dad32eae4827ac313f5d986b8b21494801f1bf97a1ac6c03ae5 \ + --hash=sha256:5dbd1d2bef14efee43f5318b5d36d805a489f6600252bb53626d4bfafd95e27c + # via types-requests typing-extensions==4.4.0 \ --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e diff --git a/scripts/smoke.bash b/scripts/smoke.bash index dceb58d5..49f7d8ac 100755 --- a/scripts/smoke.bash +++ b/scripts/smoke.bash @@ -2,7 +2,8 @@ set -ex -ruff tavern +ruff tavern tests --fix +black tavern tests # Separate as isort can interfere with other testenvs tox --parallel -c tox.ini \ diff --git a/tavern/_core/schema/extensions.py b/tavern/_core/schema/extensions.py index 5e6c9eb9..ca352be0 100644 --- a/tavern/_core/schema/extensions.py +++ b/tavern/_core/schema/extensions.py @@ -368,6 +368,8 @@ def validate_cert_tuple_or_str(value, rule_obj, path) -> bool: def validate_file_spec(value, rule_obj, path) -> bool: """Validate file upload arguments""" + logger = get_pykwalify_logger("tavern.schema.extensions") + if not isinstance(value, dict): raise BadSchemaError( "File specification must be a mapping of file names to file specs, got {}".format( @@ -375,11 +377,16 @@ def validate_file_spec(value, rule_obj, path) -> bool: ) ) + if value.get("file_path"): + # If the file spec was a list, this function will be called for each item. Just call this + # function recursively to check each item. + return validate_file_spec({"file": value}, rule_obj, path) + for _, filespec in value.items(): if isinstance(filespec, str): file_path = filespec elif isinstance(filespec, dict): - valid = {"file_path", "content_type", "content_encoding"} + valid = {"file_path", "content_type", "content_encoding", "form_field_name"} extra = set(filespec.keys()) - valid if extra: raise BadSchemaError( @@ -399,7 +406,7 @@ def validate_file_spec(value, rule_obj, path) -> bool: if not os.path.exists(file_path): if re.search(".*{.+}.*", file_path): - get_pykwalify_logger("tavern.schemas.extensions").debug( + logger.debug( "Could not find file path, but it might be a format variable, so continuing" ) else: diff --git a/tavern/_core/schema/tests.jsonschema.yaml b/tavern/_core/schema/tests.jsonschema.yaml index ebd62f08..880333df 100644 --- a/tavern/_core/schema/tests.jsonschema.yaml +++ b/tavern/_core/schema/tests.jsonschema.yaml @@ -162,7 +162,9 @@ definitions: description: Path to a file to upload as the request body files: - type: object + oneOf: + - type: object + - type: array description: Files to send as part of the request clear_session_cookies: diff --git a/tavern/_plugins/rest/files.py b/tavern/_plugins/rest/files.py new file mode 100644 index 00000000..3f72db8a --- /dev/null +++ b/tavern/_plugins/rest/files.py @@ -0,0 +1,189 @@ +import dataclasses +import logging +import mimetypes +import os +from contextlib import ExitStack +from typing import Any, List, Optional, Tuple, Union + +from tavern._core import exceptions +from tavern._core.dict_util import format_keys +from tavern._core.pytest.config import TestConfig + +logger = logging.getLogger(__name__) + + +@dataclasses.dataclass +class _Filespec: + """A description of a file for a file upload, possibly as part of a multi part upload""" + + path: str + content_type: Optional[str] = None + content_encoding: Optional[str] = None + form_field_name: Optional[str] = None + + +def _parse_filespec(filespec: Union[str, dict]) -> _Filespec: + """ + Get configuration for uploading file + + Args: + filespec: Can either be one of + - A path to a file + - A dict containing 'long' format, possibly including content type/encoding and the + multipart 'name' + + Returns: + The parsed file spec + + Raises: + exceptions.BadSchemaError: If the file spec was invalid + """ + if isinstance(filespec, str): + return _Filespec(filespec) + elif isinstance(filespec, dict): + try: + # The one required key + path = filespec["file_path"] + except KeyError as e: + raise exceptions.BadSchemaError( + "File spec dict did not contain the required 'file_path' key" + ) from e + + return _Filespec( + path, + filespec.get("content_type"), + filespec.get("content_encoding"), + filespec.get("form_field_name"), + ) + else: + # Could remove, also done in schema check + raise exceptions.BadSchemaError( + "File specification must be a path or a dictionary" + ) + + +def guess_filespec( + filespec: Union[str, dict], stack: ExitStack, test_block_config: TestConfig +) -> Tuple[List, Optional[str]]: + """tries to guess the content type and encoding from a file. + + Args: + test_block_config: config for test/stage + stack: exit stack to add open files context to + filespec: a string path to a file or a dictionary of the file path, content type, and encoding. + + Returns: + A tuple of either length 2 (filename and file object), 3 (as before, with content type), + or 4 (as before, with with content encoding). If a group name for the multipart upload + was specified, this is also returned. + + Notes: + If a 4-tuple is returned, the last element is a dictionary of headers to send to requests, + _not_ the raw encoding value. + """ + if not mimetypes.inited: + mimetypes.init() + + parsed = _parse_filespec(filespec) + + filepath = format_keys(parsed.path, test_block_config.variables) + filename = os.path.basename(filepath) + + # a 2-tuple ('filename', fileobj) + file_spec = [ + filename, + stack.enter_context(open(filepath, "rb")), + ] + + # Try to guess as well, but don't override what the user specified + guessed_content_type, guessed_encoding = mimetypes.guess_type(filepath) + content_type = parsed.content_type or guessed_content_type + encoding = parsed.content_encoding or guessed_encoding + + # If it doesn't have a mimetype, or can't guess it, don't + # send the content type for the file + if content_type: + # a 3-tuple ('filename', fileobj, 'content_type') + logger.debug("content_type for '%s' = '%s'", filename, content_type) + file_spec.append(content_type) + if encoding: + # or a 4-tuple ('filename', fileobj, 'content_type', custom_headers) + logger.debug("encoding for '%s' = '%s'", filename, encoding) + # encoding is None for no encoding or the name of the + # program used to encode (e.g. compress or gzip). The + # encoding is suitable for use as a Content-Encoding header. + file_spec.append({"Content-Encoding": encoding}) + + return file_spec, parsed.form_field_name + + +def _parse_file_mapping(file_args, stack, test_block_config) -> dict: + """Parses a simple mapping of uploads where each key is mapped to one form field name which has one file""" + files_to_send = {} + for key, filespec in file_args.items(): + file_spec, form_field_name = guess_filespec(filespec, stack, test_block_config) + + # If it's a dict then the key is used as the name, at least to maintain backwards compatability + if form_field_name: + logger.warning( + f"Specified 'form_field_name' as '{form_field_name}' in file spec, but the file name was inferred to be '{key}' from the mapping - the form_field_name will be ignored" + ) + + files_to_send[key] = tuple(file_spec) + return files_to_send + + +def _parse_file_list(file_args, stack, test_block_config) -> List: + """Parses a case where there may be multiple files uploaded as part of one form field""" + files_to_send: List[Any] = [] + for filespec in file_args: + file_spec, form_field_name = guess_filespec(filespec, stack, test_block_config) + + if not form_field_name: + raise exceptions.BadSchemaError( + "If specifying a list of files to upload for a multi part upload, the 'form_field_name' key must also be specified for each file to upload" + ) + + files_to_send.append( + ( + form_field_name, + tuple(file_spec), + ) + ) + + return files_to_send + + +def get_file_arguments( + request_args: dict, stack: ExitStack, test_block_config: TestConfig +) -> dict: + """Get correct arguments for anything that should be passed as a file to + requests + + Args: + request_args: args passed to requests + test_block_config: config for test + stack: context stack to add file objects to so they're + closed correctly after use + + Returns: + mapping of 'files' block to pass directly to requests + """ + + files_to_send: Optional[Union[dict, List]] = None + + file_args = request_args.get("files") + + if isinstance(file_args, dict): + files_to_send = _parse_file_mapping(file_args, stack, test_block_config) + elif isinstance(file_args, list): + files_to_send = _parse_file_list(file_args, stack, test_block_config) + elif file_args is not None: + raise exceptions.BadSchemaError( + f"'files' key in a HTTP request can only be a dict or a list but was {type(file_args)}" + ) + + if files_to_send: + return {"files": files_to_send} + else: + return {} diff --git a/tavern/_plugins/rest/request.py b/tavern/_plugins/rest/request.py index 1639b990..e7ffe752 100644 --- a/tavern/_plugins/rest/request.py +++ b/tavern/_plugins/rest/request.py @@ -1,12 +1,10 @@ import contextlib import json import logging -import mimetypes -import os import warnings from contextlib import ExitStack from itertools import filterfalse, tee -from typing import Mapping, MutableMapping, Optional, Union +from typing import Mapping, MutableMapping, Optional from urllib.parse import quote_plus import requests @@ -20,6 +18,7 @@ from tavern._core.general import valid_http_methods from tavern._core.pytest.config import TestConfig from tavern._core.report import attach_yaml +from tavern._plugins.rest.files import get_file_arguments, guess_filespec from tavern.request import BaseRequest logger = logging.getLogger(__name__) @@ -94,7 +93,14 @@ def get_header(name): filename = fspec.get("file_body") if filename: with ExitStack() as stack: - file_spec = guess_filespec(filename, stack, test_block_config) + file_spec, group_name = guess_filespec(filename, stack, test_block_config) + + # Group name doesn't matter here as it's a single file + if group_name: + logger.warning( + f"'group_name' for the 'file_body' key was specified as '{group_name}' but this will be ignored " + ) + fspec["file_body"] = filename if len(file_spec) == 2: logger.debug( @@ -326,114 +332,6 @@ def partition(pred, iterable): return deep_dict_merge(from_cookiejar, from_extra) -def _read_filespec(filespec: Union[str, dict]): - """ - Get configuration for uploading file - - Can either be just a path to a file or a 'long' format including content type/encoding - - Args: - filespec: Either a string with the path to a file or a dictionary with file_path and possible content_type and/or content_encoding - - Returns: - (file path, content type, content encoding) - """ - if isinstance(filespec, str): - return filespec, None, None - elif isinstance(filespec, dict): - return ( - filespec.get("file_path"), - filespec.get("content_type"), - filespec.get("content_encoding"), - ) - else: - # Could remove, also done in schema check - raise exceptions.BadSchemaError( - "File specification must be a path or a dictionary" - ) - - -def _get_file_arguments( - request_args: dict, stack: ExitStack, test_block_config: TestConfig -) -> dict: - """Get corect arguments for anything that should be passed as a file to - requests - - Args: - request_args: args passed to requests - test_block_config: config for test - stack: context stack to add file objects to so they're - closed correctly after use - - Returns: - mapping of 'files' block to pass directly to requests - """ - - files_to_send = {} - - for key, filespec in request_args.get("files", {}).items(): - file_spec = guess_filespec(filespec, stack, test_block_config) - - files_to_send[key] = tuple(file_spec) - - if files_to_send: - return {"files": files_to_send} - else: - return {} - - -def guess_filespec( - filespec: Union[str, dict], stack: ExitStack, test_block_config: TestConfig -): - """tries to guess the content type and encoding from a file. - - Args: - test_block_config: config for test/stage - stack: exit stack to add open files context to - filespec: a string path to a file or a dictionary of the file path, content type, and encoding. - - Returns: - tuple: A tuple of either length 2 (filename and file object), 3 (as before, with ceontent type), or 4 (as before, with with content encoding) - - Notes: - If a 4-tuple is returned, the last element is a dictionary of headers to send to requests, _not_ the raw encoding value. - """ - if not mimetypes.inited: - mimetypes.init() - - filepath, content_type, encoding = _read_filespec(filespec) - - filepath = format_keys(filepath, test_block_config.variables) - filename = os.path.basename(filepath) - - # a 2-tuple ('filename', fileobj) - file_spec = [ - filename, - stack.enter_context(open(filepath, "rb")), - ] - - # Try to guess as well, but don't override what the user specified - guessed_content_type, guessed_encoding = mimetypes.guess_type(filepath) - content_type = content_type or guessed_content_type - encoding = encoding or guessed_encoding - - # If it doesn't have a mimetype, or can't guess it, don't - # send the content type for the file - if content_type: - # a 3-tuple ('filename', fileobj, 'content_type') - logger.debug("content_type for '%s' = '%s'", filename, content_type) - file_spec.append(content_type) - if encoding: - # or a 4-tuple ('filename', fileobj, 'content_type', custom_headers) - logger.debug("encoding for '%s' = '%s'", filename, encoding) - # encoding is None for no encoding or the name of the - # program used to encode (e.g. compress or gzip). The - # encoding is suitable for use as a Content-Encoding header. - file_spec.append({"Content-Encoding": encoding}) - - return file_spec - - class RestRequest(BaseRequest): optional_in_file = [ "json", @@ -530,9 +428,10 @@ def prepared_request(): file = stack.enter_context(open(file_body, "rb")) request_args.update(data=file) else: - self._request_args.update( - _get_file_arguments(request_args, stack, test_block_config) - ) + files = get_file_arguments(request_args, stack, test_block_config) + if files: + logger.debug("Sending %d files in request", len(files["files"])) + self._request_args.update(files) headers = self._request_args.get("headers", {}) for k, v in headers.items(): diff --git a/tests/integration/server.py b/tests/integration/server.py index d409b89f..7d178015 100644 --- a/tests/integration/server.py +++ b/tests/integration/server.py @@ -87,8 +87,6 @@ def upload_fake_file(): def _handle_files(): - if not mimetypes.inited: - mimetypes.init() for item in request.files.values(): if item.filename: filetype = ".{}".format(item.filename.split(".")[-1]) @@ -104,21 +102,72 @@ def _handle_files(): return "", 200 +class BadFileUploadException(Exception): + """Something wrong when uploading files""" + + +def _verify_is_file_multipart(): + if not mimetypes.inited: + mimetypes.init() + + if not request.content_type.startswith("multipart/form-data"): + raise BadFileUploadException("Was not a multipart form upload") + + if not request.files: + raise BadFileUploadException("No files in request") + + @app.route("/fake_upload_file_data", methods=["POST"]) def upload_fake_file_and_data(): - if not request.files: - return "", 401 + try: + _verify_is_file_multipart() + except BadFileUploadException as e: + return jsonify({"error": str(e)}), 400 if not request.form.to_dict(): - return "", 402 - - # Verify that the content type is `multipart` - if not request.content_type.startswith("multipart/form-data"): - return "", 403 + return "", 400 return _handle_files() +@app.route("/files_expect_in_order", methods=["POST"]) +def upload_specific_files_in_order(): + """Expects a multipart form upload with files in the correct order + + See test_files.tavern.yaml for expected list of files here + """ + + try: + _verify_is_file_multipart() + except BadFileUploadException as e: + return jsonify({"error": str(e)}), 400 + + try: + group_1 = request.files.getlist("group_1") + if len(group_1) != 2: + raise Exception(f"expected 2 files in group 1, got {len(group_1)}") + if group_1[0].filename != "OK.txt": + raise Exception( + f"First file in group 1 should be OK.txt, was {group_1[0].filename}" + ) + if group_1[1].filename != "OK.json.gz": + raise Exception( + f"Second file in group 1 should be OK.json.gz, was {group_1[1].filename}" + ) + + group_2 = request.files.getlist("group_2") + if len(group_2) != 1: + raise Exception(f"expected 1 files in group 2, got {len(group_2)}") + if group_2[0].filename != "OK.txt": + raise Exception( + f"First file in group 2 should be OK.txt, was {group_2[0].filename}" + ) + except Exception as e: + return jsonify({"error": str(e)}), 400 + + return "", 200 + + @app.route("/nested/again", methods=["GET"]) def multiple_path_items_response(): response = {"status": "OK"} diff --git a/tests/integration/test_files.tavern.yaml b/tests/integration/test_files.tavern.yaml index 76454922..f7f49247 100644 --- a/tests/integration/test_files.tavern.yaml +++ b/tests/integration/test_files.tavern.yaml @@ -224,3 +224,59 @@ stages: test_files: "test_files.tavern.yaml" response: status_code: 200 + +--- +test_name: Test uploading multi part files in a common group + +stages: + - name: Upload files + request: + url: "{global_host}/files_expect_in_order" + method: POST + files: + - form_field_name: group_2 + file_path: OK.txt + - form_field_name: group_1 + file_path: OK.txt + - form_field_name: group_1 + file_path: OK.json.gz + response: + status_code: 200 + +--- +test_name: Test uploading multi part files in a common group in a different order + +stages: + - name: Upload files + request: + url: "{global_host}/files_expect_in_order" + method: POST + files: + - form_field_name: group_1 + file_path: OK.txt + - form_field_name: group_2 + file_path: OK.txt + - form_field_name: group_1 + file_path: OK.json.gz + response: + status_code: 200 + +--- +test_name: Test uploading multi part files with wrong groups + +stages: + - name: Upload files + request: + url: "{global_host}/files_expect_in_order" + method: POST + files: + - form_field_name: group_1 + file_path: OK.txt + - form_field_name: group_2 + file_path: OK.txt + - form_field_name: group_3 + file_path: OK.json.gz + response: + status_code: 400 + json: + error: expected 2 files in group 1, got 1 diff --git a/tests/unit/test_request.py b/tests/unit/test_request.py index 2efdbe72..43aa6309 100644 --- a/tests/unit/test_request.py +++ b/tests/unit/test_request.py @@ -2,18 +2,20 @@ import os import tempfile from contextlib import ExitStack +from textwrap import dedent from unittest.mock import Mock import pytest import requests +import yaml from requests.cookies import RequestsCookieJar from tavern._core import exceptions from tavern._core.extfunctions import update_from_ext +from tavern._plugins.rest.files import get_file_arguments from tavern._plugins.rest.request import ( RestRequest, _check_allow_redirects, - _get_file_arguments, _read_expected_cookies, get_request_args, ) @@ -400,14 +402,14 @@ def test_get_no_files(self, mock_stack, includes): request_args = {} - assert _get_file_arguments(request_args, mock_stack, includes) == {} + assert get_file_arguments(request_args, mock_stack, includes) == {} def test_get_empty_files_list(self, mock_stack, includes): """No specific files specified -> no files""" request_args = {"files": {}} - assert _get_file_arguments(request_args, mock_stack, includes) == {} + assert get_file_arguments(request_args, mock_stack, includes) == {} def test_a_file(self, mock_stack, includes): """Json file should have the correct mimetype etc.""" @@ -415,7 +417,7 @@ def test_a_file(self, mock_stack, includes): with tempfile.NamedTemporaryFile(suffix=".json") as tfile: request_args = {"files": {"file1": tfile.name}} - file_spec = _get_file_arguments(request_args, mock_stack, includes) + file_spec = get_file_arguments(request_args, mock_stack, includes) file = file_spec["files"]["file1"] assert file[0] == os.path.basename(tfile.name) @@ -435,7 +437,7 @@ def test_use_long_form_content_type(self, mock_stack, includes): } } - file_spec = _get_file_arguments(request_args, mock_stack, includes) + file_spec = get_file_arguments(request_args, mock_stack, includes) file = file_spec["files"]["file1"] assert file[0] == os.path.basename(tfile.name) @@ -462,7 +464,53 @@ def test_format_filename(self, mock_stack, includes, file_args): includes.variables["tmpname"] = tfile.name request_args = {"files": {"file1": tfile.name}} - file_spec = _get_file_arguments(request_args, mock_stack, includes) + file_spec = get_file_arguments(request_args, mock_stack, includes) file = file_spec["files"]["file1"] assert file[0] == os.path.basename(tfile.name) + + def test_grouped_file_names(self, mock_stack, includes): + """Parse grouped names appropriately""" + with tempfile.NamedTemporaryFile() as tfile: + raw_yaml_args = """ + # Send file_1.txt and file_2.txt, both with name="input_files", in the multipart data. + - form_field_name: "input_files" + file_path: "%FILENAME%" + content_type: "application/customtype" + content_encoding: "UTF16" + - form_field_name: "input_files" + file_path: "%FILENAME%" + content_type: "application/json" + """ + + raw_yaml_args = raw_yaml_args.replace("%FILENAME%", tfile.name) + + file_args = yaml.safe_load(dedent(raw_yaml_args)) + + request_args = {"files": file_args} + + parsed = get_file_arguments(request_args, mock_stack, includes) + + parsed_into = { + "files": [ + ( + "input_files", + ( + os.path.basename(tfile.name), + mock_stack.enter_context.return_value, + "application/customtype", + {"Content-Encoding": "UTF16"}, + ), + ), + ( + "input_files", + ( + os.path.basename(tfile.name), + mock_stack.enter_context.return_value, + "application/json", + ), + ), + ], + } + + assert parsed_into == parsed diff --git a/tox-integration.ini b/tox-integration.ini index 402763c0..10598e92 100644 --- a/tox-integration.ini +++ b/tox-integration.ini @@ -32,7 +32,7 @@ commands = ; docker-compose build docker-compose up --build -d python -m pytest --collect-only - python -m pytest --tavern-global-cfg={toxinidir}/tests/integration/global_cfg.yaml --cov tavern + python -m pytest --tavern-global-cfg={toxinidir}/tests/integration/global_cfg.yaml --cov tavern {posargs} generic: py.test --tavern-global-cfg={toxinidir}/tests/integration/global_cfg.yaml -n 3 generic: tavern-ci --stdout . --tavern-global-cfg={toxinidir}/tests/integration/global_cfg.yaml From e0a5f9c5ed1f5940365e15e1e9d1f09267165b07 Mon Sep 17 00:00:00 2001 From: Michael Boulton Date: Sun, 4 Jun 2023 12:20:17 +0100 Subject: [PATCH 04/25] Bump to 2.1.0 --- CHANGELOG.md | 6 ++---- docs/source/conf.py | 2 +- pyproject.toml | 4 ++-- tavern/__init__.py | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2bcd486..5bfd9284 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -166,8 +166,6 @@ calling run() directly will now cause a pytest isntance to be run in the backgro # 0.18.0 Add 'timeout' parameter for http requests (2018-08-24) -## show Bump version: 0.17.2 → 0.18.0 (2018-08-24) - ## 0.18.1 Add content type/encoding to uploaded files (2018-09-05) ## 0.18.2 Fix formatting environment variables in command line global config files (2018-09-21) @@ -261,8 +259,6 @@ The initial 2 hooks should allow a user to do something before every test and af ## 1.1.1 Travis fix (2020-05-23) -## travis-force Attempt to force travis to commit (2020-05-23) - ## 1.1.2 fforce new verison to make travis actually commit (2020-05-23) ## 1.1.3 travis (2020-05-23) @@ -408,3 +404,5 @@ This is technically not a operational change but I'm adding a new tag so it can ## 2.0.5 Attempt to fix deadlock in subscribe locks (2023-02-16) ## 2.0.6 Fix a few small MQTT issues (2023-03-13) + +## 2.0.7 Lock pytest to <7.3 to fix issue with marks (2023-04-15) diff --git a/docs/source/conf.py b/docs/source/conf.py index 7ae58bfc..80c2ada6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -73,7 +73,7 @@ # The short X.Y version. version = "1.0" # The full version, including alpha/beta/rc tags. -release = "2.0.7" +release = "2.1.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index edd3a318..7cbded78 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ keywords = ["testing", "pytest"] name = "tavern" description = "Simple testing of RESTful APIs" -version = "2.0.7" +version = "2.1.0" dependencies = [ "PyYAML>=5.3.1,<7", @@ -161,7 +161,7 @@ target-version = "py38" known-first-party = ["tavern"] [tool.tbump.version] -current = "2.0.7" +current = "2.1.0" regex = ''' (?P\d+) diff --git a/tavern/__init__.py b/tavern/__init__.py index 536d021d..c6b12cd3 100644 --- a/tavern/__init__.py +++ b/tavern/__init__.py @@ -1,2 +1,2 @@ """Stop pytest warning about module already imported: PYTEST_DONT_REWRITE""" -__version__ = "2.0.7" +__version__ = "2.1.0" From 225be839b5ae7969271afc3229c58719580f9e37 Mon Sep 17 00:00:00 2001 From: michaelboulton Date: Sun, 4 Jun 2023 12:18:39 +0100 Subject: [PATCH 05/25] Update dependencies (#872) --- .pre-commit-config.yaml | 4 +- constraints.txt | 131 ++-- pyproject.toml | 5 +- requirements.txt | 959 +++++++++++++++++------------- tavern/_core/loader.py | 2 +- tavern/_core/pytest/file.py | 5 +- tavern/_core/schema/extensions.py | 2 +- tavern/_plugins/mqtt/response.py | 2 +- tavern/_plugins/rest/request.py | 2 +- tavern/_plugins/rest/response.py | 25 +- 10 files changed, 622 insertions(+), 515 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c8f31170..6ca570f8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,11 +1,11 @@ repos: - repo: https://github.com/ambv/black - rev: 23.1.0 + rev: 23.3.0 hooks: - id: black files: "(tavern|tests)" - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: "v0.0.246" + rev: "v0.0.270" hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/constraints.txt b/constraints.txt index 7d1fd467..e4e1d2e7 100644 --- a/constraints.txt +++ b/constraints.txt @@ -4,26 +4,28 @@ # # pip-compile --all-extras --output-file=constraints.txt --resolver=backtracking --strip-extras pyproject.toml # -allure-pytest==2.12.0 +allure-pytest==2.13.2 # via tavern (pyproject.toml) -allure-python-commons==2.12.0 +allure-python-commons==2.13.2 # via allure-pytest -attrs==22.1.0 +attrs==23.1.0 # via # allure-python-commons # jsonschema # pytest bcrypt==4.0.1 # via paramiko -black==23.1.0 +black==23.3.0 # via tavern (pyproject.toml) -bleach==5.0.1 +bleach==6.0.0 # via readme-renderer -build==0.9.0 +blinker==1.6.2 + # via flask +build==0.10.0 # via pip-tools bump2version==1.0.1 # via tavern (pyproject.toml) -certifi==2022.12.7 +certifi==2023.5.7 # via requests cffi==1.15.1 # via @@ -31,7 +33,7 @@ cffi==1.15.1 # pynacl cfgv==3.3.1 # via pre-commit -charset-normalizer==2.1.1 +charset-normalizer==3.1.0 # via requests click==8.1.3 # via @@ -40,13 +42,11 @@ click==8.1.3 # pip-tools colorlog==6.7.0 # via tavern (pyproject.toml) -commonmark==0.9.1 - # via rich -coverage==7.0.0 +coverage==7.2.7 # via # pytest-cov # tavern (pyproject.toml) -cryptography==39.0.1 +cryptography==41.0.1 # via # paramiko # secretstorage @@ -54,7 +54,7 @@ distlib==0.3.6 # via virtualenv distro==1.8.0 # via docker-compose -docker==6.0.1 +docker==6.1.3 # via docker-compose docker-compose==1.29.2 # via tavern (pyproject.toml) @@ -64,37 +64,37 @@ docopt==0.6.2 # via # docker-compose # pykwalify -docutils==0.19 +docutils==0.20.1 # via # flit # readme-renderer -exceptiongroup==1.0.4 +exceptiongroup==1.1.1 # via pytest execnet==1.9.0 # via pytest-xdist -faker==15.3.4 +faker==18.10.1 # via tavern (pyproject.toml) -filelock==3.8.2 +filelock==3.12.0 # via # tox # virtualenv -flask==2.2.5 +flask==2.3.2 # via tavern (pyproject.toml) -flit==3.8.0 +flit==3.9.0 # via tavern (pyproject.toml) -flit-core==3.8.0 +flit-core==3.9.0 # via flit fluent-logger==0.10.0 # via tavern (pyproject.toml) -identify==2.5.10 +identify==2.5.24 # via pre-commit idna==3.4 # via requests -importlib-metadata==5.2.0 +importlib-metadata==6.6.0 # via # keyring # twine -iniconfig==1.1.1 +iniconfig==2.0.0 # via pytest itsdangerous==2.1.2 # via @@ -116,45 +116,47 @@ jsonschema==3.2.0 # tavern (pyproject.toml) keyring==23.13.1 # via twine -markupsafe==2.1.1 +markdown-it-py==2.2.0 + # via rich +markupsafe==2.1.3 # via # jinja2 # werkzeug -more-itertools==9.0.0 +mdurl==0.1.2 + # via markdown-it-py +more-itertools==9.1.0 # via jaraco-classes -msgpack==1.0.4 +msgpack==1.0.5 # via fluent-logger -mypy==0.991 +mypy==1.3.0 # via tavern (pyproject.toml) -mypy-extensions==0.4.3 +mypy-extensions==1.0.0 # via # black # mypy # tavern (pyproject.toml) -nodeenv==1.7.0 +nodeenv==1.8.0 # via pre-commit -packaging==22.0 +packaging==23.1 # via # black # build # docker # pytest # tox -paho-mqtt==1.5.1 +paho-mqtt==1.6.1 # via tavern (pyproject.toml) -paramiko==2.12.0 +paramiko==3.2.0 # via docker -pathspec==0.10.3 +pathspec==0.11.1 # via black -pbr==5.11.0 +pbr==5.11.1 # via stevedore -pep517==0.13.0 - # via build -pip-tools==6.12.1 +pip-tools==6.13.0 # via tavern (pyproject.toml) -pkginfo==1.9.2 +pkginfo==1.9.6 # via twine -platformdirs==2.6.0 +platformdirs==3.5.1 # via # black # virtualenv @@ -163,7 +165,7 @@ pluggy==1.0.0 # allure-python-commons # pytest # tox -pre-commit==2.20.0 +pre-commit==3.3.2 # via tavern (pyproject.toml) py==1.11.0 # via @@ -171,28 +173,30 @@ py==1.11.0 # tox pycparser==2.21 # via cffi -pygments==2.13.0 +pygments==2.15.1 # via # readme-renderer # rich # tavern (pyproject.toml) -pyjwt==2.6.0 +pyjwt==2.7.0 # via tavern (pyproject.toml) pykwalify==1.8.0 # via tavern (pyproject.toml) pynacl==1.5.0 # via paramiko -pyrsistent==0.19.2 +pyproject-hooks==1.0.0 + # via build +pyrsistent==0.19.3 # via jsonschema -pytest==7.2.0 +pytest==7.2.2 # via # allure-pytest # pytest-cov # pytest-xdist # tavern (pyproject.toml) -pytest-cov==4.0.0 +pytest-cov==4.1.0 # via tavern (pyproject.toml) -pytest-xdist==3.1.0 +pytest-xdist==3.3.1 # via tavern (pyproject.toml) python-box==6.1.0 # via tavern (pyproject.toml) @@ -200,7 +204,7 @@ python-dateutil==2.8.2 # via # faker # pykwalify -python-dotenv==0.21.0 +python-dotenv==0.21.1 # via docker-compose pyyaml==5.4.1 # via @@ -217,28 +221,25 @@ requests==2.31.0 # requests-toolbelt # tavern (pyproject.toml) # twine -requests-toolbelt==0.10.1 +requests-toolbelt==1.0.0 # via twine rfc3986==2.0.0 # via twine -rich==12.6.0 +rich==13.4.1 # via twine -ruamel-yaml==0.17.21 +ruamel-yaml==0.17.31 # via pykwalify ruamel-yaml-clib==0.2.7 # via ruamel-yaml -ruff==0.0.246 +ruff==0.0.270 # via tavern (pyproject.toml) secretstorage==3.3.3 # via keyring six==1.16.0 # via - # allure-pytest - # allure-python-commons # bleach # dockerpty # jsonschema - # paramiko # python-dateutil # tox # websocket-client @@ -246,15 +247,13 @@ stevedore==4.1.1 # via tavern (pyproject.toml) texttable==1.6.7 # via docker-compose -toml==0.10.2 - # via pre-commit tomli==2.0.1 # via # black # build # coverage # mypy - # pep517 + # pyproject-hooks # pytest # tox tomli-w==1.0.0 @@ -263,26 +262,26 @@ tox==3.28.0 # via # tavern (pyproject.toml) # tox-travis -tox-travis==0.12 +tox-travis==0.13 # via tavern (pyproject.toml) twine==4.0.2 # via tavern (pyproject.toml) -types-pyyaml==6.0.12.2 +types-pyyaml==6.0.12.10 # via tavern (pyproject.toml) -types-requests==2.31.0.0 +types-requests==2.31.0.1 # via tavern (pyproject.toml) types-setuptools==67.8.0.0 # via tavern (pyproject.toml) types-urllib3==1.26.25.13 # via types-requests -typing-extensions==4.4.0 +typing-extensions==4.6.3 # via mypy -urllib3==1.26.13 +urllib3==2.0.2 # via # docker # requests # twine -virtualenv==20.17.1 +virtualenv==20.23.0 # via # pre-commit # tox @@ -292,13 +291,13 @@ websocket-client==0.59.0 # via # docker # docker-compose -werkzeug==2.2.3 +werkzeug==2.3.4 # via flask -wheel==0.38.4 +wheel==0.40.0 # via # pip-tools # tavern (pyproject.toml) -zipp==3.11.0 +zipp==3.15.0 # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: diff --git a/pyproject.toml b/pyproject.toml index 7cbded78..fd4ef5b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ Source = "https://github.com/taverntesting/tavern" dev = [ "Faker", "allure-pytest", - "black==23.1.0", + "black==23.3.0", "bump2version", "colorlog", "docker-compose", @@ -73,7 +73,7 @@ dev = [ "pre-commit", "pygments", "pytest-cov", - "ruff>=0.0.246", + "ruff>=0.0.270", "pytest-xdist", "py", "tox>=3,<4", @@ -149,6 +149,7 @@ ignore = [ "B905", # zip(..., strict=True) only valid from 3.10+ "PLR0912", "PLR0915", "PLR0911", "PLR0913", # too many branches/variables/return values - sometimes this is just unavoidable "PLR2004", # 'magic numbers' + "PLW2901", # Loop variable overridden ] select = ["E", "F", "B", "W", "I", "S", "C4", "ICN", "T20", "PLE", "RUF", "SIM105", "PL"] # Look at: UP diff --git a/requirements.txt b/requirements.txt index 54015fc6..ced87e5d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,17 +4,17 @@ # # pip-compile --all-extras --generate-hashes --output-file=requirements.txt --resolver=backtracking pyproject.toml # -allure-pytest==2.12.0 \ - --hash=sha256:1a10b2b78334443097d7be890a53c991e857e13d14781377c2f8d11eb4b5582c \ - --hash=sha256:85b73b1dbe9908ba4f84b80118a93e1049c02dd593209260d8c1c950cf286f6c +allure-pytest==2.13.2 \ + --hash=sha256:17de9dbee7f61c8e66a5b5e818b00e419dbcea44cb55c24319401ba813220690 \ + --hash=sha256:22243159e8ec81ce2b5254b4013802198821b1b42f118f69d4a289396607c7b3 # via tavern (pyproject.toml) -allure-python-commons==2.12.0 \ - --hash=sha256:d5c362dd01167f086331822e9b1912d4e6fd6cbc2d1a006dd048e77e82a7ae73 \ - --hash=sha256:f968c69d4e656bcf274f2ef6578f24afcaab663f8814e238d0ab2b8bec2e0134 +allure-python-commons==2.13.2 \ + --hash=sha256:2bb3646ec3fbf5b36d178a5e735002bc130ae9f9ba80f080af97d368ba375051 \ + --hash=sha256:8a03681330231b1deadd86b97ff68841c6591320114ae638570f1ed60d7a2033 # via allure-pytest -attrs==22.1.0 \ - --hash=sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6 \ - --hash=sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c +attrs==23.1.0 \ + --hash=sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04 \ + --hash=sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015 # via # allure-python-commons # jsonschema @@ -42,48 +42,52 @@ bcrypt==4.0.1 \ --hash=sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e \ --hash=sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3 # via paramiko -black==23.1.0 \ - --hash=sha256:0052dba51dec07ed029ed61b18183942043e00008ec65d5028814afaab9a22fd \ - --hash=sha256:0680d4380db3719ebcfb2613f34e86c8e6d15ffeabcf8ec59355c5e7b85bb555 \ - --hash=sha256:121ca7f10b4a01fd99951234abdbd97728e1240be89fde18480ffac16503d481 \ - --hash=sha256:162e37d49e93bd6eb6f1afc3e17a3d23a823042530c37c3c42eeeaf026f38468 \ - --hash=sha256:2a951cc83ab535d248c89f300eccbd625e80ab880fbcfb5ac8afb5f01a258ac9 \ - --hash=sha256:2bf649fda611c8550ca9d7592b69f0637218c2369b7744694c5e4902873b2f3a \ - --hash=sha256:382998821f58e5c8238d3166c492139573325287820963d2f7de4d518bd76958 \ - --hash=sha256:49f7b39e30f326a34b5c9a4213213a6b221d7ae9d58ec70df1c4a307cf2a1580 \ - --hash=sha256:57c18c5165c1dbe291d5306e53fb3988122890e57bd9b3dcb75f967f13411a26 \ - --hash=sha256:7a0f701d314cfa0896b9001df70a530eb2472babb76086344e688829efd97d32 \ - --hash=sha256:8178318cb74f98bc571eef19068f6ab5613b3e59d4f47771582f04e175570ed8 \ - --hash=sha256:8b70eb40a78dfac24842458476135f9b99ab952dd3f2dab738c1881a9b38b753 \ - --hash=sha256:9880d7d419bb7e709b37e28deb5e68a49227713b623c72b2b931028ea65f619b \ - --hash=sha256:9afd3f493666a0cd8f8df9a0200c6359ac53940cbde049dcb1a7eb6ee2dd7074 \ - --hash=sha256:a29650759a6a0944e7cca036674655c2f0f63806ddecc45ed40b7b8aa314b651 \ - --hash=sha256:a436e7881d33acaf2536c46a454bb964a50eff59b21b51c6ccf5a40601fbef24 \ - --hash=sha256:a59db0a2094d2259c554676403fa2fac3473ccf1354c1c63eccf7ae65aac8ab6 \ - --hash=sha256:a8471939da5e824b891b25751955be52ee7f8a30a916d570a5ba8e0f2eb2ecad \ - --hash=sha256:b0bd97bea8903f5a2ba7219257a44e3f1f9d00073d6cc1add68f0beec69692ac \ - --hash=sha256:b6a92a41ee34b883b359998f0c8e6eb8e99803aa8bf3123bf2b2e6fec505a221 \ - --hash=sha256:bb460c8561c8c1bec7824ecbc3ce085eb50005883a6203dcfb0122e95797ee06 \ - --hash=sha256:bfffba28dc52a58f04492181392ee380e95262af14ee01d4bc7bb1b1c6ca8d27 \ - --hash=sha256:c1c476bc7b7d021321e7d93dc2cbd78ce103b84d5a4cf97ed535fbc0d6660648 \ - --hash=sha256:c91dfc2c2a4e50df0026f88d2215e166616e0c80e86004d0003ece0488db2739 \ - --hash=sha256:e6663f91b6feca5d06f2ccd49a10f254f9298cc1f7f49c46e498a0771b507104 +black==23.3.0 \ + --hash=sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5 \ + --hash=sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915 \ + --hash=sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326 \ + --hash=sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940 \ + --hash=sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b \ + --hash=sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30 \ + --hash=sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c \ + --hash=sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c \ + --hash=sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab \ + --hash=sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27 \ + --hash=sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2 \ + --hash=sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961 \ + --hash=sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9 \ + --hash=sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb \ + --hash=sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70 \ + --hash=sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331 \ + --hash=sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2 \ + --hash=sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266 \ + --hash=sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d \ + --hash=sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6 \ + --hash=sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b \ + --hash=sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925 \ + --hash=sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8 \ + --hash=sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4 \ + --hash=sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3 # via tavern (pyproject.toml) -bleach==5.0.1 \ - --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ - --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c +bleach==6.0.0 \ + --hash=sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414 \ + --hash=sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4 # via readme-renderer -build==0.9.0 \ - --hash=sha256:1a07724e891cbd898923145eb7752ee7653674c511378eb9c7691aab1612bc3c \ - --hash=sha256:38a7a2b7a0bdc61a42a0a67509d88c71ecfc37b393baba770fae34e20929ff69 +blinker==1.6.2 \ + --hash=sha256:4afd3de66ef3a9f8067559fb7a1cbe555c17dcbe15971b05d1b625c3e7abe213 \ + --hash=sha256:c3d739772abb7bc2860abf5f2ec284223d9ad5c76da018234f6f50d6f31ab1f0 + # via flask +build==0.10.0 \ + --hash=sha256:af266720050a66c893a6096a2f410989eeac74ff9a68ba194b3f6473e8e26171 \ + --hash=sha256:d5b71264afdb5951d6704482aac78de887c80691c52b88a9ad195983ca2c9269 # via pip-tools bump2version==1.0.1 \ --hash=sha256:37f927ea17cde7ae2d7baf832f8e80ce3777624554a653006c9144f8017fe410 \ --hash=sha256:762cb2bfad61f4ec8e2bdf452c7c267416f8c70dd9ecb1653fd0bbb01fa936e6 # via tavern (pyproject.toml) -certifi==2022.12.7 \ - --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \ - --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18 +certifi==2023.5.7 \ + --hash=sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7 \ + --hash=sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716 # via requests cffi==1.15.1 \ --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ @@ -157,9 +161,82 @@ cfgv==3.3.1 \ --hash=sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426 \ --hash=sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736 # via pre-commit -charset-normalizer==2.1.1 \ - --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \ - --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f +charset-normalizer==3.1.0 \ + --hash=sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6 \ + --hash=sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1 \ + --hash=sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e \ + --hash=sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373 \ + --hash=sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62 \ + --hash=sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230 \ + --hash=sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be \ + --hash=sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c \ + --hash=sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0 \ + --hash=sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448 \ + --hash=sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f \ + --hash=sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649 \ + --hash=sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d \ + --hash=sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0 \ + --hash=sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706 \ + --hash=sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a \ + --hash=sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59 \ + --hash=sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23 \ + --hash=sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5 \ + --hash=sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb \ + --hash=sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e \ + --hash=sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e \ + --hash=sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c \ + --hash=sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28 \ + --hash=sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d \ + --hash=sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41 \ + --hash=sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974 \ + --hash=sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce \ + --hash=sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f \ + --hash=sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1 \ + --hash=sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d \ + --hash=sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8 \ + --hash=sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017 \ + --hash=sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31 \ + --hash=sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7 \ + --hash=sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8 \ + --hash=sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e \ + --hash=sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14 \ + --hash=sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd \ + --hash=sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d \ + --hash=sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795 \ + --hash=sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b \ + --hash=sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b \ + --hash=sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b \ + --hash=sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203 \ + --hash=sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f \ + --hash=sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19 \ + --hash=sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1 \ + --hash=sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a \ + --hash=sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac \ + --hash=sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9 \ + --hash=sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0 \ + --hash=sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137 \ + --hash=sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f \ + --hash=sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6 \ + --hash=sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5 \ + --hash=sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909 \ + --hash=sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f \ + --hash=sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0 \ + --hash=sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324 \ + --hash=sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755 \ + --hash=sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb \ + --hash=sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854 \ + --hash=sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c \ + --hash=sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60 \ + --hash=sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84 \ + --hash=sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0 \ + --hash=sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b \ + --hash=sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1 \ + --hash=sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531 \ + --hash=sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1 \ + --hash=sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11 \ + --hash=sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326 \ + --hash=sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df \ + --hash=sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab # via requests click==8.1.3 \ --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ @@ -172,87 +249,90 @@ colorlog==6.7.0 \ --hash=sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662 \ --hash=sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5 # via tavern (pyproject.toml) -commonmark==0.9.1 \ - --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ - --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 - # via rich -coverage[toml]==7.0.0 \ - --hash=sha256:0a8b0e86bede874bf5da566b02194fbb12dd14ce3585cabd58452007f272ba81 \ - --hash=sha256:100546219af59d2ad82d4575de03a303eb27b75ea36ffbd1677371924d50bcbc \ - --hash=sha256:10b6246cae61896ab4c7568e498e492cbb73a2dfa4c3af79141c43cf806f929a \ - --hash=sha256:215f40ef86f1958a1151fa7fad2b4f2f99534c4e10a34a1e065eba3f19ef8868 \ - --hash=sha256:2331b7bd84a1be79bd17ca8e103ce38db8cbf7cb354dc56e651ba489cf849212 \ - --hash=sha256:30220518dd89c4878908d73f5f3d1269f86e9e045354436534587a18c7b9da85 \ - --hash=sha256:32b94ad926e933976627f040f96dd1d9b0ac91f8d27e868c30a28253b9b6ac2d \ - --hash=sha256:33efe89cd0efef016db19d8d05aa46631f76793de90a61b6717acb202b36fe60 \ - --hash=sha256:36b62f0220459e528ad5806cc7dede71aa716e067d2cb10cb4a09686b8791fba \ - --hash=sha256:3c0deee68e0dae1d6e3fe6943c76d7e66fbeb6519bd08e4e5366bcc28a8a9aca \ - --hash=sha256:3ec256a592b497f26054195f7d7148892aca8c4cdcc064a7cc66ef7a0455b811 \ - --hash=sha256:43ec1935c6d6caab4f3bc126d20bd709c0002a175d62208ebe745be37a826a41 \ - --hash=sha256:5885a4ceb6dde34271bb0adafa4a248a7f589c89821e9da3110c39f92f41e21b \ - --hash=sha256:59e71912c7fc78d08a567ee65656123878f49ca1b5672e660ea70bf8dfbebf8f \ - --hash=sha256:793dcd9d42035746fc7637df4336f7581df19d33c5c5253cf988c99d8e93a8ba \ - --hash=sha256:8593c9baf1f0f273afa22f5b45508b76adc7b8e94e17e7d98fbe1e3cd5812af2 \ - --hash=sha256:8938f3a10f45019b502020ba9567b97b6ecc8c76b664b421705c5406d4f92fe8 \ - --hash=sha256:8dbf83a4611c591b5de65069b6fd4dd3889200ed270cd2f7f5ac765d3842889f \ - --hash=sha256:8f1e6d9c70d45a960d3f3d781ea62b167fdf2e0e1f6bb282b96feea653adb923 \ - --hash=sha256:96b5b1f1079e48f56bfccf103bcf44d48b9eb5163f1ea523fad580f15d3fe5e0 \ - --hash=sha256:97c0b001ff15b8e8882995fc07ac0a08c8baf8b13c1145f3f12e0587bbb0e335 \ - --hash=sha256:9a175da2a7320e18fc3ee1d147639a2b3a8f037e508c96aa2da160294eb50e17 \ - --hash=sha256:9fadd15f9fcfd7b16d9cccce9f5e6ec6f9b8df860633ad9aa62c2b14c259560f \ - --hash=sha256:a290b7921c1c05787b953e5854d394e887df40696f21381cc33c4e2179bf50ac \ - --hash=sha256:a30b646fbdd5bc52f506e149fa4fbdef82432baf6b81774e61ec4e3b43b9cbde \ - --hash=sha256:a6fff0f08bc5ffd0d78db821971472b4adc2ee876b86f743e46d634fb8e3c22f \ - --hash=sha256:a7e1bb36b4e57a2d304322021b35d4e4a25fa0d501ba56e8e51efaebf4480556 \ - --hash=sha256:a8785791c2120af114ea7a06137f7778632e568a5aa2bbfc3b46c573b702af74 \ - --hash=sha256:ae088eb1cbdad8206931b1bf3f11dee644e038a9300be84d3e705e29356e5b1d \ - --hash=sha256:b18df11efa615b79b9ecc13035a712957ff6283f7b244e57684e1c092869f541 \ - --hash=sha256:b8f7cd942dda3795fc9eadf303cc53a422ac057e3b70c2ad6d4276ec6a83a541 \ - --hash=sha256:bc904aa96105d73357de03de76336b1e3db28e2b12067d36625fd9646ab043fd \ - --hash=sha256:bcaf18e46668057051a312c714a4548b81f7e8fb3454116ad97be7562d2a99e4 \ - --hash=sha256:bf437a04b9790d3c9cd5b48e9ce9aa84229040e3ae7d6c670a55118906113c5a \ - --hash=sha256:c1ba6e63b831112b9484ff5905370d89e43d4316bac76d403031f60d61597466 \ - --hash=sha256:c4b63888bef2928d0eca12cbce0760cfb696acb4fe226eb55178b6a2a039328a \ - --hash=sha256:c685fc17d6f4f1a3833e9dac27d0b931f7ccb52be6c30d269374203c7d0204a2 \ - --hash=sha256:cda63459eb20652b22e038729a8f5063862c189a3963cb042a764b753172f75e \ - --hash=sha256:d43d406a4d73aa7f855fa44fa77ff47e739b565b2af3844600cdc016d01e46b9 \ - --hash=sha256:d564142a03d3bc8913499a458e931b52ddfe952f69b6cd4b24d810fd2959044a \ - --hash=sha256:d6b4af31fb49a2ae8de1cd505fa66c403bfcc5066e845ac19d8904dcfc9d40da \ - --hash=sha256:db8141856dc9be0917413df7200f53accf1d84c8b156868e6af058a1ea8e903a \ - --hash=sha256:de06e7585abe88c6d38c1b73ce4c3cb4c1a79fbb0da0d0f8e8689ef5729ec60d \ - --hash=sha256:e06abac1a4aec1ff989131e43ca917fc7bd296f34bf0cfe86cbf74343b21566d \ - --hash=sha256:e645c73cbfc4577d93747d3f793115acf6f907a7eb9208fa807fdcf2da1964a4 \ - --hash=sha256:e907db8bdd0ad1253a33c20fdc5f0f6209d271114a9c6f1fcdf96617343f7ca0 \ - --hash=sha256:f2569682d6ea9628da8d6ba38579a48b1e53081226ec7a6c82b5024b3ce5009f \ - --hash=sha256:f6a4bf5bdee93f6817797beba7086292c2ebde6df0d5822e0c33f8b05415c339 \ - --hash=sha256:f9071e197faa24837b967bc9aa0b9ef961f805a75f1ee3ea1f3367f55cd46c3c \ - --hash=sha256:fb85b7a7a4b204bd59d6d0b0c8d87d9ffa820da225e691dfaffc3137dc05b5f6 \ - --hash=sha256:fee283cd36c3f14422d9c1b51da24ddbb5e1eed89ad2480f6a9f115df38b5df8 +coverage[toml]==7.2.7 \ + --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ + --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ + --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ + --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ + --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ + --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ + --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ + --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ + --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ + --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ + --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ + --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ + --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ + --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ + --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ + --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ + --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ + --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ + --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ + --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ + --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ + --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ + --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ + --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ + --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ + --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ + --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ + --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ + --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ + --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ + --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ + --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ + --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ + --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ + --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ + --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ + --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ + --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ + --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ + --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ + --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ + --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ + --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ + --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ + --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ + --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ + --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ + --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ + --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ + --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ + --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ + --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ + --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ + --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ + --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ + --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ + --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ + --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ + --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ + --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 # via # pytest-cov # tavern (pyproject.toml) -cryptography==39.0.1 \ - --hash=sha256:0f8da300b5c8af9f98111ffd512910bc792b4c77392a9523624680f7956a99d4 \ - --hash=sha256:35f7c7d015d474f4011e859e93e789c87d21f6f4880ebdc29896a60403328f1f \ - --hash=sha256:5aa67414fcdfa22cf052e640cb5ddc461924a045cacf325cd164e65312d99502 \ - --hash=sha256:5d2d8b87a490bfcd407ed9d49093793d0f75198a35e6eb1a923ce1ee86c62b41 \ - --hash=sha256:6687ef6d0a6497e2b58e7c5b852b53f62142cfa7cd1555795758934da363a965 \ - --hash=sha256:6f8ba7f0328b79f08bdacc3e4e66fb4d7aab0c3584e0bd41328dce5262e26b2e \ - --hash=sha256:706843b48f9a3f9b9911979761c91541e3d90db1ca905fd63fee540a217698bc \ - --hash=sha256:807ce09d4434881ca3a7594733669bd834f5b2c6d5c7e36f8c00f691887042ad \ - --hash=sha256:83e17b26de248c33f3acffb922748151d71827d6021d98c70e6c1a25ddd78505 \ - --hash=sha256:96f1157a7c08b5b189b16b47bc9db2332269d6680a196341bf30046330d15388 \ - --hash=sha256:aec5a6c9864be7df2240c382740fcf3b96928c46604eaa7f3091f58b878c0bb6 \ - --hash=sha256:b0afd054cd42f3d213bf82c629efb1ee5f22eba35bf0eec88ea9ea7304f511a2 \ - --hash=sha256:ced4e447ae29ca194449a3f1ce132ded8fcab06971ef5f618605aacaa612beac \ - --hash=sha256:d1f6198ee6d9148405e49887803907fe8962a23e6c6f83ea7d98f1c0de375695 \ - --hash=sha256:e124352fd3db36a9d4a21c1aa27fd5d051e621845cb87fb851c08f4f75ce8be6 \ - --hash=sha256:e422abdec8b5fa8462aa016786680720d78bdce7a30c652b7fadf83a4ba35336 \ - --hash=sha256:ef8b72fa70b348724ff1218267e7f7375b8de4e8194d1636ee60510aae104cd0 \ - --hash=sha256:f0c64d1bd842ca2633e74a1a28033d139368ad959872533b1bab8c80e8240a0c \ - --hash=sha256:f24077a3b5298a5a06a8e0536e3ea9ec60e4c7ac486755e5fb6e6ea9b3500106 \ - --hash=sha256:fdd188c8a6ef8769f148f88f859884507b954cc64db6b52f66ef199bb9ad660a \ - --hash=sha256:fe913f20024eb2cb2f323e42a64bdf2911bb9738a15dba7d3cce48151034e3a8 +cryptography==41.0.1 \ + --hash=sha256:059e348f9a3c1950937e1b5d7ba1f8e968508ab181e75fc32b879452f08356db \ + --hash=sha256:1a5472d40c8f8e91ff7a3d8ac6dfa363d8e3138b961529c996f3e2df0c7a411a \ + --hash=sha256:1a8e6c2de6fbbcc5e14fd27fb24414507cb3333198ea9ab1258d916f00bc3039 \ + --hash=sha256:1fee5aacc7367487b4e22484d3c7e547992ed726d14864ee33c0176ae43b0d7c \ + --hash=sha256:5d092fdfedaec4cbbffbf98cddc915ba145313a6fdaab83c6e67f4e6c218e6f3 \ + --hash=sha256:5f0ff6e18d13a3de56f609dd1fd11470918f770c6bd5d00d632076c727d35485 \ + --hash=sha256:7bfc55a5eae8b86a287747053140ba221afc65eb06207bedf6e019b8934b477c \ + --hash=sha256:7fa01527046ca5facdf973eef2535a27fec4cb651e4daec4d043ef63f6ecd4ca \ + --hash=sha256:8dde71c4169ec5ccc1087bb7521d54251c016f126f922ab2dfe6649170a3b8c5 \ + --hash=sha256:8f4ab7021127a9b4323537300a2acfb450124b2def3756f64dc3a3d2160ee4b5 \ + --hash=sha256:948224d76c4b6457349d47c0c98657557f429b4e93057cf5a2f71d603e2fc3a3 \ + --hash=sha256:9a6c7a3c87d595608a39980ebaa04d5a37f94024c9f24eb7d10262b92f739ddb \ + --hash=sha256:b46e37db3cc267b4dea1f56da7346c9727e1209aa98487179ee8ebed09d21e43 \ + --hash=sha256:b4ceb5324b998ce2003bc17d519080b4ec8d5b7b70794cbd2836101406a9be31 \ + --hash=sha256:cb33ccf15e89f7ed89b235cff9d49e2e62c6c981a6061c9c8bb47ed7951190bc \ + --hash=sha256:d198820aba55660b4d74f7b5fd1f17db3aa5eb3e6893b0a41b75e84e4f9e0e4b \ + --hash=sha256:d34579085401d3f49762d2f7d6634d6b6c2ae1242202e860f4d26b046e3a1006 \ + --hash=sha256:eb8163f5e549a22888c18b0d53d6bb62a20510060a22fd5a995ec8a05268df8a \ + --hash=sha256:f73bff05db2a3e5974a6fd248af2566134d8981fd7ab012e5dd4ddb1d9a70699 # via # paramiko # secretstorage @@ -264,9 +344,9 @@ distro==1.8.0 \ --hash=sha256:02e111d1dc6a50abb8eed6bf31c3e48ed8b0830d1ea2a1b78c61765c2513fdd8 \ --hash=sha256:99522ca3e365cac527b44bde033f64c6945d90eb9f769703caaec52b09bbd3ff # via docker-compose -docker[ssh]==6.0.1 \ - --hash=sha256:896c4282e5c7af5c45e8b683b0b0c33932974fe6e50fc6906a0a83616ab3da97 \ - --hash=sha256:dbcb3bd2fa80dca0788ed908218bf43972772009b881ed1e20dfc29a65e49782 +docker[ssh]==6.1.3 \ + --hash=sha256:aa6d17830045ba5ef0168d5eaa34d37beeb113948c413affe1d5991fc11f9a20 \ + --hash=sha256:aecd2277b8bf8e506e484f6ab7aec39abe0038e29fa4a6d3ba86c3fe01844ed9 # via docker-compose docker-compose==1.29.2 \ --hash=sha256:4c8cd9d21d237412793d18bd33110049ee9af8dab3fe2c213bbd0733959b09b7 \ @@ -280,63 +360,63 @@ docopt==0.6.2 \ # via # docker-compose # pykwalify -docutils==0.19 \ - --hash=sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6 \ - --hash=sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc +docutils==0.20.1 \ + --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \ + --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b # via # flit # readme-renderer -exceptiongroup==1.0.4 \ - --hash=sha256:542adf9dea4055530d6e1279602fa5cb11dab2395fa650b8674eaec35fc4a828 \ - --hash=sha256:bd14967b79cd9bdb54d97323216f8fdf533e278df937aa2a90089e7d6e06e5ec +exceptiongroup==1.1.1 \ + --hash=sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e \ + --hash=sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785 # via pytest execnet==1.9.0 \ --hash=sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5 \ --hash=sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142 # via pytest-xdist -faker==15.3.4 \ - --hash=sha256:2d5443724f640ce07658ca8ca8bbd40d26b58914e63eec6549727869aa67e2cc \ - --hash=sha256:c2a2ff9dd8dfd991109b517ab98d5cb465e857acb45f6b643a0e284a9eb2cc76 +faker==18.10.1 \ + --hash=sha256:633b278caa3ec239463f9139c74da2607c8da5710e56d5d7d30fc8a7440104c4 \ + --hash=sha256:d9f363720c4a6cf9884c6c3e26e2ce26266ffe5d741a9bc7cb9256779bc62190 # via tavern (pyproject.toml) -filelock==3.8.2 \ - --hash=sha256:7565f628ea56bfcd8e54e42bdc55da899c85c1abfe1b5bcfd147e9188cebb3b2 \ - --hash=sha256:8df285554452285f79c035efb0c861eb33a4bcfa5b7a137016e32e6a90f9792c +filelock==3.12.0 \ + --hash=sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9 \ + --hash=sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718 # via # tox # virtualenv -flask==2.2.5 \ - --hash=sha256:58107ed83443e86067e41eff4631b058178191a355886f8e479e347fa1285fdf \ - --hash=sha256:edee9b0a7ff26621bd5a8c10ff484ae28737a2410d99b0bb9a6850c7fb977aa0 +flask==2.3.2 \ + --hash=sha256:77fd4e1249d8c9923de34907236b747ced06e5467ecac1a7bb7115ae0e9670b0 \ + --hash=sha256:8c2f9abd47a9e8df7f0c3f091ce9497d011dc3b31effcf4c85a6e2b50f4114ef # via tavern (pyproject.toml) -flit==3.8.0 \ - --hash=sha256:5ee0f88fd1cfa4160d1a8fa01237e96d06d677ae0403a0bbabbb277cb37c5e9c \ - --hash=sha256:d0f2a8f4bd45dc794befbf5839ecc0fd3830d65a57bd52b5997542fac5d5e937 +flit==3.9.0 \ + --hash=sha256:076c3aaba5ac24cf0ad3251f910900d95a08218e6bcb26f21fef1036cc4679ca \ + --hash=sha256:d75edf5eb324da20d53570a6a6f87f51e606eee8384925cd66a90611140844c7 # via tavern (pyproject.toml) -flit-core==3.8.0 \ - --hash=sha256:64a29ec845164a6abe1136bf4bc5ae012bdfe758ed42fc7571a9059a7c80bd83 \ - --hash=sha256:b305b30c99526df5e63d6022dd2310a0a941a187bd3884f4c8ef0418df6c39f3 +flit-core==3.9.0 \ + --hash=sha256:72ad266176c4a3fcfab5f2930d76896059851240570ce9a98733b658cb786eba \ + --hash=sha256:7aada352fb0c7f5538c4fafeddf314d3a6a92ee8e2b1de70482329e42de70301 # via flit fluent-logger==0.10.0 \ --hash=sha256:543637e5e62ec3fc3c92b44e5a4e148a3cea88a0f8ca4fae26c7e60fda7564c1 \ --hash=sha256:678bda90c513ff0393964b64544ce41ef25669d2089ce6c3b63d9a18554b9bfa # via tavern (pyproject.toml) -identify==2.5.10 \ - --hash=sha256:dce9e31fee7dbc45fea36a9e855c316b8fbf807e65a862f160840bb5a2bf5dfd \ - --hash=sha256:fb7c2feaeca6976a3ffa31ec3236a6911fbc51aec9acc111de2aed99f244ade2 +identify==2.5.24 \ + --hash=sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4 \ + --hash=sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d # via pre-commit idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 # via requests -importlib-metadata==5.2.0 \ - --hash=sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f \ - --hash=sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd +importlib-metadata==6.6.0 \ + --hash=sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed \ + --hash=sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705 # via # keyring # twine -iniconfig==1.1.1 \ - --hash=sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3 \ - --hash=sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32 +iniconfig==2.0.0 \ + --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \ + --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 # via pytest itsdangerous==2.1.2 \ --hash=sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44 \ @@ -372,190 +452,211 @@ keyring==23.13.1 \ --hash=sha256:771ed2a91909389ed6148631de678f82ddc73737d85a927f382a8a1b157898cd \ --hash=sha256:ba2e15a9b35e21908d0aaf4e0a47acc52d6ae33444df0da2b49d41a46ef6d678 # via twine -markupsafe==2.1.1 \ - --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \ - --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \ - --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \ - --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \ - --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \ - --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \ - --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \ - --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \ - --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \ - --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \ - --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \ - --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \ - --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \ - --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \ - --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \ - --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \ - --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \ - --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \ - --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \ - --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \ - --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \ - --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \ - --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \ - --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \ - --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \ - --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \ - --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \ - --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \ - --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \ - --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \ - --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \ - --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \ - --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \ - --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \ - --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \ - --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \ - --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \ - --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \ - --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \ - --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7 +markdown-it-py==2.2.0 \ + --hash=sha256:5a35f8d1870171d9acc47b99612dc146129b631baf04970128b568f190d0cc30 \ + --hash=sha256:7c9a5e412688bc771c67432cbfebcdd686c93ce6484913dccf06cb5a0bea35a1 + # via rich +markupsafe==2.1.3 \ + --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \ + --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \ + --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \ + --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \ + --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \ + --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \ + --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \ + --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \ + --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \ + --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \ + --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \ + --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \ + --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \ + --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \ + --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \ + --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \ + --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \ + --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \ + --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \ + --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \ + --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \ + --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \ + --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \ + --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \ + --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \ + --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \ + --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \ + --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \ + --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \ + --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \ + --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \ + --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \ + --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \ + --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \ + --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \ + --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \ + --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \ + --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \ + --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \ + --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \ + --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \ + --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \ + --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \ + --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \ + --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \ + --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \ + --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \ + --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \ + --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \ + --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 # via # jinja2 # werkzeug -more-itertools==9.0.0 \ - --hash=sha256:250e83d7e81d0c87ca6bd942e6aeab8cc9daa6096d12c5308f3f92fa5e5c1f41 \ - --hash=sha256:5a6257e40878ef0520b1803990e3e22303a41b5714006c32a3fd8304b26ea1ab +mdurl==0.1.2 \ + --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ + --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba + # via markdown-it-py +more-itertools==9.1.0 \ + --hash=sha256:cabaa341ad0389ea83c17a94566a53ae4c9d07349861ecb14dc6d0345cf9ac5d \ + --hash=sha256:d2bc7f02446e86a68911e58ded76d6561eea00cddfb2a91e7019bbb586c799f3 # via jaraco-classes -msgpack==1.0.4 \ - --hash=sha256:002b5c72b6cd9b4bafd790f364b8480e859b4712e91f43014fe01e4f957b8467 \ - --hash=sha256:0a68d3ac0104e2d3510de90a1091720157c319ceeb90d74f7b5295a6bee51bae \ - --hash=sha256:0df96d6eaf45ceca04b3f3b4b111b86b33785683d682c655063ef8057d61fd92 \ - --hash=sha256:0dfe3947db5fb9ce52aaea6ca28112a170db9eae75adf9339a1aec434dc954ef \ - --hash=sha256:0e3590f9fb9f7fbc36df366267870e77269c03172d086fa76bb4eba8b2b46624 \ - --hash=sha256:11184bc7e56fd74c00ead4f9cc9a3091d62ecb96e97653add7a879a14b003227 \ - --hash=sha256:112b0f93202d7c0fef0b7810d465fde23c746a2d482e1e2de2aafd2ce1492c88 \ - --hash=sha256:1276e8f34e139aeff1c77a3cefb295598b504ac5314d32c8c3d54d24fadb94c9 \ - --hash=sha256:1576bd97527a93c44fa856770197dec00d223b0b9f36ef03f65bac60197cedf8 \ - --hash=sha256:1e91d641d2bfe91ba4c52039adc5bccf27c335356055825c7f88742c8bb900dd \ - --hash=sha256:26b8feaca40a90cbe031b03d82b2898bf560027160d3eae1423f4a67654ec5d6 \ - --hash=sha256:2999623886c5c02deefe156e8f869c3b0aaeba14bfc50aa2486a0415178fce55 \ - --hash=sha256:2a2df1b55a78eb5f5b7d2a4bb221cd8363913830145fad05374a80bf0877cb1e \ - --hash=sha256:2bb8cdf50dd623392fa75525cce44a65a12a00c98e1e37bf0fb08ddce2ff60d2 \ - --hash=sha256:2cc5ca2712ac0003bcb625c96368fd08a0f86bbc1a5578802512d87bc592fe44 \ - --hash=sha256:35bc0faa494b0f1d851fd29129b2575b2e26d41d177caacd4206d81502d4c6a6 \ - --hash=sha256:3c11a48cf5e59026ad7cb0dc29e29a01b5a66a3e333dc11c04f7e991fc5510a9 \ - --hash=sha256:449e57cc1ff18d3b444eb554e44613cffcccb32805d16726a5494038c3b93dab \ - --hash=sha256:462497af5fd4e0edbb1559c352ad84f6c577ffbbb708566a0abaaa84acd9f3ae \ - --hash=sha256:4733359808c56d5d7756628736061c432ded018e7a1dff2d35a02439043321aa \ - --hash=sha256:48f5d88c99f64c456413d74a975bd605a9b0526293218a3b77220a2c15458ba9 \ - --hash=sha256:49565b0e3d7896d9ea71d9095df15b7f75a035c49be733051c34762ca95bbf7e \ - --hash=sha256:4ab251d229d10498e9a2f3b1e68ef64cb393394ec477e3370c457f9430ce9250 \ - --hash=sha256:4d5834a2a48965a349da1c5a79760d94a1a0172fbb5ab6b5b33cbf8447e109ce \ - --hash=sha256:4dea20515f660aa6b7e964433b1808d098dcfcabbebeaaad240d11f909298075 \ - --hash=sha256:545e3cf0cf74f3e48b470f68ed19551ae6f9722814ea969305794645da091236 \ - --hash=sha256:63e29d6e8c9ca22b21846234913c3466b7e4ee6e422f205a2988083de3b08cae \ - --hash=sha256:6916c78f33602ecf0509cc40379271ba0f9ab572b066bd4bdafd7434dee4bc6e \ - --hash=sha256:6a4192b1ab40f8dca3f2877b70e63799d95c62c068c84dc028b40a6cb03ccd0f \ - --hash=sha256:6c9566f2c39ccced0a38d37c26cc3570983b97833c365a6044edef3574a00c08 \ - --hash=sha256:76ee788122de3a68a02ed6f3a16bbcd97bc7c2e39bd4d94be2f1821e7c4a64e6 \ - --hash=sha256:7760f85956c415578c17edb39eed99f9181a48375b0d4a94076d84148cf67b2d \ - --hash=sha256:77ccd2af37f3db0ea59fb280fa2165bf1b096510ba9fe0cc2bf8fa92a22fdb43 \ - --hash=sha256:81fc7ba725464651190b196f3cd848e8553d4d510114a954681fd0b9c479d7e1 \ - --hash=sha256:85f279d88d8e833ec015650fd15ae5eddce0791e1e8a59165318f371158efec6 \ - --hash=sha256:9667bdfdf523c40d2511f0e98a6c9d3603be6b371ae9a238b7ef2dc4e7a427b0 \ - --hash=sha256:a75dfb03f8b06f4ab093dafe3ddcc2d633259e6c3f74bb1b01996f5d8aa5868c \ - --hash=sha256:ac5bd7901487c4a1dd51a8c58f2632b15d838d07ceedaa5e4c080f7190925bff \ - --hash=sha256:aca0f1644d6b5a73eb3e74d4d64d5d8c6c3d577e753a04c9e9c87d07692c58db \ - --hash=sha256:b17be2478b622939e39b816e0aa8242611cc8d3583d1cd8ec31b249f04623243 \ - --hash=sha256:c1683841cd4fa45ac427c18854c3ec3cd9b681694caf5bff04edb9387602d661 \ - --hash=sha256:c23080fdeec4716aede32b4e0ef7e213c7b1093eede9ee010949f2a418ced6ba \ - --hash=sha256:d5b5b962221fa2c5d3a7f8133f9abffc114fe218eb4365e40f17732ade576c8e \ - --hash=sha256:d603de2b8d2ea3f3bcb2efe286849aa7a81531abc52d8454da12f46235092bcb \ - --hash=sha256:e83f80a7fec1a62cf4e6c9a660e39c7f878f603737a0cdac8c13131d11d97f52 \ - --hash=sha256:eb514ad14edf07a1dbe63761fd30f89ae79b42625731e1ccf5e1f1092950eaa6 \ - --hash=sha256:eba96145051ccec0ec86611fe9cf693ce55f2a3ce89c06ed307de0e085730ec1 \ - --hash=sha256:ed6f7b854a823ea44cf94919ba3f727e230da29feb4a99711433f25800cf747f \ - --hash=sha256:f0029245c51fd9473dc1aede1160b0a29f4a912e6b1dd353fa6d317085b219da \ - --hash=sha256:f5d869c18f030202eb412f08b28d2afeea553d6613aee89e200d7aca7ef01f5f \ - --hash=sha256:fb62ea4b62bfcb0b380d5680f9a4b3f9a2d166d9394e9bbd9666c0ee09a3645c \ - --hash=sha256:fcb8a47f43acc113e24e910399376f7277cf8508b27e5b88499f053de6b115a8 +msgpack==1.0.5 \ + --hash=sha256:06f5174b5f8ed0ed919da0e62cbd4ffde676a374aba4020034da05fab67b9164 \ + --hash=sha256:0c05a4a96585525916b109bb85f8cb6511db1c6f5b9d9cbcbc940dc6b4be944b \ + --hash=sha256:137850656634abddfb88236008339fdaba3178f4751b28f270d2ebe77a563b6c \ + --hash=sha256:17358523b85973e5f242ad74aa4712b7ee560715562554aa2134d96e7aa4cbbf \ + --hash=sha256:18334484eafc2b1aa47a6d42427da7fa8f2ab3d60b674120bce7a895a0a85bdd \ + --hash=sha256:1835c84d65f46900920b3708f5ba829fb19b1096c1800ad60bae8418652a951d \ + --hash=sha256:1967f6129fc50a43bfe0951c35acbb729be89a55d849fab7686004da85103f1c \ + --hash=sha256:1ab2f3331cb1b54165976a9d976cb251a83183631c88076613c6c780f0d6e45a \ + --hash=sha256:1c0f7c47f0087ffda62961d425e4407961a7ffd2aa004c81b9c07d9269512f6e \ + --hash=sha256:20a97bf595a232c3ee6d57ddaadd5453d174a52594bf9c21d10407e2a2d9b3bd \ + --hash=sha256:20c784e66b613c7f16f632e7b5e8a1651aa5702463d61394671ba07b2fc9e025 \ + --hash=sha256:266fa4202c0eb94d26822d9bfd7af25d1e2c088927fe8de9033d929dd5ba24c5 \ + --hash=sha256:28592e20bbb1620848256ebc105fc420436af59515793ed27d5c77a217477705 \ + --hash=sha256:288e32b47e67f7b171f86b030e527e302c91bd3f40fd9033483f2cacc37f327a \ + --hash=sha256:3055b0455e45810820db1f29d900bf39466df96ddca11dfa6d074fa47054376d \ + --hash=sha256:332360ff25469c346a1c5e47cbe2a725517919892eda5cfaffe6046656f0b7bb \ + --hash=sha256:362d9655cd369b08fda06b6657a303eb7172d5279997abe094512e919cf74b11 \ + --hash=sha256:366c9a7b9057e1547f4ad51d8facad8b406bab69c7d72c0eb6f529cf76d4b85f \ + --hash=sha256:36961b0568c36027c76e2ae3ca1132e35123dcec0706c4b7992683cc26c1320c \ + --hash=sha256:379026812e49258016dd84ad79ac8446922234d498058ae1d415f04b522d5b2d \ + --hash=sha256:382b2c77589331f2cb80b67cc058c00f225e19827dbc818d700f61513ab47bea \ + --hash=sha256:476a8fe8fae289fdf273d6d2a6cb6e35b5a58541693e8f9f019bfe990a51e4ba \ + --hash=sha256:48296af57cdb1d885843afd73c4656be5c76c0c6328db3440c9601a98f303d87 \ + --hash=sha256:4867aa2df9e2a5fa5f76d7d5565d25ec76e84c106b55509e78c1ede0f152659a \ + --hash=sha256:4c075728a1095efd0634a7dccb06204919a2f67d1893b6aa8e00497258bf926c \ + --hash=sha256:4f837b93669ce4336e24d08286c38761132bc7ab29782727f8557e1eb21b2080 \ + --hash=sha256:4f8d8b3bf1ff2672567d6b5c725a1b347fe838b912772aa8ae2bf70338d5a198 \ + --hash=sha256:525228efd79bb831cf6830a732e2e80bc1b05436b086d4264814b4b2955b2fa9 \ + --hash=sha256:5494ea30d517a3576749cad32fa27f7585c65f5f38309c88c6d137877fa28a5a \ + --hash=sha256:55b56a24893105dc52c1253649b60f475f36b3aa0fc66115bffafb624d7cb30b \ + --hash=sha256:56a62ec00b636583e5cb6ad313bbed36bb7ead5fa3a3e38938503142c72cba4f \ + --hash=sha256:57e1f3528bd95cc44684beda696f74d3aaa8a5e58c816214b9046512240ef437 \ + --hash=sha256:586d0d636f9a628ddc6a17bfd45aa5b5efaf1606d2b60fa5d87b8986326e933f \ + --hash=sha256:5cb47c21a8a65b165ce29f2bec852790cbc04936f502966768e4aae9fa763cb7 \ + --hash=sha256:6c4c68d87497f66f96d50142a2b73b97972130d93677ce930718f68828b382e2 \ + --hash=sha256:821c7e677cc6acf0fd3f7ac664c98803827ae6de594a9f99563e48c5a2f27eb0 \ + --hash=sha256:916723458c25dfb77ff07f4c66aed34e47503b2eb3188b3adbec8d8aa6e00f48 \ + --hash=sha256:9e6ca5d5699bcd89ae605c150aee83b5321f2115695e741b99618f4856c50898 \ + --hash=sha256:9f5ae84c5c8a857ec44dc180a8b0cc08238e021f57abdf51a8182e915e6299f0 \ + --hash=sha256:a2b031c2e9b9af485d5e3c4520f4220d74f4d222a5b8dc8c1a3ab9448ca79c57 \ + --hash=sha256:a61215eac016f391129a013c9e46f3ab308db5f5ec9f25811e811f96962599a8 \ + --hash=sha256:a740fa0e4087a734455f0fc3abf5e746004c9da72fbd541e9b113013c8dc3282 \ + --hash=sha256:a9985b214f33311df47e274eb788a5893a761d025e2b92c723ba4c63936b69b1 \ + --hash=sha256:ab31e908d8424d55601ad7075e471b7d0140d4d3dd3272daf39c5c19d936bd82 \ + --hash=sha256:ac9dd47af78cae935901a9a500104e2dea2e253207c924cc95de149606dc43cc \ + --hash=sha256:addab7e2e1fcc04bd08e4eb631c2a90960c340e40dfc4a5e24d2ff0d5a3b3edb \ + --hash=sha256:b1d46dfe3832660f53b13b925d4e0fa1432b00f5f7210eb3ad3bb9a13c6204a6 \ + --hash=sha256:b2de4c1c0538dcb7010902a2b97f4e00fc4ddf2c8cda9749af0e594d3b7fa3d7 \ + --hash=sha256:b5ef2f015b95f912c2fcab19c36814963b5463f1fb9049846994b007962743e9 \ + --hash=sha256:b72d0698f86e8d9ddf9442bdedec15b71df3598199ba33322d9711a19f08145c \ + --hash=sha256:bae7de2026cbfe3782c8b78b0db9cbfc5455e079f1937cb0ab8d133496ac55e1 \ + --hash=sha256:bf22a83f973b50f9d38e55c6aade04c41ddda19b00c4ebc558930d78eecc64ed \ + --hash=sha256:c075544284eadc5cddc70f4757331d99dcbc16b2bbd4849d15f8aae4cf36d31c \ + --hash=sha256:c396e2cc213d12ce017b686e0f53497f94f8ba2b24799c25d913d46c08ec422c \ + --hash=sha256:cb5aaa8c17760909ec6cb15e744c3ebc2ca8918e727216e79607b7bbce9c8f77 \ + --hash=sha256:cdc793c50be3f01106245a61b739328f7dccc2c648b501e237f0699fe1395b81 \ + --hash=sha256:d25dd59bbbbb996eacf7be6b4ad082ed7eacc4e8f3d2df1ba43822da9bfa122a \ + --hash=sha256:e42b9594cc3bf4d838d67d6ed62b9e59e201862a25e9a157019e171fbe672dd3 \ + --hash=sha256:e57916ef1bd0fee4f21c4600e9d1da352d8816b52a599c46460e93a6e9f17086 \ + --hash=sha256:ed40e926fa2f297e8a653c954b732f125ef97bdd4c889f243182299de27e2aa9 \ + --hash=sha256:ef8108f8dedf204bb7b42994abf93882da1159728a2d4c5e82012edd92c9da9f \ + --hash=sha256:f933bbda5a3ee63b8834179096923b094b76f0c7a73c1cfe8f07ad608c58844b \ + --hash=sha256:fe5c63197c55bce6385d9aee16c4d0641684628f63ace85f73571e65ad1c1e8d # via fluent-logger -mypy==0.991 \ - --hash=sha256:0714258640194d75677e86c786e80ccf294972cc76885d3ebbb560f11db0003d \ - --hash=sha256:0c8f3be99e8a8bd403caa8c03be619544bc2c77a7093685dcf308c6b109426c6 \ - --hash=sha256:0cca5adf694af539aeaa6ac633a7afe9bbd760df9d31be55ab780b77ab5ae8bf \ - --hash=sha256:1c8cd4fb70e8584ca1ed5805cbc7c017a3d1a29fb450621089ffed3e99d1857f \ - --hash=sha256:1f7d1a520373e2272b10796c3ff721ea1a0712288cafaa95931e66aa15798813 \ - --hash=sha256:209ee89fbb0deed518605edddd234af80506aec932ad28d73c08f1400ef80a33 \ - --hash=sha256:26efb2fcc6b67e4d5a55561f39176821d2adf88f2745ddc72751b7890f3194ad \ - --hash=sha256:37bd02ebf9d10e05b00d71302d2c2e6ca333e6c2a8584a98c00e038db8121f05 \ - --hash=sha256:3a700330b567114b673cf8ee7388e949f843b356a73b5ab22dd7cff4742a5297 \ - --hash=sha256:3c0165ba8f354a6d9881809ef29f1a9318a236a6d81c690094c5df32107bde06 \ - --hash=sha256:3d80e36b7d7a9259b740be6d8d906221789b0d836201af4234093cae89ced0cd \ - --hash=sha256:4175593dc25d9da12f7de8de873a33f9b2b8bdb4e827a7cae952e5b1a342e243 \ - --hash=sha256:4307270436fd7694b41f913eb09210faff27ea4979ecbcd849e57d2da2f65305 \ - --hash=sha256:5e80e758243b97b618cdf22004beb09e8a2de1af481382e4d84bc52152d1c476 \ - --hash=sha256:641411733b127c3e0dab94c45af15fea99e4468f99ac88b39efb1ad677da5711 \ - --hash=sha256:652b651d42f155033a1967739788c436491b577b6a44e4c39fb340d0ee7f0d70 \ - --hash=sha256:6d7464bac72a85cb3491c7e92b5b62f3dcccb8af26826257760a552a5e244aa5 \ - --hash=sha256:74e259b5c19f70d35fcc1ad3d56499065c601dfe94ff67ae48b85596b9ec1461 \ - --hash=sha256:7d17e0a9707d0772f4a7b878f04b4fd11f6f5bcb9b3813975a9b13c9332153ab \ - --hash=sha256:901c2c269c616e6cb0998b33d4adbb4a6af0ac4ce5cd078afd7bc95830e62c1c \ - --hash=sha256:98e781cd35c0acf33eb0295e8b9c55cdbef64fcb35f6d3aa2186f289bed6e80d \ - --hash=sha256:a12c56bf73cdab116df96e4ff39610b92a348cc99a1307e1da3c3768bbb5b135 \ - --hash=sha256:ac6e503823143464538efda0e8e356d871557ef60ccd38f8824a4257acc18d93 \ - --hash=sha256:b8472f736a5bfb159a5e36740847808f6f5b659960115ff29c7cecec1741c648 \ - --hash=sha256:b86ce2c1866a748c0f6faca5232059f881cda6dda2a893b9a8373353cfe3715a \ - --hash=sha256:bc9ec663ed6c8f15f4ae9d3c04c989b744436c16d26580eaa760ae9dd5d662eb \ - --hash=sha256:c9166b3f81a10cdf9b49f2d594b21b31adadb3d5e9db9b834866c3258b695be3 \ - --hash=sha256:d13674f3fb73805ba0c45eb6c0c3053d218aa1f7abead6e446d474529aafc372 \ - --hash=sha256:de32edc9b0a7e67c2775e574cb061a537660e51210fbf6006b0b36ea695ae9bb \ - --hash=sha256:e62ebaad93be3ad1a828a11e90f0e76f15449371ffeecca4a0a0b9adc99abcef +mypy==1.3.0 \ + --hash=sha256:1c4c42c60a8103ead4c1c060ac3cdd3ff01e18fddce6f1016e08939647a0e703 \ + --hash=sha256:44797d031a41516fcf5cbfa652265bb994e53e51994c1bd649ffcd0c3a7eccbf \ + --hash=sha256:473117e310febe632ddf10e745a355714e771ffe534f06db40702775056614c4 \ + --hash=sha256:4c99c3ecf223cf2952638da9cd82793d8f3c0c5fa8b6ae2b2d9ed1e1ff51ba85 \ + --hash=sha256:550a8b3a19bb6589679a7c3c31f64312e7ff482a816c96e0cecec9ad3a7564dd \ + --hash=sha256:658fe7b674769a0770d4b26cb4d6f005e88a442fe82446f020be8e5f5efb2fae \ + --hash=sha256:6e33bb8b2613614a33dff70565f4c803f889ebd2f859466e42b46e1df76018dd \ + --hash=sha256:6e42d29e324cdda61daaec2336c42512e59c7c375340bd202efa1fe0f7b8f8ca \ + --hash=sha256:74bc9b6e0e79808bf8678d7678b2ae3736ea72d56eede3820bd3849823e7f305 \ + --hash=sha256:76ec771e2342f1b558c36d49900dfe81d140361dd0d2df6cd71b3db1be155409 \ + --hash=sha256:7d23370d2a6b7a71dc65d1266f9a34e4cde9e8e21511322415db4b26f46f6b8c \ + --hash=sha256:87df44954c31d86df96c8bd6e80dfcd773473e877ac6176a8e29898bfb3501cb \ + --hash=sha256:8c5979d0deb27e0f4479bee18ea0f83732a893e81b78e62e2dda3e7e518c92ee \ + --hash=sha256:95d8d31a7713510685b05fbb18d6ac287a56c8f6554d88c19e73f724a445448a \ + --hash=sha256:a22435632710a4fcf8acf86cbd0d69f68ac389a3892cb23fbad176d1cddaf228 \ + --hash=sha256:a8763e72d5d9574d45ce5881962bc8e9046bf7b375b0abf031f3e6811732a897 \ + --hash=sha256:c1eb485cea53f4f5284e5baf92902cd0088b24984f4209e25981cc359d64448d \ + --hash=sha256:c5d2cc54175bab47011b09688b418db71403aefad07cbcd62d44010543fc143f \ + --hash=sha256:cbc07246253b9e3d7d74c9ff948cd0fd7a71afcc2b77c7f0a59c26e9395cb152 \ + --hash=sha256:d0b6c62206e04061e27009481cb0ec966f7d6172b5b936f3ead3d74f29fe3dcf \ + --hash=sha256:ddae0f39ca146972ff6bb4399f3b2943884a774b8771ea0a8f50e971f5ea5ba8 \ + --hash=sha256:e1f4d16e296f5135624b34e8fb741eb0eadedca90862405b1f1fde2040b9bd11 \ + --hash=sha256:e86c2c6852f62f8f2b24cb7a613ebe8e0c7dc1402c61d36a609174f63e0ff017 \ + --hash=sha256:ebc95f8386314272bbc817026f8ce8f4f0d2ef7ae44f947c4664efac9adec929 \ + --hash=sha256:f9dca1e257d4cc129517779226753dbefb4f2266c4eaad610fc15c6a7e14283e \ + --hash=sha256:faff86aa10c1aa4a10e1a301de160f3d8fc8703b88c7e98de46b531ff1276a9a # via tavern (pyproject.toml) -mypy-extensions==0.4.3 \ - --hash=sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d \ - --hash=sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8 +mypy-extensions==1.0.0 \ + --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \ + --hash=sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782 # via # black # mypy # tavern (pyproject.toml) -nodeenv==1.7.0 \ - --hash=sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e \ - --hash=sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b +nodeenv==1.8.0 \ + --hash=sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2 \ + --hash=sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec # via pre-commit -packaging==22.0 \ - --hash=sha256:2198ec20bd4c017b8f9717e00f0c8714076fc2fd93816750ab48e2c41de2cfd3 \ - --hash=sha256:957e2148ba0e1a3b282772e791ef1d8083648bc131c8ab0c1feba110ce1146c3 +packaging==23.1 \ + --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \ + --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f # via # black # build # docker # pytest # tox -paho-mqtt==1.5.1 \ - --hash=sha256:9feb068e822be7b3a116324e01fb6028eb1d66412bf98595ae72698965cb1cae +paho-mqtt==1.6.1 \ + --hash=sha256:2a8291c81623aec00372b5a85558a372c747cbca8e9934dfe218638b8eefc26f # via tavern (pyproject.toml) -paramiko==2.12.0 \ - --hash=sha256:376885c05c5d6aa6e1f4608aac2a6b5b0548b1add40274477324605903d9cd49 \ - --hash=sha256:b2df1a6325f6996ef55a8789d0462f5b502ea83b3c990cbb5bbe57345c6812c4 +paramiko==3.2.0 \ + --hash=sha256:93cdce625a8a1dc12204439d45033f3261bdb2c201648cfcdc06f9fd0f94ec29 \ + --hash=sha256:df0f9dd8903bc50f2e10580af687f3015bf592a377cd438d2ec9546467a14eb8 # via docker -pathspec==0.10.3 \ - --hash=sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6 \ - --hash=sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6 +pathspec==0.11.1 \ + --hash=sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687 \ + --hash=sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293 # via black -pbr==5.11.0 \ - --hash=sha256:b97bc6695b2aff02144133c2e7399d5885223d42b7912ffaec2ca3898e673bfe \ - --hash=sha256:db2317ff07c84c4c63648c9064a79fe9d9f5c7ce85a9099d4b6258b3db83225a +pbr==5.11.1 \ + --hash=sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b \ + --hash=sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3 # via stevedore -pep517==0.13.0 \ - --hash=sha256:4ba4446d80aed5b5eac6509ade100bff3e7943a8489de249654a5ae9b33ee35b \ - --hash=sha256:ae69927c5c172be1add9203726d4b84cf3ebad1edcd5f71fcdc746e66e829f59 - # via build -pip-tools==6.12.1 \ - --hash=sha256:88efb7b29a923ffeac0713e6f23ef8529cc6175527d42b93f73756cc94387293 \ - --hash=sha256:f0c0c0ec57b58250afce458e2e6058b1f30a4263db895b7d72fd6311bf1dc6f7 +pip-tools==6.13.0 \ + --hash=sha256:50943f151d87e752abddec8158622c34ad7f292e193836e90e30d87da60b19d9 \ + --hash=sha256:61d46bd2eb8016ed4a924e196e6e5b0a268cd3babd79e593048720db23522bb1 # via tavern (pyproject.toml) -pkginfo==1.9.2 \ - --hash=sha256:ac03e37e4d601aaee40f8087f63fc4a2a6c9814dda2c8fa6aab1b1829653bdfa \ - --hash=sha256:d580059503f2f4549ad6e4c106d7437356dbd430e2c7df99ee1efe03d75f691e +pkginfo==1.9.6 \ + --hash=sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546 \ + --hash=sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046 # via twine -platformdirs==2.6.0 \ - --hash=sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca \ - --hash=sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e +platformdirs==3.5.1 \ + --hash=sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f \ + --hash=sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5 # via # black # virtualenv @@ -566,9 +667,9 @@ pluggy==1.0.0 \ # allure-python-commons # pytest # tox -pre-commit==2.20.0 \ - --hash=sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7 \ - --hash=sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959 +pre-commit==3.3.2 \ + --hash=sha256:66e37bec2d882de1f17f88075047ef8962581f83c234ac08da21a0c58953d1f0 \ + --hash=sha256:8056bc52181efadf4aac792b1f4f255dfd2fb5a350ded7335d251a68561e8cb6 # via tavern (pyproject.toml) py==1.11.0 \ --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \ @@ -580,16 +681,16 @@ pycparser==2.21 \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 # via cffi -pygments==2.13.0 \ - --hash=sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1 \ - --hash=sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42 +pygments==2.15.1 \ + --hash=sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c \ + --hash=sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1 # via # readme-renderer # rich # tavern (pyproject.toml) -pyjwt==2.6.0 \ - --hash=sha256:69285c7e31fc44f68a1feb309e948e0df53259d579295e6cfe2b1792329f05fd \ - --hash=sha256:d83c3d892a77bbb74d3e1a2cfa90afaadb60945205d1095d9221f04466f64c14 +pyjwt==2.7.0 \ + --hash=sha256:ba2b425b15ad5ef12f200dc67dd56af4e26de2331f965c5439994dad075876e1 \ + --hash=sha256:bd6ca4a3c4285c1a2d4349e5a035fdf8fb94e04ccd0fcbe6ba289dae9cc3e074 # via tavern (pyproject.toml) pykwalify==1.8.0 \ --hash=sha256:731dfa87338cca9f559d1fca2bdea37299116e3139b73f78ca90a543722d6651 \ @@ -607,45 +708,54 @@ pynacl==1.5.0 \ --hash=sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b \ --hash=sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543 # via paramiko -pyrsistent==0.19.2 \ - --hash=sha256:055ab45d5911d7cae397dc418808d8802fb95262751872c841c170b0dbf51eed \ - --hash=sha256:111156137b2e71f3a9936baf27cb322e8024dac3dc54ec7fb9f0bcf3249e68bb \ - --hash=sha256:187d5730b0507d9285a96fca9716310d572e5464cadd19f22b63a6976254d77a \ - --hash=sha256:21455e2b16000440e896ab99e8304617151981ed40c29e9507ef1c2e4314ee95 \ - --hash=sha256:2aede922a488861de0ad00c7630a6e2d57e8023e4be72d9d7147a9fcd2d30712 \ - --hash=sha256:3ba4134a3ff0fc7ad225b6b457d1309f4698108fb6b35532d015dca8f5abed73 \ - --hash=sha256:456cb30ca8bff00596519f2c53e42c245c09e1a4543945703acd4312949bfd41 \ - --hash=sha256:71d332b0320642b3261e9fee47ab9e65872c2bd90260e5d225dabeed93cbd42b \ - --hash=sha256:879b4c2f4d41585c42df4d7654ddffff1239dc4065bc88b745f0341828b83e78 \ - --hash=sha256:9cd3e9978d12b5d99cbdc727a3022da0430ad007dacf33d0bf554b96427f33ab \ - --hash=sha256:a178209e2df710e3f142cbd05313ba0c5ebed0a55d78d9945ac7a4e09d923308 \ - --hash=sha256:b39725209e06759217d1ac5fcdb510e98670af9e37223985f330b611f62e7425 \ - --hash=sha256:bfa0351be89c9fcbcb8c9879b826f4353be10f58f8a677efab0c017bf7137ec2 \ - --hash=sha256:bfd880614c6237243ff53a0539f1cb26987a6dc8ac6e66e0c5a40617296a045e \ - --hash=sha256:c43bec251bbd10e3cb58ced80609c5c1eb238da9ca78b964aea410fb820d00d6 \ - --hash=sha256:d690b18ac4b3e3cab73b0b7aa7dbe65978a172ff94970ff98d82f2031f8971c2 \ - --hash=sha256:d6982b5a0237e1b7d876b60265564648a69b14017f3b5f908c5be2de3f9abb7a \ - --hash=sha256:dec3eac7549869365fe263831f576c8457f6c833937c68542d08fde73457d291 \ - --hash=sha256:e371b844cec09d8dc424d940e54bba8f67a03ebea20ff7b7b0d56f526c71d584 \ - --hash=sha256:e5d8f84d81e3729c3b506657dddfe46e8ba9c330bf1858ee33108f8bb2adb38a \ - --hash=sha256:ea6b79a02a28550c98b6ca9c35b9f492beaa54d7c5c9e9949555893c8a9234d0 \ - --hash=sha256:f1258f4e6c42ad0b20f9cfcc3ada5bd6b83374516cd01c0960e3cb75fdca6770 +pyproject-hooks==1.0.0 \ + --hash=sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8 \ + --hash=sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5 + # via build +pyrsistent==0.19.3 \ + --hash=sha256:016ad1afadf318eb7911baa24b049909f7f3bb2c5b1ed7b6a8f21db21ea3faa8 \ + --hash=sha256:1a2994773706bbb4995c31a97bc94f1418314923bd1048c6d964837040376440 \ + --hash=sha256:20460ac0ea439a3e79caa1dbd560344b64ed75e85d8703943e0b66c2a6150e4a \ + --hash=sha256:3311cb4237a341aa52ab8448c27e3a9931e2ee09561ad150ba94e4cfd3fc888c \ + --hash=sha256:3a8cb235fa6d3fd7aae6a4f1429bbb1fec1577d978098da1252f0489937786f3 \ + --hash=sha256:3ab2204234c0ecd8b9368dbd6a53e83c3d4f3cab10ecaf6d0e772f456c442393 \ + --hash=sha256:42ac0b2f44607eb92ae88609eda931a4f0dfa03038c44c772e07f43e738bcac9 \ + --hash=sha256:49c32f216c17148695ca0e02a5c521e28a4ee6c5089f97e34fe24163113722da \ + --hash=sha256:4b774f9288dda8d425adb6544e5903f1fb6c273ab3128a355c6b972b7df39dcf \ + --hash=sha256:4c18264cb84b5e68e7085a43723f9e4c1fd1d935ab240ce02c0324a8e01ccb64 \ + --hash=sha256:5a474fb80f5e0d6c9394d8db0fc19e90fa540b82ee52dba7d246a7791712f74a \ + --hash=sha256:64220c429e42a7150f4bfd280f6f4bb2850f95956bde93c6fda1b70507af6ef3 \ + --hash=sha256:878433581fc23e906d947a6814336eee031a00e6defba224234169ae3d3d6a98 \ + --hash=sha256:99abb85579e2165bd8522f0c0138864da97847875ecbd45f3e7e2af569bfc6f2 \ + --hash=sha256:a2471f3f8693101975b1ff85ffd19bb7ca7dd7c38f8a81701f67d6b4f97b87d8 \ + --hash=sha256:aeda827381f5e5d65cced3024126529ddc4289d944f75e090572c77ceb19adbf \ + --hash=sha256:b735e538f74ec31378f5a1e3886a26d2ca6351106b4dfde376a26fc32a044edc \ + --hash=sha256:c147257a92374fde8498491f53ffa8f4822cd70c0d85037e09028e478cababb7 \ + --hash=sha256:c4db1bd596fefd66b296a3d5d943c94f4fac5bcd13e99bffe2ba6a759d959a28 \ + --hash=sha256:c74bed51f9b41c48366a286395c67f4e894374306b197e62810e0fdaf2364da2 \ + --hash=sha256:c9bb60a40a0ab9aba40a59f68214eed5a29c6274c83b2cc206a359c4a89fa41b \ + --hash=sha256:cc5d149f31706762c1f8bda2e8c4f8fead6e80312e3692619a75301d3dbb819a \ + --hash=sha256:ccf0d6bd208f8111179f0c26fdf84ed7c3891982f2edaeae7422575f47e66b64 \ + --hash=sha256:e42296a09e83028b3476f7073fcb69ffebac0e66dbbfd1bd847d61f74db30f19 \ + --hash=sha256:e8f2b814a3dc6225964fa03d8582c6e0b6650d68a232df41e3cc1b66a5d2f8d1 \ + --hash=sha256:f0774bf48631f3a20471dd7c5989657b639fd2d285b861237ea9e82c36a415a9 \ + --hash=sha256:f0e7c4b2f77593871e918be000b96c8107da48444d57005b6a6bc61fb4331b2c # via jsonschema -pytest==7.2.0 \ - --hash=sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71 \ - --hash=sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59 +pytest==7.2.2 \ + --hash=sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e \ + --hash=sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4 # via # allure-pytest # pytest-cov # pytest-xdist # tavern (pyproject.toml) -pytest-cov==4.0.0 \ - --hash=sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b \ - --hash=sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470 +pytest-cov==4.1.0 \ + --hash=sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6 \ + --hash=sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a # via tavern (pyproject.toml) -pytest-xdist==3.1.0 \ - --hash=sha256:40fdb8f3544921c5dfcd486ac080ce22870e71d82ced6d2e78fa97c2addd480c \ - --hash=sha256:70a76f191d8a1d2d6be69fc440cdf85f3e4c03c08b520fd5dc5d338d6cf07d89 +pytest-xdist==3.3.1 \ + --hash=sha256:d5ee0520eb1b7bcca50a60a518ab7a7707992812c578198f8b44fdfac78e8c93 \ + --hash=sha256:ff9daa7793569e6a68544850fd3927cd257cc03a7ef76c95e86915355e82b5f2 # via tavern (pyproject.toml) python-box==6.1.0 \ --hash=sha256:11cbe62f0dace8a6e2a10d210a5e87b99ad1a1286865568862516794c923a988 \ @@ -672,9 +782,9 @@ python-dateutil==2.8.2 \ # via # faker # pykwalify -python-dotenv==0.21.0 \ - --hash=sha256:1684eb44636dd462b66c3ee016599815514527ad99965de77f43e0944634a7e5 \ - --hash=sha256:b77d08274639e3d34145dfa6c7008e66df0f04b7be7a75fd0d5292c191d79045 +python-dotenv==0.21.1 \ + --hash=sha256:1c93de8f636cde3ce377292818d0e440b6e45a82f215c3744979151fa8151c49 \ + --hash=sha256:41e12e0318bebc859fcc4d97d4db8d20ad21721a6aa5047dd59f090391cb549a # via docker-compose pyyaml==5.4.1 \ --hash=sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf \ @@ -724,26 +834,27 @@ requests==2.31.0 \ # requests-toolbelt # tavern (pyproject.toml) # twine -requests-toolbelt==0.10.1 \ - --hash=sha256:18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7 \ - --hash=sha256:62e09f7ff5ccbda92772a29f394a49c3ad6cb181d568b1337626b2abb628a63d +requests-toolbelt==1.0.0 \ + --hash=sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6 \ + --hash=sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06 # via twine rfc3986==2.0.0 \ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c # via twine -rich==12.6.0 \ - --hash=sha256:a4eb26484f2c82589bd9a17c73d32a010b1e29d89f1604cd9bf3a2097b81bb5e \ - --hash=sha256:ba3a3775974105c221d31141f2c116f4fd65c5ceb0698657a11e9f295ec93fd0 +rich==13.4.1 \ + --hash=sha256:76f6b65ea7e5c5d924ba80e322231d7cb5b5981aa60bfc1e694f1bc097fe6fe1 \ + --hash=sha256:d204aadb50b936bf6b1a695385429d192bc1fdaf3e8b907e8e26f4c4e4b5bf75 # via twine -ruamel-yaml==0.17.21 \ - --hash=sha256:742b35d3d665023981bd6d16b3d24248ce5df75fdb4e2924e93a05c1f8b61ca7 \ - --hash=sha256:8b7ce697a2f212752a35c1ac414471dc16c424c9573be4926b56ff3f5d23b7af +ruamel-yaml==0.17.31 \ + --hash=sha256:098ed1eb6d338a684891a72380277c1e6fc4d4ae0e120de9a447275056dda335 \ + --hash=sha256:3cf153f0047ced526e723097ac615d3009371779432e304dbd5596b6f3a4c777 # via pykwalify ruamel-yaml-clib==0.2.7 \ --hash=sha256:045e0626baf1c52e5527bd5db361bc83180faaba2ff586e763d3d5982a876a9e \ --hash=sha256:15910ef4f3e537eea7fe45f8a5d19997479940d9196f357152a09031c5be59f3 \ --hash=sha256:184faeaec61dbaa3cace407cffc5819f7b977e75360e8d5ca19461cd851a5fc5 \ + --hash=sha256:1a6391a7cabb7641c32517539ca42cf84b87b667bad38b78d4d42dd23e957c81 \ --hash=sha256:1f08fd5a2bea9c4180db71678e850b995d2a5f4537be0e94557668cf0f5f9497 \ --hash=sha256:2aa261c29a5545adfef9296b7e33941f46aa5bbd21164228e833412af4c9c75f \ --hash=sha256:3110a99e0f94a4a3470ff67fc20d3f96c25b13d24c6980ff841e82bafe827cac \ @@ -754,13 +865,13 @@ ruamel-yaml-clib==0.2.7 \ --hash=sha256:4a4d8d417868d68b979076a9be6a38c676eca060785abaa6709c7b31593c35d1 \ --hash=sha256:4b3a93bb9bc662fc1f99c5c3ea8e623d8b23ad22f861eb6fce9377ac07ad6072 \ --hash=sha256:5bc0667c1eb8f83a3752b71b9c4ba55ef7c7058ae57022dd9b29065186a113d9 \ - --hash=sha256:721bc4ba4525f53f6a611ec0967bdcee61b31df5a56801281027a3a6d1c2daf5 \ --hash=sha256:763d65baa3b952479c4e972669f679fe490eee058d5aa85da483ebae2009d231 \ --hash=sha256:7bdb4c06b063f6fd55e472e201317a3bb6cdeeee5d5a38512ea5c01e1acbdd93 \ --hash=sha256:8831a2cedcd0f0927f788c5bdf6567d9dc9cc235646a434986a852af1cb54b4b \ --hash=sha256:91a789b4aa0097b78c93e3dc4b40040ba55bef518f84a40d4442f713b4094acb \ --hash=sha256:92460ce908546ab69770b2e576e4f99fbb4ce6ab4b245345a3869a0a0410488f \ --hash=sha256:99e77daab5d13a48a4054803d052ff40780278240a902b880dd37a51ba01a307 \ + --hash=sha256:9c7617df90c1365638916b98cdd9be833d31d337dbcd722485597b43c4a215bf \ --hash=sha256:a234a20ae07e8469da311e182e70ef6b199d0fbeb6c6cc2901204dd87fb867e8 \ --hash=sha256:a7b301ff08055d73223058b5c46c55638917f04d21577c95e00e0c4d79201a6b \ --hash=sha256:be2a7ad8fd8f7442b24323d24ba0b56c51219513cfa45b9ada3b87b76c374d4b \ @@ -769,30 +880,33 @@ ruamel-yaml-clib==0.2.7 \ --hash=sha256:d000f258cf42fec2b1bbf2863c61d7b8918d31ffee905da62dede869254d3b8a \ --hash=sha256:d5859983f26d8cd7bb5c287ef452e8aacc86501487634573d260968f753e1d71 \ --hash=sha256:d5e51e2901ec2366b79f16c2299a03e74ba4531ddcfacc1416639c557aef0ad8 \ + --hash=sha256:da538167284de58a52109a9b89b8f6a53ff8437dd6dc26d33b57bf6699153122 \ --hash=sha256:debc87a9516b237d0466a711b18b6ebeb17ba9f391eb7f91c649c5c4ec5006c7 \ --hash=sha256:df5828871e6648db72d1c19b4bd24819b80a755c4541d3409f0f7acd0f335c80 \ --hash=sha256:ecdf1a604009bd35c674b9225a8fa609e0282d9b896c03dd441a91e5f53b534e \ --hash=sha256:efa08d63ef03d079dcae1dfe334f6c8847ba8b645d08df286358b1f5293d24ab \ --hash=sha256:f01da5790e95815eb5a8a138508c01c758e5f5bc0ce4286c4f7028b8dd7ac3d0 \ - --hash=sha256:f34019dced51047d6f70cb9383b2ae2853b7fc4dce65129a5acd49f4f9256646 + --hash=sha256:f34019dced51047d6f70cb9383b2ae2853b7fc4dce65129a5acd49f4f9256646 \ + --hash=sha256:f6d3d39611ac2e4f62c3128a9eed45f19a6608670c5a2f4f07f24e8de3441d38 # via ruamel-yaml -ruff==0.0.246 \ - --hash=sha256:2474a805c4244cfaf0390a745a0c5ea9e5452f52fbce0be74930fece8bd40b90 \ - --hash=sha256:449e6632c13902df06ac14ccfc7bad71841ab90bfa64e8cb3f1a2ea91e647df0 \ - --hash=sha256:45cde6f9df94fb393ffeeada2daca279569b9d53d1d95d49b9b5b418fe70bd23 \ - --hash=sha256:468f282e26d1845f4a06dcd76fdc355f4288208e6b97f061951a7ffd6725102e \ - --hash=sha256:529a7d72f48331b97367cd6d42273f3cafa764d9373e74b75561367135958546 \ - --hash=sha256:5839a213a90220845693c95d7e6a19ab26751b9e37047ef8f4a58dc49230c817 \ - --hash=sha256:589aff453085cad28b8d1f517161a6b37a6d359cda419f64c009e0f7ff424d72 \ - --hash=sha256:64af553f8ff4d1f51a24104ac8f81b5ce6df9c230d776fa4dd22db96699efdb0 \ - --hash=sha256:67d5fa9abdcb764a7cee242fb65e303662c9cb80104a2dd0657e96fca8a7c6d8 \ - --hash=sha256:734ff8fef2e7105cf6946e525b3e8cbed035edc9d58c4f47aac7205dbd1e55c0 \ - --hash=sha256:8173a00766b88b47431e8e744f577d06c6c52c0e18181ac29a701a9d5c035b39 \ - --hash=sha256:ca7d1ee44144460ae119a6212aaff77a671a5729d543b981c786c052011cdfe3 \ - --hash=sha256:dd4f58b9295615ebb01563a38a5594fcb4664bb6106b2ccd00b90c0f1d14cf8c \ - --hash=sha256:ebe6052bc87ee51d84af231ccd27e5338fdc30d8bf49e51bdcfceb44c51c5625 \ - --hash=sha256:f6004332134580f0ede29d86a9a16102ba07c25799e0ab9683359216a419366b \ - --hash=sha256:f8403e31e64b15c9b3e2745b0400e2f43eea81493ae0fa85e275ed0800a89c19 +ruff==0.0.270 \ + --hash=sha256:0012f9b7dc137ab7f1f0355e3c4ca49b562baf6c9fa1180948deeb6648c52957 \ + --hash=sha256:08188f8351f4c0b6216e8463df0a76eb57894ca59a3da65e4ed205db980fd3ae \ + --hash=sha256:0827b074635d37984fc98d99316bfab5c8b1231bb83e60dacc83bd92883eedb4 \ + --hash=sha256:0bbfbf6fd2436165566ca85f6e57be03ed2f0a994faf40180cfbb3604c9232ef \ + --hash=sha256:0d61ae4841313f6eeb8292dc349bef27b4ce426e62c36e80ceedc3824e408734 \ + --hash=sha256:0eb412f20e77529a01fb94d578b19dcb8331b56f93632aa0cce4a2ea27b7aeba \ + --hash=sha256:21f00e47ab2308617c44435c8dfd9e2e03897461c9e647ec942deb2a235b4cfd \ + --hash=sha256:3ed3b198768d2b3a2300fb18f730cd39948a5cc36ba29ae9d4639a11040880be \ + --hash=sha256:643de865fd35cb76c4f0739aea5afe7b8e4d40d623df7e9e6ea99054e5cead0a \ + --hash=sha256:739495d2dbde87cf4e3110c8d27bc20febf93112539a968a4e02c26f0deccd1d \ + --hash=sha256:8af391ef81f7be960be10886a3c1aac0b298bde7cb9a86ec2b05faeb2081ce6b \ + --hash=sha256:95db07b7850b30ebf32b27fe98bc39e0ab99db3985edbbf0754d399eb2f0e690 \ + --hash=sha256:9613456b0b375766244c25045e353bc8890c856431cd97893c97b10cc93bd28d \ + --hash=sha256:b4c037fe2f75bcd9aed0c89c7c507cb7fa59abae2bd4c8b6fc331a28178655a4 \ + --hash=sha256:b775e2c5fc869359daf8c8b8aa0fd67240201ab2e8d536d14a0edf279af18786 \ + --hash=sha256:eca02e709b3308eb7255b5f74e779be23b5980fca3862eae28bb23069cd61ae4 \ + --hash=sha256:f74c4d550f7b8e808455ac77bbce38daafc458434815ba0bc21ae4bdb276509b # via tavern (pyproject.toml) secretstorage==3.3.3 \ --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ @@ -802,12 +916,9 @@ six==1.16.0 \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 # via - # allure-pytest - # allure-python-commons # bleach # dockerpty # jsonschema - # paramiko # python-dateutil # tox # websocket-client @@ -819,10 +930,6 @@ texttable==1.6.7 \ --hash=sha256:290348fb67f7746931bcdfd55ac7584ecd4e5b0846ab164333f0794b121760f2 \ --hash=sha256:b7b68139aa8a6339d2c320ca8b1dc42d13a7831a346b446cb9eb385f0c76310c # via docker-compose -toml==0.10.2 \ - --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ - --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f - # via pre-commit tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f @@ -831,7 +938,7 @@ tomli==2.0.1 \ # build # coverage # mypy - # pep517 + # pyproject-hooks # pytest # tox tomli-w==1.0.0 \ @@ -844,21 +951,21 @@ tox==3.28.0 \ # via # tavern (pyproject.toml) # tox-travis -tox-travis==0.12 \ - --hash=sha256:442c96b078333c94e272d0e90e4582e35e0529ea98bcd2f7f96053d690c4e7a4 \ - --hash=sha256:465cd8f71ad878962a3fce0e9e2e213994e0ae4e0c30f87fe6af1b04ea282dc4 +tox-travis==0.13 \ + --hash=sha256:3e1e4868d108748012f78cd0bd64f05b5a12b33809d6721a0b35cfb00986e55e \ + --hash=sha256:71fa355d84d32b592428ac8016f669a7c63e459fa42774a33d60072d3d7371dc # via tavern (pyproject.toml) twine==4.0.2 \ --hash=sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8 \ --hash=sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8 # via tavern (pyproject.toml) -types-pyyaml==6.0.12.2 \ - --hash=sha256:1e94e80aafee07a7e798addb2a320e32956a373f376655128ae20637adb2655b \ - --hash=sha256:6840819871c92deebe6a2067fb800c11b8a063632eb4e3e755914e7ab3604e83 +types-pyyaml==6.0.12.10 \ + --hash=sha256:662fa444963eff9b68120d70cda1af5a5f2aa57900003c2006d7626450eaae5f \ + --hash=sha256:ebab3d0700b946553724ae6ca636ea932c1b0868701d4af121630e78d695fc97 # via tavern (pyproject.toml) -types-requests==2.31.0.0 \ - --hash=sha256:7c5cea7940f8e92ec560bbc468f65bf684aa3dcf0554a6f8c4710f5f708dc598 \ - --hash=sha256:c1c29d20ab8d84dff468d7febfe8e0cb0b4664543221b386605e14672b44ea25 +types-requests==2.31.0.1 \ + --hash=sha256:3de667cffa123ce698591de0ad7db034a5317457a596eb0b4944e5a9d9e8d1ac \ + --hash=sha256:afb06ef8f25ba83d59a1d424bd7a5a939082f94b94e90ab5e6116bd2559deaa3 # via tavern (pyproject.toml) types-setuptools==67.8.0.0 \ --hash=sha256:6df73340d96b238a4188b7b7668814b37e8018168aef1eef94a3b1872e3f60ff \ @@ -868,20 +975,20 @@ types-urllib3==1.26.25.13 \ --hash=sha256:3300538c9dc11dad32eae4827ac313f5d986b8b21494801f1bf97a1ac6c03ae5 \ --hash=sha256:5dbd1d2bef14efee43f5318b5d36d805a489f6600252bb53626d4bfafd95e27c # via types-requests -typing-extensions==4.4.0 \ - --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ - --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e +typing-extensions==4.6.3 \ + --hash=sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26 \ + --hash=sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5 # via mypy -urllib3==1.26.13 \ - --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc \ - --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8 +urllib3==2.0.2 \ + --hash=sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc \ + --hash=sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e # via # docker # requests # twine -virtualenv==20.17.1 \ - --hash=sha256:ce3b1684d6e1a20a3e5ed36795a97dfc6af29bc3970ca8dab93e11ac6094b3c4 \ - --hash=sha256:f8b927684efc6f1cc206c9db297a570ab9ad0e51c16fa9e45487d36d1905c058 +virtualenv==20.23.0 \ + --hash=sha256:6abec7670e5802a528357fdc75b26b9f57d5d92f29c5462ba0fbe45feacc685e \ + --hash=sha256:a85caa554ced0c0afbd0d638e7e2d7b5f92d23478d05d17a76daeac8f279f924 # via # pre-commit # tox @@ -895,19 +1002,19 @@ websocket-client==0.59.0 \ # via # docker # docker-compose -werkzeug==2.2.3 \ - --hash=sha256:2e1ccc9417d4da358b9de6f174e3ac094391ea1d4fbef2d667865d819dfd0afe \ - --hash=sha256:56433961bc1f12533306c624f3be5e744389ac61d722175d543e1751285da612 +werkzeug==2.3.4 \ + --hash=sha256:1d5a58e0377d1fe39d061a5de4469e414e78ccb1e1e59c0f5ad6fa1c36c52b76 \ + --hash=sha256:48e5e61472fee0ddee27ebad085614ebedb7af41e88f687aaf881afb723a162f # via flask -wheel==0.38.4 \ - --hash=sha256:965f5259b566725405b05e7cf774052044b1ed30119b5d586b2703aafe8719ac \ - --hash=sha256:b60533f3f5d530e971d6737ca6d58681ee434818fab630c83a734bb10c083ce8 +wheel==0.40.0 \ + --hash=sha256:cd1196f3faee2b31968d626e1731c94f99cbdb67cf5a46e4f5656cbee7738873 \ + --hash=sha256:d236b20e7cb522daf2390fa84c55eea81c5c30190f90f29ae2ca1ad8355bf247 # via # pip-tools # tavern (pyproject.toml) -zipp==3.11.0 \ - --hash=sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa \ - --hash=sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766 +zipp==3.15.0 \ + --hash=sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b \ + --hash=sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556 # via importlib-metadata # WARNING: The following packages were not pinned, but pip requires them to be diff --git a/tavern/_core/loader.py b/tavern/_core/loader.py index 1c33cef3..7104fbe5 100644 --- a/tavern/_core/loader.py +++ b/tavern/_core/loader.py @@ -445,7 +445,7 @@ def load_single_document_yaml(filename: os.PathLike) -> dict: with open(filename, "r", encoding="utf-8") as fileobj: try: - contents = yaml.load(fileobj, Loader=IncludeLoader) # noqa + contents = yaml.load(fileobj, Loader=IncludeLoader) # type:ignore # noqa except yaml.composer.ComposerError as e: msg = "Expected only one document in this file but found multiple" raise exceptions.UnexpectedDocumentsError(msg) from e diff --git a/tavern/_core/pytest/file.py b/tavern/_core/pytest/file.py index 0733cb01..b014a58f 100644 --- a/tavern/_core/pytest/file.py +++ b/tavern/_core/pytest/file.py @@ -347,7 +347,10 @@ def collect(self) -> Iterator[YamlItem]: try: # Convert to a list so we can catch parser exceptions all_tests = list( - yaml.load_all(self.path.open(encoding="utf-8"), Loader=IncludeLoader) + yaml.load_all( + self.path.open(encoding="utf-8"), + Loader=IncludeLoader, # type:ignore + ) ) except yaml.parser.ParserError as e: raise exceptions.BadSchemaError from e diff --git a/tavern/_core/schema/extensions.py b/tavern/_core/schema/extensions.py index ca352be0..98ec55c8 100644 --- a/tavern/_core/schema/extensions.py +++ b/tavern/_core/schema/extensions.py @@ -138,7 +138,7 @@ def verify_oneof_id_name(value, rule_obj, path) -> bool: name = value.get("name") if not name: - if name == "": + if name == "": # noqa raise BadSchemaError("Name cannot be empty") if not value.get("id"): diff --git a/tavern/_plugins/mqtt/response.py b/tavern/_plugins/mqtt/response.py index 74bc7ca9..5322cdf5 100644 --- a/tavern/_plugins/mqtt/response.py +++ b/tavern/_plugins/mqtt/response.py @@ -270,7 +270,7 @@ def addwarning(w, *args, **kwargs): return False if self.expected_payload is None: - if msg.payload is None or msg.payload == "": + if msg.payload is None or msg.payload == "": # noqa logger.info("Got message with no payload (as expected) on '%s'", topic) return True else: diff --git a/tavern/_plugins/rest/request.py b/tavern/_plugins/rest/request.py index e7ffe752..7a4205bf 100644 --- a/tavern/_plugins/rest/request.py +++ b/tavern/_plugins/rest/request.py @@ -196,7 +196,7 @@ def add_request_args(keys, optional): # https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods if request_args["method"] in ["GET", "HEAD", "OPTIONS"]: if any(i in request_args for i in ["json", "data"]): - warnings.warn( + warnings.warn( # noqa "You are trying to send a body with a HTTP verb that has no semantic use for it", RuntimeWarning, ) diff --git a/tavern/_plugins/rest/response.py b/tavern/_plugins/rest/response.py index ca54b116..d14c1a30 100644 --- a/tavern/_plugins/rest/response.py +++ b/tavern/_plugins/rest/response.py @@ -105,21 +105,18 @@ def _check_status_code(self, status_code, body) -> None: "Status code '%s' matched expected '%s'", status_code, expected_code ) return + elif 400 <= status_code < 500: + # special case if there was a bad request. This assumes that the + # response would contain some kind of information as to why this + # request was rejected. + self._adderr( + "Status code was %s, expected %s:\n%s", + status_code, + expected_code, + indent_err_text(json.dumps(body)), + ) else: - if 400 <= status_code < 500: - # special case if there was a bad request. This assumes that the - # response would contain some kind of information as to why this - # request was rejected. - self._adderr( - "Status code was %s, expected %s:\n%s", - status_code, - expected_code, - indent_err_text(json.dumps(body)), - ) - else: - self._adderr( - "Status code was %s, expected %s", status_code, expected_code - ) + self._adderr("Status code was %s, expected %s", status_code, expected_code) def verify(self, response: requests.Response) -> dict: """Verify response against expected values and returns any values that From 463099f98aa44332ce2254abd0daac06a877673e Mon Sep 17 00:00:00 2001 From: michaelboulton Date: Sun, 25 Jun 2023 18:41:19 +0100 Subject: [PATCH 06/25] Do not run minimal test in CI (#874) This has started returning a 403 --- tests/integration/test_minimal.tavern.yaml | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 tests/integration/test_minimal.tavern.yaml diff --git a/tests/integration/test_minimal.tavern.yaml b/tests/integration/test_minimal.tavern.yaml deleted file mode 100644 index f66d3314..00000000 --- a/tests/integration/test_minimal.tavern.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -# Every test file has one or more tests... -test_name: Get some fake data from the JSON placeholder API - -# ...and each test has one or more stages (e.g. an HTTP request) -stages: - - name: Make sure we have the right ID - - # Define the request to be made... - request: - url: https://jsonplaceholder.typicode.com/posts/1 - method: GET - - # ...and the expected response code and body - response: - status_code: 200 - json: - id: 1 - userId: 1 - title: "sunt aut facere repellat provident occaecati excepturi optio reprehenderit" - body: "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" From 93188d10524131291592baeccda105e600554a27 Mon Sep 17 00:00:00 2001 From: Jacob Brunson Date: Sun, 25 Jun 2023 11:50:24 -0600 Subject: [PATCH 07/25] Responses with MQTT wildcarded topics. (#873) --- example/mqtt/test_mqtt.tavern.yaml | 25 +++++++++++++++++++++++++ tavern/_plugins/mqtt/client.py | 28 ++++++++++------------------ 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/example/mqtt/test_mqtt.tavern.yaml b/example/mqtt/test_mqtt.tavern.yaml index f3b6929a..b3d57b31 100644 --- a/example/mqtt/test_mqtt.tavern.yaml +++ b/example/mqtt/test_mqtt.tavern.yaml @@ -68,6 +68,31 @@ stages: --- +test_name: Test mqtt wildcard subscription + +includes: + - !include common.yaml + + +paho-mqtt: *mqtt_spec + +stages: + - *setup_device_for_test + + - name: Echo json + mqtt_publish: + topic: /device/{random_device_id}/echo + json: + message: hello world + mqtt_response: + topic: /device/+/echo/response + json: + message: hello world + timeout: 5 + qos: 1 + +--- + test_name: Test mqtt message echo json formatted topic name marks: diff --git a/tavern/_plugins/mqtt/client.py b/tavern/_plugins/mqtt/client.py index 49c73c56..84afacec 100644 --- a/tavern/_plugins/mqtt/client.py +++ b/tavern/_plugins/mqtt/client.py @@ -36,10 +36,6 @@ logger = logging.getLogger(__name__) -def root_topic(topic): - return topic.split("+")[0].split("#")[0] - - @dataclasses.dataclass class _Subscription: topic: str @@ -304,16 +300,15 @@ def _on_message(client, userdata, message) -> None: logger.info("Received mqtt message on %s", message.topic) - sanitised = root_topic(message.topic) - try: - userdata["_subscribed"][ - userdata["_subscription_mappings"][sanitised] - ].queue.put(message) - except KeyError as e: - raise exceptions.MQTTTopicException( - "Message received on unregistered topic: {}".format(message.topic) - ) from e + for sub_topic, sub_id in userdata["_subscription_mappings"].items(): + if paho.topic_matches_sub(sub_topic, message.topic): + userdata["_subscribed"][sub_id].queue.put(message) + break + else: + raise exceptions.MQTTTopicException( + "Message received on unregistered topic: {}".format(message.topic) + ) except Full: logger.exception("message queue full") @@ -369,11 +364,9 @@ def message_received(self, topic: str, timeout: int = 1): Allow regexes for topic names? Better validation for mqtt payloads """ - sanitised = root_topic(topic) - try: with self._subscribe_lock: - queue = self._subscribed[self._subscription_mappings[sanitised]].queue + queue = self._subscribed[self._subscription_mappings[topic]].queue except KeyError as e: raise exceptions.MQTTTopicException( "Unregistered topic: {}".format(topic) @@ -457,9 +450,8 @@ def subscribe(self, topic: str, *args, **kwargs) -> None: (status, mid) = self._client.subscribe(topic, *args, **kwargs) if status == 0: - sanitised = root_topic(topic) with self._subscribe_lock: - self._subscription_mappings[sanitised] = mid + self._subscription_mappings[topic] = mid self._subscribed[mid] = _Subscription(topic) else: raise exceptions.MQTTError( From 97918f6ca107eecb0e6201238fac365a4fee72aa Mon Sep 17 00:00:00 2001 From: Michael Boulton Date: Sun, 25 Jun 2023 18:56:47 +0100 Subject: [PATCH 08/25] Bump to 2.2.0 --- CHANGELOG.md | 2 ++ docs/source/conf.py | 2 +- pyproject.toml | 4 ++-- tavern/__init__.py | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bfd9284..a0a25181 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -406,3 +406,5 @@ This is technically not a operational change but I'm adding a new tag so it can ## 2.0.6 Fix a few small MQTT issues (2023-03-13) ## 2.0.7 Lock pytest to <7.3 to fix issue with marks (2023-04-15) + +# 2.1.0 Allow multi part file uploads with the same form field name (2023-06-04) diff --git a/docs/source/conf.py b/docs/source/conf.py index 80c2ada6..df7bb272 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -73,7 +73,7 @@ # The short X.Y version. version = "1.0" # The full version, including alpha/beta/rc tags. -release = "2.1.0" +release = "2.2.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index fd4ef5b5..29ed5443 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ keywords = ["testing", "pytest"] name = "tavern" description = "Simple testing of RESTful APIs" -version = "2.1.0" +version = "2.2.0" dependencies = [ "PyYAML>=5.3.1,<7", @@ -162,7 +162,7 @@ target-version = "py38" known-first-party = ["tavern"] [tool.tbump.version] -current = "2.1.0" +current = "2.2.0" regex = ''' (?P\d+) diff --git a/tavern/__init__.py b/tavern/__init__.py index c6b12cd3..b009ae71 100644 --- a/tavern/__init__.py +++ b/tavern/__init__.py @@ -1,2 +1,2 @@ """Stop pytest warning about module already imported: PYTEST_DONT_REWRITE""" -__version__ = "2.1.0" +__version__ = "2.2.0" From f3d818d112064f6d952204c5f22321e1f29b7def Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 30 Jul 2023 18:15:16 +0100 Subject: [PATCH 09/25] Bump cryptography from 41.0.1 to 41.0.2 (#876) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- constraints.txt | 2 +- requirements.txt | 44 ++++++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/constraints.txt b/constraints.txt index e4e1d2e7..8606cd67 100644 --- a/constraints.txt +++ b/constraints.txt @@ -46,7 +46,7 @@ coverage==7.2.7 # via # pytest-cov # tavern (pyproject.toml) -cryptography==41.0.1 +cryptography==41.0.2 # via # paramiko # secretstorage diff --git a/requirements.txt b/requirements.txt index ced87e5d..666d4d46 100644 --- a/requirements.txt +++ b/requirements.txt @@ -313,26 +313,30 @@ coverage[toml]==7.2.7 \ # via # pytest-cov # tavern (pyproject.toml) -cryptography==41.0.1 \ - --hash=sha256:059e348f9a3c1950937e1b5d7ba1f8e968508ab181e75fc32b879452f08356db \ - --hash=sha256:1a5472d40c8f8e91ff7a3d8ac6dfa363d8e3138b961529c996f3e2df0c7a411a \ - --hash=sha256:1a8e6c2de6fbbcc5e14fd27fb24414507cb3333198ea9ab1258d916f00bc3039 \ - --hash=sha256:1fee5aacc7367487b4e22484d3c7e547992ed726d14864ee33c0176ae43b0d7c \ - --hash=sha256:5d092fdfedaec4cbbffbf98cddc915ba145313a6fdaab83c6e67f4e6c218e6f3 \ - --hash=sha256:5f0ff6e18d13a3de56f609dd1fd11470918f770c6bd5d00d632076c727d35485 \ - --hash=sha256:7bfc55a5eae8b86a287747053140ba221afc65eb06207bedf6e019b8934b477c \ - --hash=sha256:7fa01527046ca5facdf973eef2535a27fec4cb651e4daec4d043ef63f6ecd4ca \ - --hash=sha256:8dde71c4169ec5ccc1087bb7521d54251c016f126f922ab2dfe6649170a3b8c5 \ - --hash=sha256:8f4ab7021127a9b4323537300a2acfb450124b2def3756f64dc3a3d2160ee4b5 \ - --hash=sha256:948224d76c4b6457349d47c0c98657557f429b4e93057cf5a2f71d603e2fc3a3 \ - --hash=sha256:9a6c7a3c87d595608a39980ebaa04d5a37f94024c9f24eb7d10262b92f739ddb \ - --hash=sha256:b46e37db3cc267b4dea1f56da7346c9727e1209aa98487179ee8ebed09d21e43 \ - --hash=sha256:b4ceb5324b998ce2003bc17d519080b4ec8d5b7b70794cbd2836101406a9be31 \ - --hash=sha256:cb33ccf15e89f7ed89b235cff9d49e2e62c6c981a6061c9c8bb47ed7951190bc \ - --hash=sha256:d198820aba55660b4d74f7b5fd1f17db3aa5eb3e6893b0a41b75e84e4f9e0e4b \ - --hash=sha256:d34579085401d3f49762d2f7d6634d6b6c2ae1242202e860f4d26b046e3a1006 \ - --hash=sha256:eb8163f5e549a22888c18b0d53d6bb62a20510060a22fd5a995ec8a05268df8a \ - --hash=sha256:f73bff05db2a3e5974a6fd248af2566134d8981fd7ab012e5dd4ddb1d9a70699 +cryptography==41.0.2 \ + --hash=sha256:01f1d9e537f9a15b037d5d9ee442b8c22e3ae11ce65ea1f3316a41c78756b711 \ + --hash=sha256:079347de771f9282fbfe0e0236c716686950c19dee1b76240ab09ce1624d76d7 \ + --hash=sha256:182be4171f9332b6741ee818ec27daff9fb00349f706629f5cbf417bd50e66fd \ + --hash=sha256:192255f539d7a89f2102d07d7375b1e0a81f7478925b3bc2e0549ebf739dae0e \ + --hash=sha256:2a034bf7d9ca894720f2ec1d8b7b5832d7e363571828037f9e0c4f18c1b58a58 \ + --hash=sha256:342f3767e25876751e14f8459ad85e77e660537ca0a066e10e75df9c9e9099f0 \ + --hash=sha256:439c3cc4c0d42fa999b83ded80a9a1fb54d53c58d6e59234cfe97f241e6c781d \ + --hash=sha256:49c3222bb8f8e800aead2e376cbef687bc9e3cb9b58b29a261210456a7783d83 \ + --hash=sha256:674b669d5daa64206c38e507808aae49904c988fa0a71c935e7006a3e1e83831 \ + --hash=sha256:7a9a3bced53b7f09da251685224d6a260c3cb291768f54954e28f03ef14e3766 \ + --hash=sha256:7af244b012711a26196450d34f483357e42aeddb04128885d95a69bd8b14b69b \ + --hash=sha256:7d230bf856164de164ecb615ccc14c7fc6de6906ddd5b491f3af90d3514c925c \ + --hash=sha256:84609ade00a6ec59a89729e87a503c6e36af98ddcd566d5f3be52e29ba993182 \ + --hash=sha256:9a6673c1828db6270b76b22cc696f40cde9043eb90373da5c2f8f2158957f42f \ + --hash=sha256:9b6d717393dbae53d4e52684ef4f022444fc1cce3c48c38cb74fca29e1f08eaa \ + --hash=sha256:9c3fe6534d59d071ee82081ca3d71eed3210f76ebd0361798c74abc2bcf347d4 \ + --hash=sha256:a719399b99377b218dac6cf547b6ec54e6ef20207b6165126a280b0ce97e0d2a \ + --hash=sha256:b332cba64d99a70c1e0836902720887fb4529ea49ea7f5462cf6640e095e11d2 \ + --hash=sha256:d124682c7a23c9764e54ca9ab5b308b14b18eba02722b8659fb238546de83a76 \ + --hash=sha256:d73f419a56d74fef257955f51b18d046f3506270a5fd2ac5febbfa259d6c0fa5 \ + --hash=sha256:f0dc40e6f7aa37af01aba07277d3d64d5a03dc66d682097541ec4da03cc140ee \ + --hash=sha256:f14ad275364c8b4e525d018f6716537ae7b6d369c094805cae45300847e0894f \ + --hash=sha256:f772610fe364372de33d76edcd313636a25684edb94cee53fd790195f5989d14 # via # paramiko # secretstorage From ee169672536f3f9da96edeba4d91a67066dc4818 Mon Sep 17 00:00:00 2001 From: michaelboulton Date: Sun, 30 Jul 2023 19:05:50 +0100 Subject: [PATCH 10/25] Update dependencies + use pre commit in smoke script (#879) --- .github/workflows/main.yml | 15 +- .pre-commit-config.yaml | 6 +- constraints.txt | 86 +++------- example/mqtt/docker-compose.yaml | 2 +- pyproject.toml | 12 +- requirements.txt | 263 +++++++++--------------------- scripts/smoke.bash | 4 +- tavern/_core/schema/extensions.py | 2 +- tavern/_plugins/mqtt/response.py | 2 +- tavern/_plugins/rest/request.py | 4 +- tox-integration.ini | 17 +- tox.ini | 2 +- 12 files changed, 124 insertions(+), 291 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f66ea1ec..e9da3a1f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,14 +20,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: "3.8" - - - uses: actions/cache@v3 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml', 'requirements.in') }} - restore-keys: | - ${{ runner.os }}-pip- + python-version: "3.11" - uses: pre-commit/action@v3.0.0 @@ -85,12 +78,12 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: "3.8" + python-version: "3.11" - name: install deps run: | - pip install tox-travis -c constraints.txt + pip install tox -c constraints.txt - name: tox run: | - tox -c ${TOXCFG} + tox -c ${TOXCFG} -e ${TOXENV} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6ca570f8..b0019072 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,16 +1,16 @@ repos: - repo: https://github.com/ambv/black - rev: 23.3.0 + rev: 23.7.0 hooks: - id: black files: "(tavern|tests)" - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: "v0.0.270" + rev: "v0.0.280" hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] - repo: https://github.com/pre-commit/mirrors-prettier - rev: v2.7.1 + rev: v3.0.0 hooks: - id: prettier types_or: [yaml] diff --git a/constraints.txt b/constraints.txt index 8606cd67..d1fadf80 100644 --- a/constraints.txt +++ b/constraints.txt @@ -13,10 +13,6 @@ attrs==23.1.0 # allure-python-commons # jsonschema # pytest -bcrypt==4.0.1 - # via paramiko -black==23.3.0 - # via tavern (pyproject.toml) bleach==6.0.0 # via readme-renderer blinker==1.6.2 @@ -25,21 +21,26 @@ build==0.10.0 # via pip-tools bump2version==1.0.1 # via tavern (pyproject.toml) -certifi==2023.5.7 - # via requests -cffi==1.15.1 +cachetools==5.3.1 + # via tox +certifi==2023.7.22 # via - # cryptography - # pynacl + # requests + # tavern (pyproject.toml) +cffi==1.15.1 + # via cryptography cfgv==3.3.1 # via pre-commit +chardet==5.1.0 + # via tox charset-normalizer==3.1.0 # via requests click==8.1.3 # via - # black # flask # pip-tools +colorama==0.4.6 + # via tox colorlog==6.7.0 # via tavern (pyproject.toml) coverage==7.2.7 @@ -47,23 +48,11 @@ coverage==7.2.7 # pytest-cov # tavern (pyproject.toml) cryptography==41.0.2 - # via - # paramiko - # secretstorage + # via secretstorage distlib==0.3.6 # via virtualenv -distro==1.8.0 - # via docker-compose -docker==6.1.3 - # via docker-compose -docker-compose==1.29.2 - # via tavern (pyproject.toml) -dockerpty==0.4.1 - # via docker-compose docopt==0.6.2 - # via - # docker-compose - # pykwalify + # via pykwalify docutils==0.20.1 # via # flit @@ -111,9 +100,7 @@ jinja2==3.1.2 jmespath==1.0.1 # via tavern (pyproject.toml) jsonschema==3.2.0 - # via - # docker-compose - # tavern (pyproject.toml) + # via tavern (pyproject.toml) keyring==23.13.1 # via twine markdown-it-py==2.2.0 @@ -132,24 +119,18 @@ mypy==1.3.0 # via tavern (pyproject.toml) mypy-extensions==1.0.0 # via - # black # mypy # tavern (pyproject.toml) nodeenv==1.8.0 # via pre-commit packaging==23.1 # via - # black # build - # docker + # pyproject-api # pytest # tox paho-mqtt==1.6.1 # via tavern (pyproject.toml) -paramiko==3.2.0 - # via docker -pathspec==0.11.1 - # via black pbr==5.11.1 # via stevedore pip-tools==6.13.0 @@ -158,7 +139,7 @@ pkginfo==1.9.6 # via twine platformdirs==3.5.1 # via - # black + # tox # virtualenv pluggy==1.0.0 # via @@ -168,9 +149,7 @@ pluggy==1.0.0 pre-commit==3.3.2 # via tavern (pyproject.toml) py==1.11.0 - # via - # tavern (pyproject.toml) - # tox + # via tavern (pyproject.toml) pycparser==2.21 # via cffi pygments==2.15.1 @@ -182,8 +161,8 @@ pyjwt==2.7.0 # via tavern (pyproject.toml) pykwalify==1.8.0 # via tavern (pyproject.toml) -pynacl==1.5.0 - # via paramiko +pyproject-api==1.5.3 + # via tox pyproject-hooks==1.0.0 # via build pyrsistent==0.19.3 @@ -204,19 +183,14 @@ python-dateutil==2.8.2 # via # faker # pykwalify -python-dotenv==0.21.1 - # via docker-compose -pyyaml==5.4.1 +pyyaml==6.0.1 # via - # docker-compose # pre-commit # tavern (pyproject.toml) readme-renderer==37.3 # via twine requests==2.31.0 # via - # docker - # docker-compose # flit # requests-toolbelt # tavern (pyproject.toml) @@ -231,38 +205,27 @@ ruamel-yaml==0.17.31 # via pykwalify ruamel-yaml-clib==0.2.7 # via ruamel-yaml -ruff==0.0.270 - # via tavern (pyproject.toml) secretstorage==3.3.3 # via keyring six==1.16.0 # via # bleach - # dockerpty # jsonschema # python-dateutil - # tox - # websocket-client stevedore==4.1.1 # via tavern (pyproject.toml) -texttable==1.6.7 - # via docker-compose tomli==2.0.1 # via - # black # build # coverage # mypy + # pyproject-api # pyproject-hooks # pytest # tox tomli-w==1.0.0 # via flit -tox==3.28.0 - # via - # tavern (pyproject.toml) - # tox-travis -tox-travis==0.13 +tox==4.6.0 # via tavern (pyproject.toml) twine==4.0.2 # via tavern (pyproject.toml) @@ -278,7 +241,6 @@ typing-extensions==4.6.3 # via mypy urllib3==2.0.2 # via - # docker # requests # twine virtualenv==20.23.0 @@ -287,10 +249,6 @@ virtualenv==20.23.0 # tox webencodings==0.5.1 # via bleach -websocket-client==0.59.0 - # via - # docker - # docker-compose werkzeug==2.3.4 # via flask wheel==0.40.0 diff --git a/example/mqtt/docker-compose.yaml b/example/mqtt/docker-compose.yaml index 97426b61..55d87205 100644 --- a/example/mqtt/docker-compose.yaml +++ b/example/mqtt/docker-compose.yaml @@ -44,7 +44,7 @@ services: read_only: true fluent: - image: fluent/fluentd + image: fluent/fluentd:v1.16 ports: - "24224:24224" volumes: diff --git a/pyproject.toml b/pyproject.toml index 29ed5443..3fa436b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ description = "Simple testing of RESTful APIs" version = "2.2.0" dependencies = [ - "PyYAML>=5.3.1,<7", + "PyYAML>=6.0.1,<7", "jmespath>=1,<2", "jsonschema>=3.2.0,<5", "paho-mqtt>=1.3.1,<=1.6.1", @@ -57,29 +57,25 @@ Source = "https://github.com/taverntesting/tavern" dev = [ "Faker", "allure-pytest", - "black==23.3.0", "bump2version", "colorlog", - "docker-compose", "flask>=2.2.3", "fluent-logger", "itsdangerous", "mypy", "mypy-extensions", "coverage[toml]", - "types-PyYAML", "flit >=3.2,<4", "pip-tools", "pre-commit", "pygments", "pytest-cov", - "ruff>=0.0.270", "pytest-xdist", "py", - "tox>=3,<4", - "tox-travis", + "tox>=4,<5", "twine", "wheel", + "types-PyYAML", "types-setuptools", "types-requests", # This has to be installed separately, otherwise you can't upload to pypi @@ -156,7 +152,7 @@ select = ["E", "F", "B", "W", "I", "S", "C4", "ICN", "T20", "PLE", "RUF", "SIM10 target-version = "py38" [tool.ruff.per-file-ignores] -"tests/*" = ["S"] +"tests/*" = ["S", "RUF"] [tool.ruff.isort] known-first-party = ["tavern"] diff --git a/requirements.txt b/requirements.txt index 666d4d46..2523f334 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,56 +19,6 @@ attrs==23.1.0 \ # allure-python-commons # jsonschema # pytest -bcrypt==4.0.1 \ - --hash=sha256:089098effa1bc35dc055366740a067a2fc76987e8ec75349eb9484061c54f535 \ - --hash=sha256:08d2947c490093a11416df18043c27abe3921558d2c03e2076ccb28a116cb6d0 \ - --hash=sha256:0eaa47d4661c326bfc9d08d16debbc4edf78778e6aaba29c1bc7ce67214d4410 \ - --hash=sha256:27d375903ac8261cfe4047f6709d16f7d18d39b1ec92aaf72af989552a650ebd \ - --hash=sha256:2b3ac11cf45161628f1f3733263e63194f22664bf4d0c0f3ab34099c02134665 \ - --hash=sha256:2caffdae059e06ac23fce178d31b4a702f2a3264c20bfb5ff541b338194d8fab \ - --hash=sha256:3100851841186c25f127731b9fa11909ab7b1df6fc4b9f8353f4f1fd952fbf71 \ - --hash=sha256:5ad4d32a28b80c5fa6671ccfb43676e8c1cc232887759d1cd7b6f56ea4355215 \ - --hash=sha256:67a97e1c405b24f19d08890e7ae0c4f7ce1e56a712a016746c8b2d7732d65d4b \ - --hash=sha256:705b2cea8a9ed3d55b4491887ceadb0106acf7c6387699fca771af56b1cdeeda \ - --hash=sha256:8a68f4341daf7522fe8d73874de8906f3a339048ba406be6ddc1b3ccb16fc0d9 \ - --hash=sha256:a522427293d77e1c29e303fc282e2d71864579527a04ddcfda6d4f8396c6c36a \ - --hash=sha256:ae88eca3024bb34bb3430f964beab71226e761f51b912de5133470b649d82344 \ - --hash=sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f \ - --hash=sha256:b3b85202d95dd568efcb35b53936c5e3b3600c7cdcc6115ba461df3a8e89f38d \ - --hash=sha256:b57adba8a1444faf784394de3436233728a1ecaeb6e07e8c22c8848f179b893c \ - --hash=sha256:bf4fa8b2ca74381bb5442c089350f09a3f17797829d958fad058d6e44d9eb83c \ - --hash=sha256:ca3204d00d3cb2dfed07f2d74a25f12fc12f73e606fcaa6975d1f7ae69cacbb2 \ - --hash=sha256:cbb03eec97496166b704ed663a53680ab57c5084b2fc98ef23291987b525cb7d \ - --hash=sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e \ - --hash=sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3 - # via paramiko -black==23.3.0 \ - --hash=sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5 \ - --hash=sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915 \ - --hash=sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326 \ - --hash=sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940 \ - --hash=sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b \ - --hash=sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30 \ - --hash=sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c \ - --hash=sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c \ - --hash=sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab \ - --hash=sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27 \ - --hash=sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2 \ - --hash=sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961 \ - --hash=sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9 \ - --hash=sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb \ - --hash=sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70 \ - --hash=sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331 \ - --hash=sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2 \ - --hash=sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266 \ - --hash=sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d \ - --hash=sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6 \ - --hash=sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b \ - --hash=sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925 \ - --hash=sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8 \ - --hash=sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4 \ - --hash=sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3 - # via tavern (pyproject.toml) bleach==6.0.0 \ --hash=sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414 \ --hash=sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4 @@ -85,10 +35,16 @@ bump2version==1.0.1 \ --hash=sha256:37f927ea17cde7ae2d7baf832f8e80ce3777624554a653006c9144f8017fe410 \ --hash=sha256:762cb2bfad61f4ec8e2bdf452c7c267416f8c70dd9ecb1653fd0bbb01fa936e6 # via tavern (pyproject.toml) -certifi==2023.5.7 \ - --hash=sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7 \ - --hash=sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716 - # via requests +cachetools==5.3.1 \ + --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \ + --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b + # via tox +certifi==2023.7.22 \ + --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ + --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 + # via + # requests + # tavern (pyproject.toml) cffi==1.15.1 \ --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ --hash=sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef \ @@ -154,13 +110,15 @@ cffi==1.15.1 \ --hash=sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b \ --hash=sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01 \ --hash=sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0 - # via - # cryptography - # pynacl + # via cryptography cfgv==3.3.1 \ --hash=sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426 \ --hash=sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736 # via pre-commit +chardet==5.1.0 \ + --hash=sha256:0d62712b956bc154f85fb0a266e2a3c5913c2967e00348701b32411d6def31e5 \ + --hash=sha256:362777fb014af596ad31334fde1e8c327dfdb076e1960d1694662d46a6917ab9 + # via tox charset-normalizer==3.1.0 \ --hash=sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6 \ --hash=sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1 \ @@ -242,9 +200,12 @@ click==8.1.3 \ --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48 # via - # black # flask # pip-tools +colorama==0.4.6 \ + --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ + --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 + # via tox colorlog==6.7.0 \ --hash=sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662 \ --hash=sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5 @@ -337,33 +298,14 @@ cryptography==41.0.2 \ --hash=sha256:f0dc40e6f7aa37af01aba07277d3d64d5a03dc66d682097541ec4da03cc140ee \ --hash=sha256:f14ad275364c8b4e525d018f6716537ae7b6d369c094805cae45300847e0894f \ --hash=sha256:f772610fe364372de33d76edcd313636a25684edb94cee53fd790195f5989d14 - # via - # paramiko - # secretstorage + # via secretstorage distlib==0.3.6 \ --hash=sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46 \ --hash=sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e # via virtualenv -distro==1.8.0 \ - --hash=sha256:02e111d1dc6a50abb8eed6bf31c3e48ed8b0830d1ea2a1b78c61765c2513fdd8 \ - --hash=sha256:99522ca3e365cac527b44bde033f64c6945d90eb9f769703caaec52b09bbd3ff - # via docker-compose -docker[ssh]==6.1.3 \ - --hash=sha256:aa6d17830045ba5ef0168d5eaa34d37beeb113948c413affe1d5991fc11f9a20 \ - --hash=sha256:aecd2277b8bf8e506e484f6ab7aec39abe0038e29fa4a6d3ba86c3fe01844ed9 - # via docker-compose -docker-compose==1.29.2 \ - --hash=sha256:4c8cd9d21d237412793d18bd33110049ee9af8dab3fe2c213bbd0733959b09b7 \ - --hash=sha256:8d5589373b35c8d3b1c8c1182c6e4a4ff14bffa3dd0b605fcd08f73c94cef809 - # via tavern (pyproject.toml) -dockerpty==0.4.1 \ - --hash=sha256:69a9d69d573a0daa31bcd1c0774eeed5c15c295fe719c61aca550ed1393156ce - # via docker-compose docopt==0.6.2 \ --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491 - # via - # docker-compose - # pykwalify + # via pykwalify docutils==0.20.1 \ --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \ --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b @@ -449,9 +391,7 @@ jmespath==1.0.1 \ jsonschema==3.2.0 \ --hash=sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163 \ --hash=sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a - # via - # docker-compose - # tavern (pyproject.toml) + # via tavern (pyproject.toml) keyring==23.13.1 \ --hash=sha256:771ed2a91909389ed6148631de678f82ddc73737d85a927f382a8a1b157898cd \ --hash=sha256:ba2e15a9b35e21908d0aaf4e0a47acc52d6ae33444df0da2b49d41a46ef6d678 @@ -619,7 +559,6 @@ mypy-extensions==1.0.0 \ --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \ --hash=sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782 # via - # black # mypy # tavern (pyproject.toml) nodeenv==1.8.0 \ @@ -630,22 +569,13 @@ packaging==23.1 \ --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \ --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f # via - # black # build - # docker + # pyproject-api # pytest # tox paho-mqtt==1.6.1 \ --hash=sha256:2a8291c81623aec00372b5a85558a372c747cbca8e9934dfe218638b8eefc26f # via tavern (pyproject.toml) -paramiko==3.2.0 \ - --hash=sha256:93cdce625a8a1dc12204439d45033f3261bdb2c201648cfcdc06f9fd0f94ec29 \ - --hash=sha256:df0f9dd8903bc50f2e10580af687f3015bf592a377cd438d2ec9546467a14eb8 - # via docker -pathspec==0.11.1 \ - --hash=sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687 \ - --hash=sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293 - # via black pbr==5.11.1 \ --hash=sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b \ --hash=sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3 @@ -662,7 +592,7 @@ platformdirs==3.5.1 \ --hash=sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f \ --hash=sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5 # via - # black + # tox # virtualenv pluggy==1.0.0 \ --hash=sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159 \ @@ -678,9 +608,7 @@ pre-commit==3.3.2 \ py==1.11.0 \ --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \ --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 - # via - # tavern (pyproject.toml) - # tox + # via tavern (pyproject.toml) pycparser==2.21 \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 @@ -700,18 +628,10 @@ pykwalify==1.8.0 \ --hash=sha256:731dfa87338cca9f559d1fca2bdea37299116e3139b73f78ca90a543722d6651 \ --hash=sha256:796b2ad3ed4cb99b88308b533fb2f559c30fa6efb4fa9fda11347f483d245884 # via tavern (pyproject.toml) -pynacl==1.5.0 \ - --hash=sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858 \ - --hash=sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d \ - --hash=sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93 \ - --hash=sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1 \ - --hash=sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92 \ - --hash=sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff \ - --hash=sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba \ - --hash=sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394 \ - --hash=sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b \ - --hash=sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543 - # via paramiko +pyproject-api==1.5.3 \ + --hash=sha256:14cf09828670c7b08842249c1f28c8ee6581b872e893f81b62d5465bec41502f \ + --hash=sha256:ffb5b2d7cad43f5b2688ab490de7c4d3f6f15e0b819cb588c4b771567c9729eb + # via tox pyproject-hooks==1.0.0 \ --hash=sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8 \ --hash=sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5 @@ -786,42 +706,48 @@ python-dateutil==2.8.2 \ # via # faker # pykwalify -python-dotenv==0.21.1 \ - --hash=sha256:1c93de8f636cde3ce377292818d0e440b6e45a82f215c3744979151fa8151c49 \ - --hash=sha256:41e12e0318bebc859fcc4d97d4db8d20ad21721a6aa5047dd59f090391cb549a - # via docker-compose -pyyaml==5.4.1 \ - --hash=sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf \ - --hash=sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696 \ - --hash=sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393 \ - --hash=sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77 \ - --hash=sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922 \ - --hash=sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5 \ - --hash=sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8 \ - --hash=sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10 \ - --hash=sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc \ - --hash=sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018 \ - --hash=sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e \ - --hash=sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253 \ - --hash=sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347 \ - --hash=sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183 \ - --hash=sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541 \ - --hash=sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb \ - --hash=sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185 \ - --hash=sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc \ - --hash=sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db \ - --hash=sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa \ - --hash=sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46 \ - --hash=sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122 \ - --hash=sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b \ - --hash=sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63 \ - --hash=sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df \ - --hash=sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc \ - --hash=sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247 \ - --hash=sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6 \ - --hash=sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0 +pyyaml==6.0.1 \ + --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \ + --hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \ + --hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \ + --hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \ + --hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \ + --hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \ + --hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \ + --hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \ + --hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \ + --hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \ + --hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \ + --hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \ + --hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \ + --hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \ + --hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \ + --hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \ + --hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \ + --hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \ + --hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \ + --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \ + --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \ + --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \ + --hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \ + --hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \ + --hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \ + --hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \ + --hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \ + --hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \ + --hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \ + --hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \ + --hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \ + --hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \ + --hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \ + --hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \ + --hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \ + --hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \ + --hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \ + --hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \ + --hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \ + --hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f # via - # docker-compose # pre-commit # tavern (pyproject.toml) readme-renderer==37.3 \ @@ -832,8 +758,6 @@ requests==2.31.0 \ --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 # via - # docker - # docker-compose # flit # requests-toolbelt # tavern (pyproject.toml) @@ -893,25 +817,6 @@ ruamel-yaml-clib==0.2.7 \ --hash=sha256:f34019dced51047d6f70cb9383b2ae2853b7fc4dce65129a5acd49f4f9256646 \ --hash=sha256:f6d3d39611ac2e4f62c3128a9eed45f19a6608670c5a2f4f07f24e8de3441d38 # via ruamel-yaml -ruff==0.0.270 \ - --hash=sha256:0012f9b7dc137ab7f1f0355e3c4ca49b562baf6c9fa1180948deeb6648c52957 \ - --hash=sha256:08188f8351f4c0b6216e8463df0a76eb57894ca59a3da65e4ed205db980fd3ae \ - --hash=sha256:0827b074635d37984fc98d99316bfab5c8b1231bb83e60dacc83bd92883eedb4 \ - --hash=sha256:0bbfbf6fd2436165566ca85f6e57be03ed2f0a994faf40180cfbb3604c9232ef \ - --hash=sha256:0d61ae4841313f6eeb8292dc349bef27b4ce426e62c36e80ceedc3824e408734 \ - --hash=sha256:0eb412f20e77529a01fb94d578b19dcb8331b56f93632aa0cce4a2ea27b7aeba \ - --hash=sha256:21f00e47ab2308617c44435c8dfd9e2e03897461c9e647ec942deb2a235b4cfd \ - --hash=sha256:3ed3b198768d2b3a2300fb18f730cd39948a5cc36ba29ae9d4639a11040880be \ - --hash=sha256:643de865fd35cb76c4f0739aea5afe7b8e4d40d623df7e9e6ea99054e5cead0a \ - --hash=sha256:739495d2dbde87cf4e3110c8d27bc20febf93112539a968a4e02c26f0deccd1d \ - --hash=sha256:8af391ef81f7be960be10886a3c1aac0b298bde7cb9a86ec2b05faeb2081ce6b \ - --hash=sha256:95db07b7850b30ebf32b27fe98bc39e0ab99db3985edbbf0754d399eb2f0e690 \ - --hash=sha256:9613456b0b375766244c25045e353bc8890c856431cd97893c97b10cc93bd28d \ - --hash=sha256:b4c037fe2f75bcd9aed0c89c7c507cb7fa59abae2bd4c8b6fc331a28178655a4 \ - --hash=sha256:b775e2c5fc869359daf8c8b8aa0fd67240201ab2e8d536d14a0edf279af18786 \ - --hash=sha256:eca02e709b3308eb7255b5f74e779be23b5980fca3862eae28bb23069cd61ae4 \ - --hash=sha256:f74c4d550f7b8e808455ac77bbce38daafc458434815ba0bc21ae4bdb276509b - # via tavern (pyproject.toml) secretstorage==3.3.3 \ --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 @@ -921,27 +826,20 @@ six==1.16.0 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 # via # bleach - # dockerpty # jsonschema # python-dateutil - # tox - # websocket-client stevedore==4.1.1 \ --hash=sha256:7f8aeb6e3f90f96832c301bff21a7eb5eefbe894c88c506483d355565d88cc1a \ --hash=sha256:aa6436565c069b2946fe4ebff07f5041e0c8bf18c7376dd29edf80cf7d524e4e # via tavern (pyproject.toml) -texttable==1.6.7 \ - --hash=sha256:290348fb67f7746931bcdfd55ac7584ecd4e5b0846ab164333f0794b121760f2 \ - --hash=sha256:b7b68139aa8a6339d2c320ca8b1dc42d13a7831a346b446cb9eb385f0c76310c - # via docker-compose tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f # via - # black # build # coverage # mypy + # pyproject-api # pyproject-hooks # pytest # tox @@ -949,15 +847,9 @@ tomli-w==1.0.0 \ --hash=sha256:9f2a07e8be30a0729e533ec968016807069991ae2fd921a78d42f429ae5f4463 \ --hash=sha256:f463434305e0336248cac9c2dc8076b707d8a12d019dd349f5c1e382dd1ae1b9 # via flit -tox==3.28.0 \ - --hash=sha256:57b5ab7e8bb3074edc3c0c0b4b192a4f3799d3723b2c5b76f1fa9f2d40316eea \ - --hash=sha256:d0d28f3fe6d6d7195c27f8b054c3e99d5451952b54abdae673b71609a581f640 - # via - # tavern (pyproject.toml) - # tox-travis -tox-travis==0.13 \ - --hash=sha256:3e1e4868d108748012f78cd0bd64f05b5a12b33809d6721a0b35cfb00986e55e \ - --hash=sha256:71fa355d84d32b592428ac8016f669a7c63e459fa42774a33d60072d3d7371dc +tox==4.6.0 \ + --hash=sha256:4874000453e637a87ca892f9744a2ab9a7d24064dad1b0ecbf5a4c3c146cc732 \ + --hash=sha256:954f1f647f67f481d239a193288983242a6152b67503c4a56b19a4aafaa29736 # via tavern (pyproject.toml) twine==4.0.2 \ --hash=sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8 \ @@ -987,7 +879,6 @@ urllib3==2.0.2 \ --hash=sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc \ --hash=sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e # via - # docker # requests # twine virtualenv==20.23.0 \ @@ -1000,12 +891,6 @@ webencodings==0.5.1 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 # via bleach -websocket-client==0.59.0 \ - --hash=sha256:2e50d26ca593f70aba7b13a489435ef88b8fc3b5c5643c1ce8808ff9b40f0b32 \ - --hash=sha256:d376bd60eace9d437ab6d7ee16f4ab4e821c9dae591e1b783c58ebd8aaf80c5c - # via - # docker - # docker-compose werkzeug==2.3.4 \ --hash=sha256:1d5a58e0377d1fe39d061a5de4469e414e78ccb1e1e59c0f5ad6fa1c36c52b76 \ --hash=sha256:48e5e61472fee0ddee27ebad085614ebedb7af41e88f687aaf881afb723a162f diff --git a/scripts/smoke.bash b/scripts/smoke.bash index 49f7d8ac..838ee369 100755 --- a/scripts/smoke.bash +++ b/scripts/smoke.bash @@ -2,8 +2,8 @@ set -ex -ruff tavern tests --fix -black tavern tests +pre-commit run ruff --all-files +pre-commit run black --all-files # Separate as isort can interfere with other testenvs tox --parallel -c tox.ini \ diff --git a/tavern/_core/schema/extensions.py b/tavern/_core/schema/extensions.py index 98ec55c8..ca352be0 100644 --- a/tavern/_core/schema/extensions.py +++ b/tavern/_core/schema/extensions.py @@ -138,7 +138,7 @@ def verify_oneof_id_name(value, rule_obj, path) -> bool: name = value.get("name") if not name: - if name == "": # noqa + if name == "": raise BadSchemaError("Name cannot be empty") if not value.get("id"): diff --git a/tavern/_plugins/mqtt/response.py b/tavern/_plugins/mqtt/response.py index 5322cdf5..74bc7ca9 100644 --- a/tavern/_plugins/mqtt/response.py +++ b/tavern/_plugins/mqtt/response.py @@ -270,7 +270,7 @@ def addwarning(w, *args, **kwargs): return False if self.expected_payload is None: - if msg.payload is None or msg.payload == "": # noqa + if msg.payload is None or msg.payload == "": logger.info("Got message with no payload (as expected) on '%s'", topic) return True else: diff --git a/tavern/_plugins/rest/request.py b/tavern/_plugins/rest/request.py index 7a4205bf..77d55914 100644 --- a/tavern/_plugins/rest/request.py +++ b/tavern/_plugins/rest/request.py @@ -4,7 +4,7 @@ import warnings from contextlib import ExitStack from itertools import filterfalse, tee -from typing import Mapping, MutableMapping, Optional +from typing import ClassVar, List, Mapping, MutableMapping, Optional from urllib.parse import quote_plus import requests @@ -333,7 +333,7 @@ def partition(pred, iterable): class RestRequest(BaseRequest): - optional_in_file = [ + optional_in_file: ClassVar[List[str]] = [ "json", "data", "params", diff --git a/tox-integration.ini b/tox-integration.ini index 10598e92..f9fc2ada 100644 --- a/tox-integration.ini +++ b/tox-integration.ini @@ -4,8 +4,10 @@ skip_missing_interpreters = true isolated_build = True [testenv] +allowlist_externals = + docker-compose basepython = python3.10 -passenv = DOCKER_TLS_VERIFY DOCKER_HOST DOCKER_CERT_PATH DOCKER_BUILDKIT +passenv = DOCKER_TLS_VERIFY,DOCKER_HOST,DOCKER_CERT_PATH,DOCKER_BUILDKIT setenv = TEST_HOST = http://localhost:5003 SECOND_URL_PART = again @@ -19,7 +21,6 @@ changedir = generic: tests/integration noextra: tests/integration deps = - docker-compose flask allure-pytest pyjwt @@ -36,23 +37,23 @@ commands = generic: py.test --tavern-global-cfg={toxinidir}/tests/integration/global_cfg.yaml -n 3 generic: tavern-ci --stdout . --tavern-global-cfg={toxinidir}/tests/integration/global_cfg.yaml - generic: python -c "from tavern.core import run; exit(run('.', '{toxinidir}/tests/integration/global_cfg.yaml', pytest_args=[]))" + generic: python -c "from tavern.core import run; exit(run('.', '{toxinidir}/tests/integration/global_cfg.yaml', pytest_args=[ ]))" generic: python -c "from tavern.core import run; exit(run('.', pytest_args=['--tavern-global-cfg={toxinidir}/tests/integration/global_cfg.yaml']))" cookies: tavern-ci --stdout test_server.tavern.yaml - cookies: python -c "from tavern.core import run; exit(run('test_server.tavern.yaml', pytest_args=[]))" + cookies: python -c "from tavern.core import run; exit(run('test_server.tavern.yaml', pytest_args=[ ]))" advanced: tavern-ci --stdout test_server.tavern.yaml - advanced: python -c "from tavern.core import run; exit(run('test_server.tavern.yaml', pytest_args=[]))" + advanced: python -c "from tavern.core import run; exit(run('test_server.tavern.yaml', pytest_args=[ ]))" components: tavern-ci --stdout test_ping.tavern.yaml components: tavern-ci --stdout test_hello.tavern.yaml - components: python -c "from tavern.core import run; exit(run('test_ping.tavern.yaml', pytest_args=[]))" - components: python -c "from tavern.core import run; exit(run('test_hello.tavern.yaml', pytest_args=[]))" + components: python -c "from tavern.core import run; exit(run('test_ping.tavern.yaml', pytest_args=[ ]))" + components: python -c "from tavern.core import run; exit(run('test_hello.tavern.yaml', pytest_args=[ ]))" mqtt: tavern-ci --stdout test_mqtt.tavern.yaml --cov tavern mqtt: python -c "from tavern.core import run; exit(run('test_mqtt.tavern.yaml', pytest_args=['--cov-append']))" mqtt: tavern-ci --stdout test_mqtt_failures.tavern.yaml - mqtt: python -c "from tavern.core import run; exit(run('test_mqtt_failures.tavern.yaml', pytest_args=[]))" + mqtt: python -c "from tavern.core import run; exit(run('test_mqtt_failures.tavern.yaml', pytest_args=[ ]))" docker-compose stop diff --git a/tox.ini b/tox.ini index 70494974..40db486f 100644 --- a/tox.ini +++ b/tox.ini @@ -6,7 +6,7 @@ isolated_build = True [testenv] passenv = XDG_CACHE_HOME basepython = python3.10 -whitelist_externals = +allowlist_externals = mypy install_command = python -m pip install {opts} {packages} -c constraints.txt extras = From a632ef5b798c8b46a47d918e897e9fb1362b34b6 Mon Sep 17 00:00:00 2001 From: Michael Boulton Date: Sun, 30 Jul 2023 19:08:07 +0100 Subject: [PATCH 11/25] Bump to 2.2.1 --- CHANGELOG.md | 2 ++ docs/source/conf.py | 2 +- pyproject.toml | 4 ++-- tavern/__init__.py | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0a25181..4229c1c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -408,3 +408,5 @@ This is technically not a operational change but I'm adding a new tag so it can ## 2.0.7 Lock pytest to <7.3 to fix issue with marks (2023-04-15) # 2.1.0 Allow multi part file uploads with the same form field name (2023-06-04) + +# 2.2.0 Allow wildcards in MQTT topics (2023-06-25) diff --git a/docs/source/conf.py b/docs/source/conf.py index df7bb272..46d4287d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -73,7 +73,7 @@ # The short X.Y version. version = "1.0" # The full version, including alpha/beta/rc tags. -release = "2.2.0" +release = "2.2.1" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index 3fa436b7..e8ad0c85 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ keywords = ["testing", "pytest"] name = "tavern" description = "Simple testing of RESTful APIs" -version = "2.2.0" +version = "2.2.1" dependencies = [ "PyYAML>=6.0.1,<7", @@ -158,7 +158,7 @@ target-version = "py38" known-first-party = ["tavern"] [tool.tbump.version] -current = "2.2.0" +current = "2.2.1" regex = ''' (?P\d+) diff --git a/tavern/__init__.py b/tavern/__init__.py index b009ae71..157577f3 100644 --- a/tavern/__init__.py +++ b/tavern/__init__.py @@ -1,2 +1,2 @@ """Stop pytest warning about module already imported: PYTEST_DONT_REWRITE""" -__version__ = "2.2.0" +__version__ = "2.2.1" From 7c030f0332deea92b0ebe2b393062b4f8adc2f76 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 5 Aug 2023 16:10:09 +0100 Subject: [PATCH 12/25] Bump cryptography from 41.0.2 to 41.0.3 (#880) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- constraints.txt | 2 +- requirements.txt | 48 ++++++++++++++++++++++++------------------------ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/constraints.txt b/constraints.txt index d1fadf80..6c2e2e37 100644 --- a/constraints.txt +++ b/constraints.txt @@ -47,7 +47,7 @@ coverage==7.2.7 # via # pytest-cov # tavern (pyproject.toml) -cryptography==41.0.2 +cryptography==41.0.3 # via secretstorage distlib==0.3.6 # via virtualenv diff --git a/requirements.txt b/requirements.txt index 2523f334..30032202 100644 --- a/requirements.txt +++ b/requirements.txt @@ -274,30 +274,30 @@ coverage[toml]==7.2.7 \ # via # pytest-cov # tavern (pyproject.toml) -cryptography==41.0.2 \ - --hash=sha256:01f1d9e537f9a15b037d5d9ee442b8c22e3ae11ce65ea1f3316a41c78756b711 \ - --hash=sha256:079347de771f9282fbfe0e0236c716686950c19dee1b76240ab09ce1624d76d7 \ - --hash=sha256:182be4171f9332b6741ee818ec27daff9fb00349f706629f5cbf417bd50e66fd \ - --hash=sha256:192255f539d7a89f2102d07d7375b1e0a81f7478925b3bc2e0549ebf739dae0e \ - --hash=sha256:2a034bf7d9ca894720f2ec1d8b7b5832d7e363571828037f9e0c4f18c1b58a58 \ - --hash=sha256:342f3767e25876751e14f8459ad85e77e660537ca0a066e10e75df9c9e9099f0 \ - --hash=sha256:439c3cc4c0d42fa999b83ded80a9a1fb54d53c58d6e59234cfe97f241e6c781d \ - --hash=sha256:49c3222bb8f8e800aead2e376cbef687bc9e3cb9b58b29a261210456a7783d83 \ - --hash=sha256:674b669d5daa64206c38e507808aae49904c988fa0a71c935e7006a3e1e83831 \ - --hash=sha256:7a9a3bced53b7f09da251685224d6a260c3cb291768f54954e28f03ef14e3766 \ - --hash=sha256:7af244b012711a26196450d34f483357e42aeddb04128885d95a69bd8b14b69b \ - --hash=sha256:7d230bf856164de164ecb615ccc14c7fc6de6906ddd5b491f3af90d3514c925c \ - --hash=sha256:84609ade00a6ec59a89729e87a503c6e36af98ddcd566d5f3be52e29ba993182 \ - --hash=sha256:9a6673c1828db6270b76b22cc696f40cde9043eb90373da5c2f8f2158957f42f \ - --hash=sha256:9b6d717393dbae53d4e52684ef4f022444fc1cce3c48c38cb74fca29e1f08eaa \ - --hash=sha256:9c3fe6534d59d071ee82081ca3d71eed3210f76ebd0361798c74abc2bcf347d4 \ - --hash=sha256:a719399b99377b218dac6cf547b6ec54e6ef20207b6165126a280b0ce97e0d2a \ - --hash=sha256:b332cba64d99a70c1e0836902720887fb4529ea49ea7f5462cf6640e095e11d2 \ - --hash=sha256:d124682c7a23c9764e54ca9ab5b308b14b18eba02722b8659fb238546de83a76 \ - --hash=sha256:d73f419a56d74fef257955f51b18d046f3506270a5fd2ac5febbfa259d6c0fa5 \ - --hash=sha256:f0dc40e6f7aa37af01aba07277d3d64d5a03dc66d682097541ec4da03cc140ee \ - --hash=sha256:f14ad275364c8b4e525d018f6716537ae7b6d369c094805cae45300847e0894f \ - --hash=sha256:f772610fe364372de33d76edcd313636a25684edb94cee53fd790195f5989d14 +cryptography==41.0.3 \ + --hash=sha256:0d09fb5356f975974dbcb595ad2d178305e5050656affb7890a1583f5e02a306 \ + --hash=sha256:23c2d778cf829f7d0ae180600b17e9fceea3c2ef8b31a99e3c694cbbf3a24b84 \ + --hash=sha256:3fb248989b6363906827284cd20cca63bb1a757e0a2864d4c1682a985e3dca47 \ + --hash=sha256:41d7aa7cdfded09b3d73a47f429c298e80796c8e825ddfadc84c8a7f12df212d \ + --hash=sha256:42cb413e01a5d36da9929baa9d70ca90d90b969269e5a12d39c1e0d475010116 \ + --hash=sha256:4c2f0d35703d61002a2bbdcf15548ebb701cfdd83cdc12471d2bae80878a4207 \ + --hash=sha256:4fd871184321100fb400d759ad0cddddf284c4b696568204d281c902fc7b0d81 \ + --hash=sha256:5259cb659aa43005eb55a0e4ff2c825ca111a0da1814202c64d28a985d33b087 \ + --hash=sha256:57a51b89f954f216a81c9d057bf1a24e2f36e764a1ca9a501a6964eb4a6800dd \ + --hash=sha256:652627a055cb52a84f8c448185922241dd5217443ca194d5739b44612c5e6507 \ + --hash=sha256:67e120e9a577c64fe1f611e53b30b3e69744e5910ff3b6e97e935aeb96005858 \ + --hash=sha256:6af1c6387c531cd364b72c28daa29232162010d952ceb7e5ca8e2827526aceae \ + --hash=sha256:6d192741113ef5e30d89dcb5b956ef4e1578f304708701b8b73d38e3e1461f34 \ + --hash=sha256:7efe8041897fe7a50863e51b77789b657a133c75c3b094e51b5e4b5cec7bf906 \ + --hash=sha256:84537453d57f55a50a5b6835622ee405816999a7113267739a1b4581f83535bd \ + --hash=sha256:8f09daa483aedea50d249ef98ed500569841d6498aa9c9f4b0531b9964658922 \ + --hash=sha256:95dd7f261bb76948b52a5330ba5202b91a26fbac13ad0e9fc8a3ac04752058c7 \ + --hash=sha256:a74fbcdb2a0d46fe00504f571a2a540532f4c188e6ccf26f1f178480117b33c4 \ + --hash=sha256:a983e441a00a9d57a4d7c91b3116a37ae602907a7618b882c8013b5762e80574 \ + --hash=sha256:ab8de0d091acbf778f74286f4989cf3d1528336af1b59f3e5d2ebca8b5fe49e1 \ + --hash=sha256:aeb57c421b34af8f9fe830e1955bf493a86a7996cc1338fe41b30047d16e962c \ + --hash=sha256:ce785cf81a7bdade534297ef9e490ddff800d956625020ab2ec2780a556c313e \ + --hash=sha256:d0d651aa754ef58d75cec6edfbd21259d93810b73f6ec246436a21b7841908de # via secretstorage distlib==0.3.6 \ --hash=sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46 \ From a405cb3419a00d9f261959dbc50a6e2133568ee3 Mon Sep 17 00:00:00 2001 From: michaelboulton Date: Sat, 5 Aug 2023 18:59:20 +0100 Subject: [PATCH 13/25] finally block (#830) --- .github/workflows/main.yml | 53 +++- constraints.txt | 4 +- docs/source/basics.md | 278 +++++++++++------- docs/source/http.md | 2 +- example/advanced/server.py | 12 +- example/components/server.py | 2 +- example/cookies/server.py | 8 +- example/generate_from_openapi/pub_tavern.py | 5 +- example/hooks/conftest.py | 2 +- example/hooks/server.py | 1 - example/mqtt/conftest.py | 3 +- example/mqtt/listener.py | 1 - example/mqtt/server.py | 5 +- example/simple/server.py | 1 - requirements.txt | 4 +- tavern/_core/exceptions.py | 15 +- tavern/_core/pytest/item.py | 14 +- tavern/_core/run.py | 160 +++++----- tavern/_core/schema/jsonschema.py | 2 + tavern/_core/schema/tests.jsonschema.yaml | 8 + tavern/_core/schema/tests.schema.yaml | 1 + .../integration/test_control_flow.tavern.yaml | 51 ++++ tests/unit/test_core.py | 89 +++++- tox.ini | 2 +- 24 files changed, 496 insertions(+), 227 deletions(-) create mode 100644 tests/integration/test_control_flow.tavern.yaml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e9da3a1f..67c81136 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,7 +24,7 @@ jobs: - uses: pre-commit/action@v3.0.0 - test: + unit-tests: runs-on: ubuntu-latest needs: simple-checks @@ -38,6 +38,49 @@ jobs: - TOXENV: py3 TOXCFG: tox.ini + env: + TOXENV: ${{ matrix.TOXENV }} + TOXCFG: ${{ matrix.TOXCFG }} + + steps: + - uses: actions/checkout@v3 + + - uses: actions/cache@v3 + env: + cache-name: cache-${{ matrix.TOXENV }} + with: + path: .tox + key: ${{ runner.os }}-tox-${{ env.cache-name }}-${{ hashFiles('pyproject.toml', 'requirements.in') }} + + - uses: actions/cache@v3 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml', 'requirements.in') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + + - name: install deps + run: | + pip install tox -c constraints.txt + + - name: tox + run: | + tox -c ${TOXCFG} -e ${TOXENV} + + integration-tests: + runs-on: ubuntu-latest + needs: unit-tests + + strategy: + fail-fast: false + matrix: + include: + # integration tests - TOXENV: py3-generic TOXCFG: tox-integration.ini - TOXENV: py3-mqtt @@ -56,6 +99,9 @@ jobs: TOXCFG: ${{ matrix.TOXCFG }} steps: + - uses: jpribyl/action-docker-layer-caching@v0.1.1 + continue-on-error: true + - uses: actions/checkout@v3 - uses: actions/cache@v3 @@ -63,7 +109,7 @@ jobs: cache-name: cache-${{ matrix.TOXENV }} with: path: .tox - key: ${{ runner.os }}-tox-${{ env.cache-name }}-${{ hashFiles('tox.ini', 'tox-integration.ini', 'pyproject.toml', 'requirements.in') }} + key: ${{ runner.os }}-tox-${{ env.cache-name }}-${{ hashFiles('pyproject.toml', 'requirements.in') }} - uses: actions/cache@v3 with: @@ -72,9 +118,6 @@ jobs: restore-keys: | ${{ runner.os }}-pip- - - uses: jpribyl/action-docker-layer-caching@v0.1.1 - continue-on-error: true - - name: Set up Python uses: actions/setup-python@v4 with: diff --git a/constraints.txt b/constraints.txt index 6c2e2e37..62354550 100644 --- a/constraints.txt +++ b/constraints.txt @@ -24,9 +24,7 @@ bump2version==1.0.1 cachetools==5.3.1 # via tox certifi==2023.7.22 - # via - # requests - # tavern (pyproject.toml) + # via requests cffi==1.15.1 # via cryptography cfgv==3.3.1 diff --git a/docs/source/basics.md b/docs/source/basics.md index 11852ede..ac243d91 100644 --- a/docs/source/basics.md +++ b/docs/source/basics.md @@ -52,17 +52,24 @@ just be to check that an endpoint returns a 401 with no login information. A more complicated one might be: 1. Log in to server - - `POST` login information in body - - Expect login details to be returned in body + +- `POST` login information in body +- Expect login details to be returned in body + 2. Get user information - - `GET` with login information in `Authorization` header - - Expect user information returned in body + +- `GET` with login information in `Authorization` header +- Expect user information returned in body + 3. Create a new resource with that user information - - `POST` with login information in `Authorization` header and user information in body - - Expect a 201 with the created resource in the body + +- `POST` with login information in `Authorization` header and user information in body +- Expect a 201 with the created resource in the body + 4. Make sure it's stored on the server - - `GET` with login information in `Authorization` header - - Expect the same information returned as in the previous step + +- `GET` with login information in `Authorization` header +- Expect the same information returned as in the previous step The **name** of each stage is a description of what is happening in that particular test. @@ -117,11 +124,14 @@ and lists recursively. If the response is: ```json { - "thing": { - "nested": [ - 1, 2, 3, 4 - ] - } + "thing": { + "nested": [ + 1, + 2, + 3, + 4 + ] + } } ``` @@ -148,7 +158,8 @@ response: nested_thing: "thing" ``` -This will save `{"nested": [1, 2, 3, 4]}` into the `nested_thing` variable. See the documentation for the `force_format_include` tag for how this can be used. +This will save `{"nested": [1, 2, 3, 4]}` into the `nested_thing` variable. See the documentation for +the `force_format_include` tag for how this can be used. **NOTE**: The behaviour of these queries used to be different and indexing into an array was done like `thing.nested.0`. This will be deprecated in the @@ -157,7 +168,8 @@ an array was done like `thing.nested.0`. This will be deprecated in the It is also possible to save data using function calls, [explained below](#saving-data-from-a-response). For a more formal definition of the schema that the tests are validated against, -check [tests schema](https://github.com/taverntesting/tavern/blob/master/tavern/schemas/tests.schema.yaml) in the main Tavern repository. +check [tests schema](https://github.com/taverntesting/tavern/blob/master/tavern/schemas/tests.schema.yaml) in the main +Tavern repository. ## Generating Test Reports @@ -167,7 +179,7 @@ to your Pip dependencies and pass the `--alluredir=` flag when running Tave a test report with the stages that were run, the responses, any fixtures used, and any errors. See the [Allure documentation](https://docs.qameta.io/allure/#_installing_a_commandline) for more -information on how to use it. +information on how to use it. ## Variable formatting @@ -361,14 +373,14 @@ response: type: seq required: True sequence: - - type: map - mapping: - user_number: - type: int - required: False - user_name: - type: str - required: True + - type: map + mapping: + user_number: + type: int + required: False + user_name: + type: str + required: True ``` If an external function you are using raises any exception, the test will be @@ -400,6 +412,7 @@ above that this function should _not_ take any arguments): # utils.py from box import Box + def generate_bearer_token(): token = sign_a_jwt() auth_header = { @@ -435,6 +448,7 @@ Input from external functions can be merged into a request instead by specifying def return_hello(): return {"hello": "there"} ``` + ```yaml request: url: "{host}/echo" @@ -445,14 +459,15 @@ def return_hello(): function: ext_functions:return_hello ``` -If `tavern-merge-ext-function-values` is set, this will send "hello" and "goodbye" in -the request. If not, it will just send "hello". +If `tavern-merge-ext-function-values` is set, this will send "hello" and "goodbye" in +the request. If not, it will just send "hello". Example `pytest.ini` setting `tavern-merge-ext-function-values` as an argument. + ```python # pytest.ini [pytest] -addopts = --tavern-merge-ext-function-values +addopts = --tavern - merge - ext - function - values ``` #### Saving data from a response @@ -466,10 +481,10 @@ Say that we have a server which returns a response like this: ```json { - "user": { - "name": "John Smith", - "id": "abcdef12345" - } + "user": { + "name": "John Smith", + "id": "abcdef12345" + } } ``` @@ -480,6 +495,7 @@ that this function should take the response object as the first argument): # utils.py from box import Box + def test_function(response): return Box({"test_user_name": response.json()["user"]["name"]}) ``` @@ -500,7 +516,8 @@ in later requests. #### A more complicated example For a more practical example, the built in `validate_jwt` function also returns the -decoded token as a dictionary wrapped in a [Box](https://pypi.python.org/pypi/python-box/) object, which allows dot-notation +decoded token as a dictionary wrapped in a [Box](https://pypi.python.org/pypi/python-box/) object, which allows +dot-notation access to members. This means that the contents of the token can be used for future requests. Because Tavern will already be in the Python path (because you installed it as a library) you do not need to modify the `PYTHONPATH`. @@ -602,12 +619,12 @@ response: The behaviour of various levels of 'strictness' based on the response: -| Response | strict=on | strict=off | -| ---- | -------- | ------ | -| `{ "first": 1, "second": { "nested": 2 } }` | PASS | PASS | -| `{ "first": 1 }` | FAIL | PASS | -| `{ "first": 1, "second": { "another": 2 } }` | FAIL | FAIL | -| `{ "first": 1, "second": { "nested": 2, "another": 2 } }` | FAIL | PASS | +| Response | strict=on | strict=off | +|-----------------------------------------------------------|-----------|------------| +| `{ "first": 1, "second": { "nested": 2 } }` | PASS | PASS | +| `{ "first": 1 }` | FAIL | PASS | +| `{ "first": 1, "second": { "another": 2 } }` | FAIL | FAIL | +| `{ "first": 1, "second": { "nested": 2, "another": 2 } }` | FAIL | PASS | Turning 'strict' off also means that extra items in lists will be ignored as long as the ones specified in the test response are present. For example, if the @@ -675,7 +692,7 @@ whichever configuration file Pytest is using. ```ini [pytest] -tavern-strict=json:off headers:on +tavern-strict = json:off headers:on ``` #### Per test @@ -966,8 +983,8 @@ stages: status_code: 200 json: location: - road: 123 Fake Street - country: England + road: 123 Fake Street + country: England --- test_name: Make sure giving premium works @@ -1006,7 +1023,6 @@ stages: has_premium: true ``` - ## Including external files Even with being able to use anchors within the same file, there is often some @@ -1057,9 +1073,8 @@ automatically be loaded and available for formatting as before. Multiple include files can be specified. The environment variable TAVERN_INCLUDE can contain a : separated list of -paths to search for include files. Each path in TAVERN_INCLUDE has -environment variables expanded before it is searched. - +paths to search for include files. Each path in TAVERN_INCLUDE has +environment variables expanded before it is searched. ### Including global configuration files @@ -1197,17 +1212,17 @@ might not work as expected: # pytest.ini [pytest] addopts = - # This will work +# This will work --tavern-global-cfg=integration_tests/local_urls.yaml - # This will not! - # --tavern-global-cfg integration_tests/local_urls.yaml +# This will not! +# --tavern-global-cfg integration_tests/local_urls.yaml ``` Instead, use the `tavern-global-cfg` option in your pytest.ini file: ```ini [pytest] -tavern-global-cfg= +tavern-global-cfg = integration_tests/local_urls.yaml ``` @@ -1226,10 +1241,11 @@ every test: $ tavern-ci --tavern-global-cfg common.yaml test_urls.yaml -- test_server.tavern.yaml $ py.test --tavern-global-cfg common.yaml local_docker_urls.yaml -- test_server.tavern.yaml ``` + ```ini # pytest.ini [pytest] -tavern-global-cfg= +tavern-global-cfg = common.yaml test_urls.yaml ``` @@ -1419,7 +1435,6 @@ This is also how things such as strict key checking is controlled via the An example of using `pytest_args` to exit on the first failure: - ```python from tavern.core import run @@ -1455,6 +1470,7 @@ This would match both of these response bodies: ```yaml returned_block: hello ``` + ```yaml returned_block: nested: value @@ -1495,7 +1511,7 @@ third block must start with 4 and the third block must start with 8, 9, "A", or ```yaml - name: Check that uuidv4 is returned request: - url: {host}/get_uuid/v4 + url: { host }/get_uuid/v4 method: GET response: status_code: 200 @@ -1517,31 +1533,31 @@ format `v1.2.3-510c2665d771e1`: ```yaml stages: -- name: get a token by id - request: - url: "{host}/tokens/get" - method: GET - params: - id: 456 - response: - status_code: 200 - json: - code: abc123 - id: 456 - meta: - version: !anystr - hash: 456 - save: - $ext: - function: tavern.helpers:validate_regex - extra_kwargs: - expression: "v(?P[\d\.]+)-[\w\d]+" - in_jmespath: "meta.version" + - name: get a token by id + request: + url: "{host}/tokens/get" + method: GET + params: + id: 456 + response: + status_code: 200 + json: + code: abc123 + id: 456 + meta: + version: !anystr + hash: 456 + save: + $ext: + function: tavern.helpers:validate_regex + extra_kwargs: + expression: "v(?P[\d\.]+)-[\w\d]+" + in_jmespath: "meta.version" ``` This is a more flexible version of the helper which can also be used to save values as in the example. If a named matching group is used as shown above, the saved values - can then be accessed in subsequent stages by using the `regex.` syntax, eg: +can then be accessed in subsequent stages by using the `regex.` syntax, eg: ```yaml - name: Reuse thing specified in first request @@ -1643,7 +1659,7 @@ could be done by response: status_code: 200 # Expect no users - json: [] + json: [ ] ``` Any blocks of JSON that are included this way will not be recursively formatted. @@ -2020,7 +2036,6 @@ variable_. Using the above example, perhaps we just want to test the server works correctly with the items "rotten apple", "fresh orange", and "unripe pear" rather than the 9 combinations listed above. This can be done like this: - ```yaml --- test_name: Test post a new fruit @@ -2031,9 +2046,9 @@ marks: - fruit - edible vals: - - [rotten, apple] - - [fresh, orange] - - [unripe, pear] + - [ rotten, apple ] + - [ fresh, orange ] + - [ unripe, pear ] # NOTE: we can specify a nested list like this as well: # - # - unripe @@ -2056,7 +2071,6 @@ This can be combined with the 'simpler' style of parametrisation as well - for example, to run the above test but also to specify whether the fruit was expensive or cheap: - ```yaml --- test_name: Test post a new fruit and price @@ -2067,9 +2081,9 @@ marks: - fruit - edible vals: - - [rotten, apple] - - [fresh, orange] - - [unripe, pear] + - [ rotten, apple ] + - [ fresh, orange ] + - [ unripe, pear ] - parametrize: key: price vals: @@ -2106,11 +2120,11 @@ test_name: Test sending a list of list of keys where one is not a string marks: - parametrize: key: - - fruit - - colours + - fruit + - colours vals: - - [ apple, [red, green, pink] ] - - [ pear, [yellow, green] ] + - [ apple, [ red, green, pink ] ] + - [ pear, [ yellow, green ] ] stages: - name: Send fruit and colours @@ -2142,28 +2156,28 @@ functions can be used to read values. For example this block will create 6 tests test_name: Test parametrizing random different data types in the same test marks: -- parametrize: - key: value_to_send - vals: - - a - - [b, c] - - more: stuff - - yet: [more, stuff] - - $ext: - function: ext_functions:return_string - - and: this - $ext: - function: ext_functions:return_dict - - # If 'return_dict' returns {"keys: ["a","b","c"]} this results in: - # { - # "and": "this", - # "keys": [ - # "a", - # "b", - # "c" - # ] - # } + - parametrize: + key: value_to_send + vals: + - a + - [ b, c ] + - more: stuff + - yet: [ more, stuff ] + - $ext: + function: ext_functions:return_string + - and: this + $ext: + function: ext_functions:return_dict + + # If 'return_dict' returns {"keys: ["a","b","c"]} this results in: + # { + # "and": "this", + # "keys": [ + # "a", + # "b", + # "c" + # ] + # } ``` As see in the last example, if the `$ext` function returns a dictionary then it will also be merged @@ -2196,6 +2210,7 @@ import pytest import logging import time + @pytest.fixture def server_password(): with open("/path/to/password/file", "r") as pfile: @@ -2203,6 +2218,7 @@ def server_password(): return password + @pytest.fixture(name="time_request") def fix_time_request(): t0 = time.time() @@ -2258,7 +2274,7 @@ There are some limitations on fixtures: Fixtures which are specified as `autouse` can also be used without explicitly using `usefixtures` in a test. This is a good way to essentially precompute a format variable without also having to use an external function or specify a -`usefixtures` block in every test where you need it. +`usefixtures` block in every test where you need it. To do this, just pass the `autouse=True` parameter to your fixtures along with the relevant scope. Using 'session' will evalute the fixture once at the beginning @@ -2313,6 +2329,7 @@ Example usage: ```python import logging + def pytest_tavern_beta_before_every_test_run(test_dict, variables): logging.info("Starting test %s", test_dict["test_name"]) @@ -2321,7 +2338,7 @@ def pytest_tavern_beta_before_every_test_run(test_dict, variables): ### After every test run -This hook is called _after_ execution of each test, regardless of the test +This hook is called _after_ execution of each test, regardless of the test result. The hook can, for example, be used to perform cleanup after the test is run. Example usage: @@ -2329,6 +2346,7 @@ Example usage: ```python import logging + def pytest_tavern_beta_after_every_test_run(test_dict, variables): logging.info("Ending test %s", test_dict["test_name"]) ``` @@ -2350,14 +2368,50 @@ def pytest_tavern_beta_after_every_response(expected, response): ### Before every request This hook is called just before each request with the arguments passed to the request -"function". By default, this is Session.request (from requests) for HTTP and Client.publish -(from paho-mqtt) for MQTT. +"function". By default, this is Session.request (from requests) for HTTP and Client.publish +(from paho-mqtt) for MQTT. Example usage: ```python import logging + def pytest_tavern_beta_before_every_request(request_args): logging.info("Making request: %s", request_args) ``` + +## Finalising stages + +If you need a stage to run after a test runs, whether it passes or fails (for example, to log out of a service or +invalidate a short-lived auth token) you can use the `finally` block: + +```yaml +--- +test_name: Test finally block doing nothing + +stages: + - name: stage 1 + ... + + - name: stage 2 + ... + + - name: stage 3 + ... + +finally: + - name: clean up + request: + url: "{global_host}/cleanup" + method: POST +``` + +The `finally` block accepts a list of stages which will always be run after the rest of the test finishes, whether it +passed or failed. Each stage in run in order - if one of the `finally` stages fails, the rest will not be run. + +In the above example, if "stage 2" fails then the execution order would be: + +- stage 1 +- stage 2 (fails) +- clean up diff --git a/docs/source/http.md b/docs/source/http.md index d73fa77c..b0d5c60f 100644 --- a/docs/source/http.md +++ b/docs/source/http.md @@ -171,7 +171,7 @@ stages: request: url: "{host}/expect_cookie" method: GET - cookies: [] + cookies: [ ] response: status_code: 403 json: diff --git a/example/advanced/server.py b/example/advanced/server.py index c9b399a7..726cd99e 100644 --- a/example/advanced/server.py +++ b/example/advanced/server.py @@ -1,9 +1,10 @@ -import sqlite3 +import contextlib import datetime import functools -from flask import Flask, jsonify, request, g -import jwt +import sqlite3 +import jwt +from flask import Flask, g, jsonify, request app = Flask(__name__) @@ -19,12 +20,11 @@ def get_db(): db = g._database = sqlite3.connect(DATABASE) with db: - try: + with contextlib.suppress(Exception): db.execute( "CREATE TABLE numbers_table (name TEXT NOT NULL, number INTEGER NOT NULL)" ) - except Exception: - pass + return db diff --git a/example/components/server.py b/example/components/server.py index b7792c45..3bbc59bc 100644 --- a/example/components/server.py +++ b/example/components/server.py @@ -1,8 +1,8 @@ import datetime import functools -from flask import Flask, jsonify, request import jwt +from flask import Flask, jsonify, request app = Flask(__name__) diff --git a/example/cookies/server.py b/example/cookies/server.py index e7629a06..9026f138 100644 --- a/example/cookies/server.py +++ b/example/cookies/server.py @@ -1,7 +1,8 @@ +import contextlib import functools import sqlite3 -from flask import Flask, jsonify, request, g, session +from flask import Flask, g, jsonify, request, session app = Flask(__name__) app.secret_key = "t1uNraxw+9oxUyCuXHO2G0u38ig=" @@ -17,12 +18,11 @@ def get_db(): db = g._database = sqlite3.connect(DATABASE) with db: - try: + with contextlib.suppress(Exception): db.execute( "CREATE TABLE numbers_table (name TEXT NOT NULL, number INTEGER NOT NULL)" ) - except: - pass + return db diff --git a/example/generate_from_openapi/pub_tavern.py b/example/generate_from_openapi/pub_tavern.py index 371a8284..33fd60f9 100644 --- a/example/generate_from_openapi/pub_tavern.py +++ b/example/generate_from_openapi/pub_tavern.py @@ -1,7 +1,8 @@ import sys from urllib.parse import urlparse -from coreapi import Client + import yaml +from coreapi import Client def generate_tavern_yaml(json_path): @@ -68,7 +69,7 @@ def display_help(): print( "eg: pub_tavern.py https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v2.0/json/petstore-simple.json" ) - exit(-1) + sys.exit(-1) if __name__ == "__main__": diff --git a/example/hooks/conftest.py b/example/hooks/conftest.py index 76164c7b..bac83349 100644 --- a/example/hooks/conftest.py +++ b/example/hooks/conftest.py @@ -1,6 +1,6 @@ +import logging import os import tempfile -import logging import pytest diff --git a/example/hooks/server.py b/example/hooks/server.py index 9f965f9b..91952128 100644 --- a/example/hooks/server.py +++ b/example/hooks/server.py @@ -1,6 +1,5 @@ from flask import Flask, jsonify, request - app = Flask(__name__) diff --git a/example/mqtt/conftest.py b/example/mqtt/conftest.py index cabeddff..d75e282a 100644 --- a/example/mqtt/conftest.py +++ b/example/mqtt/conftest.py @@ -1,4 +1,3 @@ -import datetime import logging import logging.config import random @@ -51,7 +50,7 @@ def setup_logging(): - stderr level: DEBUG propagate: False - tavern: + tavern: <<: *log tavern.mqtt: &reduced_log diff --git a/example/mqtt/listener.py b/example/mqtt/listener.py index 756b4735..f641831a 100644 --- a/example/mqtt/listener.py +++ b/example/mqtt/listener.py @@ -3,7 +3,6 @@ import logging.config import os import sqlite3 -import time import paho.mqtt.client as paho import yaml diff --git a/example/mqtt/server.py b/example/mqtt/server.py index c74e2a0c..bc73c910 100644 --- a/example/mqtt/server.py +++ b/example/mqtt/server.py @@ -193,10 +193,9 @@ def _reset_db(db): with db: def attempt(query): - try: + with contextlib.suppress(Exception): db.execute(query) - except: - pass + attempt("DELETE FROM devices_table") attempt( diff --git a/example/simple/server.py b/example/simple/server.py index 9f965f9b..91952128 100644 --- a/example/simple/server.py +++ b/example/simple/server.py @@ -1,6 +1,5 @@ from flask import Flask, jsonify, request - app = Flask(__name__) diff --git a/requirements.txt b/requirements.txt index 30032202..3f1d4d6a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -42,9 +42,7 @@ cachetools==5.3.1 \ certifi==2023.7.22 \ --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 - # via - # requests - # tavern (pyproject.toml) + # via requests cffi==1.15.1 \ --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ --hash=sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef \ diff --git a/tavern/_core/exceptions.py b/tavern/_core/exceptions.py index 803abe0c..3caf3a9a 100644 --- a/tavern/_core/exceptions.py +++ b/tavern/_core/exceptions.py @@ -1,5 +1,18 @@ +from typing import TYPE_CHECKING, Dict, Optional + +if TYPE_CHECKING: + from tavern._core.pytest.config import TestConfig + + class TavernException(Exception): - """Base exception""" + """Base exception + + Fields are internal and might change in future + """ + + stage: Optional[Dict] + test_block_config: Optional["TestConfig"] + is_final: bool = False class BadSchemaError(TavernException): diff --git a/tavern/_core/pytest/item.py b/tavern/_core/pytest/item.py index 2baff2fe..1c3596de 100644 --- a/tavern/_core/pytest/item.py +++ b/tavern/_core/pytest/item.py @@ -216,20 +216,18 @@ def runtest(self) -> None: logger.info("xfailing test while verifying schema") self.add_marker(pytest.mark.xfail, True) raise - except exceptions.TavernException: - if xfail == "run": + except exceptions.TavernException as e: + if xfail == "run" and not e.is_final: logger.info("xfailing test when running") self.add_marker(pytest.mark.xfail, True) + elif xfail == "finally" and e.is_final: + logger.info("xfailing test when finalising") + self.add_marker(pytest.mark.xfail, True) + raise else: if xfail: raise Exception("internal: xfail test did not fail '{}'".format(xfail)) - # else: - # if xfail: - # logger.error("Expected test to fail") - # raise exceptions.TestFailError( - # "Expected test to fail at {} stage".format(xfail) - # ) finally: call_hook( self.global_cfg, diff --git a/tavern/_core/run.py b/tavern/_core/run.py index b950b1d5..2b42e5cf 100644 --- a/tavern/_core/run.py +++ b/tavern/_core/run.py @@ -1,15 +1,17 @@ import copy +import dataclasses import functools import logging import pathlib from contextlib import ExitStack from copy import deepcopy -from typing import List, Mapping, MutableMapping +from typing import Dict, List, Mapping, MutableMapping import box from tavern._core import exceptions from tavern._core.plugins import ( + PluginHelperBase, get_expected, get_extra_sessions, get_request_type, @@ -134,7 +136,7 @@ def run_test( # Initialise test config for this test with the global configuration before # starting test_block_config = global_cfg.copy() - default_global_stricness = global_cfg.strict + default_global_strictness = global_cfg.strict tavern_box = get_tavern_box() @@ -174,41 +176,34 @@ def getonly(stage): has_only = any(getonly(stage) for stage in test_spec["stages"]) - # Run tests in a path in order - for idx, stage in enumerate(test_spec["stages"]): - if stage.get("skip"): - continue - if has_only and not getonly(stage): - continue - - test_block_config = test_block_config.with_strictness( - default_global_stricness - ) - test_block_config = test_block_config.with_strictness( - _calculate_stage_strictness(stage, test_block_config, test_spec) - ) - - # Wrap run_stage with retry helper - run_stage_with_retries = retry(stage, test_block_config)(run_stage) - - partial = functools.partial( - run_stage_with_retries, sessions, stage, test_block_config - ) - - allure_name = "Stage {}: {}".format( - idx, format_keys(stage["name"], test_block_config.variables) - ) - step = wrap_step(allure_name, partial) - - try: - step() - except exceptions.TavernException as e: - e.stage = stage # type: ignore - e.test_block_config = test_block_config # type: ignore - raise + runner = _TestRunner( + default_global_strictness, sessions, test_block_config, test_spec + ) - if getonly(stage): - break + try: + # Run tests in a path in order + for idx, stage in enumerate(test_spec["stages"]): + if stage.get("skip"): + continue + if has_only and not getonly(stage): + continue + + runner.run_stage(idx, stage) + + if getonly(stage): + break + finally: + finally_stages = test_spec.get("finally", []) + if not isinstance(finally_stages, list): + raise exceptions.BadSchemaError( + f"finally block should be a list of dicts but was {type(finally_stages)}" + ) + for idx, stage in enumerate(finally_stages): + if not isinstance(stage, dict): + raise exceptions.BadSchemaError( + f"finally block should be a dict but was {type(stage)}" + ) + runner.run_stage(idx, stage, is_final=True) def _calculate_stage_strictness( @@ -273,49 +268,74 @@ def update_stage_options(new_option): return new_strict -def run_stage( - sessions: Mapping, - stage: Mapping, - test_block_config: TestConfig, -) -> None: - """Run one stage from the test +@dataclasses.dataclass(frozen=True) +class _TestRunner: + default_global_strictness: StrictLevel + sessions: Dict[str, PluginHelperBase] + test_block_config: TestConfig + test_spec: Mapping - Args: - sessions: Dictionary of relevant 'session' objects used for this test - stage: specification of stage to be run - test_block_config: available variables for test - """ - stage = copy.deepcopy(stage) - name = stage["name"] + def run_stage(self, idx: int, stage, *, is_final: bool = False): + stage_config = self.test_block_config.with_strictness( + self.default_global_strictness + ) + stage_config = stage_config.with_strictness( + _calculate_stage_strictness(stage, stage_config, self.test_spec) + ) + # Wrap run_stage with retry helper + run_stage_with_retries = retry(stage, stage_config)(self.wrapped_run_stage) + partial = functools.partial(run_stage_with_retries, stage, stage_config) + allure_name = "Stage {}: {}".format( + idx, format_keys(stage["name"], stage_config.variables) + ) + step = wrap_step(allure_name, partial) - attach_stage_content(stage) + try: + step() + except exceptions.TavernException as e: + e.stage = stage + e.test_block_config = stage_config + e.is_final = is_final + raise - r = get_request_type(stage, test_block_config, sessions) + def wrapped_run_stage(self, stage: dict, stage_config: TestConfig): + """Run one stage from the test - tavern_box = test_block_config.variables["tavern"] - tavern_box.update(request_vars=r.request_vars) + Args: + stage: specification of stage to be run + stage_config: available variables for test + """ + stage = copy.deepcopy(stage) + name = stage["name"] - expected = get_expected(stage, test_block_config, sessions) + attach_stage_content(stage) - delay(stage, "before", test_block_config.variables) + r = get_request_type(stage, stage_config, self.sessions) - logger.info("Running stage : %s", name) + tavern_box = stage_config.variables["tavern"] + tavern_box.update(request_vars=r.request_vars) - call_hook( - test_block_config, - "pytest_tavern_beta_before_every_request", - request_args=r.request_vars, - ) + expected = get_expected(stage, stage_config, self.sessions) + + delay(stage, "before", stage_config.variables) + + logger.info("Running stage : %s", name) + + call_hook( + stage_config, + "pytest_tavern_beta_before_every_request", + request_args=r.request_vars, + ) - verifiers = get_verifiers(stage, test_block_config, sessions, expected) + verifiers = get_verifiers(stage, stage_config, self.sessions, expected) - response = r.run() + response = r.run() - for response_type, response_verifiers in verifiers.items(): - logger.debug("Running verifiers for %s", response_type) - for v in response_verifiers: - saved = v.verify(response) - test_block_config.variables.update(saved) + for response_type, response_verifiers in verifiers.items(): + logger.debug("Running verifiers for %s", response_type) + for v in response_verifiers: + saved = v.verify(response) + stage_config.variables.update(saved) - tavern_box.pop("request_vars") - delay(stage, "after", test_block_config.variables) + tavern_box.pop("request_vars") + delay(stage, "after", stage_config.variables) diff --git a/tavern/_core/schema/jsonschema.py b/tavern/_core/schema/jsonschema.py index 944dc010..896a80ce 100644 --- a/tavern/_core/schema/jsonschema.py +++ b/tavern/_core/schema/jsonschema.py @@ -163,6 +163,8 @@ def verify_jsonschema(to_verify, schema) -> None: """ ) + logger.debug("original exception from jsonschema: %s", e) + msg = "\n---\n" + "\n---\n".join([str(i) for i in real_context]) raise BadSchemaError(msg) from None diff --git a/tavern/_core/schema/tests.jsonschema.yaml b/tavern/_core/schema/tests.jsonschema.yaml index 880333df..decb652a 100644 --- a/tavern/_core/schema/tests.jsonschema.yaml +++ b/tavern/_core/schema/tests.jsonschema.yaml @@ -382,6 +382,7 @@ properties: enum: - verify - run + - finally marks: type: array @@ -427,3 +428,10 @@ properties: oneOf: - $ref: "#/definitions/stage" - $ref: "#/definitions/stage_ref" + + finally: + type: array + description: Stages to run after test finishes + + items: + $ref: "#/definitions/stage" diff --git a/tavern/_core/schema/tests.schema.yaml b/tavern/_core/schema/tests.schema.yaml index a7992d16..4cc26391 100644 --- a/tavern/_core/schema/tests.schema.yaml +++ b/tavern/_core/schema/tests.schema.yaml @@ -309,6 +309,7 @@ mapping: enum: - verify - run + - finally strict: func: check_strict_key diff --git a/tests/integration/test_control_flow.tavern.yaml b/tests/integration/test_control_flow.tavern.yaml new file mode 100644 index 00000000..dbcdfcf1 --- /dev/null +++ b/tests/integration/test_control_flow.tavern.yaml @@ -0,0 +1,51 @@ +--- +test_name: Test finally block doing nothing + +stages: + - name: Simple echo + request: + url: "{global_host}/echo" + method: POST + json: + value: "123" + response: + status_code: 200 + json: + value: "123" + +finally: + - name: nothing + request: + url: "{global_host}/echo" + method: POST + json: + value: "123" + +--- +test_name: Test finally block fail + +_xfail: finally + +stages: + - name: Simple echo + request: + url: "{global_host}/echo" + method: POST + json: + value: "123" + response: + status_code: 200 + json: + value: "123" + +finally: + - name: nothing + request: + url: "{global_host}/echo" + method: DELETE + json: + value: "123" + response: + status_code: 200 + json: + value: "123" diff --git a/tests/unit/test_core.py b/tests/unit/test_core.py index 32d2b198..17515389 100644 --- a/tests/unit/test_core.py +++ b/tests/unit/test_core.py @@ -1,3 +1,4 @@ +import copy import dataclasses import json import os @@ -37,7 +38,7 @@ def fix_example_test(): @pytest.fixture(name="mockargs") def fix_mock_response_args(fulltest): - response = fulltest["stages"][0]["response"] + response = copy.deepcopy(fulltest["stages"][0]["response"]) content = response["json"] args = { @@ -500,6 +501,92 @@ def test_format_request_var_value(self, fulltest, includes): assert pmock.called +class TestFinally: + @staticmethod + def run_test(fulltest, mockargs, includes): + mock_response = Mock(**mockargs) + + with patch( + "tavern._plugins.rest.request.requests.Session.request", + return_value=mock_response, + ) as pmock: + run_test("heif", fulltest, includes) + + assert pmock.called + + return pmock + + @pytest.mark.parametrize("finally_block", ([],)) + def test_nop(self, fulltest, mockargs, includes, finally_block): + """ignore empty finally blocks""" + fulltest["finally"] = finally_block + + self.run_test(fulltest, mockargs, includes) + + @pytest.mark.parametrize( + "finally_block", + ( + {}, + "hi", + 3, + ), + ) + def test_wrong_type(self, fulltest, mockargs, includes, finally_block): + """final stages need to be dicts too""" + fulltest["finally"] = finally_block + + with pytest.raises(exceptions.BadSchemaError): + self.run_test(fulltest, mockargs, includes) + + @pytest.fixture + def finally_request(self): + return { + "name": "step 1", + "request": {"url": "http://www.myfinal.com", "method": "POST"}, + "response": { + "status_code": 200, + "json": {"key": "value"}, + "headers": {"content-type": "application/json"}, + }, + } + + def test_finally_run(self, fulltest, mockargs, includes, finally_request): + fulltest["finally"] = [finally_request] + + pmock = self.run_test(fulltest, mockargs, includes) + + assert pmock.call_count == 2 + assert pmock.mock_calls[1].kwargs.items() >= finally_request["request"].items() + + def test_finally_run_twice(self, fulltest, mockargs, includes, finally_request): + fulltest["finally"] = [finally_request, finally_request] + + pmock = self.run_test(fulltest, mockargs, includes) + + assert pmock.call_count == 3 + assert pmock.mock_calls[1].kwargs.items() >= finally_request["request"].items() + assert pmock.mock_calls[2].kwargs.items() >= finally_request["request"].items() + + def test_finally_run_on_main_failure( + self, fulltest, mockargs, includes, finally_request + ): + fulltest["finally"] = [finally_request] + + mockargs["status_code"] = 503 + + mock_response = Mock(**mockargs) + + with patch( + "tavern._plugins.rest.request.requests.Session.request", + return_value=mock_response, + ) as pmock: + with pytest.raises(exceptions.TestFailError): + run_test("heif", fulltest, includes) + + assert pmock.call_count == 2 + assert pmock.mock_calls[1].kwargs.items() >= finally_request["request"].items() + + def test_copy_config(pytestconfig): cfg_1 = load_global_cfg(pytestconfig) diff --git a/tox.ini b/tox.ini index 40db486f..91a975e6 100644 --- a/tox.ini +++ b/tox.ini @@ -12,7 +12,7 @@ install_command = python -m pip install {opts} {packages} -c constraints.txt extras = dev commands = - {envbindir}/python -m pytest --cov-report term-missing --cov tavern + {envbindir}/python -m pytest --cov-report term-missing --cov tavern {posargs} [testenv:py3check] commands = From 9f2d2be9c1321f3f51744675f3b30cb6dda22549 Mon Sep 17 00:00:00 2001 From: Michael Boulton Date: Sat, 5 Aug 2023 19:24:24 +0100 Subject: [PATCH 14/25] Bump to 2.3.0 --- CHANGELOG.md | 2 ++ docs/source/conf.py | 2 +- pyproject.toml | 4 ++-- tavern/__init__.py | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4229c1c6..467b58d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -410,3 +410,5 @@ This is technically not a operational change but I'm adding a new tag so it can # 2.1.0 Allow multi part file uploads with the same form field name (2023-06-04) # 2.2.0 Allow wildcards in MQTT topics (2023-06-25) + +## 2.2.1 Update some dependencies (2023-07-30) diff --git a/docs/source/conf.py b/docs/source/conf.py index 46d4287d..bc501023 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -73,7 +73,7 @@ # The short X.Y version. version = "1.0" # The full version, including alpha/beta/rc tags. -release = "2.2.1" +release = "2.3.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index e8ad0c85..7b961ff8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ keywords = ["testing", "pytest"] name = "tavern" description = "Simple testing of RESTful APIs" -version = "2.2.1" +version = "2.3.0" dependencies = [ "PyYAML>=6.0.1,<7", @@ -158,7 +158,7 @@ target-version = "py38" known-first-party = ["tavern"] [tool.tbump.version] -current = "2.2.1" +current = "2.3.0" regex = ''' (?P\d+) diff --git a/tavern/__init__.py b/tavern/__init__.py index 157577f3..9213d18a 100644 --- a/tavern/__init__.py +++ b/tavern/__init__.py @@ -1,2 +1,2 @@ """Stop pytest warning about module already imported: PYTEST_DONT_REWRITE""" -__version__ = "2.2.1" +__version__ = "2.3.0" From 9bdb1060017dae8a61048cbebf63c3fa6baf53e4 Mon Sep 17 00:00:00 2001 From: michaelboulton Date: Mon, 18 Sep 2023 14:43:18 +0100 Subject: [PATCH 15/25] Fix error formatting with curly braces (#884) Fix issue where something with curly braces in it would cause an internal error while formatting --- tavern/_core/dict_util.py | 34 ++++++++--- tavern/_core/pytest/error.py | 4 +- tests/integration/881_1.json | 3 + tests/integration/881_2.yaml | 1 + tests/integration/test_include.tavern.yaml | 65 ++++++++++++++++++++++ 5 files changed, 98 insertions(+), 9 deletions(-) create mode 100644 tests/integration/881_1.json create mode 100644 tests/integration/881_2.yaml create mode 100644 tests/integration/test_include.tavern.yaml diff --git a/tavern/_core/dict_util.py b/tavern/_core/dict_util.py index 277dc252..3baea4e3 100644 --- a/tavern/_core/dict_util.py +++ b/tavern/_core/dict_util.py @@ -1,4 +1,5 @@ import contextlib +import functools import logging import os import re @@ -91,21 +92,34 @@ def _attempt_find_include(to_format: str, box_vars: box.Box): return formatter.convert_field(would_replace, conversion) # type: ignore -def format_keys(val, variables: Mapping, no_double_format: bool = True): +def format_keys( + val, + variables: Mapping, + *, + no_double_format: bool = True, + dangerously_ignore_string_format_errors: bool = False, +): """recursively format a dictionary with the given values Args: - val (object): Input dictionary to format - variables (dict): Dictionary of keys to format it with - no_double_format (bool): Whether to use the 'inner formatted string' class to avoid double formatting + val: Input dictionary to format + variables: Dictionary of keys to format it with + no_double_format: Whether to use the 'inner formatted string' class to avoid double formatting This is required if passing something via pytest-xdist, such as markers: https://github.com/taverntesting/tavern/issues/431 + dangerously_ignore_string_format_errors: whether to ignore any string formatting errors. This will result + in broken output, only use for debugging purposes. Returns: str,int,list,dict: recursively formatted values """ formatted = val + format_keys_ = functools.partial( + format_keys, + dangerously_ignore_string_format_errors=dangerously_ignore_string_format_errors, + ) + if not isinstance(variables, Box): box_vars = Box(variables) else: @@ -115,13 +129,17 @@ def format_keys(val, variables: Mapping, no_double_format: bool = True): formatted = {} # formatted = {key: format_keys(val[key], box_vars) for key in val} for key in val: - formatted[key] = format_keys(val[key], box_vars) + formatted[key] = format_keys_(val[key], box_vars) elif isinstance(val, (list, tuple)): - formatted = [format_keys(item, box_vars) for item in val] + formatted = [format_keys_(item, box_vars) for item in val] elif isinstance(formatted, FormattedString): logger.debug("Already formatted %s, not double-formatting", formatted) elif isinstance(val, str): - formatted = _check_and_format_values(val, box_vars) + try: + formatted = _check_and_format_values(val, box_vars) + except exceptions.MissingFormatError: + if not dangerously_ignore_string_format_errors: + raise if no_double_format: formatted = FormattedString(formatted) @@ -130,7 +148,7 @@ def format_keys(val, variables: Mapping, no_double_format: bool = True): if isinstance(val, ForceIncludeToken): formatted = _attempt_find_include(val.value, box_vars) else: - value = format_keys(val.value, box_vars) + value = format_keys_(val.value, box_vars) formatted = val.constructor(value) else: logger.debug("Not formatting something of type '%s'", type(formatted)) diff --git a/tavern/_core/pytest/error.py b/tavern/_core/pytest/error.py index e63677f2..6b5f12ad 100644 --- a/tavern/_core/pytest/error.py +++ b/tavern/_core/pytest/error.py @@ -152,7 +152,9 @@ def _print_formatted_stage(self, tw: TerminalWriter, stage: Mapping) -> None: keys = self._get_available_format_keys() # Format stage variables recursively - formatted_stage = format_keys(stage, keys) + formatted_stage = format_keys( + stage, keys, dangerously_ignore_string_format_errors=True + ) # Replace formatted strings with strings for dumping formatted_stage = prepare_yaml(formatted_stage) diff --git a/tests/integration/881_1.json b/tests/integration/881_1.json new file mode 100644 index 00000000..64ffa49a --- /dev/null +++ b/tests/integration/881_1.json @@ -0,0 +1,3 @@ +{ + "{enclosed-in-key}": "sample" +} \ No newline at end of file diff --git a/tests/integration/881_2.yaml b/tests/integration/881_2.yaml new file mode 100644 index 00000000..b755e68c --- /dev/null +++ b/tests/integration/881_2.yaml @@ -0,0 +1 @@ +{ "sample": !raw "{enclosed-in-value}" } diff --git a/tests/integration/test_include.tavern.yaml b/tests/integration/test_include.tavern.yaml new file mode 100644 index 00000000..4e2d45c7 --- /dev/null +++ b/tests/integration/test_include.tavern.yaml @@ -0,0 +1,65 @@ +--- +test_name: Test including json + +includes: + - !include common.yaml + +stages: + - name: Send included json + request: + url: "{host}/echo" + method: POST + json: !include 881_1.json + response: + status_code: 200 + json: !include 881_1.json + +--- +test_name: Test including json with key + +includes: + - !include common.yaml + +stages: + - name: Send included json + request: + url: "{host}/echo" + method: POST + json: !include 881_2.yaml + response: + status_code: 200 + json: !include 881_2.yaml + +--- +test_name: Test including json with error + +includes: + - !include common.yaml + +stages: + - name: Send included json + request: + url: "{host}/echo" + method: POST + json: !include 881_1.json + response: + status_code: 201 + +_xfail: run + +--- +test_name: Test including json with error and key + +includes: + - !include common.yaml + +stages: + - name: Send included json + request: + url: "{host}/echo" + method: POST + json: !include 881_2.yaml + response: + status_code: 201 + +_xfail: run From ea553ba261de7daf4a0997a6eec9070f9000df82 Mon Sep 17 00:00:00 2001 From: Michael Boulton Date: Mon, 18 Sep 2023 14:46:13 +0100 Subject: [PATCH 16/25] Bump to 2.3.1 --- CHANGELOG.md | 2 ++ docs/source/conf.py | 2 +- pyproject.toml | 4 ++-- tavern/__init__.py | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 467b58d4..d6e356ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -412,3 +412,5 @@ This is technically not a operational change but I'm adding a new tag so it can # 2.2.0 Allow wildcards in MQTT topics (2023-06-25) ## 2.2.1 Update some dependencies (2023-07-30) + +# 2.3.0 Add 'finally' block (2023-08-05) diff --git a/docs/source/conf.py b/docs/source/conf.py index bc501023..4a59b930 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -73,7 +73,7 @@ # The short X.Y version. version = "1.0" # The full version, including alpha/beta/rc tags. -release = "2.3.0" +release = "2.3.1" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index 7b961ff8..a2654132 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ keywords = ["testing", "pytest"] name = "tavern" description = "Simple testing of RESTful APIs" -version = "2.3.0" +version = "2.3.1" dependencies = [ "PyYAML>=6.0.1,<7", @@ -158,7 +158,7 @@ target-version = "py38" known-first-party = ["tavern"] [tool.tbump.version] -current = "2.3.0" +current = "2.3.1" regex = ''' (?P\d+) diff --git a/tavern/__init__.py b/tavern/__init__.py index 9213d18a..315260ee 100644 --- a/tavern/__init__.py +++ b/tavern/__init__.py @@ -1,2 +1,2 @@ """Stop pytest warning about module already imported: PYTEST_DONT_REWRITE""" -__version__ = "2.3.0" +__version__ = "2.3.1" From ac3c07a272a4f50d63c4f66552c23c7968464c82 Mon Sep 17 00:00:00 2001 From: michaelboulton Date: Mon, 18 Sep 2023 15:49:45 +0100 Subject: [PATCH 17/25] Allow using an ext function to create the URL (#885) --- tavern/_core/schema/tests.jsonschema.yaml | 7 +++++- tavern/_plugins/rest/request.py | 2 +- tests/integration/conftest.py | 5 ++++ tests/integration/ext_functions.py | 4 +++ .../test_external_functions.tavern.yaml | 25 +++++++++++++++++++ tests/integration/test_fixtures.tavern.yaml | 19 ++++++++++++++ 6 files changed, 60 insertions(+), 2 deletions(-) diff --git a/tavern/_core/schema/tests.jsonschema.yaml b/tavern/_core/schema/tests.jsonschema.yaml index decb652a..84a0899c 100644 --- a/tavern/_core/schema/tests.jsonschema.yaml +++ b/tavern/_core/schema/tests.jsonschema.yaml @@ -77,8 +77,13 @@ definitions: properties: url: - type: string description: URL to make request to + oneOf: + - type: string + - type: object + properties: + "$ext": + $ref: "#/definitions/verify_block" cert: description: Certificate to use - either a path to a certificate and key in one file, or a two item list containing the certificate and key separately diff --git a/tavern/_plugins/rest/request.py b/tavern/_plugins/rest/request.py index 77d55914..8d81d773 100644 --- a/tavern/_plugins/rest/request.py +++ b/tavern/_plugins/rest/request.py @@ -390,7 +390,7 @@ def __init__( request_args = get_request_args(rspec, test_block_config) update_from_ext( request_args, - RestRequest.optional_in_file, + RestRequest.optional_in_file + ["url"], ) # Used further down, but pop it asap to avoid unwanted side effects diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index a7461c1d..30779166 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -23,6 +23,11 @@ def autouse_thing(): return "abc" +@pytest.fixture(scope="session", autouse=True) +def fixture_echo_url(): + return "http://localhost:5003/echo" + + @pytest.fixture(scope="session", autouse=True, name="autouse_thing_named") def second(autouse_thing): return autouse_thing diff --git a/tests/integration/ext_functions.py b/tests/integration/ext_functions.py index 5c28e5fb..fbb23ab0 100644 --- a/tests/integration/ext_functions.py +++ b/tests/integration/ext_functions.py @@ -8,3 +8,7 @@ def return_goodbye_string(): def return_list_vals(): return [{"a_value": "b_value"}, 2] + + +def gen_echo_url(host): + return "{0}/echo".format(host) diff --git a/tests/integration/test_external_functions.tavern.yaml b/tests/integration/test_external_functions.tavern.yaml index bd4da169..08ea91ba 100644 --- a/tests/integration/test_external_functions.tavern.yaml +++ b/tests/integration/test_external_functions.tavern.yaml @@ -154,3 +154,28 @@ stages: json: top_level: nested: value + +--- +test_name: Test external function url + +includes: + - !include common.yaml + +stages: + - name: external function url + request: + url: + $ext: + function: ext_functions:gen_echo_url + extra_kwargs: + host: "{host}" + method: POST + json: + value1: "hi" + $ext: + function: ext_functions:return_hello + response: + status_code: 200 + json: + value1: "hi" + hello: "there" diff --git a/tests/integration/test_fixtures.tavern.yaml b/tests/integration/test_fixtures.tavern.yaml index db4422f4..6d6f8bd1 100644 --- a/tests/integration/test_fixtures.tavern.yaml +++ b/tests/integration/test_fixtures.tavern.yaml @@ -116,6 +116,7 @@ stages: status_code: 200 json: value: "{yield_str_fixture}" + --- test_name: Test autouse fixture @@ -133,3 +134,21 @@ stages: status_code: 200 json: value: "{autouse_thing_named}" + +--- +test_name: Test autouse fixture host + +includes: + - !include common.yaml + +stages: + - name: post json and expect it to be echoed + request: + url: "{fixture_echo_url}" + method: POST + json: + value: "hello" + response: + status_code: 200 + json: + value: "hello" From d6df02d8becb4c0a1b1b7390f7384b19295247bb Mon Sep 17 00:00:00 2001 From: Michael Boulton Date: Mon, 18 Sep 2023 15:50:23 +0100 Subject: [PATCH 18/25] Bump to 2.4.0 --- CHANGELOG.md | 2 ++ docs/source/conf.py | 2 +- pyproject.toml | 4 ++-- tavern/__init__.py | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6e356ee..1e3df920 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -414,3 +414,5 @@ This is technically not a operational change but I'm adding a new tag so it can ## 2.2.1 Update some dependencies (2023-07-30) # 2.3.0 Add 'finally' block (2023-08-05) + +## 2.3.1 Fix error formatting when including files with curly braces (2023-09-18) diff --git a/docs/source/conf.py b/docs/source/conf.py index 4a59b930..25ef071f 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -73,7 +73,7 @@ # The short X.Y version. version = "1.0" # The full version, including alpha/beta/rc tags. -release = "2.3.1" +release = "2.4.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index a2654132..42f485bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ keywords = ["testing", "pytest"] name = "tavern" description = "Simple testing of RESTful APIs" -version = "2.3.1" +version = "2.4.0" dependencies = [ "PyYAML>=6.0.1,<7", @@ -158,7 +158,7 @@ target-version = "py38" known-first-party = ["tavern"] [tool.tbump.version] -current = "2.3.1" +current = "2.4.0" regex = ''' (?P\d+) diff --git a/tavern/__init__.py b/tavern/__init__.py index 315260ee..231d8dc9 100644 --- a/tavern/__init__.py +++ b/tavern/__init__.py @@ -1,2 +1,2 @@ """Stop pytest warning about module already imported: PYTEST_DONT_REWRITE""" -__version__ = "2.3.1" +__version__ = "2.4.0" From 98d7316b7b94ddf412b7d046069f7894f4a25ba9 Mon Sep 17 00:00:00 2001 From: michaelboulton Date: Mon, 18 Sep 2023 16:29:03 +0100 Subject: [PATCH 19/25] Update docs builds (#886) --- .readthedocs.yaml | 15 + CONTRIBUTING.md | 7 + constraints.txt | 67 ++++- docs/source/conf.py | 2 +- docs/source/cookbook.md | 6 +- docs/source/requirements.txt | 7 - example/mqtt/README.md | 2 +- pyproject.toml | 7 + requirements.txt | 518 ++++++++++++++++++++--------------- tox-integration.ini | 10 +- 10 files changed, 394 insertions(+), 247 deletions(-) create mode 100644 .readthedocs.yaml delete mode 100644 docs/source/requirements.txt diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..26dde362 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,15 @@ +# Read the Docs configuration file for Sphinx projects +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/source/conf.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b145d4ce..2e20913d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -58,3 +58,10 @@ Run every so often to update the pre-commit hooks 1. Tag and push to git with `tbump --tag-message ""` 1. Upload to pypi with `flit publish` + +## Building the documentation + +```shell +mkdir -p dist/ +sphinx-build docs/source/ dist/ +``` \ No newline at end of file diff --git a/constraints.txt b/constraints.txt index 62354550..6ef035a3 100644 --- a/constraints.txt +++ b/constraints.txt @@ -1,9 +1,11 @@ # -# This file is autogenerated by pip-compile with Python 3.10 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile --all-extras --output-file=constraints.txt --resolver=backtracking --strip-extras pyproject.toml +# pip-compile --all-extras --output-file=constraints.txt --strip-extras pyproject.toml # +alabaster==0.7.13 + # via sphinx allure-pytest==2.13.2 # via tavern (pyproject.toml) allure-python-commons==2.13.2 @@ -13,6 +15,8 @@ attrs==23.1.0 # allure-python-commons # jsonschema # pytest +babel==2.12.1 + # via sphinx bleach==6.0.0 # via readme-renderer blinker==1.6.2 @@ -41,6 +45,10 @@ colorama==0.4.6 # via tox colorlog==6.7.0 # via tavern (pyproject.toml) +commonmark==0.9.1 + # via + # recommonmark + # tavern (pyproject.toml) coverage==7.2.7 # via # pytest-cov @@ -55,8 +63,9 @@ docutils==0.20.1 # via # flit # readme-renderer -exceptiongroup==1.1.1 - # via pytest + # recommonmark + # sphinx + # tavern (pyproject.toml) execnet==1.9.0 # via pytest-xdist faker==18.10.1 @@ -77,6 +86,8 @@ identify==2.5.24 # via pre-commit idna==3.4 # via requests +imagesize==1.4.1 + # via sphinx importlib-metadata==6.6.0 # via # keyring @@ -94,13 +105,17 @@ jeepney==0.8.0 # keyring # secretstorage jinja2==3.1.2 - # via flask + # via + # flask + # sphinx jmespath==1.0.1 # via tavern (pyproject.toml) jsonschema==3.2.0 # via tavern (pyproject.toml) keyring==23.13.1 # via twine +markdown==3.4.4 + # via sphinx-markdown-tables markdown-it-py==2.2.0 # via rich markupsafe==2.1.3 @@ -126,6 +141,7 @@ packaging==23.1 # build # pyproject-api # pytest + # sphinx # tox paho-mqtt==1.6.1 # via tavern (pyproject.toml) @@ -154,6 +170,7 @@ pygments==2.15.1 # via # readme-renderer # rich + # sphinx # tavern (pyproject.toml) pyjwt==2.7.0 # via tavern (pyproject.toml) @@ -187,10 +204,13 @@ pyyaml==6.0.1 # tavern (pyproject.toml) readme-renderer==37.3 # via twine +recommonmark==0.7.1 + # via tavern (pyproject.toml) requests==2.31.0 # via # flit # requests-toolbelt + # sphinx # tavern (pyproject.toml) # twine requests-toolbelt==1.0.0 @@ -210,17 +230,36 @@ six==1.16.0 # bleach # jsonschema # python-dateutil +snowballstemmer==2.2.0 + # via sphinx +sphinx==7.2.6 + # via + # recommonmark + # sphinx-rtd-theme + # sphinxcontrib-applehelp + # sphinxcontrib-devhelp + # sphinxcontrib-htmlhelp + # sphinxcontrib-qthelp + # sphinxcontrib-serializinghtml + # tavern (pyproject.toml) +sphinx-markdown-tables==0.0.17 + # via tavern (pyproject.toml) +sphinx-rtd-theme==0.5.1 + # via tavern (pyproject.toml) +sphinxcontrib-applehelp==1.0.7 + # via sphinx +sphinxcontrib-devhelp==1.0.5 + # via sphinx +sphinxcontrib-htmlhelp==2.0.4 + # via sphinx +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==1.0.6 + # via sphinx +sphinxcontrib-serializinghtml==1.1.9 + # via sphinx stevedore==4.1.1 # via tavern (pyproject.toml) -tomli==2.0.1 - # via - # build - # coverage - # mypy - # pyproject-api - # pyproject-hooks - # pytest - # tox tomli-w==1.0.0 # via flit tox==4.6.0 diff --git a/docs/source/conf.py b/docs/source/conf.py index 25ef071f..3e05c2cf 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -80,7 +80,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. diff --git a/docs/source/cookbook.md b/docs/source/cookbook.md index a48d9d9b..c6929a6d 100644 --- a/docs/source/cookbook.md +++ b/docs/source/cookbook.md @@ -30,7 +30,7 @@ RUN pip3 install tavern Build with: -```shell script +```shell docker build --file tavern.Dockerfile --tag tavern:latest . ``` @@ -44,7 +44,7 @@ ARG TAVERNVER RUN pip3 install tavern==$TAVERNVER ``` -```shell script +```shell export TAVERNVER=0.24.0 docker build --build-arg TAVERNVER=$TAVERNVER --file tavern.Dockerfile --tag tavern:$TAVERNVER . ``` @@ -56,7 +56,7 @@ does not take an incredibly long time to start up - see the documentation for information on how to create one. This can be used by running it on the command line with `docker run`, but -it is often easier to use it in a docker-compose file like this: +it is often easier to use it in a docker compose file like this: ```yaml --- diff --git a/docs/source/requirements.txt b/docs/source/requirements.txt deleted file mode 100644 index 6144b157..00000000 --- a/docs/source/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -sphinx==1.8.3 -sphinx_rtd_theme -recommonmark==0.5.0 -commonmark==0.8.1 -docutils==0.14 -pygments==2.7.4 -sphinx-markdown-tables==0.0.9 diff --git a/example/mqtt/README.md b/example/mqtt/README.md index 59d75915..99d319f8 100644 --- a/example/mqtt/README.md +++ b/example/mqtt/README.md @@ -13,6 +13,6 @@ The server queries this database when a `GET` request is made to `/get_device_state` and returns whether the lights are on or off. The tavern test file includes examples of how to test such a setup, using the -keys `mqtt_publish` and `mqtt_response`. Run `docker-compose up --build` in one +keys `mqtt_publish` and `mqtt_response`. Run `docker compose up --build` in one terminal and run `py.test` in another terminal, and output from the mosquitto MQTT broker, the server, and the listener will be shown inline. diff --git a/pyproject.toml b/pyproject.toml index 42f485bb..d00691f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,6 +78,13 @@ dev = [ "types-PyYAML", "types-setuptools", "types-requests", + "sphinx>=7,<8", + "sphinx_rtd_theme", + "recommonmark", + "commonmark", + "docutils", + "pygments", + "sphinx-markdown-tables", # This has to be installed separately, otherwise you can't upload to pypi # "tbump@https://github.com/michaelboulton/tbump/archive/714ba8957a3c84b625608ceca39811ebe56229dc.zip", ] diff --git a/requirements.txt b/requirements.txt index 3f1d4d6a..45239f40 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,13 @@ # -# This file is autogenerated by pip-compile with Python 3.10 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile --all-extras --generate-hashes --output-file=requirements.txt --resolver=backtracking pyproject.toml +# pip-compile --all-extras --generate-hashes --output-file=requirements.txt pyproject.toml # +alabaster==0.7.13 \ + --hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \ + --hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2 + # via sphinx allure-pytest==2.13.2 \ --hash=sha256:17de9dbee7f61c8e66a5b5e818b00e419dbcea44cb55c24319401ba813220690 \ --hash=sha256:22243159e8ec81ce2b5254b4013802198821b1b42f118f69d4a289396607c7b3 @@ -19,17 +23,17 @@ attrs==23.1.0 \ # allure-python-commons # jsonschema # pytest -bleach==6.0.0 \ - --hash=sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414 \ - --hash=sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4 - # via readme-renderer +babel==2.12.1 \ + --hash=sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610 \ + --hash=sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455 + # via sphinx blinker==1.6.2 \ --hash=sha256:4afd3de66ef3a9f8067559fb7a1cbe555c17dcbe15971b05d1b625c3e7abe213 \ --hash=sha256:c3d739772abb7bc2860abf5f2ec284223d9ad5c76da018234f6f50d6f31ab1f0 # via flask -build==0.10.0 \ - --hash=sha256:af266720050a66c893a6096a2f410989eeac74ff9a68ba194b3f6473e8e26171 \ - --hash=sha256:d5b71264afdb5951d6704482aac78de887c80691c52b88a9ad195983ca2c9269 +build==1.0.3 \ + --hash=sha256:538aab1b64f9828977f84bc63ae570b060a8ed1be419e7870b8b4fc5e6ea553b \ + --hash=sha256:589bf99a67df7c9cf07ec0ac0e5e2ea5d4b37ac63301c4986d1acb126aa83f8f # via pip-tools bump2version==1.0.1 \ --hash=sha256:37f927ea17cde7ae2d7baf832f8e80ce3777624554a653006c9144f8017fe410 \ @@ -109,13 +113,13 @@ cffi==1.15.1 \ --hash=sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01 \ --hash=sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0 # via cryptography -cfgv==3.3.1 \ - --hash=sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426 \ - --hash=sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736 +cfgv==3.4.0 \ + --hash=sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9 \ + --hash=sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560 # via pre-commit -chardet==5.1.0 \ - --hash=sha256:0d62712b956bc154f85fb0a266e2a3c5913c2967e00348701b32411d6def31e5 \ - --hash=sha256:362777fb014af596ad31334fde1e8c327dfdb076e1960d1694662d46a6917ab9 +chardet==5.2.0 \ + --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \ + --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970 # via tox charset-normalizer==3.1.0 \ --hash=sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6 \ @@ -194,9 +198,9 @@ charset-normalizer==3.1.0 \ --hash=sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df \ --hash=sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab # via requests -click==8.1.3 \ - --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ - --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48 +click==8.1.7 \ + --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \ + --hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de # via # flask # pip-tools @@ -208,67 +212,65 @@ colorlog==6.7.0 \ --hash=sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662 \ --hash=sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5 # via tavern (pyproject.toml) -coverage[toml]==7.2.7 \ - --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ - --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ - --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ - --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ - --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ - --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ - --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ - --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ - --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ - --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ - --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ - --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ - --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ - --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ - --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ - --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ - --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ - --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ - --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ - --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ - --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ - --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ - --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ - --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ - --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ - --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ - --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ - --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ - --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ - --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ - --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ - --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ - --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ - --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ - --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ - --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ - --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ - --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ - --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ - --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ - --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ - --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ - --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ - --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ - --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ - --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ - --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ - --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ - --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ - --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ - --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ - --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ - --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ - --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ - --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ - --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ - --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ - --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ - --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ - --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 +commonmark==0.9.1 \ + --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ + --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 + # via + # recommonmark + # tavern (pyproject.toml) +coverage[toml]==7.3.1 \ + --hash=sha256:025ded371f1ca280c035d91b43252adbb04d2aea4c7105252d3cbc227f03b375 \ + --hash=sha256:04312b036580ec505f2b77cbbdfb15137d5efdfade09156961f5277149f5e344 \ + --hash=sha256:0575c37e207bb9b98b6cf72fdaaa18ac909fb3d153083400c2d48e2e6d28bd8e \ + --hash=sha256:07d156269718670d00a3b06db2288b48527fc5f36859425ff7cec07c6b367745 \ + --hash=sha256:1f111a7d85658ea52ffad7084088277135ec5f368457275fc57f11cebb15607f \ + --hash=sha256:220eb51f5fb38dfdb7e5d54284ca4d0cd70ddac047d750111a68ab1798945194 \ + --hash=sha256:229c0dd2ccf956bf5aeede7e3131ca48b65beacde2029f0361b54bf93d36f45a \ + --hash=sha256:245c5a99254e83875c7fed8b8b2536f040997a9b76ac4c1da5bff398c06e860f \ + --hash=sha256:2829c65c8faaf55b868ed7af3c7477b76b1c6ebeee99a28f59a2cb5907a45760 \ + --hash=sha256:4aba512a15a3e1e4fdbfed2f5392ec221434a614cc68100ca99dcad7af29f3f8 \ + --hash=sha256:4c96dd7798d83b960afc6c1feb9e5af537fc4908852ef025600374ff1a017392 \ + --hash=sha256:50dd1e2dd13dbbd856ffef69196781edff26c800a74f070d3b3e3389cab2600d \ + --hash=sha256:5289490dd1c3bb86de4730a92261ae66ea8d44b79ed3cc26464f4c2cde581fbc \ + --hash=sha256:53669b79f3d599da95a0afbef039ac0fadbb236532feb042c534fbb81b1a4e40 \ + --hash=sha256:553d7094cb27db58ea91332e8b5681bac107e7242c23f7629ab1316ee73c4981 \ + --hash=sha256:586649ada7cf139445da386ab6f8ef00e6172f11a939fc3b2b7e7c9082052fa0 \ + --hash=sha256:5ae4c6da8b3d123500f9525b50bf0168023313963e0e2e814badf9000dd6ef92 \ + --hash=sha256:5b4ee7080878077af0afa7238df1b967f00dc10763f6e1b66f5cced4abebb0a3 \ + --hash=sha256:5d991e13ad2ed3aced177f524e4d670f304c8233edad3210e02c465351f785a0 \ + --hash=sha256:614f1f98b84eb256e4f35e726bfe5ca82349f8dfa576faabf8a49ca09e630086 \ + --hash=sha256:636a8ac0b044cfeccae76a36f3b18264edcc810a76a49884b96dd744613ec0b7 \ + --hash=sha256:6407424621f40205bbe6325686417e5e552f6b2dba3535dd1f90afc88a61d465 \ + --hash=sha256:6bc6f3f4692d806831c136c5acad5ccedd0262aa44c087c46b7101c77e139140 \ + --hash=sha256:6cb7fe1581deb67b782c153136541e20901aa312ceedaf1467dcb35255787952 \ + --hash=sha256:74bb470399dc1989b535cb41f5ca7ab2af561e40def22d7e188e0a445e7639e3 \ + --hash=sha256:75c8f0df9dfd8ff745bccff75867d63ef336e57cc22b2908ee725cc552689ec8 \ + --hash=sha256:770f143980cc16eb601ccfd571846e89a5fe4c03b4193f2e485268f224ab602f \ + --hash=sha256:7eb0b188f30e41ddd659a529e385470aa6782f3b412f860ce22b2491c89b8593 \ + --hash=sha256:7eb3cd48d54b9bd0e73026dedce44773214064be93611deab0b6a43158c3d5a0 \ + --hash=sha256:87d38444efffd5b056fcc026c1e8d862191881143c3aa80bb11fcf9dca9ae204 \ + --hash=sha256:8a07b692129b8a14ad7a37941a3029c291254feb7a4237f245cfae2de78de037 \ + --hash=sha256:966f10df9b2b2115da87f50f6a248e313c72a668248be1b9060ce935c871f276 \ + --hash=sha256:a6191b3a6ad3e09b6cfd75b45c6aeeffe7e3b0ad46b268345d159b8df8d835f9 \ + --hash=sha256:aab8e9464c00da5cb9c536150b7fbcd8850d376d1151741dd0d16dfe1ba4fd26 \ + --hash=sha256:ac3c5b7e75acac31e490b7851595212ed951889918d398b7afa12736c85e13ce \ + --hash=sha256:ac9ad38204887349853d7c313f53a7b1c210ce138c73859e925bc4e5d8fc18e7 \ + --hash=sha256:b9c0c19f70d30219113b18fe07e372b244fb2a773d4afde29d5a2f7930765136 \ + --hash=sha256:c397c70cd20f6df7d2a52283857af622d5f23300c4ca8e5bd8c7a543825baa5a \ + --hash=sha256:c6601a60318f9c3945be6ea0f2a80571f4299b6801716f8a6e4846892737ebe4 \ + --hash=sha256:c6f55d38818ca9596dc9019eae19a47410d5322408140d9a0076001a3dcb938c \ + --hash=sha256:ca70466ca3a17460e8fc9cea7123c8cbef5ada4be3140a1ef8f7b63f2f37108f \ + --hash=sha256:ca833941ec701fda15414be400c3259479bfde7ae6d806b69e63b3dc423b1832 \ + --hash=sha256:cd0f7429ecfd1ff597389907045ff209c8fdb5b013d38cfa7c60728cb484b6e3 \ + --hash=sha256:cd694e19c031733e446c8024dedd12a00cda87e1c10bd7b8539a87963685e969 \ + --hash=sha256:cdd088c00c39a27cfa5329349cc763a48761fdc785879220d54eb785c8a38520 \ + --hash=sha256:de30c1aa80f30af0f6b2058a91505ea6e36d6535d437520067f525f7df123887 \ + --hash=sha256:defbbb51121189722420a208957e26e49809feafca6afeef325df66c39c4fdb3 \ + --hash=sha256:f09195dda68d94a53123883de75bb97b0e35f5f6f9f3aa5bf6e496da718f0cb6 \ + --hash=sha256:f12d8b11a54f32688b165fd1a788c408f927b0960984b899be7e4c190ae758f1 \ + --hash=sha256:f1a317fdf5c122ad642db8a97964733ab7c3cf6009e1a8ae8821089993f175ff \ + --hash=sha256:f2781fd3cabc28278dc982a352f50c81c09a1a500cc2086dc4249853ea96b981 \ + --hash=sha256:f4f456590eefb6e1b3c9ea6328c1e9fa0f1006e7481179d749b3376fc793478e # via # pytest-cov # tavern (pyproject.toml) @@ -297,40 +299,40 @@ cryptography==41.0.3 \ --hash=sha256:ce785cf81a7bdade534297ef9e490ddff800d956625020ab2ec2780a556c313e \ --hash=sha256:d0d651aa754ef58d75cec6edfbd21259d93810b73f6ec246436a21b7841908de # via secretstorage -distlib==0.3.6 \ - --hash=sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46 \ - --hash=sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e +distlib==0.3.7 \ + --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \ + --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8 # via virtualenv docopt==0.6.2 \ --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491 # via pykwalify -docutils==0.20.1 \ - --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \ - --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b +docutils==0.18.1 \ + --hash=sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c \ + --hash=sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06 # via # flit # readme-renderer -exceptiongroup==1.1.1 \ - --hash=sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e \ - --hash=sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785 - # via pytest -execnet==1.9.0 \ - --hash=sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5 \ - --hash=sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142 + # recommonmark + # sphinx + # sphinx-rtd-theme + # tavern (pyproject.toml) +execnet==2.0.2 \ + --hash=sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41 \ + --hash=sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af # via pytest-xdist -faker==18.10.1 \ - --hash=sha256:633b278caa3ec239463f9139c74da2607c8da5710e56d5d7d30fc8a7440104c4 \ - --hash=sha256:d9f363720c4a6cf9884c6c3e26e2ce26266ffe5d741a9bc7cb9256779bc62190 +faker==19.6.1 \ + --hash=sha256:5d6b7880b3bea708075ddf91938424453f07053a59f8fa0453c1870df6ff3292 \ + --hash=sha256:64c8513c53c3a809075ee527b323a0ba61517814123f3137e4912f5d43350139 # via tavern (pyproject.toml) -filelock==3.12.0 \ - --hash=sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9 \ - --hash=sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718 +filelock==3.12.4 \ + --hash=sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4 \ + --hash=sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd # via # tox # virtualenv -flask==2.3.2 \ - --hash=sha256:77fd4e1249d8c9923de34907236b747ced06e5467ecac1a7bb7115ae0e9670b0 \ - --hash=sha256:8c2f9abd47a9e8df7f0c3f091ce9497d011dc3b31effcf4c85a6e2b50f4114ef +flask==2.3.3 \ + --hash=sha256:09c347a92aa7ff4a8e7f3206795f30d826654baf38b873d0744cd571ca609efc \ + --hash=sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b # via tavern (pyproject.toml) flit==3.9.0 \ --hash=sha256:076c3aaba5ac24cf0ad3251f910900d95a08218e6bcb26f21fef1036cc4679ca \ @@ -344,17 +346,21 @@ fluent-logger==0.10.0 \ --hash=sha256:543637e5e62ec3fc3c92b44e5a4e148a3cea88a0f8ca4fae26c7e60fda7564c1 \ --hash=sha256:678bda90c513ff0393964b64544ce41ef25669d2089ce6c3b63d9a18554b9bfa # via tavern (pyproject.toml) -identify==2.5.24 \ - --hash=sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4 \ - --hash=sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d +identify==2.5.29 \ + --hash=sha256:24437fbf6f4d3fe6efd0eb9d67e24dd9106db99af5ceb27996a5f7895f24bf1b \ + --hash=sha256:d43d52b86b15918c137e3a74fff5224f60385cd0e9c38e99d07c257f02f151a5 # via pre-commit idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 # via requests -importlib-metadata==6.6.0 \ - --hash=sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed \ - --hash=sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705 +imagesize==1.4.1 \ + --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \ + --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a + # via sphinx +importlib-metadata==6.8.0 \ + --hash=sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb \ + --hash=sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743 # via # keyring # twine @@ -368,9 +374,9 @@ itsdangerous==2.1.2 \ # via # flask # tavern (pyproject.toml) -jaraco-classes==3.2.3 \ - --hash=sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158 \ - --hash=sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a +jaraco-classes==3.3.0 \ + --hash=sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb \ + --hash=sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621 # via keyring jeepney==0.8.0 \ --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ @@ -381,7 +387,9 @@ jeepney==0.8.0 \ jinja2==3.1.2 \ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 - # via flask + # via + # flask + # sphinx jmespath==1.0.1 \ --hash=sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980 \ --hash=sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe @@ -390,21 +398,28 @@ jsonschema==3.2.0 \ --hash=sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163 \ --hash=sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a # via tavern (pyproject.toml) -keyring==23.13.1 \ - --hash=sha256:771ed2a91909389ed6148631de678f82ddc73737d85a927f382a8a1b157898cd \ - --hash=sha256:ba2e15a9b35e21908d0aaf4e0a47acc52d6ae33444df0da2b49d41a46ef6d678 +keyring==24.2.0 \ + --hash=sha256:4901caaf597bfd3bbd78c9a0c7c4c29fcd8310dab2cffefe749e916b6527acd6 \ + --hash=sha256:ca0746a19ec421219f4d713f848fa297a661a8a8c1504867e55bfb5e09091509 # via twine -markdown-it-py==2.2.0 \ - --hash=sha256:5a35f8d1870171d9acc47b99612dc146129b631baf04970128b568f190d0cc30 \ - --hash=sha256:7c9a5e412688bc771c67432cbfebcdd686c93ce6484913dccf06cb5a0bea35a1 +markdown==3.4.4 \ + --hash=sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6 \ + --hash=sha256:a4c1b65c0957b4bd9e7d86ddc7b3c9868fb9670660f6f99f6d1bca8954d5a941 + # via sphinx-markdown-tables +markdown-it-py==3.0.0 \ + --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ + --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb # via rich markupsafe==2.1.3 \ --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \ --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \ --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \ --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \ + --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \ --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \ --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \ + --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \ + --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \ --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \ --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \ --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \ @@ -412,6 +427,7 @@ markupsafe==2.1.3 \ --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \ --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \ --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \ + --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \ --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \ --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \ --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \ @@ -420,6 +436,7 @@ markupsafe==2.1.3 \ --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \ --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \ --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \ + --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \ --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \ --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \ --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \ @@ -427,9 +444,12 @@ markupsafe==2.1.3 \ --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \ --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \ --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \ + --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \ --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \ --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \ + --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \ --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \ + --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \ --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \ --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \ --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \ @@ -448,7 +468,9 @@ markupsafe==2.1.3 \ --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \ --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \ --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \ - --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 + --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \ + --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \ + --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11 # via # jinja2 # werkzeug @@ -456,9 +478,9 @@ mdurl==0.1.2 \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba # via markdown-it-py -more-itertools==9.1.0 \ - --hash=sha256:cabaa341ad0389ea83c17a94566a53ae4c9d07349861ecb14dc6d0345cf9ac5d \ - --hash=sha256:d2bc7f02446e86a68911e58ded76d6561eea00cddfb2a91e7019bbb586c799f3 +more-itertools==10.1.0 \ + --hash=sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a \ + --hash=sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6 # via jaraco-classes msgpack==1.0.5 \ --hash=sha256:06f5174b5f8ed0ed919da0e62cbd4ffde676a374aba4020034da05fab67b9164 \ @@ -525,33 +547,34 @@ msgpack==1.0.5 \ --hash=sha256:f933bbda5a3ee63b8834179096923b094b76f0c7a73c1cfe8f07ad608c58844b \ --hash=sha256:fe5c63197c55bce6385d9aee16c4d0641684628f63ace85f73571e65ad1c1e8d # via fluent-logger -mypy==1.3.0 \ - --hash=sha256:1c4c42c60a8103ead4c1c060ac3cdd3ff01e18fddce6f1016e08939647a0e703 \ - --hash=sha256:44797d031a41516fcf5cbfa652265bb994e53e51994c1bd649ffcd0c3a7eccbf \ - --hash=sha256:473117e310febe632ddf10e745a355714e771ffe534f06db40702775056614c4 \ - --hash=sha256:4c99c3ecf223cf2952638da9cd82793d8f3c0c5fa8b6ae2b2d9ed1e1ff51ba85 \ - --hash=sha256:550a8b3a19bb6589679a7c3c31f64312e7ff482a816c96e0cecec9ad3a7564dd \ - --hash=sha256:658fe7b674769a0770d4b26cb4d6f005e88a442fe82446f020be8e5f5efb2fae \ - --hash=sha256:6e33bb8b2613614a33dff70565f4c803f889ebd2f859466e42b46e1df76018dd \ - --hash=sha256:6e42d29e324cdda61daaec2336c42512e59c7c375340bd202efa1fe0f7b8f8ca \ - --hash=sha256:74bc9b6e0e79808bf8678d7678b2ae3736ea72d56eede3820bd3849823e7f305 \ - --hash=sha256:76ec771e2342f1b558c36d49900dfe81d140361dd0d2df6cd71b3db1be155409 \ - --hash=sha256:7d23370d2a6b7a71dc65d1266f9a34e4cde9e8e21511322415db4b26f46f6b8c \ - --hash=sha256:87df44954c31d86df96c8bd6e80dfcd773473e877ac6176a8e29898bfb3501cb \ - --hash=sha256:8c5979d0deb27e0f4479bee18ea0f83732a893e81b78e62e2dda3e7e518c92ee \ - --hash=sha256:95d8d31a7713510685b05fbb18d6ac287a56c8f6554d88c19e73f724a445448a \ - --hash=sha256:a22435632710a4fcf8acf86cbd0d69f68ac389a3892cb23fbad176d1cddaf228 \ - --hash=sha256:a8763e72d5d9574d45ce5881962bc8e9046bf7b375b0abf031f3e6811732a897 \ - --hash=sha256:c1eb485cea53f4f5284e5baf92902cd0088b24984f4209e25981cc359d64448d \ - --hash=sha256:c5d2cc54175bab47011b09688b418db71403aefad07cbcd62d44010543fc143f \ - --hash=sha256:cbc07246253b9e3d7d74c9ff948cd0fd7a71afcc2b77c7f0a59c26e9395cb152 \ - --hash=sha256:d0b6c62206e04061e27009481cb0ec966f7d6172b5b936f3ead3d74f29fe3dcf \ - --hash=sha256:ddae0f39ca146972ff6bb4399f3b2943884a774b8771ea0a8f50e971f5ea5ba8 \ - --hash=sha256:e1f4d16e296f5135624b34e8fb741eb0eadedca90862405b1f1fde2040b9bd11 \ - --hash=sha256:e86c2c6852f62f8f2b24cb7a613ebe8e0c7dc1402c61d36a609174f63e0ff017 \ - --hash=sha256:ebc95f8386314272bbc817026f8ce8f4f0d2ef7ae44f947c4664efac9adec929 \ - --hash=sha256:f9dca1e257d4cc129517779226753dbefb4f2266c4eaad610fc15c6a7e14283e \ - --hash=sha256:faff86aa10c1aa4a10e1a301de160f3d8fc8703b88c7e98de46b531ff1276a9a +mypy==1.5.1 \ + --hash=sha256:159aa9acb16086b79bbb0016145034a1a05360626046a929f84579ce1666b315 \ + --hash=sha256:258b22210a4a258ccd077426c7a181d789d1121aca6db73a83f79372f5569ae0 \ + --hash=sha256:26f71b535dfc158a71264e6dc805a9f8d2e60b67215ca0bfa26e2e1aa4d4d373 \ + --hash=sha256:26fb32e4d4afa205b24bf645eddfbb36a1e17e995c5c99d6d00edb24b693406a \ + --hash=sha256:2fc3a600f749b1008cc75e02b6fb3d4db8dbcca2d733030fe7a3b3502902f161 \ + --hash=sha256:32cb59609b0534f0bd67faebb6e022fe534bdb0e2ecab4290d683d248be1b275 \ + --hash=sha256:330857f9507c24de5c5724235e66858f8364a0693894342485e543f5b07c8693 \ + --hash=sha256:361da43c4f5a96173220eb53340ace68cda81845cd88218f8862dfb0adc8cddb \ + --hash=sha256:4a465ea2ca12804d5b34bb056be3a29dc47aea5973b892d0417c6a10a40b2d65 \ + --hash=sha256:51cb1323064b1099e177098cb939eab2da42fea5d818d40113957ec954fc85f4 \ + --hash=sha256:57b10c56016adce71fba6bc6e9fd45d8083f74361f629390c556738565af8eeb \ + --hash=sha256:596fae69f2bfcb7305808c75c00f81fe2829b6236eadda536f00610ac5ec2243 \ + --hash=sha256:5d627124700b92b6bbaa99f27cbe615c8ea7b3402960f6372ea7d65faf376c14 \ + --hash=sha256:6ac9c21bfe7bc9f7f1b6fae441746e6a106e48fc9de530dea29e8cd37a2c0cc4 \ + --hash=sha256:82cb6193de9bbb3844bab4c7cf80e6227d5225cc7625b068a06d005d861ad5f1 \ + --hash=sha256:8f772942d372c8cbac575be99f9cc9d9fb3bd95c8bc2de6c01411e2c84ebca8a \ + --hash=sha256:9fece120dbb041771a63eb95e4896791386fe287fefb2837258925b8326d6160 \ + --hash=sha256:a156e6390944c265eb56afa67c74c0636f10283429171018446b732f1a05af25 \ + --hash=sha256:a9ec1f695f0c25986e6f7f8778e5ce61659063268836a38c951200c57479cc12 \ + --hash=sha256:abed92d9c8f08643c7d831300b739562b0a6c9fcb028d211134fc9ab20ccad5d \ + --hash=sha256:b031b9601f1060bf1281feab89697324726ba0c0bae9d7cd7ab4b690940f0b92 \ + --hash=sha256:c543214ffdd422623e9fedd0869166c2f16affe4ba37463975043ef7d2ea8770 \ + --hash=sha256:d28ddc3e3dfeab553e743e532fb95b4e6afad51d4706dd22f28e1e5e664828d2 \ + --hash=sha256:f33592ddf9655a4894aef22d134de7393e95fcbdc2d15c1ab65828eee5c66c70 \ + --hash=sha256:f6b0e77db9ff4fda74de7df13f30016a0a663928d669c9f2c057048ba44f09bb \ + --hash=sha256:f757063a83970d67c444f6e01d9550a7402322af3557ce7630d3c957386fa8f5 \ + --hash=sha256:ff0cedc84184115202475bbb46dd99f8dcb87fe24d5d0ddfc0fe6b8575c88d2f # via tavern (pyproject.toml) mypy-extensions==1.0.0 \ --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \ @@ -559,6 +582,24 @@ mypy-extensions==1.0.0 \ # via # mypy # tavern (pyproject.toml) +nh3==0.2.14 \ + --hash=sha256:116c9515937f94f0057ef50ebcbcc10600860065953ba56f14473ff706371873 \ + --hash=sha256:18415df36db9b001f71a42a3a5395db79cf23d556996090d293764436e98e8ad \ + --hash=sha256:203cac86e313cf6486704d0ec620a992c8bc164c86d3a4fd3d761dd552d839b5 \ + --hash=sha256:2b0be5c792bd43d0abef8ca39dd8acb3c0611052ce466d0401d51ea0d9aa7525 \ + --hash=sha256:377aaf6a9e7c63962f367158d808c6a1344e2b4f83d071c43fbd631b75c4f0b2 \ + --hash=sha256:525846c56c2bcd376f5eaee76063ebf33cf1e620c1498b2a40107f60cfc6054e \ + --hash=sha256:5529a3bf99402c34056576d80ae5547123f1078da76aa99e8ed79e44fa67282d \ + --hash=sha256:7771d43222b639a4cd9e341f870cee336b9d886de1ad9bec8dddab22fe1de450 \ + --hash=sha256:88c753efbcdfc2644a5012938c6b9753f1c64a5723a67f0301ca43e7b85dcf0e \ + --hash=sha256:93a943cfd3e33bd03f77b97baa11990148687877b74193bf777956b67054dcc6 \ + --hash=sha256:9be2f68fb9a40d8440cbf34cbf40758aa7f6093160bfc7fb018cce8e424f0c3a \ + --hash=sha256:a0c509894fd4dccdff557068e5074999ae3b75f4c5a2d6fb5415e782e25679c4 \ + --hash=sha256:ac8056e937f264995a82bf0053ca898a1cb1c9efc7cd68fa07fe0060734df7e4 \ + --hash=sha256:aed56a86daa43966dd790ba86d4b810b219f75b4bb737461b6886ce2bde38fd6 \ + --hash=sha256:e8986f1dd3221d1e741fda0a12eaa4a273f1d80a35e31a1ffe579e7c621d069e \ + --hash=sha256:f99212a81c62b5f22f9e7c3e347aa00491114a5647e1f13bbebd79c3e5f08d75 + # via readme-renderer nodeenv==1.8.0 \ --hash=sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2 \ --hash=sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec @@ -570,6 +611,7 @@ packaging==23.1 \ # build # pyproject-api # pytest + # sphinx # tox paho-mqtt==1.6.1 \ --hash=sha256:2a8291c81623aec00372b5a85558a372c747cbca8e9934dfe218638b8eefc26f @@ -578,17 +620,17 @@ pbr==5.11.1 \ --hash=sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b \ --hash=sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3 # via stevedore -pip-tools==6.13.0 \ - --hash=sha256:50943f151d87e752abddec8158622c34ad7f292e193836e90e30d87da60b19d9 \ - --hash=sha256:61d46bd2eb8016ed4a924e196e6e5b0a268cd3babd79e593048720db23522bb1 +pip-tools==7.3.0 \ + --hash=sha256:8717693288720a8c6ebd07149c93ab0be1fced0b5191df9e9decd3263e20d85e \ + --hash=sha256:8e9c99127fe024c025b46a0b2d15c7bd47f18f33226cf7330d35493663fc1d1d # via tavern (pyproject.toml) pkginfo==1.9.6 \ --hash=sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546 \ --hash=sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046 # via twine -platformdirs==3.5.1 \ - --hash=sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f \ - --hash=sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5 +platformdirs==3.10.0 \ + --hash=sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d \ + --hash=sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d # via # tox # virtualenv @@ -599,9 +641,9 @@ pluggy==1.0.0 \ # allure-python-commons # pytest # tox -pre-commit==3.3.2 \ - --hash=sha256:66e37bec2d882de1f17f88075047ef8962581f83c234ac08da21a0c58953d1f0 \ - --hash=sha256:8056bc52181efadf4aac792b1f4f255dfd2fb5a350ded7335d251a68561e8cb6 +pre-commit==3.4.0 \ + --hash=sha256:6bbd5129a64cad4c0dfaeeb12cd8f7ea7e15b77028d985341478c8af3c759522 \ + --hash=sha256:96d529a951f8b677f730a7212442027e8ba53f9b04d217c4c67dc56c393ad945 # via tavern (pyproject.toml) py==1.11.0 \ --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \ @@ -611,12 +653,13 @@ pycparser==2.21 \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 # via cffi -pygments==2.15.1 \ - --hash=sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c \ - --hash=sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1 +pygments==2.16.1 \ + --hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \ + --hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29 # via # readme-renderer # rich + # sphinx # tavern (pyproject.toml) pyjwt==2.7.0 \ --hash=sha256:ba2b425b15ad5ef12f200dc67dd56af4e26de2331f965c5439994dad075876e1 \ @@ -626,9 +669,9 @@ pykwalify==1.8.0 \ --hash=sha256:731dfa87338cca9f559d1fca2bdea37299116e3139b73f78ca90a543722d6651 \ --hash=sha256:796b2ad3ed4cb99b88308b533fb2f559c30fa6efb4fa9fda11347f483d245884 # via tavern (pyproject.toml) -pyproject-api==1.5.3 \ - --hash=sha256:14cf09828670c7b08842249c1f28c8ee6581b872e893f81b62d5465bec41502f \ - --hash=sha256:ffb5b2d7cad43f5b2688ab490de7c4d3f6f15e0b819cb588c4b771567c9729eb +pyproject-api==1.6.1 \ + --hash=sha256:1817dc018adc0d1ff9ca1ed8c60e1623d5aaca40814b953af14a9cf9a5cae538 \ + --hash=sha256:4c0116d60476b0786c88692cf4e325a9814965e2469c5998b830bba16b183675 # via tox pyproject-hooks==1.0.0 \ --hash=sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8 \ @@ -748,16 +791,21 @@ pyyaml==6.0.1 \ # via # pre-commit # tavern (pyproject.toml) -readme-renderer==37.3 \ - --hash=sha256:cd653186dfc73055656f090f227f5cb22a046d7f71a841dfa305f55c9a513273 \ - --hash=sha256:f67a16caedfa71eef48a31b39708637a6f4664c4394801a7b0d6432d13907343 +readme-renderer==42.0 \ + --hash=sha256:13d039515c1f24de668e2c93f2e877b9dbe6c6c32328b90a40a49d8b2b85f36d \ + --hash=sha256:2d55489f83be4992fe4454939d1a051c33edbab778e82761d060c9fc6b308cd1 # via twine +recommonmark==0.7.1 \ + --hash=sha256:1b1db69af0231efce3fa21b94ff627ea33dee7079a01dd0a7f8482c3da148b3f \ + --hash=sha256:bdb4db649f2222dcd8d2d844f0006b958d627f732415d399791ee436a3686d67 + # via tavern (pyproject.toml) requests==2.31.0 \ --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 # via # flit # requests-toolbelt + # sphinx # tavern (pyproject.toml) # twine requests-toolbelt==1.0.0 \ @@ -768,9 +816,9 @@ rfc3986==2.0.0 \ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c # via twine -rich==13.4.1 \ - --hash=sha256:76f6b65ea7e5c5d924ba80e322231d7cb5b5981aa60bfc1e694f1bc097fe6fe1 \ - --hash=sha256:d204aadb50b936bf6b1a695385429d192bc1fdaf3e8b907e8e26f4c4e4b5bf75 +rich==13.5.3 \ + --hash=sha256:87b43e0543149efa1253f485cd845bb7ee54df16c9617b8a893650ab84b4acb6 \ + --hash=sha256:9257b468badc3d347e146a4faa268ff229039d4c2d176ab0cffb4c4fbc73d5d9 # via twine ruamel-yaml==0.17.31 \ --hash=sha256:098ed1eb6d338a684891a72380277c1e6fc4d4ae0e120de9a447275056dda335 \ @@ -823,55 +871,96 @@ six==1.16.0 \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 # via - # bleach # jsonschema # python-dateutil +snowballstemmer==2.2.0 \ + --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \ + --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a + # via sphinx +sphinx==7.2.6 \ + --hash=sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560 \ + --hash=sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5 + # via + # recommonmark + # sphinx-rtd-theme + # sphinxcontrib-applehelp + # sphinxcontrib-devhelp + # sphinxcontrib-htmlhelp + # sphinxcontrib-jquery + # sphinxcontrib-qthelp + # sphinxcontrib-serializinghtml + # tavern (pyproject.toml) +sphinx-markdown-tables==0.0.17 \ + --hash=sha256:2bd0c30779653e4dd120300cbd9ca412c480738cc2241f6dea477a883f299e04 \ + --hash=sha256:6bc6d3d400eaccfeebd288446bc08dd83083367c58b85d40fe6c12d77ef592f1 + # via tavern (pyproject.toml) +sphinx-rtd-theme==1.3.0 \ + --hash=sha256:46ddef89cc2416a81ecfbeaceab1881948c014b1b6e4450b815311a89fb977b0 \ + --hash=sha256:590b030c7abb9cf038ec053b95e5380b5c70d61591eb0b552063fbe7c41f0931 + # via tavern (pyproject.toml) +sphinxcontrib-applehelp==1.0.7 \ + --hash=sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d \ + --hash=sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa + # via sphinx +sphinxcontrib-devhelp==1.0.5 \ + --hash=sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212 \ + --hash=sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f + # via sphinx +sphinxcontrib-htmlhelp==2.0.4 \ + --hash=sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a \ + --hash=sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9 + # via sphinx +sphinxcontrib-jquery==4.1 \ + --hash=sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a \ + --hash=sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae + # via sphinx-rtd-theme +sphinxcontrib-jsmath==1.0.1 \ + --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \ + --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8 + # via sphinx +sphinxcontrib-qthelp==1.0.6 \ + --hash=sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d \ + --hash=sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4 + # via sphinx +sphinxcontrib-serializinghtml==1.1.9 \ + --hash=sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54 \ + --hash=sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1 + # via sphinx stevedore==4.1.1 \ --hash=sha256:7f8aeb6e3f90f96832c301bff21a7eb5eefbe894c88c506483d355565d88cc1a \ --hash=sha256:aa6436565c069b2946fe4ebff07f5041e0c8bf18c7376dd29edf80cf7d524e4e # via tavern (pyproject.toml) -tomli==2.0.1 \ - --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ - --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f - # via - # build - # coverage - # mypy - # pyproject-api - # pyproject-hooks - # pytest - # tox tomli-w==1.0.0 \ --hash=sha256:9f2a07e8be30a0729e533ec968016807069991ae2fd921a78d42f429ae5f4463 \ --hash=sha256:f463434305e0336248cac9c2dc8076b707d8a12d019dd349f5c1e382dd1ae1b9 # via flit -tox==4.6.0 \ - --hash=sha256:4874000453e637a87ca892f9744a2ab9a7d24064dad1b0ecbf5a4c3c146cc732 \ - --hash=sha256:954f1f647f67f481d239a193288983242a6152b67503c4a56b19a4aafaa29736 +tox==4.6.3 \ + --hash=sha256:2946a0bb38924c3a9f9575c7fb4ca1f4c11a7c69c61592f176778892155cb50c \ + --hash=sha256:9e2c5091a117d03b583c57c4c40aecd068099c17d40520e7b165e85c19334534 # via tavern (pyproject.toml) twine==4.0.2 \ --hash=sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8 \ --hash=sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8 # via tavern (pyproject.toml) -types-pyyaml==6.0.12.10 \ - --hash=sha256:662fa444963eff9b68120d70cda1af5a5f2aa57900003c2006d7626450eaae5f \ - --hash=sha256:ebab3d0700b946553724ae6ca636ea932c1b0868701d4af121630e78d695fc97 +types-pyyaml==6.0.12.11 \ + --hash=sha256:7d340b19ca28cddfdba438ee638cd4084bde213e501a3978738543e27094775b \ + --hash=sha256:a461508f3096d1d5810ec5ab95d7eeecb651f3a15b71959999988942063bf01d # via tavern (pyproject.toml) -types-requests==2.31.0.1 \ - --hash=sha256:3de667cffa123ce698591de0ad7db034a5317457a596eb0b4944e5a9d9e8d1ac \ - --hash=sha256:afb06ef8f25ba83d59a1d424bd7a5a939082f94b94e90ab5e6116bd2559deaa3 +types-requests==2.31.0.2 \ + --hash=sha256:56d181c85b5925cbc59f4489a57e72a8b2166f18273fd8ba7b6fe0c0b986f12a \ + --hash=sha256:6aa3f7faf0ea52d728bb18c0a0d1522d9bfd8c72d26ff6f61bfc3d06a411cf40 # via tavern (pyproject.toml) -types-setuptools==67.8.0.0 \ - --hash=sha256:6df73340d96b238a4188b7b7668814b37e8018168aef1eef94a3b1872e3f60ff \ - --hash=sha256:95c9ed61871d6c0e258433373a4e1753c0a7c3627a46f4d4058c7b5a08ab844f +types-setuptools==68.2.0.0 \ + --hash=sha256:77edcc843e53f8fc83bb1a840684841f3dc804ec94562623bfa2ea70d5a2ba1b \ + --hash=sha256:a4216f1e2ef29d089877b3af3ab2acf489eb869ccaf905125c69d2dc3932fd85 # via tavern (pyproject.toml) -types-urllib3==1.26.25.13 \ - --hash=sha256:3300538c9dc11dad32eae4827ac313f5d986b8b21494801f1bf97a1ac6c03ae5 \ - --hash=sha256:5dbd1d2bef14efee43f5318b5d36d805a489f6600252bb53626d4bfafd95e27c +types-urllib3==1.26.25.14 \ + --hash=sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f \ + --hash=sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e # via types-requests -typing-extensions==4.6.3 \ - --hash=sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26 \ - --hash=sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5 +typing-extensions==4.8.0 \ + --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \ + --hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef # via mypy urllib3==2.0.2 \ --hash=sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc \ @@ -879,32 +968,29 @@ urllib3==2.0.2 \ # via # requests # twine -virtualenv==20.23.0 \ - --hash=sha256:6abec7670e5802a528357fdc75b26b9f57d5d92f29c5462ba0fbe45feacc685e \ - --hash=sha256:a85caa554ced0c0afbd0d638e7e2d7b5f92d23478d05d17a76daeac8f279f924 +virtualenv==20.24.5 \ + --hash=sha256:b80039f280f4919c77b30f1c23294ae357c4c8701042086e3fc005963e4e537b \ + --hash=sha256:e8361967f6da6fbdf1426483bfe9fca8287c242ac0bc30429905721cefbff752 # via # pre-commit # tox -webencodings==0.5.1 \ - --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ - --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 - # via bleach -werkzeug==2.3.4 \ - --hash=sha256:1d5a58e0377d1fe39d061a5de4469e414e78ccb1e1e59c0f5ad6fa1c36c52b76 \ - --hash=sha256:48e5e61472fee0ddee27ebad085614ebedb7af41e88f687aaf881afb723a162f +werkzeug==2.3.7 \ + --hash=sha256:2b8c0e447b4b9dbcc85dd97b6eeb4dcbaf6c8b6c3be0bd654e25553e0a2157d8 \ + --hash=sha256:effc12dba7f3bd72e605ce49807bbe692bd729c3bb122a3b91747a6ae77df528 # via flask -wheel==0.40.0 \ - --hash=sha256:cd1196f3faee2b31968d626e1731c94f99cbdb67cf5a46e4f5656cbee7738873 \ - --hash=sha256:d236b20e7cb522daf2390fa84c55eea81c5c30190f90f29ae2ca1ad8355bf247 +wheel==0.41.2 \ + --hash=sha256:0c5ac5ff2afb79ac23ab82bab027a0be7b5dbcf2e54dc50efe4bf507de1f7985 \ + --hash=sha256:75909db2664838d015e3d9139004ee16711748a52c8f336b52882266540215d8 # via # pip-tools # tavern (pyproject.toml) -zipp==3.15.0 \ - --hash=sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b \ - --hash=sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556 +zipp==3.16.2 \ + --hash=sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0 \ + --hash=sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147 # via importlib-metadata # WARNING: The following packages were not pinned, but pip requires them to be -# pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag. +# pinned when the requirements file includes hashes and the requirement is not +# satisfied by a package already installed. Consider using the --allow-unsafe flag. # pip # setuptools diff --git a/tox-integration.ini b/tox-integration.ini index f9fc2ada..54c49340 100644 --- a/tox-integration.ini +++ b/tox-integration.ini @@ -5,7 +5,7 @@ isolated_build = True [testenv] allowlist_externals = - docker-compose + docker basepython = python3.10 passenv = DOCKER_TLS_VERIFY,DOCKER_HOST,DOCKER_CERT_PATH,DOCKER_BUILDKIT setenv = @@ -29,9 +29,9 @@ deps = colorlog mqtt: fluent-logger commands = -; docker-compose stop -; docker-compose build - docker-compose up --build -d +; docker compose stop +; docker compose build + docker compose up --build -d python -m pytest --collect-only python -m pytest --tavern-global-cfg={toxinidir}/tests/integration/global_cfg.yaml --cov tavern {posargs} @@ -56,4 +56,4 @@ commands = mqtt: tavern-ci --stdout test_mqtt_failures.tavern.yaml mqtt: python -c "from tavern.core import run; exit(run('test_mqtt_failures.tavern.yaml', pytest_args=[ ]))" - docker-compose stop + docker compose stop From 65eccdebb23b881e88ee487d49d43d60e672188e Mon Sep 17 00:00:00 2001 From: Michael Boulton Date: Mon, 18 Sep 2023 16:32:27 +0100 Subject: [PATCH 20/25] Install requirements --- .readthedocs.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 26dde362..89d61f33 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -13,3 +13,7 @@ build: # Build documentation in the "docs/" directory with Sphinx sphinx: configuration: docs/source/conf.py + +python: + install: + - requirements: requirements.txt From 9928ce437a6e8b2fc493d9a691831bd25f64b611 Mon Sep 17 00:00:00 2001 From: Michael Boulton Date: Tue, 19 Sep 2023 13:39:28 +0100 Subject: [PATCH 21/25] Add sponsorship link --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..0da48c28 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: michaelboulton From db9826adae18151f6ac9c1f798618bab91b9445f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 23 Sep 2023 14:39:49 +0100 Subject: [PATCH 22/25] Bump cryptography from 41.0.3 to 41.0.4 (#887) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- constraints.txt | 2 +- requirements.txt | 48 ++++++++++++++++++++++++------------------------ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/constraints.txt b/constraints.txt index 6ef035a3..e7eb6be7 100644 --- a/constraints.txt +++ b/constraints.txt @@ -53,7 +53,7 @@ coverage==7.2.7 # via # pytest-cov # tavern (pyproject.toml) -cryptography==41.0.3 +cryptography==41.0.4 # via secretstorage distlib==0.3.6 # via virtualenv diff --git a/requirements.txt b/requirements.txt index 45239f40..b8a8da41 100644 --- a/requirements.txt +++ b/requirements.txt @@ -274,30 +274,30 @@ coverage[toml]==7.3.1 \ # via # pytest-cov # tavern (pyproject.toml) -cryptography==41.0.3 \ - --hash=sha256:0d09fb5356f975974dbcb595ad2d178305e5050656affb7890a1583f5e02a306 \ - --hash=sha256:23c2d778cf829f7d0ae180600b17e9fceea3c2ef8b31a99e3c694cbbf3a24b84 \ - --hash=sha256:3fb248989b6363906827284cd20cca63bb1a757e0a2864d4c1682a985e3dca47 \ - --hash=sha256:41d7aa7cdfded09b3d73a47f429c298e80796c8e825ddfadc84c8a7f12df212d \ - --hash=sha256:42cb413e01a5d36da9929baa9d70ca90d90b969269e5a12d39c1e0d475010116 \ - --hash=sha256:4c2f0d35703d61002a2bbdcf15548ebb701cfdd83cdc12471d2bae80878a4207 \ - --hash=sha256:4fd871184321100fb400d759ad0cddddf284c4b696568204d281c902fc7b0d81 \ - --hash=sha256:5259cb659aa43005eb55a0e4ff2c825ca111a0da1814202c64d28a985d33b087 \ - --hash=sha256:57a51b89f954f216a81c9d057bf1a24e2f36e764a1ca9a501a6964eb4a6800dd \ - --hash=sha256:652627a055cb52a84f8c448185922241dd5217443ca194d5739b44612c5e6507 \ - --hash=sha256:67e120e9a577c64fe1f611e53b30b3e69744e5910ff3b6e97e935aeb96005858 \ - --hash=sha256:6af1c6387c531cd364b72c28daa29232162010d952ceb7e5ca8e2827526aceae \ - --hash=sha256:6d192741113ef5e30d89dcb5b956ef4e1578f304708701b8b73d38e3e1461f34 \ - --hash=sha256:7efe8041897fe7a50863e51b77789b657a133c75c3b094e51b5e4b5cec7bf906 \ - --hash=sha256:84537453d57f55a50a5b6835622ee405816999a7113267739a1b4581f83535bd \ - --hash=sha256:8f09daa483aedea50d249ef98ed500569841d6498aa9c9f4b0531b9964658922 \ - --hash=sha256:95dd7f261bb76948b52a5330ba5202b91a26fbac13ad0e9fc8a3ac04752058c7 \ - --hash=sha256:a74fbcdb2a0d46fe00504f571a2a540532f4c188e6ccf26f1f178480117b33c4 \ - --hash=sha256:a983e441a00a9d57a4d7c91b3116a37ae602907a7618b882c8013b5762e80574 \ - --hash=sha256:ab8de0d091acbf778f74286f4989cf3d1528336af1b59f3e5d2ebca8b5fe49e1 \ - --hash=sha256:aeb57c421b34af8f9fe830e1955bf493a86a7996cc1338fe41b30047d16e962c \ - --hash=sha256:ce785cf81a7bdade534297ef9e490ddff800d956625020ab2ec2780a556c313e \ - --hash=sha256:d0d651aa754ef58d75cec6edfbd21259d93810b73f6ec246436a21b7841908de +cryptography==41.0.4 \ + --hash=sha256:004b6ccc95943f6a9ad3142cfabcc769d7ee38a3f60fb0dddbfb431f818c3a67 \ + --hash=sha256:047c4603aeb4bbd8db2756e38f5b8bd7e94318c047cfe4efeb5d715e08b49311 \ + --hash=sha256:0d9409894f495d465fe6fda92cb70e8323e9648af912d5b9141d616df40a87b8 \ + --hash=sha256:23a25c09dfd0d9f28da2352503b23e086f8e78096b9fd585d1d14eca01613e13 \ + --hash=sha256:2ed09183922d66c4ec5fdaa59b4d14e105c084dd0febd27452de8f6f74704143 \ + --hash=sha256:35c00f637cd0b9d5b6c6bd11b6c3359194a8eba9c46d4e875a3660e3b400005f \ + --hash=sha256:37480760ae08065437e6573d14be973112c9e6dcaf5f11d00147ee74f37a3829 \ + --hash=sha256:3b224890962a2d7b57cf5eeb16ccaafba6083f7b811829f00476309bce2fe0fd \ + --hash=sha256:5a0f09cefded00e648a127048119f77bc2b2ec61e736660b5789e638f43cc397 \ + --hash=sha256:5b72205a360f3b6176485a333256b9bcd48700fc755fef51c8e7e67c4b63e3ac \ + --hash=sha256:7e53db173370dea832190870e975a1e09c86a879b613948f09eb49324218c14d \ + --hash=sha256:7febc3094125fc126a7f6fb1f420d0da639f3f32cb15c8ff0dc3997c4549f51a \ + --hash=sha256:80907d3faa55dc5434a16579952ac6da800935cd98d14dbd62f6f042c7f5e839 \ + --hash=sha256:86defa8d248c3fa029da68ce61fe735432b047e32179883bdb1e79ed9bb8195e \ + --hash=sha256:8ac4f9ead4bbd0bc8ab2d318f97d85147167a488be0e08814a37eb2f439d5cf6 \ + --hash=sha256:93530900d14c37a46ce3d6c9e6fd35dbe5f5601bf6b3a5c325c7bffc030344d9 \ + --hash=sha256:9eeb77214afae972a00dee47382d2591abe77bdae166bda672fb1e24702a3860 \ + --hash=sha256:b5f4dfe950ff0479f1f00eda09c18798d4f49b98f4e2006d644b3301682ebdca \ + --hash=sha256:c3391bd8e6de35f6f1140e50aaeb3e2b3d6a9012536ca23ab0d9c35ec18c8a91 \ + --hash=sha256:c880eba5175f4307129784eca96f4e70b88e57aa3f680aeba3bab0e980b0f37d \ + --hash=sha256:cecfefa17042941f94ab54f769c8ce0fe14beff2694e9ac684176a2535bf9714 \ + --hash=sha256:e40211b4923ba5a6dc9769eab704bdb3fbb58d56c5b336d30996c24fcf12aadb \ + --hash=sha256:efc8ad4e6fc4f1752ebfb58aefece8b4e3c4cae940b0994d43649bdfce8d0d4f # via secretstorage distlib==0.3.7 \ --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \ From 68f51ec9cb541d7d2fdfcd2e6e5d55ff5509bff5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 22 Oct 2023 13:06:54 +0100 Subject: [PATCH 23/25] Bump urllib3 from 2.0.2 to 2.0.7 (#889) * Bump urllib3 from 2.0.2 to 2.0.7 Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.0.2 to 2.0.7. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/2.0.2...2.0.7) --- updated-dependencies: - dependency-name: urllib3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Fix versions in test container * fix for other one as well * fix for other one as well --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Michael Boulton --- constraints.txt | 2 +- example/advanced/Dockerfile | 2 +- example/hooks/Dockerfile | 2 +- requirements.txt | 6 +++--- tests/integration/Dockerfile | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/constraints.txt b/constraints.txt index e7eb6be7..c698c75f 100644 --- a/constraints.txt +++ b/constraints.txt @@ -276,7 +276,7 @@ types-urllib3==1.26.25.13 # via types-requests typing-extensions==4.6.3 # via mypy -urllib3==2.0.2 +urllib3==2.0.7 # via # requests # twine diff --git a/example/advanced/Dockerfile b/example/advanced/Dockerfile index 490cc8dd..09ad4240 100644 --- a/example/advanced/Dockerfile +++ b/example/advanced/Dockerfile @@ -1,6 +1,6 @@ FROM python:3.10-alpine -RUN pip3 install pyjwt~=2.4.0 flask~=2.0.3 +RUN pip3 install 'pyjwt>=2.4.0,<3' 'flask>=2.2.3' ENV FLASK_DEBUG=1 ENV PYTHONUNBUFFERED=0 diff --git a/example/hooks/Dockerfile b/example/hooks/Dockerfile index 68b46a7f..edd2733d 100644 --- a/example/hooks/Dockerfile +++ b/example/hooks/Dockerfile @@ -1,6 +1,6 @@ FROM python:3.10-alpine -RUN pip3 install pyjwt~=2.4.0 flask~=2.0.3 +RUN pip3 install 'pyjwt>=2.4.0,<3' 'flask>=2.2.3' ENV FLASK_DEBUG=1 ENV PYTHONUNBUFFERED=0 diff --git a/requirements.txt b/requirements.txt index b8a8da41..3ecae750 100644 --- a/requirements.txt +++ b/requirements.txt @@ -962,9 +962,9 @@ typing-extensions==4.8.0 \ --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \ --hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef # via mypy -urllib3==2.0.2 \ - --hash=sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc \ - --hash=sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e +urllib3==2.0.7 \ + --hash=sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84 \ + --hash=sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e # via # requests # twine diff --git a/tests/integration/Dockerfile b/tests/integration/Dockerfile index 68b46a7f..edd2733d 100644 --- a/tests/integration/Dockerfile +++ b/tests/integration/Dockerfile @@ -1,6 +1,6 @@ FROM python:3.10-alpine -RUN pip3 install pyjwt~=2.4.0 flask~=2.0.3 +RUN pip3 install 'pyjwt>=2.4.0,<3' 'flask>=2.2.3' ENV FLASK_DEBUG=1 ENV PYTHONUNBUFFERED=0 From 74d70db77f286f519c27150546d1e9a132c49541 Mon Sep 17 00:00:00 2001 From: michaelboulton Date: Sun, 22 Oct 2023 13:43:23 +0100 Subject: [PATCH 24/25] Tinctures (#844) --- CONTRIBUTING.md | 4 + docs/source/basics.md | 75 ++++++++++++- requirements.txt | 16 +++ tavern/_core/dict_util.py | 6 +- tavern/_core/run.py | 16 ++- tavern/_core/schema/tests.jsonschema.yaml | 12 +++ tavern/_core/schema/tests.schema.yaml | 4 + tavern/_core/testhelpers.py | 8 +- tavern/_core/tincture.py | 81 ++++++++++++++ tests/integration/ext_functions.py | 13 +++ tests/integration/test_tincture.tavern.yaml | 60 +++++++++++ tests/unit/test_core.py | 46 ++++++++ tests/unit/test_tinctures.py | 113 ++++++++++++++++++++ 13 files changed, 444 insertions(+), 10 deletions(-) create mode 100644 tavern/_core/tincture.py create mode 100644 tests/integration/test_tincture.tavern.yaml create mode 100644 tests/unit/test_tinctures.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2e20913d..f42a1331 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,6 +47,10 @@ Run every so often to update the pre-commit hooks black tavern/ tests/ ruff --fix tavern/ tests/ +### Fix yaml formatting issues + + pre-commit run --all-files + ## Creating a new release 1. Setup `~/.pypirc` diff --git a/docs/source/basics.md b/docs/source/basics.md index ac243d91..e0c37934 100644 --- a/docs/source/basics.md +++ b/docs/source/basics.md @@ -2381,6 +2381,79 @@ def pytest_tavern_beta_before_every_request(request_args): logging.info("Making request: %s", request_args) ``` +## Tinctures + +Another way of running functions at certain times is to use the 'tinctures' functionality: + +```python +# package/helpers.py + +import logging +import time + +logger = logging.getLogger(__name__) + + +def time_request(stage): + t0 = time.time() + yield + t1 = time.time() + logger.info("Request for stage %s took %s", stage, t1 - t0) + + +def print_response(_, extra_print="affa"): + logger.info("STARTING:") + (expected, response) = yield + logger.info("Response is %s (%s)", response, extra_print) +``` + +```yaml +--- +test_name: Test tincture + +tinctures: + - function: package.helpers:time_request + +stages: + - name: Make a request + tinctures: + - function: package.helpers:print_response + extra_kwargs: + extra_print: "blooble" + request: + url: "{host}/echo" + method: POST + json: + value: "one" + + - name: Make another request + request: + url: "{host}/echo" + method: POST + json: + value: "two" +``` + +Tinctures can be specified on a per-stage level or a per-test level. When specified on the test level, the tincture is +run for every stage in the test. In the above example, the `time_request` function will be run for both stages, but +the 'print_response' function will only be run for the first stage. + +Tinctures are _similar_ to fixtures but are more similar to [external functions](#calling-external-functions). Tincture +functions do not need to be annotated with a function like Pytest fixtures, and are referred to in the same +way (`path.to.package:function`), and have arguments passed to them in the same way (`extra_kwargs`, `extra_args`) as +external functions. + +The first argument to a tincture is always a dictionary of the stage to be run. + +If a tincture has a `yield` in the middle of it, during the `yield` the stage itself will be run. If a return value is +expected from the `yield` (eg `(expected, response) = yield` in the example above) then the _expected_ return values and +the response object from the stage will be returned. This allows a tincture to introspect the response, and compare it +against the expected, the same as the `pytest_tavern_beta_after_every_response` [hook](#after-every-response). This +response object will be different for MQTT and HTTP tests! + +If you need to run something before _every_ stage or after _every_ response in your test suite, look at using +the [hooks](#hooks) instead. + ## Finalising stages If you need a stage to run after a test runs, whether it passes or fails (for example, to log out of a service or @@ -2396,7 +2469,7 @@ stages: - name: stage 2 ... - + - name: stage 3 ... diff --git a/requirements.txt b/requirements.txt index 3ecae750..d643f721 100644 --- a/requirements.txt +++ b/requirements.txt @@ -316,6 +316,10 @@ docutils==0.18.1 \ # sphinx # sphinx-rtd-theme # tavern (pyproject.toml) +exceptiongroup==1.1.3 \ + --hash=sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9 \ + --hash=sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3 + # via pytest execnet==2.0.2 \ --hash=sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41 \ --hash=sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af @@ -930,6 +934,18 @@ stevedore==4.1.1 \ --hash=sha256:7f8aeb6e3f90f96832c301bff21a7eb5eefbe894c88c506483d355565d88cc1a \ --hash=sha256:aa6436565c069b2946fe4ebff07f5041e0c8bf18c7376dd29edf80cf7d524e4e # via tavern (pyproject.toml) +tomli==2.0.1 \ + --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ + --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f + # via + # build + # coverage + # mypy + # pip-tools + # pyproject-api + # pyproject-hooks + # pytest + # tox tomli-w==1.0.0 \ --hash=sha256:9f2a07e8be30a0729e533ec968016807069991ae2fd921a78d42f429ae5f4463 \ --hash=sha256:f463434305e0336248cac9c2dc8076b707d8a12d019dd349f5c1e382dd1ae1b9 diff --git a/tavern/_core/dict_util.py b/tavern/_core/dict_util.py index 3baea4e3..fd0ab1c7 100644 --- a/tavern/_core/dict_util.py +++ b/tavern/_core/dict_util.py @@ -111,7 +111,7 @@ def format_keys( in broken output, only use for debugging purposes. Returns: - str,int,list,dict: recursively formatted values + recursively formatted values """ formatted = val @@ -131,7 +131,7 @@ def format_keys( for key in val: formatted[key] = format_keys_(val[key], box_vars) elif isinstance(val, (list, tuple)): - formatted = [format_keys_(item, box_vars) for item in val] + formatted = [format_keys_(item, box_vars) for item in val] # type: ignore elif isinstance(formatted, FormattedString): logger.debug("Already formatted %s, not double-formatting", formatted) elif isinstance(val, str): @@ -142,7 +142,7 @@ def format_keys( raise if no_double_format: - formatted = FormattedString(formatted) + formatted = FormattedString(formatted) # type: ignore elif isinstance(val, TypeConvertToken): logger.debug("Got type convert token '%s'", val) if isinstance(val, ForceIncludeToken): diff --git a/tavern/_core/run.py b/tavern/_core/run.py index 2b42e5cf..50a35355 100644 --- a/tavern/_core/run.py +++ b/tavern/_core/run.py @@ -25,6 +25,7 @@ from .report import attach_stage_content, wrap_step from .strtobool import strtobool from .testhelpers import delay, retry +from .tincture import Tinctures, get_stage_tinctures logger = logging.getLogger(__name__) @@ -276,6 +277,8 @@ class _TestRunner: test_spec: Mapping def run_stage(self, idx: int, stage, *, is_final: bool = False): + tinctures = get_stage_tinctures(stage, self.test_spec) + stage_config = self.test_block_config.with_strictness( self.default_global_strictness ) @@ -284,7 +287,9 @@ def run_stage(self, idx: int, stage, *, is_final: bool = False): ) # Wrap run_stage with retry helper run_stage_with_retries = retry(stage, stage_config)(self.wrapped_run_stage) - partial = functools.partial(run_stage_with_retries, stage, stage_config) + partial = functools.partial( + run_stage_with_retries, stage, stage_config, tinctures + ) allure_name = "Stage {}: {}".format( idx, format_keys(stage["name"], stage_config.variables) ) @@ -298,12 +303,15 @@ def run_stage(self, idx: int, stage, *, is_final: bool = False): e.is_final = is_final raise - def wrapped_run_stage(self, stage: dict, stage_config: TestConfig): + def wrapped_run_stage( + self, stage: dict, stage_config: TestConfig, tinctures: Tinctures + ): """Run one stage from the test Args: stage: specification of stage to be run stage_config: available variables for test + tinctures: tinctures for this stage/test """ stage = copy.deepcopy(stage) name = stage["name"] @@ -329,8 +337,12 @@ def wrapped_run_stage(self, stage: dict, stage_config: TestConfig): verifiers = get_verifiers(stage, stage_config, self.sessions, expected) + tinctures.start_tinctures(stage) + response = r.run() + tinctures.end_tinctures(expected, response) + for response_type, response_verifiers in verifiers.items(): logger.debug("Running verifiers for %s", response_type) for v in response_verifiers: diff --git a/tavern/_core/schema/tests.jsonschema.yaml b/tavern/_core/schema/tests.jsonschema.yaml index 84a0899c..473856ec 100644 --- a/tavern/_core/schema/tests.jsonschema.yaml +++ b/tavern/_core/schema/tests.jsonschema.yaml @@ -322,6 +322,12 @@ definitions: - name properties: + tinctures: + type: array + description: Tinctures for stage + items: + $ref: "#/definitions/verify_block" + id: type: string description: ID of stage for use in stage references @@ -415,6 +421,12 @@ properties: - key - vals + tinctures: + type: array + description: Tinctures for whole test + items: + $ref: "#/definitions/verify_block" + strict: $ref: "#/definitions/strict_block" diff --git a/tavern/_core/schema/tests.schema.yaml b/tavern/_core/schema/tests.schema.yaml index 4cc26391..ced99f63 100644 --- a/tavern/_core/schema/tests.schema.yaml +++ b/tavern/_core/schema/tests.schema.yaml @@ -28,6 +28,10 @@ schema;stage: required: true func: verify_oneof_id_name mapping: + tinctures: + func: validate_extensions + type: any + id: type: str required: false diff --git a/tavern/_core/testhelpers.py b/tavern/_core/testhelpers.py index 095c3478..42247f6c 100644 --- a/tavern/_core/testhelpers.py +++ b/tavern/_core/testhelpers.py @@ -10,13 +10,13 @@ logger = logging.getLogger(__name__) -def delay(stage, when, variables) -> None: +def delay(stage: Mapping, when: str, variables: Mapping) -> None: """Look for delay_before/delay_after and sleep Args: - stage (dict): test stage - when (str): 'before' or 'after' - variables (dict): Variables to format with + stage: test stage + when: 'before' or 'after' + variables: Variables to format with """ try: diff --git a/tavern/_core/tincture.py b/tavern/_core/tincture.py new file mode 100644 index 00000000..ae33dbf9 --- /dev/null +++ b/tavern/_core/tincture.py @@ -0,0 +1,81 @@ +import collections.abc +import inspect +import logging +from typing import Any, List + +from tavern._core import exceptions +from tavern._core.extfunctions import get_wrapped_response_function + +logger = logging.getLogger(__name__) + + +class Tinctures: + def __init__(self, tinctures: List[Any]): + self._tinctures = tinctures + self._needs_response: List[Any] = [] + + def start_tinctures(self, stage: collections.abc.Mapping): + results = [t(stage) for t in self._tinctures] + self._needs_response = [] + + for r in results: + if inspect.isgenerator(r): + # Store generator and start it + self._needs_response.append(r) + next(r) + + def end_tinctures(self, expected: collections.abc.Mapping, response) -> None: + """ + Send the response object to any tinctures that want it + + Args: + response: The response from 'run' for the stage + """ + if self._needs_response is None: + raise RuntimeError( + "should not be called before accumulating tinctures which need a response" + ) + + for n in self._needs_response: + try: + n.send((expected, response)) + except StopIteration: + pass + else: + raise RuntimeError("Tincture had more than one yield") + + +def get_stage_tinctures( + stage: collections.abc.Mapping, test_spec: collections.abc.Mapping +) -> Tinctures: + """Get tinctures for stage + + Args: + stage: Stage + test_spec: Whole test spec + """ + stage_tinctures = [] + + def add_tinctures_from_block(maybe_tinctures, blockname: str): + logger.debug("Trying to add tinctures from %s", blockname) + + def inner_yield(): + if maybe_tinctures is not None: + if isinstance(maybe_tinctures, list): + for vf in maybe_tinctures: + yield get_wrapped_response_function(vf) + elif isinstance(maybe_tinctures, dict): + yield get_wrapped_response_function(maybe_tinctures) + elif maybe_tinctures is not None: + raise exceptions.BadSchemaError( + "Badly formatted 'tinctures' block in {}".format(blockname) + ) + + stage_tinctures.extend(inner_yield()) + + add_tinctures_from_block(test_spec.get("tinctures"), "test") + add_tinctures_from_block(stage.get("tinctures"), "stage") + + logger.debug("%d tinctures for stage %s", len(stage_tinctures), stage["name"]) + + return Tinctures(stage_tinctures) diff --git a/tests/integration/ext_functions.py b/tests/integration/ext_functions.py index fbb23ab0..cf33102b 100644 --- a/tests/integration/ext_functions.py +++ b/tests/integration/ext_functions.py @@ -1,3 +1,6 @@ +import time + + def return_hello(): return {"hello": "there"} @@ -12,3 +15,13 @@ def return_list_vals(): def gen_echo_url(host): return "{0}/echo".format(host) + + +def time_request(_): + time.time() + yield + time.time() + + +def print_response(_, extra_print="affa"): + (_, r) = yield diff --git a/tests/integration/test_tincture.tavern.yaml b/tests/integration/test_tincture.tavern.yaml new file mode 100644 index 00000000..06bd1785 --- /dev/null +++ b/tests/integration/test_tincture.tavern.yaml @@ -0,0 +1,60 @@ +--- +test_name: Test tincture + fixtures + +includes: + - !include common.yaml + +tinctures: + - function: ext_functions:time_request + - function: ext_functions:print_response + extra_kwargs: + extra_print: "blooble" + +marks: + - usefixtures: + - yielder + - str_fixture + - yield_str_fixture + +stages: + - name: do something + tinctures: + - function: ext_functions:time_request + - function: ext_functions:print_response + extra_kwargs: + extra_print: "blooble" + request: + url: "{host}/echo" + method: POST + json: + value: "{str_fixture}" + response: + status_code: 200 + json: + value: "{yield_str_fixture}" + +--- +test_name: Test tincture extra kwargs fails + +includes: + - !include common.yaml + +tinctures: + - function: ext_functions:print_response + extra_kwargs: + extra_print: "blooble" + something: else + +_xfail: run + +stages: + - name: do something + request: + url: "{host}/echo" + method: POST + json: + value: "{str_fixture}" + response: + status_code: 200 + json: + value: "{yield_str_fixture}" diff --git a/tests/unit/test_core.py b/tests/unit/test_core.py index 17515389..e930d813 100644 --- a/tests/unit/test_core.py +++ b/tests/unit/test_core.py @@ -587,6 +587,52 @@ def test_finally_run_on_main_failure( assert pmock.mock_calls[1].kwargs.items() >= finally_request["request"].items() +class TestTinctures: + @pytest.mark.parametrize( + "tinctures", + ( + {"function": "abc"}, + [{"function": "abc"}], + [{"function": "abc"}, {"function": "def"}], + ), + ) + @pytest.mark.parametrize( + "at_stage_level", + ( + True, + False, + ), + ) + def test_tinctures( + self, + fulltest, + mockargs, + includes, + tinctures, + at_stage_level, + ): + if at_stage_level: + fulltest["tinctures"] = tinctures + else: + fulltest["stages"][0]["tinctures"] = tinctures + + mock_response = Mock(**mockargs) + + tincture_func_mock = Mock() + + with patch( + "tavern._plugins.rest.request.requests.Session.request", + return_value=mock_response, + ) as pmock, patch( + "tavern._core.tincture.get_wrapped_response_function", + return_value=tincture_func_mock, + ): + run_test("heif", fulltest, includes) + + assert pmock.call_count == 1 + assert tincture_func_mock.call_count == len(tinctures) + + def test_copy_config(pytestconfig): cfg_1 = load_global_cfg(pytestconfig) diff --git a/tests/unit/test_tinctures.py b/tests/unit/test_tinctures.py new file mode 100644 index 00000000..98768a7d --- /dev/null +++ b/tests/unit/test_tinctures.py @@ -0,0 +1,113 @@ +from unittest.mock import patch + +import pytest + +from tavern._core.tincture import Tinctures, get_stage_tinctures + + +@pytest.fixture(name="example") +def example(): + spec = { + "test_name": "A test with a single stage", + "stages": [ + { + "name": "step 1", + "request": {"url": "http://www.google.com", "method": "GET"}, + "response": { + "status_code": 200, + "json": {"key": "value"}, + "headers": {"content-type": "application/json"}, + }, + } + ], + } + + return spec + + +def test_empty(): + t = Tinctures([]) + + t.start_tinctures({}) + t.end_tinctures({}, None) + + +@pytest.mark.parametrize( + "tinctures", + ( + {"function": "abc"}, + [{"function": "abc"}], + [{"function": "abc"}, {"function": "def"}], + ), +) +class TestTinctures: + class TestTinctureBasic: + def test_stage_tinctures_normal(self, example, tinctures): + stage = example["stages"][0] + stage["tinctures"] = tinctures + + with patch( + "tavern._core.tincture.get_wrapped_response_function", + return_value=lambda _: None, + ) as call_mock: + t = get_stage_tinctures(stage, example) + + t.start_tinctures(stage) + t.end_tinctures(stage, None) + + assert call_mock.call_count == len(tinctures) + + def test_test_tinctures_normal(self, example, tinctures): + stage = example["stages"][0] + example["tinctures"] = tinctures + + with patch( + "tavern._core.tincture.get_wrapped_response_function", + return_value=lambda _: None, + ) as call_mock: + t = get_stage_tinctures(stage, example) + + t.start_tinctures(stage) + t.end_tinctures(stage, None) + + assert call_mock.call_count == len(tinctures) + + class TestTinctureYields: + @staticmethod + def does_yield(stage): + assert stage["name"] == "step 1" + + (expected, response) = yield + + assert expected == stage["response"] + assert response is None + + def test_stage_tinctures_normal(self, example, tinctures): + stage = example["stages"][0] + stage["tinctures"] = tinctures + + with patch( + "tavern._core.tincture.get_wrapped_response_function", + return_value=self.does_yield, + ) as call_mock: + t = get_stage_tinctures(stage, example) + + t.start_tinctures(stage) + t.end_tinctures(stage["response"], None) + + assert call_mock.call_count == len(tinctures) + + def test_test_tinctures_normal(self, example, tinctures): + stage = example["stages"][0] + example["tinctures"] = tinctures + + with patch( + "tavern._core.tincture.get_wrapped_response_function", + return_value=self.does_yield, + ) as call_mock: + t = get_stage_tinctures(stage, example) + + t.start_tinctures(stage) + t.end_tinctures(stage["response"], None) + + assert call_mock.call_count == len(tinctures) From 32b6e52c1256fac1f586444d832024b4279a95d3 Mon Sep 17 00:00:00 2001 From: Michael Boulton Date: Sun, 22 Oct 2023 13:45:49 +0100 Subject: [PATCH 25/25] Bump to 2.5.0 --- CHANGELOG.md | 2 ++ docs/source/conf.py | 2 +- pyproject.toml | 6 +++--- tavern/__init__.py | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e3df920..794d8655 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -416,3 +416,5 @@ This is technically not a operational change but I'm adding a new tag so it can # 2.3.0 Add 'finally' block (2023-08-05) ## 2.3.1 Fix error formatting when including files with curly braces (2023-09-18) + +# 2.4.0 Allow using an ext function to create a URL (2023-09-18) diff --git a/docs/source/conf.py b/docs/source/conf.py index 3e05c2cf..be8ed3dd 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -73,7 +73,7 @@ # The short X.Y version. version = "1.0" # The full version, including alpha/beta/rc tags. -release = "2.4.0" +release = "2.5.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index d00691f3..25a113ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,14 +21,14 @@ keywords = ["testing", "pytest"] name = "tavern" description = "Simple testing of RESTful APIs" -version = "2.4.0" +version = "2.5.0" dependencies = [ "PyYAML>=6.0.1,<7", "jmespath>=1,<2", "jsonschema>=3.2.0,<5", "paho-mqtt>=1.3.1,<=1.6.1", - "pyjwt>=2.4.0,<3", + "pyjwt>=2.5.0,<3", "pykwalify>=1.8.0,<2", "pytest>=7,<7.3", "python-box>=6,<7", @@ -165,7 +165,7 @@ target-version = "py38" known-first-party = ["tavern"] [tool.tbump.version] -current = "2.4.0" +current = "2.5.0" regex = ''' (?P\d+) diff --git a/tavern/__init__.py b/tavern/__init__.py index 231d8dc9..a39782e8 100644 --- a/tavern/__init__.py +++ b/tavern/__init__.py @@ -1,2 +1,2 @@ """Stop pytest warning about module already imported: PYTEST_DONT_REWRITE""" -__version__ = "2.4.0" +__version__ = "2.5.0"