diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7d38642f..b87e6b7e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,56 +1,106 @@ name: Python Tests on: - push: + push: branches: - '*' jobs: - test: + feature-branch-checks: + # these checks do not run this on master itself + if: github.ref != 'refs/heads/master' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # we need history to diff properly + + - &install-task # define a YAML anchor to re-use this task in other jobs + name: Install task to make use of Taskfile.yml + run: | + sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin + task --version + + - name: Check for CRLF line endings + run: | + task list-crlf + + - name: Check poetry.lock is up to date + run: | + pip install poetry + task check-lock + + - name: Verify CHANGELOG.md was updated + run: | + task check-changelog + + - name: Verify that the package version was updated. This is needed because master is automatically deployed to pypi.org + run: | + task check-version + + - name: Run code linter + run: | + pip install ruff + task lint + + test: + needs: feature-branch-checks runs-on: ubuntu-latest strategy: matrix: python-version: [3.11, 3.12, 3.13, 3.14] + steps: - - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - check-latest: true - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -U coveralls - pip install -e .[dev] - - name: Run tests with pytest - run: | - pytest --doctest-modules --cov=pedantic --cov-branch --cov-report= --cov-report=term - - name: Coveralls - uses: coverallsapp/github-action@v2.3.6 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - file: .coverage - deploy: - needs: test - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/master' - environment: - name: pypi-deployment - steps: - - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: 3.12 - - name: Install Build Tools - run: | - pip install -U build twine - - name: Set Twine Environment Variables - run: | - echo "TWINE_USERNAME=${{ secrets.PYPI_USERNAME }}" >> $GITHUB_ENV - echo "TWINE_PASSWORD=${{ secrets.PYPI_PASSWORD }}" >> $GITHUB_ENV - - name: Build and Upload to PyPI - run: | - python -m build - twine upload dist/* \ No newline at end of file + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + check-latest: true + + - *install-task # see above + + - name: Install dependencies + run: | + task dependencies-with-pip + pip install -U coveralls + + - name: Run tests with pytest + run: | + task tests-with-cov + + - name: Coveralls + uses: coverallsapp/github-action@v2.3.6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + file: .coverage + + deploy: + needs: test + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/master' + environment: + name: pypi-deployment + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.12 + + - name: Install Build Tools + run: | + pip install -U build twine + + - name: Set Twine Environment Variables + run: | + echo "TWINE_USERNAME=${{ secrets.PYPI_USERNAME }}" >> $GITHUB_ENV + echo "TWINE_PASSWORD=${{ secrets.PYPI_PASSWORD }}" >> $GITHUB_ENV + + - name: Build and Upload to PyPI + run: | + python -m build + twine upload dist/* diff --git a/CHANGELOG.md b/CHANGELOG.md index 0851406c..f52a4481 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,28 @@ # Changelog +## Pedantic 3.0.0 +- removed decorator `@count_calls` +- removed decorator `@does_same_as_function` +- removed decorator `@mock` +- removed decorator `@rename_kwargs` +- removed decorator `@require_kwargs` +- removed decorator `@timer` +- removed decorator `@timer_class` +- removed decorator `@uminplemented` +- removed decorator `@trace_if_returns` +- removed validator `Composite`. Just pass multiple validators directly instead. +- removed `enable_pedantic, disable_pedantic, is_enabled` +- removed `GenericMixin.type_var`. Use `GenericMixin.type_vars` instead. +- removed `GenericMixin.class_name`. Use `type(self).__name__` instead. +- added `Taskfile.yml` and use it in CI +- removed `create_pdoc.sh` +- removed `examples` +- CI: added a check that `CHANGELOG.md` is modified on feature branches +- CI: added a check that the poetry package version was updated +- added `ruff` linter and apply lint rules to code +- added helper function `run_doctest_of_single_function` +- added type checking support for `collections.abc: Generator, Iterable, Iterator, Callable` +- updated `README.md` + ## Pedantic 2.4.0 - migrate from unittest to pytest - exclude tests from package deployment diff --git a/README.md b/README.md index 41957d46..a62e428f 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,7 @@ -# pedantic-python-decorators [![Build Status](https://travis-ci.com/LostInDarkMath/pedantic-python-decorators.svg?branch=master)](https://travis-ci.com/LostInDarkMath/pedantic-python-decorators) [![Coverage Status](https://coveralls.io/repos/github/LostInDarkMath/pedantic-python-decorators/badge.svg?branch=master)](https://coveralls.io/github/LostInDarkMath/pedantic-python-decorators?branch=master) [![PyPI version](https://badge.fury.io/py/pedantic.svg)](https://badge.fury.io/py/pedantic) [![Conda Version](https://img.shields.io/conda/vn/conda-forge/pedantic.svg)](https://anaconda.org/conda-forge/pedantic) [![Last Commit](https://badgen.net/github/last-commit/LostInDarkMath/pedantic-python-decorators?color=green)](https://GitHub.com/LostInDarkMath/pedantic-python-decorators) [![Stars](https://badgen.net/github/stars/LostInDarkMath/pedantic-python-decorators?color=green)](https://GitHub.com/LostInDarkMath/pedantic-python-decorators) [![Open Issues](https://badgen.net/github/open-issues/LostInDarkMath/pedantic-python-decorators?color=green)](https://GitHub.com/LostInDarkMath/pedantic-python-decorators/issues) [![Open PRs](https://badgen.net/github/open-prs/LostInDarkMath/pedantic-python-decorators?color=green)](https://GitHub.com/LostInDarkMath/pedantic-python-decorators/pulls) +# pedantic-python-decorators [![Coverage Status](https://coveralls.io/repos/github/LostInDarkMath/pedantic-python-decorators/badge.svg?branch=master)](https://coveralls.io/github/LostInDarkMath/pedantic-python-decorators?branch=master) [![PyPI version](https://badge.fury.io/py/pedantic.svg)](https://badge.fury.io/py/pedantic) [![Conda Version](https://img.shields.io/conda/vn/conda-forge/pedantic.svg)](https://anaconda.org/conda-forge/pedantic) [![Last Commit](https://badgen.net/github/last-commit/LostInDarkMath/pedantic-python-decorators?color=green)](https://GitHub.com/LostInDarkMath/pedantic-python-decorators) [![Stars](https://badgen.net/github/stars/LostInDarkMath/pedantic-python-decorators?color=green)](https://GitHub.com/LostInDarkMath/pedantic-python-decorators) [![Open Issues](https://badgen.net/github/open-issues/LostInDarkMath/pedantic-python-decorators?color=green)](https://GitHub.com/LostInDarkMath/pedantic-python-decorators/issues) [![Open PRs](https://badgen.net/github/open-prs/LostInDarkMath/pedantic-python-decorators?color=green)](https://GitHub.com/LostInDarkMath/pedantic-python-decorators/pulls) This packages includes many decorators that will make you write cleaner Python code. -## Getting Started -This package requires Python 3.11 or later. -There are multiple options for installing this package. - -### Option 1: Installing with pip from [Pypi](https://pypi.org/) -Run `pip install pedantic`. - -### Option 2: Installing with conda from [conda-forge](conda-forge.org) -Run `conda install -c conda-forge pedantic` - -### Option 3: Installing with pip and git -1. Install [Git](https://git-scm.com/downloads) if you don't have it already. -2. Run `pip install git+https://github.com/LostInDarkMath/pedantic-python-decorators.git@master` - -### Option 4: Offline installation using wheel -1. Download the [latest release here](https://github.com/LostInDarkMath/PythonHelpers/releases/latest) by clicking on `pedantic-python-decorators-x.y.z-py-none-any.whl`. -2. Execute `pip install pedantic-python-decorators-x.y.z-py3-none-any.whl`. - ## The [@pedantic](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/method_decorators.html#pedantic.method_decorators.pedantic) decorator - Type checking at runtime The `@pedantic` decorator does the following things: - The decorated function can only be called by using keyword arguments. Positional arguments are not accepted. @@ -50,120 +32,21 @@ get_sum_of(values=[0, 1.2, 3, 5.4]) # this raises the following runtime error: ## The [@validate]() decorator As the name suggests, with `@validate` you are able to validate the values that are passed to the decorated function. -That is done in a highly customizable way. -But the highest benefit of this decorator is that it makes it extremely easy to write decoupled easy testable, maintainable and scalable code. -The following example shows the decoupled implementation of a configurable algorithm with the help of `@validate`: -```python -import os -from dataclasses import dataclass - -from pedantic import validate, ExternalParameter, overrides, Validator, Parameter, Min, ReturnAs - - -@dataclass(frozen=True) -class Configuration: - iterations: int - max_error: float - - -class ConfigurationValidator(Validator): - @overrides(Validator) - def validate(self, value: Configuration) -> Configuration: - if value.iterations < 1 or value.max_error < 0: - self.raise_exception(msg=f'Invalid configuration: {value}', value=value) - - return value - - -class ConfigFromEnvVar(ExternalParameter): - """ Reads the configuration from environment variables. """ - - @overrides(ExternalParameter) - def has_value(self) -> bool: - return 'iterations' in os.environ and 'max_error' in os.environ - - @overrides(ExternalParameter) - def load_value(self) -> Configuration: - return Configuration( - iterations=int(os.environ['iterations']), - max_error=float(os.environ['max_error']), - ) - - -class ConfigFromFile(ExternalParameter): - """ Reads the configuration from a config file. """ - - @overrides(ExternalParameter) - def has_value(self) -> bool: - return os.path.isfile('config.csv') - - @overrides(ExternalParameter) - def load_value(self) -> Configuration: - with open(file='config.csv', mode='r') as file: - content = file.readlines() - return Configuration( - iterations=int(content[0].strip('\n')), - max_error=float(content[1]), - ) - - -# choose your configuration source here: -@validate(ConfigFromEnvVar(name='config', validators=[ConfigurationValidator()]), strict=False, return_as=ReturnAs.KWARGS_WITH_NONE) -# @validate(ConfigFromFile(name='config', validators=[ConfigurationValidator()]), strict=False) - -# with strict_mode = True (which is the default) -# you need to pass a Parameter for each parameter of the decorated function -# @validate( -# Parameter(name='value', validators=[Min(5, include_boundary=False)]), -# ConfigFromFile(name='config', validators=[ConfigurationValidator()]), -# ) -def my_algorithm(value: float, config: Configuration) -> float: - """ - This method calculates something that depends on the given value with considering the configuration. - Note how well this small piece of code is designed: - - Fhe function my_algorithm() need a Configuration but has no knowledge where this come from. - - Furthermore, it doesn't care about parameter validation. - - The ConfigurationValidator doesn't know anything about the creation of the data. - - The @validate decorator is the only you need to change, if you want a different configuration source. - """ - print(value) - print(config) - return value - - -if __name__ == '__main__': - # we can call the function with a config like there is no decorator. - # This makes testing extremely easy: no config files, no environment variables or stuff like that - print(my_algorithm(value=2, config=Configuration(iterations=3, max_error=4.4))) - - os.environ['iterations'] = '12' - os.environ['max_error'] = '3.1415' - - # but we also can omit the config and load it implicitly by our custom Parameters - print(my_algorithm(value=42.0)) -``` ## List of all decorators in this package -- [@count_calls](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_count_calls.html) - [@deprecated](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_deprecated.html) -- [@does_same_as_function](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_does_same_as_function.html) - [@frozen_dataclass](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/cls_deco_frozen_dataclass.html#pedantic.decorators.cls_deco_frozen_dataclass.frozen_dataclass) - [@frozen_type_safe_dataclass](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/cls_deco_frozen_dataclass.html#pedantic.decorators.cls_deco_frozen_dataclass.frozen_type_safe_dataclass) - [@for_all_methods](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/class_decorators.html#pedantic.decorators.class_decorators.for_all_methods) - [@in_subprocess](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_in_subprocess.html) -- [@mock](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_mock.html) - [@overrides](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_overrides.html) - [@pedantic](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_pedantic.html#pedantic.decorators.fn_deco_pedantic.pedantic) - [@pedantic_class](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/class_decorators.html#pedantic.decorators.class_decorators.pedantic_class) -- [@rename_kwargs](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_rename_kwargs.html) - [@require_kwargs](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_require_kwargs.html) - [@retry](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_retry.html) -- [@timer](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_timer.html) -- [@timer_class](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/class_decorators.html#pedantic.decorators.class_decorators.timer_class) - [@trace](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_trace.html) - [@trace_class](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/class_decorators.html#pedantic.decorators.class_decorators.trace_class) - [@trace_if_returns](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_trace_if_returns.html) -- [@unimplemented](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_unimplemented.html) - [@validate](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic/decorators/fn_deco_validate/fn_deco_validate.html) ## List of all mixins in this package @@ -183,12 +66,8 @@ There are no hard dependencies. But if you want to use some advanced features yo - `GenericFlaskDeserializer` ## Contributing -Feel free to contribute by submitting a pull request :) - -## Acknowledgments -* [Rathaustreppe](https://github.com/rathaustreppe) -* [Aran-Fey](https://stackoverflow.com/questions/55503673/how-do-i-check-if-a-value-matches-a-type-in-python/55504010#55504010) -* [user395760](https://stackoverflow.com/questions/55503673/how-do-i-check-if-a-value-matches-a-type-in-python/55504010#55504010) +This project is based on [poetry](https://python-poetry.org/) and [taskfile](https://taskfile.dev). +**Tip:** Run `task validate` before making commits. ## Risks and side effects The usage of decorators may affect the performance of your application. @@ -207,6 +86,4 @@ enable_pedantic() This package is **not** compatible with compiled source code (e.g. with [Nuitka](https://github.com/Nuitka/Nuitka)). That's because it uses the `inspect` module from the standard library which will raise errors like `OSError: could not get source code` in case of compiled source code. - Don't forget to check out the [documentation](https://lostindarkmath.github.io/pedantic-python-decorators/pedantic). -Happy coding! diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 00000000..e4f15f7f --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,151 @@ +# yaml-language-server: $schema=https://taskfile.dev/schema.json + +version: '3' + +tasks: + dependencies: + desc: Updates the poetry.lock file and installs all dependencies + cmds: + - pip install --upgrade pip + - poetry lock + - poetry install --extras dev + silent: true + + dependencies-with-pip: + desc: Installs all dependencies using pip only + cmds: + - pip install --upgrade pip + - pip install .[dev] + silent: true + + tests: + desc: Runs the tests + cmds: + - pytest --doctest-modules + + tests-with-cov: + desc: Runs the tests with coverage + cmds: + - pytest --doctest-modules --cov=pedantic --cov-branch --cov-report= --cov-report=term + silent: true + + lint: + desc: Runs the linter (ruff) + silent: true + cmds: + - ruff check pedantic tests {{.CLI_ARGS}} + + lint-fix: + desc: Runs the linter and fixes all fixable errors automatically + silent: true + cmds: + - ruff check pedantic --fix + + validate: + desc: Runs all checks and updates the docu. It is recommended to do this before making a commit. + cmds: + - task: list-crlf + - task: check-changelog + - task: check-version + - task: tests + - task: lint + - task: generate-docs + + docs: + desc: Creates the HTML documentation and opens is Chrome + cmds: + - task: generate-docs + - google-chrome ./docs/index.html + silent: true + + generate-docs: + desc: Creates the HTML documentation + cmds: + - rm -rf ./docs + - pip install pdoc + - pdoc -o docs pedantic + silent: true + + check-lock: + desc: Check if poetry.lock is in sync with pyproject.toml + cmds: + - poetry check + + list-crlf: + desc: List all Python files with CRLF line endings + silent: true + cmds: + - | + files=$(find . -type d -name ".*" ! -name "." -prune -o -name "*.py" -type f -exec grep -Iq . {} \; -and -exec grep -l $'\r' {} \;) + if [ -n "$files" ]; then + echo "$files" + exit 1 + fi + + check-changelog: + desc: Fails if CHANGELOG.md was not modified compared to master + silent: true + cmds: + - | + set -e + + echo "Checking that CHANGELOG.md was updated..." + + # Ensure we have master available (works both locally and in CI) + if git show-ref --verify --quiet refs/remotes/origin/master; then + BASE=origin/master + elif git show-ref --verify --quiet refs/heads/master; then + BASE=master + else + echo "❌ Could not find master branch to diff against." + exit 1 + fi + + # Fetch latest master if we're in a repo with a remote + git fetch origin master >/dev/null 2>&1 || true + + if git diff --name-only "$BASE"...HEAD | grep -qx "CHANGELOG.md"; then + echo "✅ CHANGELOG.md was updated." + else + echo "❌ CHANGELOG.md was NOT updated." + echo "" + echo "Please add an entry describing your change." + exit 1 + fi + + check-version: + desc: Fails if the version in pyproject.toml was not bumped compared to master + silent: true + cmds: + - | + set -e + + echo "Checking that project version was updated..." + + # Determine comparison base (works locally and in CI) + if git show-ref --verify --quiet refs/remotes/origin/master; then + BASE=origin/master + elif git show-ref --verify --quiet refs/heads/master; then + BASE=master + else + echo "❌ Could not find master branch to diff against." + exit 1 + fi + + # Try to fetch latest master (no-op if no remote available) + git fetch origin master >/dev/null 2>&1 || true + + # Extract versions + CURRENT_VERSION=$(grep -E '^version\s*=' pyproject.toml | head -1 | sed -E 's/.*"(.*)".*/\1/') + BASE_VERSION=$(git show "$BASE:pyproject.toml" | grep -E '^version\s*=' | head -1 | sed -E 's/.*"(.*)".*/\1/') + + echo "Base version: $BASE_VERSION" + echo "Current version: $CURRENT_VERSION" + + if [ "$CURRENT_VERSION" = "$BASE_VERSION" ]; then + echo "❌ Version was not updated." + echo "Please bump the version in pyproject.toml." + exit 1 + fi + + echo "✅ Version was updated." diff --git a/create_pdoc.sh b/create_pdoc.sh deleted file mode 100755 index 0d883f02..00000000 --- a/create_pdoc.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -pip3 install pdoc3 -pdoc3 --html --output-dir docs pedantic --force -"docs/pedantic/index.html" diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..3bec2c37 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/docs/pedantic.html b/docs/pedantic.html new file mode 100644 index 00000000..d9c6bdd7 --- /dev/null +++ b/docs/pedantic.html @@ -0,0 +1,4918 @@ + + + + + + + pedantic API documentation + + + + + + + + + +
+
+

+pedantic

+ + + + + + +
  1from pedantic.decorators import (
+  2    calculate_in_subprocess,
+  3    deprecated,
+  4    for_all_methods,
+  5    frozen_dataclass,
+  6    frozen_type_safe_dataclass,
+  7    in_subprocess,
+  8    overrides,
+  9    pedantic,
+ 10    pedantic_class,
+ 11    pedantic_class_require_docstring,
+ 12    pedantic_require_docstring,
+ 13    retry,
+ 14    trace,
+ 15    trace_class,
+ 16)
+ 17from pedantic.decorators.fn_deco_validate.exceptions import (
+ 18    ConversionError,
+ 19    InvalidHeader,
+ 20    ParameterException,
+ 21    TooManyArguments,
+ 22    ValidateException,
+ 23    ValidatorException,
+ 24)
+ 25from pedantic.decorators.fn_deco_validate.fn_deco_validate import (
+ 26    ReturnAs,
+ 27    validate,
+ 28)
+ 29from pedantic.decorators.fn_deco_validate.parameters import (
+ 30    Deserializable,
+ 31    EnvironmentVariableParameter,
+ 32    ExternalParameter,
+ 33    Parameter,
+ 34)
+ 35from pedantic.decorators.fn_deco_validate.validators import (
+ 36    DatetimeIsoFormat,
+ 37    DateTimeUnixTimestamp,
+ 38    Email,
+ 39    ForEach,
+ 40    IsEnum,
+ 41    IsUuid,
+ 42    MatchPattern,
+ 43    Max,
+ 44    MaxLength,
+ 45    Min,
+ 46    MinLength,
+ 47    NotEmpty,
+ 48    Validator,
+ 49)
+ 50from pedantic.helper_fn import run_doctest_of_single_function
+ 51from pedantic.mixins import (
+ 52    DecoratorType,
+ 53    GenericMixin,
+ 54    WithDecoratedMethods,
+ 55    create_decorator,
+ 56)
+ 57from pedantic.type_checking_logic import (
+ 58    assert_value_matches_type,
+ 59    resolve_forward_ref,
+ 60)
+ 61
+ 62__all__ = [
+ 63    'ConversionError',
+ 64    'DateTimeUnixTimestamp',
+ 65    'DatetimeIsoFormat',
+ 66    'DecoratorType',
+ 67    'Deserializable',
+ 68    'Email',
+ 69    'EnvironmentVariableParameter',
+ 70    'ExternalParameter',
+ 71    'ForEach',
+ 72    'GenericMixin',
+ 73    'InvalidHeader',
+ 74    'IsEnum',
+ 75    'IsUuid',
+ 76    'MatchPattern',
+ 77    'Max',
+ 78    'MaxLength',
+ 79    'Min',
+ 80    'MinLength',
+ 81    'NotEmpty',
+ 82    'Parameter',
+ 83    'ParameterException',
+ 84    'ReturnAs',
+ 85    'TooManyArguments',
+ 86    'ValidateException',
+ 87    'Validator',
+ 88    'ValidatorException',
+ 89    'WithDecoratedMethods',
+ 90    'assert_value_matches_type',
+ 91    'calculate_in_subprocess',
+ 92    'create_decorator',
+ 93    'deprecated',
+ 94    'for_all_methods',
+ 95    'frozen_dataclass',
+ 96    'frozen_type_safe_dataclass',
+ 97    'in_subprocess',
+ 98    'overrides',
+ 99    'pedantic',
+100    'pedantic_class',
+101    'pedantic_class_require_docstring',
+102    'pedantic_require_docstring',
+103    'resolve_forward_ref',
+104    'retry',
+105    'run_doctest_of_single_function',
+106    'trace',
+107    'trace_class',
+108    'validate',
+109]
+110
+111try:
+112    from pedantic.decorators.fn_deco_validate.parameters import (
+113        FlaskFormParameter,
+114        FlaskGetParameter,
+115        FlaskHeaderParameter,
+116        FlaskJsonParameter,
+117        FlaskParameter,
+118        FlaskPathParameter,
+119        GenericFlaskDeserializer,
+120    )
+121
+122    __all__ +=[
+123        'FlaskFormParameter',
+124        'FlaskGetParameter',
+125        'FlaskHeaderParameter',
+126        'FlaskJsonParameter',
+127        'FlaskParameter',
+128        'FlaskPathParameter',
+129        'GenericFlaskDeserializer',
+130    ]
+131except ImportError:
+132    pass  # no Flask installed
+
+ + +
+
+ +
+ + class + ConversionError(pedantic.ValidateException): + + + +
+ +
78class ConversionError(ValidateException):
+79    """Is raised if a type cast failed."""
+
+ + +

Is raised if a type cast failed.

+
+ + +
+
+ +
+ + class + DateTimeUnixTimestamp(pedantic.Validator): + + + +
+ +
 8class DateTimeUnixTimestamp(Validator): # noqa: D101
+ 9    @overrides(Validator)
+10    def validate(self, value: float | str) -> datetime: # noqa: D102
+11        if not isinstance(value, (int, float, str)):
+12            self.raise_exception(msg=f'Invalid seconds since 1970: {value}', value=value)
+13
+14        try:
+15            seconds = float(value)
+16        except ValueError:
+17            return self.raise_exception(msg=f'Could parse {value} to float.', value=value)
+18
+19        try:
+20            return datetime(year=1970, month=1, day=1, tzinfo=UTC) + timedelta(seconds=seconds)
+21        except OverflowError:
+22            return self.raise_exception(
+23                msg=f'Date value out of range. Make sure you send SECONDS since 1970. Got: {value}', value=value)
+
+ + +

Base class for validator classes.

+
+ + +
+ +
+
@overrides(Validator)
+ + def + validate(self, value: float | str) -> datetime.datetime: + + + +
+ +
 9    @overrides(Validator)
+10    def validate(self, value: float | str) -> datetime: # noqa: D102
+11        if not isinstance(value, (int, float, str)):
+12            self.raise_exception(msg=f'Invalid seconds since 1970: {value}', value=value)
+13
+14        try:
+15            seconds = float(value)
+16        except ValueError:
+17            return self.raise_exception(msg=f'Could parse {value} to float.', value=value)
+18
+19        try:
+20            return datetime(year=1970, month=1, day=1, tzinfo=UTC) + timedelta(seconds=seconds)
+21        except OverflowError:
+22            return self.raise_exception(
+23                msg=f'Date value out of range. Make sure you send SECONDS since 1970. Got: {value}', value=value)
+
+ + +

Validates and convert the value. +Raises an [ValidatorException] in case of an invalid value. +To raise this you can simply call self.raise_exception().

+
+ + +
+
+
+ +
+ + class + DatetimeIsoFormat(pedantic.Validator): + + + +
+ +
 8class DatetimeIsoFormat(Validator): # noqa: D101
+ 9    @overrides(Validator)
+10    def validate(self, value: str) -> datetime: # noqa: D102
+11        try:
+12            value = datetime.fromisoformat(value)
+13        except (TypeError, ValueError, AttributeError):
+14            self.raise_exception(msg=f'invalid value: {value} is not a datetime in ISO format', value=value)
+15
+16        return value
+
+ + +

Base class for validator classes.

+
+ + +
+ +
+
@overrides(Validator)
+ + def + validate(self, value: str) -> datetime.datetime: + + + +
+ +
 9    @overrides(Validator)
+10    def validate(self, value: str) -> datetime: # noqa: D102
+11        try:
+12            value = datetime.fromisoformat(value)
+13        except (TypeError, ValueError, AttributeError):
+14            self.raise_exception(msg=f'invalid value: {value} is not a datetime in ISO format', value=value)
+15
+16        return value
+
+ + +

Validates and convert the value. +Raises an [ValidatorException] in case of an invalid value. +To raise this you can simply call self.raise_exception().

+
+ + +
+
+
+ +
+ + class + DecoratorType(enum.StrEnum): + + + +
+ +
10class DecoratorType(StrEnum):
+11    """
+12    The interface that defines all possible decorators types.
+13
+14    The values of this enum are used as property names and the properties are added to the decorated functions.
+15    So I would recommend naming them with a leading underscore to keep them private and also write it lowercase.
+16
+17    Example:
+18        >>> class Decorators(DecoratorType):
+19        ...     FOO = '_foo'
+20    """
+
+ + +

The interface that defines all possible decorators types.

+ +

The values of this enum are used as property names and the properties are added to the decorated functions. +So I would recommend naming them with a leading underscore to keep them private and also write it lowercase.

+ +

Example:

+ +
+
+
+

class Decorators(DecoratorType): + ... FOO = '_foo'

+
+
+
+
+ + +
+
+ +
+ + class + Deserializable(abc.ABC): + + + +
+ +
 6class Deserializable(ABC):
+ 7    """A tiny interface which has a static from_json() method which acts like a named constructor."""
+ 8
+ 9    @staticmethod
+10    @abstractmethod
+11    def from_json(data: dict[str, Any]) -> 'Deserializable':
+12        """A named constructor which creates an object from JSON."""
+
+ + +

A tiny interface which has a static from_json() method which acts like a named constructor.

+
+ + +
+ +
+
@staticmethod
+
@abstractmethod
+ + def + from_json( data: dict[str, typing.Any]) -> Deserializable: + + + +
+ +
 9    @staticmethod
+10    @abstractmethod
+11    def from_json(data: dict[str, Any]) -> 'Deserializable':
+12        """A named constructor which creates an object from JSON."""
+
+ + +

A named constructor which creates an object from JSON.

+
+ + +
+
+
+ +
+ + class + Email(pedantic.Validator): + + + +
+ +
11class Email(Validator): # noqa: D101
+12    def __init__(self, email_pattern: str = REGEX_EMAIL, post_processor: Callable[[str], str] = lambda x: x) -> None: # noqa: D107
+13        self._pattern = email_pattern
+14        self._post_processor = post_processor
+15
+16    @overrides(Validator)
+17    def validate(self, value: str) -> str: # noqa: D102
+18        if not re.fullmatch(pattern=self._pattern, string=value):
+19            self.raise_exception(msg=f'invalid email address: {value}', value=value)
+20
+21        return self._post_processor(value)
+
+ + +

Base class for validator classes.

+
+ + +
+ +
+ + Email( email_pattern: str = '[^@\\s]+@[^@\\s]+\\.[a-zA-Z0-9]+$', post_processor: Callable[[str], str] = <function Email.<lambda>>) + + + +
+ +
12    def __init__(self, email_pattern: str = REGEX_EMAIL, post_processor: Callable[[str], str] = lambda x: x) -> None: # noqa: D107
+13        self._pattern = email_pattern
+14        self._post_processor = post_processor
+
+ + + + +
+
+ +
+
@overrides(Validator)
+ + def + validate(self, value: str) -> str: + + + +
+ +
16    @overrides(Validator)
+17    def validate(self, value: str) -> str: # noqa: D102
+18        if not re.fullmatch(pattern=self._pattern, string=value):
+19            self.raise_exception(msg=f'invalid email address: {value}', value=value)
+20
+21        return self._post_processor(value)
+
+ + +

Validates and convert the value. +Raises an [ValidatorException] in case of an invalid value. +To raise this you can simply call self.raise_exception().

+
+ + +
+
+
+ +
+ + class + EnvironmentVariableParameter(pedantic.ExternalParameter): + + + +
+ +
12class EnvironmentVariableParameter(ExternalParameter):   # noqa: D101
+13    def __init__(  # noqa: D107, PLR0913
+14        self,
+15        name: str,
+16        env_var_name: str | None = None,
+17        value_type: type[str | bool | int | float] = str,
+18        validators: Iterable[Validator] | None = None,
+19        required: bool = True,
+20default: Any = NoValue,
+21     ) -> None:
+22        super().__init__(name=name, validators=validators, default=default, value_type=value_type, required=required)
+23
+24        if value_type not in [str, bool, int, float]:
+25            raise AssertionError('value_type needs to be one of these: str, bool, int & float')
+26
+27        if env_var_name is None:
+28            self._env_var_name = name
+29        else:
+30            self._env_var_name = env_var_name
+31
+32    @overrides(ExternalParameter)
+33    def has_value(self) -> bool:   # noqa: D102
+34        return self._env_var_name in os.environ
+35
+36    @overrides(ExternalParameter)
+37    def load_value(self) -> Any:   # noqa: D102
+38        return os.environ[self._env_var_name].strip()
+
+ + +

The interface for all external parameters.

+
+ + +
+ +
+ + EnvironmentVariableParameter( name: str, env_var_name: str | None = None, value_type: type[str | bool | int | float] = <class 'str'>, validators: Iterable[Validator] | None = None, required: bool = True, default: Any = <class 'pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue'>) + + + +
+ +
13    def __init__(  # noqa: D107, PLR0913
+14        self,
+15        name: str,
+16        env_var_name: str | None = None,
+17        value_type: type[str | bool | int | float] = str,
+18        validators: Iterable[Validator] | None = None,
+19        required: bool = True,
+20default: Any = NoValue,
+21     ) -> None:
+22        super().__init__(name=name, validators=validators, default=default, value_type=value_type, required=required)
+23
+24        if value_type not in [str, bool, int, float]:
+25            raise AssertionError('value_type needs to be one of these: str, bool, int & float')
+26
+27        if env_var_name is None:
+28            self._env_var_name = name
+29        else:
+30            self._env_var_name = env_var_name
+
+ + + + +
+
+ +
+
@overrides(ExternalParameter)
+ + def + has_value(self) -> bool: + + + +
+ +
32    @overrides(ExternalParameter)
+33    def has_value(self) -> bool:   # noqa: D102
+34        return self._env_var_name in os.environ
+
+ + +

Returns True if the value can be fetched.

+
+ + +
+
+ +
+
@overrides(ExternalParameter)
+ + def + load_value(self) -> Any: + + + +
+ +
36    @overrides(ExternalParameter)
+37    def load_value(self) -> Any:   # noqa: D102
+38        return os.environ[self._env_var_name].strip()
+
+ + +

Loads a value and returns it.

+
+ + +
+
+
+ +
+ + class + ExternalParameter(pedantic.Parameter, abc.ABC): + + + +
+ +
 8class ExternalParameter(Parameter, ABC):
+ 9    """The interface for all external parameters."""
+10
+11    @abstractmethod
+12    def has_value(self) -> bool:
+13        """Returns True if the value can be fetched."""
+14
+15    @abstractmethod
+16    def load_value(self) -> Any:
+17        """Loads a value and returns it."""
+
+ + +

The interface for all external parameters.

+
+ + +
+ +
+
@abstractmethod
+ + def + has_value(self) -> bool: + + + +
+ +
11    @abstractmethod
+12    def has_value(self) -> bool:
+13        """Returns True if the value can be fetched."""
+
+ + +

Returns True if the value can be fetched.

+
+ + +
+
+ +
+
@abstractmethod
+ + def + load_value(self) -> Any: + + + +
+ +
15    @abstractmethod
+16    def load_value(self) -> Any:
+17        """Loads a value and returns it."""
+
+ + +

Loads a value and returns it.

+
+ + +
+
+
+ +
+ + class + ForEach(pedantic.Validator): + + + +
+ +
10class ForEach(Validator):  # noqa: D101
+11    def __init__(self, validators: Validator | Iterable[Validator]) -> None:  # noqa: D107
+12        if isinstance(validators, Validator):
+13            self._validators = [validators]
+14        else:
+15            self._validators = validators
+16
+17    @overrides(Validator)
+18    def validate(self, value: Iterable[Any]) -> list[Any]:  # noqa: D102
+19        if not isinstance(value, collections.abc.Iterable):
+20            self.raise_exception(msg=f'{value} is not iterable.', value=value)
+21
+22        results = []
+23
+24        for item in value:
+25            for validator in self._validators:
+26                item = validator.validate(item)  # noqa: PLW2901
+27
+28            results.append(item)
+29
+30        return results
+
+ + +

Base class for validator classes.

+
+ + +
+ +
+ + ForEach( validators: Validator | Iterable[Validator]) + + + +
+ +
11    def __init__(self, validators: Validator | Iterable[Validator]) -> None:  # noqa: D107
+12        if isinstance(validators, Validator):
+13            self._validators = [validators]
+14        else:
+15            self._validators = validators
+
+ + + + +
+
+ +
+
@overrides(Validator)
+ + def + validate(self, value: Iterable[typing.Any]) -> list[typing.Any]: + + + +
+ +
17    @overrides(Validator)
+18    def validate(self, value: Iterable[Any]) -> list[Any]:  # noqa: D102
+19        if not isinstance(value, collections.abc.Iterable):
+20            self.raise_exception(msg=f'{value} is not iterable.', value=value)
+21
+22        results = []
+23
+24        for item in value:
+25            for validator in self._validators:
+26                item = validator.validate(item)  # noqa: PLW2901
+27
+28            results.append(item)
+29
+30        return results
+
+ + +

Validates and convert the value. +Raises an [ValidatorException] in case of an invalid value. +To raise this you can simply call self.raise_exception().

+
+ + +
+
+
+ +
+ + class + GenericMixin: + + + +
+ +
  5class GenericMixin:
+  6    """
+  7    A mixin that provides easy access to given type variables.
+  8
+  9    Example:
+ 10        >>> from typing import Generic, TypeVar
+ 11        >>> T = TypeVar('T')
+ 12        >>> U = TypeVar('U')
+ 13        >>> class Foo(Generic[T, U], GenericMixin):
+ 14        ...     values: list[T]
+ 15        ...     value: U
+ 16        >>> f = Foo[str, int]()
+ 17        >>> f.type_vars
+ 18        {~T: <class 'str'>, ~U: <class 'int'>}
+ 19    """
+ 20
+ 21    @property
+ 22    def type_vars(self) -> dict[TypeVar, type]:
+ 23        """
+ 24        Returns the mapping of type variables to types.
+ 25
+ 26        DO NOT call this inside __init__()!
+ 27
+ 28        Example:
+ 29            >>> from typing import Generic, TypeVar
+ 30            >>> T = TypeVar('T')
+ 31            >>> U = TypeVar('U')
+ 32            >>> class Foo(Generic[T, U], GenericMixin):
+ 33            ...     values: list[T]
+ 34            ...     value: U
+ 35            >>> f = Foo[str, int]()
+ 36            >>> f.type_vars
+ 37            {~T: <class 'str'>, ~U: <class 'int'>}
+ 38        """
+ 39
+ 40        return self._get_resolved_typevars()
+ 41
+ 42    def _get_resolved_typevars(self) -> dict[TypeVar, type]:  # noqa: C901
+ 43        """
+ 44        Returns the resolved type vars.
+ 45
+ 46        Do not call this inside the __init__() method, because at that point the relevant information are not present.
+ 47        See also https://github.com/python/cpython/issues/90899'
+ 48        """
+ 49
+ 50        mapping: dict[TypeVar, type] = {}
+ 51        class_name = type(self).__name__
+ 52
+ 53        if not hasattr(self, '__orig_bases__'):
+ 54            raise AssertionError(
+ 55                f'{class_name} is not a generic class. To make it generic, declare it like: '
+ 56                f'class {class_name}(Generic[T], GenericMixin):...',
+ 57            )
+ 58
+ 59        def collect(base: type, substitutions: dict[TypeVar, type]) -> None:
+ 60            """Recursively collect type var mappings from a generic base."""
+ 61            origin = get_origin(base) or base
+ 62            args = get_args(base)
+ 63
+ 64            params = getattr(origin, '__parameters__', ())
+ 65            # copy substitutions so each recursion has its own view
+ 66            resolved = substitutions.copy()
+ 67
+ 68            for param, arg in zip(params, args, strict=False):
+ 69                if isinstance(arg, TypeVar):
+ 70                    processed_arg = substitutions.get(arg, arg)
+ 71                else:
+ 72                    processed_arg = arg
+ 73
+ 74                mapping[param] = processed_arg
+ 75                resolved[param] = processed_arg
+ 76
+ 77            # Recurse into base classes, applying current substitutions
+ 78            for super_base in getattr(origin, '__orig_bases__', []):
+ 79                super_origin = get_origin(super_base) or super_base
+ 80                super_args = get_args(super_base)
+ 81
+ 82                if super_args:
+ 83                    # Substitute any TypeVars in the super_base's args using resolved
+ 84                    substituted_args = tuple(
+ 85                        resolved.get(a, a) if isinstance(a, TypeVar) else a
+ 86                        for a in super_args
+ 87                    )
+ 88                    # Build a new parametrized base so get_args() inside collect sees substituted_args
+ 89                    try:
+ 90                        substituted_base = super_origin[substituted_args]  # type: ignore[index]
+ 91                    except TypeError:
+ 92                        # Some origins won't accept subscription; fall back to passing the origin and trusting resolved
+ 93                        substituted_base = super_base
+ 94                    collect(base=substituted_base, substitutions=resolved)
+ 95                else:
+ 96                    collect(base=super_base, substitutions=resolved)
+ 97
+ 98        # Start from __orig_class__ if present, else walk the declared MRO bases
+ 99        cls = getattr(self, '__orig_class__', None)
+100        if cls is not None:
+101            collect(base=cls, substitutions={})
+102        else:
+103            # Walk the full MRO to catch indirect generic ancestors
+104            for c in self.__class__.__mro__:
+105                for base in getattr(c, '__orig_bases__', []):
+106                    collect(base=base, substitutions=mapping)
+107
+108        # Ensure no unresolved TypeVars remain
+109        all_params = set()
+110        for c in self.__class__.__mro__:
+111            all_params.update(getattr(c, '__parameters__', ()))
+112
+113        unresolved = {p for p in all_params if p not in mapping or isinstance(mapping[p], TypeVar)}
+114        if unresolved:
+115            raise AssertionError(
+116                f'You need to instantiate this class with type parameters! Example: {class_name}[int]()\n'
+117                f'Also make sure that you do not call this in the __init__() method of your class!\n'
+118                f'Unresolved type variables: {unresolved}\n'
+119                f'See also https://github.com/python/cpython/issues/90899',
+120            )
+121
+122        return mapping
+
+ + +

A mixin that provides easy access to given type variables.

+ +

Example:

+ +
+
+
+

from typing import Generic, TypeVar + T = TypeVar('T') + U = TypeVar('U') + class Foo(Generic[T, U], GenericMixin): + ... values: list[T] + ... value: U + f = Foostr, int + f.type_vars + {~T: , ~U: }

+
+
+
+
+ + +
+ +
+ type_vars: dict[typing.TypeVar, type] + + + +
+ +
21    @property
+22    def type_vars(self) -> dict[TypeVar, type]:
+23        """
+24        Returns the mapping of type variables to types.
+25
+26        DO NOT call this inside __init__()!
+27
+28        Example:
+29            >>> from typing import Generic, TypeVar
+30            >>> T = TypeVar('T')
+31            >>> U = TypeVar('U')
+32            >>> class Foo(Generic[T, U], GenericMixin):
+33            ...     values: list[T]
+34            ...     value: U
+35            >>> f = Foo[str, int]()
+36            >>> f.type_vars
+37            {~T: <class 'str'>, ~U: <class 'int'>}
+38        """
+39
+40        return self._get_resolved_typevars()
+
+ + +

Returns the mapping of type variables to types.

+ +

DO NOT call this inside __init__()!

+ +

Example:

+ +
+
+
+

from typing import Generic, TypeVar + T = TypeVar('T') + U = TypeVar('U') + class Foo(Generic[T, U], GenericMixin): + ... values: list[T] + ... value: U + f = Foostr, int + f.type_vars + {~T: , ~U: }

+
+
+
+
+ + +
+
+
+ +
+ + class + InvalidHeader(pedantic.ParameterException): + + + +
+ +
70class InvalidHeader(ParameterException):
+71    """Is raised if there is a validation error in a FlaskHeaderParameter."""
+
+ + +

Is raised if there is a validation error in a FlaskHeaderParameter.

+
+ + +
+
+ +
+ + class + IsEnum(pedantic.Validator): + + + +
+ +
 9class IsEnum(Validator): # noqa: D101
+10    def __init__(self, enum: EnumMeta, convert: bool = True, to_upper_case: bool = True) -> None: # noqa: D107
+11        self._enum = enum
+12        self._convert = convert
+13        self._to_upper_case = to_upper_case
+14
+15    @overrides(Validator)
+16    def validate(self, value: Any) -> Any: # noqa: D102
+17        try:
+18            if isinstance(value, str) and self._to_upper_case:
+19                value = value.upper()
+20
+21            if issubclass(self._enum, IntEnum):
+22                enum_value = self._enum(int(value))
+23            else:
+24                enum_value = self._enum(value)
+25        except (ValueError, TypeError):
+26            return self.raise_exception(msg=f'Incorrect value {value} for enum {self._enum}.', value=value)
+27
+28        if self._convert:
+29            return enum_value
+30
+31        return value
+
+ + +

Base class for validator classes.

+
+ + +
+ +
+ + IsEnum( enum: enum.EnumType, convert: bool = True, to_upper_case: bool = True) + + + +
+ +
10    def __init__(self, enum: EnumMeta, convert: bool = True, to_upper_case: bool = True) -> None: # noqa: D107
+11        self._enum = enum
+12        self._convert = convert
+13        self._to_upper_case = to_upper_case
+
+ + + + +
+
+ +
+
@overrides(Validator)
+ + def + validate(self, value: Any) -> Any: + + + +
+ +
15    @overrides(Validator)
+16    def validate(self, value: Any) -> Any: # noqa: D102
+17        try:
+18            if isinstance(value, str) and self._to_upper_case:
+19                value = value.upper()
+20
+21            if issubclass(self._enum, IntEnum):
+22                enum_value = self._enum(int(value))
+23            else:
+24                enum_value = self._enum(value)
+25        except (ValueError, TypeError):
+26            return self.raise_exception(msg=f'Incorrect value {value} for enum {self._enum}.', value=value)
+27
+28        if self._convert:
+29            return enum_value
+30
+31        return value
+
+ + +

Validates and convert the value. +Raises an [ValidatorException] in case of an invalid value. +To raise this you can simply call self.raise_exception().

+
+ + +
+
+
+ +
+ + class + IsUuid(pedantic.Validator): + + + +
+ +
 8class IsUuid(Validator): # noqa: D101
+ 9    def __init__(self, convert: bool = False) -> None: # noqa: D107
+10        self._convert = convert
+11
+12    @overrides(Validator)
+13    def validate(self, value: str) -> str: # noqa: D102
+14        try:
+15            converted_value = UUID(str(value))
+16        except ValueError:
+17            return self.raise_exception(msg=f'{value} is not a valid UUID', value=value)
+18
+19        return converted_value if self._convert else value
+
+ + +

Base class for validator classes.

+
+ + +
+ +
+ + IsUuid(convert: bool = False) + + + +
+ +
 9    def __init__(self, convert: bool = False) -> None: # noqa: D107
+10        self._convert = convert
+
+ + + + +
+
+ +
+
@overrides(Validator)
+ + def + validate(self, value: str) -> str: + + + +
+ +
12    @overrides(Validator)
+13    def validate(self, value: str) -> str: # noqa: D102
+14        try:
+15            converted_value = UUID(str(value))
+16        except ValueError:
+17            return self.raise_exception(msg=f'{value} is not a valid UUID', value=value)
+18
+19        return converted_value if self._convert else value
+
+ + +

Validates and convert the value. +Raises an [ValidatorException] in case of an invalid value. +To raise this you can simply call self.raise_exception().

+
+ + +
+
+
+ +
+ + class + MatchPattern(pedantic.Validator): + + + +
+ +
 8class MatchPattern(Validator):  # noqa: D101
+ 9    def __init__(self, pattern: str) -> None:  # noqa: D107
+10        self._pattern = re.compile(pattern=pattern)
+11
+12    @overrides(Validator)
+13    def validate(self, value: str) -> str: # noqa: D102
+14        if not self._pattern.search(string=str(value)):
+15            self.raise_exception(msg=f'Value "{value}" does not match pattern {self._pattern.pattern}.', value=value)
+16
+17        return value
+
+ + +

Base class for validator classes.

+
+ + +
+ +
+ + MatchPattern(pattern: str) + + + +
+ +
 9    def __init__(self, pattern: str) -> None:  # noqa: D107
+10        self._pattern = re.compile(pattern=pattern)
+
+ + + + +
+
+ +
+
@overrides(Validator)
+ + def + validate(self, value: str) -> str: + + + +
+ +
12    @overrides(Validator)
+13    def validate(self, value: str) -> str: # noqa: D102
+14        if not self._pattern.search(string=str(value)):
+15            self.raise_exception(msg=f'Value "{value}" does not match pattern {self._pattern.pattern}.', value=value)
+16
+17        return value
+
+ + +

Validates and convert the value. +Raises an [ValidatorException] in case of an invalid value. +To raise this you can simply call self.raise_exception().

+
+ + +
+
+
+ +
+ + class + Max(pedantic.Validator): + + + +
+ +
 7class Max(Validator):  # noqa: D101
+ 8    def __init__(self, value: float, include_boundary: bool = True) -> None:
+ 9        """
+10        >>> Max(7, True).validate(7)
+11        7
+12        >>> Max(7, False).validate(7)  # doctest: +IGNORE_EXCEPTION_DETAIL
+13        Traceback (most recent call last):
+14        ValidatorException: ...
+15        >>> Max(7, False).validate(6.999)
+16        6.999
+17        """
+18        self._value = value
+19        self._include_boundary = include_boundary
+20
+21    @overrides(Validator)
+22    def validate(self, value: float) -> int | float:  # noqa: D102
+23        if value > self._value and self._include_boundary:
+24            self.raise_exception(msg=f'greater then allowed: {value} is not <= {self._value}', value=value)
+25        elif value >= self._value and not self._include_boundary:
+26            self.raise_exception(msg=f'greater then allowed: {value} is not < {self._value}', value=value)
+27
+28        return value
+
+ + +

Base class for validator classes.

+
+ + +
+ +
+ + Max(value: float, include_boundary: bool = True) + + + +
+ +
 8    def __init__(self, value: float, include_boundary: bool = True) -> None:
+ 9        """
+10        >>> Max(7, True).validate(7)
+11        7
+12        >>> Max(7, False).validate(7)  # doctest: +IGNORE_EXCEPTION_DETAIL
+13        Traceback (most recent call last):
+14        ValidatorException: ...
+15        >>> Max(7, False).validate(6.999)
+16        6.999
+17        """
+18        self._value = value
+19        self._include_boundary = include_boundary
+
+ + +
+
>>> Max(7, True).validate(7)
+7
+>>> Max(7, False).validate(7)  # doctest: +IGNORE_EXCEPTION_DETAIL
+Traceback (most recent call last):
+ValidatorException: ...
+>>> Max(7, False).validate(6.999)
+6.999
+
+
+
+ + +
+
+ +
+
@overrides(Validator)
+ + def + validate(self, value: float) -> int | float: + + + +
+ +
21    @overrides(Validator)
+22    def validate(self, value: float) -> int | float:  # noqa: D102
+23        if value > self._value and self._include_boundary:
+24            self.raise_exception(msg=f'greater then allowed: {value} is not <= {self._value}', value=value)
+25        elif value >= self._value and not self._include_boundary:
+26            self.raise_exception(msg=f'greater then allowed: {value} is not < {self._value}', value=value)
+27
+28        return value
+
+ + +

Validates and convert the value. +Raises an [ValidatorException] in case of an invalid value. +To raise this you can simply call self.raise_exception().

+
+ + +
+
+
+ +
+ + class + MaxLength(pedantic.Validator): + + + +
+ +
10class MaxLength(Validator):  # noqa: D101
+11    def __init__(self, length: int) -> None:  # noqa: D107
+12        self._length = length
+13
+14    @overrides(Validator)
+15    def validate(self, value: Sized) -> Any:  # noqa: D102
+16        if not isinstance(value, collections.abc.Sized):
+17            self.raise_exception(msg=f'{value} has no length.', value=value)
+18
+19        if len(value) > self._length:
+20            self.raise_exception(msg=f'{value} is too long with length {len(value)}.', value=value)
+21
+22        return value
+
+ + +

Base class for validator classes.

+
+ + +
+ +
+ + MaxLength(length: int) + + + +
+ +
11    def __init__(self, length: int) -> None:  # noqa: D107
+12        self._length = length
+
+ + + + +
+
+ +
+
@overrides(Validator)
+ + def + validate(self, value: Sized) -> Any: + + + +
+ +
14    @overrides(Validator)
+15    def validate(self, value: Sized) -> Any:  # noqa: D102
+16        if not isinstance(value, collections.abc.Sized):
+17            self.raise_exception(msg=f'{value} has no length.', value=value)
+18
+19        if len(value) > self._length:
+20            self.raise_exception(msg=f'{value} is too long with length {len(value)}.', value=value)
+21
+22        return value
+
+ + +

Validates and convert the value. +Raises an [ValidatorException] in case of an invalid value. +To raise this you can simply call self.raise_exception().

+
+ + +
+
+
+ +
+ + class + Min(pedantic.Validator): + + + +
+ +
 7class Min(Validator):  # noqa: D101
+ 8    def __init__(self, value: float, include_boundary: bool = True) -> None:
+ 9        """
+10        >>> Min(7, True).validate(7)
+11        7
+12        >>> Min(7, False).validate(7)  # doctest: +IGNORE_EXCEPTION_DETAIL
+13        Traceback (most recent call last):
+14        ValidatorException: ...
+15        >>> Min(7, False).validate(7.001)
+16        7.001
+17        """
+18        self._value = value
+19        self._include_boundary = include_boundary
+20
+21    @overrides(Validator)
+22    def validate(self, value: float) -> int | float:  # noqa: D102
+23        if value < self._value and self._include_boundary:
+24            self.raise_exception(msg=f'smaller then allowed: {value} is not >= {self._value}', value=value)
+25        elif value <= self._value and not self._include_boundary:
+26            self.raise_exception(msg=f'smaller then allowed: {value} is not > {self._value}', value=value)
+27
+28        return value
+
+ + +

Base class for validator classes.

+
+ + +
+ +
+ + Min(value: float, include_boundary: bool = True) + + + +
+ +
 8    def __init__(self, value: float, include_boundary: bool = True) -> None:
+ 9        """
+10        >>> Min(7, True).validate(7)
+11        7
+12        >>> Min(7, False).validate(7)  # doctest: +IGNORE_EXCEPTION_DETAIL
+13        Traceback (most recent call last):
+14        ValidatorException: ...
+15        >>> Min(7, False).validate(7.001)
+16        7.001
+17        """
+18        self._value = value
+19        self._include_boundary = include_boundary
+
+ + +
+
>>> Min(7, True).validate(7)
+7
+>>> Min(7, False).validate(7)  # doctest: +IGNORE_EXCEPTION_DETAIL
+Traceback (most recent call last):
+ValidatorException: ...
+>>> Min(7, False).validate(7.001)
+7.001
+
+
+
+ + +
+
+ +
+
@overrides(Validator)
+ + def + validate(self, value: float) -> int | float: + + + +
+ +
21    @overrides(Validator)
+22    def validate(self, value: float) -> int | float:  # noqa: D102
+23        if value < self._value and self._include_boundary:
+24            self.raise_exception(msg=f'smaller then allowed: {value} is not >= {self._value}', value=value)
+25        elif value <= self._value and not self._include_boundary:
+26            self.raise_exception(msg=f'smaller then allowed: {value} is not > {self._value}', value=value)
+27
+28        return value
+
+ + +

Validates and convert the value. +Raises an [ValidatorException] in case of an invalid value. +To raise this you can simply call self.raise_exception().

+
+ + +
+
+
+ +
+ + class + MinLength(pedantic.Validator): + + + +
+ +
10class MinLength(Validator):  # noqa: D101
+11    def __init__(self, length: int) -> None:  # noqa: D107
+12        self._length = length
+13
+14    @overrides(Validator)
+15    def validate(self, value: Sized) -> Any:  # noqa: D102
+16        if not isinstance(value, collections.abc.Sized):
+17            self.raise_exception(msg=f'{value} has no length.', value=value)
+18
+19        if len(value) < self._length:
+20            self.raise_exception(msg=f'{value} is too short with length {len(value)}.', value=value)
+21
+22        return value
+
+ + +

Base class for validator classes.

+
+ + +
+ +
+ + MinLength(length: int) + + + +
+ +
11    def __init__(self, length: int) -> None:  # noqa: D107
+12        self._length = length
+
+ + + + +
+
+ +
+
@overrides(Validator)
+ + def + validate(self, value: Sized) -> Any: + + + +
+ +
14    @overrides(Validator)
+15    def validate(self, value: Sized) -> Any:  # noqa: D102
+16        if not isinstance(value, collections.abc.Sized):
+17            self.raise_exception(msg=f'{value} has no length.', value=value)
+18
+19        if len(value) < self._length:
+20            self.raise_exception(msg=f'{value} is too short with length {len(value)}.', value=value)
+21
+22        return value
+
+ + +

Validates and convert the value. +Raises an [ValidatorException] in case of an invalid value. +To raise this you can simply call self.raise_exception().

+
+ + +
+
+
+ +
+ + class + NotEmpty(pedantic.Validator): + + + +
+ +
 9class NotEmpty(Validator):
+10    """Validates that the given value is not empty."""
+11
+12    def __init__(self, strip: bool = True) -> None:
+13        """If strip is True, the leading and trailing whitespace will be removed."""
+14        self.strip = strip
+15
+16    @overrides(Validator)
+17    def validate(self, value: Sequence) -> Sequence:
+18        """
+19        Throws a ValidationError if the sequence is empty.
+20        If the sequence is a string, it removes all leading and trailing whitespace.
+21        """
+22
+23        if isinstance(value, str):
+24            if not value.strip():
+25                self.raise_exception(msg='Got empty String which is invalid.', value=value)
+26
+27            return value.strip() if self.strip else value
+28        if isinstance(value, collections.abc.Sequence):
+29            if len(value) == 0:
+30                raise self.raise_exception(msg='Got empty  which is invalid.', value=value)
+31
+32            return value
+33
+34        return self.raise_exception(msg=f'Got {type(value)} which is not a Sequence.', value=value)
+
+ + +

Validates that the given value is not empty.

+
+ + +
+ +
+ + NotEmpty(strip: bool = True) + + + +
+ +
12    def __init__(self, strip: bool = True) -> None:
+13        """If strip is True, the leading and trailing whitespace will be removed."""
+14        self.strip = strip
+
+ + +

If strip is True, the leading and trailing whitespace will be removed.

+
+ + +
+
+
+ strip + + +
+ + + + +
+
+ +
+
@overrides(Validator)
+ + def + validate(self, value: Sequence) -> Sequence: + + + +
+ +
16    @overrides(Validator)
+17    def validate(self, value: Sequence) -> Sequence:
+18        """
+19        Throws a ValidationError if the sequence is empty.
+20        If the sequence is a string, it removes all leading and trailing whitespace.
+21        """
+22
+23        if isinstance(value, str):
+24            if not value.strip():
+25                self.raise_exception(msg='Got empty String which is invalid.', value=value)
+26
+27            return value.strip() if self.strip else value
+28        if isinstance(value, collections.abc.Sequence):
+29            if len(value) == 0:
+30                raise self.raise_exception(msg='Got empty  which is invalid.', value=value)
+31
+32            return value
+33
+34        return self.raise_exception(msg=f'Got {type(value)} which is not a Sequence.', value=value)
+
+ + +

Throws a ValidationError if the sequence is empty. +If the sequence is a string, it removes all leading and trailing whitespace.

+
+ + +
+
+
+ +
+ + class + Parameter: + + + +
+ +
14class Parameter:  # noqa: D101
+15    exception_type: type[ParameterException] = ParameterException
+16
+17    def __init__(  # noqa: D107
+18        self,
+19        name: str,
+20        value_type: type[bool | int | float | str | dict | list] | None = None,
+21        validators: Iterable[Validator] | None = None,
+22        default: Any = NoValue,
+23        required: bool = True,
+24     ) -> None:
+25        self.name = name
+26        self.validators = validators or []
+27        self.default_value = default
+28        self.value_type = value_type
+29        self.is_required = False if default != NoValue else required
+30
+31        if value_type not in [str, bool, int, float, dict, list, None]:
+32            raise AssertionError('value_type needs to be one of these: str, bool, int, float, dict & list')
+33
+34    def validate(self, value: Any) -> Any:
+35        """Apply all validators to the given value and collect all ValidationErrors."""
+36
+37        if value is None:
+38            if self.is_required:
+39                self.raise_exception(msg=f'Value for key {self.name} is required.')
+40
+41            return None
+42
+43        if self.value_type is not None:
+44            try:
+45                result_value = convert_value(value=value, target_type=self.value_type)
+46            except ConversionError as ex:
+47                return self.raise_exception(value=value, msg=ex.message)
+48        else:
+49            result_value = value
+50
+51        for validator in self.validators:
+52            try:
+53                result_value = validator.validate(result_value)
+54            except ValidatorException as e:
+55                raise self.exception_type.from_validator_exception(exception=e, parameter_name=self.name) from e
+56
+57        return result_value
+58
+59    def raise_exception(self, msg: str, value: Any = None, validator: Validator | None = None) -> NoReturn:  # noqa: D102
+60        raise self.exception_type(
+61            value=value,
+62            parameter_name=self.name,
+63            msg=msg,
+64            validator_name=validator.name if validator else None,
+65        )
+66
+67    def __str__(self) -> str:
+68        return self.__class__.__name__ + ' name=' + self.name
+
+ + + + +
+ +
+ + Parameter( name: str, value_type: type[bool | int | float | str | dict | list] | None = None, validators: Iterable[Validator] | None = None, default: Any = <class 'pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue'>, required: bool = True) + + + +
+ +
17    def __init__(  # noqa: D107
+18        self,
+19        name: str,
+20        value_type: type[bool | int | float | str | dict | list] | None = None,
+21        validators: Iterable[Validator] | None = None,
+22        default: Any = NoValue,
+23        required: bool = True,
+24     ) -> None:
+25        self.name = name
+26        self.validators = validators or []
+27        self.default_value = default
+28        self.value_type = value_type
+29        self.is_required = False if default != NoValue else required
+30
+31        if value_type not in [str, bool, int, float, dict, list, None]:
+32            raise AssertionError('value_type needs to be one of these: str, bool, int, float, dict & list')
+
+ + + + +
+
+
+ exception_type: type[ParameterException] = +<class 'ParameterException'> + + +
+ + + + +
+
+
+ name + + +
+ + + + +
+
+
+ validators + + +
+ + + + +
+
+
+ default_value + + +
+ + + + +
+
+
+ value_type + + +
+ + + + +
+
+
+ is_required + + +
+ + + + +
+
+ +
+ + def + validate(self, value: Any) -> Any: + + + +
+ +
34    def validate(self, value: Any) -> Any:
+35        """Apply all validators to the given value and collect all ValidationErrors."""
+36
+37        if value is None:
+38            if self.is_required:
+39                self.raise_exception(msg=f'Value for key {self.name} is required.')
+40
+41            return None
+42
+43        if self.value_type is not None:
+44            try:
+45                result_value = convert_value(value=value, target_type=self.value_type)
+46            except ConversionError as ex:
+47                return self.raise_exception(value=value, msg=ex.message)
+48        else:
+49            result_value = value
+50
+51        for validator in self.validators:
+52            try:
+53                result_value = validator.validate(result_value)
+54            except ValidatorException as e:
+55                raise self.exception_type.from_validator_exception(exception=e, parameter_name=self.name) from e
+56
+57        return result_value
+
+ + +

Apply all validators to the given value and collect all ValidationErrors.

+
+ + +
+
+ +
+ + def + raise_exception( self, msg: str, value: Any = None, validator: Validator | None = None) -> NoReturn: + + + +
+ +
59    def raise_exception(self, msg: str, value: Any = None, validator: Validator | None = None) -> NoReturn:  # noqa: D102
+60        raise self.exception_type(
+61            value=value,
+62            parameter_name=self.name,
+63            msg=msg,
+64            validator_name=validator.name if validator else None,
+65        )
+
+ + + + +
+
+
+ +
+ + class + ParameterException(pedantic.ValidateException): + + + +
+ +
32class ParameterException(ValidateException):
+33    """An exception that is raised inside a Parameter."""
+34
+35    def __init__( # noqa: D107
+36        self,
+37        msg: str,
+38        parameter_name: str,
+39        value: Any | None = None,
+40        validator_name: str | None = None,
+41    ) -> None:
+42        super().__init__(msg=msg)
+43        self.validator_name = validator_name
+44        self.parameter_name = parameter_name
+45        self.value = value
+46
+47    @classmethod
+48    def from_validator_exception(cls, exception: ValidatorException, parameter_name: str = '') -> 'ParameterException':
+49        """Creates a parameter exception from a validator exception."""
+50        return cls(
+51            value=exception.value,
+52            msg=exception.message,
+53            validator_name=exception.validator_name,
+54            parameter_name=parameter_name or exception.parameter_name,
+55        )
+56
+57    def __str__(self) -> str:
+58        return str(self.to_dict)
+59
+60    @property
+61    def to_dict(self) -> dict[str, str]:  # noqa: D102
+62        return {
+63            ExceptionDictKey.VALUE: str(self.value),
+64            ExceptionDictKey.MESSAGE: self.message,
+65            ExceptionDictKey.VALIDATOR: self.validator_name,
+66            ExceptionDictKey.PARAMETER: self.parameter_name,
+67        }
+
+ + +

An exception that is raised inside a Parameter.

+
+ + +
+ +
+ + ParameterException( msg: str, parameter_name: str, value: typing.Any | None = None, validator_name: str | None = None) + + + +
+ +
35    def __init__( # noqa: D107
+36        self,
+37        msg: str,
+38        parameter_name: str,
+39        value: Any | None = None,
+40        validator_name: str | None = None,
+41    ) -> None:
+42        super().__init__(msg=msg)
+43        self.validator_name = validator_name
+44        self.parameter_name = parameter_name
+45        self.value = value
+
+ + + + +
+
+
+ validator_name + + +
+ + + + +
+
+
+ parameter_name + + +
+ + + + +
+
+
+ value + + +
+ + + + +
+
+ +
+
@classmethod
+ + def + from_validator_exception( cls, exception: ValidatorException, parameter_name: str = '') -> ParameterException: + + + +
+ +
47    @classmethod
+48    def from_validator_exception(cls, exception: ValidatorException, parameter_name: str = '') -> 'ParameterException':
+49        """Creates a parameter exception from a validator exception."""
+50        return cls(
+51            value=exception.value,
+52            msg=exception.message,
+53            validator_name=exception.validator_name,
+54            parameter_name=parameter_name or exception.parameter_name,
+55        )
+
+ + +

Creates a parameter exception from a validator exception.

+
+ + +
+
+ +
+ to_dict: dict[str, str] + + + +
+ +
60    @property
+61    def to_dict(self) -> dict[str, str]:  # noqa: D102
+62        return {
+63            ExceptionDictKey.VALUE: str(self.value),
+64            ExceptionDictKey.MESSAGE: self.message,
+65            ExceptionDictKey.VALIDATOR: self.validator_name,
+66            ExceptionDictKey.PARAMETER: self.parameter_name,
+67        }
+
+ + + + +
+
+
+ +
+ + class + ReturnAs(enum.Enum): + + + +
+ +
21class ReturnAs(Enum):  # noqa: D101
+22    ARGS = 'ARGS'
+23    KWARGS_WITH_NONE = 'KWARGS_WITH_NONE'
+24    KWARGS_WITHOUT_NONE = 'KWARGS_WITHOUT_NONE'
+
+ + + + +
+
+ ARGS = +<ReturnAs.ARGS: 'ARGS'> + + +
+ + + + +
+
+
+ KWARGS_WITH_NONE = +<ReturnAs.KWARGS_WITH_NONE: 'KWARGS_WITH_NONE'> + + +
+ + + + +
+
+
+ KWARGS_WITHOUT_NONE = +<ReturnAs.KWARGS_WITHOUT_NONE: 'KWARGS_WITHOUT_NONE'> + + +
+ + + + +
+
+
+ +
+ + class + TooManyArguments(pedantic.ValidateException): + + + +
+ +
74class TooManyArguments(ValidateException):
+75    """Is raised if the function got more arguments than expected."""
+
+ + +

Is raised if the function got more arguments than expected.

+
+ + +
+
+ +
+ + class + ValidateException(builtins.Exception): + + + +
+ +
12class ValidateException(Exception):  # noqa: N818
+13    """The base class for all exception thrown by the validate decorator."""
+14
+15    def __init__(self, msg: str) -> None: # noqa: D107
+16        self.message = msg
+
+ + +

The base class for all exception thrown by the validate decorator.

+
+ + +
+ +
+ + ValidateException(msg: str) + + + +
+ +
15    def __init__(self, msg: str) -> None: # noqa: D107
+16        self.message = msg
+
+ + + + +
+
+
+ message + + +
+ + + + +
+
+
+ +
+ + class + Validator(abc.ABC): + + + +
+ +
 8class Validator(ABC):
+ 9    """Base class for validator classes."""
+10
+11    @abstractmethod
+12    def validate(self, value: Any) -> Any:
+13        """
+14        Validates and convert the value.
+15        Raises an [ValidatorException] in case of an invalid value.
+16        To raise this you can simply call self.raise_exception().
+17        """
+18
+19    def validate_param(self, value: Any, parameter_name: str) -> Any:
+20        """
+21        Validates and converts the value, just like [validate()].
+22        The difference is that a parameter_name is included in the exception, if an exception is raised.
+23        """
+24
+25        try:
+26            return self.validate(value=value)
+27        except ValidatorException as ex:
+28            ex.parameter_name = parameter_name
+29            raise
+30
+31    def raise_exception(self, value: Any, msg: str) -> NoReturn:  # noqa: D102
+32        raise ValidatorException(value=value, validator_name=self.name, msg=msg)
+33
+34    @property
+35    def name(self) -> str: # noqa: D102
+36        return self.__class__.__name__
+
+ + +

Base class for validator classes.

+
+ + +
+ +
+
@abstractmethod
+ + def + validate(self, value: Any) -> Any: + + + +
+ +
11    @abstractmethod
+12    def validate(self, value: Any) -> Any:
+13        """
+14        Validates and convert the value.
+15        Raises an [ValidatorException] in case of an invalid value.
+16        To raise this you can simply call self.raise_exception().
+17        """
+
+ + +

Validates and convert the value. +Raises an [ValidatorException] in case of an invalid value. +To raise this you can simply call self.raise_exception().

+
+ + +
+
+ +
+ + def + validate_param(self, value: Any, parameter_name: str) -> Any: + + + +
+ +
19    def validate_param(self, value: Any, parameter_name: str) -> Any:
+20        """
+21        Validates and converts the value, just like [validate()].
+22        The difference is that a parameter_name is included in the exception, if an exception is raised.
+23        """
+24
+25        try:
+26            return self.validate(value=value)
+27        except ValidatorException as ex:
+28            ex.parameter_name = parameter_name
+29            raise
+
+ + +

Validates and converts the value, just like [validate()]. +The difference is that a parameter_name is included in the exception, if an exception is raised.

+
+ + +
+
+ +
+ + def + raise_exception(self, value: Any, msg: str) -> NoReturn: + + + +
+ +
31    def raise_exception(self, value: Any, msg: str) -> NoReturn:  # noqa: D102
+32        raise ValidatorException(value=value, validator_name=self.name, msg=msg)
+
+ + + + +
+
+ +
+ name: str + + + +
+ +
34    @property
+35    def name(self) -> str: # noqa: D102
+36        return self.__class__.__name__
+
+ + + + +
+
+
+ +
+ + class + ValidatorException(pedantic.ValidateException): + + + +
+ +
19class ValidatorException(ValidateException):
+20    """An exception that is raised inside the validate() function of a Validator."""
+21
+22    def __init__(self, msg: str, validator_name: str, value: Any, parameter_name: str = '') -> None: # noqa: D107
+23        super().__init__(msg=msg)
+24        self.validator_name = validator_name
+25        self.value = value
+26        self.parameter_name = parameter_name
+27
+28    def __str__(self) -> str:
+29        return f'{self.validator_name}: {self.message} Value: {self.value}'
+
+ + +

An exception that is raised inside the validate() function of a Validator.

+
+ + +
+ +
+ + ValidatorException(msg: str, validator_name: str, value: Any, parameter_name: str = '') + + + +
+ +
22    def __init__(self, msg: str, validator_name: str, value: Any, parameter_name: str = '') -> None: # noqa: D107
+23        super().__init__(msg=msg)
+24        self.validator_name = validator_name
+25        self.value = value
+26        self.parameter_name = parameter_name
+
+ + + + +
+
+
+ validator_name + + +
+ + + + +
+
+
+ value + + +
+ + + + +
+
+
+ parameter_name + + +
+ + + + +
+
+
+ +
+ + class + WithDecoratedMethods(abc.ABC, pedantic.GenericMixin, typing.Generic[~DecoratorTypeVar]): + + + +
+ +
 52class WithDecoratedMethods(ABC, GenericMixin, Generic[DecoratorTypeVar]):
+ 53    """
+ 54    A mixin that is used to figure out which method is decorated with custom parameterized decorators.
+ 55
+ 56    Example:
+ 57        >>> class Decorators(DecoratorType):
+ 58        ...     FOO = '_foo'
+ 59        ...     BAR = '_bar'
+ 60        >>> foo = create_decorator(decorator_type=Decorators.FOO)
+ 61        >>> bar = create_decorator(decorator_type=Decorators.BAR)
+ 62        >>> class MyClass(WithDecoratedMethods[Decorators]):
+ 63        ...    @foo(42)
+ 64        ...    def m1(self) -> None:
+ 65        ...        print('bar')
+ 66        ...
+ 67        ...    @foo(value=43)
+ 68        ...    def m2(self) -> None:
+ 69        ...        print('bar')
+ 70        ...
+ 71        ...    @bar(value=44)
+ 72        ...    def m3(self) -> None:
+ 73        ...        print('bar')
+ 74        >>> instance = MyClass()
+ 75        >>> instance.get_decorated_functions()  # doctest: +SKIP
+ 76        {
+ 77            <Decorators.FOO: '_foo'>: {
+ 78                <bound method MyClass.m1 of <__main__.MyClass object at 0x7fea7a6e2610>>: 42,
+ 79                <bound method MyClass.m2 of <__main__.MyClass object at 0x7fea7a6e2610>>: 43,
+ 80            },
+ 81            <Decorators.BAR: '_bar'>: {
+ 82                <bound method MyClass.m3 of <__main__.MyClass object at 0x7fea7a6e2610>>: 44,
+ 83            }
+ 84        }
+ 85    """
+ 86
+ 87    def get_decorated_functions(self) -> dict[DecoratorTypeVar, dict[C, T]]:
+ 88        """Returns a mapping of all functions that are decorated by the given decorator type."""
+ 89
+ 90        decorator_types: DecoratorTypeVar = self.type_vars[DecoratorTypeVar]  # type: ignore[assignment]
+ 91        decorated_functions = {t: {} for t in decorator_types}
+ 92
+ 93        for attribute_name in dir(self):
+ 94            if attribute_name.startswith('__') or attribute_name in ['type_var', 'type_vars']:
+ 95                continue
+ 96
+ 97            try:
+ 98                attribute = getattr(self, attribute_name)
+ 99            except BaseException:  # noqa: BLE001
+100                continue  # ignore bad attributes
+101
+102            for decorator_type in decorator_types:
+103                if hasattr(attribute, decorator_type):
+104                    decorated_functions[decorator_type][attribute] = getattr(attribute, decorator_type)
+105
+106        return decorated_functions
+
+ + +

A mixin that is used to figure out which method is decorated with custom parameterized decorators.

+ +

Example:

+ +
+
+
+

class Decorators(DecoratorType): + ... FOO = '_foo' + ... BAR = '_bar' + foo = create_decorator(decorator_type=Decorators.FOO) + bar = create_decorator(decorator_type=Decorators.BAR) + class MyClass(WithDecoratedMethods[Decorators]): + ... @foo(42) + ... def m1(self) -> None: + ... print('bar') + ... + ... @foo(value=43) + ... def m2(self) -> None: + ... print('bar') + ... + ... @bar(value=44) + ... def m3(self) -> None: + ... print('bar') + instance = MyClass() + instance.get_decorated_functions() # doctest: +SKIP + { + : { + >: 42, + >: 43, + }, + : { + >: 44, + } + }

+
+
+
+
+ + +
+ +
+ + def + get_decorated_functions(self) -> dict[~DecoratorTypeVar, dict[~C, ~T]]: + + + +
+ +
 87    def get_decorated_functions(self) -> dict[DecoratorTypeVar, dict[C, T]]:
+ 88        """Returns a mapping of all functions that are decorated by the given decorator type."""
+ 89
+ 90        decorator_types: DecoratorTypeVar = self.type_vars[DecoratorTypeVar]  # type: ignore[assignment]
+ 91        decorated_functions = {t: {} for t in decorator_types}
+ 92
+ 93        for attribute_name in dir(self):
+ 94            if attribute_name.startswith('__') or attribute_name in ['type_var', 'type_vars']:
+ 95                continue
+ 96
+ 97            try:
+ 98                attribute = getattr(self, attribute_name)
+ 99            except BaseException:  # noqa: BLE001
+100                continue  # ignore bad attributes
+101
+102            for decorator_type in decorator_types:
+103                if hasattr(attribute, decorator_type):
+104                    decorated_functions[decorator_type][attribute] = getattr(attribute, decorator_type)
+105
+106        return decorated_functions
+
+ + +

Returns a mapping of all functions that are decorated by the given decorator type.

+
+ + +
+
+
+ +
+ + def + assert_value_matches_type( value: Any, type_: Any, err: str, type_vars: Dict[TypeVar, Any], key: str | None = None, msg: str | None = None, context: Optional[Dict[str, Any]] = None) -> None: + + + +
+ +
17def assert_value_matches_type(  # noqa: PLR0913
+18    value: Any,
+19    type_: Any,
+20    err: str,
+21    type_vars: Dict[TypeVar_, Any],
+22    key: str | None = None,
+23    msg: str | None = None,
+24    context: Dict[str, Any] | None = None,
+25) -> None:
+26    """Checks that the given value matches the given type."""
+27
+28    if not _check_type(value=value, type_=type_, err=err, type_vars=type_vars, context=context):
+29        t = type(value)
+30        value = f'{key}={value}' if key is not None else str(value)
+31
+32        if not msg:
+33            msg = f'{err}Type hint is incorrect: Argument {value} of type {t} does not match expected type {type_}.'
+34
+35        raise PedanticTypeCheckException(msg)
+
+ + +

Checks that the given value matches the given type.

+
+ + +
+
+ +
+ + async def + calculate_in_subprocess( func: Callable[..., typing.Union[~T, Awaitable[~T]]], *args: Any, **kwargs: Any) -> ~T: + + + +
+ +
 53async def calculate_in_subprocess(func: Callable[..., T | Awaitable[T]], *args: Any, **kwargs: Any) -> T:
+ 54    """
+ 55    Calculates the result of a synchronous function in subprocess without blocking the current thread.
+ 56
+ 57    Arguments:
+ 58        func: The function that will be called in a subprocess.
+ 59        args: Positional arguments that will be passed to the function.
+ 60        kwargs: Keyword arguments that will be passed to the function.
+ 61
+ 62    Returns:
+ 63         The calculated result of the function "func".
+ 64
+ 65    Raises:
+ 66        Any Exception that is raised inside [func].
+ 67
+ 68    Further reading: https://medium.com/devopss-hole/python-multiprocessing-pickle-issue-e2d35ccf96a9
+ 69
+ 70    Example:
+ 71        >>> import time
+ 72        >>> import asyncio
+ 73        >>> def f(value: int) -> int:
+ 74        ...     time.sleep(0.1)  # a long taking synchronous blocking calculation
+ 75        ...     return 2 * value
+ 76        >>> asyncio.run(calculate_in_subprocess(func=f, value=42))
+ 77        84
+ 78    """
+ 79
+ 80    if Pipe is None:
+ 81        raise ImportError('You need to install the multiprocess package to use this: pip install multiprocess')
+ 82
+ 83    rx, tx = Pipe(duplex=False)  # receiver & transmitter ; Pipe is one-way only
+ 84    process = Process(target=_inner, args=(tx, func, *args), kwargs=kwargs)
+ 85    process.start()
+ 86
+ 87    event = asyncio.Event()
+ 88    loop = asyncio.get_event_loop()
+ 89    loop.add_reader(fd=rx.fileno(), callback=event.set)
+ 90
+ 91    if not rx.poll():  # do not use process.is_alive() as condition here
+ 92        await event.wait()
+ 93
+ 94    loop.remove_reader(fd=rx.fileno())
+ 95    event.clear()
+ 96
+ 97    result = rx.recv()
+ 98    process.join()  # this blocks synchronously! make sure that process is terminated before you call join()
+ 99    rx.close()
+100    tx.close()
+101
+102    if isinstance(result, SubprocessError):
+103        raise result.exception
+104
+105    return result
+
+ + +

Calculates the result of a synchronous function in subprocess without blocking the current thread.

+ +

Arguments: + func: The function that will be called in a subprocess. + args: Positional arguments that will be passed to the function. + kwargs: Keyword arguments that will be passed to the function.

+ +

Returns: + The calculated result of the function "func".

+ +

Raises: + Any Exception that is raised inside [func].

+ +

Further reading: https://medium.com/devopss-hole/python-multiprocessing-pickle-issue-e2d35ccf96a9

+ +

Example:

+ +
+
+
+

import time + import asyncio + def f(value: int) -> int: + ... time.sleep(0.1) # a long taking synchronous blocking calculation + ... return 2 * value + asyncio.run(calculate_in_subprocess(func=f, value=42)) + 84

+
+
+
+
+ + +
+
+ +
+ + def + create_decorator( decorator_type: DecoratorType, transformation: Callable[[~C, DecoratorType, ~T], ~C] | None = None) -> Callable[[~T], Callable[[~C], ~C]]: + + + +
+ +
28def create_decorator(
+29    decorator_type: DecoratorType,
+30    transformation: Callable[[C, DecoratorType, T], C] | None = None,
+31) -> Callable[[T], Callable[[C], C]]:
+32    """
+33    Creates a new decorator that is parametrized with one argument of an arbitrary type.
+34
+35    You can also pass an arbitrary [transformation] to add custom behavior to the decorator.
+36    """
+37
+38    def decorator(value: T) -> Callable[[C], C]:
+39        def fun(f: C) -> C:
+40            setattr(f, decorator_type, value)
+41
+42            if transformation is None:
+43                return f
+44
+45            return transformation(f, decorator_type, value)
+46
+47        return fun  # we do not need functools.wraps, because we return the original function here
+48
+49    return decorator
+
+ + +

Creates a new decorator that is parametrized with one argument of an arbitrary type.

+ +

You can also pass an arbitrary [transformation] to add custom behavior to the decorator.

+
+ + +
+
+ +
+ + def + deprecated( func: Callable[..., ~ReturnType] | None = None, message: str = '') -> Callable[..., ~ReturnType] | Callable[[Callable[..., ~ReturnType]], Callable[..., ~ReturnType]]: + + + +
+ +
16def deprecated(func: F | None = None, message: str = '') -> F | Callable[[F], F]:
+17    """
+18    Use this decorator to mark a function as deprecated. It will raise a warning when the function is called.
+19    You can specify an optional reason or message to display with the warning.
+20
+21    If you use Python 3.13 or newer, consider using warnings.deprecated instead from the standard library.
+22
+23    Example:
+24    >>> @deprecated
+25    ... def my_function(a, b, c):
+26    ...     pass
+27    >>> my_function(5, 4, 3)  # doctest: +SKIP
+28    >>> @deprecated(message='Will be removed soon. Please use my_function_new_instead.')
+29    ... def my_function(a, b, c):
+30    ...     pass
+31    >>> my_function(5, 4, 3)  # doctest: +SKIP
+32    """
+33
+34    def decorator(fun: F) -> F:
+35        @wraps(fun)
+36        def wrapper(*args: Any, **kwargs: Any) -> ReturnType:
+37            msg = f'Call to deprecated function {fun.__qualname__}.'
+38
+39            if message:
+40                msg += f'\nReason: {message}'
+41
+42            warnings.warn(message=msg, category=DeprecationWarning, stacklevel=2)
+43            return fun(*args, **kwargs)
+44        return wrapper
+45    return decorator if func is None else decorator(func)
+
+ + +

Use this decorator to mark a function as deprecated. It will raise a warning when the function is called. +You can specify an optional reason or message to display with the warning.

+ +

If you use Python 3.13 or newer, consider using warnings.deprecated instead from the standard library.

+ +

Example:

+ +
+
>>> @deprecated
+... def my_function(a, b, c):
+...     pass
+>>> my_function(5, 4, 3)  # doctest: +SKIP
+>>> @deprecated(message='Will be removed soon. Please use my_function_new_instead.')
+... def my_function(a, b, c):
+...     pass
+>>> my_function(5, 4, 3)  # doctest: +SKIP
+
+
+
+ + +
+
+ +
+ + def + for_all_methods(decorator: Callable[..., ~ReturnType]) -> Callable[[type[~C]], type[~C]]: + + + +
+ +
17def for_all_methods(decorator: F) -> Callable[[type[C]], type[C]]:
+18    """
+19    Applies a decorator to all methods of a class.
+20
+21    Example:
+22    >>> @for_all_methods(pedantic)
+23    ... class MyClass(object):
+24    ...     def m1(self): pass
+25    ...     def m2(self, x): pass
+26    """
+27    def decorate(cls: C) -> C:
+28        if issubclass(cls, enum.Enum):
+29            raise PedanticTypeCheckException(f'Enum "{cls}" cannot be decorated with "@pedantic_class". '
+30                                             f'Enums are not supported yet.')
+31
+32        if is_dataclass(obj=cls):
+33            raise PedanticTypeCheckException(f'Dataclass "{cls}" cannot be decorated with "@pedantic_class". '
+34                                             f'Try to write "@dataclass" over "@pedantic_class".')
+35
+36        for attr in cls.__dict__:
+37            attr_value = getattr(cls, attr)
+38
+39            if isinstance(attr_value, (types.FunctionType, types.MethodType)) and attr != '__annotate_func__':
+40                setattr(cls, attr, decorator(attr_value))
+41            elif isinstance(attr_value, property):
+42                prop = attr_value
+43                wrapped_getter = _get_wrapped(prop=prop.fget, decorator=decorator)
+44                wrapped_setter = _get_wrapped(prop=prop.fset, decorator=decorator)
+45                wrapped_deleter = _get_wrapped(prop=prop.fdel, decorator=decorator)
+46                new_prop = property(fget=wrapped_getter, fset=wrapped_setter, fdel=wrapped_deleter)
+47                setattr(cls, attr, new_prop)
+48
+49        _add_type_var_attr_and_method_to_class(cls=cls)
+50        return cls
+51    return decorate
+
+ + +

Applies a decorator to all methods of a class.

+ +

Example:

+ +
+
>>> @for_all_methods(pedantic)
+... class MyClass(object):
+...     def m1(self): pass
+...     def m2(self, x): pass
+
+
+
+ + +
+
+ +
+ + def + frozen_dataclass( cls: type[~T] | None = None, type_safe: bool = False, order: bool = False, kw_only: bool = True, slots: bool = False) -> type[~T] | Callable[[type[~T]], type[~T]]: + + + +
+ +
 19def frozen_dataclass(  # noqa: C901
+ 20    cls: type[T] | None = None,
+ 21    type_safe: bool = False,
+ 22    order: bool = False,
+ 23    kw_only: bool = True,
+ 24    slots: bool = False,
+ 25) -> type[T] | Callable[[type[T]], type[T]]:
+ 26    """
+ 27    Makes the decorated class immutable and a dataclass by adding the [@dataclass(frozen=True)]
+ 28    decorator. Also adds useful copy_with() and validate_types() instance methods to this class (see below).
+ 29
+ 30    If [type_safe] is True, a type check is performed for each field after the __post_init__ method was called
+ 31    which itself s directly called after the __init__ constructor.
+ 32    Note this have a negative impact on the performance. It's recommend to use this for debugging and testing only.
+ 33
+ 34    In a nutshell, the followings methods will be added to the decorated class automatically:
+ 35    - __init__() gives you a simple constructor like "Foo(a=6, b='hi', c=True)"
+ 36    - __eq__() lets you compare objects easily with "a == b"
+ 37    - __hash__() is also needed for instance comparison
+ 38    - __repr__() gives you a nice output when you call "print(foo)"
+ 39    - copy_with() allows you to quickly create new similar frozen instances. Use this instead of setters.
+ 40    - deep_copy_with() allows you to create deep copies and modify them.
+ 41    - validate_types() allows you to validate the types of the dataclass.
+ 42                       This is called automatically when [type_safe] is True.
+ 43
+ 44    If the [order] parameter is True (default is False), the following comparison methods
+ 45    will be added additionally:
+ 46    - __lt__() lets you compare instance like "a < b"
+ 47    - __le__() lets you compare instance like "a <= b"
+ 48    - __gt__() lets you compare instance like "a > b"
+ 49    - __ge__() lets you compare instance like "a >= b"
+ 50
+ 51    These compare the class as if it were a tuple of its fields, in order.
+ 52    Both instances in the comparison must be of the identical type.
+ 53
+ 54    The parameters slots and kw_only are only applied if the Python version is greater or equal to 3.10.
+ 55
+ 56    Example:
+ 57    >>> @frozen_dataclass
+ 58    ... class Foo:
+ 59    ...     a: int
+ 60    ...     b: str
+ 61    ...     c: bool
+ 62    >>> foo = Foo(a=6, b='hi', c=True)
+ 63    >>> print(foo)
+ 64    Foo(a=6, b='hi', c=True)
+ 65    >>> print(foo.copy_with())
+ 66    Foo(a=6, b='hi', c=True)
+ 67    >>> print(foo.copy_with(a=42))
+ 68    Foo(a=42, b='hi', c=True)
+ 69    >>> print(foo.copy_with(b='Hello'))
+ 70    Foo(a=6, b='Hello', c=True)
+ 71    >>> print(foo.copy_with(c=False))
+ 72    Foo(a=6, b='hi', c=False)
+ 73    >>> print(foo.copy_with(a=676676, b='new', c=False))
+ 74    Foo(a=676676, b='new', c=False)
+ 75    """
+ 76
+ 77    def decorator(cls_: type[T]) -> type[T]:
+ 78        args = {'frozen': True, 'order': order, 'kw_only': kw_only, 'slots': slots}
+ 79
+ 80        if type_safe:
+ 81            old_post_init = getattr(cls_, '__post_init__', lambda _: None)
+ 82
+ 83            def new_post_init(self: T) -> None:
+ 84                old_post_init(self)
+ 85                context = get_context(depth=3, increase_depth_if_name_matches=[
+ 86                    copy_with.__name__,
+ 87                    deep_copy_with.__name__,
+ 88                ])
+ 89                self.validate_types(_context=context)
+ 90
+ 91            cls_.__post_init__ = new_post_init  # must be done before applying dataclass()
+ 92
+ 93        new_class = dataclass(**args)(cls_)  # slots = True will create a new class!
+ 94
+ 95        def copy_with(self: T, **kwargs: Any) -> T:
+ 96            """
+ 97            Creates a new immutable instance that by copying all fields of this instance replaced by the new values.
+ 98            Keep in mind that this is a shallow copy!
+ 99            """
+100
+101            return replace(self, **kwargs)
+102
+103        def deep_copy_with(self: T, **kwargs: Any) -> T:
+104            """
+105            Creates a new immutable instance that by deep copying all fields of
+106            this instance replaced by the new values.
+107            """
+108
+109            current_values = {field.name: deepcopy(getattr(self, field.name)) for field in fields(self)}
+110            return new_class(**{**current_values, **kwargs})
+111
+112        def validate_types(self: T, *, _context: dict[str, type] | None = None) -> None:
+113            """
+114            Checks that all instance variable have the correct type.
+115            Raises a [PedanticTypeCheckException] if at least one type is incorrect.
+116            """
+117
+118            props = fields(new_class)
+119
+120            if _context is None:
+121                # method was called by user
+122                _context = get_context(depth=2)
+123
+124            _context = {**_context, **self.__init__.__globals__, self.__class__.__name__: self.__class__}
+125
+126            for field in props:
+127                assert_value_matches_type(
+128                    value=getattr(self, field.name),
+129                    type_=field.type,
+130                    err=f'In dataclass "{cls_.__name__}" in field "{field.name}": ',
+131                    type_vars={},
+132                    context=_context,
+133                )
+134
+135        methods_to_add = [copy_with, deep_copy_with, validate_types]
+136
+137        for method in methods_to_add:
+138            setattr(new_class, method.__name__, method)
+139
+140        return new_class
+141
+142    if cls is None:
+143        return decorator
+144
+145    return decorator(cls_=cls)
+
+ + +

Makes the decorated class immutable and a dataclass by adding the [@dataclass(frozen=True)] +decorator. Also adds useful copy_with() and validate_types() instance methods to this class (see below).

+ +

If [type_safe] is True, a type check is performed for each field after the __post_init__ method was called +which itself s directly called after the __init__ constructor. +Note this have a negative impact on the performance. It's recommend to use this for debugging and testing only.

+ +

In a nutshell, the followings methods will be added to the decorated class automatically:

+ +
    +
  • __init__() gives you a simple constructor like "Foo(a=6, b='hi', c=True)"
  • +
  • __eq__() lets you compare objects easily with "a == b"
  • +
  • __hash__() is also needed for instance comparison
  • +
  • __repr__() gives you a nice output when you call "print(foo)"
  • +
  • copy_with() allows you to quickly create new similar frozen instances. Use this instead of setters.
  • +
  • deep_copy_with() allows you to create deep copies and modify them.
  • +
  • validate_types() allows you to validate the types of the dataclass. +This is called automatically when [type_safe] is True.
  • +
+ +

If the [order] parameter is True (default is False), the following comparison methods +will be added additionally:

+ +
    +
  • __lt__() lets you compare instance like "a < b"
  • +
  • __le__() lets you compare instance like "a <= b"
  • +
  • __gt__() lets you compare instance like "a > b"
  • +
  • __ge__() lets you compare instance like "a >= b"
  • +
+ +

These compare the class as if it were a tuple of its fields, in order. +Both instances in the comparison must be of the identical type.

+ +

The parameters slots and kw_only are only applied if the Python version is greater or equal to 3.10.

+ +

Example:

+ +
+
>>> @frozen_dataclass
+... class Foo:
+...     a: int
+...     b: str
+...     c: bool
+>>> foo = Foo(a=6, b='hi', c=True)
+>>> print(foo)
+Foo(a=6, b='hi', c=True)
+>>> print(foo.copy_with())
+Foo(a=6, b='hi', c=True)
+>>> print(foo.copy_with(a=42))
+Foo(a=42, b='hi', c=True)
+>>> print(foo.copy_with(b='Hello'))
+Foo(a=6, b='Hello', c=True)
+>>> print(foo.copy_with(c=False))
+Foo(a=6, b='hi', c=False)
+>>> print(foo.copy_with(a=676676, b='new', c=False))
+Foo(a=676676, b='new', c=False)
+
+
+
+ + +
+
+ +
+ + def + frozen_type_safe_dataclass(cls: type[~T]) -> type[~T]: + + + +
+ +
13def frozen_type_safe_dataclass(cls: type[T]) -> type[T]:
+14    """Shortcut for @frozen_dataclass(type_safe=True)"""
+15
+16    return frozen_dataclass(type_safe=True)(cls)
+
+ + +

Shortcut for @frozen_dataclass(type_safe=True)

+
+ + +
+
+ +
+ + def + in_subprocess( func: Callable[..., typing.Union[~T, Awaitable[~T]]]) -> Callable[..., Awaitable[~T]]: + + + +
+ +
26def in_subprocess(func: Callable[..., T | Awaitable[T]]) -> Callable[..., Awaitable[T]]:
+27    """
+28    Executes the decorated function in a subprocess and returns the return value of it.
+29    Note that the decorated function will be replaced with an async function which returns
+30    a coroutine that needs to be awaited.
+31    This purpose of this is doing long-taking calculations without blocking the main thread
+32    of your application synchronously. That ensures that other asyncio.Tasks can work without any problem
+33    at the same time.
+34
+35    Example:
+36        >>> import time
+37        >>> import asyncio
+38        >>> @in_subprocess
+39        ... def f(value: int) -> int:
+40        ...     time.sleep(0.1)  # a long taking synchronous blocking calculation
+41        ...     return 2 * value
+42        >>> asyncio.run(f(value=42))
+43        84
+44    """
+45
+46    @wraps(func)
+47    async def wrapper(*args: Any, **kwargs: Any) -> T:
+48        return await calculate_in_subprocess(func, *args, **kwargs)
+49
+50    return wrapper
+
+ + +

Executes the decorated function in a subprocess and returns the return value of it. +Note that the decorated function will be replaced with an async function which returns +a coroutine that needs to be awaited. +This purpose of this is doing long-taking calculations without blocking the main thread +of your application synchronously. That ensures that other asyncio.Tasks can work without any problem +at the same time.

+ +

Example:

+ +
+
+
+

import time + import asyncio + @in_subprocess + ... def f(value: int) -> int: + ... time.sleep(0.1) # a long taking synchronous blocking calculation + ... return 2 * value + asyncio.run(f(value=42)) + 84

+
+
+
+
+ + +
+
+ +
+ + def + overrides(base_class: type) -> Callable[..., ~ReturnType]: + + + +
+ +
 7def overrides(base_class: type) -> F:
+ 8    """
+ 9    This is used for marking methods that overrides methods of the base class which makes the code more readable.
+10    This decorator raises an Exception if the decorated method is not a method in the parent class.
+11
+12    Example:
+13    >>> class Parent:
+14    ...     def my_instance_method(self):
+15    ...         pass
+16    >>> class Child(Parent):
+17    ...     @overrides(Parent)
+18    ...     def my_instance_method(self):
+19    ...         print('hello world')
+20    """
+21
+22    def decorator(func: F) -> F:
+23        name = func.__name__
+24
+25        if name not in dir(base_class):
+26            raise PedanticOverrideException(
+27                f'In function {func.__qualname__}:\n '
+28                f'Base class "{base_class.__name__}" does not have such a method "{name}".')
+29        return func
+30    return decorator
+
+ + +

This is used for marking methods that overrides methods of the base class which makes the code more readable. +This decorator raises an Exception if the decorated method is not a method in the parent class.

+ +

Example:

+ +
+
>>> class Parent:
+...     def my_instance_method(self):
+...         pass
+>>> class Child(Parent):
+...     @overrides(Parent)
+...     def my_instance_method(self):
+...         print('hello world')
+
+
+
+ + +
+
+ +
+ + def + pedantic( func: Callable[..., ~ReturnType] | None = None, require_docstring: bool = False) -> Callable[..., ~ReturnType]: + + + +
+ +
12def pedantic(func: F | None = None, require_docstring: bool = False) -> F:
+13    """
+14     A PedanticException is raised if one of the following happened:
+15     - The decorated function is called with positional arguments.
+16     - The function has no type annotation for their return type or one or more parameters do not have type
+17         annotations.
+18     - A type annotation is incorrect.
+19     - A type annotation misses type arguments, e.g. typing.List instead of typing.List[int].
+20     - The documented arguments do not match the argument list or their type annotations.
+21
+22    Example:
+23    >>> @pedantic
+24    ... def my_function(a: int, b: float, c: str) -> bool:
+25    ...     return float(a) == b and str(b) == c
+26    >>> my_function(a=42.0, b=14.0, c='hi')
+27    Traceback (most recent call last):
+28    ...
+29    pedantic.exceptions.PedanticTypeCheckException: In function my_function:
+30    Type hint is incorrect: Argument a=42.0 of type <class 'float'> does not match expected type <class 'int'>.
+31    >>> my_function(a=42, b=None, c='hi')
+32    Traceback (most recent call last):
+33    ...
+34    pedantic.exceptions.PedanticTypeCheckException: In function my_function:
+35    Type hint is incorrect: Argument b=None of type <class 'NoneType'> does not match expected type <class 'float'>.
+36    >>> my_function(a=42, b=42, c='hi')
+37    Traceback (most recent call last):
+38    ...
+39    pedantic.exceptions.PedanticTypeCheckException: In function my_function:
+40    Type hint is incorrect: Argument b=42 of type <class 'int'> does not match expected type <class 'float'>.
+41    >>> my_function(5, 4.0, 'hi')
+42    Traceback (most recent call last):
+43    ...
+44    pedantic.exceptions.PedanticCallWithArgsException: In function my_function:
+45    Use kwargs when you call function my_function. Args: (5, 4.0, 'hi')
+46    """
+47
+48    def decorator(f: F) -> F:
+49        decorated_func = DecoratedFunction(func=f)
+50
+51        if decorated_func.docstring is not None and (require_docstring or len(decorated_func.docstring.params)) > 0:
+52            _check_docstring(decorated_func=decorated_func)
+53
+54        @wraps(f)
+55        def wrapper(*args: Any, **kwargs: Any) -> ReturnType:
+56            call = FunctionCall(func=decorated_func, args=args, kwargs=kwargs, context=get_context(2))
+57            call.assert_uses_kwargs()
+58            return call.check_types()
+59
+60        async def async_wrapper(*args: Any, **kwargs: Any) -> ReturnType:
+61            call = FunctionCall(func=decorated_func, args=args, kwargs=kwargs, context=get_context(2))
+62            call.assert_uses_kwargs()
+63            return await call.async_check_types()
+64
+65        if decorated_func.is_coroutine:
+66            return async_wrapper
+67        return wrapper
+68
+69    return decorator if func is None else decorator(f=func)
+
+ + +

A PedanticException is raised if one of the following happened:

+ +
    +
  • The decorated function is called with positional arguments.
  • +
  • The function has no type annotation for their return type or one or more parameters do not have type +annotations.
  • +
  • A type annotation is incorrect.
  • +
  • A type annotation misses type arguments, e.g. typing.List instead of typing.List[int].
  • +
  • The documented arguments do not match the argument list or their type annotations.
  • +
+ +

Example:

+ +
+
>>> @pedantic
+... def my_function(a: int, b: float, c: str) -> bool:
+...     return float(a) == b and str(b) == c
+>>> my_function(a=42.0, b=14.0, c='hi')
+Traceback (most recent call last):
+...
+pedantic.exceptions.PedanticTypeCheckException: In function my_function:
+Type hint is incorrect: Argument a=42.0 of type <class 'float'> does not match expected type <class 'int'>.
+>>> my_function(a=42, b=None, c='hi')
+Traceback (most recent call last):
+...
+pedantic.exceptions.PedanticTypeCheckException: In function my_function:
+Type hint is incorrect: Argument b=None of type <class 'NoneType'> does not match expected type <class 'float'>.
+>>> my_function(a=42, b=42, c='hi')
+Traceback (most recent call last):
+...
+pedantic.exceptions.PedanticTypeCheckException: In function my_function:
+Type hint is incorrect: Argument b=42 of type <class 'int'> does not match expected type <class 'float'>.
+>>> my_function(5, 4.0, 'hi')
+Traceback (most recent call last):
+...
+pedantic.exceptions.PedanticCallWithArgsException: In function my_function:
+Use kwargs when you call function my_function. Args: (5, 4.0, 'hi')
+
+
+
+ + +
+
+ +
+ + def + pedantic_class(cls: ~C) -> ~C: + + + +
+ +
54def pedantic_class(cls: C) -> C:
+55    """Shortcut for @for_all_methods(pedantic)"""
+56    return for_all_methods(decorator=pedantic)(cls=cls)
+
+ + +

Shortcut for @for_all_methods(pedantic)

+
+ + +
+
+ +
+ + def + pedantic_class_require_docstring(cls: ~C) -> ~C: + + + +
+ +
59def pedantic_class_require_docstring(cls: C) -> C:
+60    """Shortcut for @for_all_methods(pedantic_require_docstring)"""
+61    return for_all_methods(decorator=pedantic_require_docstring)(cls=cls)
+
+ + +

Shortcut for @for_all_methods(pedantic_require_docstring)

+
+ + +
+
+ +
+ + def + pedantic_require_docstring( func: Callable[..., ~ReturnType] | None = None) -> Callable[..., ~ReturnType]: + + + +
+ +
72def pedantic_require_docstring(func: F | None = None) -> F:
+73    """Shortcut for @pedantic(require_docstring=True)"""
+74    return pedantic(func=func, require_docstring=True)
+
+ + +

Shortcut for @pedantic(require_docstring=True)

+
+ + +
+
+ +
+ + def + resolve_forward_ref( type_: str, globals_: dict[str, typing.Any] | None = None, context: dict | None = None) -> type: + + + +
+ +
 5def resolve_forward_ref(type_: str, globals_: dict[str, Any] | None = None, context: dict | None = None) -> type:  # noqa: F405
+ 6    """
+ 7    Resolve a type annotation that is a string.
+ 8
+ 9    Raises:
+10        NameError: in case of [type_] cannot be resolved.
+11    """
+12
+13    return eval(str(type_), globals_ or globals(), context or {})  # # noqa: S307
+
+ + +

Resolve a type annotation that is a string.

+ +

Raises: + NameError: in case of [type_] cannot be resolved.

+
+ + +
+
+ +
+ + def + retry( *, attempts: int, exceptions: type[Exception] | tuple[type[Exception], ...] = <class 'Exception'>, sleep_time: datetime.timedelta = datetime.timedelta(0), logger: logging.Logger | None = None) -> Callable[[~C], ~C]: + + + +
+ +
15def retry(
+16    *,
+17    attempts: int,
+18    exceptions: type[Exception] | tuple[type[Exception], ...] = Exception,
+19    sleep_time: timedelta = timedelta(seconds=0),
+20    logger: Logger | None = None,
+21) -> Callable[[C], C]:
+22    """
+23    Retries the wrapped function/method `attempts` times if the exceptions listed
+24    in [exceptions] are thrown.
+25
+26    Args:
+27        attempts: The number of times to repeat the wrapped function/method
+28        exceptions: Lists of exceptions that trigger a retry attempt.
+29        sleep_time: The time to wait between the retry attempts.
+30        logger: The logger used for logging.
+31
+32    Example:
+33        >>> @retry(attempts=3, exceptions=(ValueError, TypeError))
+34        ... def foo():
+35        ...     raise ValueError('Some error')
+36        >>> foo()  # doctest: +SKIP
+37    """
+38
+39    def decorator(func: C) -> C:
+40        @wraps(func)
+41        def wrapper(*args: P.args, **kwargs: P.kwargs) -> Any:
+42            return retry_func(
+43                func,
+44                *args,
+45                attempts=attempts,
+46                exceptions=exceptions,
+47                sleep_time=sleep_time,
+48                logger=logger,
+49                **kwargs,
+50            )
+51        return wrapper
+52    return decorator
+
+ + +

Retries the wrapped function/method attempts times if the exceptions listed +in [exceptions] are thrown.

+ +

Args: + attempts: The number of times to repeat the wrapped function/method + exceptions: Lists of exceptions that trigger a retry attempt. + sleep_time: The time to wait between the retry attempts. + logger: The logger used for logging.

+ +

Example:

+ +
+
+
+

@retry(attempts=3, exceptions=(ValueError, TypeError)) + ... def foo(): + ... raise ValueError('Some error') + foo() # doctest: +SKIP

+
+
+
+
+ + +
+
+ +
+ + def + run_doctest_of_single_function(f: Callable) -> None: + + + +
+ +
 6def run_doctest_of_single_function(f: Callable) -> None:
+ 7    """Useful for debugging a function with doctests."""
+ 8
+ 9    finder = doctest.DocTestFinder()
+10    runner = doctest.DocTestRunner()
+11
+12    # Find doctests attached to the function
+13    tests = finder.find(f)
+14
+15    # Run them
+16    for test in tests:
+17        runner.run(test)
+18
+19    # Fail the pytest test if any doctest failed
+20    results = runner.summarize()
+21
+22    if results.failed > 0:
+23        raise AssertionError(f'Failed tests: {results.failed}')
+
+ + +

Useful for debugging a function with doctests.

+
+ + +
+
+ +
+ + def + trace(func: Callable[..., ~ReturnType]) -> Callable[..., ~ReturnType]: + + + +
+ +
13def trace(func: F) -> F:
+14    """
+15    Prints the passed arguments and the returned value on each function call.
+16
+17    Example:
+18    >>> @trace
+19    ... def my_function(a, b, c):
+20    ...     return a + b + c
+21    >>> my_function(4, 5, 6)
+22    15
+23    """
+24
+25    @wraps(func)
+26    def wrapper(*args: Any, **kwargs: Any) -> ReturnType:
+27        logger.info(f'Trace: {_get_now()} calling {func.__name__}()  with {args}, {kwargs}')
+28        original_result = func(*args, **kwargs)
+29        logger.info(f'Trace: {_get_now()} {func.__name__}() returned {original_result!r}')
+30        return original_result
+31
+32    @wraps(func)
+33    async def async_wrapper(*args: Any, **kwargs: Any) -> ReturnType:
+34        logger.info(f'Trace: {_get_now()} calling {func.__name__}()  with {args}, {kwargs}')
+35        original_result = await func(*args, **kwargs)
+36        logger.info(f'Trace: {_get_now()} {func.__name__}() returned {original_result!r}')
+37        return original_result
+38
+39    if inspect.iscoroutinefunction(func):
+40        return async_wrapper
+41    return wrapper
+
+ + +

Prints the passed arguments and the returned value on each function call.

+ +

Example:

+ +
+
>>> @trace
+... def my_function(a, b, c):
+...     return a + b + c
+>>> my_function(4, 5, 6)
+15
+
+
+
+ + +
+
+ +
+ + def + trace_class(cls: ~C) -> ~C: + + + +
+ +
64def trace_class(cls: C) -> C:
+65    """Shortcut for @for_all_methods(trace)"""
+66    return for_all_methods(decorator=trace)(cls=cls)
+
+ + +

Shortcut for @for_all_methods(trace)

+
+ + +
+
+ +
+ + def + validate( *parameters: Parameter, return_as: ReturnAs = <ReturnAs.ARGS: 'ARGS'>, strict: bool = True, ignore_input: bool = False) -> Callable: + + + +
+ +
 27def validate(  # noqa: PLR0915, C901
+ 28    *parameters: Parameter,
+ 29    return_as: ReturnAs = ReturnAs.ARGS,
+ 30    strict: bool = True,
+ 31    ignore_input: bool = False,
+ 32) -> Callable:
+ 33    """
+ 34    Validates the values that are passed to the function by using the validators in the given parameters.
+ 35    The decorated function could also be async or an instance method as well as a normal function.
+ 36
+ 37    Args:
+ 38        parameters (multiple Parameter): The parameters that will be validated.
+ 39        return_as (ReturnAs): Pass the arguments as kwargs to the decorated function if ReturnAs.KWARGS.
+ 40            Positional arguments are used otherwise.
+ 41        strict (bool): If strict is true, you have to define a Parameter for each of the
+ 42            arguments the decorated function takes.
+ 43        ignore_input (bool): If True, all given arguments passed to this decorator are ignored.
+ 44            This can be useful if you use only ExternalParameters.
+ 45
+ 46    Returns:
+ 47        Callable: The decorated function.
+ 48    """
+ 49
+ 50    def validator(func: Callable) -> Callable:  # noqa: PLR0915, C901
+ 51        is_coroutine = inspect.iscoroutinefunction(func)
+ 52
+ 53        @wraps(func)
+ 54        def wrapper(*args: Any, **kwargs: Any) -> Any:
+ 55            result = _wrapper_content(*args, **kwargs)
+ 56
+ 57            if return_as == ReturnAs.ARGS:
+ 58                if 'self' in result:
+ 59                    return func(result.pop('self'), **result)
+ 60
+ 61                return func(*result.values())
+ 62
+ 63            if return_as == ReturnAs.KWARGS_WITHOUT_NONE:
+ 64                result = {k: v for k, v in result.items() if v is not None}
+ 65
+ 66            if 'self' in result:
+ 67                return func(result.pop('self'), **result)
+ 68
+ 69            return func(**result)
+ 70
+ 71        @wraps(func)
+ 72        async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
+ 73            result = _wrapper_content(*args, **kwargs)
+ 74
+ 75            if return_as == ReturnAs.ARGS:
+ 76                if 'self' in result:
+ 77                    return await func(result.pop('self'), **result)
+ 78
+ 79                return await func(*result.values())
+ 80
+ 81            if return_as == ReturnAs.KWARGS_WITHOUT_NONE:
+ 82                result = {k: v for k, v in result.items() if v is not None}
+ 83
+ 84            if 'self' in result:
+ 85                return await func(result.pop('self'), **result)
+ 86
+ 87            return await func(**result)
+ 88
+ 89        def _wrapper_content(*args: Any, **kwargs: Any) -> dict[str, Any]:  # noqa: PLR0912, C901
+ 90            result = {}
+ 91            parameter_dict = {parameter.name: parameter for parameter in parameters}
+ 92            used_parameter_names: list[str] = []
+ 93            signature = inspect.signature(func)
+ 94
+ 95            if not ignore_input:
+ 96                for k, v in kwargs.items():
+ 97                    if k in parameter_dict:
+ 98                        parameter = parameter_dict[k]
+ 99                        result[k] = parameter.validate(value=v)
+100                        used_parameter_names.append(parameter.name)
+101                    elif strict:
+102                        raise TooManyArguments(f'Got more arguments expected: No parameter found for argument {k}')
+103                    else:
+104                        result[k] = v
+105
+106                wants_args = '*args' in str(signature)
+107                used_args = []
+108
+109                try:
+110                    bound_args = signature.bind_partial(*args).arguments
+111                except TypeError as ex:
+112                    raise ValidateException(str(ex)) from ex
+113
+114                for k in bound_args:
+115                    if k == 'args' and wants_args:
+116                        for arg, parameter in zip(
+117                            [a for a in args if a not in used_args],
+118                            [p for p in parameters if p.name not in used_parameter_names],
+119                            strict=True,
+120                        ):
+121                            result[parameter.name] = parameter.validate(arg)
+122                            used_parameter_names.append(parameter.name)
+123                    elif k in parameter_dict:
+124                        parameter = parameter_dict[k]
+125                        result[k] = parameter.validate(value=bound_args[k])
+126                        used_parameter_names.append(parameter.name)
+127                        used_args.append(bound_args[k])
+128                    elif strict and k != 'self':
+129                        raise TooManyArguments(f'Got more arguments expected: No parameter found for argument {k}')
+130                    else:
+131                        result[k] = bound_args[k]
+132
+133            unused_parameters = [parameter for parameter in parameters if parameter.name not in used_parameter_names]
+134
+135            for parameter in unused_parameters:
+136                if isinstance(parameter, ExternalParameter) and parameter.has_value():
+137                    v = parameter.load_value()
+138                    result[parameter.name] = parameter.validate(value=v)
+139                    continue
+140
+141                if parameter.is_required:
+142                    return parameter.raise_exception(msg=f'Value for parameter {parameter.name} is required.')
+143                if parameter.default_value == NoValue:
+144                    if parameter.name in signature.parameters and \
+145                            signature.parameters[parameter.name].default is not signature.empty:
+146                        value = signature.parameters[parameter.name].default
+147                    else:
+148                        raise ValidateException(f'Got neither value nor default value for parameter {parameter.name}')
+149                else:
+150                    value = parameter.default_value
+151
+152                result[parameter.name] = value
+153
+154            # this is ugly, but I really want this behavior
+155            if (
+156                strict and IS_FLASK_INSTALLED and
+157                all(isinstance(p, FlaskJsonParameter) for p in parameter_dict.values())
+158                and request.is_json  # this check must come last
+159            ):
+160                unexpected_args = [k for k in request.json if k not in parameter_dict]
+161
+162                if unexpected_args:
+163                    raise TooManyArguments(f'Got unexpected arguments: {unexpected_args}')
+164
+165            return result
+166
+167        if is_coroutine:
+168            return async_wrapper
+169        return wrapper
+170    return validator
+
+ + +

Validates the values that are passed to the function by using the validators in the given parameters. +The decorated function could also be async or an instance method as well as a normal function.

+ +

Args: + parameters (multiple Parameter): The parameters that will be validated. + return_as (ReturnAs): Pass the arguments as kwargs to the decorated function if ReturnAs.KWARGS. + Positional arguments are used otherwise. + strict (bool): If strict is true, you have to define a Parameter for each of the + arguments the decorated function takes. + ignore_input (bool): If True, all given arguments passed to this decorator are ignored. + This can be useful if you use only ExternalParameters.

+ +

Returns: + Callable: The decorated function.

+
+ + +
+
+ +
+ + class + FlaskFormParameter(pedantic.FlaskParameter): + + + +
+ +
38class FlaskFormParameter(FlaskParameter):  # noqa: D101
+39    @overrides(FlaskParameter)
+40    def get_dict(self) -> dict:  # noqa: D102
+41        return request.form
+
+ + +

The interface for all external parameters.

+
+ + +
+ +
+
@overrides(FlaskParameter)
+ + def + get_dict(self) -> dict: + + + +
+ +
39    @overrides(FlaskParameter)
+40    def get_dict(self) -> dict:  # noqa: D102
+41        return request.form
+
+ + +

Returns the actual values as a dictionary.

+
+ + +
+
+
+ +
+ + class + FlaskGetParameter(pedantic.FlaskParameter): + + + +
+ +
51class FlaskGetParameter(FlaskParameter):  # noqa: D101
+52    @overrides(FlaskParameter)
+53    def get_dict(self) -> dict:  # noqa: D102
+54        return request.args
+55
+56    @overrides(ExternalParameter)
+57    def load_value(self) -> Any:  # noqa: D102
+58        value = request.args.getlist(self.name)
+59
+60        if self.value_type is list:
+61            return value
+62
+63        return value[0]
+
+ + +

The interface for all external parameters.

+
+ + +
+ +
+
@overrides(FlaskParameter)
+ + def + get_dict(self) -> dict: + + + +
+ +
52    @overrides(FlaskParameter)
+53    def get_dict(self) -> dict:  # noqa: D102
+54        return request.args
+
+ + +

Returns the actual values as a dictionary.

+
+ + +
+
+ +
+
@overrides(ExternalParameter)
+ + def + load_value(self) -> Any: + + + +
+ +
56    @overrides(ExternalParameter)
+57    def load_value(self) -> Any:  # noqa: D102
+58        value = request.args.getlist(self.name)
+59
+60        if self.value_type is list:
+61            return value
+62
+63        return value[0]
+
+ + +

Loads a value and returns it.

+
+ + +
+
+
+ +
+ + class + FlaskHeaderParameter(pedantic.FlaskParameter): + + + +
+ +
66class FlaskHeaderParameter(FlaskParameter):  # noqa: D101
+67    exception_type = InvalidHeader
+68
+69    @overrides(FlaskParameter)
+70    def get_dict(self) -> dict:  # noqa: D102
+71        return request.headers
+
+ + +

The interface for all external parameters.

+
+ + +
+
+ exception_type = +<class 'InvalidHeader'> + + +
+ + + + +
+
+ +
+
@overrides(FlaskParameter)
+ + def + get_dict(self) -> dict: + + + +
+ +
69    @overrides(FlaskParameter)
+70    def get_dict(self) -> dict:  # noqa: D102
+71        return request.headers
+
+ + +

Returns the actual values as a dictionary.

+
+ + +
+
+
+ +
+ + class + FlaskJsonParameter(pedantic.FlaskParameter): + + + +
+ +
29class FlaskJsonParameter(FlaskParameter):  # noqa: D101
+30    @overrides(FlaskParameter)
+31    def get_dict(self) -> dict:  # noqa: D102
+32        if not request.is_json:
+33            return {}
+34
+35        return request.json
+
+ + +

The interface for all external parameters.

+
+ + +
+ +
+
@overrides(FlaskParameter)
+ + def + get_dict(self) -> dict: + + + +
+ +
30    @overrides(FlaskParameter)
+31    def get_dict(self) -> dict:  # noqa: D102
+32        if not request.is_json:
+33            return {}
+34
+35        return request.json
+
+ + +

Returns the actual values as a dictionary.

+
+ + +
+
+
+ +
+ + class + FlaskParameter(pedantic.ExternalParameter, abc.ABC): + + + +
+ +
13class FlaskParameter(ExternalParameter, ABC):  # noqa: D101
+14    @abstractmethod
+15    def get_dict(self) -> dict[str, Any]:
+16        """Returns the actual values as a dictionary."""
+17
+18    @overrides(ExternalParameter)
+19    def has_value(self) -> bool:  # noqa: D102
+20        dict_ = self.get_dict()
+21        return dict_ is not None and self.name in dict_
+22
+23    @overrides(ExternalParameter)
+24    def load_value(self) -> Any:  # noqa: D102
+25        dict_ = self.get_dict()
+26        return dict_[self.name]
+
+ + +

The interface for all external parameters.

+
+ + +
+ +
+
@abstractmethod
+ + def + get_dict(self) -> dict[str, typing.Any]: + + + +
+ +
14    @abstractmethod
+15    def get_dict(self) -> dict[str, Any]:
+16        """Returns the actual values as a dictionary."""
+
+ + +

Returns the actual values as a dictionary.

+
+ + +
+
+ +
+
@overrides(ExternalParameter)
+ + def + has_value(self) -> bool: + + + +
+ +
18    @overrides(ExternalParameter)
+19    def has_value(self) -> bool:  # noqa: D102
+20        dict_ = self.get_dict()
+21        return dict_ is not None and self.name in dict_
+
+ + +

Returns True if the value can be fetched.

+
+ + +
+
+ +
+
@overrides(ExternalParameter)
+ + def + load_value(self) -> Any: + + + +
+ +
23    @overrides(ExternalParameter)
+24    def load_value(self) -> Any:  # noqa: D102
+25        dict_ = self.get_dict()
+26        return dict_[self.name]
+
+ + +

Loads a value and returns it.

+
+ + +
+
+
+ +
+ + class + FlaskPathParameter(pedantic.Parameter): + + + +
+ +
44class FlaskPathParameter(Parameter):
+45    """
+46    This is a special case because Flask passes path parameter as kwargs to validate().
+47    Therefore, this doesn't need to be an ExternalParameter.
+48    """
+
+ + +

This is a special case because Flask passes path parameter as kwargs to validate(). +Therefore, this doesn't need to be an ExternalParameter.

+
+ + +
+
+ +
+ + class + GenericFlaskDeserializer(pedantic.ExternalParameter): + + + +
+ +
 74class GenericFlaskDeserializer(ExternalParameter):
+ 75    """
+ 76    A JSON deserializer for classes which implements the [Deserializable] interface.
+ 77
+ 78    Further reading: https://github.com/LostInDarkMath/pedantic-python-decorators/issues/55
+ 79    """
+ 80
+ 81    def __init__(self, cls: type[Deserializable], catch_exception: bool = True, **kwargs: Any) -> None:  # noqa: D107
+ 82        super().__init__(**kwargs)
+ 83        self._cls = cls
+ 84        self._catch_exceptions = catch_exception
+ 85
+ 86    @overrides(ExternalParameter)
+ 87    def has_value(self) -> bool:  # noqa: D102
+ 88        return request.is_json
+ 89
+ 90    @overrides(ExternalParameter)
+ 91    def load_value(self) -> Any:  # noqa: D102
+ 92        try:
+ 93            return self._cls.from_json(request.json)
+ 94        except ValidatorException as ex:
+ 95            raise ParameterException.from_validator_exception(exception=ex, parameter_name='') from ex
+ 96        except Exception as ex:
+ 97            if self._catch_exceptions:
+ 98                self.raise_exception(msg=str(ex))
+ 99
+100            raise
+
+ + +

A JSON deserializer for classes which implements the [Deserializable] interface.

+ +

Further reading: https://github.com/LostInDarkMath/pedantic-python-decorators/issues/55

+
+ + +
+ +
+ + GenericFlaskDeserializer( cls: type[Deserializable], catch_exception: bool = True, **kwargs: Any) + + + +
+ +
81    def __init__(self, cls: type[Deserializable], catch_exception: bool = True, **kwargs: Any) -> None:  # noqa: D107
+82        super().__init__(**kwargs)
+83        self._cls = cls
+84        self._catch_exceptions = catch_exception
+
+ + + + +
+
+ +
+
@overrides(ExternalParameter)
+ + def + has_value(self) -> bool: + + + +
+ +
86    @overrides(ExternalParameter)
+87    def has_value(self) -> bool:  # noqa: D102
+88        return request.is_json
+
+ + +

Returns True if the value can be fetched.

+
+ + +
+
+ +
+
@overrides(ExternalParameter)
+ + def + load_value(self) -> Any: + + + +
+ +
 90    @overrides(ExternalParameter)
+ 91    def load_value(self) -> Any:  # noqa: D102
+ 92        try:
+ 93            return self._cls.from_json(request.json)
+ 94        except ValidatorException as ex:
+ 95            raise ParameterException.from_validator_exception(exception=ex, parameter_name='') from ex
+ 96        except Exception as ex:
+ 97            if self._catch_exceptions:
+ 98                self.raise_exception(msg=str(ex))
+ 99
+100            raise
+
+ + +

Loads a value and returns it.

+
+ + +
+
+
+ + \ No newline at end of file diff --git a/docs/pedantic/constants.html b/docs/pedantic/constants.html deleted file mode 100644 index 34974f39..00000000 --- a/docs/pedantic/constants.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - -pedantic.constants API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.constants

-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/class_decorators.html b/docs/pedantic/decorators/class_decorators.html deleted file mode 100644 index 9ce85e5d..00000000 --- a/docs/pedantic/decorators/class_decorators.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - -pedantic.decorators.class_decorators API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.class_decorators

-
-
-
-
-
-
-
-
-

Functions

-
-
-def for_all_methods(decorator: Callable[..., ~ReturnType]) ‑> Callable[[Type[~C]], Type[~C]] -
-
-
- -Expand source code - -
def for_all_methods(decorator: F) -> Callable[[Type[C]], Type[C]]:
-    """
-        Applies a decorator to all methods of a class.
-
-        Example:
-
-        >>> @for_all_methods(pedantic)
-        ... class MyClass(object):
-        ...     def m1(self): pass
-        ...     def m2(self, x): pass
-    """
-    def decorate(cls: C) -> C:
-        if not is_enabled():
-            return cls
-
-        if issubclass(cls, enum.Enum):
-            raise PedanticTypeCheckException(f'Enum "{cls}" cannot be decorated with "@pedantic_class". '
-                                             f'Enums are not supported yet.')
-
-        if is_dataclass(obj=cls):
-            raise PedanticTypeCheckException(f'Dataclass "{cls}" cannot be decorated with "@pedantic_class". '
-                                             f'Try to write "@dataclass" over "@pedantic_class".')
-
-        for attr in cls.__dict__:
-            attr_value = getattr(cls, attr)
-
-            if isinstance(attr_value, (types.FunctionType, types.MethodType)) and attr != '__annotate_func__':
-                setattr(cls, attr, decorator(attr_value))
-            elif isinstance(attr_value, property):
-                prop = attr_value
-                wrapped_getter = _get_wrapped(prop=prop.fget, decorator=decorator)
-                wrapped_setter = _get_wrapped(prop=prop.fset, decorator=decorator)
-                wrapped_deleter = _get_wrapped(prop=prop.fdel, decorator=decorator)
-                new_prop = property(fget=wrapped_getter, fset=wrapped_setter, fdel=wrapped_deleter)
-                setattr(cls, attr, new_prop)
-
-        _add_type_var_attr_and_method_to_class(cls=cls)
-        return cls
-    return decorate
-
-

Applies a decorator to all methods of a class.

-

Example:

-
>>> @for_all_methods(pedantic)
-... class MyClass(object):
-...     def m1(self): pass
-...     def m2(self, x): pass
-
-
-
-def pedantic_class(cls: ~C) ‑> ~C -
-
-
- -Expand source code - -
def pedantic_class(cls: C) -> C:
-    """ Shortcut for @for_all_methods(pedantic) """
-    return for_all_methods(decorator=pedantic)(cls=cls)
-
-

Shortcut for @for_all_methods(pedantic)

-
-
-def pedantic_class_require_docstring(cls: ~C) ‑> ~C -
-
-
- -Expand source code - -
def pedantic_class_require_docstring(cls: C) -> C:
-    """ Shortcut for @for_all_methods(pedantic_require_docstring) """
-    return for_all_methods(decorator=pedantic_require_docstring)(cls=cls)
-
-

Shortcut for @for_all_methods(pedantic_require_docstring)

-
-
-def timer_class(cls: ~C) ‑> ~C -
-
-
- -Expand source code - -
def timer_class(cls: C) -> C:
-    """ Shortcut for @for_all_methods(timer) """
-    return for_all_methods(decorator=timer)(cls=cls)
-
-

Shortcut for @for_all_methods(timer)

-
-
-def trace_class(cls: ~C) ‑> ~C -
-
-
- -Expand source code - -
def trace_class(cls: C) -> C:
-    """ Shortcut for @for_all_methods(trace) """
-    return for_all_methods(decorator=trace)(cls=cls)
-
-

Shortcut for @for_all_methods(trace)

-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/cls_deco_frozen_dataclass.html b/docs/pedantic/decorators/cls_deco_frozen_dataclass.html deleted file mode 100644 index da6d5160..00000000 --- a/docs/pedantic/decorators/cls_deco_frozen_dataclass.html +++ /dev/null @@ -1,271 +0,0 @@ - - - - - - -pedantic.decorators.cls_deco_frozen_dataclass API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.cls_deco_frozen_dataclass

-
-
-
-
-
-
-
-
-

Functions

-
-
-def frozen_dataclass(cls: Type[~T] = None,
type_safe: bool = False,
order: bool = False,
kw_only: bool = True,
slots: bool = False) ‑> Type[~T] | Callable[[Type[~T]], Type[~T]]
-
-
-
- -Expand source code - -
def frozen_dataclass(
-        cls: Type[T] = None,
-        type_safe: bool = False,
-        order: bool = False,
-        kw_only: bool = True,
-        slots: bool = False,
-) -> Union[Type[T], Callable[[Type[T]], Type[T]]]:
-    """
-        Makes the decorated class immutable and a dataclass by adding the [@dataclass(frozen=True)]
-        decorator. Also adds useful copy_with() and validate_types() instance methods to this class (see below).
-
-        If [type_safe] is True, a type check is performed for each field after the __post_init__ method was called
-        which itself s directly called after the __init__ constructor.
-        Note this have a negative impact on the performance. It's recommend to use this for debugging and testing only.
-
-        In a nutshell, the followings methods will be added to the decorated class automatically:
-        - __init__() gives you a simple constructor like "Foo(a=6, b='hi', c=True)"
-        - __eq__() lets you compare objects easily with "a == b"
-        - __hash__() is also needed for instance comparison
-        - __repr__() gives you a nice output when you call "print(foo)"
-        - copy_with() allows you to quickly create new similar frozen instances. Use this instead of setters.
-        - deep_copy_with() allows you to create deep copies and modify them.
-        - validate_types() allows you to validate the types of the dataclass.
-                           This is called automatically when [type_safe] is True.
-
-        If the [order] parameter is True (default is False), the following comparison methods
-        will be added additionally:
-        - __lt__() lets you compare instance like "a < b"
-        - __le__() lets you compare instance like "a <= b"
-        - __gt__() lets you compare instance like "a > b"
-        - __ge__() lets you compare instance like "a >= b"
-
-        These compare the class as if it were a tuple of its fields, in order.
-        Both instances in the comparison must be of the identical type.
-
-        The parameters slots and kw_only are only applied if the Python version is greater or equal to 3.10.
-
-        Example:
-
-        >>> @frozen_dataclass
-        ... class Foo:
-        ...     a: int
-        ...     b: str
-        ...     c: bool
-        >>> foo = Foo(a=6, b='hi', c=True)
-        >>> print(foo)
-        Foo(a=6, b='hi', c=True)
-        >>> print(foo.copy_with())
-        Foo(a=6, b='hi', c=True)
-        >>> print(foo.copy_with(a=42))
-        Foo(a=42, b='hi', c=True)
-        >>> print(foo.copy_with(b='Hello'))
-        Foo(a=6, b='Hello', c=True)
-        >>> print(foo.copy_with(c=False))
-        Foo(a=6, b='hi', c=False)
-        >>> print(foo.copy_with(a=676676, b='new', c=False))
-        Foo(a=676676, b='new', c=False)
-    """
-
-    def decorator(cls_: Type[T]) -> Type[T]:
-        args = {'frozen': True, 'order': order, 'kw_only': kw_only, 'slots': slots}
-
-        if type_safe:
-            old_post_init = getattr(cls_, '__post_init__', lambda _: None)
-
-            def new_post_init(self) -> None:
-                old_post_init(self)
-                context = get_context(depth=3, increase_depth_if_name_matches=[
-                    copy_with.__name__,
-                    deep_copy_with.__name__,
-                ])
-                self.validate_types(_context=context)
-
-            setattr(cls_, '__post_init__', new_post_init)  # must be done before applying dataclass()
-
-        new_class = dataclass(**args)(cls_)  # slots = True will create a new class!
-
-        def copy_with(self, **kwargs: Any) -> T:
-            """
-                Creates a new immutable instance that by copying all fields of this instance replaced by the new values.
-                Keep in mind that this is a shallow copy!
-            """
-
-            return replace(self, **kwargs)
-
-        def deep_copy_with(self, **kwargs: Any) -> T:
-            """
-                Creates a new immutable instance that by deep copying all fields of
-                this instance replaced by the new values.
-            """
-
-            current_values = {field.name: deepcopy(getattr(self, field.name)) for field in fields(self)}
-            return new_class(**{**current_values, **kwargs})
-
-        def validate_types(self, *, _context: Dict[str, Type] = None) -> None:
-            """
-                Checks that all instance variable have the correct type.
-                Raises a [PedanticTypeCheckException] if at least one type is incorrect.
-            """
-
-            props = fields(new_class)
-
-            if _context is None:
-                # method was called by user
-                _context = get_context(depth=2)
-
-            _context = {**_context, **self.__init__.__globals__, self.__class__.__name__: self.__class__}
-
-            for field in props:
-                assert_value_matches_type(
-                    value=getattr(self, field.name),
-                    type_=field.type,
-                    err=f'In dataclass "{cls_.__name__}" in field "{field.name}": ',
-                    type_vars={},
-                    context=_context,
-                )
-
-        methods_to_add = [copy_with, deep_copy_with, validate_types]
-
-        for method in methods_to_add:
-            setattr(new_class, method.__name__, method)
-
-        return new_class
-
-    if cls is None:
-        return decorator
-
-    return decorator(cls_=cls)
-
-

Makes the decorated class immutable and a dataclass by adding the [@dataclass(frozen=True)] -decorator. Also adds useful copy_with() and validate_types() instance methods to this class (see below).

-

If [type_safe] is True, a type check is performed for each field after the post_init method was called -which itself s directly called after the init constructor. -Note this have a negative impact on the performance. It's recommend to use this for debugging and testing only.

-

In a nutshell, the followings methods will be added to the decorated class automatically: -- init() gives you a simple constructor like "Foo(a=6, b='hi', c=True)" -- eq() lets you compare objects easily with "a == b" -- hash() is also needed for instance comparison -- repr() gives you a nice output when you call "print(foo)" -- copy_with() allows you to quickly create new similar frozen instances. Use this instead of setters. -- deep_copy_with() allows you to create deep copies and modify them. -- validate_types() allows you to validate the types of the dataclass. -This is called automatically when [type_safe] is True.

-

If the [order] parameter is True (default is False), the following comparison methods -will be added additionally: -- lt() lets you compare instance like "a < b" -- le() lets you compare instance like "a <= b" -- gt() lets you compare instance like "a > b" -- ge() lets you compare instance like "a >= b"

-

These compare the class as if it were a tuple of its fields, in order. -Both instances in the comparison must be of the identical type.

-

The parameters slots and kw_only are only applied if the Python version is greater or equal to 3.10.

-

Example:

-
>>> @frozen_dataclass
-... class Foo:
-...     a: int
-...     b: str
-...     c: bool
->>> foo = Foo(a=6, b='hi', c=True)
->>> print(foo)
-Foo(a=6, b='hi', c=True)
->>> print(foo.copy_with())
-Foo(a=6, b='hi', c=True)
->>> print(foo.copy_with(a=42))
-Foo(a=42, b='hi', c=True)
->>> print(foo.copy_with(b='Hello'))
-Foo(a=6, b='Hello', c=True)
->>> print(foo.copy_with(c=False))
-Foo(a=6, b='hi', c=False)
->>> print(foo.copy_with(a=676676, b='new', c=False))
-Foo(a=676676, b='new', c=False)
-
-
-
-def frozen_type_safe_dataclass(cls: Type[~T]) ‑> Type[~T] -
-
-
- -Expand source code - -
def frozen_type_safe_dataclass(cls: Type[T]) -> Type[T]:
-    """ Shortcut for @frozen_dataclass(type_safe=True) """
-
-    return frozen_dataclass(type_safe=True)(cls)
-
-

Shortcut for @frozen_dataclass(type_safe=True)

-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_context_manager.html b/docs/pedantic/decorators/fn_deco_context_manager.html deleted file mode 100644 index e6b1817a..00000000 --- a/docs/pedantic/decorators/fn_deco_context_manager.html +++ /dev/null @@ -1,272 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_context_manager API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_context_manager

-
-
-
-
-
-
-
-
-

Functions

-
-
-def safe_async_contextmanager(f: Callable[..., AsyncIterator[~T]]) ‑> Callable[..., AsyncContextManager[~T, bool | None]] -
-
-
- -Expand source code - -
def safe_async_contextmanager(f: Callable[..., AsyncIterator[T]]) -> Callable[..., AsyncContextManager[T]]:
-    """
-    @safe_async_contextmanager decorator.
-
-    Note: You need Python 3.10 or newer for this.
-
-         Typical usage:
-
-            @safe_async_contextmanager
-            async def some_async_generator(<arguments>):
-                <setup>
-                yield <value>
-                <cleanup>
-
-        equivalent to this:
-
-            @asynccontextmanager
-            async def some_async_generator(<arguments>):
-                <setup>
-                try:
-                    yield <value>
-                finally:
-                    <cleanup>
-
-        This makes this:
-
-            async with some_async_generator(<arguments>) as <variable>:
-                <body>
-
-        equivalent to this:
-
-            <setup>
-            try:
-                <variable> = <value>
-                <body>
-            finally:
-                <cleanup>
-        """
-
-    if not isasyncgenfunction(f):
-        if not isgeneratorfunction(f):
-            raise AssertionError(f'{f.__name__} is not a generator.')
-
-        raise AssertionError(f'{f.__name__} is not an async generator. '
-                             f'So you need to use "safe_contextmanager" instead.')
-
-    @wraps(f)
-    async def wrapper(*args, **kwargs) -> Iterator[T]:
-        iterator = f(*args, **kwargs)
-
-        try:
-            yield await anext(iterator)
-        finally:
-            try:
-                await anext(iterator)
-            except StopAsyncIteration:
-                pass  # this is intended
-
-    return asynccontextmanager(wrapper)  # type: ignore
-
-

@safe_async_contextmanager decorator.

-

Note: You need Python 3.10 or newer for this.

-
 Typical usage:
-
-    @safe_async_contextmanager
-    async def some_async_generator(<arguments>):
-        <setup>
-        yield <value>
-        <cleanup>
-
-equivalent to this:
-
-    @asynccontextmanager
-    async def some_async_generator(<arguments>):
-        <setup>
-        try:
-            yield <value>
-        finally:
-            <cleanup>
-
-This makes this:
-
-    async with some_async_generator(<arguments>) as <variable>:
-        <body>
-
-equivalent to this:
-
-    <setup>
-    try:
-        <variable> = <value>
-        <body>
-    finally:
-        <cleanup>
-
-
-
-def safe_contextmanager(f: Callable[..., Iterator[~T]]) ‑> Callable[..., ContextManager[~T, bool | None]] -
-
-
- -Expand source code - -
def safe_contextmanager(f: Callable[..., Iterator[T]]) -> Callable[..., ContextManager[T]]:
-    """
-    @safe_contextmanager decorator.
-
-    Typical usage:
-
-        @safe_contextmanager
-        def some_generator(<arguments>):
-            <setup>
-            yield <value>
-            <cleanup>
-
-    equivalent to this:
-
-        @contextmanager
-        def some_generator(<arguments>):
-            <setup>
-            try:
-                yield <value>
-            finally:
-                <cleanup>
-
-    This makes this:
-
-        with some_generator(<arguments>) as <variable>:
-            <body>
-
-    equivalent to this:
-
-        <setup>
-        try:
-            <variable> = <value>
-            <body>
-        finally:
-            <cleanup>
-    """
-
-    if isasyncgenfunction(f):
-        raise AssertionError(f'{f.__name__} is async. So you need to use "safe_async_contextmanager" instead.')
-    if not isgeneratorfunction(f):
-        raise AssertionError(f'{f.__name__} is not a generator.')
-
-    @wraps(f)
-    def wrapper(*args, **kwargs) -> Iterator[T]:
-        iterator = f(*args, **kwargs)
-
-        try:
-            yield next(iterator)
-        finally:
-            try:
-                next(iterator)
-            except StopIteration:
-                pass  # this is intended
-
-    return contextmanager(wrapper)  # type: ignore
-
-

@safe_contextmanager decorator.

-

Typical usage:

-
@safe_contextmanager
-def some_generator(<arguments>):
-    <setup>
-    yield <value>
-    <cleanup>
-
-

equivalent to this:

-
@contextmanager
-def some_generator(<arguments>):
-    <setup>
-    try:
-        yield <value>
-    finally:
-        <cleanup>
-
-

This makes this:

-
with some_generator(<arguments>) as <variable>:
-    <body>
-
-

equivalent to this:

-
<setup>
-try:
-    <variable> = <value>
-    <body>
-finally:
-    <cleanup>
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_count_calls.html b/docs/pedantic/decorators/fn_deco_count_calls.html deleted file mode 100644 index 6ad3b2ae..00000000 --- a/docs/pedantic/decorators/fn_deco_count_calls.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_count_calls API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_count_calls

-
-
-
-
-
-
-
-
-

Functions

-
-
-def count_calls(func: Callable[..., ~ReturnType]) ‑> Callable[..., ~ReturnType] -
-
-
- -Expand source code - -
def count_calls(func: F) -> F:
-    """
-        Prints how often the method is called during program execution.
-
-        Example:
-
-        >>> @count_calls
-        ... def often_used_method():
-        ...    return 42
-        >>> often_used_method()
-        Count Calls: Call 1 of function 'often_used_method' at ...
-        >>> often_used_method()
-        Count Calls: Call 2 of function 'often_used_method' at ...
-        >>> often_used_method()
-        Count Calls: Call 3 of function 'often_used_method' at ...
-    """
-
-    @wraps(func)
-    def wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-        wrapper.num_calls += 1
-        print(f"Count Calls: Call {wrapper.num_calls} of function {func.__name__!r} at {datetime.now()}.")
-        return func(*args, **kwargs)
-
-    wrapper.num_calls = 0
-    return wrapper
-
-

Prints how often the method is called during program execution.

-

Example:

-
>>> @count_calls
-... def often_used_method():
-...    return 42
->>> often_used_method()
-Count Calls: Call 1 of function 'often_used_method' at ...
->>> often_used_method()
-Count Calls: Call 2 of function 'often_used_method' at ...
->>> often_used_method()
-Count Calls: Call 3 of function 'often_used_method' at ...
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_deprecated.html b/docs/pedantic/decorators/fn_deco_deprecated.html deleted file mode 100644 index 5dd14fcd..00000000 --- a/docs/pedantic/decorators/fn_deco_deprecated.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_deprecated API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_deprecated

-
-
-
-
-
-
-
-
-

Functions

-
-
-def deprecated(func: Callable[..., ~ReturnType] | None = None, message: str = '') ‑> Callable[..., ~ReturnType] | Callable[[Callable[..., ~ReturnType]], Callable[..., ~ReturnType]] -
-
-
- -Expand source code - -
def deprecated(func: F | None = None, message: str = '') -> F | Callable[[F], F]:
-    """
-        Use this decorator to mark a function as deprecated. It will raise a warning when the function is called.
-        You can specify an optional reason or message to display with the warning.
-
-        Example:
-        >>> @deprecated
-        ... def my_function(a, b, c):
-        ...     pass
-        >>> my_function(5, 4, 3)  # doctest: +SKIP
-        >>> @deprecated(message='Will be removed soon. Please use my_function_new_instead.')
-        ... def my_function(a, b, c):
-        ...     pass
-        >>> my_function(5, 4, 3)  # doctest: +SKIP
-    """
-
-    def decorator(fun: F) -> F:
-        @wraps(fun)
-        def wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-            msg = f'Call to deprecated function {fun.__qualname__}.'
-
-            if message:
-                msg += f'\nReason: {message}'
-
-            warnings.warn(message=msg, category=DeprecationWarning, stacklevel=2)
-            return fun(*args, **kwargs)
-        return wrapper
-    return decorator if func is None else decorator(func)
-
-

Use this decorator to mark a function as deprecated. It will raise a warning when the function is called. -You can specify an optional reason or message to display with the warning.

-

Example:

-
>>> @deprecated
-... def my_function(a, b, c):
-...     pass
->>> my_function(5, 4, 3)  # doctest: +SKIP
->>> @deprecated(message='Will be removed soon. Please use my_function_new_instead.')
-... def my_function(a, b, c):
-...     pass
->>> my_function(5, 4, 3)  # doctest: +SKIP
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_does_same_as_function.html b/docs/pedantic/decorators/fn_deco_does_same_as_function.html deleted file mode 100644 index 92928325..00000000 --- a/docs/pedantic/decorators/fn_deco_does_same_as_function.html +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_does_same_as_function API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_does_same_as_function

-
-
-
-
-
-
-
-
-

Functions

-
-
-def does_same_as_function(other_func: Callable[..., ~ReturnType]) ‑> Callable[..., ~ReturnType] -
-
-
- -Expand source code - -
def does_same_as_function(other_func: F) -> F:
-    """
-        Each time the decorated function is executed, the function other_func is also executed and the results
-        are compared. An AssertionError is raised if the results are not equal.
-
-        Example:
-
-        >>> def other_calculation(a, b, c):
-        ...     return c + b + a
-        >>> @does_same_as_function(other_calculation)
-        ... def some_calculation(a, b, c):
-        ...     return a + b + c
-        >>> some_calculation(1, 2, 3)
-        6
-    """
-
-    def decorator(decorated_func: F) -> F:
-        @wraps(decorated_func)
-        def wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-            result = decorated_func(*args, **kwargs)
-            other = other_func(*args, **kwargs)
-
-            if other != result:
-                raise AssertionError(f'Different outputs: Function "{decorated_func.__name__}" returns {result} and '
-                                     f'function "{other_func.__name__}" returns {other} for parameters {args} {kwargs}')
-            return result
-
-        @wraps(decorated_func)
-        async def async_wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-            result = await decorated_func(*args, **kwargs)
-
-            if inspect.iscoroutinefunction(other_func):
-                other = await other_func(*args, **kwargs)
-            else:
-                other = other_func(*args, **kwargs)
-
-            if other != result:
-                raise AssertionError(f'Different outputs: Function "{decorated_func.__name__}" returns {result} and '
-                                     f'function "{other_func.__name__}" returns {other} for parameters {args} {kwargs}')
-            return result
-
-        if inspect.iscoroutinefunction(decorated_func):
-            return async_wrapper
-        else:
-            return wrapper
-
-    return decorator
-
-

Each time the decorated function is executed, the function other_func is also executed and the results -are compared. An AssertionError is raised if the results are not equal.

-

Example:

-
>>> def other_calculation(a, b, c):
-...     return c + b + a
->>> @does_same_as_function(other_calculation)
-... def some_calculation(a, b, c):
-...     return a + b + c
->>> some_calculation(1, 2, 3)
-6
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_in_subprocess.html b/docs/pedantic/decorators/fn_deco_in_subprocess.html deleted file mode 100644 index d152fb02..00000000 --- a/docs/pedantic/decorators/fn_deco_in_subprocess.html +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_in_subprocess API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_in_subprocess

-
-
-
-
-
-
-
-
-

Functions

-
-
-async def calculate_in_subprocess(func: Callable[..., ~T | Awaitable[~T]], *args: Any, **kwargs: Any) ‑> ~T -
-
-
- -Expand source code - -
async def calculate_in_subprocess(func: Callable[..., Union[T, Awaitable[T]]], *args: Any, **kwargs: Any) -> T:
-    """
-        Calculates the result of a synchronous function in subprocess without blocking the current thread.
-
-        Arguments:
-            func: The function that will be called in a subprocess.
-            args: Positional arguments that will be passed to the function.
-            kwargs: Keyword arguments that will be passed to the function.
-
-        Returns:
-             The calculated result of the function "func".
-
-        Raises:
-            Any Exception that is raised inside [func].
-
-        Further reading: https://medium.com/devopss-hole/python-multiprocessing-pickle-issue-e2d35ccf96a9
-
-        Example:
-            >>> import time
-            >>> import asyncio
-            >>> def f(value: int) -> int:
-            ...     time.sleep(0.1)  # a long taking synchronous blocking calculation
-            ...     return 2 * value
-            >>> asyncio.run(calculate_in_subprocess(func=f, value=42))
-            84
-    """
-
-    if Pipe is None:
-        raise ImportError('You need to install the multiprocess package to use this: pip install multiprocess')
-
-    rx, tx = Pipe(duplex=False)  # receiver & transmitter ; Pipe is one-way only
-    process = Process(target=_inner, args=(tx, func, *args), kwargs=kwargs)
-    process.start()
-
-    event = asyncio.Event()
-    loop = asyncio.get_event_loop()
-    loop.add_reader(fd=rx.fileno(), callback=event.set)
-
-    if not rx.poll():  # do not use process.is_alive() as condition here
-        await event.wait()
-
-    loop.remove_reader(fd=rx.fileno())
-    event.clear()
-
-    result = rx.recv()
-    process.join()  # this blocks synchronously! make sure that process is terminated before you call join()
-    rx.close()
-    tx.close()
-
-    if isinstance(result, SubprocessError):
-        raise result.exception
-
-    return result
-
-

Calculates the result of a synchronous function in subprocess without blocking the current thread.

-

Arguments

-

func: The function that will be called in a subprocess. -args: Positional arguments that will be passed to the function. -kwargs: Keyword arguments that will be passed to the function.

-

Returns

-

The calculated result of the function "func".

-

Raises

-

Any Exception that is raised inside [func]. -Further reading: https://medium.com/devopss-hole/python-multiprocessing-pickle-issue-e2d35ccf96a9

-

Example

-
>>> import time
->>> import asyncio
->>> def f(value: int) -> int:
-...     time.sleep(0.1)  # a long taking synchronous blocking calculation
-...     return 2 * value
->>> asyncio.run(calculate_in_subprocess(func=f, value=42))
-84
-
-
-
-def in_subprocess(func: Callable[..., ~T | Awaitable[~T]]) ‑> Callable[..., Awaitable[~T]] -
-
-
- -Expand source code - -
def in_subprocess(func: Callable[..., Union[T, Awaitable[T]]]) -> Callable[..., Awaitable[T]]:
-    """
-        Executes the decorated function in a subprocess and returns the return value of it.
-        Note that the decorated function will be replaced with an async function which returns
-        a coroutine that needs to be awaited.
-        This purpose of this is doing long-taking calculations without blocking the main thread
-        of your application synchronously. That ensures that other asyncio.Tasks can work without any problem
-        at the same time.
-
-        Example:
-            >>> import time
-            >>> import asyncio
-            >>> @in_subprocess
-            ... def f(value: int) -> int:
-            ...     time.sleep(0.1)  # a long taking synchronous blocking calculation
-            ...     return 2 * value
-            >>> asyncio.run(f(value=42))
-            84
-    """
-
-    @wraps(func)
-    async def wrapper(*args: Any, **kwargs: Any) -> T:
-        return await calculate_in_subprocess(func, *args, **kwargs)
-
-    return wrapper
-
-

Executes the decorated function in a subprocess and returns the return value of it. -Note that the decorated function will be replaced with an async function which returns -a coroutine that needs to be awaited. -This purpose of this is doing long-taking calculations without blocking the main thread -of your application synchronously. That ensures that other asyncio.Tasks can work without any problem -at the same time.

-

Example

-
>>> import time
->>> import asyncio
->>> @in_subprocess
-... def f(value: int) -> int:
-...     time.sleep(0.1)  # a long taking synchronous blocking calculation
-...     return 2 * value
->>> asyncio.run(f(value=42))
-84
-
-
-
-
-
-

Classes

-
-
-class SubprocessError -(ex: Exception) -
-
-
- -Expand source code - -
class SubprocessError:
-    """ Is returned by the subprocess if an error occurs in the subprocess. """
-
-    def __init__(self, ex: Exception) -> None:
-        self.exception = ex
-
-

Is returned by the subprocess if an error occurs in the subprocess.

-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_mock.html b/docs/pedantic/decorators/fn_deco_mock.html deleted file mode 100644 index d7f46cab..00000000 --- a/docs/pedantic/decorators/fn_deco_mock.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_mock API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_mock

-
-
-
-
-
-
-
-
-

Functions

-
-
-def mock(return_value: ~ReturnType) ‑> Callable[..., ~ReturnType] -
-
-
- -Expand source code - -
def mock(return_value: ReturnType) -> F:
-    """
-        Skip the execution of the function and simply return the given return value instead.
-        This can be useful you want to check quickly if the behavior of the function causes a specific problem.
-        Without this decorator you actually need to change the implementation of the function temporarily.
-
-        Example:
-
-        >>> @mock(return_value=42)
-        ... def my_function(a, b, c):
-        ...     return a + b + c
-        >>> my_function(1, 2, 3)
-        42
-        >>> my_function(1000, 88, 204)
-        42
-    """
-
-    def decorator(func: F) -> F:
-        @wraps(func)
-        def wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-            return return_value
-
-        @wraps(func)
-        async def async_wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-            return return_value
-
-        if inspect.iscoroutinefunction(func):
-            return async_wrapper
-        else:
-            return wrapper
-    return decorator
-
-

Skip the execution of the function and simply return the given return value instead. -This can be useful you want to check quickly if the behavior of the function causes a specific problem. -Without this decorator you actually need to change the implementation of the function temporarily.

-

Example:

-
>>> @mock(return_value=42)
-... def my_function(a, b, c):
-...     return a + b + c
->>> my_function(1, 2, 3)
-42
->>> my_function(1000, 88, 204)
-42
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_overrides.html b/docs/pedantic/decorators/fn_deco_overrides.html deleted file mode 100644 index 148924bd..00000000 --- a/docs/pedantic/decorators/fn_deco_overrides.html +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_overrides API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_overrides

-
-
-
-
-
-
-
-
-

Functions

-
-
-def overrides(base_class: Type) ‑> Callable[..., ~ReturnType] -
-
-
- -Expand source code - -
def overrides(base_class: Type) -> F:
-    """
-        This is used for marking methods that overrides methods of the base class which makes the code more readable.
-        This decorator raises an Exception if the decorated method is not a method in the parent class.
-
-        Example:
-
-        >>> class Parent:
-        ...     def my_instance_method(self):
-        ...         pass
-        >>> class Child(Parent):
-        ...     @overrides(Parent)
-        ...     def my_instance_method(self):
-        ...         print('hello world')
-    """
-
-    def decorator(func: F) -> F:
-        name = func.__name__
-
-        if name not in dir(base_class):
-            raise PedanticOverrideException(
-                f'In function {func.__qualname__}:\n '
-                f'Base class "{base_class.__name__}" does not have such a method "{name}".')
-        return func
-    return decorator
-
-

This is used for marking methods that overrides methods of the base class which makes the code more readable. -This decorator raises an Exception if the decorated method is not a method in the parent class.

-

Example:

-
>>> class Parent:
-...     def my_instance_method(self):
-...         pass
->>> class Child(Parent):
-...     @overrides(Parent)
-...     def my_instance_method(self):
-...         print('hello world')
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_pedantic.html b/docs/pedantic/decorators/fn_deco_pedantic.html deleted file mode 100644 index 609a08a9..00000000 --- a/docs/pedantic/decorators/fn_deco_pedantic.html +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_pedantic API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_pedantic

-
-
-
-
-
-
-
-
-

Functions

-
-
-def pedantic(func: Callable[..., ~ReturnType] | None = None,
require_docstring: bool = False) ‑> Callable[..., ~ReturnType]
-
-
-
- -Expand source code - -
def pedantic(func: Optional[F] = None, require_docstring: bool = False) -> F:
-    """
-        A PedanticException is raised if one of the following happened:
-        - The decorated function is called with positional arguments.
-        - The function has no type annotation for their return type or one or more parameters do not have type
-            annotations.
-        - A type annotation is incorrect.
-        - A type annotation misses type arguments, e.g. typing.List instead of typing.List[int].
-        - The documented arguments do not match the argument list or their type annotations.
-
-       Example:
-
-       >>> @pedantic
-       ... def my_function(a: int, b: float, c: str) -> bool:
-       ...     return float(a) == b and str(b) == c
-       >>> my_function(a=42.0, b=14.0, c='hi')
-       Traceback (most recent call last):
-       ...
-       pedantic.exceptions.PedanticTypeCheckException: In function my_function:
-       Type hint is incorrect: Argument a=42.0 of type <class 'float'> does not match expected type <class 'int'>.
-       >>> my_function(a=42, b=None, c='hi')
-       Traceback (most recent call last):
-       ...
-       pedantic.exceptions.PedanticTypeCheckException: In function my_function:
-       Type hint is incorrect: Argument b=None of type <class 'NoneType'> does not match expected type <class 'float'>.
-       >>> my_function(a=42, b=42, c='hi')
-       Traceback (most recent call last):
-       ...
-       pedantic.exceptions.PedanticTypeCheckException: In function my_function:
-       Type hint is incorrect: Argument b=42 of type <class 'int'> does not match expected type <class 'float'>.
-       >>> my_function(5, 4.0, 'hi')
-       Traceback (most recent call last):
-       ...
-       pedantic.exceptions.PedanticCallWithArgsException: In function my_function:
-       Use kwargs when you call function my_function. Args: (5, 4.0, 'hi')
-   """
-
-    def decorator(f: F) -> F:
-        if not is_enabled():
-            return f
-
-        decorated_func = DecoratedFunction(func=f)
-
-        if decorated_func.docstring is not None and (require_docstring or len(decorated_func.docstring.params)) > 0:
-            _check_docstring(decorated_func=decorated_func)
-
-        @wraps(f)
-        def wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-            call = FunctionCall(func=decorated_func, args=args, kwargs=kwargs, context=get_context(2))
-            call.assert_uses_kwargs()
-            return call.check_types()
-
-        async def async_wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-            call = FunctionCall(func=decorated_func, args=args, kwargs=kwargs, context=get_context(2))
-            call.assert_uses_kwargs()
-            return await call.async_check_types()
-
-        if decorated_func.is_coroutine:
-            return async_wrapper
-        else:
-            return wrapper
-
-    return decorator if func is None else decorator(f=func)
-
-

A PedanticException is raised if one of the following happened: -- The decorated function is called with positional arguments. -- The function has no type annotation for their return type or one or more parameters do not have type -annotations. -- A type annotation is incorrect. -- A type annotation misses type arguments, e.g. typing.List instead of typing.List[int]. -- The documented arguments do not match the argument list or their type annotations.

-

Example:

-
>>> @pedantic
-... def my_function(a: int, b: float, c: str) -> bool:
-...     return float(a) == b and str(b) == c
->>> my_function(a=42.0, b=14.0, c='hi')
-Traceback (most recent call last):
-...
-pedantic.exceptions.PedanticTypeCheckException: In function my_function:
-Type hint is incorrect: Argument a=42.0 of type <class 'float'> does not match expected type <class 'int'>.
->>> my_function(a=42, b=None, c='hi')
-Traceback (most recent call last):
-...
-pedantic.exceptions.PedanticTypeCheckException: In function my_function:
-Type hint is incorrect: Argument b=None of type <class 'NoneType'> does not match expected type <class 'float'>.
->>> my_function(a=42, b=42, c='hi')
-Traceback (most recent call last):
-...
-pedantic.exceptions.PedanticTypeCheckException: In function my_function:
-Type hint is incorrect: Argument b=42 of type <class 'int'> does not match expected type <class 'float'>.
->>> my_function(5, 4.0, 'hi')
-Traceback (most recent call last):
-...
-pedantic.exceptions.PedanticCallWithArgsException: In function my_function:
-Use kwargs when you call function my_function. Args: (5, 4.0, 'hi')
-
-
-
-def pedantic_require_docstring(func: Callable[..., ~ReturnType] | None = None) ‑> Callable[..., ~ReturnType] -
-
-
- -Expand source code - -
def pedantic_require_docstring(func: Optional[F] = None) -> F:
-    """Shortcut for @pedantic(require_docstring=True) """
-    return pedantic(func=func, require_docstring=True)
-
-

Shortcut for @pedantic(require_docstring=True)

-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_rename_kwargs.html b/docs/pedantic/decorators/fn_deco_rename_kwargs.html deleted file mode 100644 index 8f126b8e..00000000 --- a/docs/pedantic/decorators/fn_deco_rename_kwargs.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_rename_kwargs API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_rename_kwargs

-
-
-
-
-
-
-
-
-

Functions

-
-
-def rename_kwargs(*params: Rename) ‑> Callable[[Callable[..., ~ReturnType]], Callable[..., ~ReturnType]] -
-
-
- -Expand source code - -
def rename_kwargs(*params: Rename) -> Callable[[F], F]:
-    """
-        Renames the keyword arguments based on the given "Rename" rules when the decorated function is called.
-        You can also use this to define aliases for keyword arguments.
-
-        Example:
-
-        >>> @rename_kwargs(
-        ...     Rename(from_='firstname', to='a'),
-        ...     Rename(from_='lastname', to='b'),
-        ... )
-        ... def my_function(a, b):
-        ...     return a + ' ' + b
-        >>> my_function(a='egon', b='olsen')  # the normal way
-        'egon olsen'
-        >>> my_function(firstname='egon', lastname='olsen')  # using new defined keyword arguments
-        'egon olsen'
-    """
-
-    param_dict = {p.from_: p.to for p in params}
-
-    def decorator(func: F) -> F:
-        @wraps(func)
-        def wrapper(*args, **kwargs) -> ReturnType:
-            result_kwargs = {}
-
-            for k, v in kwargs.items():
-                if k in param_dict:
-                    result_kwargs[param_dict[k]] = kwargs[k]
-                else:
-                    result_kwargs[k] = kwargs[k]
-
-            return func(*args, **result_kwargs)
-        return wrapper
-    return decorator
-
-

Renames the keyword arguments based on the given "Rename" rules when the decorated function is called. -You can also use this to define aliases for keyword arguments.

-

Example:

-
>>> @rename_kwargs(
-...     Rename(from_='firstname', to='a'),
-...     Rename(from_='lastname', to='b'),
-... )
-... def my_function(a, b):
-...     return a + ' ' + b
->>> my_function(a='egon', b='olsen')  # the normal way
-'egon olsen'
->>> my_function(firstname='egon', lastname='olsen')  # using new defined keyword arguments
-'egon olsen'
-
-
-
-
-
-

Classes

-
-
-class Rename -(from_: str, to: str) -
-
-
- -Expand source code - -
class Rename:
-    def __init__(self, from_: str, to: str) -> None:
-        self.from_ = from_
-        self.to = to
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_require_kwargs.html b/docs/pedantic/decorators/fn_deco_require_kwargs.html deleted file mode 100644 index 63debfce..00000000 --- a/docs/pedantic/decorators/fn_deco_require_kwargs.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_require_kwargs API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_require_kwargs

-
-
-
-
-
-
-
-
-

Functions

-
-
-def require_kwargs(func: Callable[..., ~ReturnType]) ‑> Callable[..., ~ReturnType] -
-
-
- -Expand source code - -
def require_kwargs(func: F) -> F:
-    """
-        Checks that each passed argument is a keyword argument.
-
-        Example:
-
-        >>> @require_kwargs
-        ... def my_function(a, b, c):
-        ...     return a + b + c
-        >>> my_function(5, 4, 3)
-        Traceback (most recent call last):
-        ...
-        pedantic.exceptions.PedanticCallWithArgsException: In function my_function:
-        Use kwargs when you call function my_function. Args: (5, 4, 3)
-        >>> my_function(a=5, b=4, c=3)
-        12
-    """
-
-    @wraps(func)
-    def wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-        decorated_func = DecoratedFunction(func=func)
-        call = FunctionCall(func=decorated_func, args=args, kwargs=kwargs, context={})
-        call.assert_uses_kwargs()
-        return func(*args, **kwargs)
-    return wrapper
-
-

Checks that each passed argument is a keyword argument.

-

Example:

-
>>> @require_kwargs
-... def my_function(a, b, c):
-...     return a + b + c
->>> my_function(5, 4, 3)
-Traceback (most recent call last):
-...
-pedantic.exceptions.PedanticCallWithArgsException: In function my_function:
-Use kwargs when you call function my_function. Args: (5, 4, 3)
->>> my_function(a=5, b=4, c=3)
-12
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_retry.html b/docs/pedantic/decorators/fn_deco_retry.html deleted file mode 100644 index c55e6503..00000000 --- a/docs/pedantic/decorators/fn_deco_retry.html +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_retry API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_retry

-
-
-
-
-
-
-
-
-

Functions

-
-
-def retry(*,
attempts: int,
exceptions: type[Exception] | tuple[type[Exception], ...] = builtins.Exception,
sleep_time: datetime.timedelta = datetime.timedelta(0),
logger: logging.Logger = None) ‑> Callable[[~C], ~C]
-
-
-
- -Expand source code - -
def retry(
-    *,
-    attempts: int,
-    exceptions: type[Exception] | tuple[type[Exception], ...] = Exception,
-    sleep_time: timedelta = timedelta(seconds=0),
-    logger: Logger = None,
-) -> Callable[[C], C]:
-    """
-    Retries the wrapped function/method `attempts` times if the exceptions listed
-    in [exceptions] are thrown.
-
-    Parameters:
-        attempts: The number of times to repeat the wrapped function/method
-        exceptions: Lists of exceptions that trigger a retry attempt.
-        sleep_time: The time to wait between the retry attempts.
-        logger: The logger used for logging.
-
-    Example:
-        >>> @retry(attempts=3, exceptions=(ValueError, TypeError))
-        ... def foo():
-        ...     raise ValueError('Some error')
-        >>> foo()  # doctest: +SKIP
-    """
-
-    def decorator(func: C) -> C:
-        @wraps(func)
-        def wrapper(*args, **kwargs) -> Any:
-            return retry_func(
-                func,
-                *args,
-                attempts=attempts,
-                exceptions=exceptions,
-                sleep_time=sleep_time,
-                logger=logger,
-                **kwargs,
-            )
-        return wrapper
-    return decorator
-
-

Retries the wrapped function/method attempts times if the exceptions listed -in [exceptions] are thrown.

-

Parameters

-

attempts: The number of times to repeat the wrapped function/method -exceptions: Lists of exceptions that trigger a retry attempt. -sleep_time: The time to wait between the retry attempts. -logger: The logger used for logging.

-

Example

-
>>> @retry(attempts=3, exceptions=(ValueError, TypeError))
-... def foo():
-...     raise ValueError('Some error')
->>> foo()  # doctest: +SKIP
-
-
-
-def retry_func(func: Callable[~P, ~R],
*args: P.args,
attempts: int,
exceptions: type[Exception] | tuple[type[Exception], ...] = builtins.Exception,
sleep_time: datetime.timedelta = datetime.timedelta(0),
logger: logging.Logger = None,
**kwargs: P.kwargs) ‑> ~R
-
-
-
- -Expand source code - -
def retry_func(
-    func: Callable[P, R],
-    *args: P.args,
-    attempts: int,
-    exceptions: type[Exception] | tuple[type[Exception], ...] = Exception,
-    sleep_time: timedelta = timedelta(seconds=0),
-    logger: Logger = None,
-    **kwargs: P.kwargs,
-) -> R:
-    attempt = 1
-
-    if logger is None:
-        logger = logging.getLogger()
-
-    while attempt < attempts:
-        try:
-            return func(*args, **kwargs)
-        except exceptions:
-            logger.warning(f'Exception thrown when attempting to run {func.__name__}, '
-                           f'attempt {attempt} of {attempts}')
-            attempt += 1
-            time.sleep(sleep_time.total_seconds())
-
-    return func(*args, **kwargs)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_timer.html b/docs/pedantic/decorators/fn_deco_timer.html deleted file mode 100644 index 8ab369b7..00000000 --- a/docs/pedantic/decorators/fn_deco_timer.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_timer API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_timer

-
-
-
-
-
-
-
-
-

Functions

-
-
-def timer(func: Callable[..., ~ReturnType]) ‑> Callable[..., ~ReturnType] -
-
-
- -Expand source code - -
def timer(func: F) -> F:
-    """
-        Prints how long the execution of the decorated function takes.
-
-        Example:
-
-        >>> @timer
-        ... def long_taking_calculation():
-        ...     return 42
-        >>> long_taking_calculation()
-        Timer: Finished function "long_taking_calculation" in 0:00:00...
-        42
-    """
-
-    @wraps(func)
-    def wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-        start_time: datetime = datetime.now()
-        value = func(*args, **kwargs)
-        end_time = datetime.now()
-        run_time = end_time - start_time
-        print(f'Timer: Finished function "{func.__name__}" in {run_time}.')
-        return value
-
-    @wraps(func)
-    async def async_wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-        start_time: datetime = datetime.now()
-        value = await func(*args, **kwargs)
-        end_time = datetime.now()
-        run_time = end_time - start_time
-        print(f'Timer: Finished function "{func.__name__}" in {run_time}.')
-        return value
-
-    if inspect.iscoroutinefunction(func):
-        return async_wrapper
-    else:
-        return wrapper
-
-

Prints how long the execution of the decorated function takes.

-

Example:

-
>>> @timer
-... def long_taking_calculation():
-...     return 42
->>> long_taking_calculation()
-Timer: Finished function "long_taking_calculation" in 0:00:00...
-42
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_trace.html b/docs/pedantic/decorators/fn_deco_trace.html deleted file mode 100644 index 2fd8f595..00000000 --- a/docs/pedantic/decorators/fn_deco_trace.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_trace API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_trace

-
-
-
-
-
-
-
-
-

Functions

-
-
-def trace(func: Callable[..., ~ReturnType]) ‑> Callable[..., ~ReturnType] -
-
-
- -Expand source code - -
def trace(func: F) -> F:
-    """
-       Prints the passed arguments and the returned value on each function call.
-
-       Example:
-
-       >>> @trace
-       ... def my_function(a, b, c):
-       ...     return a + b + c
-       >>> my_function(4, 5, 6)
-       Trace: ... calling my_function()  with (4, 5, 6), {}
-       Trace: ... my_function() returned 15
-       15
-    """
-
-    @wraps(func)
-    def wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-        print(f'Trace: {datetime.now()} calling {func.__name__}()  with {args}, {kwargs}')
-        original_result = func(*args, **kwargs)
-        print(f'Trace: {datetime.now()} {func.__name__}() returned {original_result!r}')
-        return original_result
-
-    @wraps(func)
-    async def async_wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-        print(f'Trace: {datetime.now()} calling {func.__name__}()  with {args}, {kwargs}')
-        original_result = await func(*args, **kwargs)
-        print(f'Trace: {datetime.now()} {func.__name__}() returned {original_result!r}')
-        return original_result
-
-    if inspect.iscoroutinefunction(func):
-        return async_wrapper
-    else:
-        return wrapper
-
-

Prints the passed arguments and the returned value on each function call.

-

Example:

-
>>> @trace
-... def my_function(a, b, c):
-...     return a + b + c
->>> my_function(4, 5, 6)
-Trace: ... calling my_function()  with (4, 5, 6), {}
-Trace: ... my_function() returned 15
-15
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_trace_if_returns.html b/docs/pedantic/decorators/fn_deco_trace_if_returns.html deleted file mode 100644 index c5fd3206..00000000 --- a/docs/pedantic/decorators/fn_deco_trace_if_returns.html +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_trace_if_returns API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_trace_if_returns

-
-
-
-
-
-
-
-
-

Functions

-
-
-def trace_if_returns(return_value: ~ReturnType) ‑> Callable[..., ~ReturnType] -
-
-
- -Expand source code - -
def trace_if_returns(return_value: ReturnType) -> F:
-    """
-       Prints the passed arguments if and only if the decorated function returned the given return_value.
-       This is useful if you want to figure out which input arguments leads to a special return value.
-
-       Example:
-
-       >>> @trace_if_returns(42)
-       ... def my_function(a, b, c):
-       ...     return a + b + c
-       >>> my_function(1, 2, 3)
-       6
-       >>> my_function(10, 8, 24)
-       Function my_function returned value 42 for args: (10, 8, 24) and kwargs: {}
-       42
-    """
-
-    def decorator(func: F) -> F:
-        @wraps(func)
-        def wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-            result = func(*args, **kwargs)
-
-            if result == return_value:
-                print(f'Function {func.__name__} returned value {result} for args: {args} and kwargs: {kwargs}')
-
-            return result
-
-        @wraps(func)
-        async def async_wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-            result = await func(*args, **kwargs)
-
-            if result == return_value:
-                print(f'Function {func.__name__} returned value {result} for args: {args} and kwargs: {kwargs}')
-
-            return result
-
-        if inspect.iscoroutinefunction(func):
-            return async_wrapper
-        else:
-            return wrapper
-    return decorator
-
-

Prints the passed arguments if and only if the decorated function returned the given return_value. -This is useful if you want to figure out which input arguments leads to a special return value.

-

Example:

-
>>> @trace_if_returns(42)
-... def my_function(a, b, c):
-...     return a + b + c
->>> my_function(1, 2, 3)
-6
->>> my_function(10, 8, 24)
-Function my_function returned value 42 for args: (10, 8, 24) and kwargs: {}
-42
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_unimplemented.html b/docs/pedantic/decorators/fn_deco_unimplemented.html deleted file mode 100644 index 7e059ddd..00000000 --- a/docs/pedantic/decorators/fn_deco_unimplemented.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_unimplemented API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_unimplemented

-
-
-
-
-
-
-
-
-

Functions

-
-
-def unimplemented(func: Callable[..., ~ReturnType]) ‑> Callable[..., ~ReturnType] -
-
-
- -Expand source code - -
def unimplemented(func: F) -> F:
-    """
-        For documentation purposes. Throw NotImplementedException if the function is called.
-
-        Example:
-
-        >>> @unimplemented
-        ... def my_function(a, b, c):
-        ...     pass
-        >>> my_function(5, 4, 3)
-        Traceback (most recent call last):
-        ...
-        pedantic.exceptions.NotImplementedException: Function "my_function" is not implemented yet!
-    """
-
-    @wraps(func)
-    def wrapper(*args: Any, **kwargs: Any) -> ReturnType:
-        raise NotImplementedException(f'Function "{func.__qualname__}" is not implemented yet!')
-    return wrapper
-
-

For documentation purposes. Throw NotImplementedException if the function is called.

-

Example:

-
>>> @unimplemented
-... def my_function(a, b, c):
-...     pass
->>> my_function(5, 4, 3)
-Traceback (most recent call last):
-...
-pedantic.exceptions.NotImplementedException: Function "my_function" is not implemented yet!
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/convert_value.html b/docs/pedantic/decorators/fn_deco_validate/convert_value.html deleted file mode 100644 index eb9eb4b1..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/convert_value.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.convert_value API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.convert_value

-
-
-
-
-
-
-
-
-

Functions

-
-
-def convert_value(value: Any, target_type: Type[bool | int | float | str | dict | list]) ‑> bool | int | float | str | dict | list -
-
-
- -Expand source code - -
def convert_value(value: Any, target_type: Type[T]) -> T:
-    if isinstance(value, target_type):
-        return value
-
-    value = str(value).strip().lower()
-
-    if target_type == bool:
-        if value in ['true', '1']:
-            return True
-        elif value in ['false', '0']:
-            return False
-
-        raise ConversionError(f'Value {value} cannot be converted to bool.')
-
-    try:
-        if target_type == list:
-            return [item.strip() for item in value.split(',')]
-        elif target_type == dict:
-            value = {item.split(':')[0].strip(): item.partition(':')[-1].strip() for item in value.split(',')}
-
-        return target_type(value)
-    except ValueError:
-        raise ConversionError(f'Value {value} cannot be converted to {target_type}.')
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/exceptions.html b/docs/pedantic/decorators/fn_deco_validate/exceptions.html deleted file mode 100644 index c10602ec..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/exceptions.html +++ /dev/null @@ -1,348 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.exceptions API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.exceptions

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class ConversionError -(msg: str) -
-
-
- -Expand source code - -
class ConversionError(ValidateException):
-    """ Is raised if a type cast failed. """
-
-

Is raised if a type cast failed.

-

Ancestors

- -
-
-class ExceptionDictKey -
-
-
- -Expand source code - -
class ExceptionDictKey:
-    VALUE = 'VALUE'
-    MESSAGE = 'MESSAGE'
-    PARAMETER = 'PARAMETER'
-    VALIDATOR = 'VALIDATOR'
-
-
-

Class variables

-
-
var MESSAGE
-
-

The type of the None singleton.

-
-
var PARAMETER
-
-

The type of the None singleton.

-
-
var VALIDATOR
-
-

The type of the None singleton.

-
-
var VALUE
-
-

The type of the None singleton.

-
-
-
-
-class InvalidHeader -(msg: str,
parameter_name: str,
value: Any | None = None,
validator_name: str | None = None)
-
-
-
- -Expand source code - -
class InvalidHeader(ParameterException):
-    """ Is raised if there is a validation error in a FlaskHeaderParameter. """
-
-

Is raised if there is a validation error in a FlaskHeaderParameter.

-

Ancestors

- -

Inherited members

- -
-
-class ParameterException -(msg: str,
parameter_name: str,
value: Any | None = None,
validator_name: str | None = None)
-
-
-
- -Expand source code - -
class ParameterException(ValidateException):
-    """ An exception that is raised inside a Parameter. """
-
-    def __init__(self, msg: str, parameter_name: str,
-                 value: Optional[Any] = None, validator_name: Optional[str] = None) -> None:
-        super().__init__(msg=msg)
-        self.validator_name = validator_name
-        self.parameter_name = parameter_name
-        self.value = value
-
-    @classmethod
-    def from_validator_exception(cls, exception: ValidatorException, parameter_name: str = '') -> 'ParameterException':
-        """ Creates a parameter exception from a validator exception. """
-        return cls(
-            value=exception.value,
-            msg=exception.message,
-            validator_name=exception.validator_name,
-            parameter_name=parameter_name or exception.parameter_name,
-        )
-
-    def __str__(self) -> str:
-        return str(self.to_dict)
-
-    @property
-    def to_dict(self) -> Dict[str, str]:
-        return {
-            ExceptionDictKey.VALUE: str(self.value),
-            ExceptionDictKey.MESSAGE: self.message,
-            ExceptionDictKey.VALIDATOR: self.validator_name,
-            ExceptionDictKey.PARAMETER: self.parameter_name,
-        }
-
-

An exception that is raised inside a Parameter.

-

Ancestors

- -

Subclasses

- -

Static methods

-
-
-def from_validator_exception(exception: ValidatorException,
parameter_name: str = '') ‑> ParameterException
-
-
-

Creates a parameter exception from a validator exception.

-
-
-

Instance variables

-
-
prop to_dict : Dict[str, str]
-
-
- -Expand source code - -
@property
-def to_dict(self) -> Dict[str, str]:
-    return {
-        ExceptionDictKey.VALUE: str(self.value),
-        ExceptionDictKey.MESSAGE: self.message,
-        ExceptionDictKey.VALIDATOR: self.validator_name,
-        ExceptionDictKey.PARAMETER: self.parameter_name,
-    }
-
-
-
-
-
-
-class TooManyArguments -(msg: str) -
-
-
- -Expand source code - -
class TooManyArguments(ValidateException):
-    """ Is raised if the function got more arguments than expected. """
-
-

Is raised if the function got more arguments than expected.

-

Ancestors

- -
-
-class ValidateException -(msg: str) -
-
-
- -Expand source code - -
class ValidateException(Exception):
-    """ The base class for all exception thrown by the validate decorator. """
-
-    def __init__(self, msg: str) -> None:
-        self.message = msg
-
-

The base class for all exception thrown by the validate decorator.

-

Ancestors

-
    -
  • builtins.Exception
  • -
  • builtins.BaseException
  • -
-

Subclasses

- -
-
-class ValidatorException -(msg: str, validator_name: str, value: Any, parameter_name: str = '') -
-
-
- -Expand source code - -
class ValidatorException(ValidateException):
-    """ An exception that is raised inside the validate() function of a Validator. """
-
-    def __init__(self, msg: str, validator_name: str, value: Any, parameter_name: str = '') -> None:
-        super().__init__(msg=msg)
-        self.validator_name = validator_name
-        self.value = value
-        self.parameter_name = parameter_name
-
-    def __str__(self) -> str:
-        return f'{self.validator_name}: {self.message} Value: {self.value}'
-
-

An exception that is raised inside the validate() function of a Validator.

-

Ancestors

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/fn_deco_validate.html b/docs/pedantic/decorators/fn_deco_validate/fn_deco_validate.html deleted file mode 100644 index 396909fc..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/fn_deco_validate.html +++ /dev/null @@ -1,349 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.fn_deco_validate API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.fn_deco_validate

-
-
-
-
-
-
-
-
-

Functions

-
-
-def validate(*parameters: Parameter,
return_as: ReturnAs = ReturnAs.ARGS,
strict: bool = True,
ignore_input: bool = False) ‑> Callable
-
-
-
- -Expand source code - -
def validate(
-        *parameters: Parameter,
-        return_as: ReturnAs = ReturnAs.ARGS,
-        strict: bool = True,
-        ignore_input: bool = False,
-) -> Callable:
-    """
-        Validates the values that are passed to the function by using the validators in the given parameters.
-        The decorated function could also be async or an instance method as well as a normal function.
-
-        Args:
-            parameters (multiple Parameter): The parameters that will be validated.
-            return_as (ReturnAs): Pass the arguments as kwargs to the decorated function if ReturnAs.KWARGS.
-                Positional arguments are used otherwise.
-            strict (bool): If strict is true, you have to define a Parameter for each of the
-                arguments the decorated function takes.
-            ignore_input (bool): If True, all given arguments passed to this decorator are ignored.
-                This can be useful if you use only ExternalParameters.
-
-        Returns:
-            Callable: The decorated function.
-    """
-
-    def validator(func: Callable) -> Callable:
-        is_coroutine = inspect.iscoroutinefunction(func)
-
-        @wraps(func)
-        def wrapper(*args, **kwargs) -> Any:
-            result = _wrapper_content(*args, **kwargs)
-
-            if return_as == ReturnAs.ARGS:
-                if 'self' in result:
-                    return func(result.pop('self'), **result)
-
-                return func(*result.values())
-
-            if return_as == ReturnAs.KWARGS_WITHOUT_NONE:
-                result = {k: v for k, v in result.items() if v is not None}
-
-            if 'self' in result:
-                return func(result.pop('self'), **result)
-
-            return func(**result)
-
-        @wraps(func)
-        async def async_wrapper(*args, **kwargs) -> Any:
-            result = _wrapper_content(*args, **kwargs)
-
-            if return_as == ReturnAs.ARGS:
-                if 'self' in result:
-                    return await func(result.pop('self'), **result)
-
-                return await func(*result.values())
-
-            if return_as == ReturnAs.KWARGS_WITHOUT_NONE:
-                result = {k: v for k, v in result.items() if v is not None}
-
-            if 'self' in result:
-                return await func(result.pop('self'), **result)
-
-            return await func(**result)
-
-        def _wrapper_content(*args, **kwargs) -> Dict[str, Any]:
-            result = {}
-            parameter_dict = {parameter.name: parameter for parameter in parameters}
-            used_parameter_names: List[str] = []
-            signature = inspect.signature(func)
-
-            if not ignore_input:
-                for k, v in kwargs.items():
-                    if k in parameter_dict:
-                        parameter = parameter_dict[k]
-                        result[k] = parameter.validate(value=v)
-                        used_parameter_names.append(parameter.name)
-                    else:
-                        if strict:
-                            raise TooManyArguments(f'Got more arguments expected: No parameter found for argument {k}')
-                        else:
-                            result[k] = v
-
-                wants_args = '*args' in str(signature)
-                used_args = []
-
-                try:
-                    bound_args = signature.bind_partial(*args).arguments
-                except TypeError as ex:
-                    raise ValidateException(str(ex))
-
-                for k in bound_args:
-                    if k == 'args' and wants_args:
-                        for arg, parameter in zip(
-                                [a for a in args if a not in used_args],
-                                [p for p in parameters if p.name not in used_parameter_names]
-                        ):
-                            print(f'Validate value {arg} with {parameter}')
-                            result[parameter.name] = parameter.validate(arg)
-                            used_parameter_names.append(parameter.name)
-                    elif k in parameter_dict:
-                        parameter = parameter_dict[k]
-                        result[k] = parameter.validate(value=bound_args[k])
-                        used_parameter_names.append(parameter.name)
-                        used_args.append(bound_args[k])
-                    else:
-                        if strict and k != 'self':
-                            raise TooManyArguments(f'Got more arguments expected: No parameter found for argument {k}')
-                        else:
-                            result[k] = bound_args[k]
-
-            unused_parameters = [parameter for parameter in parameters if parameter.name not in used_parameter_names]
-
-            for parameter in unused_parameters:
-                if isinstance(parameter, ExternalParameter):
-                    if parameter.has_value():
-                        v = parameter.load_value()
-                        result[parameter.name] = parameter.validate(value=v)
-                        continue
-
-                if parameter.is_required:
-                    return parameter.raise_exception(msg=f'Value for parameter {parameter.name} is required.')
-                elif parameter.default_value == NoValue:
-                    if parameter.name in signature.parameters and \
-                            signature.parameters[parameter.name].default is not signature.empty:
-                        value = signature.parameters[parameter.name].default
-                    else:
-                        raise ValidateException(f'Got neither value nor default value for parameter {parameter.name}')
-                else:
-                    value = parameter.default_value
-
-                result[parameter.name] = value
-
-            # this is ugly, but I really want this behavior
-            if strict and IS_FLASK_INSTALLED:
-                if all([isinstance(p, FlaskJsonParameter) for p in parameter_dict.values()]) and request.is_json:
-                    unexpected_args = [k for k in request.json if k not in parameter_dict]
-
-                    if unexpected_args:
-                        raise TooManyArguments(f'Got unexpected arguments: {unexpected_args}')
-
-            return result
-
-        if is_coroutine:
-            return async_wrapper
-        else:
-            return wrapper
-    return validator
-
-

Validates the values that are passed to the function by using the validators in the given parameters. -The decorated function could also be async or an instance method as well as a normal function.

-

Args

-
-
parameters : multiple Parameter
-
The parameters that will be validated.
-
return_as : ReturnAs
-
Pass the arguments as kwargs to the decorated function if ReturnAs.KWARGS. -Positional arguments are used otherwise.
-
strict : bool
-
If strict is true, you have to define a Parameter for each of the -arguments the decorated function takes.
-
ignore_input : bool
-
If True, all given arguments passed to this decorator are ignored. -This can be useful if you use only ExternalParameters.
-
-

Returns

-
-
Callable
-
The decorated function.
-
-
-
-
-
-

Classes

-
-
-class ReturnAs -(*args, **kwds) -
-
-
- -Expand source code - -
class ReturnAs(Enum):
-    ARGS = 'ARGS'
-    KWARGS_WITH_NONE = 'KWARGS_WITH_NONE'
-    KWARGS_WITHOUT_NONE = 'KWARGS_WITHOUT_NONE'
-
-

Create a collection of name/value pairs.

-

Example enumeration:

-
>>> class Color(Enum):
-...     RED = 1
-...     BLUE = 2
-...     GREEN = 3
-
-

Access them by:

-
    -
  • attribute access:
  • -
-
-
-
-

Color.RED -

-
-
-
-
    -
  • value lookup:
  • -
-
-
-
-

Color(1) -

-
-
-
-
    -
  • name lookup:
  • -
-
-
-
-

Color['RED'] -

-
-
-
-

Enumerations can be iterated over, and know how many members they have:

-
>>> len(Color)
-3
-
-
>>> list(Color)
-[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]
-
-

Methods can be added to enumerations, and members can have their own -attributes – see the documentation for details.

-

Ancestors

-
    -
  • enum.Enum
  • -
-

Class variables

-
-
var ARGS
-
-

The type of the None singleton.

-
-
var KWARGS_WITHOUT_NONE
-
-

The type of the None singleton.

-
-
var KWARGS_WITH_NONE
-
-

The type of the None singleton.

-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/index.html b/docs/pedantic/decorators/fn_deco_validate/index.html deleted file mode 100644 index 36d8de37..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/index.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate

-
-
-
-
-

Sub-modules

-
-
pedantic.decorators.fn_deco_validate.convert_value
-
-
-
-
pedantic.decorators.fn_deco_validate.exceptions
-
-
-
-
pedantic.decorators.fn_deco_validate.fn_deco_validate
-
-
-
-
pedantic.decorators.fn_deco_validate.parameters
-
-
-
-
pedantic.decorators.fn_deco_validate.validators
-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/parameters/abstract_external_parameter.html b/docs/pedantic/decorators/fn_deco_validate/parameters/abstract_external_parameter.html deleted file mode 100644 index a1ea848c..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/parameters/abstract_external_parameter.html +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.parameters.abstract_external_parameter API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.parameters.abstract_external_parameter

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class ExternalParameter -(name: str,
value_type: Type[bool | int | float | str | dict | list] = None,
validators: Iterable[Validator] = None,
default: Any = pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue,
required: bool = True)
-
-
-
- -Expand source code - -
class ExternalParameter(Parameter, ABC):
-    @abstractmethod
-    def has_value(self) -> bool:
-        """ Returns True if the value can be fetched. """
-
-    @abstractmethod
-    def load_value(self) -> Any:
-        """Loads a value and returns it."""
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Subclasses

- -

Methods

-
-
-def has_value(self) ‑> bool -
-
-
- -Expand source code - -
@abstractmethod
-def has_value(self) -> bool:
-    """ Returns True if the value can be fetched. """
-
-

Returns True if the value can be fetched.

-
-
-def load_value(self) ‑> Any -
-
-
- -Expand source code - -
@abstractmethod
-def load_value(self) -> Any:
-    """Loads a value and returns it."""
-
-

Loads a value and returns it.

-
-
-

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/parameters/abstract_parameter.html b/docs/pedantic/decorators/fn_deco_validate/parameters/abstract_parameter.html deleted file mode 100644 index 6c069b6a..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/parameters/abstract_parameter.html +++ /dev/null @@ -1,223 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.parameters.abstract_parameter API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.parameters.abstract_parameter

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class NoValue -
-
-
- -Expand source code - -
class NoValue:
-    pass
-
-
-
-
-class Parameter -(name: str,
value_type: Type[bool | int | float | str | dict | list] = None,
validators: Iterable[Validator] = None,
default: Any = pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue,
required: bool = True)
-
-
-
- -Expand source code - -
class Parameter:
-    exception_type: Type[ParameterException] = ParameterException
-
-    def __init__(self,
-                 name: str,
-                 value_type: Type[Union[bool, int, float, str, dict, list]] = None,
-                 validators: Iterable[Validator] = None,
-                 default: Any = NoValue,
-                 required: bool = True,
-                 ) -> None:
-        self.name = name
-        self.validators = validators if validators else []
-        self.default_value = default
-        self.value_type = value_type
-        self.is_required = False if default != NoValue else required
-
-        if value_type not in [str, bool, int, float, dict, list, None]:
-            raise AssertionError(f'value_type needs to be one of these: str, bool, int, float, dict & list')
-
-    def validate(self, value: Any) -> Any:
-        """ Apply all validators to the given value and collect all ValidationErrors. """
-
-        if value is None:
-            if self.is_required:
-                self.raise_exception(msg=f'Value for key {self.name} is required.')
-
-            return None
-
-        if self.value_type is not None:
-            try:
-                result_value = convert_value(value=value, target_type=self.value_type)
-            except ConversionError as ex:
-                return self.raise_exception(value=value, msg=ex.message)
-        else:
-            result_value = value
-
-        for validator in self.validators:
-            try:
-                result_value = validator.validate(result_value)
-            except ValidatorException as e:
-                raise self.exception_type.from_validator_exception(exception=e, parameter_name=self.name)
-
-        return result_value
-
-    def raise_exception(self, msg: str, value: Any = None, validator: Optional[Validator] = None) -> NoReturn:
-        raise self.exception_type(value=value, parameter_name=self.name, msg=msg,
-                                  validator_name=validator.name if validator else None)
-
-    def __str__(self) -> str:
-        return self.__class__.__name__ + ' name=' + self.name
-
-
-

Subclasses

- -

Class variables

-
-
var exception_type : Type[ParameterException]
-
-

An exception that is raised inside a Parameter.

-
-
-

Methods

-
-
-def raise_exception(self,
msg: str,
value: Any = None,
validator: Validator | None = None) ‑> NoReturn
-
-
-
- -Expand source code - -
def raise_exception(self, msg: str, value: Any = None, validator: Optional[Validator] = None) -> NoReturn:
-    raise self.exception_type(value=value, parameter_name=self.name, msg=msg,
-                              validator_name=validator.name if validator else None)
-
-
-
-
-def validate(self, value: Any) ‑> Any -
-
-
- -Expand source code - -
def validate(self, value: Any) -> Any:
-    """ Apply all validators to the given value and collect all ValidationErrors. """
-
-    if value is None:
-        if self.is_required:
-            self.raise_exception(msg=f'Value for key {self.name} is required.')
-
-        return None
-
-    if self.value_type is not None:
-        try:
-            result_value = convert_value(value=value, target_type=self.value_type)
-        except ConversionError as ex:
-            return self.raise_exception(value=value, msg=ex.message)
-    else:
-        result_value = value
-
-    for validator in self.validators:
-        try:
-            result_value = validator.validate(result_value)
-        except ValidatorException as e:
-            raise self.exception_type.from_validator_exception(exception=e, parameter_name=self.name)
-
-    return result_value
-
-

Apply all validators to the given value and collect all ValidationErrors.

-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/parameters/deserializable.html b/docs/pedantic/decorators/fn_deco_validate/parameters/deserializable.html deleted file mode 100644 index 33312072..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/parameters/deserializable.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.parameters.deserializable API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.parameters.deserializable

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class Deserializable -
-
-
- -Expand source code - -
class Deserializable(ABC):
-    """ A tiny interface which has a static from_json() method which acts like a named constructor. """
-
-    @staticmethod
-    @abstractmethod
-    def from_json(data: Dict[str, Any]) -> 'Deserializable':
-        """ A named constructor which creates an object from JSON. """
-
-

A tiny interface which has a static from_json() method which acts like a named constructor.

-

Ancestors

-
    -
  • abc.ABC
  • -
-

Static methods

-
-
-def from_json(data: Dict[str, Any]) ‑> Deserializable -
-
-
- -Expand source code - -
@staticmethod
-@abstractmethod
-def from_json(data: Dict[str, Any]) -> 'Deserializable':
-    """ A named constructor which creates an object from JSON. """
-
-

A named constructor which creates an object from JSON.

-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/parameters/environment_variable_parameter.html b/docs/pedantic/decorators/fn_deco_validate/parameters/environment_variable_parameter.html deleted file mode 100644 index f9390223..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/parameters/environment_variable_parameter.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.parameters.environment_variable_parameter API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.parameters.environment_variable_parameter

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class EnvironmentVariableParameter -(name: str,
env_var_name: str = None,
value_type: Type[str | bool | int | float] = builtins.str,
validators: Iterable[Validator] = None,
required: bool = True,
default: Any = pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue)
-
-
-
- -Expand source code - -
class EnvironmentVariableParameter(ExternalParameter):
-    def __init__(self,
-                 name: str,
-                 env_var_name: str = None,
-                 value_type: Type[Union[str, bool, int, float]] = str,
-                 validators: Iterable[Validator] = None,
-                 required: bool = True,
-                 default: Any = NoValue,
-                 ) -> None:
-        super().__init__(name=name, validators=validators, default=default, value_type=value_type, required=required)
-
-        if value_type not in [str, bool, int, float]:
-            raise AssertionError(f'value_type needs to be one of these: str, bool, int & float')
-
-        if env_var_name is None:
-            self._env_var_name = name
-        else:
-            self._env_var_name = env_var_name
-
-    @overrides(ExternalParameter)
-    def has_value(self) -> bool:
-        return self._env_var_name in os.environ
-
-    @overrides(ExternalParameter)
-    def load_value(self) -> Any:
-        return os.environ[self._env_var_name].strip()
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/parameters/flask_parameters.html b/docs/pedantic/decorators/fn_deco_validate/parameters/flask_parameters.html deleted file mode 100644 index f1caf6c0..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/parameters/flask_parameters.html +++ /dev/null @@ -1,411 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.parameters.flask_parameters API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.parameters.flask_parameters

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class FlaskFormParameter -(name: str,
value_type: Type[bool | int | float | str | dict | list] = None,
validators: Iterable[Validator] = None,
default: Any = pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue,
required: bool = True)
-
-
-
- -Expand source code - -
class FlaskFormParameter(FlaskParameter):
-    @overrides(FlaskParameter)
-    def get_dict(self) -> Dict:
-        return request.form
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-class FlaskGetParameter -(name: str,
value_type: Type[bool | int | float | str | dict | list] = None,
validators: Iterable[Validator] = None,
default: Any = pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue,
required: bool = True)
-
-
-
- -Expand source code - -
class FlaskGetParameter(FlaskParameter):
-    @overrides(FlaskParameter)
-    def get_dict(self) -> Dict:
-        return request.args
-
-    @overrides(ExternalParameter)
-    def load_value(self) -> Any:
-        value = request.args.getlist(self.name)
-
-        if self.value_type == list:
-            return value
-
-        return value[0]
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-class FlaskHeaderParameter -(name: str,
value_type: Type[bool | int | float | str | dict | list] = None,
validators: Iterable[Validator] = None,
default: Any = pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue,
required: bool = True)
-
-
-
- -Expand source code - -
class FlaskHeaderParameter(FlaskParameter):
-    exception_type = InvalidHeader
-
-    @overrides(FlaskParameter)
-    def get_dict(self) -> Dict:
-        return request.headers
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-class FlaskJsonParameter -(name: str,
value_type: Type[bool | int | float | str | dict | list] = None,
validators: Iterable[Validator] = None,
default: Any = pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue,
required: bool = True)
-
-
-
- -Expand source code - -
class FlaskJsonParameter(FlaskParameter):
-    @overrides(FlaskParameter)
-    def get_dict(self) -> Dict:
-        if not request.is_json:
-            return {}
-
-        return request.json
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-class FlaskParameter -(name: str,
value_type: Type[bool | int | float | str | dict | list] = None,
validators: Iterable[Validator] = None,
default: Any = pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue,
required: bool = True)
-
-
-
- -Expand source code - -
class FlaskParameter(ExternalParameter, ABC):
-    @abstractmethod
-    def get_dict(self) -> Dict[str, Any]:
-        """ Returns the actual values as a dictionary. """
-
-    @overrides(ExternalParameter)
-    def has_value(self) -> bool:
-        dict_ = self.get_dict()
-        return dict_ is not None and self.name in dict_
-
-    @overrides(ExternalParameter)
-    def load_value(self) -> Any:
-        dict_ = self.get_dict()
-        return dict_[self.name]
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Subclasses

- -

Methods

-
-
-def get_dict(self) ‑> Dict[str, Any] -
-
-
- -Expand source code - -
@abstractmethod
-def get_dict(self) -> Dict[str, Any]:
-    """ Returns the actual values as a dictionary. """
-
-

Returns the actual values as a dictionary.

-
-
-

Inherited members

- -
-
-class FlaskPathParameter -(name: str,
value_type: Type[bool | int | float | str | dict | list] = None,
validators: Iterable[Validator] = None,
default: Any = pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue,
required: bool = True)
-
-
-
- -Expand source code - -
class FlaskPathParameter(Parameter):
-    """
-    This is a special case because Flask passes path parameter as kwargs to validate().
-    Therefore, this doesn't need to be an ExternalParameter.
-    """
-
-

This is a special case because Flask passes path parameter as kwargs to validate(). -Therefore, this doesn't need to be an ExternalParameter.

-

Ancestors

- -

Inherited members

- -
-
-class GenericFlaskDeserializer -(cls: Type[Deserializable],
catch_exception: bool = True,
**kwargs)
-
-
-
- -Expand source code - -
class GenericFlaskDeserializer(ExternalParameter):
-    """
-        A JSON deserializer for classes which implements the [Deserializable] interface.
-
-        Further reading: https://github.com/LostInDarkMath/pedantic-python-decorators/issues/55
-    """
-
-    def __init__(self, cls: Type[Deserializable], catch_exception: bool = True, **kwargs) -> None:
-        super().__init__(**kwargs)
-        self._cls = cls
-        self._catch_exceptions = catch_exception
-
-    @overrides(ExternalParameter)
-    def has_value(self) -> bool:
-        return request.is_json
-
-    @overrides(ExternalParameter)
-    def load_value(self) -> Any:
-        try:
-            return self._cls.from_json(request.json)
-        except ValidatorException as ex:
-            raise ParameterException.from_validator_exception(exception=ex, parameter_name='')
-        except Exception as ex:
-            if self._catch_exceptions:
-                self.raise_exception(msg=str(ex))
-
-            raise ex
-
-

A JSON deserializer for classes which implements the [Deserializable] interface.

-

Further reading: https://github.com/LostInDarkMath/pedantic-python-decorators/issues/55

-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/parameters/index.html b/docs/pedantic/decorators/fn_deco_validate/parameters/index.html deleted file mode 100644 index eadb489f..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/parameters/index.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.parameters API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.parameters

-
-
-
-
-

Sub-modules

-
-
pedantic.decorators.fn_deco_validate.parameters.abstract_external_parameter
-
-
-
-
pedantic.decorators.fn_deco_validate.parameters.abstract_parameter
-
-
-
-
pedantic.decorators.fn_deco_validate.parameters.deserializable
-
-
-
-
pedantic.decorators.fn_deco_validate.parameters.environment_variable_parameter
-
-
-
-
pedantic.decorators.fn_deco_validate.parameters.flask_parameters
-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/abstract_validator.html b/docs/pedantic/decorators/fn_deco_validate/validators/abstract_validator.html deleted file mode 100644 index 66295cc6..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/abstract_validator.html +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators.abstract_validator API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators.abstract_validator

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class Validator -
-
-
- -Expand source code - -
class Validator(ABC):
-    @abstractmethod
-    def validate(self, value: Any) -> Any:
-        """
-            Validates and convert the value.
-            Raises an [ValidatorException] in case of an invalid value.
-            To raise this you can simply call self.raise_exception().
-        """
-
-    def validate_param(self, value: Any, parameter_name: str) -> Any:
-        """
-            Validates and converts the value, just like [validate()].
-            The difference is that a parameter_name is included in the exception, if an exception is raised.
-        """
-
-        try:
-            return self.validate(value=value)
-        except ValidatorException as ex:
-            ex.parameter_name = parameter_name
-            raise ex
-
-    def raise_exception(self, value: Any, msg: str) -> NoReturn:
-        raise ValidatorException(value=value, validator_name=self.name, msg=msg)
-
-    @property
-    def name(self) -> str:
-        return self.__class__.__name__
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

-
    -
  • abc.ABC
  • -
-

Subclasses

- -

Instance variables

-
-
prop name : str
-
-
- -Expand source code - -
@property
-def name(self) -> str:
-    return self.__class__.__name__
-
-
-
-
-

Methods

-
-
-def raise_exception(self, value: Any, msg: str) ‑> NoReturn -
-
-
- -Expand source code - -
def raise_exception(self, value: Any, msg: str) -> NoReturn:
-    raise ValidatorException(value=value, validator_name=self.name, msg=msg)
-
-
-
-
-def validate(self, value: Any) ‑> Any -
-
-
- -Expand source code - -
@abstractmethod
-def validate(self, value: Any) -> Any:
-    """
-        Validates and convert the value.
-        Raises an [ValidatorException] in case of an invalid value.
-        To raise this you can simply call self.raise_exception().
-    """
-
-

Validates and convert the value. -Raises an [ValidatorException] in case of an invalid value. -To raise this you can simply call self.raise_exception().

-
-
-def validate_param(self, value: Any, parameter_name: str) ‑> Any -
-
-
- -Expand source code - -
def validate_param(self, value: Any, parameter_name: str) -> Any:
-    """
-        Validates and converts the value, just like [validate()].
-        The difference is that a parameter_name is included in the exception, if an exception is raised.
-    """
-
-    try:
-        return self.validate(value=value)
-    except ValidatorException as ex:
-        ex.parameter_name = parameter_name
-        raise ex
-
-

Validates and converts the value, just like [validate()]. -The difference is that a parameter_name is included in the exception, if an exception is raised.

-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/composite_validator.html b/docs/pedantic/decorators/fn_deco_validate/validators/composite_validator.html deleted file mode 100644 index ef8781ca..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/composite_validator.html +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators.composite_validator API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators.composite_validator

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class Composite -(validators: Iterable[Validator]) -
-
-
- -Expand source code - -
class Composite(Validator):
-    def __init__(self, validators: Iterable[Validator]) -> None:
-        self._validators = validators
-
-    def __iter__(self) -> Iterator[Validator]:
-        for validator in self._validators:
-            yield validator
-
-    @overrides(Validator)
-    def validate(self, value: Any) -> Any:
-        for validator in self:
-            validator.validate(value)
-
-        return value
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/datetime_isoformat.html b/docs/pedantic/decorators/fn_deco_validate/validators/datetime_isoformat.html deleted file mode 100644 index 5049cba5..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/datetime_isoformat.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators.datetime_isoformat API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators.datetime_isoformat

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class DatetimeIsoFormat -
-
-
- -Expand source code - -
class DatetimeIsoFormat(Validator):
-    @overrides(Validator)
-    def validate(self, value: str) -> datetime:
-        try:
-            value = datetime.fromisoformat(value)
-        except (TypeError, ValueError, AttributeError):
-            self.raise_exception(msg=f'invalid value: {value} is not a datetime in ISO format', value=value)
-
-        return value
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/datetime_unix_timestamp.html b/docs/pedantic/decorators/fn_deco_validate/validators/datetime_unix_timestamp.html deleted file mode 100644 index 282a875b..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/datetime_unix_timestamp.html +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators.datetime_unix_timestamp API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators.datetime_unix_timestamp

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class DateTimeUnixTimestamp -
-
-
- -Expand source code - -
class DateTimeUnixTimestamp(Validator):
-    @overrides(Validator)
-    def validate(self, value: Union[int, float, str]) -> datetime:
-        if not isinstance(value, (int, float, str)):
-            self.raise_exception(msg=f'Invalid seconds since 1970: {value}', value=value)
-
-        try:
-            seconds = float(value)
-        except ValueError:
-            return self.raise_exception(msg=f'Could parse {value} to float.', value=value)
-
-        try:
-            return datetime(year=1970, month=1, day=1) + timedelta(seconds=seconds)
-        except OverflowError:
-            return self.raise_exception(
-                msg=f'Date value out of range. Make sure you send SECONDS since 1970. Got: {value}', value=value)
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/email.html b/docs/pedantic/decorators/fn_deco_validate/validators/email.html deleted file mode 100644 index 0a1ff927..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/email.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators.email API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators.email

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class Email -(email_pattern: str = '[^@\\s]+@[^@\\s]+\\.[a-zA-Z0-9]+$',
post_processor: Callable[[str], str] = <function Email.<lambda>>)
-
-
-
- -Expand source code - -
class Email(Validator):
-    def __init__(self, email_pattern: str = REGEX_EMAIL, post_processor: Callable[[str], str] = lambda x: x) -> None:
-        self._pattern = email_pattern
-        self._post_processor = post_processor
-
-    @overrides(Validator)
-    def validate(self, value: str) -> str:
-        if not re.fullmatch(pattern=self._pattern, string=value):
-            self.raise_exception(msg=f'invalid email address: {value}', value=value)
-
-        return self._post_processor(value)
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/enum.html b/docs/pedantic/decorators/fn_deco_validate/validators/enum.html deleted file mode 100644 index 017d3577..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/enum.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators.enum API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators.enum

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class IsEnum -(enum: enum.EnumType, convert: bool = True, to_upper_case: bool = True) -
-
-
- -Expand source code - -
class IsEnum(Validator):
-    def __init__(self, enum: EnumMeta, convert: bool = True, to_upper_case: bool = True) -> None:
-        self._enum = enum
-        self._convert = convert
-        self._to_upper_case = to_upper_case
-
-    @overrides(Validator)
-    def validate(self, value: Any) -> Any:
-        try:
-            if isinstance(value, str) and self._to_upper_case:
-                value = value.upper()
-
-            if issubclass(self._enum, IntEnum):
-                enum_value = self._enum(int(value))
-            else:
-                enum_value = self._enum(value)
-        except (ValueError, TypeError):
-            return self.raise_exception(msg=f'Incorrect value {value} for enum {self._enum}.', value=value)
-
-        if self._convert:
-            return enum_value
-
-        return value
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/for_each.html b/docs/pedantic/decorators/fn_deco_validate/validators/for_each.html deleted file mode 100644 index 100d0e39..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/for_each.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators.for_each API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators.for_each

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class ForEach -(validators: Validator | Iterable[Validator]) -
-
-
- -Expand source code - -
class ForEach(Validator):
-    def __init__(self, validators: Union[Validator, Iterable[Validator]]) -> None:
-        if isinstance(validators, Validator):
-            self._validators = [validators]
-        else:
-            self._validators = validators
-
-    @overrides(Validator)
-    def validate(self, value: Iterable[Any]) -> List[Any]:
-        if not isinstance(value, collections.abc.Iterable):
-            self.raise_exception(msg=f'{value} is not iterable.', value=value)
-
-        results = []
-
-        for item in value:
-            for validator in self._validators:
-                item = validator.validate(item)
-
-            results.append(item)
-
-        return results
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/index.html b/docs/pedantic/decorators/fn_deco_validate/validators/index.html deleted file mode 100644 index d5a45a52..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/index.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators

-
-
-
-
-

Sub-modules

-
-
pedantic.decorators.fn_deco_validate.validators.abstract_validator
-
-
-
-
pedantic.decorators.fn_deco_validate.validators.composite_validator
-
-
-
-
pedantic.decorators.fn_deco_validate.validators.datetime_isoformat
-
-
-
-
pedantic.decorators.fn_deco_validate.validators.datetime_unix_timestamp
-
-
-
-
pedantic.decorators.fn_deco_validate.validators.email
-
-
-
-
pedantic.decorators.fn_deco_validate.validators.enum
-
-
-
-
pedantic.decorators.fn_deco_validate.validators.for_each
-
-
-
-
pedantic.decorators.fn_deco_validate.validators.is_uuid
-
-
-
-
pedantic.decorators.fn_deco_validate.validators.match_pattern
-
-
-
-
pedantic.decorators.fn_deco_validate.validators.max
-
-
-
-
pedantic.decorators.fn_deco_validate.validators.max_length
-
-
-
-
pedantic.decorators.fn_deco_validate.validators.min
-
-
-
-
pedantic.decorators.fn_deco_validate.validators.min_length
-
-
-
-
pedantic.decorators.fn_deco_validate.validators.not_empty
-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/is_uuid.html b/docs/pedantic/decorators/fn_deco_validate/validators/is_uuid.html deleted file mode 100644 index 246659e1..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/is_uuid.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators.is_uuid API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators.is_uuid

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class IsUuid -(convert: bool = False) -
-
-
- -Expand source code - -
class IsUuid(Validator):
-    def __init__(self, convert: bool = False) -> None:
-        self._convert = convert
-
-    @overrides(Validator)
-    def validate(self, value: str) -> str:
-        try:
-            converted_value = UUID(str(value))
-        except ValueError:
-            return self.raise_exception(msg=f'{value} is not a valid UUID', value=value)
-
-        return converted_value if self._convert else value
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/match_pattern.html b/docs/pedantic/decorators/fn_deco_validate/validators/match_pattern.html deleted file mode 100644 index a17a0ee0..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/match_pattern.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators.match_pattern API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators.match_pattern

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class MatchPattern -(pattern: str) -
-
-
- -Expand source code - -
class MatchPattern(Validator):
-    def __init__(self, pattern: str) -> None:
-        self._pattern = re.compile(pattern=pattern)
-
-    @overrides(Validator)
-    def validate(self, value: str) -> str:
-        if not self._pattern.search(string=str(value)):
-            self.raise_exception(msg=f'Value "{value}" does not match pattern {self._pattern.pattern}.', value=value)
-
-        return value
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/max.html b/docs/pedantic/decorators/fn_deco_validate/validators/max.html deleted file mode 100644 index 419900da..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/max.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators.max API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators.max

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class Max -(value: int | float, include_boundary: bool = True) -
-
-
- -Expand source code - -
class Max(Validator):
-    def __init__(self, value: Union[int, float], include_boundary: bool = True) -> None:
-        """
-            >>> Max(7, True).validate(7)
-            7
-            >>> Max(7, False).validate(7)  # doctest: +IGNORE_EXCEPTION_DETAIL
-            Traceback (most recent call last):
-            ValidatorException: ...
-            >>> Max(7, False).validate(6.999)
-            6.999
-        """
-        self._value = value
-        self._include_boundary = include_boundary
-
-    @overrides(Validator)
-    def validate(self, value: Union[int, float]) -> Union[int, float]:
-        if value > self._value and self._include_boundary:
-            self.raise_exception(msg=f'greater then allowed: {value} is not <= {self._value}', value=value)
-        elif value >= self._value and not self._include_boundary:
-            self.raise_exception(msg=f'greater then allowed: {value} is not < {self._value}', value=value)
-
-        return value
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-
>>> Max(7, True).validate(7)
-7
->>> Max(7, False).validate(7)  # doctest: +IGNORE_EXCEPTION_DETAIL
-Traceback (most recent call last):
-ValidatorException: ...
->>> Max(7, False).validate(6.999)
-6.999
-
-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/max_length.html b/docs/pedantic/decorators/fn_deco_validate/validators/max_length.html deleted file mode 100644 index 0cbcc6cd..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/max_length.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators.max_length API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators.max_length

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class MaxLength -(length: int) -
-
-
- -Expand source code - -
class MaxLength(Validator):
-    def __init__(self, length: int) -> None:
-        self._length = length
-
-    @overrides(Validator)
-    def validate(self, value: Sized) -> Any:
-        if not isinstance(value, collections.abc.Sized):
-            self.raise_exception(msg=f'{value} has no length.', value=value)
-
-        if len(value) > self._length:
-            self.raise_exception(msg=f'{value} is too long with length {len(value)}.', value=value)
-
-        return value
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/min.html b/docs/pedantic/decorators/fn_deco_validate/validators/min.html deleted file mode 100644 index c08eb3cd..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/min.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators.min API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators.min

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class Min -(value: int | float, include_boundary: bool = True) -
-
-
- -Expand source code - -
class Min(Validator):
-    def __init__(self, value: Union[int, float], include_boundary: bool = True) -> None:
-        """
-            >>> Min(7, True).validate(7)
-            7
-            >>> Min(7, False).validate(7)  # doctest: +IGNORE_EXCEPTION_DETAIL
-            Traceback (most recent call last):
-            ValidatorException: ...
-            >>> Min(7, False).validate(7.001)
-            7.001
-        """
-        self._value = value
-        self._include_boundary = include_boundary
-
-    @overrides(Validator)
-    def validate(self, value: Union[int, float]) -> Union[int, float]:
-        if value < self._value and self._include_boundary:
-            self.raise_exception(msg=f'smaller then allowed: {value} is not >= {self._value}', value=value)
-        elif value <= self._value and not self._include_boundary:
-            self.raise_exception(msg=f'smaller then allowed: {value} is not > {self._value}', value=value)
-
-        return value
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-
>>> Min(7, True).validate(7)
-7
->>> Min(7, False).validate(7)  # doctest: +IGNORE_EXCEPTION_DETAIL
-Traceback (most recent call last):
-ValidatorException: ...
->>> Min(7, False).validate(7.001)
-7.001
-
-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/min_length.html b/docs/pedantic/decorators/fn_deco_validate/validators/min_length.html deleted file mode 100644 index cf64d410..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/min_length.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators.min_length API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators.min_length

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class MinLength -(length: int) -
-
-
- -Expand source code - -
class MinLength(Validator):
-    def __init__(self, length: int) -> None:
-        self._length = length
-
-    @overrides(Validator)
-    def validate(self, value: Sized) -> Any:
-        if not isinstance(value, collections.abc.Sized):
-            self.raise_exception(msg=f'{value} has no length.', value=value)
-
-        if len(value) < self._length:
-            self.raise_exception(msg=f'{value} is too short with length {len(value)}.', value=value)
-
-        return value
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/fn_deco_validate/validators/not_empty.html b/docs/pedantic/decorators/fn_deco_validate/validators/not_empty.html deleted file mode 100644 index 9f120087..00000000 --- a/docs/pedantic/decorators/fn_deco_validate/validators/not_empty.html +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - -pedantic.decorators.fn_deco_validate.validators.not_empty API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators.fn_deco_validate.validators.not_empty

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class NotEmpty -(strip: bool = True) -
-
-
- -Expand source code - -
class NotEmpty(Validator):
-    def __init__(self, strip: bool = True) -> None:
-        self.strip = strip
-
-    @overrides(Validator)
-    def validate(self, value: Sequence) -> Sequence:
-        """
-            Throws a ValidationError if the sequence is empty.
-            If the sequence is a string, it removes all leading and trailing whitespace.
-        """
-
-        if isinstance(value, str):
-            if not value.strip():
-                self.raise_exception(msg=f'Got empty String which is invalid.', value=value)
-
-            return value.strip() if self.strip else value
-        elif isinstance(value, collections.abc.Sequence):
-            if len(value) == 0:
-                raise self.raise_exception(msg=f'Got empty  which is invalid.', value=value)
-
-            return value
-
-        self.raise_exception(msg=f'Got {type(value)} which is not a Sequence.', value=value)
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Methods

-
-
-def validate(self, value: Sequence) ‑> Sequence -
-
-
- -Expand source code - -
@overrides(Validator)
-def validate(self, value: Sequence) -> Sequence:
-    """
-        Throws a ValidationError if the sequence is empty.
-        If the sequence is a string, it removes all leading and trailing whitespace.
-    """
-
-    if isinstance(value, str):
-        if not value.strip():
-            self.raise_exception(msg=f'Got empty String which is invalid.', value=value)
-
-        return value.strip() if self.strip else value
-    elif isinstance(value, collections.abc.Sequence):
-        if len(value) == 0:
-            raise self.raise_exception(msg=f'Got empty  which is invalid.', value=value)
-
-        return value
-
-    self.raise_exception(msg=f'Got {type(value)} which is not a Sequence.', value=value)
-
-

Throws a ValidationError if the sequence is empty. -If the sequence is a string, it removes all leading and trailing whitespace.

-
-
-

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/decorators/index.html b/docs/pedantic/decorators/index.html deleted file mode 100644 index a7b0f048..00000000 --- a/docs/pedantic/decorators/index.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - -pedantic.decorators API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.decorators

-
-
-
-
-

Sub-modules

-
-
pedantic.decorators.class_decorators
-
-
-
-
pedantic.decorators.cls_deco_frozen_dataclass
-
-
-
-
pedantic.decorators.fn_deco_context_manager
-
-
-
-
pedantic.decorators.fn_deco_count_calls
-
-
-
-
pedantic.decorators.fn_deco_deprecated
-
-
-
-
pedantic.decorators.fn_deco_does_same_as_function
-
-
-
-
pedantic.decorators.fn_deco_in_subprocess
-
-
-
-
pedantic.decorators.fn_deco_mock
-
-
-
-
pedantic.decorators.fn_deco_overrides
-
-
-
-
pedantic.decorators.fn_deco_pedantic
-
-
-
-
pedantic.decorators.fn_deco_rename_kwargs
-
-
-
-
pedantic.decorators.fn_deco_require_kwargs
-
-
-
-
pedantic.decorators.fn_deco_retry
-
-
-
-
pedantic.decorators.fn_deco_timer
-
-
-
-
pedantic.decorators.fn_deco_trace
-
-
-
-
pedantic.decorators.fn_deco_trace_if_returns
-
-
-
-
pedantic.decorators.fn_deco_unimplemented
-
-
-
-
pedantic.decorators.fn_deco_validate
-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/env_var_logic.html b/docs/pedantic/env_var_logic.html deleted file mode 100644 index 09563dae..00000000 --- a/docs/pedantic/env_var_logic.html +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - -pedantic.env_var_logic API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.env_var_logic

-
-
-
-
-
-
-
-
-

Functions

-
-
-def disable_pedantic() ‑> None -
-
-
- -Expand source code - -
def disable_pedantic() -> None:
-    os.environ[ENVIRONMENT_VARIABLE_NAME] = '0'
-
-
-
-
-def enable_pedantic() ‑> None -
-
-
- -Expand source code - -
def enable_pedantic() -> None:
-    os.environ[ENVIRONMENT_VARIABLE_NAME] = '1'
-
-
-
-
-def is_enabled() ‑> bool -
-
-
- -Expand source code - -
def is_enabled() -> bool:
-    if ENVIRONMENT_VARIABLE_NAME not in os.environ:
-        return True
-
-    return os.environ[ENVIRONMENT_VARIABLE_NAME] == '1'
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/examples/index.html b/docs/pedantic/examples/index.html deleted file mode 100644 index 3c5bf8cf..00000000 --- a/docs/pedantic/examples/index.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - -pedantic.examples API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.examples

-
-
-
-
-

Sub-modules

-
-
pedantic.examples.validate
-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/examples/validate.html b/docs/pedantic/examples/validate.html deleted file mode 100644 index 6cc3ffe9..00000000 --- a/docs/pedantic/examples/validate.html +++ /dev/null @@ -1,280 +0,0 @@ - - - - - - -pedantic.examples.validate API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.examples.validate

-
-
-
-
-
-
-
-
-

Functions

-
-
-def my_algorithm(value: float,
config: Configuration) ‑> float
-
-
-
- -Expand source code - -
@validate(ConfigFromEnvVar(name='config', validators=[ConfigurationValidator()]), strict=False, return_as=ReturnAs.KWARGS_WITH_NONE)
-# @validate(ConfigFromFile(name='config', validators=[ConfigurationValidator()]), strict=False)
-
-# with strict_mode = True (which is the default)
-# you need to pass a Parameter for each parameter of the decorated function
-# @validate(
-#     Parameter(name='value', validators=[Min(5, include_boundary=False)]),
-#     ConfigFromFile(name='config', validators=[ConfigurationValidator()]),
-# )
-def my_algorithm(value: float, config: Configuration) -> float:
-    """
-        This method calculates something that depends on the given value with considering the configuration.
-        Note how well this small piece of code is designed:
-            - Fhe function my_algorithm() need a Configuration but has no knowledge where this come from.
-            - Furthermore, it need does not care about parameter validation.
-            - The ConfigurationValidator doesn't now anything about the creation of the data.
-            - The @validate decorator is the only you need to change, if you want a different configuration source.
-    """
-    print(value)
-    print(config)
-    return value
-
-

This method calculates something that depends on the given value with considering the configuration. -Note how well this small piece of code is designed: -- Fhe function my_algorithm() need a Configuration but has no knowledge where this come from. -- Furthermore, it need does not care about parameter validation. -- The ConfigurationValidator doesn't now anything about the creation of the data. -- The @validate decorator is the only you need to change, if you want a different configuration source.

-
-
-
-
-

Classes

-
-
-class ConfigFromEnvVar -(name: str,
value_type: Type[bool | int | float | str | dict | list] = None,
validators: Iterable[Validator] = None,
default: Any = pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue,
required: bool = True)
-
-
-
- -Expand source code - -
class ConfigFromEnvVar(ExternalParameter):
-    """ Reads the configuration from environment variables. """
-
-    @overrides(ExternalParameter)
-    def has_value(self) -> bool:
-        return 'iterations' in os.environ and 'max_error' in os.environ
-
-    @overrides(ExternalParameter)
-    def load_value(self) -> Configuration:
-        return Configuration(
-            iterations=int(os.environ['iterations']),
-            max_error=float(os.environ['max_error']),
-        )
-
-

Reads the configuration from environment variables.

-

Ancestors

- -

Inherited members

- -
-
-class ConfigFromFile -(name: str,
value_type: Type[bool | int | float | str | dict | list] = None,
validators: Iterable[Validator] = None,
default: Any = pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue,
required: bool = True)
-
-
-
- -Expand source code - -
class ConfigFromFile(ExternalParameter):
-    """ Reads the configuration from a config file. """
-
-    @overrides(ExternalParameter)
-    def has_value(self) -> bool:
-        return os.path.isfile('config.csv')
-
-    @overrides(ExternalParameter)
-    def load_value(self) -> Configuration:
-        with open(file='config.csv', mode='r') as file:
-            content = file.readlines()
-            return Configuration(
-                iterations=int(content[0].strip('\n')),
-                max_error=float(content[1]),
-            )
-
-

Reads the configuration from a config file.

-

Ancestors

- -

Inherited members

- -
-
-class Configuration -(iterations: int, max_error: float) -
-
-
- -Expand source code - -
@dataclass(frozen=True)
-class Configuration:
-    iterations: int
-    max_error: float
-
-

Configuration(iterations: int, max_error: float)

-

Instance variables

-
-
var iterations : int
-
-

The type of the None singleton.

-
-
var max_error : float
-
-

The type of the None singleton.

-
-
-
-
-class ConfigurationValidator -
-
-
- -Expand source code - -
class ConfigurationValidator(Validator):
-    @overrides(Validator)
-    def validate(self, value: Configuration) -> Configuration:
-        if value.iterations < 1 or value.max_error < 0:
-            self.raise_exception(msg=f'Invalid configuration: {value}', value=value)
-
-        return value
-
-

Helper class that provides a standard way to create an ABC using -inheritance.

-

Ancestors

- -

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/exceptions.html b/docs/pedantic/exceptions.html deleted file mode 100644 index 0a8f6c6d..00000000 --- a/docs/pedantic/exceptions.html +++ /dev/null @@ -1,240 +0,0 @@ - - - - - - -pedantic.exceptions API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.exceptions

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class NotImplementedException -(*args, **kwargs) -
-
-
- -Expand source code - -
class NotImplementedException(Exception):
-    pass
-
-

Common base class for all non-exit exceptions.

-

Ancestors

-
    -
  • builtins.Exception
  • -
  • builtins.BaseException
  • -
-
-
-class PedanticCallWithArgsException -(*args, **kwargs) -
-
-
- -Expand source code - -
class PedanticCallWithArgsException(PedanticException):
-    pass
-
-

Common base class for all non-exit exceptions.

-

Ancestors

- -
-
-class PedanticDocstringException -(*args, **kwargs) -
-
-
- -Expand source code - -
class PedanticDocstringException(PedanticException):
-    pass
-
-

Common base class for all non-exit exceptions.

-

Ancestors

- -
-
-class PedanticException -(*args, **kwargs) -
-
-
- -Expand source code - -
class PedanticException(Exception):
-    pass
-
-

Common base class for all non-exit exceptions.

-

Ancestors

-
    -
  • builtins.Exception
  • -
  • builtins.BaseException
  • -
-

Subclasses

- -
-
-class PedanticOverrideException -(*args, **kwargs) -
-
-
- -Expand source code - -
class PedanticOverrideException(PedanticException):
-    pass
-
-

Common base class for all non-exit exceptions.

-

Ancestors

- -
-
-class PedanticTypeCheckException -(*args, **kwargs) -
-
-
- -Expand source code - -
class PedanticTypeCheckException(PedanticException):
-    pass
-
-

Common base class for all non-exit exceptions.

-

Ancestors

- -
-
-class PedanticTypeVarMismatchException -(*args, **kwargs) -
-
-
- -Expand source code - -
class PedanticTypeVarMismatchException(PedanticException):
-    pass
-
-

Common base class for all non-exit exceptions.

-

Ancestors

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/get_context.html b/docs/pedantic/get_context.html deleted file mode 100644 index 59f122e8..00000000 --- a/docs/pedantic/get_context.html +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - -pedantic.get_context API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.get_context

-
-
-
-
-
-
-
-
-

Functions

-
-
-def get_context(depth: int = 1, increase_depth_if_name_matches: List[str] = None) ‑> Dict[str, Type] -
-
-
- -Expand source code - -
def get_context(depth: int = 1, increase_depth_if_name_matches: List[str] = None) -> Dict[str, Type]:
-    """
-        Get the context of a frame at the given depth of the current call stack.
-        See also: https://docs.python.org/3/library/sys.html#sys._getframe
-    """
-
-    frame = sys._getframe(depth)
-    name = frame.f_code.co_name
-
-    if name in (increase_depth_if_name_matches or []):
-        frame = sys._getframe(depth + 1)
-
-    return {**frame.f_globals, **frame.f_locals}
-
-

Get the context of a frame at the given depth of the current call stack. -See also: https://docs.python.org/3/library/sys.html#sys._getframe

-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/helper_methods.html b/docs/pedantic/helper_methods.html deleted file mode 100644 index 0f2da387..00000000 --- a/docs/pedantic/helper_methods.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - -pedantic.helper_methods API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.helper_methods

-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/index.html b/docs/pedantic/index.html deleted file mode 100644 index c2b1778b..00000000 --- a/docs/pedantic/index.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - -pedantic API documentation - - - - - - - - - - - -
-
-
-

Package pedantic

-
-
-
-
-

Sub-modules

-
-
pedantic.constants
-
-
-
-
pedantic.decorators
-
-
-
-
pedantic.env_var_logic
-
-
-
-
pedantic.examples
-
-
-
-
pedantic.exceptions
-
-
-
-
pedantic.get_context
-
-
-
-
pedantic.mixins
-
-
-
-
pedantic.models
-
-
-
-
pedantic.type_checking_logic
-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/mixins/generic_mixin.html b/docs/pedantic/mixins/generic_mixin.html deleted file mode 100644 index 6f648901..00000000 --- a/docs/pedantic/mixins/generic_mixin.html +++ /dev/null @@ -1,345 +0,0 @@ - - - - - - -pedantic.mixins.generic_mixin API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.mixins.generic_mixin

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class GenericMixin -
-
-
- -Expand source code - -
class GenericMixin:
-    """
-        A mixin that provides easy access to given type variables.
-
-        Example:
-            >>> from typing import Generic, TypeVar
-            >>> T = TypeVar('T')
-            >>> U = TypeVar('U')
-            >>> class Foo(Generic[T, U], GenericMixin):
-            ...     values: list[T]
-            ...     value: U
-            >>> f = Foo[str, int]()
-            >>> f.type_vars
-            {~T: <class 'str'>, ~U: <class 'int'>}
-    """
-
-    @property
-    def type_var(self) -> Type:
-        """
-            Get the type variable for this class.
-            Use this for convenience if your class has only one type parameter.
-
-            DO NOT call this inside __init__()!
-
-            Example:
-                >>> from typing import Generic, TypeVar
-                >>> T = TypeVar('T')
-                >>> class Foo(Generic[T], GenericMixin):
-                ...     value: T
-                >>> f = Foo[float]()
-                >>> f.type_var
-                <class 'float'>
-        """
-
-        types = self._get_resolved_typevars()
-        assert len(types) == 1, f'You have multiple type parameters. Please use "type_vars" instead of "type_var".'
-        return list(types.values())[0]  # type: ignore
-
-    @property
-    def type_vars(self) -> Dict[TypeVar, Type]:
-        """
-            Returns the mapping of type variables to types.
-
-            DO NOT call this inside __init__()!
-
-            Example:
-                >>> from typing import Generic, TypeVar
-                >>> T = TypeVar('T')
-                >>> U = TypeVar('U')
-                >>> class Foo(Generic[T, U], GenericMixin):
-                ...     values: list[T]
-                ...     value: U
-                >>> f = Foo[str, int]()
-                >>> f.type_vars
-                {~T: <class 'str'>, ~U: <class 'int'>}
-        """
-
-        return self._get_resolved_typevars()
-
-    def _get_resolved_typevars(self) -> Dict[TypeVar, Type]:
-        """
-        Do not call this inside the __init__() method, because at that point the relevant information are not present.
-        See also https://github.com/python/cpython/issues/90899'
-        """
-
-        mapping: dict[TypeVar, type] = {}
-
-        if not hasattr(self, '__orig_bases__'):
-            raise AssertionError(
-                f'{self.class_name} is not a generic class. To make it generic, declare it like: '
-                f'class {self.class_name}(Generic[T], GenericMixin):...'
-            )
-
-        def collect(base, substitutions: dict[TypeVar, type]):
-            """Recursively collect type var mappings from a generic base."""
-            origin = get_origin(base) or base
-            args = get_args(base)
-
-            params = getattr(origin, '__parameters__', ())
-            # copy substitutions so each recursion has its own view
-            resolved = substitutions.copy()
-
-            for param, arg in zip(params, args):
-                if isinstance(arg, TypeVar):
-                    arg = substitutions.get(arg, arg)
-                mapping[param] = arg
-                resolved[param] = arg
-
-            # Recurse into base classes, applying current substitutions
-            for super_base in getattr(origin, '__orig_bases__', []):
-                super_origin = get_origin(super_base) or super_base
-                super_args = get_args(super_base)
-
-                if super_args:
-                    # Substitute any TypeVars in the super_base's args using resolved
-                    substituted_args = tuple(
-                        resolved.get(a, a) if isinstance(a, TypeVar) else a
-                        for a in super_args
-                    )
-                    # Build a new parametrized base so get_args() inside collect sees substituted_args
-                    try:
-                        substituted_base = super_origin[substituted_args]  # type: ignore[index]
-                    except TypeError:
-                        # Some origins won't accept subscription; fall back to passing the origin and trusting resolved
-                        substituted_base = super_base
-                    collect(base=substituted_base, substitutions=resolved)
-                else:
-                    collect(base=super_base, substitutions=resolved)
-
-        # Start from __orig_class__ if present, else walk the declared MRO bases
-        cls = getattr(self, '__orig_class__', None)
-        if cls is not None:
-            collect(base=cls, substitutions={})
-        else:
-            # Walk the full MRO to catch indirect generic ancestors
-            for c in self.__class__.__mro__:
-                for base in getattr(c, '__orig_bases__', []):
-                    collect(base=base, substitutions=mapping)
-
-        # Ensure no unresolved TypeVars remain
-        all_params = set()
-        for c in self.__class__.__mro__:
-            all_params.update(getattr(c, '__parameters__', ()))
-
-        unresolved = {p for p in all_params if p not in mapping or isinstance(mapping[p], TypeVar)}
-        if unresolved:
-            raise AssertionError(
-                f'You need to instantiate this class with type parameters! Example: {self.class_name}[int]()\n'
-                f'Also make sure that you do not call this in the __init__() method of your class!\n'
-                f'Unresolved type variables: {unresolved}\n'
-                f'See also https://github.com/python/cpython/issues/90899'
-            )
-
-        return mapping
-    @property
-    def class_name(self) -> str:
-        """ Get the name of the class of this instance. """
-
-        return type(self).__name__
-
-

A mixin that provides easy access to given type variables.

-

Example

-
>>> from typing import Generic, TypeVar
->>> T = TypeVar('T')
->>> U = TypeVar('U')
->>> class Foo(Generic[T, U], GenericMixin):
-...     values: list[T]
-...     value: U
->>> f = Foo[str, int]()
->>> f.type_vars
-{~T: <class 'str'>, ~U: <class 'int'>}
-
-

Subclasses

- -

Instance variables

-
-
prop class_name : str
-
-
- -Expand source code - -
@property
-def class_name(self) -> str:
-    """ Get the name of the class of this instance. """
-
-    return type(self).__name__
-
-

Get the name of the class of this instance.

-
-
prop type_var : Type
-
-
- -Expand source code - -
@property
-def type_var(self) -> Type:
-    """
-        Get the type variable for this class.
-        Use this for convenience if your class has only one type parameter.
-
-        DO NOT call this inside __init__()!
-
-        Example:
-            >>> from typing import Generic, TypeVar
-            >>> T = TypeVar('T')
-            >>> class Foo(Generic[T], GenericMixin):
-            ...     value: T
-            >>> f = Foo[float]()
-            >>> f.type_var
-            <class 'float'>
-    """
-
-    types = self._get_resolved_typevars()
-    assert len(types) == 1, f'You have multiple type parameters. Please use "type_vars" instead of "type_var".'
-    return list(types.values())[0]  # type: ignore
-
-

Get the type variable for this class. -Use this for convenience if your class has only one type parameter.

-

DO NOT call this inside init()!

-

Example

-
>>> from typing import Generic, TypeVar
->>> T = TypeVar('T')
->>> class Foo(Generic[T], GenericMixin):
-...     value: T
->>> f = Foo[float]()
->>> f.type_var
-<class 'float'>
-
-
-
prop type_vars : Dict[TypeVar, Type]
-
-
- -Expand source code - -
@property
-def type_vars(self) -> Dict[TypeVar, Type]:
-    """
-        Returns the mapping of type variables to types.
-
-        DO NOT call this inside __init__()!
-
-        Example:
-            >>> from typing import Generic, TypeVar
-            >>> T = TypeVar('T')
-            >>> U = TypeVar('U')
-            >>> class Foo(Generic[T, U], GenericMixin):
-            ...     values: list[T]
-            ...     value: U
-            >>> f = Foo[str, int]()
-            >>> f.type_vars
-            {~T: <class 'str'>, ~U: <class 'int'>}
-    """
-
-    return self._get_resolved_typevars()
-
-

Returns the mapping of type variables to types.

-

DO NOT call this inside init()!

-

Example

-
>>> from typing import Generic, TypeVar
->>> T = TypeVar('T')
->>> U = TypeVar('U')
->>> class Foo(Generic[T, U], GenericMixin):
-...     values: list[T]
-...     value: U
->>> f = Foo[str, int]()
->>> f.type_vars
-{~T: <class 'str'>, ~U: <class 'int'>}
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/mixins/index.html b/docs/pedantic/mixins/index.html deleted file mode 100644 index 395e738e..00000000 --- a/docs/pedantic/mixins/index.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - -pedantic.mixins API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.mixins

-
-
-
-
-

Sub-modules

-
-
pedantic.mixins.generic_mixin
-
-
-
-
pedantic.mixins.with_decorated_methods
-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/mixins/with_decorated_methods.html b/docs/pedantic/mixins/with_decorated_methods.html deleted file mode 100644 index f92feb20..00000000 --- a/docs/pedantic/mixins/with_decorated_methods.html +++ /dev/null @@ -1,300 +0,0 @@ - - - - - - -pedantic.mixins.with_decorated_methods API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.mixins.with_decorated_methods

-
-
-
-
-
-
-
-
-

Functions

-
-
-def create_decorator(decorator_type: DecoratorType,
transformation: Callable[[~C, DecoratorType, ~T], ~C] = None) ‑> Callable[[~T], Callable[[~C], ~C]]
-
-
-
- -Expand source code - -
def create_decorator(
-    decorator_type: DecoratorType,
-    transformation: Callable[[C, DecoratorType, T], C] = None,
-) -> Callable[[T], Callable[[C], C]]:
-    """
-    Creates a new decorator that is parametrized with one argument of an arbitrary type.
-    You can also pass an arbitrary [transformation] to add custom behavior to the decorator.
-    """
-
-    def decorator(value: T) -> Callable[[C], C]:
-        def fun(f: C) -> C:
-            setattr(f, decorator_type, value)
-
-            if transformation is None:
-                return f
-
-            return transformation(f, decorator_type, value)
-
-        return fun  # we do not need functools.wraps, because we return the original function here
-
-    return decorator
-
-

Creates a new decorator that is parametrized with one argument of an arbitrary type. -You can also pass an arbitrary [transformation] to add custom behavior to the decorator.

-
-
-
-
-

Classes

-
-
-class DecoratorType -(*args, **kwds) -
-
-
- -Expand source code - -
class DecoratorType(StrEnum):
-    """
-    The interface that defines all possible decorators types.
-
-    The values of this enum are used as property names and the properties are added to the decorated functions.
-    So I would recommend naming them with a leading underscore to keep them private and also write it lowercase.
-
-    Example:
-        >>> class Decorators(DecoratorType):
-        ...     FOO = '_foo'
-    """
-
-

The interface that defines all possible decorators types.

-

The values of this enum are used as property names and the properties are added to the decorated functions. -So I would recommend naming them with a leading underscore to keep them private and also write it lowercase.

-

Example

-
>>> class Decorators(DecoratorType):
-...     FOO = '_foo'
-
-

Ancestors

-
    -
  • enum.StrEnum
  • -
  • builtins.str
  • -
  • enum.ReprEnum
  • -
  • enum.Enum
  • -
-
-
-class WithDecoratedMethods -
-
-
- -Expand source code - -
class WithDecoratedMethods(ABC, Generic[DecoratorTypeVar], GenericMixin):
-    """
-    A mixin that is used to figure out which method is decorated with custom parameterized decorators.
-    Example:
-        >>> class Decorators(DecoratorType):
-        ...     FOO = '_foo'
-        ...     BAR = '_bar'
-        >>> foo = create_decorator(decorator_type=Decorators.FOO)
-        >>> bar = create_decorator(decorator_type=Decorators.BAR)
-        >>> class MyClass(WithDecoratedMethods[Decorators]):
-        ...    @foo(42)
-        ...    def m1(self) -> None:
-        ...        print('bar')
-        ...
-        ...    @foo(value=43)
-        ...    def m2(self) -> None:
-        ...        print('bar')
-        ...
-        ...    @bar(value=44)
-        ...    def m3(self) -> None:
-        ...        print('bar')
-        >>> instance = MyClass()
-        >>> instance.get_decorated_functions()  # doctest: +SKIP
-        {
-            <Decorators.FOO: '_foo'>: {
-                <bound method MyClass.m1 of <__main__.MyClass object at 0x7fea7a6e2610>>: 42,
-                <bound method MyClass.m2 of <__main__.MyClass object at 0x7fea7a6e2610>>: 43,
-            },
-            <Decorators.BAR: '_bar'>: {
-                <bound method MyClass.m3 of <__main__.MyClass object at 0x7fea7a6e2610>>: 44,
-            }
-        }
-    """
-
-    def get_decorated_functions(self) -> dict[DecoratorTypeVar, dict[C, T]]:
-        decorator_types = self.type_vars[DecoratorTypeVar]
-        decorated_functions = {t: dict() for t in decorator_types}  # type: ignore
-
-        for attribute_name in dir(self):
-            if attribute_name.startswith('__') or attribute_name in ['type_var', 'type_vars']:
-                continue
-
-            try:
-                attribute = getattr(self, attribute_name)
-            except BaseException:
-                continue  # ignore bad attributes
-
-            for decorator_type in decorator_types:  # type: ignore
-                if hasattr(attribute, decorator_type):
-                    decorated_functions[decorator_type][attribute] = getattr(attribute, decorator_type)
-
-        return decorated_functions
-
-

A mixin that is used to figure out which method is decorated with custom parameterized decorators.

-

Example

-
>>> class Decorators(DecoratorType):
-...     FOO = '_foo'
-...     BAR = '_bar'
->>> foo = create_decorator(decorator_type=Decorators.FOO)
->>> bar = create_decorator(decorator_type=Decorators.BAR)
->>> class MyClass(WithDecoratedMethods[Decorators]):
-...    @foo(42)
-...    def m1(self) -> None:
-...        print('bar')
-...
-...    @foo(value=43)
-...    def m2(self) -> None:
-...        print('bar')
-...
-...    @bar(value=44)
-...    def m3(self) -> None:
-...        print('bar')
->>> instance = MyClass()
->>> instance.get_decorated_functions()  # doctest: +SKIP
-{
-    <Decorators.FOO: '_foo'>: {
-        <bound method MyClass.m1 of <__main__.MyClass object at 0x7fea7a6e2610>>: 42,
-        <bound method MyClass.m2 of <__main__.MyClass object at 0x7fea7a6e2610>>: 43,
-    },
-    <Decorators.BAR: '_bar'>: {
-        <bound method MyClass.m3 of <__main__.MyClass object at 0x7fea7a6e2610>>: 44,
-    }
-}
-
-

Ancestors

- -

Methods

-
-
-def get_decorated_functions(self) ‑> dict[~DecoratorTypeVar, dict[~C, ~T]] -
-
-
- -Expand source code - -
def get_decorated_functions(self) -> dict[DecoratorTypeVar, dict[C, T]]:
-    decorator_types = self.type_vars[DecoratorTypeVar]
-    decorated_functions = {t: dict() for t in decorator_types}  # type: ignore
-
-    for attribute_name in dir(self):
-        if attribute_name.startswith('__') or attribute_name in ['type_var', 'type_vars']:
-            continue
-
-        try:
-            attribute = getattr(self, attribute_name)
-        except BaseException:
-            continue  # ignore bad attributes
-
-        for decorator_type in decorator_types:  # type: ignore
-            if hasattr(attribute, decorator_type):
-                decorated_functions[decorator_type][attribute] = getattr(attribute, decorator_type)
-
-    return decorated_functions
-
-
-
-
-

Inherited members

- -
-
-
-
- -
- - - diff --git a/docs/pedantic/models/decorated_function.html b/docs/pedantic/models/decorated_function.html deleted file mode 100644 index 8d427566..00000000 --- a/docs/pedantic/models/decorated_function.html +++ /dev/null @@ -1,514 +0,0 @@ - - - - - - -pedantic.models.decorated_function API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.models.decorated_function

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class DecoratedFunction -(func: Callable[..., Any]) -
-
-
- -Expand source code - -
class DecoratedFunction:
-    def __init__(self, func: Callable[..., Any]) -> None:
-        self._func = func
-
-        if not callable(func):
-            raise PedanticTypeCheckException(f'{self.full_name} should be a method or function.')
-
-        self._full_arg_spec = inspect.getfullargspec(func)
-        self._signature = inspect.signature(func)
-        self._err = f'In function {self.full_name}:\n'
-
-        try:
-            source = inspect.getsource(object=func)
-        except TypeError:
-            source = None
-
-        self._source: str | None = source
-
-        if IS_DOCSTRING_PARSER_INSTALLED:
-            self._docstring = parse(func.__doc__)
-        else:  # pragma: no cover
-            self._docstring = None
-
-    @property
-    def func(self) -> Callable[..., Any]:
-        return self._func
-
-    @property
-    def annotations(self) -> Dict[str, Any]:
-        return self._full_arg_spec.annotations
-
-    @property
-    def docstring(self) -> Optional[Docstring]:
-        """
-            Returns the docstring if the docstring-parser package is installed else None.
-            See also https://pypi.org/project/docstring-parser/
-        """
-
-        return self._docstring
-
-    @property
-    def raw_doc(self) -> Optional[str]:
-        return self._func.__doc__
-
-    @property
-    def signature(self) -> inspect.Signature:
-        return self._signature
-
-    @property
-    def err(self) -> str:
-        return self._err
-
-    @property
-    def source(self) -> str:
-        return self._source
-
-    @property
-    def name(self) -> str:
-        if hasattr(self._func, '__name__'):
-            return self._func.__name__
-
-        return self._func.func.__name__
-
-    @property
-    def full_name(self) -> str:
-        if hasattr(self._func, '__qualname__'):
-            return self._func.__qualname__
-
-        return self._func.func.__qualname__
-
-    @property
-    def is_static_method(self) -> bool:
-        """ I honestly have no idea how to do this better :( """
-
-        if self.source is None:
-            return False
-
-        return '@staticmethod' in self.source
-
-    @property
-    def wants_args(self) -> bool:
-        if self.source is None:
-            return False
-
-        return '*args' in self.source
-
-    @property
-    def is_property_setter(self) -> bool:
-        if self.source is None:
-            return False
-
-        return f'@{self.name}.setter' in self.source
-
-    @property
-    def should_have_kwargs(self) -> bool:
-        if self.is_property_setter or self.wants_args:
-            return False
-        elif not self.name.startswith('__') or not self.name.endswith('__'):
-            return True
-        return self.name in FUNCTIONS_THAT_REQUIRE_KWARGS
-
-    @property
-    def is_instance_method(self) -> bool:
-        return self._full_arg_spec.args != [] and self._full_arg_spec.args[0] == 'self'
-
-    @property
-    def is_class_method(self) -> bool:
-        """
-            Returns true if the function is decoratorated with the @classmethod decorator.
-            See also: https://stackoverflow.com/questions/19227724/check-if-a-function-uses-classmethod
-        """
-
-        return inspect.ismethod(self._func)
-
-    @property
-    def num_of_decorators(self) -> int:
-        if self.source is None:
-            return 0
-
-        return len(re.findall('@', self.source.split('def')[0]))
-
-    @property
-    def is_pedantic(self) -> bool:
-        if self.source is None:
-            return False
-
-        return '@pedantic' in self.source or '@require_kwargs' in self.source
-
-    @property
-    def is_coroutine(self) -> bool:
-        return inspect.iscoroutinefunction(self._func)
-
-    @property
-    def is_generator(self) -> bool:
-        return inspect.isgeneratorfunction(self._func)
-
-
-

Instance variables

-
-
prop annotations : Dict[str, Any]
-
-
- -Expand source code - -
@property
-def annotations(self) -> Dict[str, Any]:
-    return self._full_arg_spec.annotations
-
-
-
-
prop docstring : docstring_parser.common.Docstring | None
-
-
- -Expand source code - -
@property
-def docstring(self) -> Optional[Docstring]:
-    """
-        Returns the docstring if the docstring-parser package is installed else None.
-        See also https://pypi.org/project/docstring-parser/
-    """
-
-    return self._docstring
-
-

Returns the docstring if the docstring-parser package is installed else None. -See also https://pypi.org/project/docstring-parser/

-
-
prop err : str
-
-
- -Expand source code - -
@property
-def err(self) -> str:
-    return self._err
-
-
-
-
prop full_name : str
-
-
- -Expand source code - -
@property
-def full_name(self) -> str:
-    if hasattr(self._func, '__qualname__'):
-        return self._func.__qualname__
-
-    return self._func.func.__qualname__
-
-
-
-
prop func : Callable[..., Any]
-
-
- -Expand source code - -
@property
-def func(self) -> Callable[..., Any]:
-    return self._func
-
-
-
-
prop is_class_method : bool
-
-
- -Expand source code - -
@property
-def is_class_method(self) -> bool:
-    """
-        Returns true if the function is decoratorated with the @classmethod decorator.
-        See also: https://stackoverflow.com/questions/19227724/check-if-a-function-uses-classmethod
-    """
-
-    return inspect.ismethod(self._func)
-
-

Returns true if the function is decoratorated with the @classmethod decorator. -See also: https://stackoverflow.com/questions/19227724/check-if-a-function-uses-classmethod

-
-
prop is_coroutine : bool
-
-
- -Expand source code - -
@property
-def is_coroutine(self) -> bool:
-    return inspect.iscoroutinefunction(self._func)
-
-
-
-
prop is_generator : bool
-
-
- -Expand source code - -
@property
-def is_generator(self) -> bool:
-    return inspect.isgeneratorfunction(self._func)
-
-
-
-
prop is_instance_method : bool
-
-
- -Expand source code - -
@property
-def is_instance_method(self) -> bool:
-    return self._full_arg_spec.args != [] and self._full_arg_spec.args[0] == 'self'
-
-
-
-
prop is_pedantic : bool
-
-
- -Expand source code - -
@property
-def is_pedantic(self) -> bool:
-    if self.source is None:
-        return False
-
-    return '@pedantic' in self.source or '@require_kwargs' in self.source
-
-
-
-
prop is_property_setter : bool
-
-
- -Expand source code - -
@property
-def is_property_setter(self) -> bool:
-    if self.source is None:
-        return False
-
-    return f'@{self.name}.setter' in self.source
-
-
-
-
prop is_static_method : bool
-
-
- -Expand source code - -
@property
-def is_static_method(self) -> bool:
-    """ I honestly have no idea how to do this better :( """
-
-    if self.source is None:
-        return False
-
-    return '@staticmethod' in self.source
-
-

I honestly have no idea how to do this better :(

-
-
prop name : str
-
-
- -Expand source code - -
@property
-def name(self) -> str:
-    if hasattr(self._func, '__name__'):
-        return self._func.__name__
-
-    return self._func.func.__name__
-
-
-
-
prop num_of_decorators : int
-
-
- -Expand source code - -
@property
-def num_of_decorators(self) -> int:
-    if self.source is None:
-        return 0
-
-    return len(re.findall('@', self.source.split('def')[0]))
-
-
-
-
prop raw_doc : str | None
-
-
- -Expand source code - -
@property
-def raw_doc(self) -> Optional[str]:
-    return self._func.__doc__
-
-
-
-
prop should_have_kwargs : bool
-
-
- -Expand source code - -
@property
-def should_have_kwargs(self) -> bool:
-    if self.is_property_setter or self.wants_args:
-        return False
-    elif not self.name.startswith('__') or not self.name.endswith('__'):
-        return True
-    return self.name in FUNCTIONS_THAT_REQUIRE_KWARGS
-
-
-
-
prop signature : inspect.Signature
-
-
- -Expand source code - -
@property
-def signature(self) -> inspect.Signature:
-    return self._signature
-
-
-
-
prop source : str
-
-
- -Expand source code - -
@property
-def source(self) -> str:
-    return self._source
-
-
-
-
prop wants_args : bool
-
-
- -Expand source code - -
@property
-def wants_args(self) -> bool:
-    if self.source is None:
-        return False
-
-    return '*args' in self.source
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/models/function_call.html b/docs/pedantic/models/function_call.html deleted file mode 100644 index 42d08d18..00000000 --- a/docs/pedantic/models/function_call.html +++ /dev/null @@ -1,465 +0,0 @@ - - - - - - -pedantic.models.function_call API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.models.function_call

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class FunctionCall -(func: DecoratedFunction,
args: Tuple[Any, ...],
kwargs: Dict[str, Any],
context: Dict[str, Type])
-
-
-
- -Expand source code - -
class FunctionCall:
-    def __init__(self, func: DecoratedFunction, args: Tuple[Any, ...], kwargs: Dict[str, Any], context: Dict[str, Type]) -> None:
-        self._func = func
-        self._args = args
-        self._kwargs = kwargs
-        self._context = context
-        self._instance = self.args[0] if self.func.is_instance_method else None
-        self._type_vars = dict()
-        self._params_without_self = {k: v for k, v in self.func.signature.parameters.items() if v.name != 'self'}
-        self._already_checked_kwargs = []
-        self._get_type_vars = lambda: self._type_vars
-
-    @property
-    def func(self) -> DecoratedFunction:
-        return self._func
-
-    @property
-    def args(self) -> Tuple[Any, ...]:
-        return self._args
-
-    @property
-    def kwargs(self) -> Dict[str, Any]:
-        return self._kwargs
-
-    @property
-    def not_yet_check_kwargs(self) -> Dict[str, Any]:
-        return {k: v for k, v in self._kwargs.items() if k not in self._already_checked_kwargs}
-
-    @property
-    def type_vars(self) -> Dict[TypeVar, Any]:
-        if hasattr(self._instance, TYPE_VAR_METHOD_NAME):
-            self._get_type_vars = getattr(self._instance, TYPE_VAR_METHOD_NAME)
-
-        res = self._get_type_vars()
-
-        if TYPE_VAR_SELF not in res:
-            res[TYPE_VAR_SELF] = self.clazz
-
-        return res
-
-    @property
-    def clazz(self) -> Optional[Type]:
-        """ Return the enclosing class of the called function if there is one. """
-
-        if self._instance is not None:
-            # case instance method
-            return type(self._instance)
-        elif self.func.is_class_method:
-            return self.func.func.__self__
-        elif self.func.is_static_method:
-            if not self.args:
-                # static method was called on class
-                class_name = self.func.full_name.split('.')[-2]
-                return ForwardRef(class_name)   # this ForwardRef is resolved later
-
-            # static method was called on instance
-            return type(self.args[0])
-
-    @property
-    def params_without_self(self) -> Dict[str, inspect.Parameter]:
-        return self._params_without_self
-
-    @property
-    def args_without_self(self) -> Tuple[Any, ...]:
-        max_allowed = 0 if not self.func.is_pedantic else 1
-        uses_multiple_decorators = self.func.num_of_decorators > max_allowed
-
-        if self.func.is_instance_method or self.func.is_static_method or uses_multiple_decorators:
-            return self.args[1:]  # self is always the first argument if present
-        return self.args
-
-    def assert_uses_kwargs(self) -> None:
-        if self.func.should_have_kwargs and self.args_without_self:
-            raise PedanticCallWithArgsException(
-                f'{self.func.err}Use kwargs when you call function {self.func.name}. Args: {self.args_without_self}')
-
-    def check_types(self) -> ReturnType:
-        self._check_types_of_arguments()
-        return self._check_types_return(result=self._get_return_value())
-
-    async def async_check_types(self) -> ReturnType:
-        self._check_types_of_arguments()
-        return self._check_types_return(result=await self._async_get_return_value())
-
-    def _check_types_of_arguments(self) -> None:
-        d = self.params_without_self.items()
-        self._check_type_param(params={k: v for k, v in d if not str(v).startswith('*')})
-        self._check_types_args(params={k: v for k, v in d if str(v).startswith('*') and not str(v).startswith('**')})
-        self._check_types_kwargs(params={k: v for k, v in d if str(v).startswith('**')})
-
-    def _check_type_param(self, params: Dict[str, inspect.Parameter]) -> None:
-        arg_index = 1 if self.func.is_instance_method else 0
-
-        for key, param in params.items():
-            self._already_checked_kwargs.append(key)
-            self._assert_param_has_type_annotation(param=param)
-
-            if param.default is inspect.Signature.empty:
-                if self.func.should_have_kwargs:
-                    if key not in self.kwargs:
-                        raise PedanticTypeCheckException(f'{self.func.err}Parameter "{key}" is unfilled.')
-
-                    actual_value = self.kwargs[key]
-                else:
-                    actual_value = self.args[arg_index]
-                    arg_index += 1
-            else:
-                if key in self.kwargs:
-                    actual_value = self.kwargs[key]
-                else:
-                    actual_value = param.default
-
-            assert_value_matches_type(
-                value=actual_value,
-                type_=param.annotation,
-                err=self.func.err,
-                type_vars=self.type_vars,
-                key=key,
-                context=self._context,
-            )
-
-    def _check_types_args(self, params: Dict[str, inspect.Parameter]) -> None:
-        if not params:
-            return
-
-        expected = list(params.values())[0].annotation  # it's not possible to have more than 1
-
-        for arg in self.args:
-            assert_value_matches_type(
-                value=arg,
-                type_=expected,
-                err=self.func.err,
-                type_vars=self.type_vars,
-                context=self._context,
-            )
-
-    def _check_types_kwargs(self, params: Dict[str, inspect.Parameter]) -> None:
-        if not params:
-            return
-
-        param = list(params.values())[0]  # it's not possible to have more than 1
-        self._assert_param_has_type_annotation(param=param)
-
-        for kwarg in self.not_yet_check_kwargs:
-            actual_value = self.kwargs[kwarg]
-            assert_value_matches_type(
-                value=actual_value,
-                type_=param.annotation,
-                err=self.func.err,
-                type_vars=self.type_vars,
-                key=kwarg,
-                context=self._context,
-            )
-
-    def _check_types_return(self, result: Any) -> Union[None, GeneratorWrapper]:
-        if self.func.signature.return_annotation is inspect.Signature.empty:
-            raise PedanticTypeCheckException(
-                f'{self.func.err}There should be a type hint for the return type (e.g. None if nothing is returned).')
-
-        expected_result_type = self.func.annotations['return']
-
-        if self.func.is_generator:
-            return GeneratorWrapper(
-                wrapped=result, expected_type=expected_result_type, err_msg=self.func.err, type_vars=self.type_vars)
-
-        msg = f'{self.func.err}Type hint of return value is incorrect: Expected type {expected_result_type} ' \
-              f'but {result} of type {type(result)} was the return value which does not match.'
-        assert_value_matches_type(
-            value=result,
-            type_=expected_result_type,
-            err=self.func.err,
-            type_vars=self.type_vars,
-            msg=msg,
-            context=self._context,
-        )
-        return result
-
-    def _assert_param_has_type_annotation(self, param: inspect.Parameter):
-        if param.annotation == inspect.Parameter.empty:
-            raise PedanticTypeCheckException(f'{self.func.err}Parameter "{param.name}" should have a type hint.')
-
-    def _get_return_value(self) -> Any:
-        if self.func.is_static_method or self.func.is_class_method:
-            return self.func.func(**self.kwargs)
-        else:
-            return self.func.func(*self.args, **self.kwargs)
-
-    async def _async_get_return_value(self) -> Any:
-        if self.func.is_static_method or self.func.is_class_method:
-            return await self.func.func(**self.kwargs)
-        else:
-            return await self.func.func(*self.args, **self.kwargs)
-
-
-

Instance variables

-
-
prop args : Tuple[Any, ...]
-
-
- -Expand source code - -
@property
-def args(self) -> Tuple[Any, ...]:
-    return self._args
-
-
-
-
prop args_without_self : Tuple[Any, ...]
-
-
- -Expand source code - -
@property
-def args_without_self(self) -> Tuple[Any, ...]:
-    max_allowed = 0 if not self.func.is_pedantic else 1
-    uses_multiple_decorators = self.func.num_of_decorators > max_allowed
-
-    if self.func.is_instance_method or self.func.is_static_method or uses_multiple_decorators:
-        return self.args[1:]  # self is always the first argument if present
-    return self.args
-
-
-
-
prop clazz : Type | None
-
-
- -Expand source code - -
@property
-def clazz(self) -> Optional[Type]:
-    """ Return the enclosing class of the called function if there is one. """
-
-    if self._instance is not None:
-        # case instance method
-        return type(self._instance)
-    elif self.func.is_class_method:
-        return self.func.func.__self__
-    elif self.func.is_static_method:
-        if not self.args:
-            # static method was called on class
-            class_name = self.func.full_name.split('.')[-2]
-            return ForwardRef(class_name)   # this ForwardRef is resolved later
-
-        # static method was called on instance
-        return type(self.args[0])
-
-

Return the enclosing class of the called function if there is one.

-
-
prop funcDecoratedFunction
-
-
- -Expand source code - -
@property
-def func(self) -> DecoratedFunction:
-    return self._func
-
-
-
-
prop kwargs : Dict[str, Any]
-
-
- -Expand source code - -
@property
-def kwargs(self) -> Dict[str, Any]:
-    return self._kwargs
-
-
-
-
prop not_yet_check_kwargs : Dict[str, Any]
-
-
- -Expand source code - -
@property
-def not_yet_check_kwargs(self) -> Dict[str, Any]:
-    return {k: v for k, v in self._kwargs.items() if k not in self._already_checked_kwargs}
-
-
-
-
prop params_without_self : Dict[str, inspect.Parameter]
-
-
- -Expand source code - -
@property
-def params_without_self(self) -> Dict[str, inspect.Parameter]:
-    return self._params_without_self
-
-
-
-
prop type_vars : Dict[TypeVar, Any]
-
-
- -Expand source code - -
@property
-def type_vars(self) -> Dict[TypeVar, Any]:
-    if hasattr(self._instance, TYPE_VAR_METHOD_NAME):
-        self._get_type_vars = getattr(self._instance, TYPE_VAR_METHOD_NAME)
-
-    res = self._get_type_vars()
-
-    if TYPE_VAR_SELF not in res:
-        res[TYPE_VAR_SELF] = self.clazz
-
-    return res
-
-
-
-
-

Methods

-
-
-def assert_uses_kwargs(self) ‑> None -
-
-
- -Expand source code - -
def assert_uses_kwargs(self) -> None:
-    if self.func.should_have_kwargs and self.args_without_self:
-        raise PedanticCallWithArgsException(
-            f'{self.func.err}Use kwargs when you call function {self.func.name}. Args: {self.args_without_self}')
-
-
-
-
-async def async_check_types(self) ‑> ~ReturnType -
-
-
- -Expand source code - -
async def async_check_types(self) -> ReturnType:
-    self._check_types_of_arguments()
-    return self._check_types_return(result=await self._async_get_return_value())
-
-
-
-
-def check_types(self) ‑> ~ReturnType -
-
-
- -Expand source code - -
def check_types(self) -> ReturnType:
-    self._check_types_of_arguments()
-    return self._check_types_return(result=self._get_return_value())
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/models/generator_wrapper.html b/docs/pedantic/models/generator_wrapper.html deleted file mode 100644 index 8d5ce8aa..00000000 --- a/docs/pedantic/models/generator_wrapper.html +++ /dev/null @@ -1,220 +0,0 @@ - - - - - - -pedantic.models.generator_wrapper API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.models.generator_wrapper

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class GeneratorWrapper -(wrapped: Generator,
expected_type: Any,
err_msg: str,
type_vars: Dict[TypeVar, Any])
-
-
-
- -Expand source code - -
class GeneratorWrapper:
-    def __init__(self, wrapped: Generator, expected_type: Any, err_msg: str, type_vars: Dict[TypeVar, Any]) -> None:
-        self._generator = wrapped
-        self._err = err_msg
-        self._yield_type = None
-        self._send_type = None
-        self._return_type = None
-        self._type_vars = type_vars
-        self._initialized = False
-
-        self._set_and_check_return_types(expected_return_type=expected_type)
-
-    def __iter__(self) -> 'GeneratorWrapper':
-        return self
-
-    def __next__(self) -> Any:
-        return self.send(obj=None)
-
-    def __getattr__(self, name: str) -> Any:
-        return getattr(self._generator, name)
-
-    def throw(self, *args) -> Any:
-        return self._generator.throw(*args)
-
-    def close(self) -> None:
-        self._generator.close()
-
-    def send(self, obj) -> Any:
-        if self._initialized:
-            assert_value_matches_type(value=obj, type_=self._send_type, type_vars=self._type_vars, err=self._err)
-        else:
-            self._initialized = True
-
-        try:
-            returned_value = self._generator.send(obj)
-        except StopIteration as ex:
-            assert_value_matches_type(value=ex.value,
-                                      type_=self._return_type,
-                                      type_vars=self._type_vars,
-                                      err=self._err)
-            raise ex
-
-        assert_value_matches_type(value=returned_value,
-                                  type_=self._yield_type,
-                                  type_vars=self._type_vars,
-                                  err=self._err)
-        return returned_value
-
-    def _set_and_check_return_types(self, expected_return_type: Any) -> Any:
-        base_generic = get_base_generic(cls=expected_return_type)
-
-        if base_generic not in [Generator, Iterable, Iterator]:
-            raise PedanticTypeCheckException(
-                f'{self._err}Generator should have type annotation "typing.Generator[]", "typing.Iterator[]" or '
-                f'"typing.Iterable[]". Got "{expected_return_type}" instead.')
-
-        result = get_type_arguments(expected_return_type)
-
-        if len(result) == 1:
-            self._yield_type = result[0]
-        elif len(result) == 3:
-            self._yield_type = result[0]
-            self._send_type = result[1]
-            self._return_type = result[2]
-        else:
-            raise PedanticTypeCheckException(f'{self._err}Generator should have a type argument. Got: {result}')
-        return result[0]
-
-
-

Methods

-
-
-def close(self) ‑> None -
-
-
- -Expand source code - -
def close(self) -> None:
-    self._generator.close()
-
-
-
-
-def send(self, obj) ‑> Any -
-
-
- -Expand source code - -
def send(self, obj) -> Any:
-    if self._initialized:
-        assert_value_matches_type(value=obj, type_=self._send_type, type_vars=self._type_vars, err=self._err)
-    else:
-        self._initialized = True
-
-    try:
-        returned_value = self._generator.send(obj)
-    except StopIteration as ex:
-        assert_value_matches_type(value=ex.value,
-                                  type_=self._return_type,
-                                  type_vars=self._type_vars,
-                                  err=self._err)
-        raise ex
-
-    assert_value_matches_type(value=returned_value,
-                              type_=self._yield_type,
-                              type_vars=self._type_vars,
-                              err=self._err)
-    return returned_value
-
-
-
-
-def throw(self, *args) ‑> Any -
-
-
- -Expand source code - -
def throw(self, *args) -> Any:
-    return self._generator.throw(*args)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/models/index.html b/docs/pedantic/models/index.html deleted file mode 100644 index 409c8686..00000000 --- a/docs/pedantic/models/index.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - -pedantic.models API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.models

-
-
-
-
-

Sub-modules

-
-
pedantic.models.decorated_function
-
-
-
-
pedantic.models.function_call
-
-
-
-
pedantic.models.generator_wrapper
-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/index.html b/docs/pedantic/tests/index.html deleted file mode 100644 index 98d274f5..00000000 --- a/docs/pedantic/tests/index.html +++ /dev/null @@ -1,218 +0,0 @@ - - - - - - -pedantic.tests API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests

-
-
-
-
-

Sub-modules

-
-
pedantic.tests.test_assert_value_matches_type
-
-
-
-
pedantic.tests.test_async_context_manager
-
-
-
-
pedantic.tests.test_context_manager
-
-
-
-
pedantic.tests.test_frozen_dataclass
-
-
-
-
pedantic.tests.test_generator_wrapper
-
-
-
-
pedantic.tests.test_generic_mixin
-
-
-
-
pedantic.tests.test_in_subprocess
-
-
-
-
pedantic.tests.test_rename_kwargs
-
-
-
-
pedantic.tests.test_resolve_forward_ref
-
-
-
-
pedantic.tests.test_retry
-
-
-
-
pedantic.tests.test_with_decorated_methods
-
-
-
-
pedantic.tests.tests_class_decorators
-
-
-
-
pedantic.tests.tests_combination_of_decorators
-
-
-
-
pedantic.tests.tests_decorated_function
-
-
-
-
pedantic.tests.tests_docstring
-
-
-
-
pedantic.tests.tests_doctests
-
-
-
-
pedantic.tests.tests_environment_variables
-
-
-
-
pedantic.tests.tests_generator
-
-
-
-
pedantic.tests.tests_generic_classes
-
-
-
-
pedantic.tests.tests_main
-
-
-
-
pedantic.tests.tests_mock
-
-
-
-
pedantic.tests.tests_pedantic
-
-
-
-
pedantic.tests.tests_pedantic_async
-
-
-
-
pedantic.tests.tests_pedantic_class
-
-
-
-
pedantic.tests.tests_pedantic_class_docstring
-
-
-
-
pedantic.tests.tests_pedantic_python_311
-
-
-
-
pedantic.tests.tests_require_kwargs
-
-
-
-
pedantic.tests.tests_small_method_decorators
-
-
-
-
pedantic.tests.validate
-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/test_assert_value_matches_type.html b/docs/pedantic/tests/test_assert_value_matches_type.html deleted file mode 100644 index 004f72ce..00000000 --- a/docs/pedantic/tests/test_assert_value_matches_type.html +++ /dev/null @@ -1,650 +0,0 @@ - - - - - - -pedantic.tests.test_assert_value_matches_type API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.test_assert_value_matches_type

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class Foo -(value: int) -
-
-
- -Expand source code - -
@dataclass
-class Foo:
-    value: int
-
-

Foo(value: int)

-

Instance variables

-
-
var value : int
-
-

The type of the None singleton.

-
-
-
-
-class TestAssertValueMatchesType -(methodName='runTest') -
-
-
- -Expand source code - -
class TestAssertValueMatchesType(unittest.TestCase):
-    def test_callable(self):
-        def _cb(foo: Foo) -> str:
-            return str(foo.value)
-
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., str],
-            err='',
-            type_vars={},
-        )
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            assert_value_matches_type(
-                value=_cb,
-                type_=Callable[..., int],
-                err='',
-                type_vars={},
-            )
-
-    def test_callable_return_type_none(self):
-        def _cb(foo: Foo) -> None:
-            return print(foo)
-
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., None],
-            err='',
-            type_vars={},
-        )
-
-    def test_callable_awaitable(self):
-        async def _cb(foo: Foo) -> str:
-            return str(foo.value)
-
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., Awaitable[str]],
-            err='',
-            type_vars={},
-        )
-
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., Awaitable[Any]],
-            err='',
-            type_vars={},
-        )
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            assert_value_matches_type(
-                value=_cb,
-                type_=Callable[..., Awaitable[int]],
-                err='',
-                type_vars={},
-            )
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            assert_value_matches_type(
-                value=_cb,
-                type_=Callable[..., str],
-                err='',
-                type_vars={},
-            )
-
-    def test_callable_coroutine(self):
-        async def _cb(foo: Foo) -> str:
-            return str(foo.value)
-
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., Coroutine[None, None, str]],
-            err='',
-            type_vars={},
-        )
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            assert_value_matches_type(
-                value=_cb,
-                type_=Callable[..., Coroutine[None, None, int]],
-                err='',
-                type_vars={},
-            )
-
-    def test_callable_awaitable_with_none_return_type(self):
-        async def _cb(foo: Foo) -> None:
-            print(foo)
-
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., Awaitable[None]],
-            err='',
-            type_vars={},
-        )
-
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., Awaitable[Any]],
-            err='',
-            type_vars={},
-        )
-
-    def test_callable_with_old_union_type_hint(self):
-        async def _cb(machine_id: str) -> Union[int, None]:
-            return 42
-
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., Awaitable[Union[int, None]]],
-            err='',
-            type_vars={},
-        )
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            assert_value_matches_type(
-                value=_cb,
-                type_=Callable[..., Awaitable[int]],
-                err='',
-                type_vars={},
-            )
-
-    def test_callable_with_new_union_type_hint(self):
-        async def _cb(machine_id: str) -> int | None:
-            return 42
-
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., Awaitable[int | None]],
-            err='',
-            type_vars={},
-        )
-
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., Awaitable[Any]],
-            err='',
-            type_vars={},
-        )
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            assert_value_matches_type(
-                value=_cb,
-                type_=Callable[..., Awaitable[int]],
-                err='',
-                type_vars={},
-            )
-
-    def test_forward_ref_inheritance(self):
-        T = TypeVar('T')
-
-        class State(Generic[T], ABC):
-            pass
-
-        class StateMachine(Generic[T], ABC):
-            pass
-
-        class MachineState(State['MachineStateMachine']):
-            pass
-
-        class OfflineMachineState(MachineState):
-            pass
-
-        class MachineStateMachine(StateMachine[MachineState]):
-            pass
-
-        assert_value_matches_type(
-            value=OfflineMachineState(),
-            type_=Optional['MachineState'],
-            err='',
-            type_vars={},
-            context=locals(),
-        )
-
-    def test_tuple_with_ellipsis(self):
-        """ Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/75 """
-
-        assert_value_matches_type(
-            value=(1, 2.0, 'hello'),
-            type_=Tuple[Any, ...],
-            err='',
-            type_vars={},
-            context=locals(),
-        )
-
-    def test_union_of_callable(self):
-        """ Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/74 """
-
-        assert_value_matches_type(
-            value=datetime.now(),
-            type_=Union[datetime, Callable[[], datetime]],
-            err='',
-            type_vars={},
-            context=locals(),
-        )
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_callable(self) -
-
-
- -Expand source code - -
def test_callable(self):
-    def _cb(foo: Foo) -> str:
-        return str(foo.value)
-
-    assert_value_matches_type(
-        value=_cb,
-        type_=Callable[..., str],
-        err='',
-        type_vars={},
-    )
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., int],
-            err='',
-            type_vars={},
-        )
-
-
-
-
-def test_callable_awaitable(self) -
-
-
- -Expand source code - -
def test_callable_awaitable(self):
-    async def _cb(foo: Foo) -> str:
-        return str(foo.value)
-
-    assert_value_matches_type(
-        value=_cb,
-        type_=Callable[..., Awaitable[str]],
-        err='',
-        type_vars={},
-    )
-
-    assert_value_matches_type(
-        value=_cb,
-        type_=Callable[..., Awaitable[Any]],
-        err='',
-        type_vars={},
-    )
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., Awaitable[int]],
-            err='',
-            type_vars={},
-        )
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., str],
-            err='',
-            type_vars={},
-        )
-
-
-
-
-def test_callable_awaitable_with_none_return_type(self) -
-
-
- -Expand source code - -
def test_callable_awaitable_with_none_return_type(self):
-    async def _cb(foo: Foo) -> None:
-        print(foo)
-
-    assert_value_matches_type(
-        value=_cb,
-        type_=Callable[..., Awaitable[None]],
-        err='',
-        type_vars={},
-    )
-
-    assert_value_matches_type(
-        value=_cb,
-        type_=Callable[..., Awaitable[Any]],
-        err='',
-        type_vars={},
-    )
-
-
-
-
-def test_callable_coroutine(self) -
-
-
- -Expand source code - -
def test_callable_coroutine(self):
-    async def _cb(foo: Foo) -> str:
-        return str(foo.value)
-
-    assert_value_matches_type(
-        value=_cb,
-        type_=Callable[..., Coroutine[None, None, str]],
-        err='',
-        type_vars={},
-    )
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., Coroutine[None, None, int]],
-            err='',
-            type_vars={},
-        )
-
-
-
-
-def test_callable_return_type_none(self) -
-
-
- -Expand source code - -
def test_callable_return_type_none(self):
-    def _cb(foo: Foo) -> None:
-        return print(foo)
-
-    assert_value_matches_type(
-        value=_cb,
-        type_=Callable[..., None],
-        err='',
-        type_vars={},
-    )
-
-
-
-
-def test_callable_with_new_union_type_hint(self) -
-
-
- -Expand source code - -
def test_callable_with_new_union_type_hint(self):
-    async def _cb(machine_id: str) -> int | None:
-        return 42
-
-    assert_value_matches_type(
-        value=_cb,
-        type_=Callable[..., Awaitable[int | None]],
-        err='',
-        type_vars={},
-    )
-
-    assert_value_matches_type(
-        value=_cb,
-        type_=Callable[..., Awaitable[Any]],
-        err='',
-        type_vars={},
-    )
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., Awaitable[int]],
-            err='',
-            type_vars={},
-        )
-
-
-
-
-def test_callable_with_old_union_type_hint(self) -
-
-
- -Expand source code - -
def test_callable_with_old_union_type_hint(self):
-    async def _cb(machine_id: str) -> Union[int, None]:
-        return 42
-
-    assert_value_matches_type(
-        value=_cb,
-        type_=Callable[..., Awaitable[Union[int, None]]],
-        err='',
-        type_vars={},
-    )
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        assert_value_matches_type(
-            value=_cb,
-            type_=Callable[..., Awaitable[int]],
-            err='',
-            type_vars={},
-        )
-
-
-
-
-def test_forward_ref_inheritance(self) -
-
-
- -Expand source code - -
def test_forward_ref_inheritance(self):
-    T = TypeVar('T')
-
-    class State(Generic[T], ABC):
-        pass
-
-    class StateMachine(Generic[T], ABC):
-        pass
-
-    class MachineState(State['MachineStateMachine']):
-        pass
-
-    class OfflineMachineState(MachineState):
-        pass
-
-    class MachineStateMachine(StateMachine[MachineState]):
-        pass
-
-    assert_value_matches_type(
-        value=OfflineMachineState(),
-        type_=Optional['MachineState'],
-        err='',
-        type_vars={},
-        context=locals(),
-    )
-
-
-
-
-def test_tuple_with_ellipsis(self) -
-
-
- -Expand source code - -
def test_tuple_with_ellipsis(self):
-    """ Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/75 """
-
-    assert_value_matches_type(
-        value=(1, 2.0, 'hello'),
-        type_=Tuple[Any, ...],
-        err='',
-        type_vars={},
-        context=locals(),
-    )
-
- -
-
-def test_union_of_callable(self) -
-
-
- -Expand source code - -
def test_union_of_callable(self):
-    """ Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/74 """
-
-    assert_value_matches_type(
-        value=datetime.now(),
-        type_=Union[datetime, Callable[[], datetime]],
-        err='',
-        type_vars={},
-        context=locals(),
-    )
-
- -
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/test_async_context_manager.html b/docs/pedantic/tests/test_async_context_manager.html deleted file mode 100644 index 7393a93e..00000000 --- a/docs/pedantic/tests/test_async_context_manager.html +++ /dev/null @@ -1,324 +0,0 @@ - - - - - - -pedantic.tests.test_async_context_manager API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.test_async_context_manager

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestAsyncContextManager -(methodName='runTest') -
-
-
- -Expand source code - -
class TestAsyncContextManager(unittest.IsolatedAsyncioTestCase):
-    async def test_safe_context_manager_no_exception(self):
-        before = False
-        after = False
-
-        @safe_async_contextmanager
-        async def foo():
-            nonlocal before, after
-            before = True
-            yield 42
-            after = True
-
-        self.assertFalse(before)
-        self.assertFalse(after)
-
-        async with foo() as f:
-            self.assertTrue(before)
-            self.assertFalse(after)
-            self.assertEqual(42, f)
-
-        self.assertTrue(before)
-        self.assertTrue(after)
-
-    async def test_safe_context_manager_with_exception(self):
-        before = False
-        after = False
-
-        @safe_async_contextmanager
-        async def foo():
-            nonlocal before, after
-            before = True
-            yield 42
-            after = True
-
-        self.assertFalse(before)
-        self.assertFalse(after)
-
-        with self.assertRaises(expected_exception=ValueError):
-            async with foo() as f:
-                self.assertTrue(before)
-                self.assertFalse(after)
-                self.assertEqual(42, f)
-                raise ValueError('oh no')
-
-        self.assertTrue(before)
-        self.assertTrue(after)
-
-    async def test_safe_context_manager_with_args_kwargs(self):
-        @safe_async_contextmanager
-        async def foo(a, b):
-            yield a, b
-
-        async with foo(42, b=43) as f:
-            self.assertEqual((42, 43), f)
-
-    def test_safe_context_manager_async(self):
-        with self.assertRaises(expected_exception=AssertionError) as e:
-            @safe_async_contextmanager
-            def foo(a, b):
-                yield a, b
-
-        expected = 'foo is not an async generator. So you need to use "safe_contextmanager" instead.'
-        self.assertEqual(expected, e.exception.args[0])
-
-    async def test_safe_context_manager_non_generator(self):
-        with self.assertRaises(expected_exception=AssertionError) as e:
-            @safe_async_contextmanager
-            async def foo(a, b):
-                return a, b
-
-        expected = 'foo is not a generator.'
-        self.assertEqual(expected, e.exception.args[0])
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.async_case.IsolatedAsyncioTestCase
  • -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_safe_context_manager_async(self) -
-
-
- -Expand source code - -
def test_safe_context_manager_async(self):
-    with self.assertRaises(expected_exception=AssertionError) as e:
-        @safe_async_contextmanager
-        def foo(a, b):
-            yield a, b
-
-    expected = 'foo is not an async generator. So you need to use "safe_contextmanager" instead.'
-    self.assertEqual(expected, e.exception.args[0])
-
-
-
-
-async def test_safe_context_manager_no_exception(self) -
-
-
- -Expand source code - -
async def test_safe_context_manager_no_exception(self):
-    before = False
-    after = False
-
-    @safe_async_contextmanager
-    async def foo():
-        nonlocal before, after
-        before = True
-        yield 42
-        after = True
-
-    self.assertFalse(before)
-    self.assertFalse(after)
-
-    async with foo() as f:
-        self.assertTrue(before)
-        self.assertFalse(after)
-        self.assertEqual(42, f)
-
-    self.assertTrue(before)
-    self.assertTrue(after)
-
-
-
-
-async def test_safe_context_manager_non_generator(self) -
-
-
- -Expand source code - -
async def test_safe_context_manager_non_generator(self):
-    with self.assertRaises(expected_exception=AssertionError) as e:
-        @safe_async_contextmanager
-        async def foo(a, b):
-            return a, b
-
-    expected = 'foo is not a generator.'
-    self.assertEqual(expected, e.exception.args[0])
-
-
-
-
-async def test_safe_context_manager_with_args_kwargs(self) -
-
-
- -Expand source code - -
async def test_safe_context_manager_with_args_kwargs(self):
-    @safe_async_contextmanager
-    async def foo(a, b):
-        yield a, b
-
-    async with foo(42, b=43) as f:
-        self.assertEqual((42, 43), f)
-
-
-
-
-async def test_safe_context_manager_with_exception(self) -
-
-
- -Expand source code - -
async def test_safe_context_manager_with_exception(self):
-    before = False
-    after = False
-
-    @safe_async_contextmanager
-    async def foo():
-        nonlocal before, after
-        before = True
-        yield 42
-        after = True
-
-    self.assertFalse(before)
-    self.assertFalse(after)
-
-    with self.assertRaises(expected_exception=ValueError):
-        async with foo() as f:
-            self.assertTrue(before)
-            self.assertFalse(after)
-            self.assertEqual(42, f)
-            raise ValueError('oh no')
-
-    self.assertTrue(before)
-    self.assertTrue(after)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/test_context_manager.html b/docs/pedantic/tests/test_context_manager.html deleted file mode 100644 index 2db18d1c..00000000 --- a/docs/pedantic/tests/test_context_manager.html +++ /dev/null @@ -1,323 +0,0 @@ - - - - - - -pedantic.tests.test_context_manager API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.test_context_manager

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestContextManager -(methodName='runTest') -
-
-
- -Expand source code - -
class TestContextManager(TestCase):
-    def test_safe_context_manager_no_exception(self):
-        before = False
-        after = False
-
-        @safe_contextmanager
-        def foo():
-            nonlocal before, after
-            before = True
-            yield 42
-            after = True
-
-        self.assertFalse(before)
-        self.assertFalse(after)
-
-        with foo() as f:
-            self.assertTrue(before)
-            self.assertFalse(after)
-            self.assertEqual(42, f)
-
-        self.assertTrue(before)
-        self.assertTrue(after)
-
-    def test_safe_context_manager_with_exception(self):
-        before = False
-        after = False
-
-        @safe_contextmanager
-        def foo():
-            nonlocal before, after
-            before = True
-            yield 42
-            after = True
-
-        self.assertFalse(before)
-        self.assertFalse(after)
-
-        with self.assertRaises(expected_exception=ValueError):
-            with foo() as f:
-                self.assertTrue(before)
-                self.assertFalse(after)
-                self.assertEqual(42, f)
-                raise ValueError('oh no')
-
-        self.assertTrue(before)
-        self.assertTrue(after)
-
-    def test_safe_context_manager_with_args_kwargs(self):
-        @safe_contextmanager
-        def foo(a, b):
-            yield a, b
-
-        with foo(42, b=43) as f:
-            self.assertEqual((42, 43), f)
-
-    def test_safe_context_manager_async(self):
-        with self.assertRaises(expected_exception=AssertionError) as e:
-            @safe_contextmanager
-            async def foo(a, b):
-                yield a, b
-
-        expected = 'foo is async. So you need to use "safe_async_contextmanager" instead.'
-        self.assertEqual(expected, e.exception.args[0])
-
-    def test_safe_context_manager_non_generator(self):
-        with self.assertRaises(expected_exception=AssertionError) as e:
-            @safe_contextmanager
-            def foo(a, b):
-                return a, b
-
-        expected = 'foo is not a generator.'
-        self.assertEqual(expected, e.exception.args[0])
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_safe_context_manager_async(self) -
-
-
- -Expand source code - -
def test_safe_context_manager_async(self):
-    with self.assertRaises(expected_exception=AssertionError) as e:
-        @safe_contextmanager
-        async def foo(a, b):
-            yield a, b
-
-    expected = 'foo is async. So you need to use "safe_async_contextmanager" instead.'
-    self.assertEqual(expected, e.exception.args[0])
-
-
-
-
-def test_safe_context_manager_no_exception(self) -
-
-
- -Expand source code - -
def test_safe_context_manager_no_exception(self):
-    before = False
-    after = False
-
-    @safe_contextmanager
-    def foo():
-        nonlocal before, after
-        before = True
-        yield 42
-        after = True
-
-    self.assertFalse(before)
-    self.assertFalse(after)
-
-    with foo() as f:
-        self.assertTrue(before)
-        self.assertFalse(after)
-        self.assertEqual(42, f)
-
-    self.assertTrue(before)
-    self.assertTrue(after)
-
-
-
-
-def test_safe_context_manager_non_generator(self) -
-
-
- -Expand source code - -
def test_safe_context_manager_non_generator(self):
-    with self.assertRaises(expected_exception=AssertionError) as e:
-        @safe_contextmanager
-        def foo(a, b):
-            return a, b
-
-    expected = 'foo is not a generator.'
-    self.assertEqual(expected, e.exception.args[0])
-
-
-
-
-def test_safe_context_manager_with_args_kwargs(self) -
-
-
- -Expand source code - -
def test_safe_context_manager_with_args_kwargs(self):
-    @safe_contextmanager
-    def foo(a, b):
-        yield a, b
-
-    with foo(42, b=43) as f:
-        self.assertEqual((42, 43), f)
-
-
-
-
-def test_safe_context_manager_with_exception(self) -
-
-
- -Expand source code - -
def test_safe_context_manager_with_exception(self):
-    before = False
-    after = False
-
-    @safe_contextmanager
-    def foo():
-        nonlocal before, after
-        before = True
-        yield 42
-        after = True
-
-    self.assertFalse(before)
-    self.assertFalse(after)
-
-    with self.assertRaises(expected_exception=ValueError):
-        with foo() as f:
-            self.assertTrue(before)
-            self.assertFalse(after)
-            self.assertEqual(42, f)
-            raise ValueError('oh no')
-
-    self.assertTrue(before)
-    self.assertTrue(after)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/test_frozen_dataclass.html b/docs/pedantic/tests/test_frozen_dataclass.html deleted file mode 100644 index 3dc0e8e3..00000000 --- a/docs/pedantic/tests/test_frozen_dataclass.html +++ /dev/null @@ -1,1378 +0,0 @@ - - - - - - -pedantic.tests.test_frozen_dataclass API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.test_frozen_dataclass

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class A -(*,
foo: List[int],
bar: Dict[str, str],
values: Tuple[BB])
-
-
-
- -Expand source code - -
@frozen_type_safe_dataclass
-class A:
-    foo: List[int]
-    bar: Dict[str, str]
-    values: Tuple[B, B]
-
-

A(*, foo: List[int], bar: Dict[str, str], values: Tuple[pedantic.tests.test_frozen_dataclass.B, pedantic.tests.test_frozen_dataclass.B])

-

Instance variables

-
-
var bar : Dict[str, str]
-
-

The type of the None singleton.

-
-
var foo : List[int]
-
-

The type of the None singleton.

-
-
var values : Tuple[BB]
-
-

The type of the None singleton.

-
-
-

Methods

-
-
-def copy_with(self, **kwargs: Any) ‑> ~T -
-
-
- -Expand source code - -
def copy_with(self, **kwargs: Any) -> T:
-    """
-        Creates a new immutable instance that by copying all fields of this instance replaced by the new values.
-        Keep in mind that this is a shallow copy!
-    """
-
-    return replace(self, **kwargs)
-
-

Creates a new immutable instance that by copying all fields of this instance replaced by the new values. -Keep in mind that this is a shallow copy!

-
-
-def deep_copy_with(self, **kwargs: Any) ‑> ~T -
-
-
- -Expand source code - -
def deep_copy_with(self, **kwargs: Any) -> T:
-    """
-        Creates a new immutable instance that by deep copying all fields of
-        this instance replaced by the new values.
-    """
-
-    current_values = {field.name: deepcopy(getattr(self, field.name)) for field in fields(self)}
-    return new_class(**{**current_values, **kwargs})
-
-

Creates a new immutable instance that by deep copying all fields of -this instance replaced by the new values.

-
-
-def validate_types(self) ‑> None -
-
-
- -Expand source code - -
def validate_types(self, *, _context: Dict[str, Type] = None) -> None:
-    """
-        Checks that all instance variable have the correct type.
-        Raises a [PedanticTypeCheckException] if at least one type is incorrect.
-    """
-
-    props = fields(new_class)
-
-    if _context is None:
-        # method was called by user
-        _context = get_context(depth=2)
-
-    _context = {**_context, **self.__init__.__globals__, self.__class__.__name__: self.__class__}
-
-    for field in props:
-        assert_value_matches_type(
-            value=getattr(self, field.name),
-            type_=field.type,
-            err=f'In dataclass "{cls_.__name__}" in field "{field.name}": ',
-            type_vars={},
-            context=_context,
-        )
-
-

Checks that all instance variable have the correct type. -Raises a [PedanticTypeCheckException] if at least one type is incorrect.

-
-
-
-
-class B -(*, v: Set[int]) -
-
-
- -Expand source code - -
@frozen_type_safe_dataclass
-class B:
-    v: Set[int]
-
-

B(*, v: Set[int])

-

Instance variables

-
-
var v : Set[int]
-
-

The type of the None singleton.

-
-
-

Methods

-
-
-def copy_with(self, **kwargs: Any) ‑> ~T -
-
-
- -Expand source code - -
def copy_with(self, **kwargs: Any) -> T:
-    """
-        Creates a new immutable instance that by copying all fields of this instance replaced by the new values.
-        Keep in mind that this is a shallow copy!
-    """
-
-    return replace(self, **kwargs)
-
-

Creates a new immutable instance that by copying all fields of this instance replaced by the new values. -Keep in mind that this is a shallow copy!

-
-
-def deep_copy_with(self, **kwargs: Any) ‑> ~T -
-
-
- -Expand source code - -
def deep_copy_with(self, **kwargs: Any) -> T:
-    """
-        Creates a new immutable instance that by deep copying all fields of
-        this instance replaced by the new values.
-    """
-
-    current_values = {field.name: deepcopy(getattr(self, field.name)) for field in fields(self)}
-    return new_class(**{**current_values, **kwargs})
-
-

Creates a new immutable instance that by deep copying all fields of -this instance replaced by the new values.

-
-
-def validate_types(self) ‑> None -
-
-
- -Expand source code - -
def validate_types(self, *, _context: Dict[str, Type] = None) -> None:
-    """
-        Checks that all instance variable have the correct type.
-        Raises a [PedanticTypeCheckException] if at least one type is incorrect.
-    """
-
-    props = fields(new_class)
-
-    if _context is None:
-        # method was called by user
-        _context = get_context(depth=2)
-
-    _context = {**_context, **self.__init__.__globals__, self.__class__.__name__: self.__class__}
-
-    for field in props:
-        assert_value_matches_type(
-            value=getattr(self, field.name),
-            type_=field.type,
-            err=f'In dataclass "{cls_.__name__}" in field "{field.name}": ',
-            type_vars={},
-            context=_context,
-        )
-
-

Checks that all instance variable have the correct type. -Raises a [PedanticTypeCheckException] if at least one type is incorrect.

-
-
-
-
-class Foo -(*, a: int, b: str, c: bool) -
-
-
- -Expand source code - -
@frozen_dataclass
-class Foo:
-    a: int
-    b: str
-    c: bool
-
-

Foo(*, a: int, b: str, c: bool)

-

Instance variables

-
-
var a : int
-
-

The type of the None singleton.

-
-
var b : str
-
-

The type of the None singleton.

-
-
var c : bool
-
-

The type of the None singleton.

-
-
-

Methods

-
-
-def copy_with(self, **kwargs: Any) ‑> ~T -
-
-
- -Expand source code - -
def copy_with(self, **kwargs: Any) -> T:
-    """
-        Creates a new immutable instance that by copying all fields of this instance replaced by the new values.
-        Keep in mind that this is a shallow copy!
-    """
-
-    return replace(self, **kwargs)
-
-

Creates a new immutable instance that by copying all fields of this instance replaced by the new values. -Keep in mind that this is a shallow copy!

-
-
-def deep_copy_with(self, **kwargs: Any) ‑> ~T -
-
-
- -Expand source code - -
def deep_copy_with(self, **kwargs: Any) -> T:
-    """
-        Creates a new immutable instance that by deep copying all fields of
-        this instance replaced by the new values.
-    """
-
-    current_values = {field.name: deepcopy(getattr(self, field.name)) for field in fields(self)}
-    return new_class(**{**current_values, **kwargs})
-
-

Creates a new immutable instance that by deep copying all fields of -this instance replaced by the new values.

-
-
-def validate_types(self) ‑> None -
-
-
- -Expand source code - -
def validate_types(self, *, _context: Dict[str, Type] = None) -> None:
-    """
-        Checks that all instance variable have the correct type.
-        Raises a [PedanticTypeCheckException] if at least one type is incorrect.
-    """
-
-    props = fields(new_class)
-
-    if _context is None:
-        # method was called by user
-        _context = get_context(depth=2)
-
-    _context = {**_context, **self.__init__.__globals__, self.__class__.__name__: self.__class__}
-
-    for field in props:
-        assert_value_matches_type(
-            value=getattr(self, field.name),
-            type_=field.type,
-            err=f'In dataclass "{cls_.__name__}" in field "{field.name}": ',
-            type_vars={},
-            context=_context,
-        )
-
-

Checks that all instance variable have the correct type. -Raises a [PedanticTypeCheckException] if at least one type is incorrect.

-
-
-
-
-class TestFrozenDataclass -(methodName='runTest') -
-
-
- -Expand source code - -
class TestFrozenDataclass(unittest.TestCase):
-    def test_equals_and_hash(self):
-        a = Foo(a=6, b='hi', c=True)
-        b = Foo(a=6, b='hi', c=True)
-        c = Foo(a=7, b='hi', c=True)
-
-        self.assertEqual(a, b)
-        self.assertEqual(hash(a), hash(b))
-
-        self.assertNotEqual(a, c)
-        self.assertNotEqual(hash(a), hash(c))
-
-    def test_copy_with(self):
-        foo = Foo(a=6, b='hi', c=True)
-
-        copy_1 = foo.copy_with()
-        self.assertEqual(foo, copy_1)
-
-        copy_2 = foo.copy_with(a=42)
-        self.assertNotEqual(foo, copy_2)
-        self.assertEqual(42, copy_2.a)
-        self.assertEqual(foo.b, copy_2.b)
-        self.assertEqual(foo.c, copy_2.c)
-
-        copy_3 = foo.copy_with(b='Hello')
-        self.assertNotEqual(foo, copy_3)
-        self.assertEqual(foo.a, copy_3.a)
-        self.assertEqual('Hello', copy_3.b)
-        self.assertEqual(foo.c, copy_3.c)
-
-        copy_4 = foo.copy_with(c=False)
-        self.assertNotEqual(foo, copy_4)
-        self.assertEqual(foo.a, copy_4.a)
-        self.assertEqual(foo.b, copy_4.b)
-        self.assertEqual(False, copy_4.c)
-
-        copy_5 = foo.copy_with(a=676676, b='new', c=False)
-        self.assertNotEqual(foo, copy_5)
-        self.assertEqual(676676, copy_5.a)
-        self.assertEqual('new', copy_5.b)
-        self.assertEqual(False, copy_5.c)
-
-    def test_validate_types(self):
-        foo = Foo(a=6, b='hi', c=True)
-        foo.validate_types()
-
-        bar = Foo(a=6.6, b='hi', c=True)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException) as exc:
-            bar.validate_types()
-
-        expected = 'In dataclass "Foo" in field "a": Type hint is incorrect: Argument 6.6 of type <class \'float\'> ' \
-                   'does not match expected type <class \'int\'>.'
-        self.assertEqual(str(exc.exception), expected)
-
-    def test_frozen_dataclass_above_dataclass(self):
-        # This is the same behavior like
-        # >>> @dataclass(frozen=True)
-        # ... @dataclass
-        # ... class C:
-        # ...     foo: int
-
-        @frozen_dataclass
-        @dataclass
-        class A:
-            foo: int
-
-        with self.assertRaises(expected_exception=TypeError):
-            A()
-
-        with self.assertRaises(expected_exception=FrozenInstanceError):
-            A(foo=3)
-
-    def test_frozen_dataclass_below_dataclass(self):
-        @dataclass
-        @frozen_dataclass
-        class A:
-            foo: int
-
-        with self.assertRaises(expected_exception=TypeError):
-            A()
-
-        a = A(foo=3)
-
-        with self.assertRaises(expected_exception=FrozenInstanceError):
-            a.foo = 4
-
-        b = a.copy_with(foo=4)
-        self.assertEqual(4, b.foo)
-
-
-    def test_frozen_typesafe_dataclass_with_post_init(self):
-        b = 3
-
-        @frozen_dataclass(type_safe=True)
-        class A:
-            foo: int
-
-            def __post_init__(self) -> None:
-                nonlocal b
-                b = 33
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException) as exc:
-            A(foo=42.7)
-
-        self.assertEqual(
-            'In dataclass "A" in field "foo": Type hint is incorrect: Argument 42.7 of type'
-            ' <class \'float\'> does not match expected type <class \'int\'>.',
-            str(exc.exception)
-        )
-
-        # we check that the __post_init__ method is executed
-        self.assertEqual(33, b)
-
-    def test_frozen_typesafe_dataclass_without_post_init(self):
-        @frozen_dataclass(type_safe=True)
-        class A:
-            foo: int
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException) as exc:
-            A(foo=42.7)
-
-        self.assertEqual(
-            'In dataclass "A" in field "foo": Type hint is incorrect: Argument 42.7 of type'
-            ' <class \'float\'> does not match expected type <class \'int\'>.',
-            str(exc.exception)
-        )
-
-    def test_frozen_dataclass_with_empty_braces(self):
-        @frozen_dataclass()
-        class A:
-            foo: int
-
-        a = A(foo=42)
-        self.assertEqual(42, a.foo)
-
-    def test_frozen_dataclass_no_braces(self):
-        @frozen_dataclass
-        class A:
-            foo: int
-
-        a = A(foo=42)
-        self.assertEqual(42, a.foo)
-
-    def test_frozen_dataclass_order(self):
-        @frozen_dataclass(order=True)
-        class A:
-            foo: int
-            bar: int
-
-        a = A(foo=42, bar=43)
-        b = A(foo=42, bar=42)
-        c = A(foo=41, bar=44)
-        d = A(foo=44, bar=0)
-        self.assertLess(b, a)
-        self.assertLess(c, b)
-        self.assertLess(a, d)
-
-    def test_frozen_type_safe_dataclass_copy_with_check(self):
-        @frozen_type_safe_dataclass
-        class A:
-            foo: int
-            bar: bool
-
-        a = A(foo=42, bar=False)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            a.copy_with(foo=1.1)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            a.copy_with(bar=11)
-
-        a.copy_with(foo=11, bar=True)
-
-    def test_copy_with_is_shallow(self):
-        a = A(foo=[1, 2], bar={'hello': 'world'}, values=(B(v={4, 5}), B(v={6})))
-        shallow = a.copy_with()
-
-        # manipulation
-        shallow.bar['hello'] = 'pedantic'
-        shallow.foo.append(3)
-
-        self.assertEqual([1, 2, 3], a.foo)
-        self.assertEqual([1, 2, 3], shallow.foo)
-        self.assertEqual('pedantic', a.bar['hello'])
-        self.assertEqual('pedantic', shallow.bar['hello'])
-
-    def test_copy_with_and_deep_copy_with(self):
-        a = A(foo=[1, 2], bar={'hello': 'world'}, values=(B(v={4, 5}), B(v={6})))
-        deep = a.deep_copy_with()
-
-        # manipulation
-        deep.bar['hello'] = 'pedantic'
-        deep.foo.append(3)
-
-        self.assertEqual([1, 2], a.foo)
-        self.assertEqual([1, 2, 3], deep.foo)
-        self.assertEqual('world', a.bar['hello'])
-        self.assertEqual('pedantic', deep.bar['hello'])
-
-    def test_frozen_dataclass_inheritance_override_post_init(self):
-        i = 1
-
-        @frozen_type_safe_dataclass
-        class A:
-            bar: int
-
-            def __post_init__(self):
-                nonlocal i
-                i += 1
-                print('hello a')
-
-        @frozen_type_safe_dataclass
-        class B(A):
-            foo: int
-
-            def __post_init__(self):
-                nonlocal i
-                i *= 10
-                print('hello b')
-
-        A(bar=3)
-        self.assertEqual(2, i)
-
-        b = B(bar=3, foo=42)
-        self.assertEqual(20, i)  # post init of A was not called
-        self.assertEqual(3, b.bar)
-        self.assertEqual(42, b.foo)
-
-        a = b.copy_with()
-        self.assertEqual(b, a)
-        self.assertEqual(200, i)
-
-    def test_frozen_dataclass_inheritance_not_override_post_init(self):
-        i = 1
-
-        @frozen_type_safe_dataclass
-        class A:
-            bar: int
-
-            def __post_init__(self):
-                nonlocal i
-                i += 1
-                print('hello a')
-
-        @frozen_type_safe_dataclass
-        class B(A):
-            foo: int
-
-        A(bar=3)
-        self.assertEqual(2, i)
-
-        b = B(bar=3, foo=42)
-        self.assertEqual(3, i)  # post init of A was called
-        self.assertEqual(3, b.bar)
-        self.assertEqual(42, b.foo)
-
-        a = b.copy_with()
-        self.assertEqual(b, a)
-        self.assertEqual(4, i)
-
-    def test_type_safe_frozen_dataclass_with_awaitable(self):
-        @frozen_type_safe_dataclass
-        class A:
-            f: Callable[..., Awaitable[int]]
-
-        async def _cb() -> int:
-            return 42
-
-        async def _cb_2() -> str:
-            return '42'
-
-        A(f=_cb)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            A(f=_cb_2)
-
-    def test_type_safe_frozen_dataclass_with_forward_ref(self):
-        T = TypeVar('T')
-
-        class State(Generic[T], ABC):
-            pass
-
-        class StateMachine(Generic[T], ABC):
-            pass
-
-        @frozen_type_safe_dataclass
-        class StateChangeResult:
-            new_state: Optional['MachineState']
-
-        class MachineState(State['MachineStateMachine']):
-            pass
-
-        class OfflineMachineState(MachineState):
-            pass
-
-        class OnlineMachineState:
-            pass
-
-        class MachineStateMachine(StateMachine[MachineState]):
-            pass
-
-        s = StateChangeResult(new_state=OfflineMachineState())
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            StateChangeResult(new_state=OnlineMachineState())
-
-        s.validate_types()
-
-    def test_forward_ref_to_itself(self):
-        """ Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/72 """
-
-        @frozen_type_safe_dataclass
-        class Comment:
-            replies: List['Comment']
-
-        comment = Comment(replies=[Comment(replies=[])])
-        comment.copy_with(replies=[Comment(replies=[])])
-        comment.validate_types()
-
-    def test_forward_ref_to_itself_while_class_not_in_scope(self):
-        """ Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/72 """
-
-        def _scope():
-            @frozen_type_safe_dataclass
-            class Comment:
-                replies: List['Comment']
-
-            def _make(replies=None):
-                return Comment(replies=replies or [])
-
-            return _make
-
-        make = _scope()
-
-        comment = make(replies=[make(replies=[])])
-        comment.copy_with(replies=[make(replies=[])])
-        comment.validate_types()
-
-    def test_slots_work_with_equals(self):
-        @frozen_dataclass(slots=True)
-        class Foo:
-            a: int
-
-        o = Foo(a=0)
-        assert o == o.copy_with()
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_copy_with(self) -
-
-
- -Expand source code - -
def test_copy_with(self):
-    foo = Foo(a=6, b='hi', c=True)
-
-    copy_1 = foo.copy_with()
-    self.assertEqual(foo, copy_1)
-
-    copy_2 = foo.copy_with(a=42)
-    self.assertNotEqual(foo, copy_2)
-    self.assertEqual(42, copy_2.a)
-    self.assertEqual(foo.b, copy_2.b)
-    self.assertEqual(foo.c, copy_2.c)
-
-    copy_3 = foo.copy_with(b='Hello')
-    self.assertNotEqual(foo, copy_3)
-    self.assertEqual(foo.a, copy_3.a)
-    self.assertEqual('Hello', copy_3.b)
-    self.assertEqual(foo.c, copy_3.c)
-
-    copy_4 = foo.copy_with(c=False)
-    self.assertNotEqual(foo, copy_4)
-    self.assertEqual(foo.a, copy_4.a)
-    self.assertEqual(foo.b, copy_4.b)
-    self.assertEqual(False, copy_4.c)
-
-    copy_5 = foo.copy_with(a=676676, b='new', c=False)
-    self.assertNotEqual(foo, copy_5)
-    self.assertEqual(676676, copy_5.a)
-    self.assertEqual('new', copy_5.b)
-    self.assertEqual(False, copy_5.c)
-
-
-
-
-def test_copy_with_and_deep_copy_with(self) -
-
-
- -Expand source code - -
def test_copy_with_and_deep_copy_with(self):
-    a = A(foo=[1, 2], bar={'hello': 'world'}, values=(B(v={4, 5}), B(v={6})))
-    deep = a.deep_copy_with()
-
-    # manipulation
-    deep.bar['hello'] = 'pedantic'
-    deep.foo.append(3)
-
-    self.assertEqual([1, 2], a.foo)
-    self.assertEqual([1, 2, 3], deep.foo)
-    self.assertEqual('world', a.bar['hello'])
-    self.assertEqual('pedantic', deep.bar['hello'])
-
-
-
-
-def test_copy_with_is_shallow(self) -
-
-
- -Expand source code - -
def test_copy_with_is_shallow(self):
-    a = A(foo=[1, 2], bar={'hello': 'world'}, values=(B(v={4, 5}), B(v={6})))
-    shallow = a.copy_with()
-
-    # manipulation
-    shallow.bar['hello'] = 'pedantic'
-    shallow.foo.append(3)
-
-    self.assertEqual([1, 2, 3], a.foo)
-    self.assertEqual([1, 2, 3], shallow.foo)
-    self.assertEqual('pedantic', a.bar['hello'])
-    self.assertEqual('pedantic', shallow.bar['hello'])
-
-
-
-
-def test_equals_and_hash(self) -
-
-
- -Expand source code - -
def test_equals_and_hash(self):
-    a = Foo(a=6, b='hi', c=True)
-    b = Foo(a=6, b='hi', c=True)
-    c = Foo(a=7, b='hi', c=True)
-
-    self.assertEqual(a, b)
-    self.assertEqual(hash(a), hash(b))
-
-    self.assertNotEqual(a, c)
-    self.assertNotEqual(hash(a), hash(c))
-
-
-
-
-def test_forward_ref_to_itself(self) -
-
-
- -Expand source code - -
def test_forward_ref_to_itself(self):
-    """ Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/72 """
-
-    @frozen_type_safe_dataclass
-    class Comment:
-        replies: List['Comment']
-
-    comment = Comment(replies=[Comment(replies=[])])
-    comment.copy_with(replies=[Comment(replies=[])])
-    comment.validate_types()
-
- -
-
-def test_forward_ref_to_itself_while_class_not_in_scope(self) -
-
-
- -Expand source code - -
def test_forward_ref_to_itself_while_class_not_in_scope(self):
-    """ Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/72 """
-
-    def _scope():
-        @frozen_type_safe_dataclass
-        class Comment:
-            replies: List['Comment']
-
-        def _make(replies=None):
-            return Comment(replies=replies or [])
-
-        return _make
-
-    make = _scope()
-
-    comment = make(replies=[make(replies=[])])
-    comment.copy_with(replies=[make(replies=[])])
-    comment.validate_types()
-
- -
-
-def test_frozen_dataclass_above_dataclass(self) -
-
-
- -Expand source code - -
def test_frozen_dataclass_above_dataclass(self):
-    # This is the same behavior like
-    # >>> @dataclass(frozen=True)
-    # ... @dataclass
-    # ... class C:
-    # ...     foo: int
-
-    @frozen_dataclass
-    @dataclass
-    class A:
-        foo: int
-
-    with self.assertRaises(expected_exception=TypeError):
-        A()
-
-    with self.assertRaises(expected_exception=FrozenInstanceError):
-        A(foo=3)
-
-
-
-
-def test_frozen_dataclass_below_dataclass(self) -
-
-
- -Expand source code - -
def test_frozen_dataclass_below_dataclass(self):
-    @dataclass
-    @frozen_dataclass
-    class A:
-        foo: int
-
-    with self.assertRaises(expected_exception=TypeError):
-        A()
-
-    a = A(foo=3)
-
-    with self.assertRaises(expected_exception=FrozenInstanceError):
-        a.foo = 4
-
-    b = a.copy_with(foo=4)
-    self.assertEqual(4, b.foo)
-
-
-
-
-def test_frozen_dataclass_inheritance_not_override_post_init(self) -
-
-
- -Expand source code - -
def test_frozen_dataclass_inheritance_not_override_post_init(self):
-    i = 1
-
-    @frozen_type_safe_dataclass
-    class A:
-        bar: int
-
-        def __post_init__(self):
-            nonlocal i
-            i += 1
-            print('hello a')
-
-    @frozen_type_safe_dataclass
-    class B(A):
-        foo: int
-
-    A(bar=3)
-    self.assertEqual(2, i)
-
-    b = B(bar=3, foo=42)
-    self.assertEqual(3, i)  # post init of A was called
-    self.assertEqual(3, b.bar)
-    self.assertEqual(42, b.foo)
-
-    a = b.copy_with()
-    self.assertEqual(b, a)
-    self.assertEqual(4, i)
-
-
-
-
-def test_frozen_dataclass_inheritance_override_post_init(self) -
-
-
- -Expand source code - -
def test_frozen_dataclass_inheritance_override_post_init(self):
-    i = 1
-
-    @frozen_type_safe_dataclass
-    class A:
-        bar: int
-
-        def __post_init__(self):
-            nonlocal i
-            i += 1
-            print('hello a')
-
-    @frozen_type_safe_dataclass
-    class B(A):
-        foo: int
-
-        def __post_init__(self):
-            nonlocal i
-            i *= 10
-            print('hello b')
-
-    A(bar=3)
-    self.assertEqual(2, i)
-
-    b = B(bar=3, foo=42)
-    self.assertEqual(20, i)  # post init of A was not called
-    self.assertEqual(3, b.bar)
-    self.assertEqual(42, b.foo)
-
-    a = b.copy_with()
-    self.assertEqual(b, a)
-    self.assertEqual(200, i)
-
-
-
-
-def test_frozen_dataclass_no_braces(self) -
-
-
- -Expand source code - -
def test_frozen_dataclass_no_braces(self):
-    @frozen_dataclass
-    class A:
-        foo: int
-
-    a = A(foo=42)
-    self.assertEqual(42, a.foo)
-
-
-
-
-def test_frozen_dataclass_order(self) -
-
-
- -Expand source code - -
def test_frozen_dataclass_order(self):
-    @frozen_dataclass(order=True)
-    class A:
-        foo: int
-        bar: int
-
-    a = A(foo=42, bar=43)
-    b = A(foo=42, bar=42)
-    c = A(foo=41, bar=44)
-    d = A(foo=44, bar=0)
-    self.assertLess(b, a)
-    self.assertLess(c, b)
-    self.assertLess(a, d)
-
-
-
-
-def test_frozen_dataclass_with_empty_braces(self) -
-
-
- -Expand source code - -
def test_frozen_dataclass_with_empty_braces(self):
-    @frozen_dataclass()
-    class A:
-        foo: int
-
-    a = A(foo=42)
-    self.assertEqual(42, a.foo)
-
-
-
-
-def test_frozen_type_safe_dataclass_copy_with_check(self) -
-
-
- -Expand source code - -
def test_frozen_type_safe_dataclass_copy_with_check(self):
-    @frozen_type_safe_dataclass
-    class A:
-        foo: int
-        bar: bool
-
-    a = A(foo=42, bar=False)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        a.copy_with(foo=1.1)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        a.copy_with(bar=11)
-
-    a.copy_with(foo=11, bar=True)
-
-
-
-
-def test_frozen_typesafe_dataclass_with_post_init(self) -
-
-
- -Expand source code - -
def test_frozen_typesafe_dataclass_with_post_init(self):
-    b = 3
-
-    @frozen_dataclass(type_safe=True)
-    class A:
-        foo: int
-
-        def __post_init__(self) -> None:
-            nonlocal b
-            b = 33
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException) as exc:
-        A(foo=42.7)
-
-    self.assertEqual(
-        'In dataclass "A" in field "foo": Type hint is incorrect: Argument 42.7 of type'
-        ' <class \'float\'> does not match expected type <class \'int\'>.',
-        str(exc.exception)
-    )
-
-    # we check that the __post_init__ method is executed
-    self.assertEqual(33, b)
-
-
-
-
-def test_frozen_typesafe_dataclass_without_post_init(self) -
-
-
- -Expand source code - -
def test_frozen_typesafe_dataclass_without_post_init(self):
-    @frozen_dataclass(type_safe=True)
-    class A:
-        foo: int
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException) as exc:
-        A(foo=42.7)
-
-    self.assertEqual(
-        'In dataclass "A" in field "foo": Type hint is incorrect: Argument 42.7 of type'
-        ' <class \'float\'> does not match expected type <class \'int\'>.',
-        str(exc.exception)
-    )
-
-
-
-
-def test_slots_work_with_equals(self) -
-
-
- -Expand source code - -
def test_slots_work_with_equals(self):
-    @frozen_dataclass(slots=True)
-    class Foo:
-        a: int
-
-    o = Foo(a=0)
-    assert o == o.copy_with()
-
-
-
-
-def test_type_safe_frozen_dataclass_with_awaitable(self) -
-
-
- -Expand source code - -
def test_type_safe_frozen_dataclass_with_awaitable(self):
-    @frozen_type_safe_dataclass
-    class A:
-        f: Callable[..., Awaitable[int]]
-
-    async def _cb() -> int:
-        return 42
-
-    async def _cb_2() -> str:
-        return '42'
-
-    A(f=_cb)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        A(f=_cb_2)
-
-
-
-
-def test_type_safe_frozen_dataclass_with_forward_ref(self) -
-
-
- -Expand source code - -
def test_type_safe_frozen_dataclass_with_forward_ref(self):
-    T = TypeVar('T')
-
-    class State(Generic[T], ABC):
-        pass
-
-    class StateMachine(Generic[T], ABC):
-        pass
-
-    @frozen_type_safe_dataclass
-    class StateChangeResult:
-        new_state: Optional['MachineState']
-
-    class MachineState(State['MachineStateMachine']):
-        pass
-
-    class OfflineMachineState(MachineState):
-        pass
-
-    class OnlineMachineState:
-        pass
-
-    class MachineStateMachine(StateMachine[MachineState]):
-        pass
-
-    s = StateChangeResult(new_state=OfflineMachineState())
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        StateChangeResult(new_state=OnlineMachineState())
-
-    s.validate_types()
-
-
-
-
-def test_validate_types(self) -
-
-
- -Expand source code - -
def test_validate_types(self):
-    foo = Foo(a=6, b='hi', c=True)
-    foo.validate_types()
-
-    bar = Foo(a=6.6, b='hi', c=True)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException) as exc:
-        bar.validate_types()
-
-    expected = 'In dataclass "Foo" in field "a": Type hint is incorrect: Argument 6.6 of type <class \'float\'> ' \
-               'does not match expected type <class \'int\'>.'
-    self.assertEqual(str(exc.exception), expected)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/test_generator_wrapper.html b/docs/pedantic/tests/test_generator_wrapper.html deleted file mode 100644 index 634d7966..00000000 --- a/docs/pedantic/tests/test_generator_wrapper.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - -pedantic.tests.test_generator_wrapper API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.test_generator_wrapper

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestGeneratorWrapper -(methodName='runTest') -
-
-
- -Expand source code - -
class TestGeneratorWrapper(TestCase):
-    def test_generator_wrapper(self) -> None:
-        def gen_func() -> Iterator[int]:
-            num = 0
-
-            while num < 100:
-                yield num
-                num += 1
-
-        generator = gen_func()
-
-        g = GeneratorWrapper(
-            wrapped=generator,
-            expected_type=Iterator[int],
-            err_msg='msg',
-            type_vars={},
-        )
-
-        print(sum([x for x in g]))
-
-        with self.assertRaises(expected_exception=Exception):
-            g.throw(Exception('error'))
-
-        with self.assertRaises(expected_exception=AttributeError):
-            g.invalid
-
-        g.close()
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_generator_wrapper(self) ‑> None -
-
-
- -Expand source code - -
def test_generator_wrapper(self) -> None:
-    def gen_func() -> Iterator[int]:
-        num = 0
-
-        while num < 100:
-            yield num
-            num += 1
-
-    generator = gen_func()
-
-    g = GeneratorWrapper(
-        wrapped=generator,
-        expected_type=Iterator[int],
-        err_msg='msg',
-        type_vars={},
-    )
-
-    print(sum([x for x in g]))
-
-    with self.assertRaises(expected_exception=Exception):
-        g.throw(Exception('error'))
-
-    with self.assertRaises(expected_exception=AttributeError):
-        g.invalid
-
-    g.close()
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/test_generic_mixin.html b/docs/pedantic/tests/test_generic_mixin.html deleted file mode 100644 index f23d4211..00000000 --- a/docs/pedantic/tests/test_generic_mixin.html +++ /dev/null @@ -1,540 +0,0 @@ - - - - - - -pedantic.tests.test_generic_mixin API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.test_generic_mixin

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestGenericMixin -(methodName='runTest') -
-
-
- -Expand source code - -
class TestGenericMixin(unittest.TestCase):
-    def test_single_type_var(self):
-        class Foo(Generic[T], GenericMixin):
-            value: T
-
-        foo = Foo[str]()
-        assert foo.type_var == str
-        assert foo.type_vars == {T: str}
-
-        invalid = Foo()
-
-        with self.assertRaises(expected_exception=AssertionError) as err:
-            invalid.type_var
-
-        assert f'You need to instantiate this class with type parameters! Example: Foo[int]()' in err.exception.args[0]
-
-    def test_multiple_type_vars(self):
-        class Foo(Generic[T, U], GenericMixin):
-            value: T
-            values: List[U]
-
-        foo = Foo[str, int]()
-
-        with self.assertRaises(expected_exception=AssertionError) as err:
-           foo.type_var
-
-        self.assertEqual(err.exception.args[0], 'You have multiple type parameters. '
-                                                'Please use "type_vars" instead of "type_var".')
-
-        assert foo.type_vars == {T: str, U: int}
-
-        invalid = Foo()
-
-        with self.assertRaises(expected_exception=AssertionError) as err:
-            invalid.type_var
-
-        assert f'You need to instantiate this class with type parameters! Example: Foo[int]()' in err.exception.args[0]
-
-    def test_non_generic_class(self):
-        class Foo(GenericMixin):
-            value: int
-
-        invalid = Foo()
-
-        with self.assertRaises(expected_exception=AssertionError) as err:
-            invalid.type_var
-
-        self.assertEqual(err.exception.args[0], f'Foo is not a generic class. To make it generic, declare it like: '
-                                                f'class Foo(Generic[T], GenericMixin):...')
-
-    def test_call_type_var_in_constructor(self):
-        class Foo(Generic[T], GenericMixin):
-            def __init__(self) -> None:
-                self.x = self.type_var()
-
-        with self.assertRaises(expected_exception=AssertionError) as err:
-            Foo[str]()
-
-        assert 'make sure that you do not call this in the __init__() method' in err.exception.args[0]
-
-    def test_subclass_set_type_variable(self):
-        class Gen(Generic[T], GenericMixin):
-            def __init__(self, value: T) -> None:
-                self.value = value
-
-            def get_type(self) -> dict[TypeVar, Type]:
-                return self.type_vars
-
-        class MyClass(Gen[int]):
-            pass
-
-        bar = Gen[int](value=4)
-        assert bar.get_type() == {T: int}
-
-        foo = MyClass(value=4)
-        assert foo.get_type() == {T: int}
-
-    def test_subclass_with_multiple_parents(self):
-        class Gen(Generic[T], GenericMixin):
-            def __init__(self, value: T) -> None:
-                self.value = value
-
-            def get_type(self) -> dict[TypeVar, Type]:
-                return self.type_vars
-
-        class MyMixin:
-            value = 42
-
-        class MyClass(MyMixin, Gen[int]):
-            pass
-
-        bar = Gen[int](value=4)
-        assert bar.get_type() == {T: int}
-
-        foo = MyClass(value=4)
-        assert foo.get_type() == {T: int}
-
-    def test_resolved_type_var_inheritance(self):
-        class Foo(Generic[T]): ...
-
-        class Bar(Foo[int], Generic[U], GenericMixin): ...
-
-        bar = Bar[str]()
-        assert bar.type_vars == {T: int, U: str}
-
-    def test_resolved_type_var_inheritance_2(self):
-        class Foo(Generic[T], GenericMixin): ...
-
-        class Bar(Foo[int], Generic[U]): ...
-
-        bar = Bar[str]()
-        assert bar.type_vars == {T: int, U: str}
-
-    def test_very_complex_inheritance(self):
-        class Foo(Generic[E], GenericMixin): ...
-        class Bar(Foo[int], Generic[S]): ...
-        class Baz(Foo[int]): ...
-        class Deep(Baz): ...
-        class Deeper(Baz, Generic[T]): ...
-
-        foo = Foo[str]()
-        actual = foo.type_vars
-        assert actual == {E: str}
-
-        bar = Bar[str]()
-        actual = bar.type_vars
-        assert actual == {E: int, S: str}
-
-        baz = Baz()
-        actual = baz.type_vars
-        assert actual == {E: int}
-
-        deep = Deep()
-        actual = deep.type_vars
-        assert actual == {E: int}
-
-        deeper = Deeper[bool]()
-        actual = deeper.type_vars
-        assert actual == {E: int, T: bool}
-
-        with self.assertRaises(expected_exception=AssertionError) as err:
-            Foo().type_vars
-
-        assert 'You need to instantiate this class with type parameters! Example: Foo[int]()' in err.exception.args[0]
-
-    def test_substitution_lookup_hits(self):
-        class Base(Generic[A], GenericMixin): ...
-        class Mid(Base[A], Generic[A]): ...
-        class Final(Mid[int]): ...
-
-        obj = Final()
-        actual = obj.type_vars
-        assert actual == {A: int}
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_call_type_var_in_constructor(self) -
-
-
- -Expand source code - -
def test_call_type_var_in_constructor(self):
-    class Foo(Generic[T], GenericMixin):
-        def __init__(self) -> None:
-            self.x = self.type_var()
-
-    with self.assertRaises(expected_exception=AssertionError) as err:
-        Foo[str]()
-
-    assert 'make sure that you do not call this in the __init__() method' in err.exception.args[0]
-
-
-
-
-def test_multiple_type_vars(self) -
-
-
- -Expand source code - -
def test_multiple_type_vars(self):
-    class Foo(Generic[T, U], GenericMixin):
-        value: T
-        values: List[U]
-
-    foo = Foo[str, int]()
-
-    with self.assertRaises(expected_exception=AssertionError) as err:
-       foo.type_var
-
-    self.assertEqual(err.exception.args[0], 'You have multiple type parameters. '
-                                            'Please use "type_vars" instead of "type_var".')
-
-    assert foo.type_vars == {T: str, U: int}
-
-    invalid = Foo()
-
-    with self.assertRaises(expected_exception=AssertionError) as err:
-        invalid.type_var
-
-    assert f'You need to instantiate this class with type parameters! Example: Foo[int]()' in err.exception.args[0]
-
-
-
-
-def test_non_generic_class(self) -
-
-
- -Expand source code - -
def test_non_generic_class(self):
-    class Foo(GenericMixin):
-        value: int
-
-    invalid = Foo()
-
-    with self.assertRaises(expected_exception=AssertionError) as err:
-        invalid.type_var
-
-    self.assertEqual(err.exception.args[0], f'Foo is not a generic class. To make it generic, declare it like: '
-                                            f'class Foo(Generic[T], GenericMixin):...')
-
-
-
-
-def test_resolved_type_var_inheritance(self) -
-
-
- -Expand source code - -
def test_resolved_type_var_inheritance(self):
-    class Foo(Generic[T]): ...
-
-    class Bar(Foo[int], Generic[U], GenericMixin): ...
-
-    bar = Bar[str]()
-    assert bar.type_vars == {T: int, U: str}
-
-
-
-
-def test_resolved_type_var_inheritance_2(self) -
-
-
- -Expand source code - -
def test_resolved_type_var_inheritance_2(self):
-    class Foo(Generic[T], GenericMixin): ...
-
-    class Bar(Foo[int], Generic[U]): ...
-
-    bar = Bar[str]()
-    assert bar.type_vars == {T: int, U: str}
-
-
-
-
-def test_single_type_var(self) -
-
-
- -Expand source code - -
def test_single_type_var(self):
-    class Foo(Generic[T], GenericMixin):
-        value: T
-
-    foo = Foo[str]()
-    assert foo.type_var == str
-    assert foo.type_vars == {T: str}
-
-    invalid = Foo()
-
-    with self.assertRaises(expected_exception=AssertionError) as err:
-        invalid.type_var
-
-    assert f'You need to instantiate this class with type parameters! Example: Foo[int]()' in err.exception.args[0]
-
-
-
-
-def test_subclass_set_type_variable(self) -
-
-
- -Expand source code - -
def test_subclass_set_type_variable(self):
-    class Gen(Generic[T], GenericMixin):
-        def __init__(self, value: T) -> None:
-            self.value = value
-
-        def get_type(self) -> dict[TypeVar, Type]:
-            return self.type_vars
-
-    class MyClass(Gen[int]):
-        pass
-
-    bar = Gen[int](value=4)
-    assert bar.get_type() == {T: int}
-
-    foo = MyClass(value=4)
-    assert foo.get_type() == {T: int}
-
-
-
-
-def test_subclass_with_multiple_parents(self) -
-
-
- -Expand source code - -
def test_subclass_with_multiple_parents(self):
-    class Gen(Generic[T], GenericMixin):
-        def __init__(self, value: T) -> None:
-            self.value = value
-
-        def get_type(self) -> dict[TypeVar, Type]:
-            return self.type_vars
-
-    class MyMixin:
-        value = 42
-
-    class MyClass(MyMixin, Gen[int]):
-        pass
-
-    bar = Gen[int](value=4)
-    assert bar.get_type() == {T: int}
-
-    foo = MyClass(value=4)
-    assert foo.get_type() == {T: int}
-
-
-
-
-def test_substitution_lookup_hits(self) -
-
-
- -Expand source code - -
def test_substitution_lookup_hits(self):
-    class Base(Generic[A], GenericMixin): ...
-    class Mid(Base[A], Generic[A]): ...
-    class Final(Mid[int]): ...
-
-    obj = Final()
-    actual = obj.type_vars
-    assert actual == {A: int}
-
-
-
-
-def test_very_complex_inheritance(self) -
-
-
- -Expand source code - -
def test_very_complex_inheritance(self):
-    class Foo(Generic[E], GenericMixin): ...
-    class Bar(Foo[int], Generic[S]): ...
-    class Baz(Foo[int]): ...
-    class Deep(Baz): ...
-    class Deeper(Baz, Generic[T]): ...
-
-    foo = Foo[str]()
-    actual = foo.type_vars
-    assert actual == {E: str}
-
-    bar = Bar[str]()
-    actual = bar.type_vars
-    assert actual == {E: int, S: str}
-
-    baz = Baz()
-    actual = baz.type_vars
-    assert actual == {E: int}
-
-    deep = Deep()
-    actual = deep.type_vars
-    assert actual == {E: int}
-
-    deeper = Deeper[bool]()
-    actual = deeper.type_vars
-    assert actual == {E: int, T: bool}
-
-    with self.assertRaises(expected_exception=AssertionError) as err:
-        Foo().type_vars
-
-    assert 'You need to instantiate this class with type parameters! Example: Foo[int]()' in err.exception.args[0]
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/test_in_subprocess.html b/docs/pedantic/tests/test_in_subprocess.html deleted file mode 100644 index c2ae42fc..00000000 --- a/docs/pedantic/tests/test_in_subprocess.html +++ /dev/null @@ -1,539 +0,0 @@ - - - - - - -pedantic.tests.test_in_subprocess API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.test_in_subprocess

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestInSubprocess -(methodName='runTest') -
-
-
- -Expand source code - -
class TestInSubprocess(unittest.IsolatedAsyncioTestCase):
-    async def test_in_subprocess_simple(self):
-        @in_subprocess
-        def f() -> int:
-            return 42
-
-        assert await f() == 42
-
-    async def test_in_subprocess_custom_object(self):
-        class Foo:
-            def __init__(self, v) -> None:
-                self._value = v
-
-        @in_subprocess
-        def f() -> Foo:
-            return Foo(v=42)
-
-        assert (await f())._value == 42
-
-    async def test_in_subprocess_simple_async(self):
-        @in_subprocess
-        async def f() -> int:
-            return 42
-
-        assert await f() == 42
-
-    async def test_in_subprocess_no_args(self):
-        @in_subprocess
-        def f() -> int:
-            time.sleep(0.1)
-            return 42
-
-        async def t() -> None:
-            for _ in range(6):
-                await asyncio.sleep(0.01)
-                nonlocal counter
-                counter += 1
-
-        counter = 0
-        task = asyncio.create_task(t())
-        assert await f() == 42
-        assert counter >= 5
-        await task
-
-    async def test_in_subprocess_no_args_no_return(self):
-        @in_subprocess
-        def f() -> None:
-            time.sleep(0.1)
-
-        assert await f() is None
-
-    async def test_in_subprocess_exception(self):
-        @in_subprocess
-        def f() -> NoReturn:
-            raise RuntimeError('foo')
-
-        with self.assertRaises(expected_exception=RuntimeError):
-            await f()
-
-    async def test_not_in_subprocess_blocks(self):
-        async def f() -> int:
-            time.sleep(0.1)
-            return 42
-
-        async def t() -> None:
-            for _ in range(6):
-                await asyncio.sleep(0.05)
-                nonlocal counter
-                counter += 1
-
-        counter = 0
-        task = asyncio.create_task(t())
-        assert await f() == 42
-        assert counter == 0
-        await task
-
-    async def test_in_subprocess_with_arguments(self):
-        @in_subprocess
-        def f(a: int, b: int) -> int:
-            return a + b
-
-        assert await f(4, 5) == 9
-        assert await f(a=4, b=5) == 9
-
-    def test_inner_function_sync(self):
-        """ Needed for line coverage"""
-
-        rx, tx = Pipe(duplex=False)
-        _inner(tx, lambda x: 1 / x, x=42)
-        assert rx.recv() == 1 / 42
-
-        _inner(tx, lambda x: 1 / x, x=0)
-        ex = rx.recv()
-        assert isinstance(ex, SubprocessError)
-
-    def test_inner_function_async(self):
-        """ Needed for line coverage"""
-
-        async def foo(x):
-            return 1/x
-
-        rx, tx = Pipe(duplex=False)
-        _inner(tx, foo, x=42)
-        assert rx.recv() == 1 / 42
-
-        _inner(tx, foo, x=0)
-        ex = rx.recv()
-        assert isinstance(ex, SubprocessError)
-
-    async def test_in_subprocess_instance_method(self):
-        class Foo:
-            async def pos_args(self) -> int:
-                return await self.f(4, 5)
-
-            async def kw_args(self) -> int:
-                return await self.f(a=4, b=5)
-
-            @in_subprocess
-            def f(self, a: int, b: int) -> int:
-                return a + b
-
-        foo = Foo()
-        assert await foo.pos_args() == 9
-        assert await foo.kw_args() == 9
-
-    async def test_in_subprocess_static_method(self):
-        class Foo:
-            async def pos_args(self) -> int:
-                return await self.f(4, 5)
-
-            async def kw_args(self) -> int:
-                return await self.f(a=4, b=5)
-
-            @staticmethod
-            @in_subprocess
-            def f(a: int, b: int) -> int:
-                return a + b
-
-        foo = Foo()
-        assert await foo.pos_args() == 9
-        assert await foo.kw_args() == 9
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.async_case.IsolatedAsyncioTestCase
  • -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-async def test_in_subprocess_custom_object(self) -
-
-
- -Expand source code - -
async def test_in_subprocess_custom_object(self):
-    class Foo:
-        def __init__(self, v) -> None:
-            self._value = v
-
-    @in_subprocess
-    def f() -> Foo:
-        return Foo(v=42)
-
-    assert (await f())._value == 42
-
-
-
-
-async def test_in_subprocess_exception(self) -
-
-
- -Expand source code - -
async def test_in_subprocess_exception(self):
-    @in_subprocess
-    def f() -> NoReturn:
-        raise RuntimeError('foo')
-
-    with self.assertRaises(expected_exception=RuntimeError):
-        await f()
-
-
-
-
-async def test_in_subprocess_instance_method(self) -
-
-
- -Expand source code - -
async def test_in_subprocess_instance_method(self):
-    class Foo:
-        async def pos_args(self) -> int:
-            return await self.f(4, 5)
-
-        async def kw_args(self) -> int:
-            return await self.f(a=4, b=5)
-
-        @in_subprocess
-        def f(self, a: int, b: int) -> int:
-            return a + b
-
-    foo = Foo()
-    assert await foo.pos_args() == 9
-    assert await foo.kw_args() == 9
-
-
-
-
-async def test_in_subprocess_no_args(self) -
-
-
- -Expand source code - -
async def test_in_subprocess_no_args(self):
-    @in_subprocess
-    def f() -> int:
-        time.sleep(0.1)
-        return 42
-
-    async def t() -> None:
-        for _ in range(6):
-            await asyncio.sleep(0.01)
-            nonlocal counter
-            counter += 1
-
-    counter = 0
-    task = asyncio.create_task(t())
-    assert await f() == 42
-    assert counter >= 5
-    await task
-
-
-
-
-async def test_in_subprocess_no_args_no_return(self) -
-
-
- -Expand source code - -
async def test_in_subprocess_no_args_no_return(self):
-    @in_subprocess
-    def f() -> None:
-        time.sleep(0.1)
-
-    assert await f() is None
-
-
-
-
-async def test_in_subprocess_simple(self) -
-
-
- -Expand source code - -
async def test_in_subprocess_simple(self):
-    @in_subprocess
-    def f() -> int:
-        return 42
-
-    assert await f() == 42
-
-
-
-
-async def test_in_subprocess_simple_async(self) -
-
-
- -Expand source code - -
async def test_in_subprocess_simple_async(self):
-    @in_subprocess
-    async def f() -> int:
-        return 42
-
-    assert await f() == 42
-
-
-
-
-async def test_in_subprocess_static_method(self) -
-
-
- -Expand source code - -
async def test_in_subprocess_static_method(self):
-    class Foo:
-        async def pos_args(self) -> int:
-            return await self.f(4, 5)
-
-        async def kw_args(self) -> int:
-            return await self.f(a=4, b=5)
-
-        @staticmethod
-        @in_subprocess
-        def f(a: int, b: int) -> int:
-            return a + b
-
-    foo = Foo()
-    assert await foo.pos_args() == 9
-    assert await foo.kw_args() == 9
-
-
-
-
-async def test_in_subprocess_with_arguments(self) -
-
-
- -Expand source code - -
async def test_in_subprocess_with_arguments(self):
-    @in_subprocess
-    def f(a: int, b: int) -> int:
-        return a + b
-
-    assert await f(4, 5) == 9
-    assert await f(a=4, b=5) == 9
-
-
-
-
-def test_inner_function_async(self) -
-
-
- -Expand source code - -
def test_inner_function_async(self):
-    """ Needed for line coverage"""
-
-    async def foo(x):
-        return 1/x
-
-    rx, tx = Pipe(duplex=False)
-    _inner(tx, foo, x=42)
-    assert rx.recv() == 1 / 42
-
-    _inner(tx, foo, x=0)
-    ex = rx.recv()
-    assert isinstance(ex, SubprocessError)
-
-

Needed for line coverage

-
-
-def test_inner_function_sync(self) -
-
-
- -Expand source code - -
def test_inner_function_sync(self):
-    """ Needed for line coverage"""
-
-    rx, tx = Pipe(duplex=False)
-    _inner(tx, lambda x: 1 / x, x=42)
-    assert rx.recv() == 1 / 42
-
-    _inner(tx, lambda x: 1 / x, x=0)
-    ex = rx.recv()
-    assert isinstance(ex, SubprocessError)
-
-

Needed for line coverage

-
-
-async def test_not_in_subprocess_blocks(self) -
-
-
- -Expand source code - -
async def test_not_in_subprocess_blocks(self):
-    async def f() -> int:
-        time.sleep(0.1)
-        return 42
-
-    async def t() -> None:
-        for _ in range(6):
-            await asyncio.sleep(0.05)
-            nonlocal counter
-            counter += 1
-
-    counter = 0
-    task = asyncio.create_task(t())
-    assert await f() == 42
-    assert counter == 0
-    await task
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/test_rename_kwargs.html b/docs/pedantic/tests/test_rename_kwargs.html deleted file mode 100644 index 6915f80c..00000000 --- a/docs/pedantic/tests/test_rename_kwargs.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - -pedantic.tests.test_rename_kwargs API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.test_rename_kwargs

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestRenameKwargs -(methodName='runTest') -
-
-
- -Expand source code - -
class TestRenameKwargs(unittest.TestCase):
-    def test_rename_kwargs(self):
-        @rename_kwargs(
-            Rename(from_='x', to='a'),
-            Rename(from_='y', to='b'),
-        )
-        def operation(a: int, b: int) -> int:
-            return a + b
-
-        operation(4, 5)
-        operation(a=4, b=5)
-        operation(x=4, y=5)
-        operation(x=4, b=5)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_rename_kwargs(self) -
-
-
- -Expand source code - -
def test_rename_kwargs(self):
-    @rename_kwargs(
-        Rename(from_='x', to='a'),
-        Rename(from_='y', to='b'),
-    )
-    def operation(a: int, b: int) -> int:
-        return a + b
-
-    operation(4, 5)
-    operation(a=4, b=5)
-    operation(x=4, y=5)
-    operation(x=4, b=5)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/test_resolve_forward_ref.html b/docs/pedantic/tests/test_resolve_forward_ref.html deleted file mode 100644 index a6e34737..00000000 --- a/docs/pedantic/tests/test_resolve_forward_ref.html +++ /dev/null @@ -1,212 +0,0 @@ - - - - - - -pedantic.tests.test_resolve_forward_ref API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.test_resolve_forward_ref

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestResolveForwardRef -(methodName='runTest') -
-
-
- -Expand source code - -
class TestResolveForwardRef(TestCase):
-    def test_resolve_forward_ref_primitive_types(self):
-        assert resolve_forward_ref(type_='int') == int
-        assert resolve_forward_ref(type_='float') == float
-        assert resolve_forward_ref(type_='str') == str
-        assert resolve_forward_ref(type_='bool') == bool
-
-    def test_resolve_forward_ref_typing_types(self):
-        assert resolve_forward_ref(type_='List[int]') == List[int]
-        assert resolve_forward_ref(type_='Optional[List[Union[str, float]]]') == Optional[List[Union[str, float]]]
-
-    def test_unresolvable_type(self):
-        with self.assertRaises(NameError):
-            resolve_forward_ref(type_='Invalid')
-
-    def test_resolve_forward_ref_custom_class(self):
-        class Foo:
-            pass
-
-        context = locals()
-        assert resolve_forward_ref(type_='Foo', context=context) == Foo
-        assert resolve_forward_ref(type_='Optional[Foo]', context=context) == Optional[Foo]
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_resolve_forward_ref_custom_class(self) -
-
-
- -Expand source code - -
def test_resolve_forward_ref_custom_class(self):
-    class Foo:
-        pass
-
-    context = locals()
-    assert resolve_forward_ref(type_='Foo', context=context) == Foo
-    assert resolve_forward_ref(type_='Optional[Foo]', context=context) == Optional[Foo]
-
-
-
-
-def test_resolve_forward_ref_primitive_types(self) -
-
-
- -Expand source code - -
def test_resolve_forward_ref_primitive_types(self):
-    assert resolve_forward_ref(type_='int') == int
-    assert resolve_forward_ref(type_='float') == float
-    assert resolve_forward_ref(type_='str') == str
-    assert resolve_forward_ref(type_='bool') == bool
-
-
-
-
-def test_resolve_forward_ref_typing_types(self) -
-
-
- -Expand source code - -
def test_resolve_forward_ref_typing_types(self):
-    assert resolve_forward_ref(type_='List[int]') == List[int]
-    assert resolve_forward_ref(type_='Optional[List[Union[str, float]]]') == Optional[List[Union[str, float]]]
-
-
-
-
-def test_unresolvable_type(self) -
-
-
- -Expand source code - -
def test_unresolvable_type(self):
-    with self.assertRaises(NameError):
-        resolve_forward_ref(type_='Invalid')
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/test_retry.html b/docs/pedantic/tests/test_retry.html deleted file mode 100644 index db668a9d..00000000 --- a/docs/pedantic/tests/test_retry.html +++ /dev/null @@ -1,615 +0,0 @@ - - - - - - -pedantic.tests.test_retry API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.test_retry

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestRetry -(methodName='runTest') -
-
-
- -Expand source code - -
class TestRetry(unittest.TestCase):
-    def test_retry_positive_no_args(self):
-        count = 0
-
-        @retry(attempts=5)
-        def foo():
-            nonlocal count
-            count += 1
-
-        foo()
-        assert count == 1
-
-    def test_retry_positive_args_and_kwargs(self):
-        count = 0
-
-        @retry(attempts=5)
-        def foo(x, y):
-            nonlocal count
-            count += x + y
-
-        foo(12, y=42)
-        assert count == 54
-
-    def test_retry_positive_no_args_fails_every_time(self):
-        count = 0
-
-        @retry(attempts=5)
-        def foo():
-            nonlocal count
-            count += 1
-            raise ValueError('foo')
-
-        with self.assertRaises(ValueError):
-            foo()
-
-        assert count == 5
-
-    def test_retry_positive_no_args_fails_different_exception_type(self):
-        count = 0
-
-        @retry(attempts=5, exceptions=AssertionError)
-        def foo():
-            nonlocal count
-            count += 1
-            raise ValueError('foo')
-
-        with self.assertRaises(ValueError):
-            foo()
-
-        assert count == 1
-
-    def test_retry_fails_same_exception_type(self):
-        count = 0
-
-        @retry(attempts=5, exceptions=AssertionError)
-        def foo():
-            nonlocal count
-            count += 1
-            raise AssertionError('foo')
-
-        with self.assertRaises(AssertionError):
-            foo()
-
-        assert count == 5
-
-    def test_retry_positive_no_args_fails_on_first_times(self):
-        count = 0
-
-        @retry(attempts=5)
-        def foo() -> int:
-            nonlocal count
-            count += 1
-
-            if count < 3:
-                raise ValueError('foo')
-
-            return count
-
-        assert foo() == 3
-        assert count == 3
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_retry_fails_same_exception_type(self) -
-
-
- -Expand source code - -
def test_retry_fails_same_exception_type(self):
-    count = 0
-
-    @retry(attempts=5, exceptions=AssertionError)
-    def foo():
-        nonlocal count
-        count += 1
-        raise AssertionError('foo')
-
-    with self.assertRaises(AssertionError):
-        foo()
-
-    assert count == 5
-
-
-
-
-def test_retry_positive_args_and_kwargs(self) -
-
-
- -Expand source code - -
def test_retry_positive_args_and_kwargs(self):
-    count = 0
-
-    @retry(attempts=5)
-    def foo(x, y):
-        nonlocal count
-        count += x + y
-
-    foo(12, y=42)
-    assert count == 54
-
-
-
-
-def test_retry_positive_no_args(self) -
-
-
- -Expand source code - -
def test_retry_positive_no_args(self):
-    count = 0
-
-    @retry(attempts=5)
-    def foo():
-        nonlocal count
-        count += 1
-
-    foo()
-    assert count == 1
-
-
-
-
-def test_retry_positive_no_args_fails_different_exception_type(self) -
-
-
- -Expand source code - -
def test_retry_positive_no_args_fails_different_exception_type(self):
-    count = 0
-
-    @retry(attempts=5, exceptions=AssertionError)
-    def foo():
-        nonlocal count
-        count += 1
-        raise ValueError('foo')
-
-    with self.assertRaises(ValueError):
-        foo()
-
-    assert count == 1
-
-
-
-
-def test_retry_positive_no_args_fails_every_time(self) -
-
-
- -Expand source code - -
def test_retry_positive_no_args_fails_every_time(self):
-    count = 0
-
-    @retry(attempts=5)
-    def foo():
-        nonlocal count
-        count += 1
-        raise ValueError('foo')
-
-    with self.assertRaises(ValueError):
-        foo()
-
-    assert count == 5
-
-
-
-
-def test_retry_positive_no_args_fails_on_first_times(self) -
-
-
- -Expand source code - -
def test_retry_positive_no_args_fails_on_first_times(self):
-    count = 0
-
-    @retry(attempts=5)
-    def foo() -> int:
-        nonlocal count
-        count += 1
-
-        if count < 3:
-            raise ValueError('foo')
-
-        return count
-
-    assert foo() == 3
-    assert count == 3
-
-
-
-
-
-
-class TestRetryFunc -(methodName='runTest') -
-
-
- -Expand source code - -
class TestRetryFunc(unittest.TestCase):
-    def test_retry_positive_no_args(self):
-        count = 0
-
-        def foo():
-            nonlocal count
-            count += 1
-
-        retry_func(func=foo, attempts=5)
-        assert count == 1
-
-    def test_retry_positive_args_and_kwargs(self):
-        count = 0
-
-        def foo(x, y):
-            nonlocal count
-            count += x + y
-
-        retry_func(foo, 12, attempts=5, y=42)
-        assert count == 54
-
-    def test_retry_positive_no_args_fails_every_time(self):
-        count = 0
-
-        def foo():
-            nonlocal count
-            count += 1
-            raise ValueError('foo')
-
-        with self.assertRaises(ValueError):
-            retry_func(func=foo, attempts=5)
-
-        assert count == 5
-
-    def test_retry_positive_no_args_fails_different_exception_type(self):
-        count = 0
-
-        def foo():
-            nonlocal count
-            count += 1
-            raise ValueError('foo')
-
-        with self.assertRaises(ValueError):
-            retry_func(func=foo, attempts=5, exceptions=AssertionError)
-
-        assert count == 1
-
-    def test_retry_fails_same_exception_type(self):
-        count = 0
-
-        def foo():
-            nonlocal count
-            count += 1
-            raise AssertionError('foo')
-
-        with self.assertRaises(AssertionError):
-            retry_func(func=foo, attempts=5, exceptions=AssertionError)
-
-        assert count == 5
-
-    def test_retry_positive_no_args_fails_on_first_times(self):
-        count = 0
-
-        def foo() -> int:
-            nonlocal count
-            count += 1
-
-            if count < 3:
-                raise ValueError('foo')
-
-            return count
-
-        assert retry_func(func=foo, attempts=5) == 3
-        assert count == 3
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_retry_fails_same_exception_type(self) -
-
-
- -Expand source code - -
def test_retry_fails_same_exception_type(self):
-    count = 0
-
-    def foo():
-        nonlocal count
-        count += 1
-        raise AssertionError('foo')
-
-    with self.assertRaises(AssertionError):
-        retry_func(func=foo, attempts=5, exceptions=AssertionError)
-
-    assert count == 5
-
-
-
-
-def test_retry_positive_args_and_kwargs(self) -
-
-
- -Expand source code - -
def test_retry_positive_args_and_kwargs(self):
-    count = 0
-
-    def foo(x, y):
-        nonlocal count
-        count += x + y
-
-    retry_func(foo, 12, attempts=5, y=42)
-    assert count == 54
-
-
-
-
-def test_retry_positive_no_args(self) -
-
-
- -Expand source code - -
def test_retry_positive_no_args(self):
-    count = 0
-
-    def foo():
-        nonlocal count
-        count += 1
-
-    retry_func(func=foo, attempts=5)
-    assert count == 1
-
-
-
-
-def test_retry_positive_no_args_fails_different_exception_type(self) -
-
-
- -Expand source code - -
def test_retry_positive_no_args_fails_different_exception_type(self):
-    count = 0
-
-    def foo():
-        nonlocal count
-        count += 1
-        raise ValueError('foo')
-
-    with self.assertRaises(ValueError):
-        retry_func(func=foo, attempts=5, exceptions=AssertionError)
-
-    assert count == 1
-
-
-
-
-def test_retry_positive_no_args_fails_every_time(self) -
-
-
- -Expand source code - -
def test_retry_positive_no_args_fails_every_time(self):
-    count = 0
-
-    def foo():
-        nonlocal count
-        count += 1
-        raise ValueError('foo')
-
-    with self.assertRaises(ValueError):
-        retry_func(func=foo, attempts=5)
-
-    assert count == 5
-
-
-
-
-def test_retry_positive_no_args_fails_on_first_times(self) -
-
-
- -Expand source code - -
def test_retry_positive_no_args_fails_on_first_times(self):
-    count = 0
-
-    def foo() -> int:
-        nonlocal count
-        count += 1
-
-        if count < 3:
-            raise ValueError('foo')
-
-        return count
-
-    assert retry_func(func=foo, attempts=5) == 3
-    assert count == 3
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/test_with_decorated_methods.html b/docs/pedantic/tests/test_with_decorated_methods.html deleted file mode 100644 index a92c7a57..00000000 --- a/docs/pedantic/tests/test_with_decorated_methods.html +++ /dev/null @@ -1,452 +0,0 @@ - - - - - - -pedantic.tests.test_with_decorated_methods API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.test_with_decorated_methods

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class Decorators -(*args, **kwds) -
-
-
- -Expand source code - -
class Decorators(DecoratorType):
-    FOO = '_foo'
-    BAR = '_bar'
-
-

The interface that defines all possible decorators types.

-

The values of this enum are used as property names and the properties are added to the decorated functions. -So I would recommend naming them with a leading underscore to keep them private and also write it lowercase.

-

Example

-
>>> class Decorators(DecoratorType):
-...     FOO = '_foo'
-
-

Ancestors

-
    -
  • DecoratorType
  • -
  • enum.StrEnum
  • -
  • builtins.str
  • -
  • enum.ReprEnum
  • -
  • enum.Enum
  • -
-

Class variables

-
-
var BAR
-
-

The type of the None singleton.

-
-
var FOO
-
-

The type of the None singleton.

-
-
-
-
-class TestWithDecoratedMethods -(methodName='runTest') -
-
-
- -Expand source code - -
class TestWithDecoratedMethods(unittest.TestCase):
-    def test_no_decorated_methods(self):
-        class MyClass(WithDecoratedMethods[Decorators]):
-            pass
-
-        instance = MyClass()
-        assert instance.get_decorated_functions() == {Decorators.FOO: {}, Decorators.BAR: {}}
-
-    def test_class_with_bad_property(self):
-        class MyClass(WithDecoratedMethods[Decorators]):
-            @property
-            def bad(self) -> NoReturn:
-                raise RuntimeError('bad man')
-
-        instance = MyClass()
-        assert instance.get_decorated_functions() == {Decorators.FOO: {}, Decorators.BAR: {}}
-
-    def test_with_decorated_methods_sync(self):
-        class MyClass(WithDecoratedMethods[Decorators]):
-            @foo(42)
-            def m1(self) -> None:
-                print('bar')
-
-            @foo(value=43)
-            def m2(self) -> None:
-                print('bar')
-
-            @bar(value=44)
-            def m3(self) -> None:
-                print('bar')
-
-        instance = MyClass()
-        expected = {
-            Decorators.FOO: {
-                instance.m1: 42,
-                instance.m2: 43,
-            },
-            Decorators.BAR: {
-                instance.m3: 44,
-            }
-        }
-        assert instance.get_decorated_functions() == expected
-
-    def test_with_decorated_methods_async(self):
-        class MyClass(WithDecoratedMethods[Decorators]):
-            @foo(42)
-            async def m1(self) -> None:
-                print('bar')
-
-            @foo(value=43)
-            async def m2(self) -> None:
-                print('bar')
-
-            @bar(value=44)
-            async def m3(self) -> None:
-                print('bar')
-
-        instance = MyClass()
-        expected = {
-            Decorators.FOO: {
-                instance.m1: 42,
-                instance.m2: 43,
-            },
-            Decorators.BAR: {
-                instance.m3: 44,
-            }
-        }
-        assert instance.get_decorated_functions() == expected
-
-
-    def test_with_custom_transformation(self):
-        def my_transformation(f, decorator_type, value):
-            assert decorator_type == Decorators.BAR
-            assert value == 42
-
-            @wraps(f)
-            def wrapper(*args, **kwargs):
-                f(*args, **kwargs)
-                return 4422  # we add a return value
-
-            return wrapper
-
-        my_decorator = create_decorator(decorator_type=Decorators.BAR, transformation=my_transformation)
-
-        class MyClass(WithDecoratedMethods[Decorators]):
-            @my_decorator(42)
-            def m1(self) -> int:
-                return 1
-
-        instance = MyClass()
-        expected = {
-            Decorators.BAR: {
-                instance.m1: 42,
-            },
-            Decorators.FOO: {},
-        }
-        assert instance.get_decorated_functions() == expected
-
-        assert instance.m1() == 4422  # check that transformation was applied
-
-    def test_with_decorated_methods_can_have_generic_child_class(self):
-        class MyClass(Generic[T], WithDecoratedMethods[Decorators]):
-            @foo(42)
-            def m1(self) -> None: ...
-
-        instance = MyClass[int]()
-        actual = instance.get_decorated_functions()
-        assert actual == {Decorators.FOO: {instance.m1: 42}, Decorators.BAR: {}}
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_class_with_bad_property(self) -
-
-
- -Expand source code - -
def test_class_with_bad_property(self):
-    class MyClass(WithDecoratedMethods[Decorators]):
-        @property
-        def bad(self) -> NoReturn:
-            raise RuntimeError('bad man')
-
-    instance = MyClass()
-    assert instance.get_decorated_functions() == {Decorators.FOO: {}, Decorators.BAR: {}}
-
-
-
-
-def test_no_decorated_methods(self) -
-
-
- -Expand source code - -
def test_no_decorated_methods(self):
-    class MyClass(WithDecoratedMethods[Decorators]):
-        pass
-
-    instance = MyClass()
-    assert instance.get_decorated_functions() == {Decorators.FOO: {}, Decorators.BAR: {}}
-
-
-
-
-def test_with_custom_transformation(self) -
-
-
- -Expand source code - -
def test_with_custom_transformation(self):
-    def my_transformation(f, decorator_type, value):
-        assert decorator_type == Decorators.BAR
-        assert value == 42
-
-        @wraps(f)
-        def wrapper(*args, **kwargs):
-            f(*args, **kwargs)
-            return 4422  # we add a return value
-
-        return wrapper
-
-    my_decorator = create_decorator(decorator_type=Decorators.BAR, transformation=my_transformation)
-
-    class MyClass(WithDecoratedMethods[Decorators]):
-        @my_decorator(42)
-        def m1(self) -> int:
-            return 1
-
-    instance = MyClass()
-    expected = {
-        Decorators.BAR: {
-            instance.m1: 42,
-        },
-        Decorators.FOO: {},
-    }
-    assert instance.get_decorated_functions() == expected
-
-    assert instance.m1() == 4422  # check that transformation was applied
-
-
-
-
-def test_with_decorated_methods_async(self) -
-
-
- -Expand source code - -
def test_with_decorated_methods_async(self):
-    class MyClass(WithDecoratedMethods[Decorators]):
-        @foo(42)
-        async def m1(self) -> None:
-            print('bar')
-
-        @foo(value=43)
-        async def m2(self) -> None:
-            print('bar')
-
-        @bar(value=44)
-        async def m3(self) -> None:
-            print('bar')
-
-    instance = MyClass()
-    expected = {
-        Decorators.FOO: {
-            instance.m1: 42,
-            instance.m2: 43,
-        },
-        Decorators.BAR: {
-            instance.m3: 44,
-        }
-    }
-    assert instance.get_decorated_functions() == expected
-
-
-
-
-def test_with_decorated_methods_can_have_generic_child_class(self) -
-
-
- -Expand source code - -
def test_with_decorated_methods_can_have_generic_child_class(self):
-    class MyClass(Generic[T], WithDecoratedMethods[Decorators]):
-        @foo(42)
-        def m1(self) -> None: ...
-
-    instance = MyClass[int]()
-    actual = instance.get_decorated_functions()
-    assert actual == {Decorators.FOO: {instance.m1: 42}, Decorators.BAR: {}}
-
-
-
-
-def test_with_decorated_methods_sync(self) -
-
-
- -Expand source code - -
def test_with_decorated_methods_sync(self):
-    class MyClass(WithDecoratedMethods[Decorators]):
-        @foo(42)
-        def m1(self) -> None:
-            print('bar')
-
-        @foo(value=43)
-        def m2(self) -> None:
-            print('bar')
-
-        @bar(value=44)
-        def m3(self) -> None:
-            print('bar')
-
-    instance = MyClass()
-    expected = {
-        Decorators.FOO: {
-            instance.m1: 42,
-            instance.m2: 43,
-        },
-        Decorators.BAR: {
-            instance.m3: 44,
-        }
-    }
-    assert instance.get_decorated_functions() == expected
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_class_decorators.html b/docs/pedantic/tests/tests_class_decorators.html deleted file mode 100644 index ed678fd4..00000000 --- a/docs/pedantic/tests/tests_class_decorators.html +++ /dev/null @@ -1,211 +0,0 @@ - - - - - - -pedantic.tests.tests_class_decorators API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_class_decorators

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestClassDecorators -(methodName='runTest') -
-
-
- -Expand source code - -
class TestClassDecorators(unittest.TestCase):
-
-    def test_trace_class(self):
-        @trace_class
-        class MyClass:
-            def __init__(self, s: str) -> None:
-                self.s = s
-
-            def double(self, b: int) -> str:
-                return self.s + str(b)
-
-            @staticmethod
-            def generator() -> 'MyClass':
-                return MyClass(s='generated')
-
-        m = MyClass.generator()
-        m.double(b=42)
-
-    def test_timer_class(self):
-        @timer_class
-        class MyClass:
-            def __init__(self, s: str) -> None:
-                self.s = s
-
-            def double(self, b: int) -> str:
-                return self.s + str(b)
-
-            @staticmethod
-            def generator() -> 'MyClass':
-                return MyClass(s='generated')
-
-        m = MyClass.generator()
-        m.double(b=42)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_timer_class(self) -
-
-
- -Expand source code - -
def test_timer_class(self):
-    @timer_class
-    class MyClass:
-        def __init__(self, s: str) -> None:
-            self.s = s
-
-        def double(self, b: int) -> str:
-            return self.s + str(b)
-
-        @staticmethod
-        def generator() -> 'MyClass':
-            return MyClass(s='generated')
-
-    m = MyClass.generator()
-    m.double(b=42)
-
-
-
-
-def test_trace_class(self) -
-
-
- -Expand source code - -
def test_trace_class(self):
-    @trace_class
-    class MyClass:
-        def __init__(self, s: str) -> None:
-            self.s = s
-
-        def double(self, b: int) -> str:
-            return self.s + str(b)
-
-        @staticmethod
-        def generator() -> 'MyClass':
-            return MyClass(s='generated')
-
-    m = MyClass.generator()
-    m.double(b=42)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_combination_of_decorators.html b/docs/pedantic/tests/tests_combination_of_decorators.html deleted file mode 100644 index cd9fd39f..00000000 --- a/docs/pedantic/tests/tests_combination_of_decorators.html +++ /dev/null @@ -1,531 +0,0 @@ - - - - - - -pedantic.tests.tests_combination_of_decorators API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_combination_of_decorators

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestCombinationOfDecorators -(methodName='runTest') -
-
-
- -Expand source code - -
class TestCombinationOfDecorators(unittest.TestCase):
-    def test_pedantic_overrides(self):
-        class MyClass(ABC):
-            @pedantic
-            @abstractmethod
-            def op(self, a: int) -> None:
-                pass
-
-        class Child(MyClass):
-            a = 0
-
-            @pedantic
-            @overrides(MyClass)
-            def op(self, a: int) -> None:
-                self.a = a
-
-        c = Child()
-        c.op(a=42)
-
-    def test_pedantic_below_validate(self):
-        @validate(
-            Parameter(name='x', validators=[Min(0)]),
-            return_as=ReturnAs.KWARGS_WITH_NONE,
-        )
-        @pedantic
-        def some_calculation(x: int) -> int:
-            return x
-
-        some_calculation(x=42)
-        some_calculation(42)
-
-        with self.assertRaises(expected_exception=ParameterException):
-            some_calculation(x=-1)
-        with self.assertRaises(expected_exception=ParameterException):
-            some_calculation(x=-42)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            some_calculation(x=1.0)
-
-    def test_pedantic_above_validate(self):
-        @pedantic
-        @validate(
-            Parameter(name='x', validators=[Min(0)]),
-        )
-        def some_calculation(x: int) -> int:
-            return x
-
-        some_calculation(x=42)
-
-        with self.assertRaises(expected_exception=ParameterException):
-            some_calculation(x=-1)
-        with self.assertRaises(expected_exception=ParameterException):
-            some_calculation(x=-42)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            some_calculation(x=1.0)
-        with self.assertRaises(expected_exception=PedanticException):
-            some_calculation(42)
-
-    def test_pedantic_above_validate_on_instance_method(self):
-        class MyClass:
-            @pedantic
-            @validate(
-                Parameter(name='x', validators=[Min(0)]),
-            )
-            def some_calculation(self, x: int) -> int:
-                return x
-
-        m = MyClass()
-        m.some_calculation(x=42)
-        with self.assertRaises(expected_exception=ParameterException):
-            m.some_calculation(x=-1)
-        with self.assertRaises(expected_exception=ParameterException):
-            m.some_calculation(x=-42)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.some_calculation(x=1.0)
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            m.some_calculation(42)
-
-    def test_pedantic_below_validate_on_instance_method(self):
-        class MyClass:
-            @validate(
-                Parameter(name='x', validators=[Min(0)]),
-            )
-            @pedantic
-            def some_calculation(self, x: int) -> int:
-                return x
-
-        m = MyClass()
-        m.some_calculation(x=42)
-        m.some_calculation(42)
-
-        with self.assertRaises(expected_exception=ParameterException):
-            m.some_calculation(x=-1)
-        with self.assertRaises(expected_exception=ParameterException):
-            m.some_calculation(x=-42)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.some_calculation(x=1.0)
-
-    def test_pedantic_class_with_validate_instance_method(self):
-        @pedantic_class
-        class MyClass:
-            @validate(
-                Parameter(name='x', validators=[Min(0)]),
-            )
-            def some_calculation(self, x: int) -> int:
-                return x
-
-        m = MyClass()
-        m.some_calculation(x=42)
-        with self.assertRaises(expected_exception=ParameterException):
-            m.some_calculation(x=-1)
-        with self.assertRaises(expected_exception=ParameterException):
-            m.some_calculation(x=-42)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.some_calculation(x=1.0)
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            m.some_calculation(42)
-
-    def test_pedantic_class_static_method_1(self):
-        @pedantic_class
-        class MyClass:
-            @staticmethod
-            def some_calculation(x: int) -> int:
-                return x
-
-        m = MyClass()
-        m.some_calculation(x=42)
-        MyClass.some_calculation(x=45)
-
-    def test_pedantic_class_static_method_2(self):
-        """Never do this, but it works"""
-        @for_all_methods(staticmethod)
-        @pedantic_class
-        class MyClass:
-            def some_calculation(x: int) -> int:
-                return x
-
-        m = MyClass()
-        m.some_calculation(x=42)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.some_calculation(x=42.0)
-        MyClass.some_calculation(x=45)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            MyClass.some_calculation(x=45.0)
-
-    def test_pedantic_static_method_1(self):
-        class MyClass:
-            @staticmethod
-            @pedantic
-            def some_calculation(x: int) -> int:
-                return x
-
-        m = MyClass()
-        m.some_calculation(x=42)
-        MyClass.some_calculation(x=45)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_pedantic_above_validate(self) -
-
-
- -Expand source code - -
def test_pedantic_above_validate(self):
-    @pedantic
-    @validate(
-        Parameter(name='x', validators=[Min(0)]),
-    )
-    def some_calculation(x: int) -> int:
-        return x
-
-    some_calculation(x=42)
-
-    with self.assertRaises(expected_exception=ParameterException):
-        some_calculation(x=-1)
-    with self.assertRaises(expected_exception=ParameterException):
-        some_calculation(x=-42)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        some_calculation(x=1.0)
-    with self.assertRaises(expected_exception=PedanticException):
-        some_calculation(42)
-
-
-
-
-def test_pedantic_above_validate_on_instance_method(self) -
-
-
- -Expand source code - -
def test_pedantic_above_validate_on_instance_method(self):
-    class MyClass:
-        @pedantic
-        @validate(
-            Parameter(name='x', validators=[Min(0)]),
-        )
-        def some_calculation(self, x: int) -> int:
-            return x
-
-    m = MyClass()
-    m.some_calculation(x=42)
-    with self.assertRaises(expected_exception=ParameterException):
-        m.some_calculation(x=-1)
-    with self.assertRaises(expected_exception=ParameterException):
-        m.some_calculation(x=-42)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.some_calculation(x=1.0)
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        m.some_calculation(42)
-
-
-
-
-def test_pedantic_below_validate(self) -
-
-
- -Expand source code - -
def test_pedantic_below_validate(self):
-    @validate(
-        Parameter(name='x', validators=[Min(0)]),
-        return_as=ReturnAs.KWARGS_WITH_NONE,
-    )
-    @pedantic
-    def some_calculation(x: int) -> int:
-        return x
-
-    some_calculation(x=42)
-    some_calculation(42)
-
-    with self.assertRaises(expected_exception=ParameterException):
-        some_calculation(x=-1)
-    with self.assertRaises(expected_exception=ParameterException):
-        some_calculation(x=-42)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        some_calculation(x=1.0)
-
-
-
-
-def test_pedantic_below_validate_on_instance_method(self) -
-
-
- -Expand source code - -
def test_pedantic_below_validate_on_instance_method(self):
-    class MyClass:
-        @validate(
-            Parameter(name='x', validators=[Min(0)]),
-        )
-        @pedantic
-        def some_calculation(self, x: int) -> int:
-            return x
-
-    m = MyClass()
-    m.some_calculation(x=42)
-    m.some_calculation(42)
-
-    with self.assertRaises(expected_exception=ParameterException):
-        m.some_calculation(x=-1)
-    with self.assertRaises(expected_exception=ParameterException):
-        m.some_calculation(x=-42)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.some_calculation(x=1.0)
-
-
-
-
-def test_pedantic_class_static_method_1(self) -
-
-
- -Expand source code - -
def test_pedantic_class_static_method_1(self):
-    @pedantic_class
-    class MyClass:
-        @staticmethod
-        def some_calculation(x: int) -> int:
-            return x
-
-    m = MyClass()
-    m.some_calculation(x=42)
-    MyClass.some_calculation(x=45)
-
-
-
-
-def test_pedantic_class_static_method_2(self) -
-
-
- -Expand source code - -
def test_pedantic_class_static_method_2(self):
-    """Never do this, but it works"""
-    @for_all_methods(staticmethod)
-    @pedantic_class
-    class MyClass:
-        def some_calculation(x: int) -> int:
-            return x
-
-    m = MyClass()
-    m.some_calculation(x=42)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.some_calculation(x=42.0)
-    MyClass.some_calculation(x=45)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        MyClass.some_calculation(x=45.0)
-
-

Never do this, but it works

-
-
-def test_pedantic_class_with_validate_instance_method(self) -
-
-
- -Expand source code - -
def test_pedantic_class_with_validate_instance_method(self):
-    @pedantic_class
-    class MyClass:
-        @validate(
-            Parameter(name='x', validators=[Min(0)]),
-        )
-        def some_calculation(self, x: int) -> int:
-            return x
-
-    m = MyClass()
-    m.some_calculation(x=42)
-    with self.assertRaises(expected_exception=ParameterException):
-        m.some_calculation(x=-1)
-    with self.assertRaises(expected_exception=ParameterException):
-        m.some_calculation(x=-42)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.some_calculation(x=1.0)
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        m.some_calculation(42)
-
-
-
-
-def test_pedantic_overrides(self) -
-
-
- -Expand source code - -
def test_pedantic_overrides(self):
-    class MyClass(ABC):
-        @pedantic
-        @abstractmethod
-        def op(self, a: int) -> None:
-            pass
-
-    class Child(MyClass):
-        a = 0
-
-        @pedantic
-        @overrides(MyClass)
-        def op(self, a: int) -> None:
-            self.a = a
-
-    c = Child()
-    c.op(a=42)
-
-
-
-
-def test_pedantic_static_method_1(self) -
-
-
- -Expand source code - -
def test_pedantic_static_method_1(self):
-    class MyClass:
-        @staticmethod
-        @pedantic
-        def some_calculation(x: int) -> int:
-            return x
-
-    m = MyClass()
-    m.some_calculation(x=42)
-    MyClass.some_calculation(x=45)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_decorated_function.html b/docs/pedantic/tests/tests_decorated_function.html deleted file mode 100644 index a1c68292..00000000 --- a/docs/pedantic/tests/tests_decorated_function.html +++ /dev/null @@ -1,460 +0,0 @@ - - - - - - -pedantic.tests.tests_decorated_function API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_decorated_function

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestDecoratedFunction -(methodName='runTest') -
-
-
- -Expand source code - -
class TestDecoratedFunction(unittest.TestCase):
-    def test_static_method(self):
-        def f_1(): pass
-
-        deco_f = DecoratedFunction(f_1)
-        self.assertFalse(deco_f.is_static_method)
-
-        class MyClass:
-            def f_1(self): pass
-
-            @staticmethod
-            def f_2(): pass
-
-            @classmethod
-            def f_3(cls): pass
-
-        deco_f_1 = DecoratedFunction(MyClass.f_1)
-        deco_f_2 = DecoratedFunction(MyClass.f_2)
-        deco_f_3 = DecoratedFunction(MyClass.f_3)
-
-        self.assertFalse(deco_f_1.is_static_method)
-        self.assertTrue(deco_f_2.is_static_method)
-        self.assertFalse(deco_f_3.is_static_method)
-
-    def test_function_wants_args(self):
-        def f_1(*args, **kwargs): pass
-
-        def f_2(a, b, *args, **kwargs): pass
-
-        def f_3(a, b, *args): pass
-
-        def f_4(*args): pass
-
-        def f_5(): pass
-
-        self.assertTrue(DecoratedFunction(f_1).wants_args)
-        self.assertTrue(DecoratedFunction(f_2).wants_args)
-        self.assertTrue(DecoratedFunction(f_3).wants_args)
-        self.assertTrue(DecoratedFunction(f_4).wants_args)
-        self.assertFalse(DecoratedFunction(f_5).wants_args)
-
-        class MyClass:
-            def f(self): pass
-
-            @staticmethod
-            def g(): pass
-
-        self.assertFalse(DecoratedFunction(MyClass.f).wants_args)
-        self.assertFalse(DecoratedFunction(MyClass.g).wants_args)
-
-    def test_is_property_setter(self):
-        def f_1(): pass
-
-        self.assertFalse(DecoratedFunction(f_1).is_property_setter)
-
-        class MyClass:
-            _h = 42
-
-            def f_1(self): pass
-
-            @staticmethod
-            def f_2(): pass
-
-        self.assertFalse(DecoratedFunction(MyClass.f_1).is_property_setter)
-        self.assertFalse(DecoratedFunction(MyClass.f_2).is_property_setter)
-
-    def test_wants_kwargs(self):
-        def f_1(*args, **kwargs): pass
-
-        def f_2(a, b, *args, **kwargs): pass
-
-        def f_3(a, b, *args): pass
-
-        def f_4(*args): pass
-
-        def f_5(): pass
-
-        def f_6(a, b, c): pass
-
-        self.assertFalse(DecoratedFunction(f_1).should_have_kwargs)
-        self.assertFalse(DecoratedFunction(f_2).should_have_kwargs)
-        self.assertFalse(DecoratedFunction(f_3).should_have_kwargs)
-        self.assertFalse(DecoratedFunction(f_4).should_have_kwargs)
-        self.assertTrue(DecoratedFunction(f_5).should_have_kwargs)
-        self.assertTrue(DecoratedFunction(f_6).should_have_kwargs)
-
-        class A:
-            def f(self): pass
-
-            @staticmethod
-            def g(): pass
-
-            def __compare__(self, other): pass
-
-        self.assertTrue(DecoratedFunction(A.f).should_have_kwargs)
-        self.assertTrue(DecoratedFunction(A.g).should_have_kwargs)
-        self.assertFalse(DecoratedFunction(A.__compare__).should_have_kwargs)
-
-    def test_instance_method(self):
-        def h(): pass
-
-        self.assertFalse(DecoratedFunction(h).is_instance_method)
-
-        class A:
-            def f(self): pass
-
-            @staticmethod
-            def g(): pass
-
-        self.assertTrue(DecoratedFunction(A.f).is_instance_method)
-        self.assertFalse(DecoratedFunction(A.g).is_instance_method)
-
-    def test_num_decorators(self):
-        def decorator(f):
-            return f
-
-        def f_1(): pass
-
-        @decorator
-        def f_2(): pass
-
-        @decorator
-        @decorator
-        def f_3(): pass
-
-        @decorator
-        @decorator
-        @decorator
-        def f_4():
-            pass
-
-        self.assertEqual(DecoratedFunction(f_1).num_of_decorators, 0)
-        self.assertEqual(DecoratedFunction(f_2).num_of_decorators, 1)
-        self.assertEqual(DecoratedFunction(f_3).num_of_decorators, 2)
-        self.assertEqual(DecoratedFunction(f_4).num_of_decorators, 3)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_function_wants_args(self) -
-
-
- -Expand source code - -
def test_function_wants_args(self):
-    def f_1(*args, **kwargs): pass
-
-    def f_2(a, b, *args, **kwargs): pass
-
-    def f_3(a, b, *args): pass
-
-    def f_4(*args): pass
-
-    def f_5(): pass
-
-    self.assertTrue(DecoratedFunction(f_1).wants_args)
-    self.assertTrue(DecoratedFunction(f_2).wants_args)
-    self.assertTrue(DecoratedFunction(f_3).wants_args)
-    self.assertTrue(DecoratedFunction(f_4).wants_args)
-    self.assertFalse(DecoratedFunction(f_5).wants_args)
-
-    class MyClass:
-        def f(self): pass
-
-        @staticmethod
-        def g(): pass
-
-    self.assertFalse(DecoratedFunction(MyClass.f).wants_args)
-    self.assertFalse(DecoratedFunction(MyClass.g).wants_args)
-
-
-
-
-def test_instance_method(self) -
-
-
- -Expand source code - -
def test_instance_method(self):
-    def h(): pass
-
-    self.assertFalse(DecoratedFunction(h).is_instance_method)
-
-    class A:
-        def f(self): pass
-
-        @staticmethod
-        def g(): pass
-
-    self.assertTrue(DecoratedFunction(A.f).is_instance_method)
-    self.assertFalse(DecoratedFunction(A.g).is_instance_method)
-
-
-
-
-def test_is_property_setter(self) -
-
-
- -Expand source code - -
def test_is_property_setter(self):
-    def f_1(): pass
-
-    self.assertFalse(DecoratedFunction(f_1).is_property_setter)
-
-    class MyClass:
-        _h = 42
-
-        def f_1(self): pass
-
-        @staticmethod
-        def f_2(): pass
-
-    self.assertFalse(DecoratedFunction(MyClass.f_1).is_property_setter)
-    self.assertFalse(DecoratedFunction(MyClass.f_2).is_property_setter)
-
-
-
-
-def test_num_decorators(self) -
-
-
- -Expand source code - -
def test_num_decorators(self):
-    def decorator(f):
-        return f
-
-    def f_1(): pass
-
-    @decorator
-    def f_2(): pass
-
-    @decorator
-    @decorator
-    def f_3(): pass
-
-    @decorator
-    @decorator
-    @decorator
-    def f_4():
-        pass
-
-    self.assertEqual(DecoratedFunction(f_1).num_of_decorators, 0)
-    self.assertEqual(DecoratedFunction(f_2).num_of_decorators, 1)
-    self.assertEqual(DecoratedFunction(f_3).num_of_decorators, 2)
-    self.assertEqual(DecoratedFunction(f_4).num_of_decorators, 3)
-
-
-
-
-def test_static_method(self) -
-
-
- -Expand source code - -
def test_static_method(self):
-    def f_1(): pass
-
-    deco_f = DecoratedFunction(f_1)
-    self.assertFalse(deco_f.is_static_method)
-
-    class MyClass:
-        def f_1(self): pass
-
-        @staticmethod
-        def f_2(): pass
-
-        @classmethod
-        def f_3(cls): pass
-
-    deco_f_1 = DecoratedFunction(MyClass.f_1)
-    deco_f_2 = DecoratedFunction(MyClass.f_2)
-    deco_f_3 = DecoratedFunction(MyClass.f_3)
-
-    self.assertFalse(deco_f_1.is_static_method)
-    self.assertTrue(deco_f_2.is_static_method)
-    self.assertFalse(deco_f_3.is_static_method)
-
-
-
-
-def test_wants_kwargs(self) -
-
-
- -Expand source code - -
def test_wants_kwargs(self):
-    def f_1(*args, **kwargs): pass
-
-    def f_2(a, b, *args, **kwargs): pass
-
-    def f_3(a, b, *args): pass
-
-    def f_4(*args): pass
-
-    def f_5(): pass
-
-    def f_6(a, b, c): pass
-
-    self.assertFalse(DecoratedFunction(f_1).should_have_kwargs)
-    self.assertFalse(DecoratedFunction(f_2).should_have_kwargs)
-    self.assertFalse(DecoratedFunction(f_3).should_have_kwargs)
-    self.assertFalse(DecoratedFunction(f_4).should_have_kwargs)
-    self.assertTrue(DecoratedFunction(f_5).should_have_kwargs)
-    self.assertTrue(DecoratedFunction(f_6).should_have_kwargs)
-
-    class A:
-        def f(self): pass
-
-        @staticmethod
-        def g(): pass
-
-        def __compare__(self, other): pass
-
-    self.assertTrue(DecoratedFunction(A.f).should_have_kwargs)
-    self.assertTrue(DecoratedFunction(A.g).should_have_kwargs)
-    self.assertFalse(DecoratedFunction(A.__compare__).should_have_kwargs)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_docstring.html b/docs/pedantic/tests/tests_docstring.html deleted file mode 100644 index feb88dfc..00000000 --- a/docs/pedantic/tests/tests_docstring.html +++ /dev/null @@ -1,1410 +0,0 @@ - - - - - - -pedantic.tests.tests_docstring API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_docstring

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestRequireDocstringGoogleFormat -(methodName='runTest') -
-
-
- -Expand source code - -
class TestRequireDocstringGoogleFormat(TestCase):
-
-    def test_no_docstring(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_require_docstring
-            def calc(n: int, m: int, i: int) -> int:
-                return n + m + i
-
-    def test_one_line_doc_string_missing_arguments_and_return(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_require_docstring
-            def calc(n: int, m: int, i: int) -> int:
-                """Returns the sum of the three args."""
-                return n + m + i
-
-    def test_one_line_doc_string_corrected(self):
-        @pedantic_require_docstring
-        def calc(n: int, m: int, i: int) -> int:
-            """Returns the sum of the three args.
-
-            Args:
-                n (int): something
-                m (int): something
-                i (int): something
-
-            Returns:
-                int: bar
-            """
-            return n + m + i
-
-        calc(n=42, m=40, i=38)
-
-    def test_list_vs_typing_list(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_require_docstring
-            def calc(file_loc: str, print_cols: bool) -> List[str]:
-                """Gets and prints the spreadsheet's header columns
-
-                Args:
-                    file_loc (str): The file location of the spreadsheet
-                    print_cols (bool): A flag used to print the columns to the console
-                        (default is False)
-
-                Returns:
-                    list: a list of strings representing the header columns
-                """
-                return [file_loc, str(print_cols)]
-
-    def test_google_docstring_2(self):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool) -> List[str]:
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console
-                    (default is False)
-
-            Returns:
-                List[str]: a list of strings representing the header columns
-            """
-
-            return [file_loc, str(print_cols)]
-
-        calc(file_loc='Hi', print_cols=False)
-
-    def test_google_docstring_3(self):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool) -> List[str]:
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console
-                    (default is False)
-
-            Returns:
-                List[str]: a list of strings representing the header columns
-            """
-
-            return [file_loc, str(print_cols)]
-
-        calc(file_loc='Hi', print_cols=False)
-
-    def test_more_parameter_documented_than_the_function_takes(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_require_docstring
-            def calc(file_loc: str, print_cols: bool) -> List[str]:
-                """Gets and prints the spreadsheet's header columns
-
-                Args:
-                    file_loc (str): The file location of the spreadsheet
-                    print_cols (bool): A flag used to print the columns to the console
-                        (default is False)
-                    amount (int): THIS ARGUMENT IS NOT TAKEN BY THE FUNCTION
-
-                Returns:
-                    List[str]: a list of strings representing the header columns
-                """
-                return [file_loc, str(print_cols)]
-
-    def test_google_docstring_corrected(self):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool, amount: int) -> List[str]:
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console
-                    (default is False)
-                amount (int): now it is
-
-            Returns:
-                List[str]: a list of strings representing the header columns
-            """
-
-            return [file_loc, str(print_cols), str(amount)]
-
-        calc(file_loc='Hi', print_cols=False, amount=42)
-
-    def test_no_args_keyword_before_documented_arguments(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_require_docstring
-            def calc(file_loc: str, print_cols: bool) -> list:
-                """Gets and prints the spreadsheet's header columns
-
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console
-                    (default is False)
-
-                Returns:
-                    list: a list of strings representing the header columns
-                """
-                return [file_loc, str(print_cols)]
-
-    def test_google_no_return_keyword(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_require_docstring
-            def calc(file_loc: str, print_cols: bool) -> list:
-                """Gets and prints the spreadsheet's header columns
-
-                Args:
-                    file_loc (str): The file location of the spreadsheet
-                    print_cols (bool): A flag used to print the columns to the console
-                        (default is False)
-
-                list: a list of strings representing the header columns
-                """
-                return [file_loc, str(print_cols)]
-
-    def test_keep_it_simple(self):
-        @pedantic_require_docstring
-        def calc() -> None:
-            """Gets and prints the spreadsheet's header columns"""
-            pass
-
-        calc()
-
-    def test_docstring_misses_argument(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_require_docstring
-            def calc(name: str) -> None:
-                """Gets and prints the spreadsheet's header columns"""
-                print('hi ' + name)
-
-    def test_keep_it_simple_2_corrected(self):
-        @pedantic_require_docstring
-        def calc(name: str) -> None:
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                name (str): the name
-            """
-            print('hi ' + name)
-
-        calc(name='maria')
-
-    def test_undocumented_arg(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_require_docstring
-            def calc(file_loc: str, print_cols: bool, number: int) -> List[str]:
-                """Gets and prints the spreadsheet's header columns
-
-                Args:
-                    file_loc (str): The file location of the spreadsheet
-                    print_cols (bool): A flag used to print the columns to the console
-                        (default is False)
-
-                Returns:
-                    List[str]: a list of strings representing the header columns
-                """
-                return [file_loc, str(print_cols), str(number)]
-
-    def test_undocumented_arg_corrected(self):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool, number: int) -> List[str]:
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console
-                    (default is False)
-                number (int): magic number
-
-            Returns:
-                List[str]: a list of strings representing the header columns
-            """
-
-            return [file_loc, str(print_cols), str(number)]
-
-        calc(file_loc='Hi', print_cols=False, number=42)
-
-    def test_restructured_text_style_doctsring_cannot_be_parsed_yet(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_require_docstring
-            def calc(file_loc: str, print_cols: bool) -> List[str]:
-                """Gets and prints the spreadsheet's header columns
-
-                :param file_loc: The file location of the spreadsheet
-                :type file_loc: str
-                :param print_cols: A flag used to print the columns to the console
-                :type print_cols: bool
-                :returns: a list of strings representing the header column
-                :rtype: List[str]
-                """
-                return [file_loc, str(print_cols)]
-
-    def test_return_nothing_but_document_return_value(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_require_docstring
-            def calc(file_loc: str, print_cols: bool):
-                """Gets and prints the spreadsheet's header columns
-
-                Args:
-                    file_loc (str): The file location of the spreadsheet
-                    print_cols (bool): A flag used to print the columns to the console
-                        (default is False)
-
-                Returns:
-                    list: a list of strings representing the header columns
-                """
-                print([file_loc, str(print_cols)])
-
-    def test_return_nothing_but_document_return_value_2(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_require_docstring
-            def calc(file_loc: str, print_cols: bool) -> None:
-                """Gets and prints the spreadsheet's header columns
-
-                Args:
-                    file_loc (str): The file location of the spreadsheet
-                    print_cols (bool): A flag used to print the columns to the console
-                        (default is False)
-
-                Returns:
-                    list: a list of strings representing the header columns
-                """
-                print([file_loc, str(print_cols)])
-
-    def test_return_value_1_corrected(self):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool) -> None:
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console
-                    (default is False)
-            """
-
-            a = [file_loc, str(print_cols)]
-        calc(file_loc='Hi', print_cols=False)
-
-    def test_return_value_is_not_documented(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            # the error message here is actually wrong due to the behavior of the docstring-parser package
-            @pedantic_require_docstring
-            def calc(file_loc: str, print_cols: bool) -> List[str]:
-                """Gets and prints the spreadsheet's header columns
-
-                Args:
-                    file_loc (str): The file location of the spreadsheet
-                    print_cols (bool): A flag used to print the columns to the console (default is False)
-
-                Returns:
-                """
-                return [file_loc, str(print_cols)]
-
-    def test_return_value_2_corrected(self):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool) -> List[str]:
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console
-                    (default is False)
-
-            Returns:
-                List[str]: results
-            """
-
-            return [file_loc, str(print_cols)]
-
-        calc(file_loc='Hi', print_cols=False)
-
-    def test_return_value_is_not_documented_3(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_require_docstring
-            def calc(file_loc: str, print_cols: bool) -> List[str]:
-                """Gets and prints the spreadsheet's header columns
-
-                Args:
-                    file_loc (str): The file location of the spreadsheet
-                    print_cols (bool): A flag used to print the columns to the console
-                        (default is False)
-                """
-                return [file_loc, str(print_cols)]
-
-    def test_wrong_format_1(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            class MyText:
-                text = 'hi'
-
-                @pedantic_require_docstring
-                def __contains__(self, substring: str) -> bool:
-                    """
-                    Checks if contains substring.
-                    Overriding __contains__ build in functions allows to use the 'in' operator blah readability
-
-                    Example:
-                    my_text = MyText('abc')
-                    if 'ab' in my_text -> true
-                    :param: substring: substring
-                    :return: True if substring is stored, False otherwise.
-                    """
-                    return substring in self.text
-
-    def test_undocumented_arg_3(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic
-            def calc(a: int, b: float, c: str) -> str:
-                """Returns some cool string
-
-                Args:
-                    a (int): something
-                    b (float): something
-
-                Returns:
-                    str: something
-                """
-                return str(a) + str(b) + c
-
-            calc(a=42, b=3.14, c='hi')
-
-    def test_pedantic_1_corrected(self):
-        @pedantic
-        def calc(a: int, b: float, c: str) -> str:
-            """Returns some cool string
-
-            Args:
-                a (int): something
-                b (float): something
-                c (str): something
-
-            Returns:
-                str: something
-            """
-            return str(a) + str(b) + c
-
-        calc(a=42, b=3.14, c='hi')
-
-    def test_documented_none_as_return_type(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_require_docstring
-            def calc() -> None:
-                """some cool stuff
-
-                Returns:
-                    None: the evil void
-                """
-                pass
-
-    def test_exception_in_docstring_parser(self):
-        @pedantic_class
-        class Foo:
-            def func(self, b: str) -> str:
-                """
-                Function with docstring syntax error below.
-                Args:
-                    b (str):
-                    simple string
-                Returns:
-                    str: simple string
-                """
-                return b
-
-    def test_user_class(self):
-        class BPMNEnum:
-            attr = 'BPMNEnum'
-
-        class BPMNElement:
-            attr = 'BPMNElement'
-
-        @pedantic_class_require_docstring
-        class MyClass:
-            def make_element(self, element_type: BPMNEnum,
-                             src_tgt_elements: Optional[List[BPMNElement]] = None) -> List[BPMNElement]:
-                """
-                Searches all element_types in XML-DOM and returns corresponding
-                BPMN-Objects.
-                Args:
-                    element_type(BPMNEnum): abc
-                    src_tgt_elements (Optional[List[BPMNElement]]): abc
-
-                Returns:
-                    List[BPMNElement]: abc
-                """
-                element_type.attr = '42'
-                return src_tgt_elements
-
-        m = MyClass()
-        m.make_element(element_type=BPMNEnum(), src_tgt_elements=[BPMNElement()])
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.make_element(element_type=BPMNElement(), src_tgt_elements=[BPMNEnum()])
-
-    def test_user_class_with_typing(self):
-        class BPMNEnum:
-            attr = 'BPMNEnum'
-
-        class BPMNElement:
-            attr = 'BPMNElement'
-
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_class_require_docstring
-            class MyClass:
-
-                def make_element(self, element_type: BPMNEnum,
-                                 src_tgt_elements: Optional[List[BPMNElement]] = None) -> List[BPMNElement]:
-                    """
-                    Searches all element_types in XML-DOM and returns corresponding
-                    BPMN-Objects.
-                    Args:
-                        element_type(BPMNEnum): abc
-                        src_tgt_elements (typing.Optional[List[BPMNElement]]): abc
-
-                    Returns:
-                        List[BPMNElement]: abc
-                    """
-                    element_type.attr = '42'
-                    return src_tgt_elements
-
-    def test_factory(self):
-        @pedantic_require_docstring
-        def get_instance() -> TestCase:
-            """
-            Returns:
-                TestCase: A new TestCase
-            """
-            return TestCase()
-
-        get_instance()
-
-    def test_pedantic_args(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic(require_docstring=True)
-            def no_docstrings() -> None:
-                print('.')
-
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_require_docstring
-            def no_docstrings() -> None:
-                print('.')
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_docstring_misses_argument(self) -
-
-
- -Expand source code - -
def test_docstring_misses_argument(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_require_docstring
-        def calc(name: str) -> None:
-            """Gets and prints the spreadsheet's header columns"""
-            print('hi ' + name)
-
-
-
-
-def test_documented_none_as_return_type(self) -
-
-
- -Expand source code - -
def test_documented_none_as_return_type(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_require_docstring
-        def calc() -> None:
-            """some cool stuff
-
-            Returns:
-                None: the evil void
-            """
-            pass
-
-
-
-
-def test_exception_in_docstring_parser(self) -
-
-
- -Expand source code - -
def test_exception_in_docstring_parser(self):
-    @pedantic_class
-    class Foo:
-        def func(self, b: str) -> str:
-            """
-            Function with docstring syntax error below.
-            Args:
-                b (str):
-                simple string
-            Returns:
-                str: simple string
-            """
-            return b
-
-
-
-
-def test_factory(self) -
-
-
- -Expand source code - -
def test_factory(self):
-    @pedantic_require_docstring
-    def get_instance() -> TestCase:
-        """
-        Returns:
-            TestCase: A new TestCase
-        """
-        return TestCase()
-
-    get_instance()
-
-
-
-
-def test_google_docstring_2(self) -
-
-
- -Expand source code - -
def test_google_docstring_2(self):
-    @pedantic_require_docstring
-    def calc(file_loc: str, print_cols: bool) -> List[str]:
-        """Gets and prints the spreadsheet's header columns
-
-        Args:
-            file_loc (str): The file location of the spreadsheet
-            print_cols (bool): A flag used to print the columns to the console
-                (default is False)
-
-        Returns:
-            List[str]: a list of strings representing the header columns
-        """
-
-        return [file_loc, str(print_cols)]
-
-    calc(file_loc='Hi', print_cols=False)
-
-
-
-
-def test_google_docstring_3(self) -
-
-
- -Expand source code - -
def test_google_docstring_3(self):
-    @pedantic_require_docstring
-    def calc(file_loc: str, print_cols: bool) -> List[str]:
-        """Gets and prints the spreadsheet's header columns
-
-        Args:
-            file_loc (str): The file location of the spreadsheet
-            print_cols (bool): A flag used to print the columns to the console
-                (default is False)
-
-        Returns:
-            List[str]: a list of strings representing the header columns
-        """
-
-        return [file_loc, str(print_cols)]
-
-    calc(file_loc='Hi', print_cols=False)
-
-
-
-
-def test_google_docstring_corrected(self) -
-
-
- -Expand source code - -
def test_google_docstring_corrected(self):
-    @pedantic_require_docstring
-    def calc(file_loc: str, print_cols: bool, amount: int) -> List[str]:
-        """Gets and prints the spreadsheet's header columns
-
-        Args:
-            file_loc (str): The file location of the spreadsheet
-            print_cols (bool): A flag used to print the columns to the console
-                (default is False)
-            amount (int): now it is
-
-        Returns:
-            List[str]: a list of strings representing the header columns
-        """
-
-        return [file_loc, str(print_cols), str(amount)]
-
-    calc(file_loc='Hi', print_cols=False, amount=42)
-
-
-
-
-def test_google_no_return_keyword(self) -
-
-
- -Expand source code - -
def test_google_no_return_keyword(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool) -> list:
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console
-                    (default is False)
-
-            list: a list of strings representing the header columns
-            """
-            return [file_loc, str(print_cols)]
-
-
-
-
-def test_keep_it_simple(self) -
-
-
- -Expand source code - -
def test_keep_it_simple(self):
-    @pedantic_require_docstring
-    def calc() -> None:
-        """Gets and prints the spreadsheet's header columns"""
-        pass
-
-    calc()
-
-
-
-
-def test_keep_it_simple_2_corrected(self) -
-
-
- -Expand source code - -
def test_keep_it_simple_2_corrected(self):
-    @pedantic_require_docstring
-    def calc(name: str) -> None:
-        """Gets and prints the spreadsheet's header columns
-
-        Args:
-            name (str): the name
-        """
-        print('hi ' + name)
-
-    calc(name='maria')
-
-
-
-
-def test_list_vs_typing_list(self) -
-
-
- -Expand source code - -
def test_list_vs_typing_list(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool) -> List[str]:
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console
-                    (default is False)
-
-            Returns:
-                list: a list of strings representing the header columns
-            """
-            return [file_loc, str(print_cols)]
-
-
-
-
-def test_more_parameter_documented_than_the_function_takes(self) -
-
-
- -Expand source code - -
def test_more_parameter_documented_than_the_function_takes(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool) -> List[str]:
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console
-                    (default is False)
-                amount (int): THIS ARGUMENT IS NOT TAKEN BY THE FUNCTION
-
-            Returns:
-                List[str]: a list of strings representing the header columns
-            """
-            return [file_loc, str(print_cols)]
-
-
-
-
-def test_no_args_keyword_before_documented_arguments(self) -
-
-
- -Expand source code - -
def test_no_args_keyword_before_documented_arguments(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool) -> list:
-            """Gets and prints the spreadsheet's header columns
-
-            file_loc (str): The file location of the spreadsheet
-            print_cols (bool): A flag used to print the columns to the console
-                (default is False)
-
-            Returns:
-                list: a list of strings representing the header columns
-            """
-            return [file_loc, str(print_cols)]
-
-
-
-
-def test_no_docstring(self) -
-
-
- -Expand source code - -
def test_no_docstring(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_require_docstring
-        def calc(n: int, m: int, i: int) -> int:
-            return n + m + i
-
-
-
-
-def test_one_line_doc_string_corrected(self) -
-
-
- -Expand source code - -
def test_one_line_doc_string_corrected(self):
-    @pedantic_require_docstring
-    def calc(n: int, m: int, i: int) -> int:
-        """Returns the sum of the three args.
-
-        Args:
-            n (int): something
-            m (int): something
-            i (int): something
-
-        Returns:
-            int: bar
-        """
-        return n + m + i
-
-    calc(n=42, m=40, i=38)
-
-
-
-
-def test_one_line_doc_string_missing_arguments_and_return(self) -
-
-
- -Expand source code - -
def test_one_line_doc_string_missing_arguments_and_return(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_require_docstring
-        def calc(n: int, m: int, i: int) -> int:
-            """Returns the sum of the three args."""
-            return n + m + i
-
-
-
-
-def test_pedantic_1_corrected(self) -
-
-
- -Expand source code - -
def test_pedantic_1_corrected(self):
-    @pedantic
-    def calc(a: int, b: float, c: str) -> str:
-        """Returns some cool string
-
-        Args:
-            a (int): something
-            b (float): something
-            c (str): something
-
-        Returns:
-            str: something
-        """
-        return str(a) + str(b) + c
-
-    calc(a=42, b=3.14, c='hi')
-
-
-
-
-def test_pedantic_args(self) -
-
-
- -Expand source code - -
def test_pedantic_args(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic(require_docstring=True)
-        def no_docstrings() -> None:
-            print('.')
-
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_require_docstring
-        def no_docstrings() -> None:
-            print('.')
-
-
-
-
-def test_restructured_text_style_doctsring_cannot_be_parsed_yet(self) -
-
-
- -Expand source code - -
def test_restructured_text_style_doctsring_cannot_be_parsed_yet(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool) -> List[str]:
-            """Gets and prints the spreadsheet's header columns
-
-            :param file_loc: The file location of the spreadsheet
-            :type file_loc: str
-            :param print_cols: A flag used to print the columns to the console
-            :type print_cols: bool
-            :returns: a list of strings representing the header column
-            :rtype: List[str]
-            """
-            return [file_loc, str(print_cols)]
-
-
-
-
-def test_return_nothing_but_document_return_value(self) -
-
-
- -Expand source code - -
def test_return_nothing_but_document_return_value(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool):
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console
-                    (default is False)
-
-            Returns:
-                list: a list of strings representing the header columns
-            """
-            print([file_loc, str(print_cols)])
-
-
-
-
-def test_return_nothing_but_document_return_value_2(self) -
-
-
- -Expand source code - -
def test_return_nothing_but_document_return_value_2(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool) -> None:
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console
-                    (default is False)
-
-            Returns:
-                list: a list of strings representing the header columns
-            """
-            print([file_loc, str(print_cols)])
-
-
-
-
-def test_return_value_1_corrected(self) -
-
-
- -Expand source code - -
def test_return_value_1_corrected(self):
-    @pedantic_require_docstring
-    def calc(file_loc: str, print_cols: bool) -> None:
-        """Gets and prints the spreadsheet's header columns
-
-        Args:
-            file_loc (str): The file location of the spreadsheet
-            print_cols (bool): A flag used to print the columns to the console
-                (default is False)
-        """
-
-        a = [file_loc, str(print_cols)]
-    calc(file_loc='Hi', print_cols=False)
-
-
-
-
-def test_return_value_2_corrected(self) -
-
-
- -Expand source code - -
def test_return_value_2_corrected(self):
-    @pedantic_require_docstring
-    def calc(file_loc: str, print_cols: bool) -> List[str]:
-        """Gets and prints the spreadsheet's header columns
-
-        Args:
-            file_loc (str): The file location of the spreadsheet
-            print_cols (bool): A flag used to print the columns to the console
-                (default is False)
-
-        Returns:
-            List[str]: results
-        """
-
-        return [file_loc, str(print_cols)]
-
-    calc(file_loc='Hi', print_cols=False)
-
-
-
-
-def test_return_value_is_not_documented(self) -
-
-
- -Expand source code - -
def test_return_value_is_not_documented(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        # the error message here is actually wrong due to the behavior of the docstring-parser package
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool) -> List[str]:
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console (default is False)
-
-            Returns:
-            """
-            return [file_loc, str(print_cols)]
-
-
-
-
-def test_return_value_is_not_documented_3(self) -
-
-
- -Expand source code - -
def test_return_value_is_not_documented_3(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool) -> List[str]:
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console
-                    (default is False)
-            """
-            return [file_loc, str(print_cols)]
-
-
-
-
-def test_undocumented_arg(self) -
-
-
- -Expand source code - -
def test_undocumented_arg(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_require_docstring
-        def calc(file_loc: str, print_cols: bool, number: int) -> List[str]:
-            """Gets and prints the spreadsheet's header columns
-
-            Args:
-                file_loc (str): The file location of the spreadsheet
-                print_cols (bool): A flag used to print the columns to the console
-                    (default is False)
-
-            Returns:
-                List[str]: a list of strings representing the header columns
-            """
-            return [file_loc, str(print_cols), str(number)]
-
-
-
-
-def test_undocumented_arg_3(self) -
-
-
- -Expand source code - -
def test_undocumented_arg_3(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic
-        def calc(a: int, b: float, c: str) -> str:
-            """Returns some cool string
-
-            Args:
-                a (int): something
-                b (float): something
-
-            Returns:
-                str: something
-            """
-            return str(a) + str(b) + c
-
-        calc(a=42, b=3.14, c='hi')
-
-
-
-
-def test_undocumented_arg_corrected(self) -
-
-
- -Expand source code - -
def test_undocumented_arg_corrected(self):
-    @pedantic_require_docstring
-    def calc(file_loc: str, print_cols: bool, number: int) -> List[str]:
-        """Gets and prints the spreadsheet's header columns
-
-        Args:
-            file_loc (str): The file location of the spreadsheet
-            print_cols (bool): A flag used to print the columns to the console
-                (default is False)
-            number (int): magic number
-
-        Returns:
-            List[str]: a list of strings representing the header columns
-        """
-
-        return [file_loc, str(print_cols), str(number)]
-
-    calc(file_loc='Hi', print_cols=False, number=42)
-
-
-
-
-def test_user_class(self) -
-
-
- -Expand source code - -
def test_user_class(self):
-    class BPMNEnum:
-        attr = 'BPMNEnum'
-
-    class BPMNElement:
-        attr = 'BPMNElement'
-
-    @pedantic_class_require_docstring
-    class MyClass:
-        def make_element(self, element_type: BPMNEnum,
-                         src_tgt_elements: Optional[List[BPMNElement]] = None) -> List[BPMNElement]:
-            """
-            Searches all element_types in XML-DOM and returns corresponding
-            BPMN-Objects.
-            Args:
-                element_type(BPMNEnum): abc
-                src_tgt_elements (Optional[List[BPMNElement]]): abc
-
-            Returns:
-                List[BPMNElement]: abc
-            """
-            element_type.attr = '42'
-            return src_tgt_elements
-
-    m = MyClass()
-    m.make_element(element_type=BPMNEnum(), src_tgt_elements=[BPMNElement()])
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.make_element(element_type=BPMNElement(), src_tgt_elements=[BPMNEnum()])
-
-
-
-
-def test_user_class_with_typing(self) -
-
-
- -Expand source code - -
def test_user_class_with_typing(self):
-    class BPMNEnum:
-        attr = 'BPMNEnum'
-
-    class BPMNElement:
-        attr = 'BPMNElement'
-
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_class_require_docstring
-        class MyClass:
-
-            def make_element(self, element_type: BPMNEnum,
-                             src_tgt_elements: Optional[List[BPMNElement]] = None) -> List[BPMNElement]:
-                """
-                Searches all element_types in XML-DOM and returns corresponding
-                BPMN-Objects.
-                Args:
-                    element_type(BPMNEnum): abc
-                    src_tgt_elements (typing.Optional[List[BPMNElement]]): abc
-
-                Returns:
-                    List[BPMNElement]: abc
-                """
-                element_type.attr = '42'
-                return src_tgt_elements
-
-
-
-
-def test_wrong_format_1(self) -
-
-
- -Expand source code - -
def test_wrong_format_1(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        class MyText:
-            text = 'hi'
-
-            @pedantic_require_docstring
-            def __contains__(self, substring: str) -> bool:
-                """
-                Checks if contains substring.
-                Overriding __contains__ build in functions allows to use the 'in' operator blah readability
-
-                Example:
-                my_text = MyText('abc')
-                if 'ab' in my_text -> true
-                :param: substring: substring
-                :return: True if substring is stored, False otherwise.
-                """
-                return substring in self.text
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_doctests.html b/docs/pedantic/tests/tests_doctests.html deleted file mode 100644 index 709e903d..00000000 --- a/docs/pedantic/tests/tests_doctests.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - -pedantic.tests.tests_doctests API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_doctests

-
-
-
-
-
-
-
-
-

Functions

-
-
-def get_doctest_test_suite() ‑> unittest.suite.TestSuite -
-
-
- -Expand source code - -
def get_doctest_test_suite() -> unittest.TestSuite:
-    parent_module = __import__('pedantic')
-    modules = [
-        parent_module.decorators.fn_deco_count_calls,
-        parent_module.decorators.fn_deco_deprecated,
-        parent_module.decorators.fn_deco_does_same_as_function,
-        parent_module.decorators.fn_deco_in_subprocess,
-        parent_module.decorators.fn_deco_overrides,
-        parent_module.decorators.fn_deco_pedantic,
-        parent_module.decorators.fn_deco_rename_kwargs,
-        parent_module.decorators.fn_deco_timer,
-        parent_module.decorators.fn_deco_trace,
-        parent_module.decorators.fn_deco_trace_if_returns,
-        parent_module.decorators.fn_deco_unimplemented,
-        parent_module.mixins.generic_mixin,
-        parent_module.type_checking_logic.check_types,
-        parent_module.type_checking_logic.check_generic_classes,
-        parent_module.type_checking_logic.check_docstring,
-        parent_module.decorators.cls_deco_frozen_dataclass,
-    ]
-    test_suites = [doctest.DocTestSuite(module=module, optionflags=doctest.ELLIPSIS) for module in modules]
-    return unittest.TestSuite(test_suites)
-
-
-
-
-def run_doctests() ‑> None -
-
-
- -Expand source code - -
def run_doctests() -> None:
-    unittest.TextTestRunner().run(get_doctest_test_suite())
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_environment_variables.html b/docs/pedantic/tests/tests_environment_variables.html deleted file mode 100644 index 110791b6..00000000 --- a/docs/pedantic/tests/tests_environment_variables.html +++ /dev/null @@ -1,247 +0,0 @@ - - - - - - -pedantic.tests.tests_environment_variables API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_environment_variables

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestEnvironmentVariables -(methodName='runTest') -
-
-
- -Expand source code - -
class TestEnvironmentVariables(unittest.TestCase):
-    def setUp(self) -> None:
-        self.state = is_enabled()
-        enable_pedantic()
-
-    def tearDown(self) -> None:
-        enable_pedantic()
-
-    def test_pedantic_enabled(self):
-        enable_pedantic()
-
-        @pedantic
-        def some_method():
-            return 42
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            some_method()
-
-    def test_pedantic_disabled(self):
-        disable_pedantic()
-
-        @pedantic
-        def some_method():
-            return 42
-
-        some_method()
-
-    def test_enable_disable(self):
-        enable_pedantic()
-        self.assertTrue(is_enabled())
-        disable_pedantic()
-        self.assertFalse(is_enabled())
-        enable_pedantic()
-        self.assertTrue(is_enabled())
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def setUp(self) ‑> None -
-
-
- -Expand source code - -
def setUp(self) -> None:
-    self.state = is_enabled()
-    enable_pedantic()
-
-

Hook method for setting up the test fixture before exercising it.

-
-
-def tearDown(self) ‑> None -
-
-
- -Expand source code - -
def tearDown(self) -> None:
-    enable_pedantic()
-
-

Hook method for deconstructing the test fixture after testing it.

-
-
-def test_enable_disable(self) -
-
-
- -Expand source code - -
def test_enable_disable(self):
-    enable_pedantic()
-    self.assertTrue(is_enabled())
-    disable_pedantic()
-    self.assertFalse(is_enabled())
-    enable_pedantic()
-    self.assertTrue(is_enabled())
-
-
-
-
-def test_pedantic_disabled(self) -
-
-
- -Expand source code - -
def test_pedantic_disabled(self):
-    disable_pedantic()
-
-    @pedantic
-    def some_method():
-        return 42
-
-    some_method()
-
-
-
-
-def test_pedantic_enabled(self) -
-
-
- -Expand source code - -
def test_pedantic_enabled(self):
-    enable_pedantic()
-
-    @pedantic
-    def some_method():
-        return 42
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        some_method()
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_generator.html b/docs/pedantic/tests/tests_generator.html deleted file mode 100644 index 211f078c..00000000 --- a/docs/pedantic/tests/tests_generator.html +++ /dev/null @@ -1,410 +0,0 @@ - - - - - - -pedantic.tests.tests_generator API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_generator

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestGenerator -(methodName='runTest') -
-
-
- -Expand source code - -
class TestGenerator(unittest.TestCase):
-    def test_iterator(self):
-        @pedantic
-        def gen_func() -> Iterator[int]:
-            num = 0
-
-            while num < 100:
-                yield num
-                num += 1
-
-        gen = gen_func()
-        next(gen)
-
-    def test_iterator_wrong_type_hint(self):
-        @pedantic
-        def genfunc() -> Iterator[float]:
-            num = 0
-
-            while num < 100:
-                yield num
-                num += 1
-
-        gen = genfunc()
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            next(gen)
-
-    def test_iterator_no_type_args(self):
-        @pedantic
-        def genfunc() -> Iterator:
-            num = 0
-
-            while num < 100:
-                yield num
-                num += 1
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            genfunc()
-
-    def test_iterator_completely_wrong_type_hint(self):
-        @pedantic
-        def gen_func() -> List[int]:
-            num = 0
-
-            while num < 100:
-                yield num
-                num += 1
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            gen_func()
-
-    def test_iterable(self):
-        @pedantic
-        def gen_func() -> Iterable[int]:
-            num = 0
-
-            while num < 100:
-                yield num
-                num += 1
-
-        gen = gen_func()
-        next(gen)
-
-    def test_iterable_no_type_args(self):
-        @pedantic
-        def gen_func() -> Iterable:
-            num = 0
-
-            while num < 100:
-                yield num
-                num += 1
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            gen_func()
-
-    def test_generator(self):
-        @pedantic
-        def gen_func() -> Generator[int, None, str]:
-            num = 0
-
-            while num < 100:
-                yield num
-                num += 1
-            return 'Done'
-
-        gen = gen_func()
-        next(gen)
-
-    def test_invalid_no_type_args_generator(self):
-        @pedantic
-        def gen_func() -> Generator:
-            num = 0
-
-            while num < 100:
-                yield num
-                num += 1
-            return 'Done'
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            gen_func()
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_generator(self) -
-
-
- -Expand source code - -
def test_generator(self):
-    @pedantic
-    def gen_func() -> Generator[int, None, str]:
-        num = 0
-
-        while num < 100:
-            yield num
-            num += 1
-        return 'Done'
-
-    gen = gen_func()
-    next(gen)
-
-
-
-
-def test_invalid_no_type_args_generator(self) -
-
-
- -Expand source code - -
def test_invalid_no_type_args_generator(self):
-    @pedantic
-    def gen_func() -> Generator:
-        num = 0
-
-        while num < 100:
-            yield num
-            num += 1
-        return 'Done'
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        gen_func()
-
-
-
-
-def test_iterable(self) -
-
-
- -Expand source code - -
def test_iterable(self):
-    @pedantic
-    def gen_func() -> Iterable[int]:
-        num = 0
-
-        while num < 100:
-            yield num
-            num += 1
-
-    gen = gen_func()
-    next(gen)
-
-
-
-
-def test_iterable_no_type_args(self) -
-
-
- -Expand source code - -
def test_iterable_no_type_args(self):
-    @pedantic
-    def gen_func() -> Iterable:
-        num = 0
-
-        while num < 100:
-            yield num
-            num += 1
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        gen_func()
-
-
-
-
-def test_iterator(self) -
-
-
- -Expand source code - -
def test_iterator(self):
-    @pedantic
-    def gen_func() -> Iterator[int]:
-        num = 0
-
-        while num < 100:
-            yield num
-            num += 1
-
-    gen = gen_func()
-    next(gen)
-
-
-
-
-def test_iterator_completely_wrong_type_hint(self) -
-
-
- -Expand source code - -
def test_iterator_completely_wrong_type_hint(self):
-    @pedantic
-    def gen_func() -> List[int]:
-        num = 0
-
-        while num < 100:
-            yield num
-            num += 1
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        gen_func()
-
-
-
-
-def test_iterator_no_type_args(self) -
-
-
- -Expand source code - -
def test_iterator_no_type_args(self):
-    @pedantic
-    def genfunc() -> Iterator:
-        num = 0
-
-        while num < 100:
-            yield num
-            num += 1
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        genfunc()
-
-
-
-
-def test_iterator_wrong_type_hint(self) -
-
-
- -Expand source code - -
def test_iterator_wrong_type_hint(self):
-    @pedantic
-    def genfunc() -> Iterator[float]:
-        num = 0
-
-        while num < 100:
-            yield num
-            num += 1
-
-    gen = genfunc()
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        next(gen)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_generic_classes.html b/docs/pedantic/tests/tests_generic_classes.html deleted file mode 100644 index 4f4789a6..00000000 --- a/docs/pedantic/tests/tests_generic_classes.html +++ /dev/null @@ -1,841 +0,0 @@ - - - - - - -pedantic.tests.tests_generic_classes API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_generic_classes

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestGenericClasses -(methodName='runTest') -
-
-
- -Expand source code - -
class TestGenericClasses(unittest.TestCase):
-    def test_pedantic_generic_class(self):
-        T = TypeVar('T')
-
-        @pedantic_class
-        class LoggedVar(Generic[T]):
-            def __init__(self, value: T, name: str, logger: Any) -> None:
-                self.name = name
-                self.logger = logger
-                self.value = value
-
-            def set(self, new: T) -> None:
-                self.log(message='Set ' + repr(self.value))
-                self.value = new
-
-            def get(self) -> T:
-                self.log(message='Get ' + repr(self.value))
-                return self.value
-
-            def log(self, message: str) -> None:
-                self.logger = self.name + message
-
-        o = LoggedVar[int](value=42, name='hi', logger='test')
-        o.set(new=57)
-        self.assertTrue(isinstance(o.get(), int))
-
-        with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-            o.set(new=3.14)
-
-    def test_stack(self):
-        T = TypeVar('T')
-
-        @pedantic_class
-        class Stack(Generic[T]):
-            def __init__(self) -> None:
-                self.items: List[T] = []
-
-            def push(self, item: T) -> None:
-                self.items.append(item)
-
-            def pop(self) -> T:
-                return self.items.pop()
-
-            def empty(self) -> bool:
-                return not self.items
-
-            def top(self) -> Optional[T]:
-                if len(self.items) > 0:
-                    return self.items[len(self.items) - 1]
-                else:
-                    return None
-
-        my_stack = Stack[str]()
-        get_type_vars = getattr(my_stack, TYPE_VAR_METHOD_NAME)
-        self.assertEqual(get_type_vars(), {T: str, TYPE_VAR_SELF: Stack})
-        with self.assertRaises(expected_exception=IndexError):
-            my_stack.pop()
-        self.assertIsNone(my_stack.top())
-        self.assertIsNone(my_stack.top())
-        # self.assertFalse(T in get_type_vars())
-        my_stack.push(item='hi')
-        self.assertTrue(T in get_type_vars())
-        my_stack.push(item='world')
-        self.assertTrue(T in get_type_vars())
-        self.assertTrue(len(get_type_vars()), 1)
-        self.assertEqual(my_stack.pop(), 'world')
-        self.assertEqual(my_stack.pop(), 'hi')
-        self.assertIsNone(my_stack.top())
-        with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-            my_stack.push(item=42)
-
-        my_other_stack = Stack[int]()
-        get_type_vars = getattr(my_other_stack, TYPE_VAR_METHOD_NAME)
-        self.assertEqual(get_type_vars(), {T: int, TYPE_VAR_SELF: Stack})
-        with self.assertRaises(expected_exception=IndexError):
-            my_other_stack.pop()
-        self.assertIsNone(my_other_stack.top())
-        self.assertIsNone(my_other_stack.top())
-        my_other_stack.push(item=100)
-        self.assertTrue(len(get_type_vars()), 1)
-        my_other_stack.push(item=142)
-        self.assertTrue(len(get_type_vars()), 1)
-        self.assertEqual(my_other_stack.pop(), 142)
-        self.assertEqual(my_other_stack.pop(), 100)
-        self.assertIsNone(my_other_stack.top())
-        with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-            my_other_stack.push(item='42')
-
-    def test_generic_class_initialised_without_generics(self):
-        T = TypeVar('T')
-
-        @pedantic_class
-        class MyClass(Generic[T]):
-            def __init__(self, a: T) -> None:
-                self.a = a
-
-            def get_a(self) -> T:
-                return self.a
-
-            def set_a(self, val: T) -> None:
-                self.a = val
-
-        with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-            m = MyClass(a=42)
-
-    def test_generic_class_initialised_without_generics_2(self):
-        T = TypeVar('T')
-
-        @pedantic_class
-        class MyClass(Generic[T]):
-            def __init__(self, a: T) -> None:
-                self.a = a
-
-            def get_a(self) -> T:
-                return self.a
-
-            def set_a(self, val: T) -> None:
-                self.a = val
-
-        MyClass(a=42)  # it is not recognized if it isn't assigned
-
-    def test_generic_class_inheritance(self):
-        class Parent:
-            pass
-
-        class Child1(Parent):
-            pass
-
-        class Child2(Parent):
-            pass
-
-        T = TypeVar('T')
-
-        @pedantic_class
-        class MyClass(Generic[T]):
-            def __init__(self, a: T) -> None:
-                self.a = a
-
-            def get_a(self) -> T:
-                return self.a
-
-            def set_a(self, val: T) -> None:
-                self.a = val
-
-        m = MyClass[Parent](a=Child1())
-        self.assertTrue(isinstance(m.get_a(), Child1))
-        self.assertFalse(isinstance(m.get_a(), Child2))
-        m.set_a(val=Child2())
-        self.assertTrue(isinstance(m.get_a(), Child2))
-        self.assertFalse(isinstance(m.get_a(), Child1))
-
-    def test_merge_dicts(self):
-        def create():
-            T = TypeVar('T')
-
-            @pedantic_class
-            class MyClass(Generic[T]):
-                def __init__(self, a: T) -> None:
-                    self.a = a
-
-                def get_a(self) -> T:
-                    return self.a
-
-                def set_a(self, val: T) -> None:
-                    self.a = val
-            return MyClass(a=42)
-        a = create()
-        with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-            a.set_a(val='hi')
-
-    def test_recursion_depth_exceeded(self):
-        T = TypeVar('T')
-
-        @pedantic_class
-        class Stack(Generic[T]):
-            def __init__(self) -> None:
-                self.items: List[T] = []
-
-            def len(self) -> int:
-                return len(self.items)
-
-            def push(self, item: T) -> None:
-                self.items.append(item)
-
-            def pop(self) -> T:
-                if len(self.items) > 0:
-                    return self.items.pop()
-                else:
-                    raise ValueError()
-
-            def empty(self) -> bool:
-                return not self.items
-
-            def top(self) -> Optional[T]:
-                if len(self.items) > 0:
-                    return self.items[len(self.items) - 1]
-                else:
-                    return None
-
-            def __len__(self) -> int:
-                return len(self.items)
-
-        def create_stack():
-            stack = Stack[int]()
-            return stack
-
-        with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-            stack: Stack[int] = Stack()
-            self.assertTrue(stack.empty())
-        with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-            stack = Stack()
-            self.assertTrue(stack.empty())
-        stack = create_stack()
-        self.assertTrue(stack.empty())
-
-    def test_generic_union(self):
-        T = TypeVar('T')
-
-        @pedantic_class
-        class Stack(Generic[T]):
-            def __init__(self) -> None:
-                self.items: List[T] = []
-
-            def len(self) -> int:
-                return len(self.items)
-
-            def push(self, item: T) -> None:
-                self.items.append(item)
-
-            def pop(self) -> T:
-                if len(self.items) > 0:
-                    return self.items.pop()
-                else:
-                    raise ValueError()
-
-            def empty(self) -> bool:
-                return not self.items
-
-            def top(self) -> Optional[T]:
-                if len(self.items) > 0:
-                    return self.items[len(self.items) - 1]
-                else:
-                    return None
-
-            def __len__(self) -> int:
-                return len(self.items)
-
-        s = Stack[Union[int, float, str]]()
-        s.push(item=42)
-        s.push(item='hello')
-        s.push(item=3.1415)
-        with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-            s.push(item=[1, 2])
-
-    def test_inheritance(self):
-        T = TypeVar('T')
-
-        @pedantic_class
-        class Stack(Generic[T]):
-            def __init__(self) -> None:
-                self.items: List[T] = []
-
-            def len(self) -> int:
-                return len(self.items)
-
-            def push(self, item: T) -> None:
-                self.items.append(item)
-
-            def pop(self) -> T:
-                if len(self.items) > 0:
-                    return self.items.pop()
-                else:
-                    raise ValueError()
-
-            def empty(self) -> bool:
-                return not self.items
-
-            def top(self) -> Optional[T]:
-                if len(self.items) > 0:
-                    return self.items[len(self.items) - 1]
-                else:
-                    return None
-
-            def __len__(self) -> int:
-                return len(self.items)
-
-        @pedantic_class
-        class Parent:
-            pass
-
-        @pedantic_class
-        class Child1(Parent):
-            pass
-
-        @pedantic_class
-        class Child2(Parent):
-            pass
-
-        parent_stack = Stack[Parent]()
-        parent_stack.push(item=Child1())
-        parent_stack.push(item=Child2())
-        parent_stack.push(item=Parent())
-
-        child_1_stack = Stack[Child1]()
-        child_1_stack.push(item=Child1())
-        with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-            child_1_stack.push(item=Child2())
-        with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-            child_1_stack.push(item=Parent())
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_generic_class_inheritance(self) -
-
-
- -Expand source code - -
def test_generic_class_inheritance(self):
-    class Parent:
-        pass
-
-    class Child1(Parent):
-        pass
-
-    class Child2(Parent):
-        pass
-
-    T = TypeVar('T')
-
-    @pedantic_class
-    class MyClass(Generic[T]):
-        def __init__(self, a: T) -> None:
-            self.a = a
-
-        def get_a(self) -> T:
-            return self.a
-
-        def set_a(self, val: T) -> None:
-            self.a = val
-
-    m = MyClass[Parent](a=Child1())
-    self.assertTrue(isinstance(m.get_a(), Child1))
-    self.assertFalse(isinstance(m.get_a(), Child2))
-    m.set_a(val=Child2())
-    self.assertTrue(isinstance(m.get_a(), Child2))
-    self.assertFalse(isinstance(m.get_a(), Child1))
-
-
-
-
-def test_generic_class_initialised_without_generics(self) -
-
-
- -Expand source code - -
def test_generic_class_initialised_without_generics(self):
-    T = TypeVar('T')
-
-    @pedantic_class
-    class MyClass(Generic[T]):
-        def __init__(self, a: T) -> None:
-            self.a = a
-
-        def get_a(self) -> T:
-            return self.a
-
-        def set_a(self, val: T) -> None:
-            self.a = val
-
-    with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-        m = MyClass(a=42)
-
-
-
-
-def test_generic_class_initialised_without_generics_2(self) -
-
-
- -Expand source code - -
def test_generic_class_initialised_without_generics_2(self):
-    T = TypeVar('T')
-
-    @pedantic_class
-    class MyClass(Generic[T]):
-        def __init__(self, a: T) -> None:
-            self.a = a
-
-        def get_a(self) -> T:
-            return self.a
-
-        def set_a(self, val: T) -> None:
-            self.a = val
-
-    MyClass(a=42)  # it is not recognized if it isn't assigned
-
-
-
-
-def test_generic_union(self) -
-
-
- -Expand source code - -
def test_generic_union(self):
-    T = TypeVar('T')
-
-    @pedantic_class
-    class Stack(Generic[T]):
-        def __init__(self) -> None:
-            self.items: List[T] = []
-
-        def len(self) -> int:
-            return len(self.items)
-
-        def push(self, item: T) -> None:
-            self.items.append(item)
-
-        def pop(self) -> T:
-            if len(self.items) > 0:
-                return self.items.pop()
-            else:
-                raise ValueError()
-
-        def empty(self) -> bool:
-            return not self.items
-
-        def top(self) -> Optional[T]:
-            if len(self.items) > 0:
-                return self.items[len(self.items) - 1]
-            else:
-                return None
-
-        def __len__(self) -> int:
-            return len(self.items)
-
-    s = Stack[Union[int, float, str]]()
-    s.push(item=42)
-    s.push(item='hello')
-    s.push(item=3.1415)
-    with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-        s.push(item=[1, 2])
-
-
-
-
-def test_inheritance(self) -
-
-
- -Expand source code - -
def test_inheritance(self):
-    T = TypeVar('T')
-
-    @pedantic_class
-    class Stack(Generic[T]):
-        def __init__(self) -> None:
-            self.items: List[T] = []
-
-        def len(self) -> int:
-            return len(self.items)
-
-        def push(self, item: T) -> None:
-            self.items.append(item)
-
-        def pop(self) -> T:
-            if len(self.items) > 0:
-                return self.items.pop()
-            else:
-                raise ValueError()
-
-        def empty(self) -> bool:
-            return not self.items
-
-        def top(self) -> Optional[T]:
-            if len(self.items) > 0:
-                return self.items[len(self.items) - 1]
-            else:
-                return None
-
-        def __len__(self) -> int:
-            return len(self.items)
-
-    @pedantic_class
-    class Parent:
-        pass
-
-    @pedantic_class
-    class Child1(Parent):
-        pass
-
-    @pedantic_class
-    class Child2(Parent):
-        pass
-
-    parent_stack = Stack[Parent]()
-    parent_stack.push(item=Child1())
-    parent_stack.push(item=Child2())
-    parent_stack.push(item=Parent())
-
-    child_1_stack = Stack[Child1]()
-    child_1_stack.push(item=Child1())
-    with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-        child_1_stack.push(item=Child2())
-    with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-        child_1_stack.push(item=Parent())
-
-
-
-
-def test_merge_dicts(self) -
-
-
- -Expand source code - -
def test_merge_dicts(self):
-    def create():
-        T = TypeVar('T')
-
-        @pedantic_class
-        class MyClass(Generic[T]):
-            def __init__(self, a: T) -> None:
-                self.a = a
-
-            def get_a(self) -> T:
-                return self.a
-
-            def set_a(self, val: T) -> None:
-                self.a = val
-        return MyClass(a=42)
-    a = create()
-    with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-        a.set_a(val='hi')
-
-
-
-
-def test_pedantic_generic_class(self) -
-
-
- -Expand source code - -
def test_pedantic_generic_class(self):
-    T = TypeVar('T')
-
-    @pedantic_class
-    class LoggedVar(Generic[T]):
-        def __init__(self, value: T, name: str, logger: Any) -> None:
-            self.name = name
-            self.logger = logger
-            self.value = value
-
-        def set(self, new: T) -> None:
-            self.log(message='Set ' + repr(self.value))
-            self.value = new
-
-        def get(self) -> T:
-            self.log(message='Get ' + repr(self.value))
-            return self.value
-
-        def log(self, message: str) -> None:
-            self.logger = self.name + message
-
-    o = LoggedVar[int](value=42, name='hi', logger='test')
-    o.set(new=57)
-    self.assertTrue(isinstance(o.get(), int))
-
-    with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-        o.set(new=3.14)
-
-
-
-
-def test_recursion_depth_exceeded(self) -
-
-
- -Expand source code - -
def test_recursion_depth_exceeded(self):
-    T = TypeVar('T')
-
-    @pedantic_class
-    class Stack(Generic[T]):
-        def __init__(self) -> None:
-            self.items: List[T] = []
-
-        def len(self) -> int:
-            return len(self.items)
-
-        def push(self, item: T) -> None:
-            self.items.append(item)
-
-        def pop(self) -> T:
-            if len(self.items) > 0:
-                return self.items.pop()
-            else:
-                raise ValueError()
-
-        def empty(self) -> bool:
-            return not self.items
-
-        def top(self) -> Optional[T]:
-            if len(self.items) > 0:
-                return self.items[len(self.items) - 1]
-            else:
-                return None
-
-        def __len__(self) -> int:
-            return len(self.items)
-
-    def create_stack():
-        stack = Stack[int]()
-        return stack
-
-    with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-        stack: Stack[int] = Stack()
-        self.assertTrue(stack.empty())
-    with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-        stack = Stack()
-        self.assertTrue(stack.empty())
-    stack = create_stack()
-    self.assertTrue(stack.empty())
-
-
-
-
-def test_stack(self) -
-
-
- -Expand source code - -
def test_stack(self):
-    T = TypeVar('T')
-
-    @pedantic_class
-    class Stack(Generic[T]):
-        def __init__(self) -> None:
-            self.items: List[T] = []
-
-        def push(self, item: T) -> None:
-            self.items.append(item)
-
-        def pop(self) -> T:
-            return self.items.pop()
-
-        def empty(self) -> bool:
-            return not self.items
-
-        def top(self) -> Optional[T]:
-            if len(self.items) > 0:
-                return self.items[len(self.items) - 1]
-            else:
-                return None
-
-    my_stack = Stack[str]()
-    get_type_vars = getattr(my_stack, TYPE_VAR_METHOD_NAME)
-    self.assertEqual(get_type_vars(), {T: str, TYPE_VAR_SELF: Stack})
-    with self.assertRaises(expected_exception=IndexError):
-        my_stack.pop()
-    self.assertIsNone(my_stack.top())
-    self.assertIsNone(my_stack.top())
-    # self.assertFalse(T in get_type_vars())
-    my_stack.push(item='hi')
-    self.assertTrue(T in get_type_vars())
-    my_stack.push(item='world')
-    self.assertTrue(T in get_type_vars())
-    self.assertTrue(len(get_type_vars()), 1)
-    self.assertEqual(my_stack.pop(), 'world')
-    self.assertEqual(my_stack.pop(), 'hi')
-    self.assertIsNone(my_stack.top())
-    with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-        my_stack.push(item=42)
-
-    my_other_stack = Stack[int]()
-    get_type_vars = getattr(my_other_stack, TYPE_VAR_METHOD_NAME)
-    self.assertEqual(get_type_vars(), {T: int, TYPE_VAR_SELF: Stack})
-    with self.assertRaises(expected_exception=IndexError):
-        my_other_stack.pop()
-    self.assertIsNone(my_other_stack.top())
-    self.assertIsNone(my_other_stack.top())
-    my_other_stack.push(item=100)
-    self.assertTrue(len(get_type_vars()), 1)
-    my_other_stack.push(item=142)
-    self.assertTrue(len(get_type_vars()), 1)
-    self.assertEqual(my_other_stack.pop(), 142)
-    self.assertEqual(my_other_stack.pop(), 100)
-    self.assertIsNone(my_other_stack.top())
-    with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-        my_other_stack.push(item='42')
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_main.html b/docs/pedantic/tests/tests_main.html deleted file mode 100644 index 3604caac..00000000 --- a/docs/pedantic/tests/tests_main.html +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - -pedantic.tests.tests_main API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_main

-
-
-
-
-
-
-
-
-

Functions

-
-
-def run_all_tests() ‑> None -
-
-
- -Expand source code - -
def run_all_tests() -> None:
-    test_classes_to_run = [
-        TestAssertValueMatchesType,
-        TestGenericMixin,
-        TestWithDecoratedMethods,
-        TestRequireKwargs,
-        TestClassDecorators,
-        TestContextManager,
-        TestFrozenDataclass,
-        TestPedanticClass,
-        TestDecoratorRequireKwargsAndTypeCheck,
-        TestSmallDecoratorMethods,
-        TestCombinationOfDecorators,
-        TestRequireDocstringGoogleFormat,
-        TestPedanticClassDocstring,
-        TestDecoratedFunction,
-        TestEnvironmentVariables,
-        TestGenericClasses,
-        TestGenerator,
-        TestMock,
-        TestGeneratorWrapper,
-        TestRenameKwargs,
-        TestRetry,
-        TestRetryFunc,
-        TestResolveForwardRef,
-        # validate
-        TestValidatorDatetimeIsoformat,
-        TestFlaskParameters,
-        TestParameterEnvironmentVariable,
-        TestConvertValue,
-        TestValidate,
-        TestValidatorComposite,
-        TestValidatorDatetimeUnixTimestamp,
-        TestValidatorEmail,
-        TestValidatorForEach,
-        TestValidatorIsEnum,
-        TestValidatorIsUUID,
-        TestValidatorMatchPattern,
-        TestValidatorMax,
-        TestValidatorMaxLength,
-        TestValidatorMin,
-        TestValidatorMinLength,
-        TestValidatorNotEmpty,
-
-        # async
-        AsyncValidateTests,
-        AsyncSmallDecoratorTests,
-        TestPedanticAsyncio,
-        TestInSubprocess,
-        TestAsyncContextManager,
-
-        TestPedanticPython311AddedStuff,
-    ]
-
-    loader = unittest.TestLoader()
-    suites_list = [get_doctest_test_suite()]
-
-    for test_class in test_classes_to_run:
-        suite = loader.loadTestsFromTestCase(test_class)
-        suites_list.append(suite)
-
-    big_suite = unittest.TestSuite(suites_list)
-    runner = unittest.TextTestRunner()
-    result = runner.run(big_suite)
-    assert not result.errors and not result.failures, f'Some tests failed!'
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_mock.html b/docs/pedantic/tests/tests_mock.html deleted file mode 100644 index f91a4771..00000000 --- a/docs/pedantic/tests/tests_mock.html +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - -pedantic.tests.tests_mock API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_mock

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestMock -(methodName='runTest') -
-
-
- -Expand source code - -
class TestMock(TestCase):
-    def test_mock(self) -> None:
-        @mock(return_value=42)
-        def my_function(a, b, c):
-            return a + b + c
-
-        assert my_function(1, 2, 3) == 42
-        assert my_function(100, 200, 300) == 42
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_mock(self) ‑> None -
-
-
- -Expand source code - -
def test_mock(self) -> None:
-    @mock(return_value=42)
-    def my_function(a, b, c):
-        return a + b + c
-
-    assert my_function(1, 2, 3) == 42
-    assert my_function(100, 200, 300) == 42
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_pedantic.html b/docs/pedantic/tests/tests_pedantic.html deleted file mode 100644 index 2cad9899..00000000 --- a/docs/pedantic/tests/tests_pedantic.html +++ /dev/null @@ -1,7613 +0,0 @@ - - - - - - -pedantic.tests.tests_pedantic API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_pedantic

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class Child -
-
-
- -Expand source code - -
class Child(Parent):
-    def method(self, a: int):
-        pass
-
-
-

Ancestors

- -

Methods

-
-
-def method(self, a: int) -
-
-
- -Expand source code - -
def method(self, a: int):
-    pass
-
-
-
-
-
-
-class Parent -
-
-
- -Expand source code - -
class Parent:
-    pass
-
-
-

Subclasses

- -
-
-class TestDecoratorRequireKwargsAndTypeCheck -(methodName='runTest') -
-
-
- -Expand source code - -
class TestDecoratorRequireKwargsAndTypeCheck(unittest.TestCase):
-    def tearDown(self) -> None:
-        if os.path.isfile(TEST_FILE):
-            os.remove(TEST_FILE)
-
-    def test_no_kwargs(self):
-        @pedantic
-        def calc(n: int, m: int, i: int) -> int:
-            return n + m + i
-
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            calc(42, 40, 38)
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            calc(42, m=40, i=38)
-        calc(n=42, m=40, i=38)
-
-    def test_nested_type_hints_1(self):
-        @pedantic
-        def calc(n: int) -> List[List[float]]:
-            return [0.0 * n]
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(n=42)
-
-    def test_nested_type_hints_1_corrected(self):
-        @pedantic
-        def calc(n: int) -> List[List[float]]:
-            return [[0.0 * n]]
-
-        calc(n=42)
-
-    def test_nested_type_hints_2(self):
-        """Problem here: int != float"""
-        @pedantic
-        def calc(n: int) -> List[Tuple[float, str]]:
-            return [(n, str(n))]
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(n=42)
-
-    def test_nested_type_hints_2_corrected(self):
-        @pedantic
-        def calc(n: int) -> List[Tuple[int, str]]:
-            return [(n, str(n))]
-
-        @pedantic
-        def calc_2(n: float) -> List[Tuple[float, str]]:
-            return [(n, str(n))]
-
-        calc(n=42)
-        calc_2(n=42.0)
-
-    def test_nested_type_hints_3(self):
-        """Problem here: inner function actually returns Tuple[int, str]"""
-        @pedantic
-        def calc(n: int) -> Callable[[int, float], Tuple[float, str]]:
-            @pedantic
-            def f(x: int, y: float) -> Tuple[float, str]:
-                return n * x, str(y)
-            return f
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(n=42)(x=3, y=3.14)
-
-    def test_nested_type_hints_3_corrected(self):
-        @pedantic
-        def calc(n: int) -> Callable[[int, float], Tuple[int, str]]:
-            @pedantic
-            def f(x: int, y: float) -> Tuple[int, str]:
-                return n * x, str(y)
-
-            return f
-
-        calc(n=42)(x=3, y=3.14)
-
-    def test_nested_type_hints_4(self):
-        """Problem here: return type is actually float"""
-        @pedantic
-        def calc(n: List[List[float]]) -> int:
-            return n[0][0]
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(n=[[42.0]])
-
-    def test_nested_type_hints_corrected(self):
-        @pedantic
-        def calc(n: List[List[float]]) -> int:
-            return int(n[0][0])
-
-        calc(n=[[42.0]])
-
-    def test_nested_type_hints_5(self):
-        """Problem here: Tuple[float, str] != Tuple[float, float]"""
-
-        @pedantic
-        def calc(n: int) -> Callable[[int, float], Tuple[float, str]]:
-            @pedantic
-            def f(x: int, y: float) -> Tuple[float, float]:
-                return n * float(x), y
-            return f
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(n=42)
-
-    def test_nested_type_hints_5_corrected(self):
-        @pedantic
-        def calc(n: int) -> Callable[[int, float], Tuple[float, float]]:
-            @pedantic
-            def f(x: int, y: float) -> Tuple[float, float]:
-                return n * float(x), y
-            return f
-
-        calc(n=42)
-
-    def test_missing_type_hint_1(self):
-        """Problem here: type hint for n missed"""
-        @pedantic
-        def calc(n) -> float:
-            return 42.0 * n
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(n=42)
-
-    def test_missing_type_hint_1_corrected(self):
-        @pedantic
-        def calc(n: int) -> float:
-            return 42.0 * n
-
-        calc(n=42)
-
-    def test_missing_type_hint_2(self):
-        """Problem here: Return type annotation missed"""
-        @pedantic
-        def calc(n: int):
-            return 'Hi' + str(n)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(n=42)
-
-    def test_missing_type_hint_2_corrected(self):
-        @pedantic
-        def calc(n: int) -> str:
-            return 'Hi' + str(n)
-
-        calc(n=42)
-
-    def test_missing_type_hint_3(self):
-        """Problem here: type hint for i missed"""
-        @pedantic
-        def calc(n: int, m: int, i) -> int:
-            return n + m + i
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(n=42, m=40, i=38)
-
-    def test_missing_type_hint_3_corrected(self):
-        @pedantic
-        def calc(n: int, m: int, i: int) -> int:
-            return n + m + i
-
-        calc(n=42, m=40, i=38)
-
-    def test_all_ok_2(self):
-        @pedantic
-        def calc(n: int, m: int, i: int) -> str:
-            return str(n + m + i)
-
-        calc(n=42, m=40, i=38)
-
-    def test_all_ok_3(self):
-        @pedantic
-        def calc(n: int, m: int, i: int) -> None:
-            str(n + m + i)
-
-        calc(n=42, m=40, i=38)
-
-    def test_all_ok_4(self):
-        @pedantic
-        def calc(n: int) -> List[List[int]]:
-            return [[n]]
-
-        calc(n=42)
-
-    def test_all_ok_5(self):
-        @pedantic
-        def calc(n: int) -> List[Tuple[float, str]]:
-            return [(float(n), str(n))]
-
-        calc(n=42)
-
-    def test_all_ok_6(self):
-        @pedantic
-        def calc(n: int) -> Callable[[int, float], Tuple[float, str]]:
-            @pedantic
-            def f(x: int, y: float) -> Tuple[float, str]:
-                return n * float(x), str(y)
-            return f
-
-        calc(n=42)(x=72, y=3.14)
-
-    def test_all_ok_7(self):
-        @pedantic
-        def calc(n: List[List[float]]) -> Any:
-            return n[0][0]
-
-        calc(n=[[42.0]])
-
-    def test_all_ok_8(self):
-        @pedantic
-        def calc(n: int) -> Callable[[int, float], Tuple[float, str]]:
-            @pedantic
-            def f(x: int, y: float) -> Tuple[float, str]:
-                return n * float(x), str(y)
-
-            return f
-
-        calc(n=42)(x=3, y=3.14)
-
-    def test_wrong_type_hint_1(self):
-        """Problem here: str != int"""
-        @pedantic
-        def calc(n: int, m: int, i: int) -> str:
-            return n + m + i
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(n=42, m=40, i=38)
-
-    def test_wrong_type_hint_1_corrected(self):
-        @pedantic
-        def calc(n: int, m: int, i: int) -> str:
-            return str(n + m + i)
-
-        calc(n=42, m=40, i=38)
-
-    def test_wrong_type_hint_2(self):
-        """Problem here: str != int"""
-        @pedantic
-        def calc(n: int, m: int, i: str) -> int:
-            return n + m + i
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(n=42, m=40, i=38)
-
-    def test_wrong_type_hint_2_corrected(self):
-        @pedantic
-        def calc(n: int, m: int, i: str) -> int:
-            return n + m + int(i)
-
-        calc(n=42, m=40, i='38')
-
-    def test_wrong_type_hint_3(self):
-        """Problem here: None != int"""
-        @pedantic
-        def calc(n: int, m: int, i: int) -> None:
-            return n + m + i
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(n=42, m=40, i=38)
-
-    def test_wrong_type_hint_corrected(self):
-        @pedantic
-        def calc(n: int, m: int, i: int) -> None:
-            print(n + m + i)
-
-        calc(n=42, m=40, i=38)
-
-    def test_wrong_type_hint_4(self):
-        """Problem here: None != int"""
-        @pedantic
-        def calc(n: int, m: int, i: int) -> int:
-            print(n + m + i)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(n=42, m=40, i=38)
-
-    def test_wrong_type_hint_4_corrected(self):
-        @pedantic
-        def calc(n: int, m: int, i: int) -> int:
-            return n + m + i
-
-        calc(n=42, m=40, i=38)
-
-    def test_none_1(self):
-        """Problem here: None is not accepted"""
-        @pedantic
-        def calc(n: int, m: int, i: int) -> int:
-            return n + m + i
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(n=42, m=40, i=None)
-
-    def test_none_2(self):
-        @pedantic
-        def calc(n: int, m: int, i: Optional[int]) -> int:
-            return n + m + i if i is not None else n + m
-
-        calc(n=42, m=40, i=None)
-
-    def test_none_3(self):
-        @pedantic
-        def calc(n: int, m: int, i: Union[int, None]) -> int:
-            return n + m + i if i is not None else n + m
-
-        calc(n=42, m=40, i=None)
-
-    def test_none_4(self):
-        """Problem here: function may return None"""
-        @pedantic
-        def calc(n: int, m: int, i: Union[int, None]) -> int:
-            return n + m + i if i is not None else None
-
-        calc(n=42, m=40, i=42)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(n=42, m=40, i=None)
-
-    def test_none_5(self):
-        @pedantic
-        def calc(n: int, m: int, i: Union[int, None]) -> Optional[int]:
-            return n + m + i if i is not None else None
-
-        calc(n=42, m=40, i=None)
-
-    def test_inheritance_1(self):
-        class MyClassA:
-            pass
-
-        class MyClassB(MyClassA):
-            pass
-
-        @pedantic
-        def calc(a: MyClassA) -> str:
-            return str(a)
-
-        calc(a=MyClassA())
-        calc(a=MyClassB())
-
-    def test_inheritance_2(self):
-        """Problem here: A is not a subtype of B"""
-        class MyClassA:
-            pass
-
-        class MyClassB(MyClassA):
-            pass
-
-        @pedantic
-        def calc(a: MyClassB) -> str:
-            return str(a)
-
-        calc(a=MyClassB())
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(a=MyClassA())
-
-    def test_instance_method_1(self):
-        class MyClassA:
-            @pedantic
-            def calc(self, i: int) -> str:
-                return str(i)
-
-        a = MyClassA()
-        a.calc(i=42)
-
-    def test_instance_method_2(self):
-        """Problem here: 'i' has no type annotation"""
-        class MyClassA:
-            @pedantic
-            def calc(self, i) -> str:
-                return str(i)
-
-        a = MyClassA()
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            a.calc(i=42)
-
-    def test_instance_method_2_corrected(self):
-        class MyClassA:
-            @pedantic
-            def calc(self, i: int) -> str:
-                return str(i)
-
-        a = MyClassA()
-        a.calc(i=42)
-
-    def test_instance_method_int_is_not_float(self):
-        class MyClassA:
-            @pedantic
-            def calc(self, i: float) -> str:
-                return str(i)
-
-        a = MyClassA()
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            a.calc(i=42)
-
-    def test_instance_method_3_corrected(self):
-        class MyClassA:
-            @pedantic
-            def calc(self, i: float) -> str:
-                return str(i)
-
-        a = MyClassA()
-        a.calc(i=42.0)
-
-    def test_instance_method_no_kwargs(self):
-        class MyClassA:
-            @pedantic
-            def calc(self, i: int) -> str:
-                return str(i)
-
-        a = MyClassA()
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            a.calc(42)
-
-    def test_instance_method_5(self):
-        """Problem here: instance methods is not called with kwargs"""
-        class MyClassA:
-            @pedantic
-            def calc(self, i: int) -> str:
-                return str(i)
-
-        a = MyClassA()
-        a.calc(i=42)
-
-    def test_lambda_1(self):
-        @pedantic
-        def calc(i: float) -> Callable[[float], str]:
-            return lambda x: str(x * i)
-
-        calc(i=42.0)(10.0)
-
-    def test_lambda_3(self):
-        @pedantic
-        def calc(i: float) -> Callable[[float], str]:
-            def res(x: float) -> str:
-                return str(x * i)
-            return res
-
-        calc(i=42.0)(10.0)
-
-    def test_lambda_int_is_not_float(self):
-        @pedantic
-        def calc(i: float) -> Callable[[float], str]:
-            def res(x: int) -> str:
-                return str(x * i)
-            return res
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(i=42.0)(x=10)
-
-    def test_lambda_4_almost_corrected(self):
-        """Problem here: float != str"""
-        @pedantic
-        def calc(i: float) -> Callable[[float], str]:
-            @pedantic
-            def res(x: int) -> str:
-                return str(x * i)
-            return res
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(i=42.0)(x=10)
-
-    def test_lambda_4_almost_corrected_2(self):
-        @pedantic
-        def calc(i: float) -> Callable[[int], str]:
-            @pedantic
-            def res(x: int) -> str:
-                return str(x * i)
-            return res
-
-        calc(i=42.0)(x=10)
-
-    def test_lambda_5(self):
-        """Problem here: float != int"""
-        @pedantic
-        def calc(i: float) -> Callable[[float], str]:
-            @pedantic
-            def res(x: float) -> str:
-                return str(x * i)
-            return res
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(i=42.0)(x=10)
-
-    def test_lambda_corrected(self):
-        @pedantic
-        def calc(i: float) -> Callable[[float], str]:
-            @pedantic
-            def res(x: float) -> str:
-                return str(x * i)
-
-            return res
-
-        calc(i=42.0)(x=10.0)
-
-    def test_tuple_without_type_args(self):
-        @pedantic
-        def calc(i: Tuple) -> str:
-            return str(i)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(i=(42.0, 43, 'hi'))
-
-    def test_tuple_without_args_corrected(self):
-        @pedantic
-        def calc(i: Tuple[Any, ...]) -> str:
-            return str(i)
-
-        calc(i=(42.0, 43, 'hi'))
-
-    def test_callable_without_type_args(self):
-        @pedantic
-        def calc(i: Callable) -> str:
-            return str(i(' you'))
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(i=lambda x: (42.0, 43, 'hi', x))
-
-    def test_callable_without_args_correct_with_lambdas(self):
-        @pedantic
-        def calc(i: Callable[[Any], Tuple[Any, ...]]) -> str:
-            return str(i(x=' you'))
-
-        calc(i=lambda x: (42.0, 43, 'hi', x))
-
-    def test_callable_without_args_corrected(self):
-        @pedantic
-        def calc(i: Callable[[Any], Tuple[Any, ...]]) -> str:
-            return str(i(x=' you'))
-
-        @pedantic
-        def arg(x: Any) -> Tuple[Any, ...]:
-            return 42.0, 43, 'hi', x
-        calc(i=arg)
-
-    def test_list_without_args(self):
-        @pedantic
-        def calc(i: List) -> Any:
-            return [i]
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(i=[42.0, 43, 'hi'])
-
-    def test_list_without_args_corrected(self):
-        @pedantic
-        def calc(i: List[Any]) -> List[List[Any]]:
-            return [i]
-
-        calc(i=[42.0, 43, 'hi'])
-
-    def test_ellipsis_in_callable_1(self):
-        @pedantic
-        def calc(i: Callable[..., int]) -> int:
-            return i()
-
-        @pedantic
-        def call() -> int:
-            return 42
-
-        calc(i=call)
-
-    def test_ellipsis_in_callable_2(self):
-        @pedantic
-        def calc(i: Callable[..., int]) -> int:
-            return i(x=3.14, y=5)
-
-        @pedantic
-        def call(x: float, y: int) -> int:
-            return 42
-
-        calc(i=call)
-
-    def test_ellipsis_in_callable_3(self):
-        """Problem here: call to "call" misses one argument"""
-        @pedantic
-        def calc(i: Callable[..., int]) -> int:
-            return i(x=3.14)
-
-        @pedantic
-        def call(x: float, y: int) -> int:
-            return 42
-
-        with self.assertRaises(expected_exception=PedanticException):
-            calc(i=call)
-
-    def test_optional_args_1(self):
-        @pedantic
-        def calc(a: int, b: int = 42) -> int:
-            return a + b
-
-        calc(a=2)
-
-    def test_optional_args_2(self):
-        @pedantic
-        def calc(a: int = 3, b: int = 42, c: float = 5.0) -> float:
-            return a + b + c
-
-        calc()
-        calc(a=1)
-        calc(b=1)
-        calc(c=1.0)
-        calc(a=1, b=1)
-        calc(a=1, c=1.0)
-        calc(b=1, c=1.0)
-        calc(a=1, b=1, c=1.0)
-
-    def test_optional_args_3(self):
-        """Problem here: optional argument c: 5 is not a float"""
-        @pedantic
-        def calc(a: int = 3, b: int = 42, c: float = 5) -> float:
-            return a + b + c
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc()
-
-    def test_optional_args_3_corrected(self):
-        @pedantic
-        def calc(a: int = 3, b: int = 42, c: float = 5.0) -> float:
-            return a + b + c
-
-        calc()
-
-    def test_optional_args_4(self):
-        class MyClass:
-            @pedantic
-            def foo(self, a: int, b: Optional[int] = 1) -> int:
-                return a + b
-
-        my_class = MyClass()
-        my_class.foo(a=10)
-
-    def test_optional_args_5(self):
-        @pedantic
-        def calc(d: Optional[Dict[int, int]] = None) -> Optional[int]:
-            if d is None:
-                return None
-            return sum(d.keys())
-
-        calc(d=None)
-        calc()
-        calc(d={42: 3})
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(d={42: 3.14})
-
-    def test_optional_args_6(self):
-        """"Problem here: str != int"""
-        @pedantic
-        def calc(d: int = 42) -> int:
-            return int(d)
-
-        calc(d=99999)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(d='999999')
-
-    def test_enum_1(self):
-        """Problem here: Type hint for 'a' should be MyEnum instead of MyEnum.GAMMA"""
-        class MyEnum(Enum):
-            ALPHA = 'startEvent'
-            BETA = 'task'
-            GAMMA = 'sequenceFlow'
-
-        class MyClass:
-            @pedantic
-            def operation(self, a: MyEnum.GAMMA) -> None:
-                print(a)
-
-        m = MyClass()
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.operation(a=MyEnum.GAMMA)
-
-    def test_enum_1_corrected(self):
-        class MyEnum(Enum):
-            ALPHA = 'startEvent'
-            BETA = 'task'
-            GAMMA = 'sequenceFlow'
-
-        @pedantic
-        def operation(a: MyEnum) -> None:
-            print(a)
-
-        operation(a=MyEnum.GAMMA)
-
-    def test_sloppy_types_dict(self):
-        @pedantic
-        def operation(d: dict) -> int:
-            return len(d.keys())
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            operation(d={1: 1, 2: 2})
-
-    def test_sloppy_types_dict_almost_corrected_no_type_args(self):
-        @pedantic
-        def operation(d: Dict) -> int:
-            return len(d.keys())
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            operation(d={1: 1, 2: 2})
-
-    def test_sloppy_types_dict_corrected(self):
-        @pedantic
-        def operation(d: Dict[int, int]) -> int:
-            return len(d.keys())
-
-        operation(d={1: 1, 2: 2})
-
-    def test_sloppy_types_list(self):
-        @pedantic
-        def operation(d: list) -> int:
-            return len(d)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            operation(d=[1, 2, 3, 4])
-
-    def test_sloppy_types_list_almost_corrected_no_type_args(self):
-        @pedantic
-        def operation(d: List) -> int:
-            return len(d)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            operation(d=[1, 2, 3, 4])
-
-    def test_sloppy_types_list_corrected(self):
-        @pedantic
-        def operation(d: List[int]) -> int:
-            return len(d)
-
-        operation(d=[1, 2, 3, 4])
-
-    def test_sloppy_types_tuple(self):
-        @pedantic
-        def operation(d: tuple) -> int:
-            return len(d)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            operation(d=(1, 2, 3))
-
-    def test_sloppy_types_tuple_almost_corrected_no_type_args(self):
-        @pedantic
-        def operation(d: Tuple) -> int:
-            return len(d)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            operation(d=(1, 2, 3))
-
-    def test_sloppy_types_tuple_corrected(self):
-        @pedantic
-        def operation(d: Tuple[int, int, int]) -> int:
-            return len(d)
-
-        operation(d=(1, 2, 3))
-
-    def test_sloppy_types_set(self):
-        @pedantic
-        def operation(d: set) -> int:
-            return len(d)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            operation(d={1, 2, 3})
-
-    def test_sloppy_types_set_almost_corrected_to_type_args(self):
-        @pedantic
-        def operation(d: Set) -> int:
-            return len(d)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            operation(d={1, 2, 3})
-
-    def test_sloppy_types_set_corrected(self):
-        @pedantic
-        def operation(d: Set[int]) -> int:
-            return len(d)
-
-        operation(d={1, 2, 3})
-
-    def test_sloppy_types_frozenset(self):
-        @pedantic
-        def operation(d: frozenset) -> int:
-            return len(d)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            operation(d=frozenset({1, 2, 3}))
-
-    def test_sloppy_types_frozenset_almost_corrected_no_type_args(self):
-        @pedantic
-        def operation(d: FrozenSet) -> int:
-            return len(d)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            operation(d=frozenset({1, 2, 3}))
-
-    def test_sloppy_types_frozenset_corrected(self):
-        @pedantic
-        def operation(d: FrozenSet[int]) -> int:
-            return len(d)
-
-        operation(d=frozenset({1, 2, 3}))
-
-    def test_type_list_but_got_tuple(self):
-        @pedantic
-        def calc(ls: List[Any]) -> int:
-            return len(ls)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            calc(ls=(1, 2, 3))
-
-    def test_type_list_corrected(self):
-        @pedantic
-        def calc(ls: Tuple[Any, ...]) -> int:
-            return len(ls)
-
-        calc(ls=(1, 2, 3))
-
-    def test_any(self):
-        @pedantic
-        def calc(ls: List[Any]) -> Dict[int, Any]:
-            return {i: ls[i] for i in range(0, len(ls))}
-
-        calc(ls=[1, 2, 3])
-        calc(ls=[1.11, 2.0, 3.0])
-        calc(ls=['1', '2', '3'])
-        calc(ls=[10.5, '2', (3, 4, 5)])
-
-    def test_aliases(self):
-        Vector = List[float]
-
-        @pedantic
-        def scale(scalar: float, vector: Vector) -> Vector:
-            return [scalar * num for num in vector]
-
-        scale(scalar=2.0, vector=[1.0, -4.2, 5.4])
-
-    def test_new_type(self):
-        UserId = NewType('UserId', int)
-
-        @pedantic
-        def get_user_name(user_id: UserId) -> str:
-            return str(user_id)
-
-        some_id = UserId(524313)
-        get_user_name(user_id=some_id)
-
-        # the following would be desirable but impossible to check at runtime:
-        # with self.assertRaises(expected_exception=AssertionError):
-        #     get_user_name(user_id=-1)
-
-    def test_list_of_new_type(self):
-        UserId = NewType('UserId', int)
-
-        @pedantic
-        def get_user_name(user_ids: List[UserId]) -> str:
-            return str(user_ids)
-
-        get_user_name(user_ids=[UserId(524313), UserId(42)])
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            get_user_name(user_ids=[UserId(524313), UserId(42), 430.0])
-
-    def test_callable_no_args(self):
-        @pedantic
-        def f(g: Callable[[], str]) -> str:
-            return g()
-
-        @pedantic
-        def greetings() -> str:
-            return 'hello world'
-
-        f(g=greetings)
-
-    def test_type_var(self):
-        T = TypeVar('T')
-
-        @pedantic
-        def first(ls: List[T]) -> T:
-            return ls[0]
-
-        first(ls=[1, 2, 3])
-
-    def test_type_var_wrong(self):
-        T = TypeVar('T')
-
-        @pedantic
-        def first(ls: List[T]) -> T:
-            return str(ls[0])
-
-        with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-            first(ls=[1, 2, 3])
-
-    def test_type_var_wrong_sequence(self):
-        T = TypeVar('T')
-
-        @pedantic
-        def first(ls: Sequence[T]) -> T:
-            return str(ls[0])
-
-        with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-            first(ls=[1, 2, 3])
-
-    def test_double_pedantic(self):
-        @pedantic
-        @pedantic
-        def f(x: int, y: float) -> Tuple[float, str]:
-            return float(x), str(y)
-
-        f(x=5, y=3.14)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            f(x=5.0, y=3.14)
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            f(5, 3.14)
-
-    def test_args_kwargs(self):
-        @pedantic
-        def some_method(a: int = 0, b: float = 0.0) -> float:
-            return a * b
-
-        @pedantic
-        def wrapper_method(*args: Union[int, float], **kwargs: Union[int, float]) -> float:
-            return some_method(*args, **kwargs)
-
-        some_method()
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            some_method(3, 3.0)
-        some_method(a=3, b=3.0)
-        wrapper_method()
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            wrapper_method(3, 3.0)
-        wrapper_method(a=3, b=3.0)
-
-    def test_args_kwargs_no_type_hint(self):
-        @pedantic
-        def method_no_type_hint(*args, **kwargs) -> None:
-            print(args)
-            print(kwargs)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            method_no_type_hint(a=3, b=3.0)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            method_no_type_hint()
-
-    def test_args_kwargs_wrong_type_hint(self):
-        """See: https://www.python.org/dev/peps/pep-0484/#arbitrary-argument-lists-and-default-argument-values"""
-        @pedantic
-        def wrapper_method(*args: str, **kwargs: str) -> None:
-            print(args)
-            print(kwargs)
-
-        wrapper_method()
-        wrapper_method('hi', 'you', ':)')
-        wrapper_method(a='hi', b='you', c=':)')
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            wrapper_method('hi', 'you', ':)', 7)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            wrapper_method(3, 3.0)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            wrapper_method(a=3, b=3.0)
-
-    def test_additional_kwargs(self):
-        @pedantic
-        def some_method(a: int, b: float = 0.0, **kwargs: int) -> float:
-            return sum([a, b])
-
-        some_method(a=5)
-        some_method(a=5, b=0.1)
-        some_method(a=5, b=0.1, c=4)
-        some_method(a=5, b=0.1, c=4, d=5, e=6)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            some_method(a=5, b=0.1, c=4, d=5.0, e=6)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            some_method(a=5.0, b=0.1, c=4, d=5, e=6)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            some_method(a=5, b=0, c=4, d=5, e=6)
-
-    def test_args_kwargs_different_types(self):
-        @pedantic
-        def foo(*args: str, **kwds: int) -> None:
-            print(args)
-            print(kwds)
-
-        foo('a', 'b', 'c')
-        foo(x=1, y=2)
-        foo('', z=0)
-
-    def test_pedantic_on_class(self):
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            @pedantic
-            class MyClass:
-                pass
-            MyClass()
-
-    def test_is_subtype_tuple(self):
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            @pedantic
-            def foo() -> Callable[[Tuple[float, str]], Tuple[int]]:
-                def bar(a: Tuple[float]) -> Tuple[int]:
-                    return len(a[1]) + int(a[0]),
-                return bar
-            foo()
-
-    def test_is_subtype_tuple_corrected(self):
-        @pedantic
-        def foo() -> Callable[[Tuple[float, str]], Tuple[int]]:
-            def bar(a: Tuple[float, str]) -> Tuple[int]:
-                return len(a[1]) + int(a[0]),
-            return bar
-        foo()
-
-    def test_forward_ref(self):
-        class Conversation:
-            pass
-
-        @pedantic
-        def get_conversations() -> List['Conversation']:
-            return [Conversation(), Conversation()]
-
-        get_conversations()
-
-    def test_alternative_list_type_hint(self):
-        @pedantic
-        def _is_digit_in_int(digit: [int], num: int) -> bool:
-            num_str = str(num)
-            for i in num_str:
-                if int(i) == digit:
-                    return True
-            return False
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            _is_digit_in_int(digit=4, num=42)
-
-    def test_callable_with_union_return(self):
-        class MyClass:
-            pass
-
-        @pedantic
-        def admin_required(func: Callable[..., Union[str, MyClass]]) -> Callable[..., Union[str, MyClass]]:
-            @wraps(func)
-            def decorated_function(*args, **kwargs):
-                return func(*args, **kwargs)
-            return decorated_function
-
-        @admin_required
-        @pedantic
-        def get_server_info() -> str:
-            return 'info'
-
-        get_server_info()
-
-    def test_pedantic(self):
-        @pedantic
-        def foo(a: int, b: str) -> str:
-            return 'abc'
-
-        self.assertEqual('abc', foo(a=4, b='abc'))
-
-    def test_pedantic_always(self):
-        @pedantic
-        def foo(a: int, b: str) -> str:
-            return 'abc'
-
-        self.assertEqual('abc', foo(a=4, b='abc'))
-
-    def test_pedantic_arguments_fail(self):
-        @pedantic
-        def foo(a: int, b: str) -> str:
-            return 'abc'
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            foo(a=4, b=5)
-
-    def test_pedantic_return_type_fail(self):
-        @pedantic
-        def foo(a: int, b: str) -> str:
-            return 6
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            foo(a=4, b='abc')
-
-    def test_return_type_none(self):
-        @pedantic
-        def foo() -> None:
-            return 'a'
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            foo()
-
-    def test_marco(self):
-        @pedantic_class
-        class A:
-            def __init__(self, val: int) -> None:
-                self.val = val
-
-            def __eq__(self, other: 'A') -> bool:  # other: A and all subclasses
-                return self.val == other.val
-
-        @pedantic_class
-        class B(A):
-            def __init__(self, val: int) -> None:
-                super().__init__(val=val)
-
-        @pedantic_class
-        class C(A):
-            def __init__(self, val: int) -> None:
-                super().__init__(val=val)
-
-        a = A(val=42)
-        b = B(val=42)
-        c = C(val=42)
-
-        assert a == b  # works
-        assert a == c  # works
-        assert b == c  # error
-
-    def test_date_datetime(self):
-        @pedantic
-        def foo(a: datetime, b: date) -> None:
-            pass
-
-        foo(a=datetime(1995, 2, 5), b=date(1987, 8, 7))
-        foo(a=datetime(1995, 2, 5), b=datetime(1987, 8, 7))
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            foo(a=date(1995, 2, 5), b=date(1987, 8, 7))
-
-    def test_any_type(self):
-        @pedantic
-        def foo(a: Any) -> None:
-            pass
-
-        foo(a='aa')
-
-    def test_callable_exact_arg_count(self):
-        @pedantic
-        def foo(a: Callable[[int, str], int]) -> None:
-            pass
-
-        def some_callable(x: int, y: str) -> int:
-            pass
-
-        foo(a=some_callable)
-
-    def test_callable_bad_type(self):
-        @pedantic
-        def foo(a: Callable[..., int]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=5)
-
-    def test_callable_too_few_arguments(self):
-        @pedantic
-        def foo(a: Callable[[int, str], int]) -> None:
-            pass
-
-        def some_callable(x: int) -> int:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=some_callable)
-
-    def test_callable_mandatory_kwonlyargs(self):
-        @pedantic
-        def foo(a: Callable[[int, str], int]) -> None:
-            pass
-
-        def some_callable(x: int, y: str, *, z: float, bar: str) -> int:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=some_callable)
-
-    def test_callable_class(self):
-        """
-        Test that passing a class as a callable does not count the "self" argument "a"gainst the
-        ones declared in the Callable specification.
-
-        """
-        @pedantic
-        def foo(a: Callable[[int, str], Any]) -> None:
-            pass
-
-        class SomeClass:
-            def __init__(self, x: int, y: str):
-                pass
-
-        foo(a=SomeClass)
-
-    def test_callable_plain(self):
-        @pedantic
-        def foo(a: Callable[..., Any]) -> None:
-            pass
-
-        def callback(a):
-            pass
-
-        foo(a=callback)
-
-    def test_callable_bound_method(self):
-        @pedantic
-        def foo(callback: Callable[[int], Any]) -> None:
-            pass
-
-        foo(callback=Child().method)
-
-    def test_callable_defaults(self):
-        """
-        Test that a callable having "too many" arguments don't raise an error if the extra
-        arguments have default values.
-
-        """
-        @pedantic
-        def foo(callback: Callable[[int, str], Any]) -> None:
-            pass
-
-        def some_callable(x: int, y: str, z: float = 1.2) -> int:
-            pass
-
-        foo(callback=some_callable)
-
-    def test_callable_builtin(self):
-        @pedantic
-        def foo(callback: types.BuiltinFunctionType) -> None:
-            pass
-
-        foo(callback=[].append)
-
-    def test_dict_bad_type(self):
-        @pedantic
-        def foo(a: Dict[str, int]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=5)
-
-    def test_dict_bad_key_type(self):
-        @pedantic
-        def foo(a: Dict[str, int]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a={1: 2})
-
-    def test_dict_bad_value_type(self):
-        @pedantic
-        def foo(a: Dict[str, int]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a={'x': 'a'})
-
-    def test_list_bad_type(self):
-        @pedantic
-        def foo(a: List[int]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=5)
-
-    def test_list_bad_element(self):
-        @pedantic
-        def foo(a: List[int]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=[1, 2, 'bb'])
-
-    def test_sequence_bad_type(self):
-        @pedantic
-        def foo(a: Sequence[int]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=5)
-
-    def test_sequence_bad_element(self):
-        @pedantic
-        def foo(a: Sequence[int]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=[1, 2, 'bb'])
-
-    def test_abstractset_custom_type(self):
-        T = TypeVar('T')
-
-        @pedantic_class
-        class DummySet(AbstractSet[T]):
-            def __contains__(self, x: object) -> bool:
-                return x == 1
-
-            def __len__(self) -> T:
-                return 1
-
-            def __iter__(self) -> Iterator[T]:
-                yield 1
-
-        @pedantic
-        def foo(a: AbstractSet[int]) -> None:
-            pass
-
-        foo(a=DummySet[int]())
-
-    def test_abstractset_bad_type(self):
-        @pedantic
-        def foo(a: AbstractSet[int]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=5)
-
-    def test_set_bad_type(self):
-        @pedantic
-        def foo(a: Set[int]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=5)
-
-    def test_abstractset_bad_element(self):
-        @pedantic
-        def foo(a: AbstractSet[int]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a={1, 2, 'bb'})
-
-    def test_set_bad_element(self):
-        @pedantic
-        def foo(a: Set[int]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a={1, 2, 'bb'})
-
-    def test_tuple_bad_type(self):
-        @pedantic
-        def foo(a: Tuple[int]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=5)
-
-    def test_tuple_too_many_elements(self):
-        @pedantic
-        def foo(a: Tuple[int, str]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=(1, 'aa', 2))
-
-    def test_tuple_too_few_elements(self):
-        @pedantic
-        def foo(a: Tuple[int, str]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=(1,))
-
-    def test_tuple_bad_element(self):
-        @pedantic
-        def foo(a: Tuple[int, str]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=(1, 2))
-
-    def test_tuple_ellipsis_bad_element(self):
-        @pedantic
-        def foo(a: Tuple[int, ...]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=(1, 2, 'blah'))
-
-    def test_namedtuple(self):
-        Employee = NamedTuple('Employee', [('name', str), ('id', int)])
-
-        @pedantic
-        def foo(bar: Employee) -> None:
-            print(bar)
-
-        foo(bar=Employee('bob', 1))
-
-    def test_namedtuple_key_mismatch(self):
-        Employee1 = NamedTuple('Employee', [('name', str), ('id', int)])
-        Employee2 = NamedTuple('Employee', [('firstname', str), ('id', int)])
-
-        @pedantic
-        def foo(bar: Employee1) -> None:
-            print(bar)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(bar=Employee2('bob', 1))
-
-    def test_namedtuple_type_mismatch(self):
-        Employee = NamedTuple('Employee', [('name', str), ('id', int)])
-
-        @pedantic
-        def foo(bar: Employee) -> None:
-            print(bar)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(bar=('bob', 1))
-
-    def test_namedtuple_huge_type_mismatch(self):
-        Employee = NamedTuple('Employee', [('name', str), ('id', int)])
-
-        @pedantic
-        def foo(bar: int) -> None:
-            print(bar)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(bar=foo(bar=Employee('bob', 1)))
-
-    def test_namedtuple_wrong_field_type(self):
-        Employee = NamedTuple('Employee', [('name', str), ('id', int)])
-
-        @pedantic
-        def foo(bar: Employee) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(bar=Employee(2, 1))
-
-    def test_union(self):
-        @pedantic
-        def foo(a: Union[str, int]) -> None:
-            pass
-
-        for value in [6, 'xa']:
-            foo(a=value)
-
-    def test_union_new_syntax(self):
-        @pedantic
-        def foo(a: str | int) -> None:
-            pass
-
-        for value in [6, 'xa']:
-            foo(a=value)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=1.7)
-
-    def test_union_typing_type(self):
-        @pedantic
-        def foo(a: Union[str, Collection]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=1)
-
-    def test_union_fail(self):
-        @pedantic
-        def foo(a: Union[str, int]) -> None:
-            pass
-
-        for value in [5.6, b'xa']:
-            with self.assertRaises(PedanticTypeCheckException):
-                foo(a=value)
-
-    def test_type_var_constraints(self):
-        T = TypeVar('T', int, str)
-
-        @pedantic
-        def foo(a: T, b: T) -> None:
-            pass
-
-        for values in [
-            {'a': 6, 'b': 7},
-            {'a': 'aa', 'b': "bb"},
-        ]:
-            foo(**values)
-
-    def test_type_var_constraints_fail_typing_type(self):
-        T = TypeVar('T', int, Collection)
-
-        @pedantic
-        def foo(a: T, b: T) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a='aa', b='bb')
-
-    def test_typevar_constraints_fail(self):
-        T = TypeVar('T', int, str)
-
-        @pedantic
-        def foo(a: T, b: T) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=2.5, b='aa')
-
-    def test_typevar_bound(self):
-        T = TypeVar('T', bound=Parent)
-
-        @pedantic
-        def foo(a: T, b: T) -> None:
-            pass
-
-        foo(a=Child(), b=Child())
-
-    def test_type_var_bound_fail(self):
-        T = TypeVar('T', bound=Child)
-
-        @pedantic
-        def foo(a: T, b: T) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=Parent(), b=Parent())
-
-    def test_type_var_invariant_fail(self):
-        T = TypeVar('T', int, str)
-
-        @pedantic
-        def foo(a: T, b: T) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=2, b=3.6)
-
-    def test_type_var_covariant(self):
-        T = TypeVar('T', covariant=True)
-
-        @pedantic
-        def foo(a: T, b: T) -> None:
-            pass
-
-        foo(a=Parent(), b=Child())
-
-    def test_type_var_covariant_fail(self):
-        T = TypeVar('T', covariant=True)
-
-        @pedantic
-        def foo(a: T, b: T) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeVarMismatchException):
-            foo(a=Child(), b=Parent())
-
-    def test_type_var_contravariant(self):
-        T = TypeVar('T', contravariant=True)
-
-        @pedantic
-        def foo(a: T, b: T) -> None:
-            pass
-
-        foo(a=Child(), b=Parent())
-
-    def test_type_var_contravariant_fail(self):
-        T = TypeVar('T', contravariant=True)
-
-        @pedantic
-        def foo(a: T, b: T) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeVarMismatchException):
-            foo(a=Parent(), b=Child())
-
-    def test_class_bad_subclass(self):
-        @pedantic
-        def foo(a: Type[Child]) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=Parent)
-
-    def test_class_any(self):
-        @pedantic
-        def foo(a: Type[Any]) -> None:
-            pass
-
-        foo(a=str)
-
-    def test_wrapped_function(self):
-        def decorator(func):
-            @wraps(func)
-            def wrapper(*args, **kwargs):
-                return func(*args, **kwargs)
-            return wrapper
-
-        @pedantic
-        @decorator
-        def foo(a: 'Child') -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=Parent())
-
-    def test_mismatching_default_type(self):
-        @pedantic
-        def foo(a: str = 1) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo()
-
-    def test_implicit_default_none(self):
-        """
-        Test that if the default value is ``None``, a ``None`` argument can be passed.
-
-        """
-        @pedantic
-        def foo(a: Optional[str] = None) -> None:
-            pass
-
-        foo()
-
-    def test_generator_simple(self):
-        """Test that argument type checking works in a generator function too."""
-        @pedantic
-        def generate(a: int) -> Generator[int, int, None]:
-            yield a
-            yield a + 1
-
-        gen = generate(a=1)
-        next(gen)
-
-    def test_wrapped_generator_no_return_type_annotation(self):
-        """Test that return type checking works in a generator function too."""
-        @pedantic
-        def generate(a: int) -> Generator[int, int, None]:
-            yield a
-            yield a + 1
-
-        gen = generate(a=1)
-        next(gen)
-
-    def test_varargs(self):
-        @pedantic
-        def foo(*args: int) -> None:
-            pass
-
-        foo(1, 2)
-
-    def test_varargs_fail(self):
-        @pedantic
-        def foo(*args: int) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(1, 'a')
-
-    def test_kwargs(self):
-        @pedantic
-        def foo(**kwargs: int) -> None:
-            pass
-
-        foo(a=1, b=2)
-
-    def test_kwargs_fail(self):
-        @pedantic
-        def foo(**kwargs: int) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=1, b='a')
-
-    def test_generic(self):
-        T_Foo = TypeVar('T_Foo')
-
-        class FooGeneric(Generic[T_Foo]):
-            pass
-
-        @pedantic
-        def foo(a: FooGeneric[str]) -> None:
-            print(a)
-
-        foo(a=FooGeneric[str]())
-
-    def test_newtype(self):
-        myint = NewType("myint", int)
-
-        @pedantic
-        def foo(a: myint) -> int:
-            return 42
-
-        assert foo(a=1) == 42
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a="a")
-
-    def test_collection(self):
-        @pedantic
-        def foo(a: Collection) -> None:
-            pass
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=True)
-
-    def test_binary_io(self):
-        @pedantic
-        def foo(a: BinaryIO) -> None:
-            print(a)
-
-        foo(a=BytesIO())
-
-    def test_text_io(self):
-        @pedantic
-        def foo(a: TextIO) -> None:
-            print(a)
-
-        foo(a=StringIO())
-
-    def test_binary_io_fail(self):
-        @pedantic
-        def foo(a: TextIO) -> None:
-            print(a)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=BytesIO())
-
-    def test_text_io_fail(self):
-        @pedantic
-        def foo(a: BinaryIO) -> None:
-            print(a)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=StringIO())
-
-    def test_binary_io_real_file(self):
-        @pedantic
-        def foo(a: BinaryIO) -> None:
-            print(a)
-
-        with open(file=TEST_FILE, mode='wb') as f:
-            foo(a=f)
-
-    def test_text_io_real_file(self):
-        @pedantic
-        def foo(a: TextIO) -> None:
-            print(a)
-
-        with open(file=TEST_FILE, mode='w') as f:
-            foo(a=f)
-
-    def test_pedantic_return_type_var_fail(self):
-        T = TypeVar('T', int, float)
-
-        @pedantic
-        def foo(a: T, b: T) -> T:
-            return 'a'
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=4, b=2)
-
-    def test_callable(self):
-        @pedantic
-        def foo_1(a: Callable[..., int]) -> None:
-            print(a)
-
-        @pedantic
-        def foo_2(a: Callable) -> None:
-            print(a)
-
-        def some_callable() -> int:
-            return 4
-
-        foo_1(a=some_callable)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo_2(a=some_callable)
-
-    def test_list(self):
-        @pedantic
-        def foo_1(a: List[int]) -> None:
-            print(a)
-
-        @pedantic
-        def foo_2(a: List) -> None:
-            print(a)
-
-        @pedantic
-        def foo_3(a: list) -> None:
-            print(a)
-
-        @pedantic
-        def foo_4(a: list[int]) -> None:
-            print(a)
-
-        foo_1(a=[1, 2])
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo_2(a=[1, 2])
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo_3(a=[1, 2])
-
-
-        foo_4(a=[1, 2])
-
-    def test_dict(self):
-        @pedantic
-        def foo_1(a: Dict[str, int]) -> None:
-            print(a)
-
-        @pedantic
-        def foo_2(a: Dict) -> None:
-            print(a)
-
-        @pedantic
-        def foo_3(a: dict) -> None:
-            print(a)
-
-        @pedantic
-        def foo_4(a: dict[str, int]) -> None:
-            print(a)
-
-        foo_1(a={'x': 2})
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo_2(a={'x': 2})
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo_3(a={'x': 2})
-
-        foo_4(a={'x': 2})
-
-    def test_sequence(self):
-        @pedantic
-        def foo(a: Sequence[str]) -> None:
-            print(a)
-
-        for value in [('a', 'b'), ['a', 'b'], 'abc']:
-            foo(a=value)
-
-    def test_sequence_no_type_args(self):
-        @pedantic
-        def foo(a: Sequence) -> None:
-            print(a)
-
-        for value in [('a', 'b'), ['a', 'b'], 'abc']:
-            with self.assertRaises(PedanticTypeCheckException):
-                foo(a=value)
-
-    def test_iterable(self):
-        @pedantic
-        def foo(a: Iterable[str]) -> None:
-            print(a)
-
-        for value in [('a', 'b'), ['a', 'b'], 'abc']:
-            foo(a=value)
-
-    def test_iterable_no_type_args(self):
-        @pedantic
-        def foo(a: Iterable) -> None:
-            print(a)
-
-        for value in [('a', 'b'), ['a', 'b'], 'abc']:
-            with self.assertRaises(PedanticTypeCheckException):
-                foo(a=value)
-
-    def test_container(self):
-        @pedantic
-        def foo(a: Container[str]) -> None:
-            print(a)
-
-        for value in [('a', 'b'), ['a', 'b'], 'abc']:
-            foo(a=value)
-
-    def test_container_no_type_args(self):
-        @pedantic
-        def foo(a: Container) -> None:
-            print(a)
-
-        for value in [('a', 'b'), ['a', 'b'], 'abc']:
-            with self.assertRaises(PedanticTypeCheckException):
-                foo(a=value)
-
-    def test_set(self):
-        @pedantic
-        def foo_1(a: AbstractSet[int]) -> None:
-            print(a)
-
-        @pedantic
-        def foo_2(a: Set[int]) -> None:
-            print(a)
-
-        for value in [set(), {6}]:
-            foo_1(a=value)
-            foo_2(a=value)
-
-    def test_set_no_type_args(self):
-        @pedantic
-        def foo_1(a: AbstractSet) -> None:
-            print(a)
-
-        @pedantic
-        def foo_2(a: Set) -> None:
-            print(a)
-
-        @pedantic
-        def foo_3(a: set) -> None:
-            print(a)
-
-        for value in [set(), {6}]:
-            with self.assertRaises(PedanticTypeCheckException):
-                foo_1(a=value)
-
-            with self.assertRaises(PedanticTypeCheckException):
-                foo_2(a=value)
-
-            with self.assertRaises(PedanticTypeCheckException):
-                foo_3(a=value)
-
-    def test_tuple(self):
-        @pedantic
-        def foo_1(a: Tuple[int, int]) -> None:
-            print(a)
-
-        @pedantic
-        def foo_2(a: Tuple[int, ...]) -> None:
-            print(a)
-
-        foo_1(a=(1, 2))
-        foo_2(a=(1, 2))
-
-    def test_tuple_no_type_args(self):
-        @pedantic
-        def foo_1(a: Tuple) -> None:
-            print(a)
-
-        @pedantic
-        def foo_2(a: tuple) -> None:
-            print(a)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo_1(a=(1, 2))
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo_2(a=(1, 2))
-
-    def test_empty_tuple(self):
-        @pedantic
-        def foo(a: Tuple[()]) -> None:
-            print(a)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=())
-
-    def test_class(self):
-        @pedantic
-        def foo_1(a: Type[Parent]) -> None:
-            print(a)
-
-        @pedantic
-        def foo_2(a: Type[TypeVar('UnboundType')]) -> None:
-            print(a)
-
-        @pedantic
-        def foo_3(a: Type[TypeVar('BoundType', bound=Parent)]) -> None:
-            print(a)
-
-        foo_1(a=Child)
-        foo_2(a=Child)
-        foo_3(a=Child)
-
-    def test_class_no_type_vars(self):
-        @pedantic
-        def foo_1(a: Type) -> None:
-            print(a)
-
-        @pedantic
-        def foo_2(a: type) -> None:
-            print(a)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo_1(a=Child)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo_2(a=Child)
-
-    def test_class_not_a_class(self):
-        @pedantic
-        def foo(a: Type[Parent]) -> None:
-            print(a)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=1)
-
-    def test_complex(self):
-        @pedantic
-        def foo(a: complex) -> None:
-            print(a)
-
-        foo(a=complex(1, 5))
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=1.0)
-
-    def test_float(self):
-        @pedantic
-        def foo(a: float) -> None:
-            print(a)
-
-        foo(a=1.5)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=1)
-
-    def test_coroutine_correct_return_type(self):
-        @pedantic
-        async def foo() -> str:
-            return 'foo'
-
-        coro = foo()
-
-        with self.assertRaises(StopIteration):
-            coro.send(None)
-
-    def test_coroutine_wrong_return_type(self):
-        @pedantic
-        async def foo() -> str:
-            return 1
-
-        coro = foo()
-
-        with self.assertRaises(PedanticTypeCheckException):
-            coro.send(None)
-
-    def test_bytearray_bytes(self):
-        @pedantic
-        def foo(x: bytearray) -> None:
-            pass
-
-        foo(x=bytearray([1]))
-
-    def test_class_decorator(self):
-        @pedantic_class
-        class Foo:
-            @staticmethod
-            def staticmethod() -> int:
-                return 'foo'
-
-            @classmethod
-            def classmethod(cls) -> int:
-                return 'foo'
-
-            def method(self) -> int:
-                return 'foo'
-
-        with self.assertRaises(PedanticTypeCheckException):
-            Foo.staticmethod()
-
-        with self.assertRaises(PedanticTypeCheckException):
-            Foo.classmethod()
-
-        with self.assertRaises(PedanticTypeCheckException):
-            Foo().method()
-
-    def test_generator(self):
-        @pedantic
-        def genfunc() -> Generator[int, str, List[str]]:
-            val1 = yield 2
-            val2 = yield 3
-            val3 = yield 4
-            return [val1, val2, val3]
-
-        gen = genfunc()
-
-        with self.assertRaises(StopIteration):
-            value = next(gen)
-            while True:
-                value = gen.send(str(value))
-                assert isinstance(value, int)
-
-    def test_generator_no_type_args(self):
-        @pedantic
-        def genfunc() -> Generator:
-            val1 = yield 2
-            val2 = yield 3
-            val3 = yield 4
-            return [val1, val2, val3]
-
-        with self.assertRaises(PedanticTypeCheckException):
-            genfunc()
-
-    def test_iterator(self):
-        @pedantic
-        def genfunc() -> Iterator[int]:
-            val1 = yield 2
-            val2 = yield 3
-            val3 = yield 4
-            return [val1, val2, val3]
-
-        gen = genfunc()
-
-        with self.assertRaises(PedanticTypeCheckException):
-            value = next(gen)
-            while True:
-                value = gen.send(str(value))
-                assert isinstance(value, int)
-
-    def test_iterator_no_type_args(self):
-        @pedantic
-        def genfunc() -> Iterator:
-            val1 = yield 2
-            val2 = yield 3
-            val3 = yield 4
-            return [val1, val2, val3]
-
-        with self.assertRaises(PedanticTypeCheckException):
-            genfunc()
-
-    def test_iterable_advanced(self):
-        @pedantic
-        def genfunc() -> Iterable[int]:
-            val1 = yield 2
-            val2 = yield 3
-            val3 = yield 4
-            return [val1, val2, val3]
-
-        gen = genfunc()
-
-        with self.assertRaises(PedanticTypeCheckException):
-            value = next(gen)
-            while True:
-                value = gen.send(str(value))
-                assert isinstance(value, int)
-
-    def test_iterable_advanced_no_type_args(self):
-        @pedantic
-        def genfunc() -> Iterable:
-            val1 = yield 2
-            val2 = yield 3
-            val3 = yield 4
-            return [val1, val2, val3]
-
-        with self.assertRaises(PedanticTypeCheckException):
-            genfunc()
-
-    def test_generator_bad_yield(self):
-        @pedantic
-        def genfunc_1() -> Generator[int, str, None]:
-            yield 'foo'
-
-        @pedantic
-        def genfunc_2() -> Iterable[int]:
-            yield 'foo'
-
-        @pedantic
-        def genfunc_3() -> Iterator[int]:
-            yield 'foo'
-
-        gen = genfunc_1()
-
-        with self.assertRaises(PedanticTypeCheckException):
-            next(gen)
-
-        gen = genfunc_2()
-
-        with self.assertRaises(PedanticTypeCheckException):
-            next(gen)
-
-        gen = genfunc_3()
-
-        with self.assertRaises(PedanticTypeCheckException):
-            next(gen)
-
-    def test_generator_bad_send(self):
-        @pedantic
-        def genfunc() -> Generator[int, str, None]:
-            yield 1
-            yield 2
-
-        gen = genfunc()
-        next(gen)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            gen.send(2)
-
-    def test_generator_bad_return(self):
-        @pedantic
-        def genfunc() -> Generator[int, str, str]:
-            yield 1
-            return 6
-
-        gen = genfunc()
-        next(gen)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            gen.send('foo')
-
-    def test_return_generator(self):
-        @pedantic
-        def genfunc() -> Generator[int, None, None]:
-            yield 1
-
-        @pedantic
-        def foo() -> Generator[int, None, None]:
-            return genfunc()
-
-        foo()
-
-    def test_local_class(self):
-        @pedantic_class
-        class LocalClass:
-            class Inner:
-                pass
-
-            def create_inner(self) -> 'Inner':
-                return self.Inner()
-
-        retval = LocalClass().create_inner()
-        assert isinstance(retval, LocalClass.Inner)
-
-    def test_local_class_async(self):
-        @pedantic_class
-        class LocalClass:
-            class Inner:
-                pass
-
-            async def create_inner(self) -> 'Inner':
-                return self.Inner()
-
-        coro = LocalClass().create_inner()
-
-        with self.assertRaises(StopIteration):
-            coro.send(None)
-
-    def test_callable_nonmember(self):
-        class CallableClass:
-            def __call__(self):
-                pass
-
-        @pedantic_class
-        class LocalClass:
-            some_callable = CallableClass()
-
-    def test_inherited_class_method(self):
-        @pedantic_class
-        class Parent:
-            @classmethod
-            def foo(cls, x: str) -> str:
-                return cls.__name__
-
-        @pedantic_class
-        class Child(Parent):
-            pass
-
-        self.assertEqual('Parent', Child.foo(x='bar'))
-
-        with self.assertRaises(PedanticTypeCheckException):
-            Child.foo(x=1)
-
-    def test_type_var_forward_ref_bound(self):
-        TBound = TypeVar('TBound', bound='Parent')
-
-        @pedantic
-        def func(x: TBound) -> None:
-            pass
-
-        func(x=Parent())
-
-        with self.assertRaises(PedanticTypeCheckException):
-            func(x='foo')
-
-    def test_noreturn(self):
-        @pedantic
-        def foo() -> NoReturn:
-            pass
-
-        @pedantic
-        def bar() -> NoReturn:
-            raise ZeroDivisionError('bar')
-
-        with self.assertRaises(expected_exception=ZeroDivisionError):
-            bar()
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo()
-
-    def test_literal(self):
-        @pedantic
-        def foo(a: Literal[1, True, 'x', b'y', 404]) -> None:
-            print(a)
-
-        foo(a=404)
-        foo(a=True)
-        foo(a='x')
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=4)
-
-    def test_literal_union(self):
-        @pedantic
-        def foo(a: Union[str, Literal[1, 6, 8]]) -> None:
-            print(a)
-
-        foo(a=6)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=4)
-
-    def test_literal_illegal_value(self):
-        @pedantic
-        def foo(a: Literal[1, 1.1]) -> None:
-            print(a)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=4)
-
-    def test_enum(self):
-        with self.assertRaises(PedanticTypeCheckException):
-            @pedantic_class
-            class MyEnum(Enum):
-                A = 'a'
-
-    def test_enum_aggregate(self):
-        T = TypeVar('T', bound=IntEnum)
-
-        @pedantic_class
-        class EnumAggregate(Generic[T]):
-            enum: ClassVar[Type[T]]
-
-            def __init__(self, value: Union[int, str, List[T]]) -> None:
-                assert len(self.enum) < 10
-
-                if value == '':
-                    raise ValueError(f'Parameter "value" cannot be empty!')
-
-                if isinstance(value, list):
-                    self._value = ''.join([str(x.value) for x in value])
-                else:
-                    self._value = str(value)
-
-                self._value = ''.join(sorted(self._value))  # sort characters in string
-                self.to_list()  # check if is valid
-
-            def __contains__(self, item: T) -> bool:
-                return item in self.to_list()
-
-            def __eq__(self, other: Union['EnumAggregate', str]) -> bool:
-                if isinstance(other, str):
-                    return self._value == other
-
-                return self._value == other._value
-
-            def __str__(self) -> str:
-                return self._value
-
-            def to_list(self) -> List[T]:
-                return [self.enum(int(character)) for character in self._value]
-
-            @property
-            def value(self) -> str:
-                return self._value
-
-            @classmethod
-            def all(cls) -> str:
-                return ''.join([str(x.value) for x in cls.enum])
-
-        class Gender(IntEnum):
-            MALE = 1
-            FEMALE = 2
-            DIVERS = 3
-
-        @pedantic_class
-        class Genders(EnumAggregate[Gender]):
-            enum = Gender
-
-        Genders(value=12)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            Genders(value=Child())
-
-    def test_primitive_list_dict_tuple(self):
-        @pedantic
-        def f(x: list[dict[int, tuple[float, str]]]) -> list[Any]:
-            return x
-
-        f(x=[{3: (3.24, 'hi')}])
-
-        for value in [
-            [{3, (3, 'hi')}],
-            [{3: (3, 'hi')}],
-            [{3: (3.24, 3)}],
-            [{3: (3.24, 'hi')}, {0}],
-        ]:
-            with self.assertRaises(PedanticTypeCheckException):
-                f(x=value)
-
-    def test_dataclass_protocol(self):
-        class IsDataclass(typing.Protocol):
-            __dataclass_fields__: ClassVar[Dict]
-
-        @dataclass
-        class Foo:
-            v: int
-
-        @pedantic
-        def foo(x: IsDataclass) -> IsDataclass:
-            return x
-
-        foo(x=Foo(v=42))
-
-    def test_dataclass_protocol_in_type(self):
-        class IsDataclass(typing.Protocol):
-            __dataclass_fields__: ClassVar[Dict]
-
-        @dataclass
-        class Foo:
-            v: int
-
-        @pedantic
-        def foo(x: type[IsDataclass]) -> IsDataclass:
-            return x
-
-        assert foo(x=Foo) == Foo
-
-    def test_dataclass_protocol_in_type_with_union(self):
-        class IsDataclass(typing.Protocol):
-            __dataclass_fields__: ClassVar[Dict]
-
-        @dataclass
-        class Foo:
-            v: int
-
-        @pedantic
-        def foo(x: type[None | bool | IsDataclass]) -> IsDataclass:
-            return x
-
-        assert foo(x=Foo) == Foo
-
-    def test_partial_function(self):
-        @pedantic
-        def f(a: int, b: int) -> int:
-            return a + b
-
-        g = pedantic(partial(f, a=1))
-
-        assert f(a=2, b=3) == 5
-        assert g(b=3) == 4
-
-        with self.assertRaises(PedanticTypeCheckException):
-            f(a='2', b=3)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            g(b='2')
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def tearDown(self) ‑> None -
-
-
- -Expand source code - -
def tearDown(self) -> None:
-    if os.path.isfile(TEST_FILE):
-        os.remove(TEST_FILE)
-
-

Hook method for deconstructing the test fixture after testing it.

-
-
-def test_abstractset_bad_element(self) -
-
-
- -Expand source code - -
def test_abstractset_bad_element(self):
-    @pedantic
-    def foo(a: AbstractSet[int]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a={1, 2, 'bb'})
-
-
-
-
-def test_abstractset_bad_type(self) -
-
-
- -Expand source code - -
def test_abstractset_bad_type(self):
-    @pedantic
-    def foo(a: AbstractSet[int]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=5)
-
-
-
-
-def test_abstractset_custom_type(self) -
-
-
- -Expand source code - -
def test_abstractset_custom_type(self):
-    T = TypeVar('T')
-
-    @pedantic_class
-    class DummySet(AbstractSet[T]):
-        def __contains__(self, x: object) -> bool:
-            return x == 1
-
-        def __len__(self) -> T:
-            return 1
-
-        def __iter__(self) -> Iterator[T]:
-            yield 1
-
-    @pedantic
-    def foo(a: AbstractSet[int]) -> None:
-        pass
-
-    foo(a=DummySet[int]())
-
-
-
-
-def test_additional_kwargs(self) -
-
-
- -Expand source code - -
def test_additional_kwargs(self):
-    @pedantic
-    def some_method(a: int, b: float = 0.0, **kwargs: int) -> float:
-        return sum([a, b])
-
-    some_method(a=5)
-    some_method(a=5, b=0.1)
-    some_method(a=5, b=0.1, c=4)
-    some_method(a=5, b=0.1, c=4, d=5, e=6)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        some_method(a=5, b=0.1, c=4, d=5.0, e=6)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        some_method(a=5.0, b=0.1, c=4, d=5, e=6)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        some_method(a=5, b=0, c=4, d=5, e=6)
-
-
-
-
-def test_aliases(self) -
-
-
- -Expand source code - -
def test_aliases(self):
-    Vector = List[float]
-
-    @pedantic
-    def scale(scalar: float, vector: Vector) -> Vector:
-        return [scalar * num for num in vector]
-
-    scale(scalar=2.0, vector=[1.0, -4.2, 5.4])
-
-
-
-
-def test_all_ok_2(self) -
-
-
- -Expand source code - -
def test_all_ok_2(self):
-    @pedantic
-    def calc(n: int, m: int, i: int) -> str:
-        return str(n + m + i)
-
-    calc(n=42, m=40, i=38)
-
-
-
-
-def test_all_ok_3(self) -
-
-
- -Expand source code - -
def test_all_ok_3(self):
-    @pedantic
-    def calc(n: int, m: int, i: int) -> None:
-        str(n + m + i)
-
-    calc(n=42, m=40, i=38)
-
-
-
-
-def test_all_ok_4(self) -
-
-
- -Expand source code - -
def test_all_ok_4(self):
-    @pedantic
-    def calc(n: int) -> List[List[int]]:
-        return [[n]]
-
-    calc(n=42)
-
-
-
-
-def test_all_ok_5(self) -
-
-
- -Expand source code - -
def test_all_ok_5(self):
-    @pedantic
-    def calc(n: int) -> List[Tuple[float, str]]:
-        return [(float(n), str(n))]
-
-    calc(n=42)
-
-
-
-
-def test_all_ok_6(self) -
-
-
- -Expand source code - -
def test_all_ok_6(self):
-    @pedantic
-    def calc(n: int) -> Callable[[int, float], Tuple[float, str]]:
-        @pedantic
-        def f(x: int, y: float) -> Tuple[float, str]:
-            return n * float(x), str(y)
-        return f
-
-    calc(n=42)(x=72, y=3.14)
-
-
-
-
-def test_all_ok_7(self) -
-
-
- -Expand source code - -
def test_all_ok_7(self):
-    @pedantic
-    def calc(n: List[List[float]]) -> Any:
-        return n[0][0]
-
-    calc(n=[[42.0]])
-
-
-
-
-def test_all_ok_8(self) -
-
-
- -Expand source code - -
def test_all_ok_8(self):
-    @pedantic
-    def calc(n: int) -> Callable[[int, float], Tuple[float, str]]:
-        @pedantic
-        def f(x: int, y: float) -> Tuple[float, str]:
-            return n * float(x), str(y)
-
-        return f
-
-    calc(n=42)(x=3, y=3.14)
-
-
-
-
-def test_alternative_list_type_hint(self) -
-
-
- -Expand source code - -
def test_alternative_list_type_hint(self):
-    @pedantic
-    def _is_digit_in_int(digit: [int], num: int) -> bool:
-        num_str = str(num)
-        for i in num_str:
-            if int(i) == digit:
-                return True
-        return False
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        _is_digit_in_int(digit=4, num=42)
-
-
-
-
-def test_any(self) -
-
-
- -Expand source code - -
def test_any(self):
-    @pedantic
-    def calc(ls: List[Any]) -> Dict[int, Any]:
-        return {i: ls[i] for i in range(0, len(ls))}
-
-    calc(ls=[1, 2, 3])
-    calc(ls=[1.11, 2.0, 3.0])
-    calc(ls=['1', '2', '3'])
-    calc(ls=[10.5, '2', (3, 4, 5)])
-
-
-
-
-def test_any_type(self) -
-
-
- -Expand source code - -
def test_any_type(self):
-    @pedantic
-    def foo(a: Any) -> None:
-        pass
-
-    foo(a='aa')
-
-
-
-
-def test_args_kwargs(self) -
-
-
- -Expand source code - -
def test_args_kwargs(self):
-    @pedantic
-    def some_method(a: int = 0, b: float = 0.0) -> float:
-        return a * b
-
-    @pedantic
-    def wrapper_method(*args: Union[int, float], **kwargs: Union[int, float]) -> float:
-        return some_method(*args, **kwargs)
-
-    some_method()
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        some_method(3, 3.0)
-    some_method(a=3, b=3.0)
-    wrapper_method()
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        wrapper_method(3, 3.0)
-    wrapper_method(a=3, b=3.0)
-
-
-
-
-def test_args_kwargs_different_types(self) -
-
-
- -Expand source code - -
def test_args_kwargs_different_types(self):
-    @pedantic
-    def foo(*args: str, **kwds: int) -> None:
-        print(args)
-        print(kwds)
-
-    foo('a', 'b', 'c')
-    foo(x=1, y=2)
-    foo('', z=0)
-
-
-
-
-def test_args_kwargs_no_type_hint(self) -
-
-
- -Expand source code - -
def test_args_kwargs_no_type_hint(self):
-    @pedantic
-    def method_no_type_hint(*args, **kwargs) -> None:
-        print(args)
-        print(kwargs)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        method_no_type_hint(a=3, b=3.0)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        method_no_type_hint()
-
-
-
-
-def test_args_kwargs_wrong_type_hint(self) -
-
-
- -Expand source code - -
def test_args_kwargs_wrong_type_hint(self):
-    """See: https://www.python.org/dev/peps/pep-0484/#arbitrary-argument-lists-and-default-argument-values"""
-    @pedantic
-    def wrapper_method(*args: str, **kwargs: str) -> None:
-        print(args)
-        print(kwargs)
-
-    wrapper_method()
-    wrapper_method('hi', 'you', ':)')
-    wrapper_method(a='hi', b='you', c=':)')
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        wrapper_method('hi', 'you', ':)', 7)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        wrapper_method(3, 3.0)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        wrapper_method(a=3, b=3.0)
-
- -
-
-def test_binary_io(self) -
-
-
- -Expand source code - -
def test_binary_io(self):
-    @pedantic
-    def foo(a: BinaryIO) -> None:
-        print(a)
-
-    foo(a=BytesIO())
-
-
-
-
-def test_binary_io_fail(self) -
-
-
- -Expand source code - -
def test_binary_io_fail(self):
-    @pedantic
-    def foo(a: TextIO) -> None:
-        print(a)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=BytesIO())
-
-
-
-
-def test_binary_io_real_file(self) -
-
-
- -Expand source code - -
def test_binary_io_real_file(self):
-    @pedantic
-    def foo(a: BinaryIO) -> None:
-        print(a)
-
-    with open(file=TEST_FILE, mode='wb') as f:
-        foo(a=f)
-
-
-
-
-def test_bytearray_bytes(self) -
-
-
- -Expand source code - -
def test_bytearray_bytes(self):
-    @pedantic
-    def foo(x: bytearray) -> None:
-        pass
-
-    foo(x=bytearray([1]))
-
-
-
-
-def test_callable(self) -
-
-
- -Expand source code - -
def test_callable(self):
-    @pedantic
-    def foo_1(a: Callable[..., int]) -> None:
-        print(a)
-
-    @pedantic
-    def foo_2(a: Callable) -> None:
-        print(a)
-
-    def some_callable() -> int:
-        return 4
-
-    foo_1(a=some_callable)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo_2(a=some_callable)
-
-
-
-
-def test_callable_bad_type(self) -
-
-
- -Expand source code - -
def test_callable_bad_type(self):
-    @pedantic
-    def foo(a: Callable[..., int]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=5)
-
-
-
-
-def test_callable_bound_method(self) -
-
-
- -Expand source code - -
def test_callable_bound_method(self):
-    @pedantic
-    def foo(callback: Callable[[int], Any]) -> None:
-        pass
-
-    foo(callback=Child().method)
-
-
-
-
-def test_callable_builtin(self) -
-
-
- -Expand source code - -
def test_callable_builtin(self):
-    @pedantic
-    def foo(callback: types.BuiltinFunctionType) -> None:
-        pass
-
-    foo(callback=[].append)
-
-
-
-
-def test_callable_class(self) -
-
-
- -Expand source code - -
def test_callable_class(self):
-    """
-    Test that passing a class as a callable does not count the "self" argument "a"gainst the
-    ones declared in the Callable specification.
-
-    """
-    @pedantic
-    def foo(a: Callable[[int, str], Any]) -> None:
-        pass
-
-    class SomeClass:
-        def __init__(self, x: int, y: str):
-            pass
-
-    foo(a=SomeClass)
-
-

Test that passing a class as a callable does not count the "self" argument "a"gainst the -ones declared in the Callable specification.

-
-
-def test_callable_defaults(self) -
-
-
- -Expand source code - -
def test_callable_defaults(self):
-    """
-    Test that a callable having "too many" arguments don't raise an error if the extra
-    arguments have default values.
-
-    """
-    @pedantic
-    def foo(callback: Callable[[int, str], Any]) -> None:
-        pass
-
-    def some_callable(x: int, y: str, z: float = 1.2) -> int:
-        pass
-
-    foo(callback=some_callable)
-
-

Test that a callable having "too many" arguments don't raise an error if the extra -arguments have default values.

-
-
-def test_callable_exact_arg_count(self) -
-
-
- -Expand source code - -
def test_callable_exact_arg_count(self):
-    @pedantic
-    def foo(a: Callable[[int, str], int]) -> None:
-        pass
-
-    def some_callable(x: int, y: str) -> int:
-        pass
-
-    foo(a=some_callable)
-
-
-
-
-def test_callable_mandatory_kwonlyargs(self) -
-
-
- -Expand source code - -
def test_callable_mandatory_kwonlyargs(self):
-    @pedantic
-    def foo(a: Callable[[int, str], int]) -> None:
-        pass
-
-    def some_callable(x: int, y: str, *, z: float, bar: str) -> int:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=some_callable)
-
-
-
-
-def test_callable_no_args(self) -
-
-
- -Expand source code - -
def test_callable_no_args(self):
-    @pedantic
-    def f(g: Callable[[], str]) -> str:
-        return g()
-
-    @pedantic
-    def greetings() -> str:
-        return 'hello world'
-
-    f(g=greetings)
-
-
-
-
-def test_callable_nonmember(self) -
-
-
- -Expand source code - -
def test_callable_nonmember(self):
-    class CallableClass:
-        def __call__(self):
-            pass
-
-    @pedantic_class
-    class LocalClass:
-        some_callable = CallableClass()
-
-
-
-
-def test_callable_plain(self) -
-
-
- -Expand source code - -
def test_callable_plain(self):
-    @pedantic
-    def foo(a: Callable[..., Any]) -> None:
-        pass
-
-    def callback(a):
-        pass
-
-    foo(a=callback)
-
-
-
-
-def test_callable_too_few_arguments(self) -
-
-
- -Expand source code - -
def test_callable_too_few_arguments(self):
-    @pedantic
-    def foo(a: Callable[[int, str], int]) -> None:
-        pass
-
-    def some_callable(x: int) -> int:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=some_callable)
-
-
-
-
-def test_callable_with_union_return(self) -
-
-
- -Expand source code - -
def test_callable_with_union_return(self):
-    class MyClass:
-        pass
-
-    @pedantic
-    def admin_required(func: Callable[..., Union[str, MyClass]]) -> Callable[..., Union[str, MyClass]]:
-        @wraps(func)
-        def decorated_function(*args, **kwargs):
-            return func(*args, **kwargs)
-        return decorated_function
-
-    @admin_required
-    @pedantic
-    def get_server_info() -> str:
-        return 'info'
-
-    get_server_info()
-
-
-
-
-def test_callable_without_args_correct_with_lambdas(self) -
-
-
- -Expand source code - -
def test_callable_without_args_correct_with_lambdas(self):
-    @pedantic
-    def calc(i: Callable[[Any], Tuple[Any, ...]]) -> str:
-        return str(i(x=' you'))
-
-    calc(i=lambda x: (42.0, 43, 'hi', x))
-
-
-
-
-def test_callable_without_args_corrected(self) -
-
-
- -Expand source code - -
def test_callable_without_args_corrected(self):
-    @pedantic
-    def calc(i: Callable[[Any], Tuple[Any, ...]]) -> str:
-        return str(i(x=' you'))
-
-    @pedantic
-    def arg(x: Any) -> Tuple[Any, ...]:
-        return 42.0, 43, 'hi', x
-    calc(i=arg)
-
-
-
-
-def test_callable_without_type_args(self) -
-
-
- -Expand source code - -
def test_callable_without_type_args(self):
-    @pedantic
-    def calc(i: Callable) -> str:
-        return str(i(' you'))
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(i=lambda x: (42.0, 43, 'hi', x))
-
-
-
-
-def test_class(self) -
-
-
- -Expand source code - -
def test_class(self):
-    @pedantic
-    def foo_1(a: Type[Parent]) -> None:
-        print(a)
-
-    @pedantic
-    def foo_2(a: Type[TypeVar('UnboundType')]) -> None:
-        print(a)
-
-    @pedantic
-    def foo_3(a: Type[TypeVar('BoundType', bound=Parent)]) -> None:
-        print(a)
-
-    foo_1(a=Child)
-    foo_2(a=Child)
-    foo_3(a=Child)
-
-
-
-
-def test_class_any(self) -
-
-
- -Expand source code - -
def test_class_any(self):
-    @pedantic
-    def foo(a: Type[Any]) -> None:
-        pass
-
-    foo(a=str)
-
-
-
-
-def test_class_bad_subclass(self) -
-
-
- -Expand source code - -
def test_class_bad_subclass(self):
-    @pedantic
-    def foo(a: Type[Child]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=Parent)
-
-
-
-
-def test_class_decorator(self) -
-
-
- -Expand source code - -
def test_class_decorator(self):
-    @pedantic_class
-    class Foo:
-        @staticmethod
-        def staticmethod() -> int:
-            return 'foo'
-
-        @classmethod
-        def classmethod(cls) -> int:
-            return 'foo'
-
-        def method(self) -> int:
-            return 'foo'
-
-    with self.assertRaises(PedanticTypeCheckException):
-        Foo.staticmethod()
-
-    with self.assertRaises(PedanticTypeCheckException):
-        Foo.classmethod()
-
-    with self.assertRaises(PedanticTypeCheckException):
-        Foo().method()
-
-
-
-
-def test_class_no_type_vars(self) -
-
-
- -Expand source code - -
def test_class_no_type_vars(self):
-    @pedantic
-    def foo_1(a: Type) -> None:
-        print(a)
-
-    @pedantic
-    def foo_2(a: type) -> None:
-        print(a)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo_1(a=Child)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo_2(a=Child)
-
-
-
-
-def test_class_not_a_class(self) -
-
-
- -Expand source code - -
def test_class_not_a_class(self):
-    @pedantic
-    def foo(a: Type[Parent]) -> None:
-        print(a)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=1)
-
-
-
-
-def test_collection(self) -
-
-
- -Expand source code - -
def test_collection(self):
-    @pedantic
-    def foo(a: Collection) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=True)
-
-
-
-
-def test_complex(self) -
-
-
- -Expand source code - -
def test_complex(self):
-    @pedantic
-    def foo(a: complex) -> None:
-        print(a)
-
-    foo(a=complex(1, 5))
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=1.0)
-
-
-
-
-def test_container(self) -
-
-
- -Expand source code - -
def test_container(self):
-    @pedantic
-    def foo(a: Container[str]) -> None:
-        print(a)
-
-    for value in [('a', 'b'), ['a', 'b'], 'abc']:
-        foo(a=value)
-
-
-
-
-def test_container_no_type_args(self) -
-
-
- -Expand source code - -
def test_container_no_type_args(self):
-    @pedantic
-    def foo(a: Container) -> None:
-        print(a)
-
-    for value in [('a', 'b'), ['a', 'b'], 'abc']:
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=value)
-
-
-
-
-def test_coroutine_correct_return_type(self) -
-
-
- -Expand source code - -
def test_coroutine_correct_return_type(self):
-    @pedantic
-    async def foo() -> str:
-        return 'foo'
-
-    coro = foo()
-
-    with self.assertRaises(StopIteration):
-        coro.send(None)
-
-
-
-
-def test_coroutine_wrong_return_type(self) -
-
-
- -Expand source code - -
def test_coroutine_wrong_return_type(self):
-    @pedantic
-    async def foo() -> str:
-        return 1
-
-    coro = foo()
-
-    with self.assertRaises(PedanticTypeCheckException):
-        coro.send(None)
-
-
-
-
-def test_dataclass_protocol(self) -
-
-
- -Expand source code - -
def test_dataclass_protocol(self):
-    class IsDataclass(typing.Protocol):
-        __dataclass_fields__: ClassVar[Dict]
-
-    @dataclass
-    class Foo:
-        v: int
-
-    @pedantic
-    def foo(x: IsDataclass) -> IsDataclass:
-        return x
-
-    foo(x=Foo(v=42))
-
-
-
-
-def test_dataclass_protocol_in_type(self) -
-
-
- -Expand source code - -
def test_dataclass_protocol_in_type(self):
-    class IsDataclass(typing.Protocol):
-        __dataclass_fields__: ClassVar[Dict]
-
-    @dataclass
-    class Foo:
-        v: int
-
-    @pedantic
-    def foo(x: type[IsDataclass]) -> IsDataclass:
-        return x
-
-    assert foo(x=Foo) == Foo
-
-
-
-
-def test_dataclass_protocol_in_type_with_union(self) -
-
-
- -Expand source code - -
def test_dataclass_protocol_in_type_with_union(self):
-    class IsDataclass(typing.Protocol):
-        __dataclass_fields__: ClassVar[Dict]
-
-    @dataclass
-    class Foo:
-        v: int
-
-    @pedantic
-    def foo(x: type[None | bool | IsDataclass]) -> IsDataclass:
-        return x
-
-    assert foo(x=Foo) == Foo
-
-
-
-
-def test_date_datetime(self) -
-
-
- -Expand source code - -
def test_date_datetime(self):
-    @pedantic
-    def foo(a: datetime, b: date) -> None:
-        pass
-
-    foo(a=datetime(1995, 2, 5), b=date(1987, 8, 7))
-    foo(a=datetime(1995, 2, 5), b=datetime(1987, 8, 7))
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        foo(a=date(1995, 2, 5), b=date(1987, 8, 7))
-
-
-
-
-def test_dict(self) -
-
-
- -Expand source code - -
def test_dict(self):
-    @pedantic
-    def foo_1(a: Dict[str, int]) -> None:
-        print(a)
-
-    @pedantic
-    def foo_2(a: Dict) -> None:
-        print(a)
-
-    @pedantic
-    def foo_3(a: dict) -> None:
-        print(a)
-
-    @pedantic
-    def foo_4(a: dict[str, int]) -> None:
-        print(a)
-
-    foo_1(a={'x': 2})
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo_2(a={'x': 2})
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo_3(a={'x': 2})
-
-    foo_4(a={'x': 2})
-
-
-
-
-def test_dict_bad_key_type(self) -
-
-
- -Expand source code - -
def test_dict_bad_key_type(self):
-    @pedantic
-    def foo(a: Dict[str, int]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a={1: 2})
-
-
-
-
-def test_dict_bad_type(self) -
-
-
- -Expand source code - -
def test_dict_bad_type(self):
-    @pedantic
-    def foo(a: Dict[str, int]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=5)
-
-
-
-
-def test_dict_bad_value_type(self) -
-
-
- -Expand source code - -
def test_dict_bad_value_type(self):
-    @pedantic
-    def foo(a: Dict[str, int]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a={'x': 'a'})
-
-
-
-
-def test_double_pedantic(self) -
-
-
- -Expand source code - -
def test_double_pedantic(self):
-    @pedantic
-    @pedantic
-    def f(x: int, y: float) -> Tuple[float, str]:
-        return float(x), str(y)
-
-    f(x=5, y=3.14)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        f(x=5.0, y=3.14)
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        f(5, 3.14)
-
-
-
-
-def test_ellipsis_in_callable_1(self) -
-
-
- -Expand source code - -
def test_ellipsis_in_callable_1(self):
-    @pedantic
-    def calc(i: Callable[..., int]) -> int:
-        return i()
-
-    @pedantic
-    def call() -> int:
-        return 42
-
-    calc(i=call)
-
-
-
-
-def test_ellipsis_in_callable_2(self) -
-
-
- -Expand source code - -
def test_ellipsis_in_callable_2(self):
-    @pedantic
-    def calc(i: Callable[..., int]) -> int:
-        return i(x=3.14, y=5)
-
-    @pedantic
-    def call(x: float, y: int) -> int:
-        return 42
-
-    calc(i=call)
-
-
-
-
-def test_ellipsis_in_callable_3(self) -
-
-
- -Expand source code - -
def test_ellipsis_in_callable_3(self):
-    """Problem here: call to "call" misses one argument"""
-    @pedantic
-    def calc(i: Callable[..., int]) -> int:
-        return i(x=3.14)
-
-    @pedantic
-    def call(x: float, y: int) -> int:
-        return 42
-
-    with self.assertRaises(expected_exception=PedanticException):
-        calc(i=call)
-
-

Problem here: call to "call" misses one argument

-
-
-def test_empty_tuple(self) -
-
-
- -Expand source code - -
def test_empty_tuple(self):
-    @pedantic
-    def foo(a: Tuple[()]) -> None:
-        print(a)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=())
-
-
-
-
-def test_enum(self) -
-
-
- -Expand source code - -
def test_enum(self):
-    with self.assertRaises(PedanticTypeCheckException):
-        @pedantic_class
-        class MyEnum(Enum):
-            A = 'a'
-
-
-
-
-def test_enum_1(self) -
-
-
- -Expand source code - -
def test_enum_1(self):
-    """Problem here: Type hint for 'a' should be MyEnum instead of MyEnum.GAMMA"""
-    class MyEnum(Enum):
-        ALPHA = 'startEvent'
-        BETA = 'task'
-        GAMMA = 'sequenceFlow'
-
-    class MyClass:
-        @pedantic
-        def operation(self, a: MyEnum.GAMMA) -> None:
-            print(a)
-
-    m = MyClass()
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.operation(a=MyEnum.GAMMA)
-
-

Problem here: Type hint for 'a' should be MyEnum instead of MyEnum.GAMMA

-
-
-def test_enum_1_corrected(self) -
-
-
- -Expand source code - -
def test_enum_1_corrected(self):
-    class MyEnum(Enum):
-        ALPHA = 'startEvent'
-        BETA = 'task'
-        GAMMA = 'sequenceFlow'
-
-    @pedantic
-    def operation(a: MyEnum) -> None:
-        print(a)
-
-    operation(a=MyEnum.GAMMA)
-
-
-
-
-def test_enum_aggregate(self) -
-
-
- -Expand source code - -
def test_enum_aggregate(self):
-    T = TypeVar('T', bound=IntEnum)
-
-    @pedantic_class
-    class EnumAggregate(Generic[T]):
-        enum: ClassVar[Type[T]]
-
-        def __init__(self, value: Union[int, str, List[T]]) -> None:
-            assert len(self.enum) < 10
-
-            if value == '':
-                raise ValueError(f'Parameter "value" cannot be empty!')
-
-            if isinstance(value, list):
-                self._value = ''.join([str(x.value) for x in value])
-            else:
-                self._value = str(value)
-
-            self._value = ''.join(sorted(self._value))  # sort characters in string
-            self.to_list()  # check if is valid
-
-        def __contains__(self, item: T) -> bool:
-            return item in self.to_list()
-
-        def __eq__(self, other: Union['EnumAggregate', str]) -> bool:
-            if isinstance(other, str):
-                return self._value == other
-
-            return self._value == other._value
-
-        def __str__(self) -> str:
-            return self._value
-
-        def to_list(self) -> List[T]:
-            return [self.enum(int(character)) for character in self._value]
-
-        @property
-        def value(self) -> str:
-            return self._value
-
-        @classmethod
-        def all(cls) -> str:
-            return ''.join([str(x.value) for x in cls.enum])
-
-    class Gender(IntEnum):
-        MALE = 1
-        FEMALE = 2
-        DIVERS = 3
-
-    @pedantic_class
-    class Genders(EnumAggregate[Gender]):
-        enum = Gender
-
-    Genders(value=12)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        Genders(value=Child())
-
-
-
-
-def test_float(self) -
-
-
- -Expand source code - -
def test_float(self):
-    @pedantic
-    def foo(a: float) -> None:
-        print(a)
-
-    foo(a=1.5)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=1)
-
-
-
-
-def test_forward_ref(self) -
-
-
- -Expand source code - -
def test_forward_ref(self):
-    class Conversation:
-        pass
-
-    @pedantic
-    def get_conversations() -> List['Conversation']:
-        return [Conversation(), Conversation()]
-
-    get_conversations()
-
-
-
-
-def test_generator(self) -
-
-
- -Expand source code - -
def test_generator(self):
-    @pedantic
-    def genfunc() -> Generator[int, str, List[str]]:
-        val1 = yield 2
-        val2 = yield 3
-        val3 = yield 4
-        return [val1, val2, val3]
-
-    gen = genfunc()
-
-    with self.assertRaises(StopIteration):
-        value = next(gen)
-        while True:
-            value = gen.send(str(value))
-            assert isinstance(value, int)
-
-
-
-
-def test_generator_bad_return(self) -
-
-
- -Expand source code - -
def test_generator_bad_return(self):
-    @pedantic
-    def genfunc() -> Generator[int, str, str]:
-        yield 1
-        return 6
-
-    gen = genfunc()
-    next(gen)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        gen.send('foo')
-
-
-
-
-def test_generator_bad_send(self) -
-
-
- -Expand source code - -
def test_generator_bad_send(self):
-    @pedantic
-    def genfunc() -> Generator[int, str, None]:
-        yield 1
-        yield 2
-
-    gen = genfunc()
-    next(gen)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        gen.send(2)
-
-
-
-
-def test_generator_bad_yield(self) -
-
-
- -Expand source code - -
def test_generator_bad_yield(self):
-    @pedantic
-    def genfunc_1() -> Generator[int, str, None]:
-        yield 'foo'
-
-    @pedantic
-    def genfunc_2() -> Iterable[int]:
-        yield 'foo'
-
-    @pedantic
-    def genfunc_3() -> Iterator[int]:
-        yield 'foo'
-
-    gen = genfunc_1()
-
-    with self.assertRaises(PedanticTypeCheckException):
-        next(gen)
-
-    gen = genfunc_2()
-
-    with self.assertRaises(PedanticTypeCheckException):
-        next(gen)
-
-    gen = genfunc_3()
-
-    with self.assertRaises(PedanticTypeCheckException):
-        next(gen)
-
-
-
-
-def test_generator_no_type_args(self) -
-
-
- -Expand source code - -
def test_generator_no_type_args(self):
-    @pedantic
-    def genfunc() -> Generator:
-        val1 = yield 2
-        val2 = yield 3
-        val3 = yield 4
-        return [val1, val2, val3]
-
-    with self.assertRaises(PedanticTypeCheckException):
-        genfunc()
-
-
-
-
-def test_generator_simple(self) -
-
-
- -Expand source code - -
def test_generator_simple(self):
-    """Test that argument type checking works in a generator function too."""
-    @pedantic
-    def generate(a: int) -> Generator[int, int, None]:
-        yield a
-        yield a + 1
-
-    gen = generate(a=1)
-    next(gen)
-
-

Test that argument type checking works in a generator function too.

-
-
-def test_generic(self) -
-
-
- -Expand source code - -
def test_generic(self):
-    T_Foo = TypeVar('T_Foo')
-
-    class FooGeneric(Generic[T_Foo]):
-        pass
-
-    @pedantic
-    def foo(a: FooGeneric[str]) -> None:
-        print(a)
-
-    foo(a=FooGeneric[str]())
-
-
-
-
-def test_implicit_default_none(self) -
-
-
- -Expand source code - -
def test_implicit_default_none(self):
-    """
-    Test that if the default value is ``None``, a ``None`` argument can be passed.
-
-    """
-    @pedantic
-    def foo(a: Optional[str] = None) -> None:
-        pass
-
-    foo()
-
-

Test that if the default value is None, a None argument can be passed.

-
-
-def test_inheritance_1(self) -
-
-
- -Expand source code - -
def test_inheritance_1(self):
-    class MyClassA:
-        pass
-
-    class MyClassB(MyClassA):
-        pass
-
-    @pedantic
-    def calc(a: MyClassA) -> str:
-        return str(a)
-
-    calc(a=MyClassA())
-    calc(a=MyClassB())
-
-
-
-
-def test_inheritance_2(self) -
-
-
- -Expand source code - -
def test_inheritance_2(self):
-    """Problem here: A is not a subtype of B"""
-    class MyClassA:
-        pass
-
-    class MyClassB(MyClassA):
-        pass
-
-    @pedantic
-    def calc(a: MyClassB) -> str:
-        return str(a)
-
-    calc(a=MyClassB())
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(a=MyClassA())
-
-

Problem here: A is not a subtype of B

-
-
-def test_inherited_class_method(self) -
-
-
- -Expand source code - -
def test_inherited_class_method(self):
-    @pedantic_class
-    class Parent:
-        @classmethod
-        def foo(cls, x: str) -> str:
-            return cls.__name__
-
-    @pedantic_class
-    class Child(Parent):
-        pass
-
-    self.assertEqual('Parent', Child.foo(x='bar'))
-
-    with self.assertRaises(PedanticTypeCheckException):
-        Child.foo(x=1)
-
-
-
-
-def test_instance_method_1(self) -
-
-
- -Expand source code - -
def test_instance_method_1(self):
-    class MyClassA:
-        @pedantic
-        def calc(self, i: int) -> str:
-            return str(i)
-
-    a = MyClassA()
-    a.calc(i=42)
-
-
-
-
-def test_instance_method_2(self) -
-
-
- -Expand source code - -
def test_instance_method_2(self):
-    """Problem here: 'i' has no type annotation"""
-    class MyClassA:
-        @pedantic
-        def calc(self, i) -> str:
-            return str(i)
-
-    a = MyClassA()
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        a.calc(i=42)
-
-

Problem here: 'i' has no type annotation

-
-
-def test_instance_method_2_corrected(self) -
-
-
- -Expand source code - -
def test_instance_method_2_corrected(self):
-    class MyClassA:
-        @pedantic
-        def calc(self, i: int) -> str:
-            return str(i)
-
-    a = MyClassA()
-    a.calc(i=42)
-
-
-
-
-def test_instance_method_3_corrected(self) -
-
-
- -Expand source code - -
def test_instance_method_3_corrected(self):
-    class MyClassA:
-        @pedantic
-        def calc(self, i: float) -> str:
-            return str(i)
-
-    a = MyClassA()
-    a.calc(i=42.0)
-
-
-
-
-def test_instance_method_5(self) -
-
-
- -Expand source code - -
def test_instance_method_5(self):
-    """Problem here: instance methods is not called with kwargs"""
-    class MyClassA:
-        @pedantic
-        def calc(self, i: int) -> str:
-            return str(i)
-
-    a = MyClassA()
-    a.calc(i=42)
-
-

Problem here: instance methods is not called with kwargs

-
-
-def test_instance_method_int_is_not_float(self) -
-
-
- -Expand source code - -
def test_instance_method_int_is_not_float(self):
-    class MyClassA:
-        @pedantic
-        def calc(self, i: float) -> str:
-            return str(i)
-
-    a = MyClassA()
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        a.calc(i=42)
-
-
-
-
-def test_instance_method_no_kwargs(self) -
-
-
- -Expand source code - -
def test_instance_method_no_kwargs(self):
-    class MyClassA:
-        @pedantic
-        def calc(self, i: int) -> str:
-            return str(i)
-
-    a = MyClassA()
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        a.calc(42)
-
-
-
-
-def test_is_subtype_tuple(self) -
-
-
- -Expand source code - -
def test_is_subtype_tuple(self):
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        @pedantic
-        def foo() -> Callable[[Tuple[float, str]], Tuple[int]]:
-            def bar(a: Tuple[float]) -> Tuple[int]:
-                return len(a[1]) + int(a[0]),
-            return bar
-        foo()
-
-
-
-
-def test_is_subtype_tuple_corrected(self) -
-
-
- -Expand source code - -
def test_is_subtype_tuple_corrected(self):
-    @pedantic
-    def foo() -> Callable[[Tuple[float, str]], Tuple[int]]:
-        def bar(a: Tuple[float, str]) -> Tuple[int]:
-            return len(a[1]) + int(a[0]),
-        return bar
-    foo()
-
-
-
-
-def test_iterable(self) -
-
-
- -Expand source code - -
def test_iterable(self):
-    @pedantic
-    def foo(a: Iterable[str]) -> None:
-        print(a)
-
-    for value in [('a', 'b'), ['a', 'b'], 'abc']:
-        foo(a=value)
-
-
-
-
-def test_iterable_advanced(self) -
-
-
- -Expand source code - -
def test_iterable_advanced(self):
-    @pedantic
-    def genfunc() -> Iterable[int]:
-        val1 = yield 2
-        val2 = yield 3
-        val3 = yield 4
-        return [val1, val2, val3]
-
-    gen = genfunc()
-
-    with self.assertRaises(PedanticTypeCheckException):
-        value = next(gen)
-        while True:
-            value = gen.send(str(value))
-            assert isinstance(value, int)
-
-
-
-
-def test_iterable_advanced_no_type_args(self) -
-
-
- -Expand source code - -
def test_iterable_advanced_no_type_args(self):
-    @pedantic
-    def genfunc() -> Iterable:
-        val1 = yield 2
-        val2 = yield 3
-        val3 = yield 4
-        return [val1, val2, val3]
-
-    with self.assertRaises(PedanticTypeCheckException):
-        genfunc()
-
-
-
-
-def test_iterable_no_type_args(self) -
-
-
- -Expand source code - -
def test_iterable_no_type_args(self):
-    @pedantic
-    def foo(a: Iterable) -> None:
-        print(a)
-
-    for value in [('a', 'b'), ['a', 'b'], 'abc']:
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=value)
-
-
-
-
-def test_iterator(self) -
-
-
- -Expand source code - -
def test_iterator(self):
-    @pedantic
-    def genfunc() -> Iterator[int]:
-        val1 = yield 2
-        val2 = yield 3
-        val3 = yield 4
-        return [val1, val2, val3]
-
-    gen = genfunc()
-
-    with self.assertRaises(PedanticTypeCheckException):
-        value = next(gen)
-        while True:
-            value = gen.send(str(value))
-            assert isinstance(value, int)
-
-
-
-
-def test_iterator_no_type_args(self) -
-
-
- -Expand source code - -
def test_iterator_no_type_args(self):
-    @pedantic
-    def genfunc() -> Iterator:
-        val1 = yield 2
-        val2 = yield 3
-        val3 = yield 4
-        return [val1, val2, val3]
-
-    with self.assertRaises(PedanticTypeCheckException):
-        genfunc()
-
-
-
-
-def test_kwargs(self) -
-
-
- -Expand source code - -
def test_kwargs(self):
-    @pedantic
-    def foo(**kwargs: int) -> None:
-        pass
-
-    foo(a=1, b=2)
-
-
-
-
-def test_kwargs_fail(self) -
-
-
- -Expand source code - -
def test_kwargs_fail(self):
-    @pedantic
-    def foo(**kwargs: int) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=1, b='a')
-
-
-
-
-def test_lambda_1(self) -
-
-
- -Expand source code - -
def test_lambda_1(self):
-    @pedantic
-    def calc(i: float) -> Callable[[float], str]:
-        return lambda x: str(x * i)
-
-    calc(i=42.0)(10.0)
-
-
-
-
-def test_lambda_3(self) -
-
-
- -Expand source code - -
def test_lambda_3(self):
-    @pedantic
-    def calc(i: float) -> Callable[[float], str]:
-        def res(x: float) -> str:
-            return str(x * i)
-        return res
-
-    calc(i=42.0)(10.0)
-
-
-
-
-def test_lambda_4_almost_corrected(self) -
-
-
- -Expand source code - -
def test_lambda_4_almost_corrected(self):
-    """Problem here: float != str"""
-    @pedantic
-    def calc(i: float) -> Callable[[float], str]:
-        @pedantic
-        def res(x: int) -> str:
-            return str(x * i)
-        return res
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(i=42.0)(x=10)
-
-

Problem here: float != str

-
-
-def test_lambda_4_almost_corrected_2(self) -
-
-
- -Expand source code - -
def test_lambda_4_almost_corrected_2(self):
-    @pedantic
-    def calc(i: float) -> Callable[[int], str]:
-        @pedantic
-        def res(x: int) -> str:
-            return str(x * i)
-        return res
-
-    calc(i=42.0)(x=10)
-
-
-
-
-def test_lambda_5(self) -
-
-
- -Expand source code - -
def test_lambda_5(self):
-    """Problem here: float != int"""
-    @pedantic
-    def calc(i: float) -> Callable[[float], str]:
-        @pedantic
-        def res(x: float) -> str:
-            return str(x * i)
-        return res
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(i=42.0)(x=10)
-
-

Problem here: float != int

-
-
-def test_lambda_corrected(self) -
-
-
- -Expand source code - -
def test_lambda_corrected(self):
-    @pedantic
-    def calc(i: float) -> Callable[[float], str]:
-        @pedantic
-        def res(x: float) -> str:
-            return str(x * i)
-
-        return res
-
-    calc(i=42.0)(x=10.0)
-
-
-
-
-def test_lambda_int_is_not_float(self) -
-
-
- -Expand source code - -
def test_lambda_int_is_not_float(self):
-    @pedantic
-    def calc(i: float) -> Callable[[float], str]:
-        def res(x: int) -> str:
-            return str(x * i)
-        return res
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(i=42.0)(x=10)
-
-
-
-
-def test_list(self) -
-
-
- -Expand source code - -
def test_list(self):
-    @pedantic
-    def foo_1(a: List[int]) -> None:
-        print(a)
-
-    @pedantic
-    def foo_2(a: List) -> None:
-        print(a)
-
-    @pedantic
-    def foo_3(a: list) -> None:
-        print(a)
-
-    @pedantic
-    def foo_4(a: list[int]) -> None:
-        print(a)
-
-    foo_1(a=[1, 2])
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo_2(a=[1, 2])
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo_3(a=[1, 2])
-
-
-    foo_4(a=[1, 2])
-
-
-
-
-def test_list_bad_element(self) -
-
-
- -Expand source code - -
def test_list_bad_element(self):
-    @pedantic
-    def foo(a: List[int]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=[1, 2, 'bb'])
-
-
-
-
-def test_list_bad_type(self) -
-
-
- -Expand source code - -
def test_list_bad_type(self):
-    @pedantic
-    def foo(a: List[int]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=5)
-
-
-
-
-def test_list_of_new_type(self) -
-
-
- -Expand source code - -
def test_list_of_new_type(self):
-    UserId = NewType('UserId', int)
-
-    @pedantic
-    def get_user_name(user_ids: List[UserId]) -> str:
-        return str(user_ids)
-
-    get_user_name(user_ids=[UserId(524313), UserId(42)])
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        get_user_name(user_ids=[UserId(524313), UserId(42), 430.0])
-
-
-
-
-def test_list_without_args(self) -
-
-
- -Expand source code - -
def test_list_without_args(self):
-    @pedantic
-    def calc(i: List) -> Any:
-        return [i]
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(i=[42.0, 43, 'hi'])
-
-
-
-
-def test_list_without_args_corrected(self) -
-
-
- -Expand source code - -
def test_list_without_args_corrected(self):
-    @pedantic
-    def calc(i: List[Any]) -> List[List[Any]]:
-        return [i]
-
-    calc(i=[42.0, 43, 'hi'])
-
-
-
-
-def test_literal(self) -
-
-
- -Expand source code - -
def test_literal(self):
-    @pedantic
-    def foo(a: Literal[1, True, 'x', b'y', 404]) -> None:
-        print(a)
-
-    foo(a=404)
-    foo(a=True)
-    foo(a='x')
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=4)
-
-
-
-
-def test_literal_illegal_value(self) -
-
-
- -Expand source code - -
def test_literal_illegal_value(self):
-    @pedantic
-    def foo(a: Literal[1, 1.1]) -> None:
-        print(a)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=4)
-
-
-
-
-def test_literal_union(self) -
-
-
- -Expand source code - -
def test_literal_union(self):
-    @pedantic
-    def foo(a: Union[str, Literal[1, 6, 8]]) -> None:
-        print(a)
-
-    foo(a=6)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=4)
-
-
-
-
-def test_local_class(self) -
-
-
- -Expand source code - -
def test_local_class(self):
-    @pedantic_class
-    class LocalClass:
-        class Inner:
-            pass
-
-        def create_inner(self) -> 'Inner':
-            return self.Inner()
-
-    retval = LocalClass().create_inner()
-    assert isinstance(retval, LocalClass.Inner)
-
-
-
-
-def test_local_class_async(self) -
-
-
- -Expand source code - -
def test_local_class_async(self):
-    @pedantic_class
-    class LocalClass:
-        class Inner:
-            pass
-
-        async def create_inner(self) -> 'Inner':
-            return self.Inner()
-
-    coro = LocalClass().create_inner()
-
-    with self.assertRaises(StopIteration):
-        coro.send(None)
-
-
-
-
-def test_marco(self) -
-
-
- -Expand source code - -
def test_marco(self):
-    @pedantic_class
-    class A:
-        def __init__(self, val: int) -> None:
-            self.val = val
-
-        def __eq__(self, other: 'A') -> bool:  # other: A and all subclasses
-            return self.val == other.val
-
-    @pedantic_class
-    class B(A):
-        def __init__(self, val: int) -> None:
-            super().__init__(val=val)
-
-    @pedantic_class
-    class C(A):
-        def __init__(self, val: int) -> None:
-            super().__init__(val=val)
-
-    a = A(val=42)
-    b = B(val=42)
-    c = C(val=42)
-
-    assert a == b  # works
-    assert a == c  # works
-    assert b == c  # error
-
-
-
-
-def test_mismatching_default_type(self) -
-
-
- -Expand source code - -
def test_mismatching_default_type(self):
-    @pedantic
-    def foo(a: str = 1) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo()
-
-
-
-
-def test_missing_type_hint_1(self) -
-
-
- -Expand source code - -
def test_missing_type_hint_1(self):
-    """Problem here: type hint for n missed"""
-    @pedantic
-    def calc(n) -> float:
-        return 42.0 * n
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(n=42)
-
-

Problem here: type hint for n missed

-
-
-def test_missing_type_hint_1_corrected(self) -
-
-
- -Expand source code - -
def test_missing_type_hint_1_corrected(self):
-    @pedantic
-    def calc(n: int) -> float:
-        return 42.0 * n
-
-    calc(n=42)
-
-
-
-
-def test_missing_type_hint_2(self) -
-
-
- -Expand source code - -
def test_missing_type_hint_2(self):
-    """Problem here: Return type annotation missed"""
-    @pedantic
-    def calc(n: int):
-        return 'Hi' + str(n)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(n=42)
-
-

Problem here: Return type annotation missed

-
-
-def test_missing_type_hint_2_corrected(self) -
-
-
- -Expand source code - -
def test_missing_type_hint_2_corrected(self):
-    @pedantic
-    def calc(n: int) -> str:
-        return 'Hi' + str(n)
-
-    calc(n=42)
-
-
-
-
-def test_missing_type_hint_3(self) -
-
-
- -Expand source code - -
def test_missing_type_hint_3(self):
-    """Problem here: type hint for i missed"""
-    @pedantic
-    def calc(n: int, m: int, i) -> int:
-        return n + m + i
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(n=42, m=40, i=38)
-
-

Problem here: type hint for i missed

-
-
-def test_missing_type_hint_3_corrected(self) -
-
-
- -Expand source code - -
def test_missing_type_hint_3_corrected(self):
-    @pedantic
-    def calc(n: int, m: int, i: int) -> int:
-        return n + m + i
-
-    calc(n=42, m=40, i=38)
-
-
-
-
-def test_namedtuple(self) -
-
-
- -Expand source code - -
def test_namedtuple(self):
-    Employee = NamedTuple('Employee', [('name', str), ('id', int)])
-
-    @pedantic
-    def foo(bar: Employee) -> None:
-        print(bar)
-
-    foo(bar=Employee('bob', 1))
-
-
-
-
-def test_namedtuple_huge_type_mismatch(self) -
-
-
- -Expand source code - -
def test_namedtuple_huge_type_mismatch(self):
-    Employee = NamedTuple('Employee', [('name', str), ('id', int)])
-
-    @pedantic
-    def foo(bar: int) -> None:
-        print(bar)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(bar=foo(bar=Employee('bob', 1)))
-
-
-
-
-def test_namedtuple_key_mismatch(self) -
-
-
- -Expand source code - -
def test_namedtuple_key_mismatch(self):
-    Employee1 = NamedTuple('Employee', [('name', str), ('id', int)])
-    Employee2 = NamedTuple('Employee', [('firstname', str), ('id', int)])
-
-    @pedantic
-    def foo(bar: Employee1) -> None:
-        print(bar)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(bar=Employee2('bob', 1))
-
-
-
-
-def test_namedtuple_type_mismatch(self) -
-
-
- -Expand source code - -
def test_namedtuple_type_mismatch(self):
-    Employee = NamedTuple('Employee', [('name', str), ('id', int)])
-
-    @pedantic
-    def foo(bar: Employee) -> None:
-        print(bar)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(bar=('bob', 1))
-
-
-
-
-def test_namedtuple_wrong_field_type(self) -
-
-
- -Expand source code - -
def test_namedtuple_wrong_field_type(self):
-    Employee = NamedTuple('Employee', [('name', str), ('id', int)])
-
-    @pedantic
-    def foo(bar: Employee) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(bar=Employee(2, 1))
-
-
-
-
-def test_nested_type_hints_1(self) -
-
-
- -Expand source code - -
def test_nested_type_hints_1(self):
-    @pedantic
-    def calc(n: int) -> List[List[float]]:
-        return [0.0 * n]
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(n=42)
-
-
-
-
-def test_nested_type_hints_1_corrected(self) -
-
-
- -Expand source code - -
def test_nested_type_hints_1_corrected(self):
-    @pedantic
-    def calc(n: int) -> List[List[float]]:
-        return [[0.0 * n]]
-
-    calc(n=42)
-
-
-
-
-def test_nested_type_hints_2(self) -
-
-
- -Expand source code - -
def test_nested_type_hints_2(self):
-    """Problem here: int != float"""
-    @pedantic
-    def calc(n: int) -> List[Tuple[float, str]]:
-        return [(n, str(n))]
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(n=42)
-
-

Problem here: int != float

-
-
-def test_nested_type_hints_2_corrected(self) -
-
-
- -Expand source code - -
def test_nested_type_hints_2_corrected(self):
-    @pedantic
-    def calc(n: int) -> List[Tuple[int, str]]:
-        return [(n, str(n))]
-
-    @pedantic
-    def calc_2(n: float) -> List[Tuple[float, str]]:
-        return [(n, str(n))]
-
-    calc(n=42)
-    calc_2(n=42.0)
-
-
-
-
-def test_nested_type_hints_3(self) -
-
-
- -Expand source code - -
def test_nested_type_hints_3(self):
-    """Problem here: inner function actually returns Tuple[int, str]"""
-    @pedantic
-    def calc(n: int) -> Callable[[int, float], Tuple[float, str]]:
-        @pedantic
-        def f(x: int, y: float) -> Tuple[float, str]:
-            return n * x, str(y)
-        return f
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(n=42)(x=3, y=3.14)
-
-

Problem here: inner function actually returns Tuple[int, str]

-
-
-def test_nested_type_hints_3_corrected(self) -
-
-
- -Expand source code - -
def test_nested_type_hints_3_corrected(self):
-    @pedantic
-    def calc(n: int) -> Callable[[int, float], Tuple[int, str]]:
-        @pedantic
-        def f(x: int, y: float) -> Tuple[int, str]:
-            return n * x, str(y)
-
-        return f
-
-    calc(n=42)(x=3, y=3.14)
-
-
-
-
-def test_nested_type_hints_4(self) -
-
-
- -Expand source code - -
def test_nested_type_hints_4(self):
-    """Problem here: return type is actually float"""
-    @pedantic
-    def calc(n: List[List[float]]) -> int:
-        return n[0][0]
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(n=[[42.0]])
-
-

Problem here: return type is actually float

-
-
-def test_nested_type_hints_5(self) -
-
-
- -Expand source code - -
def test_nested_type_hints_5(self):
-    """Problem here: Tuple[float, str] != Tuple[float, float]"""
-
-    @pedantic
-    def calc(n: int) -> Callable[[int, float], Tuple[float, str]]:
-        @pedantic
-        def f(x: int, y: float) -> Tuple[float, float]:
-            return n * float(x), y
-        return f
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(n=42)
-
-

Problem here: Tuple[float, str] != Tuple[float, float]

-
-
-def test_nested_type_hints_5_corrected(self) -
-
-
- -Expand source code - -
def test_nested_type_hints_5_corrected(self):
-    @pedantic
-    def calc(n: int) -> Callable[[int, float], Tuple[float, float]]:
-        @pedantic
-        def f(x: int, y: float) -> Tuple[float, float]:
-            return n * float(x), y
-        return f
-
-    calc(n=42)
-
-
-
-
-def test_nested_type_hints_corrected(self) -
-
-
- -Expand source code - -
def test_nested_type_hints_corrected(self):
-    @pedantic
-    def calc(n: List[List[float]]) -> int:
-        return int(n[0][0])
-
-    calc(n=[[42.0]])
-
-
-
-
-def test_new_type(self) -
-
-
- -Expand source code - -
def test_new_type(self):
-    UserId = NewType('UserId', int)
-
-    @pedantic
-    def get_user_name(user_id: UserId) -> str:
-        return str(user_id)
-
-    some_id = UserId(524313)
-    get_user_name(user_id=some_id)
-
-    # the following would be desirable but impossible to check at runtime:
-    # with self.assertRaises(expected_exception=AssertionError):
-    #     get_user_name(user_id=-1)
-
-
-
-
-def test_newtype(self) -
-
-
- -Expand source code - -
def test_newtype(self):
-    myint = NewType("myint", int)
-
-    @pedantic
-    def foo(a: myint) -> int:
-        return 42
-
-    assert foo(a=1) == 42
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a="a")
-
-
-
-
-def test_no_kwargs(self) -
-
-
- -Expand source code - -
def test_no_kwargs(self):
-    @pedantic
-    def calc(n: int, m: int, i: int) -> int:
-        return n + m + i
-
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        calc(42, 40, 38)
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        calc(42, m=40, i=38)
-    calc(n=42, m=40, i=38)
-
-
-
-
-def test_none_1(self) -
-
-
- -Expand source code - -
def test_none_1(self):
-    """Problem here: None is not accepted"""
-    @pedantic
-    def calc(n: int, m: int, i: int) -> int:
-        return n + m + i
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(n=42, m=40, i=None)
-
-

Problem here: None is not accepted

-
-
-def test_none_2(self) -
-
-
- -Expand source code - -
def test_none_2(self):
-    @pedantic
-    def calc(n: int, m: int, i: Optional[int]) -> int:
-        return n + m + i if i is not None else n + m
-
-    calc(n=42, m=40, i=None)
-
-
-
-
-def test_none_3(self) -
-
-
- -Expand source code - -
def test_none_3(self):
-    @pedantic
-    def calc(n: int, m: int, i: Union[int, None]) -> int:
-        return n + m + i if i is not None else n + m
-
-    calc(n=42, m=40, i=None)
-
-
-
-
-def test_none_4(self) -
-
-
- -Expand source code - -
def test_none_4(self):
-    """Problem here: function may return None"""
-    @pedantic
-    def calc(n: int, m: int, i: Union[int, None]) -> int:
-        return n + m + i if i is not None else None
-
-    calc(n=42, m=40, i=42)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(n=42, m=40, i=None)
-
-

Problem here: function may return None

-
-
-def test_none_5(self) -
-
-
- -Expand source code - -
def test_none_5(self):
-    @pedantic
-    def calc(n: int, m: int, i: Union[int, None]) -> Optional[int]:
-        return n + m + i if i is not None else None
-
-    calc(n=42, m=40, i=None)
-
-
-
-
-def test_noreturn(self) -
-
-
- -Expand source code - -
def test_noreturn(self):
-    @pedantic
-    def foo() -> NoReturn:
-        pass
-
-    @pedantic
-    def bar() -> NoReturn:
-        raise ZeroDivisionError('bar')
-
-    with self.assertRaises(expected_exception=ZeroDivisionError):
-        bar()
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo()
-
-
-
-
-def test_optional_args_1(self) -
-
-
- -Expand source code - -
def test_optional_args_1(self):
-    @pedantic
-    def calc(a: int, b: int = 42) -> int:
-        return a + b
-
-    calc(a=2)
-
-
-
-
-def test_optional_args_2(self) -
-
-
- -Expand source code - -
def test_optional_args_2(self):
-    @pedantic
-    def calc(a: int = 3, b: int = 42, c: float = 5.0) -> float:
-        return a + b + c
-
-    calc()
-    calc(a=1)
-    calc(b=1)
-    calc(c=1.0)
-    calc(a=1, b=1)
-    calc(a=1, c=1.0)
-    calc(b=1, c=1.0)
-    calc(a=1, b=1, c=1.0)
-
-
-
-
-def test_optional_args_3(self) -
-
-
- -Expand source code - -
def test_optional_args_3(self):
-    """Problem here: optional argument c: 5 is not a float"""
-    @pedantic
-    def calc(a: int = 3, b: int = 42, c: float = 5) -> float:
-        return a + b + c
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc()
-
-

Problem here: optional argument c: 5 is not a float

-
-
-def test_optional_args_3_corrected(self) -
-
-
- -Expand source code - -
def test_optional_args_3_corrected(self):
-    @pedantic
-    def calc(a: int = 3, b: int = 42, c: float = 5.0) -> float:
-        return a + b + c
-
-    calc()
-
-
-
-
-def test_optional_args_4(self) -
-
-
- -Expand source code - -
def test_optional_args_4(self):
-    class MyClass:
-        @pedantic
-        def foo(self, a: int, b: Optional[int] = 1) -> int:
-            return a + b
-
-    my_class = MyClass()
-    my_class.foo(a=10)
-
-
-
-
-def test_optional_args_5(self) -
-
-
- -Expand source code - -
def test_optional_args_5(self):
-    @pedantic
-    def calc(d: Optional[Dict[int, int]] = None) -> Optional[int]:
-        if d is None:
-            return None
-        return sum(d.keys())
-
-    calc(d=None)
-    calc()
-    calc(d={42: 3})
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(d={42: 3.14})
-
-
-
-
-def test_optional_args_6(self) -
-
-
- -Expand source code - -
def test_optional_args_6(self):
-    """"Problem here: str != int"""
-    @pedantic
-    def calc(d: int = 42) -> int:
-        return int(d)
-
-    calc(d=99999)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(d='999999')
-
-

"Problem here: str != int

-
-
-def test_partial_function(self) -
-
-
- -Expand source code - -
def test_partial_function(self):
-    @pedantic
-    def f(a: int, b: int) -> int:
-        return a + b
-
-    g = pedantic(partial(f, a=1))
-
-    assert f(a=2, b=3) == 5
-    assert g(b=3) == 4
-
-    with self.assertRaises(PedanticTypeCheckException):
-        f(a='2', b=3)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        g(b='2')
-
-
-
-
-def test_pedantic(self) -
-
-
- -Expand source code - -
def test_pedantic(self):
-    @pedantic
-    def foo(a: int, b: str) -> str:
-        return 'abc'
-
-    self.assertEqual('abc', foo(a=4, b='abc'))
-
-
-
-
-def test_pedantic_always(self) -
-
-
- -Expand source code - -
def test_pedantic_always(self):
-    @pedantic
-    def foo(a: int, b: str) -> str:
-        return 'abc'
-
-    self.assertEqual('abc', foo(a=4, b='abc'))
-
-
-
-
-def test_pedantic_arguments_fail(self) -
-
-
- -Expand source code - -
def test_pedantic_arguments_fail(self):
-    @pedantic
-    def foo(a: int, b: str) -> str:
-        return 'abc'
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        foo(a=4, b=5)
-
-
-
-
-def test_pedantic_on_class(self) -
-
-
- -Expand source code - -
def test_pedantic_on_class(self):
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        @pedantic
-        class MyClass:
-            pass
-        MyClass()
-
-
-
-
-def test_pedantic_return_type_fail(self) -
-
-
- -Expand source code - -
def test_pedantic_return_type_fail(self):
-    @pedantic
-    def foo(a: int, b: str) -> str:
-        return 6
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        foo(a=4, b='abc')
-
-
-
-
-def test_pedantic_return_type_var_fail(self) -
-
-
- -Expand source code - -
def test_pedantic_return_type_var_fail(self):
-    T = TypeVar('T', int, float)
-
-    @pedantic
-    def foo(a: T, b: T) -> T:
-        return 'a'
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=4, b=2)
-
-
-
-
-def test_primitive_list_dict_tuple(self) -
-
-
- -Expand source code - -
def test_primitive_list_dict_tuple(self):
-    @pedantic
-    def f(x: list[dict[int, tuple[float, str]]]) -> list[Any]:
-        return x
-
-    f(x=[{3: (3.24, 'hi')}])
-
-    for value in [
-        [{3, (3, 'hi')}],
-        [{3: (3, 'hi')}],
-        [{3: (3.24, 3)}],
-        [{3: (3.24, 'hi')}, {0}],
-    ]:
-        with self.assertRaises(PedanticTypeCheckException):
-            f(x=value)
-
-
-
-
-def test_return_generator(self) -
-
-
- -Expand source code - -
def test_return_generator(self):
-    @pedantic
-    def genfunc() -> Generator[int, None, None]:
-        yield 1
-
-    @pedantic
-    def foo() -> Generator[int, None, None]:
-        return genfunc()
-
-    foo()
-
-
-
-
-def test_return_type_none(self) -
-
-
- -Expand source code - -
def test_return_type_none(self):
-    @pedantic
-    def foo() -> None:
-        return 'a'
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        foo()
-
-
-
-
-def test_sequence(self) -
-
-
- -Expand source code - -
def test_sequence(self):
-    @pedantic
-    def foo(a: Sequence[str]) -> None:
-        print(a)
-
-    for value in [('a', 'b'), ['a', 'b'], 'abc']:
-        foo(a=value)
-
-
-
-
-def test_sequence_bad_element(self) -
-
-
- -Expand source code - -
def test_sequence_bad_element(self):
-    @pedantic
-    def foo(a: Sequence[int]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=[1, 2, 'bb'])
-
-
-
-
-def test_sequence_bad_type(self) -
-
-
- -Expand source code - -
def test_sequence_bad_type(self):
-    @pedantic
-    def foo(a: Sequence[int]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=5)
-
-
-
-
-def test_sequence_no_type_args(self) -
-
-
- -Expand source code - -
def test_sequence_no_type_args(self):
-    @pedantic
-    def foo(a: Sequence) -> None:
-        print(a)
-
-    for value in [('a', 'b'), ['a', 'b'], 'abc']:
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=value)
-
-
-
-
-def test_set(self) -
-
-
- -Expand source code - -
def test_set(self):
-    @pedantic
-    def foo_1(a: AbstractSet[int]) -> None:
-        print(a)
-
-    @pedantic
-    def foo_2(a: Set[int]) -> None:
-        print(a)
-
-    for value in [set(), {6}]:
-        foo_1(a=value)
-        foo_2(a=value)
-
-
-
-
-def test_set_bad_element(self) -
-
-
- -Expand source code - -
def test_set_bad_element(self):
-    @pedantic
-    def foo(a: Set[int]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a={1, 2, 'bb'})
-
-
-
-
-def test_set_bad_type(self) -
-
-
- -Expand source code - -
def test_set_bad_type(self):
-    @pedantic
-    def foo(a: Set[int]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=5)
-
-
-
-
-def test_set_no_type_args(self) -
-
-
- -Expand source code - -
def test_set_no_type_args(self):
-    @pedantic
-    def foo_1(a: AbstractSet) -> None:
-        print(a)
-
-    @pedantic
-    def foo_2(a: Set) -> None:
-        print(a)
-
-    @pedantic
-    def foo_3(a: set) -> None:
-        print(a)
-
-    for value in [set(), {6}]:
-        with self.assertRaises(PedanticTypeCheckException):
-            foo_1(a=value)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo_2(a=value)
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo_3(a=value)
-
-
-
-
-def test_sloppy_types_dict(self) -
-
-
- -Expand source code - -
def test_sloppy_types_dict(self):
-    @pedantic
-    def operation(d: dict) -> int:
-        return len(d.keys())
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        operation(d={1: 1, 2: 2})
-
-
-
-
-def test_sloppy_types_dict_almost_corrected_no_type_args(self) -
-
-
- -Expand source code - -
def test_sloppy_types_dict_almost_corrected_no_type_args(self):
-    @pedantic
-    def operation(d: Dict) -> int:
-        return len(d.keys())
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        operation(d={1: 1, 2: 2})
-
-
-
-
-def test_sloppy_types_dict_corrected(self) -
-
-
- -Expand source code - -
def test_sloppy_types_dict_corrected(self):
-    @pedantic
-    def operation(d: Dict[int, int]) -> int:
-        return len(d.keys())
-
-    operation(d={1: 1, 2: 2})
-
-
-
-
-def test_sloppy_types_frozenset(self) -
-
-
- -Expand source code - -
def test_sloppy_types_frozenset(self):
-    @pedantic
-    def operation(d: frozenset) -> int:
-        return len(d)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        operation(d=frozenset({1, 2, 3}))
-
-
-
-
-def test_sloppy_types_frozenset_almost_corrected_no_type_args(self) -
-
-
- -Expand source code - -
def test_sloppy_types_frozenset_almost_corrected_no_type_args(self):
-    @pedantic
-    def operation(d: FrozenSet) -> int:
-        return len(d)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        operation(d=frozenset({1, 2, 3}))
-
-
-
-
-def test_sloppy_types_frozenset_corrected(self) -
-
-
- -Expand source code - -
def test_sloppy_types_frozenset_corrected(self):
-    @pedantic
-    def operation(d: FrozenSet[int]) -> int:
-        return len(d)
-
-    operation(d=frozenset({1, 2, 3}))
-
-
-
-
-def test_sloppy_types_list(self) -
-
-
- -Expand source code - -
def test_sloppy_types_list(self):
-    @pedantic
-    def operation(d: list) -> int:
-        return len(d)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        operation(d=[1, 2, 3, 4])
-
-
-
-
-def test_sloppy_types_list_almost_corrected_no_type_args(self) -
-
-
- -Expand source code - -
def test_sloppy_types_list_almost_corrected_no_type_args(self):
-    @pedantic
-    def operation(d: List) -> int:
-        return len(d)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        operation(d=[1, 2, 3, 4])
-
-
-
-
-def test_sloppy_types_list_corrected(self) -
-
-
- -Expand source code - -
def test_sloppy_types_list_corrected(self):
-    @pedantic
-    def operation(d: List[int]) -> int:
-        return len(d)
-
-    operation(d=[1, 2, 3, 4])
-
-
-
-
-def test_sloppy_types_set(self) -
-
-
- -Expand source code - -
def test_sloppy_types_set(self):
-    @pedantic
-    def operation(d: set) -> int:
-        return len(d)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        operation(d={1, 2, 3})
-
-
-
-
-def test_sloppy_types_set_almost_corrected_to_type_args(self) -
-
-
- -Expand source code - -
def test_sloppy_types_set_almost_corrected_to_type_args(self):
-    @pedantic
-    def operation(d: Set) -> int:
-        return len(d)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        operation(d={1, 2, 3})
-
-
-
-
-def test_sloppy_types_set_corrected(self) -
-
-
- -Expand source code - -
def test_sloppy_types_set_corrected(self):
-    @pedantic
-    def operation(d: Set[int]) -> int:
-        return len(d)
-
-    operation(d={1, 2, 3})
-
-
-
-
-def test_sloppy_types_tuple(self) -
-
-
- -Expand source code - -
def test_sloppy_types_tuple(self):
-    @pedantic
-    def operation(d: tuple) -> int:
-        return len(d)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        operation(d=(1, 2, 3))
-
-
-
-
-def test_sloppy_types_tuple_almost_corrected_no_type_args(self) -
-
-
- -Expand source code - -
def test_sloppy_types_tuple_almost_corrected_no_type_args(self):
-    @pedantic
-    def operation(d: Tuple) -> int:
-        return len(d)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        operation(d=(1, 2, 3))
-
-
-
-
-def test_sloppy_types_tuple_corrected(self) -
-
-
- -Expand source code - -
def test_sloppy_types_tuple_corrected(self):
-    @pedantic
-    def operation(d: Tuple[int, int, int]) -> int:
-        return len(d)
-
-    operation(d=(1, 2, 3))
-
-
-
-
-def test_text_io(self) -
-
-
- -Expand source code - -
def test_text_io(self):
-    @pedantic
-    def foo(a: TextIO) -> None:
-        print(a)
-
-    foo(a=StringIO())
-
-
-
-
-def test_text_io_fail(self) -
-
-
- -Expand source code - -
def test_text_io_fail(self):
-    @pedantic
-    def foo(a: BinaryIO) -> None:
-        print(a)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=StringIO())
-
-
-
-
-def test_text_io_real_file(self) -
-
-
- -Expand source code - -
def test_text_io_real_file(self):
-    @pedantic
-    def foo(a: TextIO) -> None:
-        print(a)
-
-    with open(file=TEST_FILE, mode='w') as f:
-        foo(a=f)
-
-
-
-
-def test_tuple(self) -
-
-
- -Expand source code - -
def test_tuple(self):
-    @pedantic
-    def foo_1(a: Tuple[int, int]) -> None:
-        print(a)
-
-    @pedantic
-    def foo_2(a: Tuple[int, ...]) -> None:
-        print(a)
-
-    foo_1(a=(1, 2))
-    foo_2(a=(1, 2))
-
-
-
-
-def test_tuple_bad_element(self) -
-
-
- -Expand source code - -
def test_tuple_bad_element(self):
-    @pedantic
-    def foo(a: Tuple[int, str]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=(1, 2))
-
-
-
-
-def test_tuple_bad_type(self) -
-
-
- -Expand source code - -
def test_tuple_bad_type(self):
-    @pedantic
-    def foo(a: Tuple[int]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=5)
-
-
-
-
-def test_tuple_ellipsis_bad_element(self) -
-
-
- -Expand source code - -
def test_tuple_ellipsis_bad_element(self):
-    @pedantic
-    def foo(a: Tuple[int, ...]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=(1, 2, 'blah'))
-
-
-
-
-def test_tuple_no_type_args(self) -
-
-
- -Expand source code - -
def test_tuple_no_type_args(self):
-    @pedantic
-    def foo_1(a: Tuple) -> None:
-        print(a)
-
-    @pedantic
-    def foo_2(a: tuple) -> None:
-        print(a)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo_1(a=(1, 2))
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo_2(a=(1, 2))
-
-
-
-
-def test_tuple_too_few_elements(self) -
-
-
- -Expand source code - -
def test_tuple_too_few_elements(self):
-    @pedantic
-    def foo(a: Tuple[int, str]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=(1,))
-
-
-
-
-def test_tuple_too_many_elements(self) -
-
-
- -Expand source code - -
def test_tuple_too_many_elements(self):
-    @pedantic
-    def foo(a: Tuple[int, str]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=(1, 'aa', 2))
-
-
-
-
-def test_tuple_without_args_corrected(self) -
-
-
- -Expand source code - -
def test_tuple_without_args_corrected(self):
-    @pedantic
-    def calc(i: Tuple[Any, ...]) -> str:
-        return str(i)
-
-    calc(i=(42.0, 43, 'hi'))
-
-
-
-
-def test_tuple_without_type_args(self) -
-
-
- -Expand source code - -
def test_tuple_without_type_args(self):
-    @pedantic
-    def calc(i: Tuple) -> str:
-        return str(i)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(i=(42.0, 43, 'hi'))
-
-
-
-
-def test_type_list_but_got_tuple(self) -
-
-
- -Expand source code - -
def test_type_list_but_got_tuple(self):
-    @pedantic
-    def calc(ls: List[Any]) -> int:
-        return len(ls)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(ls=(1, 2, 3))
-
-
-
-
-def test_type_list_corrected(self) -
-
-
- -Expand source code - -
def test_type_list_corrected(self):
-    @pedantic
-    def calc(ls: Tuple[Any, ...]) -> int:
-        return len(ls)
-
-    calc(ls=(1, 2, 3))
-
-
-
-
-def test_type_var(self) -
-
-
- -Expand source code - -
def test_type_var(self):
-    T = TypeVar('T')
-
-    @pedantic
-    def first(ls: List[T]) -> T:
-        return ls[0]
-
-    first(ls=[1, 2, 3])
-
-
-
-
-def test_type_var_bound_fail(self) -
-
-
- -Expand source code - -
def test_type_var_bound_fail(self):
-    T = TypeVar('T', bound=Child)
-
-    @pedantic
-    def foo(a: T, b: T) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=Parent(), b=Parent())
-
-
-
-
-def test_type_var_constraints(self) -
-
-
- -Expand source code - -
def test_type_var_constraints(self):
-    T = TypeVar('T', int, str)
-
-    @pedantic
-    def foo(a: T, b: T) -> None:
-        pass
-
-    for values in [
-        {'a': 6, 'b': 7},
-        {'a': 'aa', 'b': "bb"},
-    ]:
-        foo(**values)
-
-
-
-
-def test_type_var_constraints_fail_typing_type(self) -
-
-
- -Expand source code - -
def test_type_var_constraints_fail_typing_type(self):
-    T = TypeVar('T', int, Collection)
-
-    @pedantic
-    def foo(a: T, b: T) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a='aa', b='bb')
-
-
-
-
-def test_type_var_contravariant(self) -
-
-
- -Expand source code - -
def test_type_var_contravariant(self):
-    T = TypeVar('T', contravariant=True)
-
-    @pedantic
-    def foo(a: T, b: T) -> None:
-        pass
-
-    foo(a=Child(), b=Parent())
-
-
-
-
-def test_type_var_contravariant_fail(self) -
-
-
- -Expand source code - -
def test_type_var_contravariant_fail(self):
-    T = TypeVar('T', contravariant=True)
-
-    @pedantic
-    def foo(a: T, b: T) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeVarMismatchException):
-        foo(a=Parent(), b=Child())
-
-
-
-
-def test_type_var_covariant(self) -
-
-
- -Expand source code - -
def test_type_var_covariant(self):
-    T = TypeVar('T', covariant=True)
-
-    @pedantic
-    def foo(a: T, b: T) -> None:
-        pass
-
-    foo(a=Parent(), b=Child())
-
-
-
-
-def test_type_var_covariant_fail(self) -
-
-
- -Expand source code - -
def test_type_var_covariant_fail(self):
-    T = TypeVar('T', covariant=True)
-
-    @pedantic
-    def foo(a: T, b: T) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeVarMismatchException):
-        foo(a=Child(), b=Parent())
-
-
-
-
-def test_type_var_forward_ref_bound(self) -
-
-
- -Expand source code - -
def test_type_var_forward_ref_bound(self):
-    TBound = TypeVar('TBound', bound='Parent')
-
-    @pedantic
-    def func(x: TBound) -> None:
-        pass
-
-    func(x=Parent())
-
-    with self.assertRaises(PedanticTypeCheckException):
-        func(x='foo')
-
-
-
-
-def test_type_var_invariant_fail(self) -
-
-
- -Expand source code - -
def test_type_var_invariant_fail(self):
-    T = TypeVar('T', int, str)
-
-    @pedantic
-    def foo(a: T, b: T) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=2, b=3.6)
-
-
-
-
-def test_type_var_wrong(self) -
-
-
- -Expand source code - -
def test_type_var_wrong(self):
-    T = TypeVar('T')
-
-    @pedantic
-    def first(ls: List[T]) -> T:
-        return str(ls[0])
-
-    with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-        first(ls=[1, 2, 3])
-
-
-
-
-def test_type_var_wrong_sequence(self) -
-
-
- -Expand source code - -
def test_type_var_wrong_sequence(self):
-    T = TypeVar('T')
-
-    @pedantic
-    def first(ls: Sequence[T]) -> T:
-        return str(ls[0])
-
-    with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
-        first(ls=[1, 2, 3])
-
-
-
-
-def test_typevar_bound(self) -
-
-
- -Expand source code - -
def test_typevar_bound(self):
-    T = TypeVar('T', bound=Parent)
-
-    @pedantic
-    def foo(a: T, b: T) -> None:
-        pass
-
-    foo(a=Child(), b=Child())
-
-
-
-
-def test_typevar_constraints_fail(self) -
-
-
- -Expand source code - -
def test_typevar_constraints_fail(self):
-    T = TypeVar('T', int, str)
-
-    @pedantic
-    def foo(a: T, b: T) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=2.5, b='aa')
-
-
-
-
-def test_union(self) -
-
-
- -Expand source code - -
def test_union(self):
-    @pedantic
-    def foo(a: Union[str, int]) -> None:
-        pass
-
-    for value in [6, 'xa']:
-        foo(a=value)
-
-
-
-
-def test_union_fail(self) -
-
-
- -Expand source code - -
def test_union_fail(self):
-    @pedantic
-    def foo(a: Union[str, int]) -> None:
-        pass
-
-    for value in [5.6, b'xa']:
-        with self.assertRaises(PedanticTypeCheckException):
-            foo(a=value)
-
-
-
-
-def test_union_new_syntax(self) -
-
-
- -Expand source code - -
def test_union_new_syntax(self):
-    @pedantic
-    def foo(a: str | int) -> None:
-        pass
-
-    for value in [6, 'xa']:
-        foo(a=value)
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=1.7)
-
-
-
-
-def test_union_typing_type(self) -
-
-
- -Expand source code - -
def test_union_typing_type(self):
-    @pedantic
-    def foo(a: Union[str, Collection]) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=1)
-
-
-
-
-def test_varargs(self) -
-
-
- -Expand source code - -
def test_varargs(self):
-    @pedantic
-    def foo(*args: int) -> None:
-        pass
-
-    foo(1, 2)
-
-
-
-
-def test_varargs_fail(self) -
-
-
- -Expand source code - -
def test_varargs_fail(self):
-    @pedantic
-    def foo(*args: int) -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(1, 'a')
-
-
-
-
-def test_wrapped_function(self) -
-
-
- -Expand source code - -
def test_wrapped_function(self):
-    def decorator(func):
-        @wraps(func)
-        def wrapper(*args, **kwargs):
-            return func(*args, **kwargs)
-        return wrapper
-
-    @pedantic
-    @decorator
-    def foo(a: 'Child') -> None:
-        pass
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo(a=Parent())
-
-
-
-
-def test_wrapped_generator_no_return_type_annotation(self) -
-
-
- -Expand source code - -
def test_wrapped_generator_no_return_type_annotation(self):
-    """Test that return type checking works in a generator function too."""
-    @pedantic
-    def generate(a: int) -> Generator[int, int, None]:
-        yield a
-        yield a + 1
-
-    gen = generate(a=1)
-    next(gen)
-
-

Test that return type checking works in a generator function too.

-
-
-def test_wrong_type_hint_1(self) -
-
-
- -Expand source code - -
def test_wrong_type_hint_1(self):
-    """Problem here: str != int"""
-    @pedantic
-    def calc(n: int, m: int, i: int) -> str:
-        return n + m + i
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(n=42, m=40, i=38)
-
-

Problem here: str != int

-
-
-def test_wrong_type_hint_1_corrected(self) -
-
-
- -Expand source code - -
def test_wrong_type_hint_1_corrected(self):
-    @pedantic
-    def calc(n: int, m: int, i: int) -> str:
-        return str(n + m + i)
-
-    calc(n=42, m=40, i=38)
-
-
-
-
-def test_wrong_type_hint_2(self) -
-
-
- -Expand source code - -
def test_wrong_type_hint_2(self):
-    """Problem here: str != int"""
-    @pedantic
-    def calc(n: int, m: int, i: str) -> int:
-        return n + m + i
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(n=42, m=40, i=38)
-
-

Problem here: str != int

-
-
-def test_wrong_type_hint_2_corrected(self) -
-
-
- -Expand source code - -
def test_wrong_type_hint_2_corrected(self):
-    @pedantic
-    def calc(n: int, m: int, i: str) -> int:
-        return n + m + int(i)
-
-    calc(n=42, m=40, i='38')
-
-
-
-
-def test_wrong_type_hint_3(self) -
-
-
- -Expand source code - -
def test_wrong_type_hint_3(self):
-    """Problem here: None != int"""
-    @pedantic
-    def calc(n: int, m: int, i: int) -> None:
-        return n + m + i
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(n=42, m=40, i=38)
-
-

Problem here: None != int

-
-
-def test_wrong_type_hint_4(self) -
-
-
- -Expand source code - -
def test_wrong_type_hint_4(self):
-    """Problem here: None != int"""
-    @pedantic
-    def calc(n: int, m: int, i: int) -> int:
-        print(n + m + i)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        calc(n=42, m=40, i=38)
-
-

Problem here: None != int

-
-
-def test_wrong_type_hint_4_corrected(self) -
-
-
- -Expand source code - -
def test_wrong_type_hint_4_corrected(self):
-    @pedantic
-    def calc(n: int, m: int, i: int) -> int:
-        return n + m + i
-
-    calc(n=42, m=40, i=38)
-
-
-
-
-def test_wrong_type_hint_corrected(self) -
-
-
- -Expand source code - -
def test_wrong_type_hint_corrected(self):
-    @pedantic
-    def calc(n: int, m: int, i: int) -> None:
-        print(n + m + i)
-
-    calc(n=42, m=40, i=38)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_pedantic_async.html b/docs/pedantic/tests/tests_pedantic_async.html deleted file mode 100644 index cfc9dead..00000000 --- a/docs/pedantic/tests/tests_pedantic_async.html +++ /dev/null @@ -1,269 +0,0 @@ - - - - - - -pedantic.tests.tests_pedantic_async API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_pedantic_async

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestPedanticAsyncio -(methodName='runTest') -
-
-
- -Expand source code - -
class TestPedanticAsyncio(unittest.IsolatedAsyncioTestCase):
-    async def test_coroutine_correct_return_type(self):
-        @pedantic
-        async def foo() -> str:
-            await asyncio.sleep(0)
-            return 'foo'
-
-        await foo()
-
-    async def test_coroutine_wrong_return_type(self):
-        @pedantic
-        async def foo() -> str:
-            await asyncio.sleep(0)
-            return 1
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            await foo()
-
-    async def test_coroutine_wrong_argument_type(self):
-        @pedantic
-        async def foo(x: int) -> int:
-            await asyncio.sleep(0)
-            return 1 + x
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            await foo(x=4.5)
-
-    async def test_static_async(self):
-        @pedantic_class
-        class Foo:
-            @staticmethod
-            async def staticmethod() -> int:
-                await asyncio.sleep(0)
-                return 'foo'
-
-            @classmethod
-            async def classmethod(cls) -> int:
-                await asyncio.sleep(0)
-                return 'foo'
-
-            async def method(self) -> int:
-                await asyncio.sleep(0)
-                return 'foo'
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            await Foo.staticmethod()
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            await Foo.classmethod()
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            await Foo().method()
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.async_case.IsolatedAsyncioTestCase
  • -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-async def test_coroutine_correct_return_type(self) -
-
-
- -Expand source code - -
async def test_coroutine_correct_return_type(self):
-    @pedantic
-    async def foo() -> str:
-        await asyncio.sleep(0)
-        return 'foo'
-
-    await foo()
-
-
-
-
-async def test_coroutine_wrong_argument_type(self) -
-
-
- -Expand source code - -
async def test_coroutine_wrong_argument_type(self):
-    @pedantic
-    async def foo(x: int) -> int:
-        await asyncio.sleep(0)
-        return 1 + x
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        await foo(x=4.5)
-
-
-
-
-async def test_coroutine_wrong_return_type(self) -
-
-
- -Expand source code - -
async def test_coroutine_wrong_return_type(self):
-    @pedantic
-    async def foo() -> str:
-        await asyncio.sleep(0)
-        return 1
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        await foo()
-
-
-
-
-async def test_static_async(self) -
-
-
- -Expand source code - -
async def test_static_async(self):
-    @pedantic_class
-    class Foo:
-        @staticmethod
-        async def staticmethod() -> int:
-            await asyncio.sleep(0)
-            return 'foo'
-
-        @classmethod
-        async def classmethod(cls) -> int:
-            await asyncio.sleep(0)
-            return 'foo'
-
-        async def method(self) -> int:
-            await asyncio.sleep(0)
-            return 'foo'
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        await Foo.staticmethod()
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        await Foo.classmethod()
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        await Foo().method()
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_pedantic_class.html b/docs/pedantic/tests/tests_pedantic_class.html deleted file mode 100644 index b2a69f09..00000000 --- a/docs/pedantic/tests/tests_pedantic_class.html +++ /dev/null @@ -1,1511 +0,0 @@ - - - - - - -pedantic.tests.tests_pedantic_class API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_pedantic_class

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestPedanticClass -(methodName='runTest') -
-
-
- -Expand source code - -
class TestPedanticClass(unittest.TestCase):
-    def tearDown(self) -> None:
-        enable_pedantic()
-
-    def test_constructor(self):
-        @pedantic_class
-        class MyClass:
-            def __init__(self, a: int) -> None:
-                self.a = a
-
-        MyClass(a=42)
-
-    def test_constructor_with_list(self):
-        class Foo(IntEnum):
-            A = 1
-            B = 2
-
-        @pedantic_class
-        class MyClass:
-            def __init__(self, b: int, a: List[Foo]) -> None:
-                self.a = a
-                self.b = b
-
-        MyClass(b=42, a=[Foo.A, Foo.B])
-
-    def test_constructor_param_without_type_hint(self):
-        @pedantic_class
-        class MyClass:
-            def __init__(self, a) -> None:
-                self.a = a
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            MyClass(a=42)
-
-    def test_constructor_without_return_type(self):
-        @pedantic_class
-        class MyClass:
-            def __init__(self, a: int):
-                self.a = a
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            MyClass(a=42)
-
-    def test_constructor_wrong_return_type(self):
-        @pedantic_class
-        class MyClass:
-            def __init__(self, a: int) -> int:
-                self.a = a
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            MyClass(a=42)
-
-    def test_constructor_must_be_called_with_kwargs(self):
-        @pedantic_class
-        class MyClass:
-            def __init__(self, a: int) -> None:
-                self.a = a
-
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            MyClass(42)
-
-    def test_multiple_methods(self):
-        @pedantic_class
-        class MyClass:
-            def __init__(self, a: int) -> None:
-                self.a = a
-
-            def calc(self, b: int) -> int:
-                return self.a - b
-
-            def print(self, s: str) -> None:
-                print(f'{self.a} and {s}')
-
-        m = MyClass(a=5)
-        m.calc(b=42)
-        m.print(s='Hi')
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            m.calc(45)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.calc(b=45.0)
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            m.print('Hi')
-
-    def test_multiple_methods_with_missing_and_wrong_type_hints(self):
-        @pedantic_class
-        class MyClass:
-            def __init__(self, a: int) -> None:
-                self.a = a
-
-            def calc(self, b: int) -> float:
-                return self.a - b
-
-            def dream(self, b) -> int:
-                return self.a * b
-
-            def print(self, s: str):
-                print(f'{self.a} and {s}')
-
-        m = MyClass(a=5)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.calc(b=42)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.print(s='Hi')
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.dream(b=2)
-
-    def test_type_annotation_string(self):
-        @pedantic_class
-        class MyClass:
-            def __init__(self, s: str) -> None:
-                self.s = s
-
-            @staticmethod
-            def generator() -> 'MyClass':
-                return MyClass(s='generated')
-
-        MyClass.generator()
-
-    def test_typo_in_type_annotation_string(self):
-        @pedantic_class
-        class MyClass:
-            def __init__(self, s: str) -> None:
-                self.s = s
-
-            @staticmethod
-            def generator() -> 'MyClas':
-                return MyClass(s='generated')
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            MyClass.generator()
-
-    def test_overriding_contains(self):
-        @pedantic_class
-        class MyClass(list):
-            def __contains__(self, item: int) -> bool:
-                return True
-
-        m = MyClass()
-        print(42 in m)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            print('something' in m)
-
-    def test_type_annotation_string_typo(self):
-        @pedantic_class
-        class MyClass:
-            def compare(self, other: 'MyClas') -> bool:
-                return self == other
-
-            def fixed_compare(self, other: 'MyClass') -> bool:
-                return self == other
-
-        m = MyClass()
-        m.fixed_compare(other=m)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.compare(other=m)
-
-    def test_docstring_not_required(self):
-        @pedantic_class
-        class Foo:
-            def __init__(self, a: int) -> None:
-                self.a = a
-
-            def bunk(self) -> int:
-                '''
-                Function with correct docstring. Yes, single-quoted docstrings are allowed too.
-                Returns:
-                    int: 42
-                '''
-                return self.a
-
-        foo = Foo(a=10)
-        foo.bunk()
-
-    def test_overrides(self):
-        @pedantic_class
-        class Abstract:
-            def func(self, b: str) -> str:
-                pass
-
-            def bunk(self) -> int:
-                pass
-
-        @pedantic_class
-        class Foo(Abstract):
-            def __init__(self, a: int) -> None:
-                self.a = a
-
-            @overrides(Abstract)
-            def func(self, b: str) -> str:
-                return b
-
-            @overrides(Abstract)
-            def bunk(self) -> int:
-                return 42
-
-        f = Foo(a=42)
-        f.func(b='Hi')
-        f.bunk()
-
-    def test_overrides_abc(self):
-        @pedantic_class
-        class Abstract(ABC):
-            @abstractmethod
-            def func(self, b: str) -> str:
-                pass
-
-            @abstractmethod
-            def bunk(self) -> int:
-                pass
-
-        @pedantic_class
-        class Foo(Abstract):
-            def __init__(self, a: int) -> None:
-                self.a = a
-
-            @overrides(Abstract)
-            def func(self, b: str) -> str:
-                return b
-
-            @overrides(Abstract)
-            def bunk(self) -> int:
-                return 42
-
-        f = Foo(a=42)
-        f.func(b='Hi')
-        f.bunk()
-
-    def test_overrides_with_type_errors_and_call_by_args3(self):
-        @pedantic_class
-        class Abstract:
-            def func(self, b: str) -> str:
-                pass
-
-            def bunk(self) -> int:
-                pass
-
-        @pedantic_class
-        class Foo(Abstract):
-            def __init__(self, a: int) -> None:
-                self.a = a
-
-            @overrides(Abstract)
-            def func(self, b: str) -> str:
-                return b
-
-            @overrides(Abstract)
-            def bunk(self) -> int:
-                return self.a
-
-        f = Foo(a=42)
-        f.func(b='Hi')
-        f.bunk()
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            f.func('Hi')
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            Foo(a=3.1415)
-        f.a = 3.145
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            f.bunk()
-
-    def test_overrides_goes_wrong(self):
-        @pedantic_class
-        class Parent:
-            def func(self, b: str) -> str:
-                return b + b + b
-
-            def bunk(self) -> int:
-                return 42
-
-        with self.assertRaises(expected_exception=PedanticOverrideException):
-            @pedantic_class
-            class Foo(Parent):
-                def __init__(self, a: int) -> None:
-                    self.a = a
-
-                @overrides(Parent)
-                def funcy(self, b: str) -> str:
-                    return b
-
-                @overrides(Parent)
-                def bunk(self) -> int:
-                    return self.a
-
-            f = Foo(a=40002)
-            f.func(b='Hi')
-            f.bunk()
-
-        p = Parent()
-        p.func(b='Hi')
-        p.bunk()
-
-    def test_static_method_with_sloppy_type_annotation(self):
-        @pedantic_class
-        class MyStaticClass:
-            @staticmethod
-            def double_func(a: int) -> int:
-                x, y = MyStaticClass.static_bar()
-                return x
-
-            @staticmethod
-            def static_bar() -> (int, int):  # this is wrong. Correct would be Tuple[int, int]
-                return 0, 1
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            print(MyStaticClass.double_func(a=0))
-
-    def test_property(self):
-        @pedantic_class
-        class MyClass(object):
-            def __init__(self, some_arg: Any) -> None:
-                self._some_attribute = some_arg
-
-            @property
-            def some_attribute(self) -> int:
-                return self._some_attribute
-
-            @some_attribute.setter
-            def some_attribute(self, value: str) -> None:
-                self._some_attribute = value
-
-            def calc(self, value: float) -> float:
-                return 2 * value
-
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            MyClass(42)
-
-        m = MyClass(some_arg=42)
-        self.assertEqual(m.some_attribute, 42)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.some_attribute = 100
-        self.assertEqual(m.some_attribute, 42)
-        m.some_attribute = '100'
-        self.assertEqual(m._some_attribute, '100')
-        m.calc(value=42.0)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            print(m.some_attribute)
-
-    def test_property_getter_and_setter_misses_type_hints(self):
-        @pedantic_class
-        class MyClass(object):
-            def __init__(self, some_arg: int) -> None:
-                self._some_attribute = some_arg
-
-            @property
-            def some_attribute(self):
-                return self._some_attribute
-
-            @some_attribute.setter
-            def some_attribute(self, value: int):
-                self._some_attribute = value
-
-            def calc(self, value: float) -> float:
-                return 2 * value
-
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            MyClass(42)
-
-        m = MyClass(some_arg=42)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.some_attribute = 100
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            print(m.some_attribute)
-        m.calc(value=42.0)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.calc(value=42)
-
-    def test_default_constructor(self):
-        @pedantic_class
-        class MyClass:
-            def fun(self) -> int:
-                return 42
-        m = MyClass()
-        m.fun()
-
-    def test_optional_callable(self):
-        @pedantic_class
-        class SemanticSimilarity:
-            def __init__(self, post_processing: bool = True, val: Optional[Callable[[float], float]] = None) -> None:
-                if post_processing is None:
-                    self.post_processing = val
-                else:
-                    self.post_processing = lambda x: x
-
-        SemanticSimilarity()
-
-    def test_optional_lambda(self):
-        @pedantic_class
-        class SemanticSimilarity:
-            def __init__(self, val: Callable[[float], float] = lambda x: x) -> None:
-                self.post_processing = val
-
-        SemanticSimilarity()
-
-    def test_class_method_type_annotation_missing(self):
-        @pedantic_class
-        class MyClass:
-            @classmethod
-            def do(cls):
-                print('i did something')
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            MyClass.do()
-
-    def test_class_method_type_annotation(self):
-        @pedantic_class
-        class MyClass:
-            @classmethod
-            def do(cls) -> None:
-                print('i did something')
-
-            @classmethod
-            def calc(cls, x: Union[int, float]) -> int:
-                return x * x
-
-        MyClass.do()
-        MyClass.calc(x=5)
-        m = MyClass()
-        m.do()
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            MyClass.calc(5)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            MyClass.calc(x=5.1)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            MyClass.calc('hi')
-
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            m.calc(5)
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            m.calc(x=5.1)
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            m.calc('hi')
-
-    def test_dataclass_inside(self):
-        """Pedantic cannot be used on dataclasses."""
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            @pedantic_class
-            @dataclass
-            class MyClass:
-                name: str
-                unit_price: float
-                quantity_on_hand: int = 0
-
-    def test_dataclass_outside(self):
-        """Pedantic cannot check the constructor of dataclasses"""
-
-        @dataclass
-        @pedantic_class
-        class MyClass:
-            name: str
-            unit_price: float
-            quantity_on_hand: int = 0
-
-            def total_cost(self) -> int:
-                return self.unit_price * self.quantity_on_hand
-
-        MyClass(name='name', unit_price=5.1)
-        a = MyClass(name='name', unit_price=5.0, quantity_on_hand=42)
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            a.total_cost()
-
-    def test_class_decorator_static_class_method(self):
-        @pedantic_class
-        class Foo:
-            @staticmethod
-            def staticmethod() -> int:
-                return 'foo'
-
-            @classmethod
-            def classmethod(cls) -> int:
-                return 'foo'
-
-            def method(self) -> int:
-                return 'foo'
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            Foo.staticmethod()
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            Foo.classmethod()
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            Foo().method()
-
-    def test_pedantic_class_disable_pedantic(self):
-        disable_pedantic()
-
-        @pedantic_class
-        class MyClass:
-            def __init__(self, pw, **kwargs):
-                self._validate_str_len(new_values=kwargs)
-
-            @staticmethod
-            def _validate_str_len(new_values: Dict[str, Any]) -> None:
-                return 42
-
-            def method(pw, **kwargs):
-                MyClass._validate_str_len(new_values=kwargs)
-
-        MyClass._validate_str_len(None)
-        MyClass._validate_str_len(new_values={1: 1, 2: 2})
-        MyClass(name='hi', age=12, pw='123')
-
-    def test_disable_pedantic_2(self):
-        """ https://github.com/LostInDarkMath/pedantic-python-decorators/issues/37 """
-
-        disable_pedantic()
-
-        @pedantic_class
-        class Foo:
-            def __init__(self) -> None:
-                self._value = 42
-
-            def do(self) -> None:
-                print(self.bar(value=self._value))
-
-            @staticmethod
-            def bar(value: int) -> int:
-                return value + 75
-
-        f = Foo()
-        f.do()
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def tearDown(self) ‑> None -
-
-
- -Expand source code - -
def tearDown(self) -> None:
-    enable_pedantic()
-
-

Hook method for deconstructing the test fixture after testing it.

-
-
-def test_class_decorator_static_class_method(self) -
-
-
- -Expand source code - -
def test_class_decorator_static_class_method(self):
-    @pedantic_class
-    class Foo:
-        @staticmethod
-        def staticmethod() -> int:
-            return 'foo'
-
-        @classmethod
-        def classmethod(cls) -> int:
-            return 'foo'
-
-        def method(self) -> int:
-            return 'foo'
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        Foo.staticmethod()
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        Foo.classmethod()
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        Foo().method()
-
-
-
-
-def test_class_method_type_annotation(self) -
-
-
- -Expand source code - -
def test_class_method_type_annotation(self):
-    @pedantic_class
-    class MyClass:
-        @classmethod
-        def do(cls) -> None:
-            print('i did something')
-
-        @classmethod
-        def calc(cls, x: Union[int, float]) -> int:
-            return x * x
-
-    MyClass.do()
-    MyClass.calc(x=5)
-    m = MyClass()
-    m.do()
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        MyClass.calc(5)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        MyClass.calc(x=5.1)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        MyClass.calc('hi')
-
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        m.calc(5)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.calc(x=5.1)
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        m.calc('hi')
-
-
-
-
-def test_class_method_type_annotation_missing(self) -
-
-
- -Expand source code - -
def test_class_method_type_annotation_missing(self):
-    @pedantic_class
-    class MyClass:
-        @classmethod
-        def do(cls):
-            print('i did something')
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        MyClass.do()
-
-
-
-
-def test_constructor(self) -
-
-
- -Expand source code - -
def test_constructor(self):
-    @pedantic_class
-    class MyClass:
-        def __init__(self, a: int) -> None:
-            self.a = a
-
-    MyClass(a=42)
-
-
-
-
-def test_constructor_must_be_called_with_kwargs(self) -
-
-
- -Expand source code - -
def test_constructor_must_be_called_with_kwargs(self):
-    @pedantic_class
-    class MyClass:
-        def __init__(self, a: int) -> None:
-            self.a = a
-
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        MyClass(42)
-
-
-
-
-def test_constructor_param_without_type_hint(self) -
-
-
- -Expand source code - -
def test_constructor_param_without_type_hint(self):
-    @pedantic_class
-    class MyClass:
-        def __init__(self, a) -> None:
-            self.a = a
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        MyClass(a=42)
-
-
-
-
-def test_constructor_with_list(self) -
-
-
- -Expand source code - -
def test_constructor_with_list(self):
-    class Foo(IntEnum):
-        A = 1
-        B = 2
-
-    @pedantic_class
-    class MyClass:
-        def __init__(self, b: int, a: List[Foo]) -> None:
-            self.a = a
-            self.b = b
-
-    MyClass(b=42, a=[Foo.A, Foo.B])
-
-
-
-
-def test_constructor_without_return_type(self) -
-
-
- -Expand source code - -
def test_constructor_without_return_type(self):
-    @pedantic_class
-    class MyClass:
-        def __init__(self, a: int):
-            self.a = a
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        MyClass(a=42)
-
-
-
-
-def test_constructor_wrong_return_type(self) -
-
-
- -Expand source code - -
def test_constructor_wrong_return_type(self):
-    @pedantic_class
-    class MyClass:
-        def __init__(self, a: int) -> int:
-            self.a = a
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        MyClass(a=42)
-
-
-
-
-def test_dataclass_inside(self) -
-
-
- -Expand source code - -
def test_dataclass_inside(self):
-    """Pedantic cannot be used on dataclasses."""
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        @pedantic_class
-        @dataclass
-        class MyClass:
-            name: str
-            unit_price: float
-            quantity_on_hand: int = 0
-
-

Pedantic cannot be used on dataclasses.

-
-
-def test_dataclass_outside(self) -
-
-
- -Expand source code - -
def test_dataclass_outside(self):
-    """Pedantic cannot check the constructor of dataclasses"""
-
-    @dataclass
-    @pedantic_class
-    class MyClass:
-        name: str
-        unit_price: float
-        quantity_on_hand: int = 0
-
-        def total_cost(self) -> int:
-            return self.unit_price * self.quantity_on_hand
-
-    MyClass(name='name', unit_price=5.1)
-    a = MyClass(name='name', unit_price=5.0, quantity_on_hand=42)
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        a.total_cost()
-
-

Pedantic cannot check the constructor of dataclasses

-
-
-def test_default_constructor(self) -
-
-
- -Expand source code - -
def test_default_constructor(self):
-    @pedantic_class
-    class MyClass:
-        def fun(self) -> int:
-            return 42
-    m = MyClass()
-    m.fun()
-
-
-
-
-def test_disable_pedantic_2(self) -
-
-
- -Expand source code - -
def test_disable_pedantic_2(self):
-    """ https://github.com/LostInDarkMath/pedantic-python-decorators/issues/37 """
-
-    disable_pedantic()
-
-    @pedantic_class
-    class Foo:
-        def __init__(self) -> None:
-            self._value = 42
-
-        def do(self) -> None:
-            print(self.bar(value=self._value))
-
-        @staticmethod
-        def bar(value: int) -> int:
-            return value + 75
-
-    f = Foo()
-    f.do()
-
- -
-
-def test_docstring_not_required(self) -
-
-
- -Expand source code - -
def test_docstring_not_required(self):
-    @pedantic_class
-    class Foo:
-        def __init__(self, a: int) -> None:
-            self.a = a
-
-        def bunk(self) -> int:
-            '''
-            Function with correct docstring. Yes, single-quoted docstrings are allowed too.
-            Returns:
-                int: 42
-            '''
-            return self.a
-
-    foo = Foo(a=10)
-    foo.bunk()
-
-
-
-
-def test_multiple_methods(self) -
-
-
- -Expand source code - -
def test_multiple_methods(self):
-    @pedantic_class
-    class MyClass:
-        def __init__(self, a: int) -> None:
-            self.a = a
-
-        def calc(self, b: int) -> int:
-            return self.a - b
-
-        def print(self, s: str) -> None:
-            print(f'{self.a} and {s}')
-
-    m = MyClass(a=5)
-    m.calc(b=42)
-    m.print(s='Hi')
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        m.calc(45)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.calc(b=45.0)
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        m.print('Hi')
-
-
-
-
-def test_multiple_methods_with_missing_and_wrong_type_hints(self) -
-
-
- -Expand source code - -
def test_multiple_methods_with_missing_and_wrong_type_hints(self):
-    @pedantic_class
-    class MyClass:
-        def __init__(self, a: int) -> None:
-            self.a = a
-
-        def calc(self, b: int) -> float:
-            return self.a - b
-
-        def dream(self, b) -> int:
-            return self.a * b
-
-        def print(self, s: str):
-            print(f'{self.a} and {s}')
-
-    m = MyClass(a=5)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.calc(b=42)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.print(s='Hi')
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.dream(b=2)
-
-
-
-
-def test_optional_callable(self) -
-
-
- -Expand source code - -
def test_optional_callable(self):
-    @pedantic_class
-    class SemanticSimilarity:
-        def __init__(self, post_processing: bool = True, val: Optional[Callable[[float], float]] = None) -> None:
-            if post_processing is None:
-                self.post_processing = val
-            else:
-                self.post_processing = lambda x: x
-
-    SemanticSimilarity()
-
-
-
-
-def test_optional_lambda(self) -
-
-
- -Expand source code - -
def test_optional_lambda(self):
-    @pedantic_class
-    class SemanticSimilarity:
-        def __init__(self, val: Callable[[float], float] = lambda x: x) -> None:
-            self.post_processing = val
-
-    SemanticSimilarity()
-
-
-
-
-def test_overrides(self) -
-
-
- -Expand source code - -
def test_overrides(self):
-    @pedantic_class
-    class Abstract:
-        def func(self, b: str) -> str:
-            pass
-
-        def bunk(self) -> int:
-            pass
-
-    @pedantic_class
-    class Foo(Abstract):
-        def __init__(self, a: int) -> None:
-            self.a = a
-
-        @overrides(Abstract)
-        def func(self, b: str) -> str:
-            return b
-
-        @overrides(Abstract)
-        def bunk(self) -> int:
-            return 42
-
-    f = Foo(a=42)
-    f.func(b='Hi')
-    f.bunk()
-
-
-
-
-def test_overrides_abc(self) -
-
-
- -Expand source code - -
def test_overrides_abc(self):
-    @pedantic_class
-    class Abstract(ABC):
-        @abstractmethod
-        def func(self, b: str) -> str:
-            pass
-
-        @abstractmethod
-        def bunk(self) -> int:
-            pass
-
-    @pedantic_class
-    class Foo(Abstract):
-        def __init__(self, a: int) -> None:
-            self.a = a
-
-        @overrides(Abstract)
-        def func(self, b: str) -> str:
-            return b
-
-        @overrides(Abstract)
-        def bunk(self) -> int:
-            return 42
-
-    f = Foo(a=42)
-    f.func(b='Hi')
-    f.bunk()
-
-
-
-
-def test_overrides_goes_wrong(self) -
-
-
- -Expand source code - -
def test_overrides_goes_wrong(self):
-    @pedantic_class
-    class Parent:
-        def func(self, b: str) -> str:
-            return b + b + b
-
-        def bunk(self) -> int:
-            return 42
-
-    with self.assertRaises(expected_exception=PedanticOverrideException):
-        @pedantic_class
-        class Foo(Parent):
-            def __init__(self, a: int) -> None:
-                self.a = a
-
-            @overrides(Parent)
-            def funcy(self, b: str) -> str:
-                return b
-
-            @overrides(Parent)
-            def bunk(self) -> int:
-                return self.a
-
-        f = Foo(a=40002)
-        f.func(b='Hi')
-        f.bunk()
-
-    p = Parent()
-    p.func(b='Hi')
-    p.bunk()
-
-
-
-
-def test_overrides_with_type_errors_and_call_by_args3(self) -
-
-
- -Expand source code - -
def test_overrides_with_type_errors_and_call_by_args3(self):
-    @pedantic_class
-    class Abstract:
-        def func(self, b: str) -> str:
-            pass
-
-        def bunk(self) -> int:
-            pass
-
-    @pedantic_class
-    class Foo(Abstract):
-        def __init__(self, a: int) -> None:
-            self.a = a
-
-        @overrides(Abstract)
-        def func(self, b: str) -> str:
-            return b
-
-        @overrides(Abstract)
-        def bunk(self) -> int:
-            return self.a
-
-    f = Foo(a=42)
-    f.func(b='Hi')
-    f.bunk()
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        f.func('Hi')
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        Foo(a=3.1415)
-    f.a = 3.145
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        f.bunk()
-
-
-
-
-def test_overriding_contains(self) -
-
-
- -Expand source code - -
def test_overriding_contains(self):
-    @pedantic_class
-    class MyClass(list):
-        def __contains__(self, item: int) -> bool:
-            return True
-
-    m = MyClass()
-    print(42 in m)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        print('something' in m)
-
-
-
-
-def test_pedantic_class_disable_pedantic(self) -
-
-
- -Expand source code - -
def test_pedantic_class_disable_pedantic(self):
-    disable_pedantic()
-
-    @pedantic_class
-    class MyClass:
-        def __init__(self, pw, **kwargs):
-            self._validate_str_len(new_values=kwargs)
-
-        @staticmethod
-        def _validate_str_len(new_values: Dict[str, Any]) -> None:
-            return 42
-
-        def method(pw, **kwargs):
-            MyClass._validate_str_len(new_values=kwargs)
-
-    MyClass._validate_str_len(None)
-    MyClass._validate_str_len(new_values={1: 1, 2: 2})
-    MyClass(name='hi', age=12, pw='123')
-
-
-
-
-def test_property(self) -
-
-
- -Expand source code - -
def test_property(self):
-    @pedantic_class
-    class MyClass(object):
-        def __init__(self, some_arg: Any) -> None:
-            self._some_attribute = some_arg
-
-        @property
-        def some_attribute(self) -> int:
-            return self._some_attribute
-
-        @some_attribute.setter
-        def some_attribute(self, value: str) -> None:
-            self._some_attribute = value
-
-        def calc(self, value: float) -> float:
-            return 2 * value
-
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        MyClass(42)
-
-    m = MyClass(some_arg=42)
-    self.assertEqual(m.some_attribute, 42)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.some_attribute = 100
-    self.assertEqual(m.some_attribute, 42)
-    m.some_attribute = '100'
-    self.assertEqual(m._some_attribute, '100')
-    m.calc(value=42.0)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        print(m.some_attribute)
-
-
-
-
-def test_property_getter_and_setter_misses_type_hints(self) -
-
-
- -Expand source code - -
def test_property_getter_and_setter_misses_type_hints(self):
-    @pedantic_class
-    class MyClass(object):
-        def __init__(self, some_arg: int) -> None:
-            self._some_attribute = some_arg
-
-        @property
-        def some_attribute(self):
-            return self._some_attribute
-
-        @some_attribute.setter
-        def some_attribute(self, value: int):
-            self._some_attribute = value
-
-        def calc(self, value: float) -> float:
-            return 2 * value
-
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        MyClass(42)
-
-    m = MyClass(some_arg=42)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.some_attribute = 100
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        print(m.some_attribute)
-    m.calc(value=42.0)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.calc(value=42)
-
-
-
-
-def test_static_method_with_sloppy_type_annotation(self) -
-
-
- -Expand source code - -
def test_static_method_with_sloppy_type_annotation(self):
-    @pedantic_class
-    class MyStaticClass:
-        @staticmethod
-        def double_func(a: int) -> int:
-            x, y = MyStaticClass.static_bar()
-            return x
-
-        @staticmethod
-        def static_bar() -> (int, int):  # this is wrong. Correct would be Tuple[int, int]
-            return 0, 1
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        print(MyStaticClass.double_func(a=0))
-
-
-
-
-def test_type_annotation_string(self) -
-
-
- -Expand source code - -
def test_type_annotation_string(self):
-    @pedantic_class
-    class MyClass:
-        def __init__(self, s: str) -> None:
-            self.s = s
-
-        @staticmethod
-        def generator() -> 'MyClass':
-            return MyClass(s='generated')
-
-    MyClass.generator()
-
-
-
-
-def test_type_annotation_string_typo(self) -
-
-
- -Expand source code - -
def test_type_annotation_string_typo(self):
-    @pedantic_class
-    class MyClass:
-        def compare(self, other: 'MyClas') -> bool:
-            return self == other
-
-        def fixed_compare(self, other: 'MyClass') -> bool:
-            return self == other
-
-    m = MyClass()
-    m.fixed_compare(other=m)
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        m.compare(other=m)
-
-
-
-
-def test_typo_in_type_annotation_string(self) -
-
-
- -Expand source code - -
def test_typo_in_type_annotation_string(self):
-    @pedantic_class
-    class MyClass:
-        def __init__(self, s: str) -> None:
-            self.s = s
-
-        @staticmethod
-        def generator() -> 'MyClas':
-            return MyClass(s='generated')
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        MyClass.generator()
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_pedantic_class_docstring.html b/docs/pedantic/tests/tests_pedantic_class_docstring.html deleted file mode 100644 index 5df08354..00000000 --- a/docs/pedantic/tests/tests_pedantic_class_docstring.html +++ /dev/null @@ -1,317 +0,0 @@ - - - - - - -pedantic.tests.tests_pedantic_class_docstring API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_pedantic_class_docstring

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestPedanticClassDocstring -(methodName='runTest') -
-
-
- -Expand source code - -
class TestPedanticClassDocstring(unittest.TestCase):
-    def test_require_docstring(self):
-        @pedantic_class_require_docstring
-        class MyClass:
-            def __init__(self, s: str) -> None:
-                """Constructor
-
-                Args:
-                    s (str): name
-                """
-                self.s = s
-
-            def double(self, b: int) -> str:
-                """some method
-
-                Args:
-                    b (int): magic number
-
-                Returns:
-                    str: cool stuff
-
-                """
-                return self.s + str(b)
-
-            @staticmethod
-            def generator() -> 'MyClass':
-                """Static
-
-                Returns:
-                    MyClass: instance
-                """
-                return MyClass(s='generated')
-
-        m = MyClass.generator()
-        m.double(b=42)
-
-    def test_typo_docstring(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_class_require_docstring
-            class MyClass:
-                def __init__(self, s: str) -> None:
-                    """Constructor
-
-                    Args:
-                        s (str): name
-                    """
-                    self.s = s
-
-                @staticmethod
-                def generator() -> 'MyClass':
-                    """Static
-
-                    Returns:
-                        MyClas: instance
-                    """
-                    return MyClass(s='generated')
-
-    def test_wrong_docstring(self):
-        with self.assertRaises(expected_exception=PedanticDocstringException):
-            @pedantic_class_require_docstring
-            class MyClass:
-                def __init__(self, s: str) -> None:
-                    """Constructor
-
-                    Args:
-                        s (str): name
-                    """
-                    self.s = s
-
-                def double(self, b: int) -> str:
-                    """some method
-
-                    Args:
-                        b (float): magic number
-
-                    Returns:
-                        str: cool stuff
-
-                    """
-                    return self.s + str(b)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_require_docstring(self) -
-
-
- -Expand source code - -
def test_require_docstring(self):
-    @pedantic_class_require_docstring
-    class MyClass:
-        def __init__(self, s: str) -> None:
-            """Constructor
-
-            Args:
-                s (str): name
-            """
-            self.s = s
-
-        def double(self, b: int) -> str:
-            """some method
-
-            Args:
-                b (int): magic number
-
-            Returns:
-                str: cool stuff
-
-            """
-            return self.s + str(b)
-
-        @staticmethod
-        def generator() -> 'MyClass':
-            """Static
-
-            Returns:
-                MyClass: instance
-            """
-            return MyClass(s='generated')
-
-    m = MyClass.generator()
-    m.double(b=42)
-
-
-
-
-def test_typo_docstring(self) -
-
-
- -Expand source code - -
def test_typo_docstring(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_class_require_docstring
-        class MyClass:
-            def __init__(self, s: str) -> None:
-                """Constructor
-
-                Args:
-                    s (str): name
-                """
-                self.s = s
-
-            @staticmethod
-            def generator() -> 'MyClass':
-                """Static
-
-                Returns:
-                    MyClas: instance
-                """
-                return MyClass(s='generated')
-
-
-
-
-def test_wrong_docstring(self) -
-
-
- -Expand source code - -
def test_wrong_docstring(self):
-    with self.assertRaises(expected_exception=PedanticDocstringException):
-        @pedantic_class_require_docstring
-        class MyClass:
-            def __init__(self, s: str) -> None:
-                """Constructor
-
-                Args:
-                    s (str): name
-                """
-                self.s = s
-
-            def double(self, b: int) -> str:
-                """some method
-
-                Args:
-                    b (float): magic number
-
-                Returns:
-                    str: cool stuff
-
-                """
-                return self.s + str(b)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_pedantic_python_311.html b/docs/pedantic/tests/tests_pedantic_python_311.html deleted file mode 100644 index da2d4958..00000000 --- a/docs/pedantic/tests/tests_pedantic_python_311.html +++ /dev/null @@ -1,423 +0,0 @@ - - - - - - -pedantic.tests.tests_pedantic_python_311 API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_pedantic_python_311

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestPedanticPython311AddedStuff -(methodName='runTest') -
-
-
- -Expand source code - -
class TestPedanticPython311AddedStuff(unittest.TestCase):
-    def test_typing_never(self):
-        from typing import Never
-
-        @pedantic
-        def never_call_me(arg: Never) -> None:
-            pass
-
-        @pedantic
-        def foo() -> Never:
-            pass
-
-        @pedantic
-        def bar() -> Never:
-            raise ZeroDivisionError('bar')
-
-        with self.assertRaises(expected_exception=ZeroDivisionError):
-            bar()
-
-        with self.assertRaises(PedanticTypeCheckException):
-            foo()
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException) as exc:
-            never_call_me(arg='42')
-
-    def test_literal_string(self):
-        from typing import LiteralString
-
-        @pedantic
-        def foo(s: LiteralString) -> None:
-            pass
-
-        foo(s='Hi')
-        foo(s=2 * 'Hi')
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            foo(s=3)
-
-    def test_self_type(self):
-        from typing import Self
-
-        class Bar:
-            pass
-
-        @pedantic_class
-        class Foo:
-            def f(self) -> Self:
-                return self
-
-            @staticmethod
-            def g() -> Self:
-                return Foo()
-
-            @classmethod
-            def h(cls) -> Self:
-                return cls()
-
-            def f_2(self) -> Self:
-                return Bar()
-
-            @staticmethod
-            def g_2() -> Self:
-                return Bar()
-
-            @classmethod
-            def h_2(cls) -> Self:
-                return Bar()
-
-        f = Foo()
-        assert f.f() == f
-        f.g()
-        f.h()
-        Foo.g()
-        Foo.h()
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            f.f_2()
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            f.g_2()
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            f.h_2()
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            Foo.g_2()
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            Foo.h_2()
-
-    def test_using_self_type_annotation_outside_class(self):
-        from typing import Self
-
-        @pedantic
-        def f() -> Self:
-            return 'hi'
-
-        with self.assertRaises(expected_exception=PedanticTypeCheckException):
-            f()
-
-    def test_type_var_tuple(self):
-        from typing import TypeVarTuple, Generic
-
-        Ts = TypeVarTuple('Ts')
-
-        @pedantic_class
-        class Array(Generic[*Ts]):
-            def __init__(self, *args: *Ts) -> None:
-                self._values = args
-
-        @pedantic
-        def add_dimension(a: Array[*Ts], value: int) -> Array[int, *Ts]:
-            return Array[int, *Ts](value, *a._values)
-
-        array = Array[int, float](42, 3.4)
-        array_2 = Array[bool, int, float, str](True, 4, 3.4, 'hi')
-        extended_array = add_dimension(a=array, value=42)
-        assert extended_array._values == (42, 42, 3.4)
-
-        # this is too complicated at the moment
-        # with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        #     Array[int, float](4.2, 3.4)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_literal_string(self) -
-
-
- -Expand source code - -
def test_literal_string(self):
-    from typing import LiteralString
-
-    @pedantic
-    def foo(s: LiteralString) -> None:
-        pass
-
-    foo(s='Hi')
-    foo(s=2 * 'Hi')
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        foo(s=3)
-
-
-
-
-def test_self_type(self) -
-
-
- -Expand source code - -
def test_self_type(self):
-    from typing import Self
-
-    class Bar:
-        pass
-
-    @pedantic_class
-    class Foo:
-        def f(self) -> Self:
-            return self
-
-        @staticmethod
-        def g() -> Self:
-            return Foo()
-
-        @classmethod
-        def h(cls) -> Self:
-            return cls()
-
-        def f_2(self) -> Self:
-            return Bar()
-
-        @staticmethod
-        def g_2() -> Self:
-            return Bar()
-
-        @classmethod
-        def h_2(cls) -> Self:
-            return Bar()
-
-    f = Foo()
-    assert f.f() == f
-    f.g()
-    f.h()
-    Foo.g()
-    Foo.h()
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        f.f_2()
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        f.g_2()
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        f.h_2()
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        Foo.g_2()
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        Foo.h_2()
-
-
-
-
-def test_type_var_tuple(self) -
-
-
- -Expand source code - -
def test_type_var_tuple(self):
-    from typing import TypeVarTuple, Generic
-
-    Ts = TypeVarTuple('Ts')
-
-    @pedantic_class
-    class Array(Generic[*Ts]):
-        def __init__(self, *args: *Ts) -> None:
-            self._values = args
-
-    @pedantic
-    def add_dimension(a: Array[*Ts], value: int) -> Array[int, *Ts]:
-        return Array[int, *Ts](value, *a._values)
-
-    array = Array[int, float](42, 3.4)
-    array_2 = Array[bool, int, float, str](True, 4, 3.4, 'hi')
-    extended_array = add_dimension(a=array, value=42)
-    assert extended_array._values == (42, 42, 3.4)
-
-    # this is too complicated at the moment
-    # with self.assertRaises(expected_exception=PedanticTypeCheckException):
-    #     Array[int, float](4.2, 3.4)
-
-
-
-
-def test_typing_never(self) -
-
-
- -Expand source code - -
def test_typing_never(self):
-    from typing import Never
-
-    @pedantic
-    def never_call_me(arg: Never) -> None:
-        pass
-
-    @pedantic
-    def foo() -> Never:
-        pass
-
-    @pedantic
-    def bar() -> Never:
-        raise ZeroDivisionError('bar')
-
-    with self.assertRaises(expected_exception=ZeroDivisionError):
-        bar()
-
-    with self.assertRaises(PedanticTypeCheckException):
-        foo()
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException) as exc:
-        never_call_me(arg='42')
-
-
-
-
-def test_using_self_type_annotation_outside_class(self) -
-
-
- -Expand source code - -
def test_using_self_type_annotation_outside_class(self):
-    from typing import Self
-
-    @pedantic
-    def f() -> Self:
-        return 'hi'
-
-    with self.assertRaises(expected_exception=PedanticTypeCheckException):
-        f()
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_require_kwargs.html b/docs/pedantic/tests/tests_require_kwargs.html deleted file mode 100644 index 425e0c5a..00000000 --- a/docs/pedantic/tests/tests_require_kwargs.html +++ /dev/null @@ -1,204 +0,0 @@ - - - - - - -pedantic.tests.tests_require_kwargs API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_require_kwargs

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestRequireKwargs -(methodName='runTest') -
-
-
- -Expand source code - -
class TestRequireKwargs(unittest.TestCase):
-
-    def test_kwargs(self):
-        @require_kwargs
-        def calc(n: int, m: int, i: int) -> int:
-            return n + m + i
-
-        calc(n=1, m=2, i=3)
-
-    def test_no_kwargs_1(self):
-        @require_kwargs
-        def calc(n: int, m: int, i: int) -> int:
-            return n + m + i
-
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            calc(1, m=2, i=3)
-
-    def test_no_kwargs_2(self):
-        @require_kwargs
-        def calc(n: int, m: int, i: int) -> int:
-            return n + m + i
-
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            calc(1, 2, 3)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_kwargs(self) -
-
-
- -Expand source code - -
def test_kwargs(self):
-    @require_kwargs
-    def calc(n: int, m: int, i: int) -> int:
-        return n + m + i
-
-    calc(n=1, m=2, i=3)
-
-
-
-
-def test_no_kwargs_1(self) -
-
-
- -Expand source code - -
def test_no_kwargs_1(self):
-    @require_kwargs
-    def calc(n: int, m: int, i: int) -> int:
-        return n + m + i
-
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        calc(1, m=2, i=3)
-
-
-
-
-def test_no_kwargs_2(self) -
-
-
- -Expand source code - -
def test_no_kwargs_2(self):
-    @require_kwargs
-    def calc(n: int, m: int, i: int) -> int:
-        return n + m + i
-
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        calc(1, 2, 3)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/tests_small_method_decorators.html b/docs/pedantic/tests/tests_small_method_decorators.html deleted file mode 100644 index cf2fec76..00000000 --- a/docs/pedantic/tests/tests_small_method_decorators.html +++ /dev/null @@ -1,988 +0,0 @@ - - - - - - -pedantic.tests.tests_small_method_decorators API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.tests_small_method_decorators

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class AsyncSmallDecoratorTests -(methodName='runTest') -
-
-
- -Expand source code - -
class AsyncSmallDecoratorTests(IsolatedAsyncioTestCase):
-    async def test_overrides_async_instance_method(self) -> None:
-        class MyClassA:
-            async def operation(self): pass
-
-        class MyClassB(MyClassA):
-            @overrides(MyClassA)
-            async def operation(self):
-                await asyncio.sleep(0)
-                return 42
-
-        b = MyClassB()
-        await b.operation()
-
-    async def test_overrides_parent_has_no_such_method_async(self):
-        class MyClassA:
-            pass
-
-        with self.assertRaises(expected_exception=PedanticOverrideException):
-            class MyClassB(MyClassA):
-                @overrides(MyClassA)
-                async def operation(self): return 42
-
-    async def test_count_calls_async(self):
-        @count_calls
-        async def operation(i: int) -> str:
-            await asyncio.sleep(0)
-            return str(i)
-
-        res = await operation(42)
-        self.assertEqual('42', res)
-
-    async def test_trace_async(self):
-        async def some_method(x, y):
-            await asyncio.sleep(0)
-            return x + y
-
-        traced_method = trace(some_method)
-        self.assertEqual(await some_method(42, 99), await traced_method(42, 99))
-
-    async def test_trace_if_returns_async(self):
-        async def some_method(x, y):
-            await asyncio.sleep(0)
-            return x + y
-
-        traced_method = trace_if_returns(100)(some_method)
-        self.assertEqual(await some_method(42, 99), await traced_method(42, 99))
-        self.assertEqual(await some_method(42, 58), await traced_method(42, 58))
-
-    async def test_timer_async(self):
-        @timer
-        async def operation(i: int) -> str:
-            await asyncio.sleep(0.05)
-            return str(i)
-
-        await operation(42)
-
-    async def test_deprecated_async(self):
-        @deprecated
-        async def old_method(i: int) -> str:
-            return str(i)
-
-        with warnings.catch_warnings(record=True) as w:
-            warnings.simplefilter("always")
-            await old_method(42)
-            assert len(w) == 1
-            assert issubclass(w[-1].category, DeprecationWarning)
-            assert "deprecated" in str(w[-1].message)
-
-    async def test_does_same_as_function_async(self):
-        async def some_method(x, y, z):
-            await asyncio.sleep(0)
-            return x * (y + z)
-
-        @does_same_as_function(some_method)
-        async def other_method(x, y, z):
-            await asyncio.sleep(0)
-            return x * y + x * z
-
-        await other_method(1, 2, 3)
-        await other_method(4, 5, 6)
-
-    async def test_does_same_as_function_async_and_sync(self):
-        def some_method(x, y, z):
-            return x * (y + z)
-
-        @does_same_as_function(some_method)
-        async def other_method(x, y, z):
-            await asyncio.sleep(0)
-            return x * y + x * z
-
-        await other_method(1, 2, 3)
-        await other_method(4, 5, 6)
-
-    async def test_does_same_as_function_wrong(self):
-        async def some_method(x, y, z):
-            await asyncio.sleep(0)
-            return x * (y + z)
-
-        @does_same_as_function(some_method)
-        async def other_method(x, y, z):
-            await asyncio.sleep(0)
-            return x * y + z
-
-        await other_method(0, 2, 0)
-
-        with self.assertRaises(expected_exception=AssertionError):
-            await other_method(4, 5, 6)
-
-    async def test_mock_async(self) -> None:
-        @mock(return_value=42)
-        async def my_function(a, b, c): return a + b + c
-
-        assert await my_function(1, 2, 3) == 42
-        assert await my_function(100, 200, 300) == 42
-
-    async def test_require_kwargs(self):
-        @require_kwargs
-        async def calc(n: int, m: int, i: int) -> int:
-            return n + m + i
-
-        await calc(n=1, m=2, i=3)
-
-        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-            await calc(1, m=2, i=3)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.async_case.IsolatedAsyncioTestCase
  • -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-async def test_count_calls_async(self) -
-
-
- -Expand source code - -
async def test_count_calls_async(self):
-    @count_calls
-    async def operation(i: int) -> str:
-        await asyncio.sleep(0)
-        return str(i)
-
-    res = await operation(42)
-    self.assertEqual('42', res)
-
-
-
-
-async def test_deprecated_async(self) -
-
-
- -Expand source code - -
async def test_deprecated_async(self):
-    @deprecated
-    async def old_method(i: int) -> str:
-        return str(i)
-
-    with warnings.catch_warnings(record=True) as w:
-        warnings.simplefilter("always")
-        await old_method(42)
-        assert len(w) == 1
-        assert issubclass(w[-1].category, DeprecationWarning)
-        assert "deprecated" in str(w[-1].message)
-
-
-
-
-async def test_does_same_as_function_async(self) -
-
-
- -Expand source code - -
async def test_does_same_as_function_async(self):
-    async def some_method(x, y, z):
-        await asyncio.sleep(0)
-        return x * (y + z)
-
-    @does_same_as_function(some_method)
-    async def other_method(x, y, z):
-        await asyncio.sleep(0)
-        return x * y + x * z
-
-    await other_method(1, 2, 3)
-    await other_method(4, 5, 6)
-
-
-
-
-async def test_does_same_as_function_async_and_sync(self) -
-
-
- -Expand source code - -
async def test_does_same_as_function_async_and_sync(self):
-    def some_method(x, y, z):
-        return x * (y + z)
-
-    @does_same_as_function(some_method)
-    async def other_method(x, y, z):
-        await asyncio.sleep(0)
-        return x * y + x * z
-
-    await other_method(1, 2, 3)
-    await other_method(4, 5, 6)
-
-
-
-
-async def test_does_same_as_function_wrong(self) -
-
-
- -Expand source code - -
async def test_does_same_as_function_wrong(self):
-    async def some_method(x, y, z):
-        await asyncio.sleep(0)
-        return x * (y + z)
-
-    @does_same_as_function(some_method)
-    async def other_method(x, y, z):
-        await asyncio.sleep(0)
-        return x * y + z
-
-    await other_method(0, 2, 0)
-
-    with self.assertRaises(expected_exception=AssertionError):
-        await other_method(4, 5, 6)
-
-
-
-
-async def test_mock_async(self) ‑> None -
-
-
- -Expand source code - -
async def test_mock_async(self) -> None:
-    @mock(return_value=42)
-    async def my_function(a, b, c): return a + b + c
-
-    assert await my_function(1, 2, 3) == 42
-    assert await my_function(100, 200, 300) == 42
-
-
-
-
-async def test_overrides_async_instance_method(self) ‑> None -
-
-
- -Expand source code - -
async def test_overrides_async_instance_method(self) -> None:
-    class MyClassA:
-        async def operation(self): pass
-
-    class MyClassB(MyClassA):
-        @overrides(MyClassA)
-        async def operation(self):
-            await asyncio.sleep(0)
-            return 42
-
-    b = MyClassB()
-    await b.operation()
-
-
-
-
-async def test_overrides_parent_has_no_such_method_async(self) -
-
-
- -Expand source code - -
async def test_overrides_parent_has_no_such_method_async(self):
-    class MyClassA:
-        pass
-
-    with self.assertRaises(expected_exception=PedanticOverrideException):
-        class MyClassB(MyClassA):
-            @overrides(MyClassA)
-            async def operation(self): return 42
-
-
-
-
-async def test_require_kwargs(self) -
-
-
- -Expand source code - -
async def test_require_kwargs(self):
-    @require_kwargs
-    async def calc(n: int, m: int, i: int) -> int:
-        return n + m + i
-
-    await calc(n=1, m=2, i=3)
-
-    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
-        await calc(1, m=2, i=3)
-
-
-
-
-async def test_timer_async(self) -
-
-
- -Expand source code - -
async def test_timer_async(self):
-    @timer
-    async def operation(i: int) -> str:
-        await asyncio.sleep(0.05)
-        return str(i)
-
-    await operation(42)
-
-
-
-
-async def test_trace_async(self) -
-
-
- -Expand source code - -
async def test_trace_async(self):
-    async def some_method(x, y):
-        await asyncio.sleep(0)
-        return x + y
-
-    traced_method = trace(some_method)
-    self.assertEqual(await some_method(42, 99), await traced_method(42, 99))
-
-
-
-
-async def test_trace_if_returns_async(self) -
-
-
- -Expand source code - -
async def test_trace_if_returns_async(self):
-    async def some_method(x, y):
-        await asyncio.sleep(0)
-        return x + y
-
-    traced_method = trace_if_returns(100)(some_method)
-    self.assertEqual(await some_method(42, 99), await traced_method(42, 99))
-    self.assertEqual(await some_method(42, 58), await traced_method(42, 58))
-
-
-
-
-
-
-class TestSmallDecoratorMethods -(methodName='runTest') -
-
-
- -Expand source code - -
class TestSmallDecoratorMethods(unittest.TestCase):
-    def test_overrides_parent_has_no_such_method(self):
-        class MyClassA:
-            pass
-
-        with self.assertRaises(expected_exception=PedanticOverrideException):
-            class MyClassB(MyClassA):
-                @overrides(MyClassA)
-                def operation(self): pass
-
-    def test_overrides_all_good(self):
-        class MyClassA:
-            def operation(self): pass
-
-        class MyClassB(MyClassA):
-            @overrides(MyClassA)
-            def operation(self):
-                return 42
-
-        b = MyClassB()
-        b.operation()
-
-    def test_overrides_static_method(self):
-        class MyClassA:
-            @staticmethod
-            def operation(): pass
-
-        class MyClassB(MyClassA):
-            @staticmethod
-            @overrides(MyClassA)
-            def operation():
-                return 42
-
-        b = MyClassB()
-        self.assertEqual(b.operation(), 42)
-        self.assertEqual(MyClassB.operation(), 42)
-
-    def test_overrides_below_property(self):
-        class MyClassA:
-            @property
-            @abstractmethod
-            def operation(self): pass
-
-        class MyClassB(MyClassA):
-            @property
-            @overrides(MyClassA)   # Note: it does not work the other way around
-            def operation(self):
-                return 43
-
-        b = MyClassB()
-        self.assertEqual(b.operation, 43)
-
-    def test_overrides_function(self):
-        class MyClassA:
-            pass
-
-        with self.assertRaises(expected_exception=PedanticOverrideException):
-            @overrides(MyClassA)
-            def operation(): return 42
-
-    def test_deprecated_1(self):
-        @deprecated
-        def old_method(i: int) -> str: return str(i)
-
-        with warnings.catch_warnings(record=True) as w:
-            warnings.simplefilter("always")
-            old_method(42)
-            assert len(w) == 1
-            assert issubclass(w[-1].category, DeprecationWarning)
-            assert "deprecated" in str(w[-1].message)
-
-    def test_deprecated_2(self):
-        def old_method(i: int) -> str:
-            return str(i)
-
-        with warnings.catch_warnings(record=True) as w:
-            warnings.simplefilter("always")
-            old_method(42)
-            assert not len(w) == 1
-
-    def test_unimplemented(self):
-        @unimplemented
-        def dirt(i: int) -> str:
-            return str(i)
-
-        with self.assertRaises(expected_exception=NotImplementedException):
-            dirt(42)
-
-    def test_timer(self):
-        @timer
-        def operation(i: int) -> str:
-            return str(i)
-
-        operation(42)
-
-    def test_count_calls(self):
-        @count_calls
-        def operation(i: int) -> str:
-            return str(i)
-
-        operation(42)
-
-    def test_trace(self):
-        def some_method(x, y):
-            return x + y
-
-        traced_method = trace(some_method)
-        self.assertEqual(some_method(42, 99), traced_method(42, 99))
-
-    def test_trace_if_returns(self):
-        def some_method(x, y):
-            return x + y
-        traced_method = trace_if_returns(100)(some_method)
-        self.assertEqual(some_method(42, 99), traced_method(42, 99))
-        self.assertEqual(some_method(42, 58), traced_method(42, 58))
-
-    def test_does_same_as_function(self):
-        def some_method(x, y, z):
-            return x * (y + z)
-
-        @does_same_as_function(some_method)
-        def other_method(x, y, z):
-            return x * y + x * z
-
-        other_method(1, 2, 3)
-        other_method(4, 5, 6)
-
-    def test_does_same_as_function_wrong(self):
-        def some_method(x, y, z):
-            return x * (y + z)
-
-        @does_same_as_function(some_method)
-        def other_method(x, y, z):
-            return x * y + z
-
-        other_method(0, 2, 0)
-        with self.assertRaises(expected_exception=AssertionError):
-            other_method(4, 5, 6)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_count_calls(self) -
-
-
- -Expand source code - -
def test_count_calls(self):
-    @count_calls
-    def operation(i: int) -> str:
-        return str(i)
-
-    operation(42)
-
-
-
-
-def test_deprecated_1(self) -
-
-
- -Expand source code - -
def test_deprecated_1(self):
-    @deprecated
-    def old_method(i: int) -> str: return str(i)
-
-    with warnings.catch_warnings(record=True) as w:
-        warnings.simplefilter("always")
-        old_method(42)
-        assert len(w) == 1
-        assert issubclass(w[-1].category, DeprecationWarning)
-        assert "deprecated" in str(w[-1].message)
-
-
-
-
-def test_deprecated_2(self) -
-
-
- -Expand source code - -
def test_deprecated_2(self):
-    def old_method(i: int) -> str:
-        return str(i)
-
-    with warnings.catch_warnings(record=True) as w:
-        warnings.simplefilter("always")
-        old_method(42)
-        assert not len(w) == 1
-
-
-
-
-def test_does_same_as_function(self) -
-
-
- -Expand source code - -
def test_does_same_as_function(self):
-    def some_method(x, y, z):
-        return x * (y + z)
-
-    @does_same_as_function(some_method)
-    def other_method(x, y, z):
-        return x * y + x * z
-
-    other_method(1, 2, 3)
-    other_method(4, 5, 6)
-
-
-
-
-def test_does_same_as_function_wrong(self) -
-
-
- -Expand source code - -
def test_does_same_as_function_wrong(self):
-    def some_method(x, y, z):
-        return x * (y + z)
-
-    @does_same_as_function(some_method)
-    def other_method(x, y, z):
-        return x * y + z
-
-    other_method(0, 2, 0)
-    with self.assertRaises(expected_exception=AssertionError):
-        other_method(4, 5, 6)
-
-
-
-
-def test_overrides_all_good(self) -
-
-
- -Expand source code - -
def test_overrides_all_good(self):
-    class MyClassA:
-        def operation(self): pass
-
-    class MyClassB(MyClassA):
-        @overrides(MyClassA)
-        def operation(self):
-            return 42
-
-    b = MyClassB()
-    b.operation()
-
-
-
-
-def test_overrides_below_property(self) -
-
-
- -Expand source code - -
def test_overrides_below_property(self):
-    class MyClassA:
-        @property
-        @abstractmethod
-        def operation(self): pass
-
-    class MyClassB(MyClassA):
-        @property
-        @overrides(MyClassA)   # Note: it does not work the other way around
-        def operation(self):
-            return 43
-
-    b = MyClassB()
-    self.assertEqual(b.operation, 43)
-
-
-
-
-def test_overrides_function(self) -
-
-
- -Expand source code - -
def test_overrides_function(self):
-    class MyClassA:
-        pass
-
-    with self.assertRaises(expected_exception=PedanticOverrideException):
-        @overrides(MyClassA)
-        def operation(): return 42
-
-
-
-
-def test_overrides_parent_has_no_such_method(self) -
-
-
- -Expand source code - -
def test_overrides_parent_has_no_such_method(self):
-    class MyClassA:
-        pass
-
-    with self.assertRaises(expected_exception=PedanticOverrideException):
-        class MyClassB(MyClassA):
-            @overrides(MyClassA)
-            def operation(self): pass
-
-
-
-
-def test_overrides_static_method(self) -
-
-
- -Expand source code - -
def test_overrides_static_method(self):
-    class MyClassA:
-        @staticmethod
-        def operation(): pass
-
-    class MyClassB(MyClassA):
-        @staticmethod
-        @overrides(MyClassA)
-        def operation():
-            return 42
-
-    b = MyClassB()
-    self.assertEqual(b.operation(), 42)
-    self.assertEqual(MyClassB.operation(), 42)
-
-
-
-
-def test_timer(self) -
-
-
- -Expand source code - -
def test_timer(self):
-    @timer
-    def operation(i: int) -> str:
-        return str(i)
-
-    operation(42)
-
-
-
-
-def test_trace(self) -
-
-
- -Expand source code - -
def test_trace(self):
-    def some_method(x, y):
-        return x + y
-
-    traced_method = trace(some_method)
-    self.assertEqual(some_method(42, 99), traced_method(42, 99))
-
-
-
-
-def test_trace_if_returns(self) -
-
-
- -Expand source code - -
def test_trace_if_returns(self):
-    def some_method(x, y):
-        return x + y
-    traced_method = trace_if_returns(100)(some_method)
-    self.assertEqual(some_method(42, 99), traced_method(42, 99))
-    self.assertEqual(some_method(42, 58), traced_method(42, 58))
-
-
-
-
-def test_unimplemented(self) -
-
-
- -Expand source code - -
def test_unimplemented(self):
-    @unimplemented
-    def dirt(i: int) -> str:
-        return str(i)
-
-    with self.assertRaises(expected_exception=NotImplementedException):
-        dirt(42)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/index.html b/docs/pedantic/tests/validate/index.html deleted file mode 100644 index 4fd012ff..00000000 --- a/docs/pedantic/tests/validate/index.html +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - -pedantic.tests.validate API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate

-
-
-
-
-

Sub-modules

-
-
pedantic.tests.validate.test_convert_value
-
-
-
-
pedantic.tests.validate.test_datetime_isoformat
-
-
-
-
pedantic.tests.validate.test_flask_parameters
-
-
-
-
pedantic.tests.validate.test_parameter_environment_variable
-
-
-
-
pedantic.tests.validate.test_validate
-
-
-
-
pedantic.tests.validate.test_validator_composite
-
-
-
-
pedantic.tests.validate.test_validator_datetime_unix_timestamp
-
-
-
-
pedantic.tests.validate.test_validator_email
-
-
-
-
pedantic.tests.validate.test_validator_for_each
-
-
-
-
pedantic.tests.validate.test_validator_is_enum
-
-
-
-
pedantic.tests.validate.test_validator_is_uuid
-
-
-
-
pedantic.tests.validate.test_validator_match_pattern
-
-
-
-
pedantic.tests.validate.test_validator_max
-
-
-
-
pedantic.tests.validate.test_validator_max_length
-
-
-
-
pedantic.tests.validate.test_validator_min
-
-
-
-
pedantic.tests.validate.test_validator_min_length
-
-
-
-
pedantic.tests.validate.test_validator_not_empty
-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_convert_value.html b/docs/pedantic/tests/validate/test_convert_value.html deleted file mode 100644 index 484efbc9..00000000 --- a/docs/pedantic/tests/validate/test_convert_value.html +++ /dev/null @@ -1,273 +0,0 @@ - - - - - - -pedantic.tests.validate.test_convert_value API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_convert_value

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestConvertValue -(methodName='runTest') -
-
-
- -Expand source code - -
class TestConvertValue(TestCase):
-    def test_convert_to_bool(self):
-        for value in [True, 1, '1', '  1 ', '  tRuE  ', 'TRUE']:
-            self.assertTrue(convert_value(value=value, target_type=bool))
-
-        for value in [False, 0, '0', '  0 ', '  fAlSe  ', 'FALSE']:
-            self.assertFalse(convert_value(value=value, target_type=bool))
-
-        for value in ['alse', 0.1, '0.2', '  0000 ', 'Talse', 'Frue', 42]:
-            with self.assertRaises(expected_exception=ConversionError):
-                self.assertFalse(convert_value(value=value, target_type=bool))
-
-    def test_convert_to_int(self):
-        for value in range(-4, 4):
-            self.assertEqual(value, convert_value(value=value, target_type=int))
-
-        self.assertEqual(42, convert_value(value='42', target_type=int))
-        self.assertEqual(0, convert_value(value='  0000 ', target_type=int))
-
-        for value in ['alse', 'Talse', 'Frue', 0.2, '0.2']:
-            with self.assertRaises(expected_exception=ConversionError):
-                self.assertFalse(convert_value(value=value, target_type=int))
-
-    def test_convert_to_float(self):
-        for value in range(-4, 4):
-            self.assertEqual(value, convert_value(value=value, target_type=float))
-
-        self.assertEqual(0.2, convert_value(value=0.2, target_type=float))
-        self.assertEqual(0.2, convert_value(value='0.2', target_type=float))
-        self.assertEqual(42, convert_value(value='42', target_type=float))
-        self.assertEqual(0, convert_value(value='  0000 ', target_type=float))
-
-        for value in ['alse', 'Talse', 'Frue']:
-            with self.assertRaises(expected_exception=ConversionError):
-                self.assertFalse(convert_value(value=value, target_type=float))
-
-    def test_convert_to_list(self):
-        for value in [[], [1], ['1', '  1 '], ['  tRuE  ', 'TRUE']]:
-            self.assertEqual(value, convert_value(value=value, target_type=list))
-
-        self.assertEqual(['1', '2', '3'], convert_value(value='1,2,3', target_type=list))
-
-    def test_convert_to_dict(self):
-        for value in [{}, {1: 2}, {'1': '  1 '}, {1: '  tRuE  ', 2: 'TRUE'}]:
-            self.assertEqual(value, convert_value(value=value, target_type=dict))
-
-        self.assertEqual({'1': '1', '2': '4', '3': '7'}, convert_value(value='1:1,2:4,3:7', target_type=dict))
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_convert_to_bool(self) -
-
-
- -Expand source code - -
def test_convert_to_bool(self):
-    for value in [True, 1, '1', '  1 ', '  tRuE  ', 'TRUE']:
-        self.assertTrue(convert_value(value=value, target_type=bool))
-
-    for value in [False, 0, '0', '  0 ', '  fAlSe  ', 'FALSE']:
-        self.assertFalse(convert_value(value=value, target_type=bool))
-
-    for value in ['alse', 0.1, '0.2', '  0000 ', 'Talse', 'Frue', 42]:
-        with self.assertRaises(expected_exception=ConversionError):
-            self.assertFalse(convert_value(value=value, target_type=bool))
-
-
-
-
-def test_convert_to_dict(self) -
-
-
- -Expand source code - -
def test_convert_to_dict(self):
-    for value in [{}, {1: 2}, {'1': '  1 '}, {1: '  tRuE  ', 2: 'TRUE'}]:
-        self.assertEqual(value, convert_value(value=value, target_type=dict))
-
-    self.assertEqual({'1': '1', '2': '4', '3': '7'}, convert_value(value='1:1,2:4,3:7', target_type=dict))
-
-
-
-
-def test_convert_to_float(self) -
-
-
- -Expand source code - -
def test_convert_to_float(self):
-    for value in range(-4, 4):
-        self.assertEqual(value, convert_value(value=value, target_type=float))
-
-    self.assertEqual(0.2, convert_value(value=0.2, target_type=float))
-    self.assertEqual(0.2, convert_value(value='0.2', target_type=float))
-    self.assertEqual(42, convert_value(value='42', target_type=float))
-    self.assertEqual(0, convert_value(value='  0000 ', target_type=float))
-
-    for value in ['alse', 'Talse', 'Frue']:
-        with self.assertRaises(expected_exception=ConversionError):
-            self.assertFalse(convert_value(value=value, target_type=float))
-
-
-
-
-def test_convert_to_int(self) -
-
-
- -Expand source code - -
def test_convert_to_int(self):
-    for value in range(-4, 4):
-        self.assertEqual(value, convert_value(value=value, target_type=int))
-
-    self.assertEqual(42, convert_value(value='42', target_type=int))
-    self.assertEqual(0, convert_value(value='  0000 ', target_type=int))
-
-    for value in ['alse', 'Talse', 'Frue', 0.2, '0.2']:
-        with self.assertRaises(expected_exception=ConversionError):
-            self.assertFalse(convert_value(value=value, target_type=int))
-
-
-
-
-def test_convert_to_list(self) -
-
-
- -Expand source code - -
def test_convert_to_list(self):
-    for value in [[], [1], ['1', '  1 '], ['  tRuE  ', 'TRUE']]:
-        self.assertEqual(value, convert_value(value=value, target_type=list))
-
-    self.assertEqual(['1', '2', '3'], convert_value(value='1,2,3', target_type=list))
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_datetime_isoformat.html b/docs/pedantic/tests/validate/test_datetime_isoformat.html deleted file mode 100644 index 982bd9e1..00000000 --- a/docs/pedantic/tests/validate/test_datetime_isoformat.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - -pedantic.tests.validate.test_datetime_isoformat API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_datetime_isoformat

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestValidatorDatetimeIsoformat -(methodName='runTest') -
-
-
- -Expand source code - -
class TestValidatorDatetimeIsoformat(TestCase):
-    def test_validator_datetime_isoformat(self) -> None:
-        @validate(Parameter(name='x', validators=[DatetimeIsoFormat()]))
-        def foo(x):
-            return x
-
-        now = datetime.now()
-        self.assertTrue(abs((now - foo(now.isoformat()) < timedelta(milliseconds=1))))
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo('12.12.2020')
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo('invalid')
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_validator_datetime_isoformat(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_datetime_isoformat(self) -> None:
-    @validate(Parameter(name='x', validators=[DatetimeIsoFormat()]))
-    def foo(x):
-        return x
-
-    now = datetime.now()
-    self.assertTrue(abs((now - foo(now.isoformat()) < timedelta(milliseconds=1))))
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo('12.12.2020')
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo('invalid')
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_flask_parameters.html b/docs/pedantic/tests/validate/test_flask_parameters.html deleted file mode 100644 index 7e046e9f..00000000 --- a/docs/pedantic/tests/validate/test_flask_parameters.html +++ /dev/null @@ -1,1531 +0,0 @@ - - - - - - -pedantic.tests.validate.test_flask_parameters API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_flask_parameters

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestFlaskParameters -(methodName='runTest') -
-
-
- -Expand source code - -
class TestFlaskParameters(TestCase):
-    def test_validator_flask_json(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/')
-        @validate(
-            FlaskJsonParameter(name='key', validators=[NotEmpty()]),
-        )
-        def hello_world(key: str) -> Response:
-            return jsonify(key)
-
-        @app.route('/required')
-        @validate(
-            FlaskJsonParameter(name='required', required=True),
-            FlaskJsonParameter(name='not_required', required=False),
-            FlaskJsonParameter(name='not_required_with_default', required=False, default=42),
-        )
-        def required_params(required, not_required, not_required_with_default) -> Response:
-            return jsonify({
-                'required': required,
-                'not_required': not_required,
-                'not_required_with_default': not_required_with_default,
-            })
-
-        @app.route('/types')
-        @validate(
-            FlaskJsonParameter(name='bool_param', value_type=bool),
-            FlaskJsonParameter(name='int_param', value_type=int),
-            FlaskJsonParameter(name='float_param', value_type=float),
-            FlaskJsonParameter(name='str_param', value_type=str),
-            FlaskJsonParameter(name='list_param', value_type=list),
-            FlaskJsonParameter(name='dict_param', value_type=dict),
-        )
-        def different_types(
-                bool_param,
-                int_param,
-                float_param,
-                str_param,
-                list_param,
-                dict_param,
-        ) -> Response:
-            return jsonify({
-                'bool_param': bool_param,
-                'int_param': int_param,
-                'float_param': float_param,
-                'str_param': str_param,
-                'list_param': list_param,
-                'dict_param': dict_param,
-            })
-
-        @app.route('/args')
-        @validate(
-            FlaskJsonParameter(name='a', validators=[NotEmpty()]),
-            FlaskJsonParameter(name='b', validators=[NotEmpty()]),
-            return_as=ReturnAs.ARGS,
-        )
-        def names_do_not_need_to_match(my_key: str, another: str) -> Response:
-            return jsonify({
-                'my_key': my_key,
-                'another': another,
-            })
-
-        @app.errorhandler(ParameterException)
-        def handle_validation_error(exception: ParameterException) -> Response:
-            print(str(exception))
-            response = jsonify(exception.to_dict)
-            response.status_code = INVALID
-            return response
-
-        @app.errorhandler(TooManyArguments)
-        def handle_validation_error(exception: TooManyArguments) -> Response:
-            print(str(exception))
-            response = jsonify(str(exception))
-            response.status_code = TOO_MANY_ARGS
-            return response
-
-        with app.test_client() as client:
-            res = client.get('/', data=json.dumps({'key': '  hello world  '}), content_type=JSON)
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual('hello world', res.json)
-
-            res = client.get('/', data=json.dumps({'key': '  '}), content_type=JSON)
-            self.assertEqual(INVALID, res.status_code)
-            expected = {
-                ExceptionDictKey.VALIDATOR: 'NotEmpty',
-                ExceptionDictKey.VALUE: '  ',
-                ExceptionDictKey.MESSAGE: 'Got empty String which is invalid.',
-                ExceptionDictKey.PARAMETER: 'key',
-            }
-            self.assertEqual(expected, res.json)
-
-            data = {
-                'key': '  hello world  ',
-                'required': '1',
-            }
-            res = client.get('/', data=json.dumps(data), content_type=JSON)
-            self.assertEqual(TOO_MANY_ARGS, res.status_code)
-            self.assertEqual("Got unexpected arguments: ['required']", res.json)
-
-    def test_validator_flask_form_data(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/')
-        @validate(FlaskFormParameter(name='key', validators=[NotEmpty()]))
-        def hello_world(key: str) -> Response:
-            return jsonify(key)
-
-        @app.errorhandler(ParameterException)
-        def handle_validation_error(exception: ParameterException) -> Response:
-            print(str(exception))
-            response = jsonify(exception.to_dict)
-            response.status_code = INVALID
-            return response
-
-        with app.test_client() as client:
-            res = client.get('/', data={'key': '  hello world  '})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual('hello world', res.json)
-
-            res = client.get('/', data={'key': '  '})
-            self.assertEqual(INVALID, res.status_code)
-            expected = {
-                ExceptionDictKey.VALIDATOR: 'NotEmpty',
-                ExceptionDictKey.VALUE: '  ',
-                ExceptionDictKey.MESSAGE: 'Got empty String which is invalid.',
-                ExceptionDictKey.PARAMETER: 'key',
-            }
-            self.assertEqual(expected, res.json)
-
-    def test_validator_flask_header(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/')
-        @validate(FlaskHeaderParameter(name='key', validators=[NotEmpty()]))
-        def hello_world(key: str) -> Response:
-            return jsonify(key)
-
-        @app.errorhandler(InvalidHeader)
-        def handle_validation_error(exception: InvalidHeader) -> Response:
-            print(str(exception))
-            response = jsonify(exception.to_dict)
-            response.status_code = INVALID
-            return response
-
-        with app.test_client() as client:
-            res = client.get('/', headers={'key': '  hello world  '}, data={})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual('hello world', res.json)
-
-            res = client.get('/', headers={'key': '  '}, data={})
-            self.assertEqual(INVALID, res.status_code)
-            expected = {
-                ExceptionDictKey.VALUE: '  ',
-                ExceptionDictKey.MESSAGE: 'Got empty String which is invalid.',
-                ExceptionDictKey.PARAMETER: 'key',
-                ExceptionDictKey.VALIDATOR: 'NotEmpty',
-            }
-            self.assertEqual(expected, res.json)
-
-    def test_validator_flask_header_optional_parameter(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/')
-        @validate(FlaskHeaderParameter(name='key', validators=[NotEmpty()], required=False))
-        def hello_world(key: str = None) -> Response:
-            return jsonify(key)
-
-        with app.test_client() as client:
-            res = client.get('/', headers={'key': '  hello world  '}, data={})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual('hello world', res.json)
-
-            res = client.get('/', headers={}, data={})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual(None, res.json)
-
-    def test_validator_flask_get(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/')
-        @validate(FlaskGetParameter(name='key', value_type=str, validators=[NotEmpty()]))
-        def hello_world(key: str) -> Response:
-            return jsonify(key)
-
-        @app.errorhandler(ParameterException)
-        def handle_validation_error(exception: ParameterException) -> Response:
-            print(str(exception))
-            response = jsonify(exception.to_dict)
-            response.status_code = INVALID
-            return response
-
-        with app.test_client() as client:
-            res = client.get('/?key=hello_world', data={})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual('hello_world', res.json)
-
-            res = client.get('/?key=hello world', data={})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual('hello world', res.json)
-
-            res = client.get('/?key= ', data={})
-            self.assertEqual(INVALID, res.status_code)
-            expected = {
-                ExceptionDictKey.VALIDATOR: 'NotEmpty',
-                ExceptionDictKey.VALUE: ' ',
-                ExceptionDictKey.MESSAGE: 'Got empty String which is invalid.',
-                ExceptionDictKey.PARAMETER: 'key',
-            }
-            self.assertEqual(expected, res.json)
-
-    def test_validator_flask_get_multiple_values_for_same_key(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/')
-        @validate(FlaskGetParameter(name='key', value_type=list, validators=[NotEmpty()]))
-        def hello_world(key: List[str]) -> Response:
-            return jsonify(key)
-
-        with app.test_client() as client:
-            res = client.get('/?key=hello&key=world', data={})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual(['hello', 'world'], res.json)
-
-    def test_validator_flask_path(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/<string:key>')
-        @validate(FlaskPathParameter(name='key', validators=[NotEmpty()]))
-        def hello_world(key: str) -> Response:
-            return jsonify(key)
-
-        @app.errorhandler(ParameterException)
-        def handle_validation_error(exception: ParameterException) -> Response:
-            print(str(exception))
-            response = jsonify(exception.to_dict)
-            response.status_code = INVALID
-            return response
-
-        with app.test_client() as client:
-            res = client.get('/hello_world', data={})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual('hello_world', res.json)
-
-            res = client.get('/hello world', data={})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual('hello world', res.json)
-
-            res = client.get('/   ', data={})
-            self.assertEqual(INVALID, res.status_code)
-            expected = {
-                ExceptionDictKey.VALIDATOR: 'NotEmpty',
-                ExceptionDictKey.VALUE: '   ',
-                ExceptionDictKey.MESSAGE: 'Got empty String which is invalid.',
-                ExceptionDictKey.PARAMETER: 'key',
-            }
-            self.assertEqual(expected, res.json)
-
-    def test_invalid_value_type(self) -> None:
-        app = Flask(__name__)
-
-        with self.assertRaises(expected_exception=AssertionError):
-            @app.route('/')
-            @validate(FlaskFormParameter(name='key', value_type=tuple))
-            def hello_world(key: str) -> Response:
-                return jsonify(key)
-
-    def test_wrong_name(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/')
-        @validate(FlaskFormParameter(name='k', value_type=str))
-        def hello_world(key: str) -> Response:
-            return jsonify(key)
-
-        @app.errorhandler(ValidateException)
-        def handle_validation_error(exception: ValidateException) -> Response:
-            print(str(exception))
-            response = jsonify(str(exception))
-            response.status_code = INVALID
-            return response
-
-        with app.test_client() as client:
-            res = client.get(data={'key': 'k'})
-            self.assertEqual(INVALID, res.status_code)
-            self.assertIn('Value for parameter k is required.', res.json)
-
-    def test_default_value(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/')
-        @validate(FlaskFormParameter(name='key', value_type=str, default='42'))
-        def hello_world(key: str) -> Response:
-            return jsonify(key)
-
-        with app.test_client() as client:
-            res = client.get(data={})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual('42', res.json)
-
-    def test_not_required_allows_none_kwargs_without_none(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/')
-        @validate(FlaskFormParameter(name='key', value_type=str, required=False),
-                  return_as=ReturnAs.KWARGS_WITHOUT_NONE)
-        def hello_world(key: str = 'it works') -> Response:
-            return jsonify(key)
-
-        with app.test_client() as client:
-            res = client.get(data={})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual('it works', res.json)
-
-    def test_not_required_allows_none_kwargs_with_none(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/')
-        @validate(FlaskFormParameter(name='key', value_type=str, required=False, default=None),
-                  return_as=ReturnAs.KWARGS_WITH_NONE)
-        def hello_world(key: str) -> Response:
-            return jsonify(key)
-
-        with app.test_client() as client:
-            res = client.get(data={'key': None})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual(None, res.json)
-
-    def test_not_required_with_default(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/')
-        @validate(FlaskFormParameter(name='key', value_type=str, required=False, default='42'))
-        def hello_world(key: str) -> Response:
-            return jsonify(key)
-
-        with app.test_client() as client:
-            res = client.get(data={})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual('42', res.json)
-
-    def test_validator_flask_path_type_conversion(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/<string:key>')
-        @validate(FlaskPathParameter(name='key', value_type=int, validators=[Min(42)]))
-        def hello_world(key: str) -> Response:
-            return jsonify(key)
-
-        @app.errorhandler(ParameterException)
-        def handle_validation_error(exception: ParameterException) -> Response:
-            print(str(exception))
-            response = jsonify(exception.to_dict)
-            response.status_code = INVALID
-            return response
-
-        with app.test_client() as client:
-            res = client.get('/42', data={})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual(42, res.json)
-
-            res = client.get('/42f', data={})
-            self.assertEqual(INVALID, res.status_code)
-            expected = {
-                ExceptionDictKey.VALIDATOR: None,
-                ExceptionDictKey.VALUE: '42f',
-                ExceptionDictKey.MESSAGE: "Value 42f cannot be converted to <class 'int'>.",
-                ExceptionDictKey.PARAMETER: 'key',
-            }
-            self.assertEqual(expected, res.json)
-
-    def test_validator_flask_json_parameter_does_not_get_json(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/')
-        @validate(FlaskJsonParameter(name='key'))
-        def hello_world(key: str) -> Response:
-            return jsonify(key)
-
-        @app.errorhandler(ParameterException)
-        def handle_validation_error(exception: ParameterException) -> Response:
-            print(str(exception))
-            response = jsonify(exception.to_dict)
-            response.status_code = INVALID
-            return response
-
-        with app.test_client() as client:
-            res = client.get('/', data={})
-            self.assertEqual(INVALID, res.status_code)
-            expected = {
-                ExceptionDictKey.VALIDATOR: None,
-                ExceptionDictKey.VALUE: 'None',
-                ExceptionDictKey.MESSAGE: 'Value for parameter key is required.',
-                ExceptionDictKey.PARAMETER: 'key',
-            }
-            self.assertEqual(expected, res.json)
-
-    def test_validator_flask_json_parameter_does_not_get_json_but_default(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/')
-        @validate(FlaskJsonParameter(name='key', default='42'))
-        def hello_world(key: str) -> Response:
-            return jsonify(key)
-
-        with app.test_client() as client:
-            res = client.get('/', data={})
-            self.assertEqual(OK, res.status_code)
-            self.assertEqual('42', res.json)
-
-    def test_too_many_arguments(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/')
-        @validate(FlaskJsonParameter(name='k', value_type=str))
-        def hello_world(**kwargs) -> Response:
-            return jsonify(str(kwargs))
-
-        @app.errorhandler(TooManyArguments)
-        def handle_validation_error(exception: TooManyArguments) -> Response:
-            print(str(exception))
-            response = jsonify(str(exception))
-            response.status_code = INVALID
-            return response
-
-        with app.test_client() as client:
-            res = client.get(data=json.dumps({'k': 'k', 'a': 1}), content_type=JSON)
-            self.assertEqual(INVALID, res.status_code)
-            self.assertEqual("Got unexpected arguments: ['a']", res.json)
-
-    def test_exception_for_required_parameter(self) -> None:
-        app = Flask(__name__)
-        key = 'PASSWORD'
-
-        @app.route('/')
-        @validate(FlaskJsonParameter(name=key, value_type=str))
-        def hello_world(**kwargs) -> Response:
-            return jsonify(str(kwargs))
-
-        @app.errorhandler(ParameterException)
-        def handle_validation_error(exception: ParameterException) -> Response:
-            reason = 'required' if 'required' in exception.message else 'invalid'
-            response = jsonify({exception.parameter_name: [{'KEY': reason}]})
-            response.status_code = INVALID
-            return response
-
-        with app.test_client() as client:
-            res = client.get(data=json.dumps({}), content_type=JSON)
-            self.assertEqual(INVALID, res.status_code)
-            self.assertEqual({key: [{'KEY': 'required'}]}, res.json)
-
-    def test_async_endpoints(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/<int:k>')
-        @validate(FlaskPathParameter(name='k', value_type=int, validators=[Min(42)]))
-        async def hello_world(k) -> Response:
-            return jsonify(str(k))
-
-        @app.route('/foo/<int:k>')
-        @validate(FlaskPathParameter(name='k', value_type=int, validators=[Min(42)]), return_as=ReturnAs.ARGS)
-        async def return_args(k) -> Response:
-            return jsonify(str(k))
-
-        @app.route('/bar/<int:k>')
-        @validate(FlaskPathParameter(name='k', value_type=int, validators=[Min(42)]),
-                  return_as=ReturnAs.KWARGS_WITH_NONE)
-        async def return_kwargs_with_none(k) -> Response:
-            return jsonify(str(k))
-
-        @app.errorhandler(ParameterException)
-        def handle_validation_error(exception: ParameterException) -> Response:
-            response = jsonify(exception.to_dict)
-            response.status_code = INVALID
-            return response
-
-        with app.test_client() as client:
-            res = client.get(path=f'/45')
-            self.assertEqual(OK, res.status_code)
-
-            res = client.get(path=f'/foo/45')
-            self.assertEqual(OK, res.status_code)
-
-            res = client.get(path=f'/bar/45')
-            self.assertEqual(OK, res.status_code)
-
-            res = client.get(path=f'/41')
-            self.assertEqual(INVALID, res.status_code)
-            expected = {
-                ExceptionDictKey.MESSAGE: 'smaller then allowed: 41 is not >= 42',
-                ExceptionDictKey.PARAMETER: 'k',
-                ExceptionDictKey.VALIDATOR: 'Min',
-                ExceptionDictKey.VALUE: '41',
-            }
-            self.assertEqual(expected, res.json)
-
-    def test_json_parameter_with_default_value(self) -> None:
-        app = Flask(__name__)
-
-        @app.route('/testing/message/<string:email>', methods=['POST'])
-        @validate(
-            FlaskPathParameter(name='email', value_type=str, validators=[Email()]),
-            FlaskJsonParameter(name='content', value_type=str, default='this is a fake message', required=False),
-        )
-        def testing_send_system_message(email: str, content: str) -> Response:
-            return jsonify({'email': email, 'content': content})
-
-        with app.test_client() as client:
-            res = client.post(path=f'/testing/message/adam@eva.de')
-            self.assertEqual(OK, res.status_code)
-            expected = {
-                'email': 'adam@eva.de',
-                'content': 'this is a fake message',
-            }
-            self.assertEqual(expected, res.json)
-
-            res = client.post(path=f'/testing/message/adam@eva.de', json={'content': 'hello world'})
-            self.assertEqual(OK, res.status_code)
-            expected = {
-                'email': 'adam@eva.de',
-                'content': 'hello world',
-            }
-            self.assertEqual(expected, res.json)
-
-    def test_generic_deserializer(self) -> None:
-        @dataclass(frozen=True)
-        class User(Deserializable):
-            firstname: str
-            lastname: str
-            age: int
-
-            @staticmethod
-            @overrides(Deserializable)
-            def from_json(data: Dict[str, Any]) -> 'User':
-                return User(
-                    firstname=data['firstname'],
-                    lastname=data['lastname'],
-                    age=Min(value=18).validate_param(value=int(data['age']), parameter_name='age'),
-                )
-
-        app = Flask(__name__)
-
-        @app.route('/foo', methods=['POST'])
-        @validate(
-            GenericFlaskDeserializer(name='user', cls=User, catch_exception=True),
-        )
-        def the_generic_approach(user: User) -> Response:
-            return jsonify({'name': user.firstname})
-
-        @app.route('/bar', methods=['POST'])
-        @validate(
-            GenericFlaskDeserializer(name='user', cls=User, catch_exception=False),
-        )
-        def do_not_catch(user: User) -> Response:
-            return jsonify({'name': user.firstname})
-
-        @app.errorhandler(ParameterException)
-        def handle_validation_error(exception: ParameterException) -> Response:
-            response = jsonify(exception.to_dict)
-            response.status_code = INVALID
-            return response
-
-        with app.test_client() as client:
-            data = {
-                'firstname': 'Albert',
-                'lastname': 'Einstein',
-                'age': '56',
-            }
-            res = client.post(path=f'/foo', json=data)
-            assert res.status_code == 200
-            assert res.json == {'name': 'Albert'}
-
-            data.pop('age')
-            res = client.post(path=f'/foo', json=data)
-            assert res.status_code == 422
-
-            res = client.post(path=f'/bar', json=data)
-            assert res.status_code == 500
-
-            data['age'] = '16'
-            res = client.post(path=f'/foo', json=data)
-            assert res.status_code == 422
-            expected = {
-                ExceptionDictKey.MESSAGE: 'smaller then allowed: 16 is not >= 18',
-                ExceptionDictKey.PARAMETER: 'age',
-                ExceptionDictKey.VALIDATOR: 'Min',
-                ExceptionDictKey.VALUE: '16',
-            }
-            assert res.json == expected
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_async_endpoints(self) ‑> None -
-
-
- -Expand source code - -
def test_async_endpoints(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/<int:k>')
-    @validate(FlaskPathParameter(name='k', value_type=int, validators=[Min(42)]))
-    async def hello_world(k) -> Response:
-        return jsonify(str(k))
-
-    @app.route('/foo/<int:k>')
-    @validate(FlaskPathParameter(name='k', value_type=int, validators=[Min(42)]), return_as=ReturnAs.ARGS)
-    async def return_args(k) -> Response:
-        return jsonify(str(k))
-
-    @app.route('/bar/<int:k>')
-    @validate(FlaskPathParameter(name='k', value_type=int, validators=[Min(42)]),
-              return_as=ReturnAs.KWARGS_WITH_NONE)
-    async def return_kwargs_with_none(k) -> Response:
-        return jsonify(str(k))
-
-    @app.errorhandler(ParameterException)
-    def handle_validation_error(exception: ParameterException) -> Response:
-        response = jsonify(exception.to_dict)
-        response.status_code = INVALID
-        return response
-
-    with app.test_client() as client:
-        res = client.get(path=f'/45')
-        self.assertEqual(OK, res.status_code)
-
-        res = client.get(path=f'/foo/45')
-        self.assertEqual(OK, res.status_code)
-
-        res = client.get(path=f'/bar/45')
-        self.assertEqual(OK, res.status_code)
-
-        res = client.get(path=f'/41')
-        self.assertEqual(INVALID, res.status_code)
-        expected = {
-            ExceptionDictKey.MESSAGE: 'smaller then allowed: 41 is not >= 42',
-            ExceptionDictKey.PARAMETER: 'k',
-            ExceptionDictKey.VALIDATOR: 'Min',
-            ExceptionDictKey.VALUE: '41',
-        }
-        self.assertEqual(expected, res.json)
-
-
-
-
-def test_default_value(self) ‑> None -
-
-
- -Expand source code - -
def test_default_value(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/')
-    @validate(FlaskFormParameter(name='key', value_type=str, default='42'))
-    def hello_world(key: str) -> Response:
-        return jsonify(key)
-
-    with app.test_client() as client:
-        res = client.get(data={})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual('42', res.json)
-
-
-
-
-def test_exception_for_required_parameter(self) ‑> None -
-
-
- -Expand source code - -
def test_exception_for_required_parameter(self) -> None:
-    app = Flask(__name__)
-    key = 'PASSWORD'
-
-    @app.route('/')
-    @validate(FlaskJsonParameter(name=key, value_type=str))
-    def hello_world(**kwargs) -> Response:
-        return jsonify(str(kwargs))
-
-    @app.errorhandler(ParameterException)
-    def handle_validation_error(exception: ParameterException) -> Response:
-        reason = 'required' if 'required' in exception.message else 'invalid'
-        response = jsonify({exception.parameter_name: [{'KEY': reason}]})
-        response.status_code = INVALID
-        return response
-
-    with app.test_client() as client:
-        res = client.get(data=json.dumps({}), content_type=JSON)
-        self.assertEqual(INVALID, res.status_code)
-        self.assertEqual({key: [{'KEY': 'required'}]}, res.json)
-
-
-
-
-def test_generic_deserializer(self) ‑> None -
-
-
- -Expand source code - -
def test_generic_deserializer(self) -> None:
-    @dataclass(frozen=True)
-    class User(Deserializable):
-        firstname: str
-        lastname: str
-        age: int
-
-        @staticmethod
-        @overrides(Deserializable)
-        def from_json(data: Dict[str, Any]) -> 'User':
-            return User(
-                firstname=data['firstname'],
-                lastname=data['lastname'],
-                age=Min(value=18).validate_param(value=int(data['age']), parameter_name='age'),
-            )
-
-    app = Flask(__name__)
-
-    @app.route('/foo', methods=['POST'])
-    @validate(
-        GenericFlaskDeserializer(name='user', cls=User, catch_exception=True),
-    )
-    def the_generic_approach(user: User) -> Response:
-        return jsonify({'name': user.firstname})
-
-    @app.route('/bar', methods=['POST'])
-    @validate(
-        GenericFlaskDeserializer(name='user', cls=User, catch_exception=False),
-    )
-    def do_not_catch(user: User) -> Response:
-        return jsonify({'name': user.firstname})
-
-    @app.errorhandler(ParameterException)
-    def handle_validation_error(exception: ParameterException) -> Response:
-        response = jsonify(exception.to_dict)
-        response.status_code = INVALID
-        return response
-
-    with app.test_client() as client:
-        data = {
-            'firstname': 'Albert',
-            'lastname': 'Einstein',
-            'age': '56',
-        }
-        res = client.post(path=f'/foo', json=data)
-        assert res.status_code == 200
-        assert res.json == {'name': 'Albert'}
-
-        data.pop('age')
-        res = client.post(path=f'/foo', json=data)
-        assert res.status_code == 422
-
-        res = client.post(path=f'/bar', json=data)
-        assert res.status_code == 500
-
-        data['age'] = '16'
-        res = client.post(path=f'/foo', json=data)
-        assert res.status_code == 422
-        expected = {
-            ExceptionDictKey.MESSAGE: 'smaller then allowed: 16 is not >= 18',
-            ExceptionDictKey.PARAMETER: 'age',
-            ExceptionDictKey.VALIDATOR: 'Min',
-            ExceptionDictKey.VALUE: '16',
-        }
-        assert res.json == expected
-
-
-
-
-def test_invalid_value_type(self) ‑> None -
-
-
- -Expand source code - -
def test_invalid_value_type(self) -> None:
-    app = Flask(__name__)
-
-    with self.assertRaises(expected_exception=AssertionError):
-        @app.route('/')
-        @validate(FlaskFormParameter(name='key', value_type=tuple))
-        def hello_world(key: str) -> Response:
-            return jsonify(key)
-
-
-
-
-def test_json_parameter_with_default_value(self) ‑> None -
-
-
- -Expand source code - -
def test_json_parameter_with_default_value(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/testing/message/<string:email>', methods=['POST'])
-    @validate(
-        FlaskPathParameter(name='email', value_type=str, validators=[Email()]),
-        FlaskJsonParameter(name='content', value_type=str, default='this is a fake message', required=False),
-    )
-    def testing_send_system_message(email: str, content: str) -> Response:
-        return jsonify({'email': email, 'content': content})
-
-    with app.test_client() as client:
-        res = client.post(path=f'/testing/message/adam@eva.de')
-        self.assertEqual(OK, res.status_code)
-        expected = {
-            'email': 'adam@eva.de',
-            'content': 'this is a fake message',
-        }
-        self.assertEqual(expected, res.json)
-
-        res = client.post(path=f'/testing/message/adam@eva.de', json={'content': 'hello world'})
-        self.assertEqual(OK, res.status_code)
-        expected = {
-            'email': 'adam@eva.de',
-            'content': 'hello world',
-        }
-        self.assertEqual(expected, res.json)
-
-
-
-
-def test_not_required_allows_none_kwargs_with_none(self) ‑> None -
-
-
- -Expand source code - -
def test_not_required_allows_none_kwargs_with_none(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/')
-    @validate(FlaskFormParameter(name='key', value_type=str, required=False, default=None),
-              return_as=ReturnAs.KWARGS_WITH_NONE)
-    def hello_world(key: str) -> Response:
-        return jsonify(key)
-
-    with app.test_client() as client:
-        res = client.get(data={'key': None})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual(None, res.json)
-
-
-
-
-def test_not_required_allows_none_kwargs_without_none(self) ‑> None -
-
-
- -Expand source code - -
def test_not_required_allows_none_kwargs_without_none(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/')
-    @validate(FlaskFormParameter(name='key', value_type=str, required=False),
-              return_as=ReturnAs.KWARGS_WITHOUT_NONE)
-    def hello_world(key: str = 'it works') -> Response:
-        return jsonify(key)
-
-    with app.test_client() as client:
-        res = client.get(data={})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual('it works', res.json)
-
-
-
-
-def test_not_required_with_default(self) ‑> None -
-
-
- -Expand source code - -
def test_not_required_with_default(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/')
-    @validate(FlaskFormParameter(name='key', value_type=str, required=False, default='42'))
-    def hello_world(key: str) -> Response:
-        return jsonify(key)
-
-    with app.test_client() as client:
-        res = client.get(data={})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual('42', res.json)
-
-
-
-
-def test_too_many_arguments(self) ‑> None -
-
-
- -Expand source code - -
def test_too_many_arguments(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/')
-    @validate(FlaskJsonParameter(name='k', value_type=str))
-    def hello_world(**kwargs) -> Response:
-        return jsonify(str(kwargs))
-
-    @app.errorhandler(TooManyArguments)
-    def handle_validation_error(exception: TooManyArguments) -> Response:
-        print(str(exception))
-        response = jsonify(str(exception))
-        response.status_code = INVALID
-        return response
-
-    with app.test_client() as client:
-        res = client.get(data=json.dumps({'k': 'k', 'a': 1}), content_type=JSON)
-        self.assertEqual(INVALID, res.status_code)
-        self.assertEqual("Got unexpected arguments: ['a']", res.json)
-
-
-
-
-def test_validator_flask_form_data(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_flask_form_data(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/')
-    @validate(FlaskFormParameter(name='key', validators=[NotEmpty()]))
-    def hello_world(key: str) -> Response:
-        return jsonify(key)
-
-    @app.errorhandler(ParameterException)
-    def handle_validation_error(exception: ParameterException) -> Response:
-        print(str(exception))
-        response = jsonify(exception.to_dict)
-        response.status_code = INVALID
-        return response
-
-    with app.test_client() as client:
-        res = client.get('/', data={'key': '  hello world  '})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual('hello world', res.json)
-
-        res = client.get('/', data={'key': '  '})
-        self.assertEqual(INVALID, res.status_code)
-        expected = {
-            ExceptionDictKey.VALIDATOR: 'NotEmpty',
-            ExceptionDictKey.VALUE: '  ',
-            ExceptionDictKey.MESSAGE: 'Got empty String which is invalid.',
-            ExceptionDictKey.PARAMETER: 'key',
-        }
-        self.assertEqual(expected, res.json)
-
-
-
-
-def test_validator_flask_get(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_flask_get(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/')
-    @validate(FlaskGetParameter(name='key', value_type=str, validators=[NotEmpty()]))
-    def hello_world(key: str) -> Response:
-        return jsonify(key)
-
-    @app.errorhandler(ParameterException)
-    def handle_validation_error(exception: ParameterException) -> Response:
-        print(str(exception))
-        response = jsonify(exception.to_dict)
-        response.status_code = INVALID
-        return response
-
-    with app.test_client() as client:
-        res = client.get('/?key=hello_world', data={})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual('hello_world', res.json)
-
-        res = client.get('/?key=hello world', data={})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual('hello world', res.json)
-
-        res = client.get('/?key= ', data={})
-        self.assertEqual(INVALID, res.status_code)
-        expected = {
-            ExceptionDictKey.VALIDATOR: 'NotEmpty',
-            ExceptionDictKey.VALUE: ' ',
-            ExceptionDictKey.MESSAGE: 'Got empty String which is invalid.',
-            ExceptionDictKey.PARAMETER: 'key',
-        }
-        self.assertEqual(expected, res.json)
-
-
-
-
-def test_validator_flask_get_multiple_values_for_same_key(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_flask_get_multiple_values_for_same_key(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/')
-    @validate(FlaskGetParameter(name='key', value_type=list, validators=[NotEmpty()]))
-    def hello_world(key: List[str]) -> Response:
-        return jsonify(key)
-
-    with app.test_client() as client:
-        res = client.get('/?key=hello&key=world', data={})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual(['hello', 'world'], res.json)
-
-
-
-
-def test_validator_flask_header(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_flask_header(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/')
-    @validate(FlaskHeaderParameter(name='key', validators=[NotEmpty()]))
-    def hello_world(key: str) -> Response:
-        return jsonify(key)
-
-    @app.errorhandler(InvalidHeader)
-    def handle_validation_error(exception: InvalidHeader) -> Response:
-        print(str(exception))
-        response = jsonify(exception.to_dict)
-        response.status_code = INVALID
-        return response
-
-    with app.test_client() as client:
-        res = client.get('/', headers={'key': '  hello world  '}, data={})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual('hello world', res.json)
-
-        res = client.get('/', headers={'key': '  '}, data={})
-        self.assertEqual(INVALID, res.status_code)
-        expected = {
-            ExceptionDictKey.VALUE: '  ',
-            ExceptionDictKey.MESSAGE: 'Got empty String which is invalid.',
-            ExceptionDictKey.PARAMETER: 'key',
-            ExceptionDictKey.VALIDATOR: 'NotEmpty',
-        }
-        self.assertEqual(expected, res.json)
-
-
-
-
-def test_validator_flask_header_optional_parameter(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_flask_header_optional_parameter(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/')
-    @validate(FlaskHeaderParameter(name='key', validators=[NotEmpty()], required=False))
-    def hello_world(key: str = None) -> Response:
-        return jsonify(key)
-
-    with app.test_client() as client:
-        res = client.get('/', headers={'key': '  hello world  '}, data={})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual('hello world', res.json)
-
-        res = client.get('/', headers={}, data={})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual(None, res.json)
-
-
-
-
-def test_validator_flask_json(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_flask_json(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/')
-    @validate(
-        FlaskJsonParameter(name='key', validators=[NotEmpty()]),
-    )
-    def hello_world(key: str) -> Response:
-        return jsonify(key)
-
-    @app.route('/required')
-    @validate(
-        FlaskJsonParameter(name='required', required=True),
-        FlaskJsonParameter(name='not_required', required=False),
-        FlaskJsonParameter(name='not_required_with_default', required=False, default=42),
-    )
-    def required_params(required, not_required, not_required_with_default) -> Response:
-        return jsonify({
-            'required': required,
-            'not_required': not_required,
-            'not_required_with_default': not_required_with_default,
-        })
-
-    @app.route('/types')
-    @validate(
-        FlaskJsonParameter(name='bool_param', value_type=bool),
-        FlaskJsonParameter(name='int_param', value_type=int),
-        FlaskJsonParameter(name='float_param', value_type=float),
-        FlaskJsonParameter(name='str_param', value_type=str),
-        FlaskJsonParameter(name='list_param', value_type=list),
-        FlaskJsonParameter(name='dict_param', value_type=dict),
-    )
-    def different_types(
-            bool_param,
-            int_param,
-            float_param,
-            str_param,
-            list_param,
-            dict_param,
-    ) -> Response:
-        return jsonify({
-            'bool_param': bool_param,
-            'int_param': int_param,
-            'float_param': float_param,
-            'str_param': str_param,
-            'list_param': list_param,
-            'dict_param': dict_param,
-        })
-
-    @app.route('/args')
-    @validate(
-        FlaskJsonParameter(name='a', validators=[NotEmpty()]),
-        FlaskJsonParameter(name='b', validators=[NotEmpty()]),
-        return_as=ReturnAs.ARGS,
-    )
-    def names_do_not_need_to_match(my_key: str, another: str) -> Response:
-        return jsonify({
-            'my_key': my_key,
-            'another': another,
-        })
-
-    @app.errorhandler(ParameterException)
-    def handle_validation_error(exception: ParameterException) -> Response:
-        print(str(exception))
-        response = jsonify(exception.to_dict)
-        response.status_code = INVALID
-        return response
-
-    @app.errorhandler(TooManyArguments)
-    def handle_validation_error(exception: TooManyArguments) -> Response:
-        print(str(exception))
-        response = jsonify(str(exception))
-        response.status_code = TOO_MANY_ARGS
-        return response
-
-    with app.test_client() as client:
-        res = client.get('/', data=json.dumps({'key': '  hello world  '}), content_type=JSON)
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual('hello world', res.json)
-
-        res = client.get('/', data=json.dumps({'key': '  '}), content_type=JSON)
-        self.assertEqual(INVALID, res.status_code)
-        expected = {
-            ExceptionDictKey.VALIDATOR: 'NotEmpty',
-            ExceptionDictKey.VALUE: '  ',
-            ExceptionDictKey.MESSAGE: 'Got empty String which is invalid.',
-            ExceptionDictKey.PARAMETER: 'key',
-        }
-        self.assertEqual(expected, res.json)
-
-        data = {
-            'key': '  hello world  ',
-            'required': '1',
-        }
-        res = client.get('/', data=json.dumps(data), content_type=JSON)
-        self.assertEqual(TOO_MANY_ARGS, res.status_code)
-        self.assertEqual("Got unexpected arguments: ['required']", res.json)
-
-
-
-
-def test_validator_flask_json_parameter_does_not_get_json(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_flask_json_parameter_does_not_get_json(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/')
-    @validate(FlaskJsonParameter(name='key'))
-    def hello_world(key: str) -> Response:
-        return jsonify(key)
-
-    @app.errorhandler(ParameterException)
-    def handle_validation_error(exception: ParameterException) -> Response:
-        print(str(exception))
-        response = jsonify(exception.to_dict)
-        response.status_code = INVALID
-        return response
-
-    with app.test_client() as client:
-        res = client.get('/', data={})
-        self.assertEqual(INVALID, res.status_code)
-        expected = {
-            ExceptionDictKey.VALIDATOR: None,
-            ExceptionDictKey.VALUE: 'None',
-            ExceptionDictKey.MESSAGE: 'Value for parameter key is required.',
-            ExceptionDictKey.PARAMETER: 'key',
-        }
-        self.assertEqual(expected, res.json)
-
-
-
-
-def test_validator_flask_json_parameter_does_not_get_json_but_default(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_flask_json_parameter_does_not_get_json_but_default(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/')
-    @validate(FlaskJsonParameter(name='key', default='42'))
-    def hello_world(key: str) -> Response:
-        return jsonify(key)
-
-    with app.test_client() as client:
-        res = client.get('/', data={})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual('42', res.json)
-
-
-
-
-def test_validator_flask_path(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_flask_path(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/<string:key>')
-    @validate(FlaskPathParameter(name='key', validators=[NotEmpty()]))
-    def hello_world(key: str) -> Response:
-        return jsonify(key)
-
-    @app.errorhandler(ParameterException)
-    def handle_validation_error(exception: ParameterException) -> Response:
-        print(str(exception))
-        response = jsonify(exception.to_dict)
-        response.status_code = INVALID
-        return response
-
-    with app.test_client() as client:
-        res = client.get('/hello_world', data={})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual('hello_world', res.json)
-
-        res = client.get('/hello world', data={})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual('hello world', res.json)
-
-        res = client.get('/   ', data={})
-        self.assertEqual(INVALID, res.status_code)
-        expected = {
-            ExceptionDictKey.VALIDATOR: 'NotEmpty',
-            ExceptionDictKey.VALUE: '   ',
-            ExceptionDictKey.MESSAGE: 'Got empty String which is invalid.',
-            ExceptionDictKey.PARAMETER: 'key',
-        }
-        self.assertEqual(expected, res.json)
-
-
-
-
-def test_validator_flask_path_type_conversion(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_flask_path_type_conversion(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/<string:key>')
-    @validate(FlaskPathParameter(name='key', value_type=int, validators=[Min(42)]))
-    def hello_world(key: str) -> Response:
-        return jsonify(key)
-
-    @app.errorhandler(ParameterException)
-    def handle_validation_error(exception: ParameterException) -> Response:
-        print(str(exception))
-        response = jsonify(exception.to_dict)
-        response.status_code = INVALID
-        return response
-
-    with app.test_client() as client:
-        res = client.get('/42', data={})
-        self.assertEqual(OK, res.status_code)
-        self.assertEqual(42, res.json)
-
-        res = client.get('/42f', data={})
-        self.assertEqual(INVALID, res.status_code)
-        expected = {
-            ExceptionDictKey.VALIDATOR: None,
-            ExceptionDictKey.VALUE: '42f',
-            ExceptionDictKey.MESSAGE: "Value 42f cannot be converted to <class 'int'>.",
-            ExceptionDictKey.PARAMETER: 'key',
-        }
-        self.assertEqual(expected, res.json)
-
-
-
-
-def test_wrong_name(self) ‑> None -
-
-
- -Expand source code - -
def test_wrong_name(self) -> None:
-    app = Flask(__name__)
-
-    @app.route('/')
-    @validate(FlaskFormParameter(name='k', value_type=str))
-    def hello_world(key: str) -> Response:
-        return jsonify(key)
-
-    @app.errorhandler(ValidateException)
-    def handle_validation_error(exception: ValidateException) -> Response:
-        print(str(exception))
-        response = jsonify(str(exception))
-        response.status_code = INVALID
-        return response
-
-    with app.test_client() as client:
-        res = client.get(data={'key': 'k'})
-        self.assertEqual(INVALID, res.status_code)
-        self.assertIn('Value for parameter k is required.', res.json)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_parameter_environment_variable.html b/docs/pedantic/tests/validate/test_parameter_environment_variable.html deleted file mode 100644 index 9653e5f4..00000000 --- a/docs/pedantic/tests/validate/test_parameter_environment_variable.html +++ /dev/null @@ -1,377 +0,0 @@ - - - - - - -pedantic.tests.validate.test_parameter_environment_variable API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_parameter_environment_variable

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestParameterEnvironmentVariable -(methodName='runTest') -
-
-
- -Expand source code - -
class TestParameterEnvironmentVariable(TestCase):
-    def setUp(self) -> None:
-        if 'foo' in os.environ:
-            del os.environ['foo']
-
-    def test_parameter_environment_variable_str(self) -> None:
-        @validate(EnvironmentVariableParameter(name='foo', value_type=str))
-        def bar(foo):
-            return foo
-
-        os.environ['foo'] = '42'
-        self.assertEqual('42', bar())
-
-    def test_parameter_environment_variable_int(self) -> None:
-        @validate(EnvironmentVariableParameter(name='foo', value_type=int))
-        def bar(foo):
-            return foo
-
-        os.environ['foo'] = '42'
-        self.assertEqual(42, bar())
-
-    def test_parameter_environment_variable_float(self) -> None:
-        @validate(EnvironmentVariableParameter(name='foo', value_type=float))
-        def bar(foo):
-            return foo
-
-        os.environ['foo'] = '42.7'
-        self.assertEqual(42.7, bar())
-
-    def test_parameter_environment_variable_bool(self) -> None:
-        @validate(EnvironmentVariableParameter(name='foo', value_type=bool))
-        def bar(foo):
-            return foo
-
-        for value in ['true', 'True', 'TRUE']:
-            os.environ['foo'] = value
-            self.assertTrue(bar())
-
-        for value in ['false', 'False', 'FALSE']:
-            os.environ['foo'] = value
-            self.assertFalse(bar())
-
-        for value in ['invalid', 'frue', 'talse']:
-            os.environ['foo'] = value
-
-            with self.assertRaises(expected_exception=ParameterException):
-                bar()
-
-    def test_parameter_environment_variable_not_set(self) -> None:
-        @validate(EnvironmentVariableParameter(name='foo'))
-        def bar(foo):
-            return foo
-
-        with self.assertRaises(expected_exception=ParameterException):
-            bar()
-
-    def test_invalid_value_type(self) -> None:
-        with self.assertRaises(expected_exception=AssertionError):
-            @validate(EnvironmentVariableParameter(name='foo', value_type=dict))
-            def bar(foo):
-                return foo
-
-    def test_parameter_environment_variable_different_name(self) -> None:
-        @validate(EnvironmentVariableParameter(name='foo', env_var_name='fuu', value_type=str))
-        def bar(foo):
-            return foo
-
-        os.environ['fuu'] = '42'
-        self.assertEqual('42', bar())
-
-    def test_two_parameters(self) -> None:
-        @validate(EnvironmentVariableParameter(name='a'), strict=False)
-        def foo(a: float, b: int):
-            print(f'{a} and {b}')
-
-        os.environ['a'] = '42'
-        foo(b=42)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def setUp(self) ‑> None -
-
-
- -Expand source code - -
def setUp(self) -> None:
-    if 'foo' in os.environ:
-        del os.environ['foo']
-
-

Hook method for setting up the test fixture before exercising it.

-
-
-def test_invalid_value_type(self) ‑> None -
-
-
- -Expand source code - -
def test_invalid_value_type(self) -> None:
-    with self.assertRaises(expected_exception=AssertionError):
-        @validate(EnvironmentVariableParameter(name='foo', value_type=dict))
-        def bar(foo):
-            return foo
-
-
-
-
-def test_parameter_environment_variable_bool(self) ‑> None -
-
-
- -Expand source code - -
def test_parameter_environment_variable_bool(self) -> None:
-    @validate(EnvironmentVariableParameter(name='foo', value_type=bool))
-    def bar(foo):
-        return foo
-
-    for value in ['true', 'True', 'TRUE']:
-        os.environ['foo'] = value
-        self.assertTrue(bar())
-
-    for value in ['false', 'False', 'FALSE']:
-        os.environ['foo'] = value
-        self.assertFalse(bar())
-
-    for value in ['invalid', 'frue', 'talse']:
-        os.environ['foo'] = value
-
-        with self.assertRaises(expected_exception=ParameterException):
-            bar()
-
-
-
-
-def test_parameter_environment_variable_different_name(self) ‑> None -
-
-
- -Expand source code - -
def test_parameter_environment_variable_different_name(self) -> None:
-    @validate(EnvironmentVariableParameter(name='foo', env_var_name='fuu', value_type=str))
-    def bar(foo):
-        return foo
-
-    os.environ['fuu'] = '42'
-    self.assertEqual('42', bar())
-
-
-
-
-def test_parameter_environment_variable_float(self) ‑> None -
-
-
- -Expand source code - -
def test_parameter_environment_variable_float(self) -> None:
-    @validate(EnvironmentVariableParameter(name='foo', value_type=float))
-    def bar(foo):
-        return foo
-
-    os.environ['foo'] = '42.7'
-    self.assertEqual(42.7, bar())
-
-
-
-
-def test_parameter_environment_variable_int(self) ‑> None -
-
-
- -Expand source code - -
def test_parameter_environment_variable_int(self) -> None:
-    @validate(EnvironmentVariableParameter(name='foo', value_type=int))
-    def bar(foo):
-        return foo
-
-    os.environ['foo'] = '42'
-    self.assertEqual(42, bar())
-
-
-
-
-def test_parameter_environment_variable_not_set(self) ‑> None -
-
-
- -Expand source code - -
def test_parameter_environment_variable_not_set(self) -> None:
-    @validate(EnvironmentVariableParameter(name='foo'))
-    def bar(foo):
-        return foo
-
-    with self.assertRaises(expected_exception=ParameterException):
-        bar()
-
-
-
-
-def test_parameter_environment_variable_str(self) ‑> None -
-
-
- -Expand source code - -
def test_parameter_environment_variable_str(self) -> None:
-    @validate(EnvironmentVariableParameter(name='foo', value_type=str))
-    def bar(foo):
-        return foo
-
-    os.environ['foo'] = '42'
-    self.assertEqual('42', bar())
-
-
-
-
-def test_two_parameters(self) ‑> None -
-
-
- -Expand source code - -
def test_two_parameters(self) -> None:
-    @validate(EnvironmentVariableParameter(name='a'), strict=False)
-    def foo(a: float, b: int):
-        print(f'{a} and {b}')
-
-    os.environ['a'] = '42'
-    foo(b=42)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_validate.html b/docs/pedantic/tests/validate/test_validate.html deleted file mode 100644 index 878e0bc1..00000000 --- a/docs/pedantic/tests/validate/test_validate.html +++ /dev/null @@ -1,1374 +0,0 @@ - - - - - - -pedantic.tests.validate.test_validate API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_validate

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class AsyncValidateTests -(methodName='runTest') -
-
-
- -Expand source code - -
class AsyncValidateTests(IsolatedAsyncioTestCase):
-    async def test_async_instance_method(self) -> None:
-        class Foo:
-            @validate(Parameter(name='k', value_type=int, validators=[Min(42)]),
-                      return_as=ReturnAs.KWARGS_WITHOUT_NONE)
-            async def bar(self, k):
-                return k
-
-            @validate(Parameter(name='k', value_type=int, validators=[Min(42)]), return_as=ReturnAs.ARGS)
-            async def bar_2(self, k):
-                return k
-
-        f = Foo()
-        res = await f.bar(k=42)
-        self.assertEqual(42, res)
-
-        with self.assertRaises(expected_exception=ParameterException):
-            await f.bar(k=41)
-
-        res = await f.bar_2(k=42)
-        self.assertEqual(42, res)
-
-        with self.assertRaises(expected_exception=ParameterException):
-            await f.bar_2(k=41)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.async_case.IsolatedAsyncioTestCase
  • -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-async def test_async_instance_method(self) ‑> None -
-
-
- -Expand source code - -
async def test_async_instance_method(self) -> None:
-    class Foo:
-        @validate(Parameter(name='k', value_type=int, validators=[Min(42)]),
-                  return_as=ReturnAs.KWARGS_WITHOUT_NONE)
-        async def bar(self, k):
-            return k
-
-        @validate(Parameter(name='k', value_type=int, validators=[Min(42)]), return_as=ReturnAs.ARGS)
-        async def bar_2(self, k):
-            return k
-
-    f = Foo()
-    res = await f.bar(k=42)
-    self.assertEqual(42, res)
-
-    with self.assertRaises(expected_exception=ParameterException):
-        await f.bar(k=41)
-
-    res = await f.bar_2(k=42)
-    self.assertEqual(42, res)
-
-    with self.assertRaises(expected_exception=ParameterException):
-        await f.bar_2(k=41)
-
-
-
-
-
-
-class TestValidate -(methodName='runTest') -
-
-
- -Expand source code - -
class TestValidate(TestCase):
-    def setUp(self) -> None:
-        if 'foo' in os.environ:
-            del os.environ['foo']
-
-    def test_single_validator(self) -> None:
-        validator = MaxLength(3)
-        converted_value = validator.validate(value='hed')
-        self.assertEqual(converted_value, 'hed')
-
-        with self.assertRaises(expected_exception=ValidatorException) as ex:
-            validator.validate(value='hello world')
-
-        expected_error_msg = 'MaxLength: hello world is too long with length 11. Value: hello world'
-        self.assertEqual(expected_error_msg, str(ex.exception))
-
-    def test_single_parameter(self) -> None:
-        parameter = Parameter(name='x', validators=[MaxLength(3)])
-        converted_value = parameter.validate(value='hed')
-        self.assertEqual(converted_value, 'hed')
-
-        with self.assertRaises(expected_exception=ParameterException):
-            parameter.validate(value='hello world')
-
-    def test_multiple_parameters(self) -> None:
-        @validate(
-            Parameter(name='a', validators=[Min(3)]),
-            Parameter(name='b', validators=[Max(3)]),
-            Parameter(name='c', validators=[Max(43)]),
-        )
-        def bar(a, b, c):
-            return a + b + c
-
-        self.assertEqual(11, bar(3, 3, 5))
-        self.assertEqual(11, bar(a=3, b=3, c=5))
-
-    def test_validate_args(self):
-        @validate(
-            Parameter(name='a', validators=[Min(42, include_boundary=False)]),
-            Parameter(name='b', validators=[Min(42, include_boundary=False)]),
-            Parameter(name='c', validators=[Min(42, include_boundary=False)]),
-        )
-        def some_calculation(a, b, c):
-            return a + b + c
-
-        some_calculation(43, 45, 50)
-        with self.assertRaises(expected_exception=ParameterException):
-            some_calculation(30, 40, 50)
-        with self.assertRaises(expected_exception=ParameterException):
-            some_calculation(c=30, a=40, b=50)
-
-    def test_validate_instance_method(self):
-        class MyClass:
-            @validate(
-                Parameter(name='x', validators=[Min(1)]),
-            )
-            def some_calculation(self, x: int) -> int:
-                return x
-
-            @validate(
-                Parameter(name='x', validators=[Min(1)]),
-                return_as=ReturnAs.KWARGS_WITHOUT_NONE,
-            )
-            def some_calculation_2(self, x: int) -> int:
-                return x
-
-        m = MyClass()
-        m.some_calculation(1)
-        m.some_calculation(42)
-
-        with self.assertRaises(expected_exception=ParameterException):
-            m.some_calculation(0)
-        with self.assertRaises(expected_exception=ParameterException):
-            m.some_calculation(-42)
-
-        m.some_calculation_2(1)
-        m.some_calculation_2(42)
-
-        with self.assertRaises(expected_exception=ParameterException):
-            m.some_calculation_2(0)
-        with self.assertRaises(expected_exception=ParameterException):
-            m.some_calculation_2(-42)
-
-    def test_validate_static_method(self):
-        """ The @staticmethod decorator have to be ABOVE the @validate decorator. """
-
-        class MyClass:
-            @staticmethod
-            @validate(
-                Parameter(name='x', validators=[Min(1)]),
-            )
-            def some_calculation(x: int) -> int:
-                return x
-
-        m = MyClass()
-        m.some_calculation(1)
-        m.some_calculation(42)
-
-        with self.assertRaises(expected_exception=ParameterException):
-            m.some_calculation(0)
-        with self.assertRaises(expected_exception=ParameterException):
-            m.some_calculation(-42)
-
-    def test_less_parameter_than_arguments(self):
-        @validate(
-            Parameter(name='b'),
-            strict=False,
-        )
-        def some_calculation(a, b, c):
-            return a + b + c
-
-        some_calculation(43, 0, -50)
-
-        with self.assertRaises(expected_exception=ValidateException):
-            some_calculation(30, None, 50)
-
-    def test_empty_parameter_kwargs_with_none(self):
-        @validate(
-            Parameter(name='a', required=False),
-            Parameter(name='b', required=True),
-            Parameter(name='c', required=False),
-            return_as=ReturnAs.KWARGS_WITH_NONE
-        )
-        def some_calculation(a, b, c):
-            return str(a) + str(b) + str(c)
-
-        self.assertEqual('430-50', some_calculation(43, 0, -50))
-        self.assertEqual('None0None', some_calculation(None, 0, None))
-
-    def test_empty_parameter_kwargs_without_none(self):
-        @validate(
-            Parameter(name='a', required=False),
-            Parameter(name='b', required=True),
-            Parameter(name='c', required=False),
-            return_as=ReturnAs.KWARGS_WITHOUT_NONE
-        )
-        def some_calculation(a: Optional[int] = 1, b: Optional[int] = 2, c:  Optional[int] = 3):
-            return str(a) + str(b) + str(c)
-
-        self.assertEqual('430-50', some_calculation(43, 0, -50))
-        self.assertEqual('103', some_calculation(None, 0, None))
-
-    def test_required(self):
-        @validate(
-            Parameter(name='a', required=True),
-            Parameter(name='b', required=True),
-            Parameter(name='c', required=True),
-        )
-        def some_calculation(a, b, c):
-            return a + b + c
-
-        some_calculation(43, 0, -50)
-
-        with self.assertRaises(expected_exception=ValidateException):
-            some_calculation(30, None, 50)
-
-    def test_call_with_args(self):
-        @validate(
-            Parameter(name='x', validators=[Min(1)]),
-        )
-        def some_calculation(x: int) -> int:
-            return x
-
-        some_calculation(42)
-
-    def test_external_parameter_accepts_value_when_given(self) -> None:
-        @validate(EnvironmentVariableParameter(name='foo'))
-        def bar(foo):
-            return foo
-
-        self.assertEqual('42', bar('42'))
-        self.assertEqual('42', bar(foo='42'))
-
-    def test_external_parameter_ignores_value_when_given(self) -> None:
-        @validate(EnvironmentVariableParameter(name='foo'), ignore_input=True)
-        def bar(foo):
-            return foo
-
-        os.environ['foo'] = '1'
-
-        self.assertEqual('1', bar('42'))
-        self.assertEqual('1', bar(foo='42'))
-
-    def test_external_parameter_mixed_with_normal_parameter(self) -> None:
-        @validate(
-            EnvironmentVariableParameter(name='foo'),
-            Parameter(name='footer'),
-            return_as=ReturnAs.KWARGS_WITHOUT_NONE,
-        )
-        def bar(foo, footer):
-            return foo, footer
-
-        self.assertEqual(('42', 3), bar('42', 3))
-
-        os.environ['foo'] = '42'
-        self.assertEqual(('42', 3), bar(footer=3))
-
-    def test_too_many_arguments(self) -> None:
-        @validate(
-            Parameter(name='x'),
-        )
-        def bar(x):
-            return x
-
-        self.assertEqual(42, bar(42))
-
-        with self.assertRaises(expected_exception=ValidateException):
-            bar(42, 43)
-
-    def test_unexpected_parameter_strict(self) -> None:
-        @validate(Parameter(name='y'))
-        def bar(x):
-            return x
-
-        with self.assertRaises(expected_exception=ValidateException):
-            bar(42)
-        with self.assertRaises(expected_exception=ValidateException):
-            bar(x=42)
-
-    def test_unexpected_parameter_not_strict(self) -> None:
-        @validate(Parameter(name='y'), strict=False)
-        def bar(x):
-            return x
-
-        with self.assertRaises(expected_exception=ValidateException):
-            self.assertEqual(42, bar(42))
-
-        with self.assertRaises(expected_exception=ValidateException):
-            self.assertEqual(42, bar(x=42))
-
-    def test_unexpected_parameter_not_strict_external(self) -> None:
-        @validate(EnvironmentVariableParameter(name='foo'))
-        def bar(x):
-            return x
-
-        with self.assertRaises(expected_exception=ValidateException):
-            self.assertEqual(42, bar(42))
-
-        with self.assertRaises(expected_exception=ValidateException):
-            self.assertEqual(42, bar(x=42))
-
-    def test_return_as_simple(self) -> None:
-        @validate(Parameter(name='x'), return_as=ReturnAs.ARGS)
-        def bar(x):
-            return x
-
-        self.assertEqual(42, bar(42))
-        self.assertEqual(42, bar(x=42))
-
-    def test_return_as_args(self) -> None:
-        @validate(Parameter(name='x'), return_as=ReturnAs.ARGS)
-        def bar(*args, **kwargs):
-            return args, kwargs
-
-        self.assertEqual(((42,), {}), bar(42))
-        self.assertEqual(((42,), {}), bar(x=42))
-
-    def test_return_as_kwargs_with_none(self) -> None:
-        @validate(Parameter(name='x'), return_as=ReturnAs.KWARGS_WITH_NONE)
-        def bar(*args, **kwargs):
-            return args, kwargs
-
-        self.assertEqual(((), {'x': 42}), bar(42))
-        self.assertEqual(((), {'x': 42}), bar(x=42))
-
-    def test_return_as_kwargs_without_none(self) -> None:
-        @validate(Parameter(name='x'), return_as=ReturnAs.KWARGS_WITHOUT_NONE)
-        def bar(*args, **kwargs):
-            return args, kwargs
-
-        self.assertEqual(((), {'x': 42}), bar(42))
-        self.assertEqual(((), {'x': 42}), bar(x=42))
-
-    def test_return_as_args_advanced(self) -> None:
-        @validate(
-            Parameter(name='a'),
-            Parameter(name='b'),
-            Parameter(name='c'),
-            return_as=ReturnAs.ARGS,
-        )
-        def bar(a, b, *args, **kwargs):
-            return a, b, args, kwargs
-
-        bar(a=1, b=3, c=42)
-        bar(1, 3, 4)
-        bar(1, 3, c=4)
-
-    def test_return_as_args_advanced_different_order(self) -> None:
-        @validate(
-            Parameter(name='c'),
-            Parameter(name='a'),
-            Parameter(name='b'),
-            return_as=ReturnAs.ARGS,
-        )
-        def bar(a, b, *args, **kwargs):
-            return a, b, args, kwargs
-
-        self.assertEqual((1, 3, (42,), {}), bar(a=1, b=3, c=42))
-        self.assertEqual((1, 3, (42,), {}), bar(1, 3, 42))
-        self.assertEqual((42, 1, (3,), {}), bar(1, 3, c=42))
-
-    def test_return_multiple_args(self) -> None:
-        @validate(
-            Parameter(name='c'),
-            Parameter(name='a'),
-            Parameter(name='b'),
-            return_as=ReturnAs.KWARGS_WITH_NONE,
-        )
-        def bar(*args, **kwargs):
-            return args, kwargs
-
-        self.assertEqual(((), {'a': 1, 'b': 3, 'c': 42}), bar(a=1, b=3, c=42))
-        self.assertEqual(((), {'a': 3, 'b': 42, 'c': 1}), bar(1, 3, 42))
-        self.assertEqual(((), {'a': 1, 'b': 3, 'c': 42}), bar(1, 3, c=42))
-
-    def test_none_is_not_validated_if_not_required_kwargs_with_none(self) -> None:
-        @validate(Parameter(name='a', validators=[Email()], required=False), return_as=ReturnAs.KWARGS_WITH_NONE)
-        def bar(a: Optional[str]):
-            return a
-
-        self.assertIsNone(bar(a=None))
-        self.assertIsNone(bar(None))
-
-        with self.assertRaises(expected_exception=ParameterException):
-            bar('no_email')
-
-    def test_none_is_not_validated_if_not_required_kwargs_without_none(self) -> None:
-        @validate(Parameter(name='a', validators=[Email()], required=False), return_as=ReturnAs.KWARGS_WITHOUT_NONE)
-        def bar(a: Optional[str] = None):
-            return a
-
-        self.assertIsNone(bar(a=None))
-        self.assertIsNone(bar(None))
-
-        with self.assertRaises(expected_exception=ParameterException):
-            bar('no_email')
-
-    def test_allow_renaming_of_parameter_of_custom_validator(self) -> None:
-        class MyCustomValidator(Validator):
-            def validate(self, i_renamed_this_arg: Any) -> Any:
-                return i_renamed_this_arg
-
-        @validate(Parameter(name='a', validators=[MyCustomValidator()]))
-        def bar(a: int):
-            return a
-
-        self.assertEqual(42, bar(42))
-        self.assertEqual(42, bar(a=42))
-
-    def test_none_is_removed_for_not_required_parameter(self) -> None:
-        @validate(Parameter(name='a', required=False))
-        def bar(a: int = 42):
-            return a
-
-        self.assertEqual(42, bar())
-        self.assertEqual(2, bar(a=2))
-        self.assertEqual(2, bar(2))
-
-    def test_default_value_is_not_validated_internal_parameter(self) -> None:
-        t = datetime(year=2021, month=11, day=24)
-        unix_timestamp = (t - datetime(year=1970, month=1, day=1)).total_seconds()
-
-        @validate(Parameter(name='a', required=False, default=t, validators=[DateTimeUnixTimestamp()]))
-        def bar(a: datetime) -> datetime:
-            return a
-
-        self.assertEqual(t, bar(a=unix_timestamp))
-        self.assertEqual(t, bar())
-
-    def test_no_default_value(self) -> None:
-        @validate(Parameter(name='a', required=False))
-        def bar(a: datetime) -> datetime:
-            return a
-
-        with self.assertRaises(expected_exception=ValidateException):
-            bar()
-
-    def test_default_value_is_not_validated_external_parameter(self) -> None:
-        t = datetime(year=2021, month=11, day=24)
-
-        if 'a' in os.environ:
-            del os.environ['a']
-
-        @validate(EnvironmentVariableParameter(name='a', default=t, validators=[DateTimeUnixTimestamp()], required=False))
-        def bar(a: datetime) -> datetime:
-            return a
-
-        self.assertEqual(t, bar())
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def setUp(self) ‑> None -
-
-
- -Expand source code - -
def setUp(self) -> None:
-    if 'foo' in os.environ:
-        del os.environ['foo']
-
-

Hook method for setting up the test fixture before exercising it.

-
-
-def test_allow_renaming_of_parameter_of_custom_validator(self) ‑> None -
-
-
- -Expand source code - -
def test_allow_renaming_of_parameter_of_custom_validator(self) -> None:
-    class MyCustomValidator(Validator):
-        def validate(self, i_renamed_this_arg: Any) -> Any:
-            return i_renamed_this_arg
-
-    @validate(Parameter(name='a', validators=[MyCustomValidator()]))
-    def bar(a: int):
-        return a
-
-    self.assertEqual(42, bar(42))
-    self.assertEqual(42, bar(a=42))
-
-
-
-
-def test_call_with_args(self) -
-
-
- -Expand source code - -
def test_call_with_args(self):
-    @validate(
-        Parameter(name='x', validators=[Min(1)]),
-    )
-    def some_calculation(x: int) -> int:
-        return x
-
-    some_calculation(42)
-
-
-
-
-def test_default_value_is_not_validated_external_parameter(self) ‑> None -
-
-
- -Expand source code - -
def test_default_value_is_not_validated_external_parameter(self) -> None:
-    t = datetime(year=2021, month=11, day=24)
-
-    if 'a' in os.environ:
-        del os.environ['a']
-
-    @validate(EnvironmentVariableParameter(name='a', default=t, validators=[DateTimeUnixTimestamp()], required=False))
-    def bar(a: datetime) -> datetime:
-        return a
-
-    self.assertEqual(t, bar())
-
-
-
-
-def test_default_value_is_not_validated_internal_parameter(self) ‑> None -
-
-
- -Expand source code - -
def test_default_value_is_not_validated_internal_parameter(self) -> None:
-    t = datetime(year=2021, month=11, day=24)
-    unix_timestamp = (t - datetime(year=1970, month=1, day=1)).total_seconds()
-
-    @validate(Parameter(name='a', required=False, default=t, validators=[DateTimeUnixTimestamp()]))
-    def bar(a: datetime) -> datetime:
-        return a
-
-    self.assertEqual(t, bar(a=unix_timestamp))
-    self.assertEqual(t, bar())
-
-
-
-
-def test_empty_parameter_kwargs_with_none(self) -
-
-
- -Expand source code - -
def test_empty_parameter_kwargs_with_none(self):
-    @validate(
-        Parameter(name='a', required=False),
-        Parameter(name='b', required=True),
-        Parameter(name='c', required=False),
-        return_as=ReturnAs.KWARGS_WITH_NONE
-    )
-    def some_calculation(a, b, c):
-        return str(a) + str(b) + str(c)
-
-    self.assertEqual('430-50', some_calculation(43, 0, -50))
-    self.assertEqual('None0None', some_calculation(None, 0, None))
-
-
-
-
-def test_empty_parameter_kwargs_without_none(self) -
-
-
- -Expand source code - -
def test_empty_parameter_kwargs_without_none(self):
-    @validate(
-        Parameter(name='a', required=False),
-        Parameter(name='b', required=True),
-        Parameter(name='c', required=False),
-        return_as=ReturnAs.KWARGS_WITHOUT_NONE
-    )
-    def some_calculation(a: Optional[int] = 1, b: Optional[int] = 2, c:  Optional[int] = 3):
-        return str(a) + str(b) + str(c)
-
-    self.assertEqual('430-50', some_calculation(43, 0, -50))
-    self.assertEqual('103', some_calculation(None, 0, None))
-
-
-
-
-def test_external_parameter_accepts_value_when_given(self) ‑> None -
-
-
- -Expand source code - -
def test_external_parameter_accepts_value_when_given(self) -> None:
-    @validate(EnvironmentVariableParameter(name='foo'))
-    def bar(foo):
-        return foo
-
-    self.assertEqual('42', bar('42'))
-    self.assertEqual('42', bar(foo='42'))
-
-
-
-
-def test_external_parameter_ignores_value_when_given(self) ‑> None -
-
-
- -Expand source code - -
def test_external_parameter_ignores_value_when_given(self) -> None:
-    @validate(EnvironmentVariableParameter(name='foo'), ignore_input=True)
-    def bar(foo):
-        return foo
-
-    os.environ['foo'] = '1'
-
-    self.assertEqual('1', bar('42'))
-    self.assertEqual('1', bar(foo='42'))
-
-
-
-
-def test_external_parameter_mixed_with_normal_parameter(self) ‑> None -
-
-
- -Expand source code - -
def test_external_parameter_mixed_with_normal_parameter(self) -> None:
-    @validate(
-        EnvironmentVariableParameter(name='foo'),
-        Parameter(name='footer'),
-        return_as=ReturnAs.KWARGS_WITHOUT_NONE,
-    )
-    def bar(foo, footer):
-        return foo, footer
-
-    self.assertEqual(('42', 3), bar('42', 3))
-
-    os.environ['foo'] = '42'
-    self.assertEqual(('42', 3), bar(footer=3))
-
-
-
-
-def test_less_parameter_than_arguments(self) -
-
-
- -Expand source code - -
def test_less_parameter_than_arguments(self):
-    @validate(
-        Parameter(name='b'),
-        strict=False,
-    )
-    def some_calculation(a, b, c):
-        return a + b + c
-
-    some_calculation(43, 0, -50)
-
-    with self.assertRaises(expected_exception=ValidateException):
-        some_calculation(30, None, 50)
-
-
-
-
-def test_multiple_parameters(self) ‑> None -
-
-
- -Expand source code - -
def test_multiple_parameters(self) -> None:
-    @validate(
-        Parameter(name='a', validators=[Min(3)]),
-        Parameter(name='b', validators=[Max(3)]),
-        Parameter(name='c', validators=[Max(43)]),
-    )
-    def bar(a, b, c):
-        return a + b + c
-
-    self.assertEqual(11, bar(3, 3, 5))
-    self.assertEqual(11, bar(a=3, b=3, c=5))
-
-
-
-
-def test_no_default_value(self) ‑> None -
-
-
- -Expand source code - -
def test_no_default_value(self) -> None:
-    @validate(Parameter(name='a', required=False))
-    def bar(a: datetime) -> datetime:
-        return a
-
-    with self.assertRaises(expected_exception=ValidateException):
-        bar()
-
-
-
-
-def test_none_is_not_validated_if_not_required_kwargs_with_none(self) ‑> None -
-
-
- -Expand source code - -
def test_none_is_not_validated_if_not_required_kwargs_with_none(self) -> None:
-    @validate(Parameter(name='a', validators=[Email()], required=False), return_as=ReturnAs.KWARGS_WITH_NONE)
-    def bar(a: Optional[str]):
-        return a
-
-    self.assertIsNone(bar(a=None))
-    self.assertIsNone(bar(None))
-
-    with self.assertRaises(expected_exception=ParameterException):
-        bar('no_email')
-
-
-
-
-def test_none_is_not_validated_if_not_required_kwargs_without_none(self) ‑> None -
-
-
- -Expand source code - -
def test_none_is_not_validated_if_not_required_kwargs_without_none(self) -> None:
-    @validate(Parameter(name='a', validators=[Email()], required=False), return_as=ReturnAs.KWARGS_WITHOUT_NONE)
-    def bar(a: Optional[str] = None):
-        return a
-
-    self.assertIsNone(bar(a=None))
-    self.assertIsNone(bar(None))
-
-    with self.assertRaises(expected_exception=ParameterException):
-        bar('no_email')
-
-
-
-
-def test_none_is_removed_for_not_required_parameter(self) ‑> None -
-
-
- -Expand source code - -
def test_none_is_removed_for_not_required_parameter(self) -> None:
-    @validate(Parameter(name='a', required=False))
-    def bar(a: int = 42):
-        return a
-
-    self.assertEqual(42, bar())
-    self.assertEqual(2, bar(a=2))
-    self.assertEqual(2, bar(2))
-
-
-
-
-def test_required(self) -
-
-
- -Expand source code - -
def test_required(self):
-    @validate(
-        Parameter(name='a', required=True),
-        Parameter(name='b', required=True),
-        Parameter(name='c', required=True),
-    )
-    def some_calculation(a, b, c):
-        return a + b + c
-
-    some_calculation(43, 0, -50)
-
-    with self.assertRaises(expected_exception=ValidateException):
-        some_calculation(30, None, 50)
-
-
-
-
-def test_return_as_args(self) ‑> None -
-
-
- -Expand source code - -
def test_return_as_args(self) -> None:
-    @validate(Parameter(name='x'), return_as=ReturnAs.ARGS)
-    def bar(*args, **kwargs):
-        return args, kwargs
-
-    self.assertEqual(((42,), {}), bar(42))
-    self.assertEqual(((42,), {}), bar(x=42))
-
-
-
-
-def test_return_as_args_advanced(self) ‑> None -
-
-
- -Expand source code - -
def test_return_as_args_advanced(self) -> None:
-    @validate(
-        Parameter(name='a'),
-        Parameter(name='b'),
-        Parameter(name='c'),
-        return_as=ReturnAs.ARGS,
-    )
-    def bar(a, b, *args, **kwargs):
-        return a, b, args, kwargs
-
-    bar(a=1, b=3, c=42)
-    bar(1, 3, 4)
-    bar(1, 3, c=4)
-
-
-
-
-def test_return_as_args_advanced_different_order(self) ‑> None -
-
-
- -Expand source code - -
def test_return_as_args_advanced_different_order(self) -> None:
-    @validate(
-        Parameter(name='c'),
-        Parameter(name='a'),
-        Parameter(name='b'),
-        return_as=ReturnAs.ARGS,
-    )
-    def bar(a, b, *args, **kwargs):
-        return a, b, args, kwargs
-
-    self.assertEqual((1, 3, (42,), {}), bar(a=1, b=3, c=42))
-    self.assertEqual((1, 3, (42,), {}), bar(1, 3, 42))
-    self.assertEqual((42, 1, (3,), {}), bar(1, 3, c=42))
-
-
-
-
-def test_return_as_kwargs_with_none(self) ‑> None -
-
-
- -Expand source code - -
def test_return_as_kwargs_with_none(self) -> None:
-    @validate(Parameter(name='x'), return_as=ReturnAs.KWARGS_WITH_NONE)
-    def bar(*args, **kwargs):
-        return args, kwargs
-
-    self.assertEqual(((), {'x': 42}), bar(42))
-    self.assertEqual(((), {'x': 42}), bar(x=42))
-
-
-
-
-def test_return_as_kwargs_without_none(self) ‑> None -
-
-
- -Expand source code - -
def test_return_as_kwargs_without_none(self) -> None:
-    @validate(Parameter(name='x'), return_as=ReturnAs.KWARGS_WITHOUT_NONE)
-    def bar(*args, **kwargs):
-        return args, kwargs
-
-    self.assertEqual(((), {'x': 42}), bar(42))
-    self.assertEqual(((), {'x': 42}), bar(x=42))
-
-
-
-
-def test_return_as_simple(self) ‑> None -
-
-
- -Expand source code - -
def test_return_as_simple(self) -> None:
-    @validate(Parameter(name='x'), return_as=ReturnAs.ARGS)
-    def bar(x):
-        return x
-
-    self.assertEqual(42, bar(42))
-    self.assertEqual(42, bar(x=42))
-
-
-
-
-def test_return_multiple_args(self) ‑> None -
-
-
- -Expand source code - -
def test_return_multiple_args(self) -> None:
-    @validate(
-        Parameter(name='c'),
-        Parameter(name='a'),
-        Parameter(name='b'),
-        return_as=ReturnAs.KWARGS_WITH_NONE,
-    )
-    def bar(*args, **kwargs):
-        return args, kwargs
-
-    self.assertEqual(((), {'a': 1, 'b': 3, 'c': 42}), bar(a=1, b=3, c=42))
-    self.assertEqual(((), {'a': 3, 'b': 42, 'c': 1}), bar(1, 3, 42))
-    self.assertEqual(((), {'a': 1, 'b': 3, 'c': 42}), bar(1, 3, c=42))
-
-
-
-
-def test_single_parameter(self) ‑> None -
-
-
- -Expand source code - -
def test_single_parameter(self) -> None:
-    parameter = Parameter(name='x', validators=[MaxLength(3)])
-    converted_value = parameter.validate(value='hed')
-    self.assertEqual(converted_value, 'hed')
-
-    with self.assertRaises(expected_exception=ParameterException):
-        parameter.validate(value='hello world')
-
-
-
-
-def test_single_validator(self) ‑> None -
-
-
- -Expand source code - -
def test_single_validator(self) -> None:
-    validator = MaxLength(3)
-    converted_value = validator.validate(value='hed')
-    self.assertEqual(converted_value, 'hed')
-
-    with self.assertRaises(expected_exception=ValidatorException) as ex:
-        validator.validate(value='hello world')
-
-    expected_error_msg = 'MaxLength: hello world is too long with length 11. Value: hello world'
-    self.assertEqual(expected_error_msg, str(ex.exception))
-
-
-
-
-def test_too_many_arguments(self) ‑> None -
-
-
- -Expand source code - -
def test_too_many_arguments(self) -> None:
-    @validate(
-        Parameter(name='x'),
-    )
-    def bar(x):
-        return x
-
-    self.assertEqual(42, bar(42))
-
-    with self.assertRaises(expected_exception=ValidateException):
-        bar(42, 43)
-
-
-
-
-def test_unexpected_parameter_not_strict(self) ‑> None -
-
-
- -Expand source code - -
def test_unexpected_parameter_not_strict(self) -> None:
-    @validate(Parameter(name='y'), strict=False)
-    def bar(x):
-        return x
-
-    with self.assertRaises(expected_exception=ValidateException):
-        self.assertEqual(42, bar(42))
-
-    with self.assertRaises(expected_exception=ValidateException):
-        self.assertEqual(42, bar(x=42))
-
-
-
-
-def test_unexpected_parameter_not_strict_external(self) ‑> None -
-
-
- -Expand source code - -
def test_unexpected_parameter_not_strict_external(self) -> None:
-    @validate(EnvironmentVariableParameter(name='foo'))
-    def bar(x):
-        return x
-
-    with self.assertRaises(expected_exception=ValidateException):
-        self.assertEqual(42, bar(42))
-
-    with self.assertRaises(expected_exception=ValidateException):
-        self.assertEqual(42, bar(x=42))
-
-
-
-
-def test_unexpected_parameter_strict(self) ‑> None -
-
-
- -Expand source code - -
def test_unexpected_parameter_strict(self) -> None:
-    @validate(Parameter(name='y'))
-    def bar(x):
-        return x
-
-    with self.assertRaises(expected_exception=ValidateException):
-        bar(42)
-    with self.assertRaises(expected_exception=ValidateException):
-        bar(x=42)
-
-
-
-
-def test_validate_args(self) -
-
-
- -Expand source code - -
def test_validate_args(self):
-    @validate(
-        Parameter(name='a', validators=[Min(42, include_boundary=False)]),
-        Parameter(name='b', validators=[Min(42, include_boundary=False)]),
-        Parameter(name='c', validators=[Min(42, include_boundary=False)]),
-    )
-    def some_calculation(a, b, c):
-        return a + b + c
-
-    some_calculation(43, 45, 50)
-    with self.assertRaises(expected_exception=ParameterException):
-        some_calculation(30, 40, 50)
-    with self.assertRaises(expected_exception=ParameterException):
-        some_calculation(c=30, a=40, b=50)
-
-
-
-
-def test_validate_instance_method(self) -
-
-
- -Expand source code - -
def test_validate_instance_method(self):
-    class MyClass:
-        @validate(
-            Parameter(name='x', validators=[Min(1)]),
-        )
-        def some_calculation(self, x: int) -> int:
-            return x
-
-        @validate(
-            Parameter(name='x', validators=[Min(1)]),
-            return_as=ReturnAs.KWARGS_WITHOUT_NONE,
-        )
-        def some_calculation_2(self, x: int) -> int:
-            return x
-
-    m = MyClass()
-    m.some_calculation(1)
-    m.some_calculation(42)
-
-    with self.assertRaises(expected_exception=ParameterException):
-        m.some_calculation(0)
-    with self.assertRaises(expected_exception=ParameterException):
-        m.some_calculation(-42)
-
-    m.some_calculation_2(1)
-    m.some_calculation_2(42)
-
-    with self.assertRaises(expected_exception=ParameterException):
-        m.some_calculation_2(0)
-    with self.assertRaises(expected_exception=ParameterException):
-        m.some_calculation_2(-42)
-
-
-
-
-def test_validate_static_method(self) -
-
-
- -Expand source code - -
def test_validate_static_method(self):
-    """ The @staticmethod decorator have to be ABOVE the @validate decorator. """
-
-    class MyClass:
-        @staticmethod
-        @validate(
-            Parameter(name='x', validators=[Min(1)]),
-        )
-        def some_calculation(x: int) -> int:
-            return x
-
-    m = MyClass()
-    m.some_calculation(1)
-    m.some_calculation(42)
-
-    with self.assertRaises(expected_exception=ParameterException):
-        m.some_calculation(0)
-    with self.assertRaises(expected_exception=ParameterException):
-        m.some_calculation(-42)
-
-

The @staticmethod decorator have to be ABOVE the @validate decorator.

-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_validator_composite.html b/docs/pedantic/tests/validate/test_validator_composite.html deleted file mode 100644 index ac4f3c8e..00000000 --- a/docs/pedantic/tests/validate/test_validator_composite.html +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - -pedantic.tests.validate.test_validator_composite API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_validator_composite

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestValidatorComposite -(methodName='runTest') -
-
-
- -Expand source code - -
class TestValidatorComposite(TestCase):
-    def test_validator_composite(self) -> None:
-        @validate(Parameter(name='x', validators=[Composite([Min(3), Max(5)])]))
-        def foo(x):
-            return x
-
-        self.assertEqual(3, foo(3))
-        self.assertEqual(4, foo(4))
-        self.assertEqual(5, foo(5))
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(5.0001)
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(2.9999)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_validator_composite(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_composite(self) -> None:
-    @validate(Parameter(name='x', validators=[Composite([Min(3), Max(5)])]))
-    def foo(x):
-        return x
-
-    self.assertEqual(3, foo(3))
-    self.assertEqual(4, foo(4))
-    self.assertEqual(5, foo(5))
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo(5.0001)
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo(2.9999)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_validator_datetime_unix_timestamp.html b/docs/pedantic/tests/validate/test_validator_datetime_unix_timestamp.html deleted file mode 100644 index b666eb9c..00000000 --- a/docs/pedantic/tests/validate/test_validator_datetime_unix_timestamp.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - -pedantic.tests.validate.test_validator_datetime_unix_timestamp API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_validator_datetime_unix_timestamp

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestValidatorDatetimeUnixTimestamp -(methodName='runTest') -
-
-
- -Expand source code - -
class TestValidatorDatetimeUnixTimestamp(TestCase):
-    def test_validator_datetime_unix_timestamp(self) -> None:
-        @validate(Parameter(name='x', validators=[DateTimeUnixTimestamp()]))
-        def foo(x):
-            return x
-
-        now = datetime.now()
-        unix_timestamp = (now - datetime(year=1970, month=1, day=1)).total_seconds()
-        self.assertEqual(now, foo(unix_timestamp))
-        self.assertEqual(now, foo(str(unix_timestamp)))
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo('12.12.2020')
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo('invalid')
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo({'a': 1})
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(unix_timestamp * 1000)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_validator_datetime_unix_timestamp(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_datetime_unix_timestamp(self) -> None:
-    @validate(Parameter(name='x', validators=[DateTimeUnixTimestamp()]))
-    def foo(x):
-        return x
-
-    now = datetime.now()
-    unix_timestamp = (now - datetime(year=1970, month=1, day=1)).total_seconds()
-    self.assertEqual(now, foo(unix_timestamp))
-    self.assertEqual(now, foo(str(unix_timestamp)))
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo('12.12.2020')
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo('invalid')
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo({'a': 1})
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo(unix_timestamp * 1000)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_validator_email.html b/docs/pedantic/tests/validate/test_validator_email.html deleted file mode 100644 index bd1cd69a..00000000 --- a/docs/pedantic/tests/validate/test_validator_email.html +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - -pedantic.tests.validate.test_validator_email API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_validator_email

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestValidatorEmail -(methodName='runTest') -
-
-
- -Expand source code - -
class TestValidatorEmail(TestCase):
-    def test_validator_email(self) -> None:
-        @validate(Parameter(name='x', validators=[Email()]))
-        def foo(x):
-            return x
-
-        for value in ['fred@web.de', 'genial@gmail.com', 'test@test.co.uk']:
-            self.assertEqual(value, foo(value))
-
-        for value in ['fred', 'fred@web', 'fred@w@eb.de', 'fred@@web.de', 'invalid@invalid']:
-            with self.assertRaises(expected_exception=ParameterException):
-                foo(value)
-
-    def test_validator_email_converts_to_lower_case(self) -> None:
-        @validate(Parameter(name='x', validators=[Email(post_processor=lambda x: x.lower())]))
-        def foo(x):
-            return x
-
-        for value in ['Fred@Web.de', 'GENIAL@GMAIL.com', 'test@test.CO.UK']:
-            self.assertEqual(value.lower(), foo(value))
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_validator_email(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_email(self) -> None:
-    @validate(Parameter(name='x', validators=[Email()]))
-    def foo(x):
-        return x
-
-    for value in ['fred@web.de', 'genial@gmail.com', 'test@test.co.uk']:
-        self.assertEqual(value, foo(value))
-
-    for value in ['fred', 'fred@web', 'fred@w@eb.de', 'fred@@web.de', 'invalid@invalid']:
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(value)
-
-
-
-
-def test_validator_email_converts_to_lower_case(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_email_converts_to_lower_case(self) -> None:
-    @validate(Parameter(name='x', validators=[Email(post_processor=lambda x: x.lower())]))
-    def foo(x):
-        return x
-
-    for value in ['Fred@Web.de', 'GENIAL@GMAIL.com', 'test@test.CO.UK']:
-        self.assertEqual(value.lower(), foo(value))
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_validator_for_each.html b/docs/pedantic/tests/validate/test_validator_for_each.html deleted file mode 100644 index 8b4f3e2f..00000000 --- a/docs/pedantic/tests/validate/test_validator_for_each.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - -pedantic.tests.validate.test_validator_for_each API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_validator_for_each

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestValidatorForEach -(methodName='runTest') -
-
-
- -Expand source code - -
class TestValidatorForEach(TestCase):
-    def test_validator_for_each_single_child(self) -> None:
-        @validate(Parameter(name='x', validators=[ForEach(Min(3))]))
-        def foo(x):
-            return x
-
-        self.assertEqual([3, 4, 5], foo([3, 4, 5]))
-
-        for value in [42, [3, 2, 5]]:
-            with self.assertRaises(expected_exception=ParameterException):
-                foo(value)
-
-    def test_validator_for_each_multiple_children(self) -> None:
-        @validate(Parameter(name='x', validators=[ForEach([Min(3), Max(4)])]))
-        def foo(x):
-            return x
-
-        self.assertEqual([3, 4], foo([3, 4]))
-
-        for value in [42, [3, 2, 5]]:
-            with self.assertRaises(expected_exception=ParameterException):
-                foo(value)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_validator_for_each_multiple_children(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_for_each_multiple_children(self) -> None:
-    @validate(Parameter(name='x', validators=[ForEach([Min(3), Max(4)])]))
-    def foo(x):
-        return x
-
-    self.assertEqual([3, 4], foo([3, 4]))
-
-    for value in [42, [3, 2, 5]]:
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(value)
-
-
-
-
-def test_validator_for_each_single_child(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_for_each_single_child(self) -> None:
-    @validate(Parameter(name='x', validators=[ForEach(Min(3))]))
-    def foo(x):
-        return x
-
-    self.assertEqual([3, 4, 5], foo([3, 4, 5]))
-
-    for value in [42, [3, 2, 5]]:
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(value)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_validator_is_enum.html b/docs/pedantic/tests/validate/test_validator_is_enum.html deleted file mode 100644 index e6ad9f74..00000000 --- a/docs/pedantic/tests/validate/test_validator_is_enum.html +++ /dev/null @@ -1,415 +0,0 @@ - - - - - - -pedantic.tests.validate.test_validator_is_enum API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_validator_is_enum

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class MyEnum -(*args, **kwds) -
-
-
- -Expand source code - -
class MyEnum(Enum):
-    RED = 'RED'
-    BLUE = 'BLUE'
-
-

Create a collection of name/value pairs.

-

Example enumeration:

-
>>> class Color(Enum):
-...     RED = 1
-...     BLUE = 2
-...     GREEN = 3
-
-

Access them by:

-
    -
  • attribute access:
  • -
-
-
-
-

Color.RED -

-
-
-
-
    -
  • value lookup:
  • -
-
-
-
-

Color(1) -

-
-
-
-
    -
  • name lookup:
  • -
-
-
-
-

Color['RED'] -

-
-
-
-

Enumerations can be iterated over, and know how many members they have:

-
>>> len(Color)
-3
-
-
>>> list(Color)
-[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]
-
-

Methods can be added to enumerations, and members can have their own -attributes – see the documentation for details.

-

Ancestors

-
    -
  • enum.Enum
  • -
-

Class variables

-
-
var BLUE
-
-

The type of the None singleton.

-
-
var RED
-
-

The type of the None singleton.

-
-
-
-
-class MyIntEnum -(*args, **kwds) -
-
-
- -Expand source code - -
class MyIntEnum(IntEnum):
-    RED = 1
-    BLUE = 2
-
-

Enum where members are also (and must be) ints

-

Ancestors

-
    -
  • enum.IntEnum
  • -
  • builtins.int
  • -
  • enum.ReprEnum
  • -
  • enum.Enum
  • -
-

Class variables

-
-
var BLUE
-
-

The type of the None singleton.

-
-
var RED
-
-

The type of the None singleton.

-
-
-
-
-class TestValidatorIsEnum -(methodName='runTest') -
-
-
- -Expand source code - -
class TestValidatorIsEnum(TestCase):
-    def test_validator_is_enum_convert_true(self) -> None:
-        @validate(Parameter(name='x', validators=[IsEnum(MyEnum, convert=True)]))
-        def foo(x):
-            return x
-
-        self.assertEqual(MyEnum.RED, foo('RED'))
-        self.assertEqual(MyEnum.BLUE, foo('BLUE'))
-
-        for value in ['fred', 1, 'GREEN']:
-            with self.assertRaises(expected_exception=ParameterException):
-                foo(value)
-
-    def test_validator_is_enum_int_enum_convert_true(self) -> None:
-        @validate(Parameter(name='x', validators=[IsEnum(MyIntEnum, convert=True)]))
-        def foo(x):
-            return x
-
-        self.assertEqual(MyIntEnum.RED, foo('1'))
-        self.assertEqual(MyIntEnum.BLUE, foo('2'))
-        self.assertEqual(MyIntEnum.RED, foo(1))
-        self.assertEqual(MyIntEnum.BLUE, foo(2))
-
-        for value in ['fred', 3, 'GREEN']:
-            with self.assertRaises(expected_exception=ParameterException):
-                foo(value)
-
-    def test_validator_is_enum_convert_false(self) -> None:
-        @validate(Parameter(name='x', validators=[IsEnum(MyEnum, convert=False)]))
-        def foo(x):
-            return x
-
-        self.assertEqual('RED', foo('RED'))
-        self.assertEqual('BLUE', foo('BLUE'))
-
-        for value in ['fred', 1, 'GREEN']:
-            with self.assertRaises(expected_exception=ParameterException):
-                foo(value)
-
-    def test_validator_is_enum_to_upper_case(self) -> None:
-        @validate(Parameter(name='x', validators=[IsEnum(MyEnum, convert=False)]))
-        def foo(x):
-            return x
-
-        self.assertEqual('RED', foo('red'))
-        self.assertEqual('BLUE', foo('blue'))
-        self.assertEqual('BLUE', foo('bLUe'))
-
-    def test_validator_is_enum_to_upper_case_disabled(self) -> None:
-        @validate(Parameter(name='x', validators=[IsEnum(MyEnum, convert=False, to_upper_case=False)]))
-        def foo(x): print(x)
-
-        for value in ['red', 'blue', 'Red', 'bLUe']:
-            with self.assertRaises(expected_exception=ParameterException):
-                foo(value)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_validator_is_enum_convert_false(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_is_enum_convert_false(self) -> None:
-    @validate(Parameter(name='x', validators=[IsEnum(MyEnum, convert=False)]))
-    def foo(x):
-        return x
-
-    self.assertEqual('RED', foo('RED'))
-    self.assertEqual('BLUE', foo('BLUE'))
-
-    for value in ['fred', 1, 'GREEN']:
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(value)
-
-
-
-
-def test_validator_is_enum_convert_true(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_is_enum_convert_true(self) -> None:
-    @validate(Parameter(name='x', validators=[IsEnum(MyEnum, convert=True)]))
-    def foo(x):
-        return x
-
-    self.assertEqual(MyEnum.RED, foo('RED'))
-    self.assertEqual(MyEnum.BLUE, foo('BLUE'))
-
-    for value in ['fred', 1, 'GREEN']:
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(value)
-
-
-
-
-def test_validator_is_enum_int_enum_convert_true(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_is_enum_int_enum_convert_true(self) -> None:
-    @validate(Parameter(name='x', validators=[IsEnum(MyIntEnum, convert=True)]))
-    def foo(x):
-        return x
-
-    self.assertEqual(MyIntEnum.RED, foo('1'))
-    self.assertEqual(MyIntEnum.BLUE, foo('2'))
-    self.assertEqual(MyIntEnum.RED, foo(1))
-    self.assertEqual(MyIntEnum.BLUE, foo(2))
-
-    for value in ['fred', 3, 'GREEN']:
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(value)
-
-
-
-
-def test_validator_is_enum_to_upper_case(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_is_enum_to_upper_case(self) -> None:
-    @validate(Parameter(name='x', validators=[IsEnum(MyEnum, convert=False)]))
-    def foo(x):
-        return x
-
-    self.assertEqual('RED', foo('red'))
-    self.assertEqual('BLUE', foo('blue'))
-    self.assertEqual('BLUE', foo('bLUe'))
-
-
-
-
-def test_validator_is_enum_to_upper_case_disabled(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_is_enum_to_upper_case_disabled(self) -> None:
-    @validate(Parameter(name='x', validators=[IsEnum(MyEnum, convert=False, to_upper_case=False)]))
-    def foo(x): print(x)
-
-    for value in ['red', 'blue', 'Red', 'bLUe']:
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(value)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_validator_is_uuid.html b/docs/pedantic/tests/validate/test_validator_is_uuid.html deleted file mode 100644 index 8db3daa4..00000000 --- a/docs/pedantic/tests/validate/test_validator_is_uuid.html +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - -pedantic.tests.validate.test_validator_is_uuid API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_validator_is_uuid

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestValidatorIsUUID -(methodName='runTest') -
-
-
- -Expand source code - -
class TestValidatorIsUUID(TestCase):
-    def test_validator_is_uuid(self):
-        @validate(Parameter(name='x', validators=[IsUuid()], required=False))
-        def foo(x):
-            return x
-
-        for id_ in [str(uuid1()), str(uuid3(uuid1(), 'b')), str(uuid4()), str(uuid5(uuid1(), 'b'))]:
-            self.assertEqual(id_, foo(id_))
-
-        for no_id in ['invalid', 12]:
-            with self.assertRaises(expected_exception=ParameterException):
-                foo(no_id)
-
-    def test_validator_is_uuid_with_for_each_and_none_value(self):
-        @validate(Parameter(name='x', validators=[ForEach(IsUuid())]))
-        def foo(x):
-            return x
-
-        uuid = str(uuid1())
-        self.assertEqual([], foo([]))
-        self.assertEqual([uuid], foo([uuid]))
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo([None])
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_validator_is_uuid(self) -
-
-
- -Expand source code - -
def test_validator_is_uuid(self):
-    @validate(Parameter(name='x', validators=[IsUuid()], required=False))
-    def foo(x):
-        return x
-
-    for id_ in [str(uuid1()), str(uuid3(uuid1(), 'b')), str(uuid4()), str(uuid5(uuid1(), 'b'))]:
-        self.assertEqual(id_, foo(id_))
-
-    for no_id in ['invalid', 12]:
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(no_id)
-
-
-
-
-def test_validator_is_uuid_with_for_each_and_none_value(self) -
-
-
- -Expand source code - -
def test_validator_is_uuid_with_for_each_and_none_value(self):
-    @validate(Parameter(name='x', validators=[ForEach(IsUuid())]))
-    def foo(x):
-        return x
-
-    uuid = str(uuid1())
-    self.assertEqual([], foo([]))
-    self.assertEqual([uuid], foo([uuid]))
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo([None])
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_validator_match_pattern.html b/docs/pedantic/tests/validate/test_validator_match_pattern.html deleted file mode 100644 index 79f7174d..00000000 --- a/docs/pedantic/tests/validate/test_validator_match_pattern.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - -pedantic.tests.validate.test_validator_match_pattern API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_validator_match_pattern

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestValidatorMatchPattern -(methodName='runTest') -
-
-
- -Expand source code - -
class TestValidatorMatchPattern(TestCase):
-    def test_validator_match_pattern(self) -> None:
-        pattern = r'^(([01]\d|2[0-3]):([0-5]\d)|24:00)$'
-
-        @validate(Parameter(name='x', validators=[MatchPattern(pattern)]))
-        def foo(x):
-            return x
-
-        for value in ['00:00', '02:45', '14:59', '23:59']:
-            self.assertEqual(value, foo(value))
-
-        for value in ['00:70', '24:00', '30:00', 'invalid']:
-            with self.assertRaises(expected_exception=ParameterException):
-                foo([3, 2, 5])
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_validator_match_pattern(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_match_pattern(self) -> None:
-    pattern = r'^(([01]\d|2[0-3]):([0-5]\d)|24:00)$'
-
-    @validate(Parameter(name='x', validators=[MatchPattern(pattern)]))
-    def foo(x):
-        return x
-
-    for value in ['00:00', '02:45', '14:59', '23:59']:
-        self.assertEqual(value, foo(value))
-
-    for value in ['00:70', '24:00', '30:00', 'invalid']:
-        with self.assertRaises(expected_exception=ParameterException):
-            foo([3, 2, 5])
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_validator_max.html b/docs/pedantic/tests/validate/test_validator_max.html deleted file mode 100644 index 68e034b0..00000000 --- a/docs/pedantic/tests/validate/test_validator_max.html +++ /dev/null @@ -1,202 +0,0 @@ - - - - - - -pedantic.tests.validate.test_validator_max API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_validator_max

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestValidatorMax -(methodName='runTest') -
-
-
- -Expand source code - -
class TestValidatorMax(TestCase):
-    def test_validator_max_length_include_boundary_true(self) -> None:
-        @validate(Parameter(name='x', validators=[Max(3, include_boundary=True)]))
-        def foo(x):
-            return x
-
-        self.assertEqual(3, foo(3))
-        self.assertEqual(2, foo(2))
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(4)
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(3.001)
-
-    def test_validator_max_length_include_boundary_false(self) -> None:
-        @validate(Parameter(name='x', validators=[Max(3, include_boundary=False)]))
-        def foo(x):
-            return x
-
-        self.assertEqual(2.9999, foo(2.9999))
-        self.assertEqual(2, foo(2))
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(4)
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(3)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_validator_max_length_include_boundary_false(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_max_length_include_boundary_false(self) -> None:
-    @validate(Parameter(name='x', validators=[Max(3, include_boundary=False)]))
-    def foo(x):
-        return x
-
-    self.assertEqual(2.9999, foo(2.9999))
-    self.assertEqual(2, foo(2))
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo(4)
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo(3)
-
-
-
-
-def test_validator_max_length_include_boundary_true(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_max_length_include_boundary_true(self) -> None:
-    @validate(Parameter(name='x', validators=[Max(3, include_boundary=True)]))
-    def foo(x):
-        return x
-
-    self.assertEqual(3, foo(3))
-    self.assertEqual(2, foo(2))
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo(4)
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo(3.001)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_validator_max_length.html b/docs/pedantic/tests/validate/test_validator_max_length.html deleted file mode 100644 index 2ef27bdb..00000000 --- a/docs/pedantic/tests/validate/test_validator_max_length.html +++ /dev/null @@ -1,183 +0,0 @@ - - - - - - -pedantic.tests.validate.test_validator_max_length API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_validator_max_length

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestValidatorMaxLength -(methodName='runTest') -
-
-
- -Expand source code - -
class TestValidatorMaxLength(TestCase):
-    def test_validator_max_length(self) -> None:
-        @validate(Parameter(name='x', validators=[MaxLength(3)]))
-        def foo(x):
-            return x
-
-        self.assertEqual('hi', foo('hi'))
-        self.assertEqual('hi!', foo('hi!'))
-        self.assertEqual([1, 2, 3], foo([1, 2, 3]))
-
-        with self.assertRaises(expected_exception=ParameterException) as ex:
-            foo('hi!!')
-
-        assert ex.exception.message == 'hi!! is too long with length 4.'
-
-        with self.assertRaises(expected_exception=ParameterException) as ex:
-            foo([1, 2, 3, 4])
-
-        assert ex.exception.message == '[1, 2, 3, 4] is too long with length 4.'
-
-        with self.assertRaises(expected_exception=ParameterException) as ex:
-            foo(42)
-
-        assert ex.exception.message == '42 has no length.'
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_validator_max_length(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_max_length(self) -> None:
-    @validate(Parameter(name='x', validators=[MaxLength(3)]))
-    def foo(x):
-        return x
-
-    self.assertEqual('hi', foo('hi'))
-    self.assertEqual('hi!', foo('hi!'))
-    self.assertEqual([1, 2, 3], foo([1, 2, 3]))
-
-    with self.assertRaises(expected_exception=ParameterException) as ex:
-        foo('hi!!')
-
-    assert ex.exception.message == 'hi!! is too long with length 4.'
-
-    with self.assertRaises(expected_exception=ParameterException) as ex:
-        foo([1, 2, 3, 4])
-
-    assert ex.exception.message == '[1, 2, 3, 4] is too long with length 4.'
-
-    with self.assertRaises(expected_exception=ParameterException) as ex:
-        foo(42)
-
-    assert ex.exception.message == '42 has no length.'
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_validator_min.html b/docs/pedantic/tests/validate/test_validator_min.html deleted file mode 100644 index 5fb2f9b2..00000000 --- a/docs/pedantic/tests/validate/test_validator_min.html +++ /dev/null @@ -1,202 +0,0 @@ - - - - - - -pedantic.tests.validate.test_validator_min API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_validator_min

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestValidatorMin -(methodName='runTest') -
-
-
- -Expand source code - -
class TestValidatorMin(TestCase):
-    def test_validator_min_length_include_boundary_true(self) -> None:
-        @validate(Parameter(name='x', validators=[Min(3, include_boundary=True)]))
-        def foo(x):
-            return x
-
-        self.assertEqual(3, foo(3))
-        self.assertEqual(4, foo(4))
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(2)
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(2.9999)
-
-    def test_validator_min_length_include_boundary_false(self) -> None:
-        @validate(Parameter(name='x', validators=[Min(3, include_boundary=False)]))
-        def foo(x):
-            return x
-
-        self.assertEqual(3.0001, foo(3.0001))
-        self.assertEqual(4, foo(4))
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(2)
-
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(3)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_validator_min_length_include_boundary_false(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_min_length_include_boundary_false(self) -> None:
-    @validate(Parameter(name='x', validators=[Min(3, include_boundary=False)]))
-    def foo(x):
-        return x
-
-    self.assertEqual(3.0001, foo(3.0001))
-    self.assertEqual(4, foo(4))
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo(2)
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo(3)
-
-
-
-
-def test_validator_min_length_include_boundary_true(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_min_length_include_boundary_true(self) -> None:
-    @validate(Parameter(name='x', validators=[Min(3, include_boundary=True)]))
-    def foo(x):
-        return x
-
-    self.assertEqual(3, foo(3))
-    self.assertEqual(4, foo(4))
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo(2)
-
-    with self.assertRaises(expected_exception=ParameterException):
-        foo(2.9999)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_validator_min_length.html b/docs/pedantic/tests/validate/test_validator_min_length.html deleted file mode 100644 index 44e3eb34..00000000 --- a/docs/pedantic/tests/validate/test_validator_min_length.html +++ /dev/null @@ -1,183 +0,0 @@ - - - - - - -pedantic.tests.validate.test_validator_min_length API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_validator_min_length

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestValidatorMinLength -(methodName='runTest') -
-
-
- -Expand source code - -
class TestValidatorMinLength(TestCase):
-    def test_validator_min_length(self) -> None:
-        @validate(Parameter(name='x', validators=[MinLength(3)]))
-        def foo(x):
-            return x
-
-        self.assertEqual('hi!', foo('hi!'))
-        self.assertEqual('hello', foo('hello'))
-        self.assertEqual([1, 2, 3], foo([1, 2, 3]))
-
-        with self.assertRaises(expected_exception=ParameterException) as ex:
-            foo('hi')
-
-        assert ex.exception.message == 'hi is too short with length 2.'
-
-        with self.assertRaises(expected_exception=ParameterException) as ex:
-            foo([1, 2])
-
-        assert ex.exception.message == '[1, 2] is too short with length 2.'
-
-        with self.assertRaises(expected_exception=ParameterException) as ex:
-            foo(42)
-
-        assert ex.exception.message == '42 has no length.'
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_validator_min_length(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_min_length(self) -> None:
-    @validate(Parameter(name='x', validators=[MinLength(3)]))
-    def foo(x):
-        return x
-
-    self.assertEqual('hi!', foo('hi!'))
-    self.assertEqual('hello', foo('hello'))
-    self.assertEqual([1, 2, 3], foo([1, 2, 3]))
-
-    with self.assertRaises(expected_exception=ParameterException) as ex:
-        foo('hi')
-
-    assert ex.exception.message == 'hi is too short with length 2.'
-
-    with self.assertRaises(expected_exception=ParameterException) as ex:
-        foo([1, 2])
-
-    assert ex.exception.message == '[1, 2] is too short with length 2.'
-
-    with self.assertRaises(expected_exception=ParameterException) as ex:
-        foo(42)
-
-    assert ex.exception.message == '42 has no length.'
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/tests/validate/test_validator_not_empty.html b/docs/pedantic/tests/validate/test_validator_not_empty.html deleted file mode 100644 index 9b69012c..00000000 --- a/docs/pedantic/tests/validate/test_validator_not_empty.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - -pedantic.tests.validate.test_validator_not_empty API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.tests.validate.test_validator_not_empty

-
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class TestValidatorNotEmpty -(methodName='runTest') -
-
-
- -Expand source code - -
class TestValidatorNotEmpty(TestCase):
-    def test_validator_not_empty(self) -> None:
-        @validate(Parameter(name='x', validators=[NotEmpty()]))
-        def foo(x):
-            return x
-
-        self.assertEqual('hi', foo('hi'))
-        self.assertEqual('hi', foo('   hi     '))
-        self.assertEqual([1], foo([1]))
-
-        for value in ['', '   ', [], {}, set()]:
-            with self.assertRaises(expected_exception=ParameterException):
-                foo(value)
-
-

A class whose instances are single test cases.

-

By default, the test code itself should be placed in a method named -'runTest'.

-

If the fixture may be used for many test cases, create as -many test methods as are needed. When instantiating such a TestCase -subclass, specify in the constructor arguments the name of the test method -that the instance is to execute.

-

Test authors should subclass TestCase for their own tests. Construction -and deconstruction of the test's environment ('fixture') can be -implemented by overriding the 'setUp' and 'tearDown' methods respectively.

-

If it is necessary to override the init method, the base class -init method must always be called. It is important that subclasses -should not change the signature of their init method, since instances -of the classes are instantiated automatically by parts of the framework -in order to be run.

-

When subclassing TestCase, you can set these attributes: -* failureException: determines which exception will be raised when -the instance's assertion methods fail; test methods raising this -exception will be deemed to have 'failed' rather than 'errored'. -* longMessage: determines whether long messages (including repr of -objects used in assert methods) will be printed on failure in addition -to any explicit message passed. -* maxDiff: sets the maximum length of a diff in failure messages -by assert methods using difflib. It is looked up as an instance -attribute so can be configured by individual tests if required.

-

Create an instance of the class that will use the named test -method when executed. Raises a ValueError if the instance does -not have a method with the specified name.

-

Ancestors

-
    -
  • unittest.case.TestCase
  • -
-

Methods

-
-
-def test_validator_not_empty(self) ‑> None -
-
-
- -Expand source code - -
def test_validator_not_empty(self) -> None:
-    @validate(Parameter(name='x', validators=[NotEmpty()]))
-    def foo(x):
-        return x
-
-    self.assertEqual('hi', foo('hi'))
-    self.assertEqual('hi', foo('   hi     '))
-    self.assertEqual([1], foo([1]))
-
-    for value in ['', '   ', [], {}, set()]:
-        with self.assertRaises(expected_exception=ParameterException):
-            foo(value)
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/type_checking_logic/check_docstring.html b/docs/pedantic/type_checking_logic/check_docstring.html deleted file mode 100644 index 4a361ba5..00000000 --- a/docs/pedantic/type_checking_logic/check_docstring.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - -pedantic.type_checking_logic.check_docstring API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.type_checking_logic.check_docstring

-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/type_checking_logic/check_generic_classes.html b/docs/pedantic/type_checking_logic/check_generic_classes.html deleted file mode 100644 index 9ed82db8..00000000 --- a/docs/pedantic/type_checking_logic/check_generic_classes.html +++ /dev/null @@ -1,201 +0,0 @@ - - - - - - -pedantic.type_checking_logic.check_generic_classes API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.type_checking_logic.check_generic_classes

-
-
-
-
-
-
-
-
-

Functions

-
-
-def check_instance_of_generic_class_and_get_type_vars(instance: Any) ‑> Dict[TypeVar, Any] -
-
-
- -Expand source code - -
def check_instance_of_generic_class_and_get_type_vars(instance: Any) -> Dict[TypeVar, Any]:
-    """
-        >>> from typing import TypeVar, Generic, List
-        >>> T = TypeVar('T')
-        >>> class A(Generic[T]): pass
-        >>> a = A() # would normally raise an error due to _assert_constructor_called_with_generics, but not in doctest
-        >>> check_instance_of_generic_class_and_get_type_vars(a)
-        {}
-        >>> b = A[int]()
-        >>> check_instance_of_generic_class_and_get_type_vars(b)
-        {~T: <class 'int'>}
-        >>> c = A[List[int]]()
-        >>> check_instance_of_generic_class_and_get_type_vars(c)
-        {~T: typing.List[int]}
-        >>> S = TypeVar('S')
-        >>> class B(Generic[T, S]): pass
-        >>> d = B()
-        >>> check_instance_of_generic_class_and_get_type_vars(d)
-        {}
-        >>> e = B[int]()
-        Traceback (most recent call last):
-        ...
-        TypeError: Too few ...; actual 1, expect... 2
-        >>> f = B[int, float]()
-        >>> check_instance_of_generic_class_and_get_type_vars(f)
-        {~T: <class 'int'>, ~S: <class 'float'>}
-        >>> class C(B): pass
-        >>> g = C()
-        >>> check_instance_of_generic_class_and_get_type_vars(g)
-        {}
-    """
-    type_vars = dict()
-    _assert_constructor_called_with_generics(instance=instance)
-
-    # The information I need is set after the object construction in the __orig_class__ attribute.
-    # This method is called before construction, and therefore it returns if the value isn't set
-    # https://stackoverflow.com/questions/60985221/how-can-i-access-t-from-a-generict-instance-early-in-its-lifecycle
-    if not hasattr(instance, '__orig_class__'):
-        return type_vars
-
-    type_variables = get_type_arguments(type(instance).__orig_bases__[0])
-    actual_types = get_type_arguments(instance.__orig_class__)
-
-    for i, type_var in enumerate(type_variables):
-        type_vars[type_var] = actual_types[i]
-    return type_vars
-
-
>>> from typing import TypeVar, Generic, List
->>> T = TypeVar('T')
->>> class A(Generic[T]): pass
->>> a = A() # would normally raise an error due to _assert_constructor_called_with_generics, but not in doctest
->>> check_instance_of_generic_class_and_get_type_vars(a)
-{}
->>> b = A[int]()
->>> check_instance_of_generic_class_and_get_type_vars(b)
-{~T: <class 'int'>}
->>> c = A[List[int]]()
->>> check_instance_of_generic_class_and_get_type_vars(c)
-{~T: typing.List[int]}
->>> S = TypeVar('S')
->>> class B(Generic[T, S]): pass
->>> d = B()
->>> check_instance_of_generic_class_and_get_type_vars(d)
-{}
->>> e = B[int]()
-Traceback (most recent call last):
-...
-TypeError: Too few ...; actual 1, expect... 2
->>> f = B[int, float]()
->>> check_instance_of_generic_class_and_get_type_vars(f)
-{~T: <class 'int'>, ~S: <class 'float'>}
->>> class C(B): pass
->>> g = C()
->>> check_instance_of_generic_class_and_get_type_vars(g)
-{}
-
-
-
-def is_instance_of_generic_class(instance: Any) ‑> bool -
-
-
- -Expand source code - -
def is_instance_of_generic_class(instance: Any) -> bool:
-    """
-        >>> class A: pass
-        >>> a = A()
-        >>> is_instance_of_generic_class(a)
-        False
-        >>> from typing import TypeVar, Generic
-        >>> T = TypeVar('T')
-        >>> class B(Generic[T]): pass
-        >>> b = B()
-        >>> is_instance_of_generic_class(b)
-        True
-        >>> b2 = B[int]()
-        >>> is_instance_of_generic_class(b2)
-        True
-    """
-    return Generic in instance.__class__.__bases__
-
-
>>> class A: pass
->>> a = A()
->>> is_instance_of_generic_class(a)
-False
->>> from typing import TypeVar, Generic
->>> T = TypeVar('T')
->>> class B(Generic[T]): pass
->>> b = B()
->>> is_instance_of_generic_class(b)
-True
->>> b2 = B[int]()
->>> is_instance_of_generic_class(b2)
-True
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/type_checking_logic/check_types.html b/docs/pedantic/type_checking_logic/check_types.html deleted file mode 100644 index acf3406b..00000000 --- a/docs/pedantic/type_checking_logic/check_types.html +++ /dev/null @@ -1,410 +0,0 @@ - - - - - - -pedantic.type_checking_logic.check_types API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.type_checking_logic.check_types

-
-
-

Idea is taken from: https://stackoverflow.com/a/55504010/10975692

-
-
-
-
-
-
-

Functions

-
-
-def assert_value_matches_type(value: Any,
type_: Any,
err: str,
type_vars: Dict[TypeVar, Any],
key: str | None = None,
msg: str | None = None,
context: Dict[str, Any] = None) ‑> None
-
-
-
- -Expand source code - -
def assert_value_matches_type(
-        value: Any,
-        type_: Any,
-        err: str,
-        type_vars: Dict[TypeVar_, Any],
-        key: Optional[str] = None,
-        msg: Optional[str] = None,
-        context: Dict[str, Any] = None,
-) -> None:
-    if not _check_type(value=value, type_=type_, err=err, type_vars=type_vars, context=context):
-        t = type(value)
-        value = f'{key}={value}' if key is not None else str(value)
-
-        if not msg:
-            msg = f'{err}Type hint is incorrect: Argument {value} of type {t} does not match expected type {type_}.'
-
-        raise PedanticTypeCheckException(msg)
-
-
-
-
-def convert_to_typing_types(x: Type) ‑> Type -
-
-
- -Expand source code - -
def convert_to_typing_types(x: typing.Type) -> typing.Type:
-    """
-        Example:
-        >>> convert_to_typing_types(int)
-        <class 'int'>
-        >>> convert_to_typing_types(list)
-        Traceback (most recent call last):
-        ...
-        ValueError: Missing type arguments
-        >>> convert_to_typing_types(list[int])
-        typing.List[int]
-        >>> convert_to_typing_types(set[int])
-        typing.Set[int]
-        >>> convert_to_typing_types(frozenset[int])
-        typing.FrozenSet[int]
-        >>> convert_to_typing_types(tuple[int])
-        typing.Tuple[int]
-        >>> convert_to_typing_types(type[int])
-        typing.Type[int]
-        >>> convert_to_typing_types(type[int | float])
-        typing.Type[int | float]
-        >>> convert_to_typing_types(tuple[int, float])
-        typing.Tuple[int, float]
-        >>> convert_to_typing_types(dict[int, float])
-        typing.Dict[int, float]
-        >>> convert_to_typing_types(list[dict[int, float]])
-        typing.List[typing.Dict[int, float]]
-        >>> convert_to_typing_types(list[dict[int, tuple[float, str]]])
-        typing.List[typing.Dict[int, typing.Tuple[float, str]]]
-    """
-
-    if x in {list, set, dict, frozenset, tuple, type}:
-        raise ValueError('Missing type arguments')
-
-    if not hasattr(x, '__origin__'):
-        return x
-
-    origin = x.__origin__  # type: ignore # checked above
-    args = [convert_to_typing_types(a) for a in x.__args__]  # type: ignore
-
-    if origin is list:
-        return typing.List[tuple(args)]
-    elif origin is set:
-        return typing.Set[tuple(args)]
-    elif origin is dict:
-        return typing.Dict[tuple(args)]
-    elif origin is tuple:
-        return typing.Tuple[tuple(args)]
-    elif origin is frozenset:
-        return typing.FrozenSet[tuple(args)]
-    elif origin is type:
-        return typing.Type[tuple(args)]
-    elif origin is typing.Union:
-        return x  # new since Python 3.14
-
-    raise RuntimeError(x)
-
-

Example:

-
>>> convert_to_typing_types(int)
-<class 'int'>
->>> convert_to_typing_types(list)
-Traceback (most recent call last):
-...
-ValueError: Missing type arguments
->>> convert_to_typing_types(list[int])
-typing.List[int]
->>> convert_to_typing_types(set[int])
-typing.Set[int]
->>> convert_to_typing_types(frozenset[int])
-typing.FrozenSet[int]
->>> convert_to_typing_types(tuple[int])
-typing.Tuple[int]
->>> convert_to_typing_types(type[int])
-typing.Type[int]
->>> convert_to_typing_types(type[int | float])
-typing.Type[int | float]
->>> convert_to_typing_types(tuple[int, float])
-typing.Tuple[int, float]
->>> convert_to_typing_types(dict[int, float])
-typing.Dict[int, float]
->>> convert_to_typing_types(list[dict[int, float]])
-typing.List[typing.Dict[int, float]]
->>> convert_to_typing_types(list[dict[int, tuple[float, str]]])
-typing.List[typing.Dict[int, typing.Tuple[float, str]]]
-
-
-
-def get_base_generic(cls: Any) ‑> Any -
-
-
- -Expand source code - -
def get_base_generic(cls: Any) -> Any:
-    """
-        >>> from typing import List, Union, Tuple, Callable, Dict, Set, Awaitable, Coroutine
-        >>> get_base_generic(List)
-        typing.List
-        >>> get_base_generic(List[float])
-        typing.List
-        >>> get_base_generic(List[List[float]])
-        typing.List
-        >>> get_base_generic(List[Union[int, float]])
-        typing.List
-        >>> get_base_generic(Tuple)
-        typing.Tuple
-        >>> get_base_generic(Tuple[float, int])
-        typing.Tuple
-        >>> get_base_generic(Tuple[Union[int, float], str])
-        typing.Tuple
-        >>> get_base_generic(Callable[..., int])
-        typing.Callable
-        >>> get_base_generic(Callable[[Union[int, str], float], int])
-        typing.Callable
-        >>> get_base_generic(Dict)
-        typing.Dict
-        >>> get_base_generic(Dict[str, str])
-        typing.Dict
-        >>> 'typing.Union' in str(get_base_generic(Union))  # 3.13: typing.Union  3.14: <class 'typing.Union'>
-        True
-        >>> 'typing.Union' in str(get_base_generic(Union[float, int, str])) # 3.13: typing.Union  3.14: <class 'typing.Union'>
-        True
-        >>> get_base_generic(Set)
-        typing.Set
-        >>> get_base_generic(Set[int])
-        typing.Set
-        >>> get_base_generic(Awaitable[int])
-        typing.Awaitable
-        >>> get_base_generic(Coroutine[None, None, int])
-        typing.Coroutine
-    """
-
-    origin = cls.__origin__ if hasattr(cls, '__origin__') else None
-    name = cls._name if hasattr(cls, '_name') else None
-
-    if name is not None:
-        return getattr(typing, name)
-    elif origin is not None and cls is not typing.Union:
-        return origin
-    return cls
-
-
>>> from typing import List, Union, Tuple, Callable, Dict, Set, Awaitable, Coroutine
->>> get_base_generic(List)
-typing.List
->>> get_base_generic(List[float])
-typing.List
->>> get_base_generic(List[List[float]])
-typing.List
->>> get_base_generic(List[Union[int, float]])
-typing.List
->>> get_base_generic(Tuple)
-typing.Tuple
->>> get_base_generic(Tuple[float, int])
-typing.Tuple
->>> get_base_generic(Tuple[Union[int, float], str])
-typing.Tuple
->>> get_base_generic(Callable[..., int])
-typing.Callable
->>> get_base_generic(Callable[[Union[int, str], float], int])
-typing.Callable
->>> get_base_generic(Dict)
-typing.Dict
->>> get_base_generic(Dict[str, str])
-typing.Dict
->>> 'typing.Union' in str(get_base_generic(Union))  # 3.13: typing.Union  3.14: <class 'typing.Union'>
-True
->>> 'typing.Union' in str(get_base_generic(Union[float, int, str])) # 3.13: typing.Union  3.14: <class 'typing.Union'>
-True
->>> get_base_generic(Set)
-typing.Set
->>> get_base_generic(Set[int])
-typing.Set
->>> get_base_generic(Awaitable[int])
-typing.Awaitable
->>> get_base_generic(Coroutine[None, None, int])
-typing.Coroutine
-
-
-
-def get_type_arguments(cls: Any) ‑> Tuple[Any, ...] -
-
-
- -Expand source code - -
def get_type_arguments(cls: Any) -> Tuple[Any, ...]:
-    """ Works similar to typing.args()
-        >>> from typing import Tuple, List, Union, Callable, Any, NewType, TypeVar, Optional, Awaitable, Coroutine
-        >>> get_type_arguments(int)
-        ()
-        >>> get_type_arguments(List[float])
-        (<class 'float'>,)
-        >>> get_type_arguments(List[int])
-        (<class 'int'>,)
-        >>> UserId = NewType('UserId', int)
-        >>> get_type_arguments(List[UserId])
-        (pedantic.type_checking_logic.check_types.UserId,)
-        >>> get_type_arguments(List)
-        ()
-        >>> T = TypeVar('T')
-        >>> get_type_arguments(List[T])
-        (~T,)
-        >>> get_type_arguments(List[List[int]])
-        (typing.List[int],)
-        >>> get_type_arguments(List[List[List[int]]])
-        (typing.List[typing.List[int]],)
-        >>> get_type_arguments(List[Tuple[float, str]])
-        (typing.Tuple[float, str],)
-        >>> get_type_arguments(List[Tuple[Any, ...]])
-        (typing.Tuple[typing.Any, ...],)
-        >>> get_type_arguments(Union[str, float, int])
-        (<class 'str'>, <class 'float'>, <class 'int'>)
-        >>> get_type_arguments(Union[str, float, List[int], int])
-        (<class 'str'>, <class 'float'>, typing.List[int], <class 'int'>)
-        >>> get_type_arguments(Callable)
-        ()
-        >>> get_type_arguments(Callable[[int, float], Tuple[float, str]])
-        ([<class 'int'>, <class 'float'>], typing.Tuple[float, str])
-        >>> get_type_arguments(Callable[..., str])
-        (Ellipsis, <class 'str'>)
-        >>> get_type_arguments(Optional[int])
-        (<class 'int'>, <class 'NoneType'>)
-        >>> get_type_arguments(str | int)
-        (<class 'str'>, <class 'int'>)
-        >>> get_type_arguments(Awaitable[str])
-        (<class 'str'>,)
-        >>> get_type_arguments(Coroutine[int, bool, str])
-        (<class 'int'>, <class 'bool'>, <class 'str'>)
-    """
-
-    result = ()
-
-    if hasattr(cls, '__args__'):
-        result = cls.__args__
-        origin = get_base_generic(cls=cls)
-
-        if origin != cls and \
-                ((origin is Callable) or (origin is collections.abc.Callable)) and \
-                result[0] is not Ellipsis:
-            result = (list(result[:-1]), result[-1])
-
-    result = result or ()
-
-    if hasattr(types, 'UnionType') and isinstance(cls, types.UnionType):
-        return result
-    elif '[' in str(cls):
-        return result
-
-    return ()
-
-

Works similar to typing.args()

-
>>> from typing import Tuple, List, Union, Callable, Any, NewType, TypeVar, Optional, Awaitable, Coroutine
->>> get_type_arguments(int)
-()
->>> get_type_arguments(List[float])
-(<class 'float'>,)
->>> get_type_arguments(List[int])
-(<class 'int'>,)
->>> UserId = NewType('UserId', int)
->>> get_type_arguments(List[UserId])
-(pedantic.type_checking_logic.check_types.UserId,)
->>> get_type_arguments(List)
-()
->>> T = TypeVar('T')
->>> get_type_arguments(List[T])
-(~T,)
->>> get_type_arguments(List[List[int]])
-(typing.List[int],)
->>> get_type_arguments(List[List[List[int]]])
-(typing.List[typing.List[int]],)
->>> get_type_arguments(List[Tuple[float, str]])
-(typing.Tuple[float, str],)
->>> get_type_arguments(List[Tuple[Any, ...]])
-(typing.Tuple[typing.Any, ...],)
->>> get_type_arguments(Union[str, float, int])
-(<class 'str'>, <class 'float'>, <class 'int'>)
->>> get_type_arguments(Union[str, float, List[int], int])
-(<class 'str'>, <class 'float'>, typing.List[int], <class 'int'>)
->>> get_type_arguments(Callable)
-()
->>> get_type_arguments(Callable[[int, float], Tuple[float, str]])
-([<class 'int'>, <class 'float'>], typing.Tuple[float, str])
->>> get_type_arguments(Callable[..., str])
-(Ellipsis, <class 'str'>)
->>> get_type_arguments(Optional[int])
-(<class 'int'>, <class 'NoneType'>)
->>> get_type_arguments(str | int)
-(<class 'str'>, <class 'int'>)
->>> get_type_arguments(Awaitable[str])
-(<class 'str'>,)
->>> get_type_arguments(Coroutine[int, bool, str])
-(<class 'int'>, <class 'bool'>, <class 'str'>)
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/type_checking_logic/index.html b/docs/pedantic/type_checking_logic/index.html deleted file mode 100644 index 928a58bc..00000000 --- a/docs/pedantic/type_checking_logic/index.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - -pedantic.type_checking_logic API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.type_checking_logic

-
-
-
-
-

Sub-modules

-
-
pedantic.type_checking_logic.check_docstring
-
-
-
-
pedantic.type_checking_logic.check_generic_classes
-
-
-
-
pedantic.type_checking_logic.check_types
-
- -
-
pedantic.type_checking_logic.resolve_forward_ref
-
-
-
-
-
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/pedantic/type_checking_logic/resolve_forward_ref.html b/docs/pedantic/type_checking_logic/resolve_forward_ref.html deleted file mode 100644 index a659b160..00000000 --- a/docs/pedantic/type_checking_logic/resolve_forward_ref.html +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - -pedantic.type_checking_logic.resolve_forward_ref API documentation - - - - - - - - - - - -
-
-
-

Module pedantic.type_checking_logic.resolve_forward_ref

-
-
-
-
-
-
-
-
-

Functions

-
-
-def resolve_forward_ref(type_: str, globals_: Dict[str, Any] = None, context: Dict = None) ‑> Type -
-
-
- -Expand source code - -
def resolve_forward_ref(type_: str, globals_: Dict[str, Any] = None, context: Dict = None) -> Type:
-    """
-        Resolve a type annotation that is a string.
-
-        Raises:
-            NameError: in case of [type_] cannot be resolved.
-    """
-
-    return eval(str(type_), globals_ or globals(), context or {})
-
-

Resolve a type annotation that is a string.

-

Raises

-
-
NameError
-
in case of [type_] cannot be resolved.
-
-
-
-
-
-
-
- -
- - - diff --git a/docs/search.js b/docs/search.js new file mode 100644 index 00000000..12bb2dd1 --- /dev/null +++ b/docs/search.js @@ -0,0 +1,46 @@ +window.pdocSearch = (function(){ +/** elasticlunr - http://weixsong.github.io * Copyright (C) 2017 Oliver Nightingale * Copyright (C) 2017 Wei Song * MIT Licensed */!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();o

\n"}, {"fullname": "pedantic.ConversionError", "modulename": "pedantic", "qualname": "ConversionError", "kind": "class", "doc": "

Is raised if a type cast failed.

\n", "bases": "pedantic.decorators.fn_deco_validate.exceptions.ValidateException"}, {"fullname": "pedantic.DateTimeUnixTimestamp", "modulename": "pedantic", "qualname": "DateTimeUnixTimestamp", "kind": "class", "doc": "

Base class for validator classes.

\n", "bases": "pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator"}, {"fullname": "pedantic.DateTimeUnixTimestamp.validate", "modulename": "pedantic", "qualname": "DateTimeUnixTimestamp.validate", "kind": "function", "doc": "

Validates and convert the value.\nRaises an [ValidatorException] in case of an invalid value.\nTo raise this you can simply call self.raise_exception().

\n", "signature": "(self, value: float | str) -> datetime.datetime:", "funcdef": "def"}, {"fullname": "pedantic.DatetimeIsoFormat", "modulename": "pedantic", "qualname": "DatetimeIsoFormat", "kind": "class", "doc": "

Base class for validator classes.

\n", "bases": "pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator"}, {"fullname": "pedantic.DatetimeIsoFormat.validate", "modulename": "pedantic", "qualname": "DatetimeIsoFormat.validate", "kind": "function", "doc": "

Validates and convert the value.\nRaises an [ValidatorException] in case of an invalid value.\nTo raise this you can simply call self.raise_exception().

\n", "signature": "(self, value: str) -> datetime.datetime:", "funcdef": "def"}, {"fullname": "pedantic.DecoratorType", "modulename": "pedantic", "qualname": "DecoratorType", "kind": "class", "doc": "

The interface that defines all possible decorators types.

\n\n

The values of this enum are used as property names and the properties are added to the decorated functions.\nSo I would recommend naming them with a leading underscore to keep them private and also write it lowercase.

\n\n

Example:

\n\n
\n
\n
\n

class Decorators(DecoratorType):\n ... FOO = '_foo'

\n
\n
\n
\n", "bases": "enum.StrEnum"}, {"fullname": "pedantic.Deserializable", "modulename": "pedantic", "qualname": "Deserializable", "kind": "class", "doc": "

A tiny interface which has a static from_json() method which acts like a named constructor.

\n", "bases": "abc.ABC"}, {"fullname": "pedantic.Deserializable.from_json", "modulename": "pedantic", "qualname": "Deserializable.from_json", "kind": "function", "doc": "

A named constructor which creates an object from JSON.

\n", "signature": "(\tdata: dict[str, typing.Any]) -> pedantic.decorators.fn_deco_validate.parameters.deserializable.Deserializable:", "funcdef": "def"}, {"fullname": "pedantic.Email", "modulename": "pedantic", "qualname": "Email", "kind": "class", "doc": "

Base class for validator classes.

\n", "bases": "pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator"}, {"fullname": "pedantic.Email.__init__", "modulename": "pedantic", "qualname": "Email.__init__", "kind": "function", "doc": "

\n", "signature": "(\temail_pattern: str = '[^@\\\\s]+@[^@\\\\s]+\\\\.[a-zA-Z0-9]+$',\tpost_processor: Callable[[str], str] = <function Email.<lambda>>)"}, {"fullname": "pedantic.Email.validate", "modulename": "pedantic", "qualname": "Email.validate", "kind": "function", "doc": "

Validates and convert the value.\nRaises an [ValidatorException] in case of an invalid value.\nTo raise this you can simply call self.raise_exception().

\n", "signature": "(self, value: str) -> str:", "funcdef": "def"}, {"fullname": "pedantic.EnvironmentVariableParameter", "modulename": "pedantic", "qualname": "EnvironmentVariableParameter", "kind": "class", "doc": "

The interface for all external parameters.

\n", "bases": "pedantic.decorators.fn_deco_validate.parameters.abstract_external_parameter.ExternalParameter"}, {"fullname": "pedantic.EnvironmentVariableParameter.__init__", "modulename": "pedantic", "qualname": "EnvironmentVariableParameter.__init__", "kind": "function", "doc": "

\n", "signature": "(\tname: str,\tenv_var_name: str | None = None,\tvalue_type: type[str | bool | int | float] = <class 'str'>,\tvalidators: Iterable[pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator] | None = None,\trequired: bool = True,\tdefault: Any = <class 'pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue'>)"}, {"fullname": "pedantic.EnvironmentVariableParameter.has_value", "modulename": "pedantic", "qualname": "EnvironmentVariableParameter.has_value", "kind": "function", "doc": "

Returns True if the value can be fetched.

\n", "signature": "(self) -> bool:", "funcdef": "def"}, {"fullname": "pedantic.EnvironmentVariableParameter.load_value", "modulename": "pedantic", "qualname": "EnvironmentVariableParameter.load_value", "kind": "function", "doc": "

Loads a value and returns it.

\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "pedantic.ExternalParameter", "modulename": "pedantic", "qualname": "ExternalParameter", "kind": "class", "doc": "

The interface for all external parameters.

\n", "bases": "pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.Parameter, abc.ABC"}, {"fullname": "pedantic.ExternalParameter.has_value", "modulename": "pedantic", "qualname": "ExternalParameter.has_value", "kind": "function", "doc": "

Returns True if the value can be fetched.

\n", "signature": "(self) -> bool:", "funcdef": "def"}, {"fullname": "pedantic.ExternalParameter.load_value", "modulename": "pedantic", "qualname": "ExternalParameter.load_value", "kind": "function", "doc": "

Loads a value and returns it.

\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "pedantic.ForEach", "modulename": "pedantic", "qualname": "ForEach", "kind": "class", "doc": "

Base class for validator classes.

\n", "bases": "pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator"}, {"fullname": "pedantic.ForEach.__init__", "modulename": "pedantic", "qualname": "ForEach.__init__", "kind": "function", "doc": "

\n", "signature": "(\tvalidators: pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator | Iterable[pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator])"}, {"fullname": "pedantic.ForEach.validate", "modulename": "pedantic", "qualname": "ForEach.validate", "kind": "function", "doc": "

Validates and convert the value.\nRaises an [ValidatorException] in case of an invalid value.\nTo raise this you can simply call self.raise_exception().

\n", "signature": "(self, value: Iterable[typing.Any]) -> list[typing.Any]:", "funcdef": "def"}, {"fullname": "pedantic.GenericMixin", "modulename": "pedantic", "qualname": "GenericMixin", "kind": "class", "doc": "

A mixin that provides easy access to given type variables.

\n\n

Example:

\n\n
\n
\n
\n

from typing import Generic, TypeVar\n T = TypeVar('T')\n U = TypeVar('U')\n class Foo(Generic[T, U], GenericMixin):\n ... values: list[T]\n ... value: U\n f = Foostr, int\n f.type_vars\n {~T: , ~U: }

\n
\n
\n
\n"}, {"fullname": "pedantic.GenericMixin.type_vars", "modulename": "pedantic", "qualname": "GenericMixin.type_vars", "kind": "variable", "doc": "

Returns the mapping of type variables to types.

\n\n

DO NOT call this inside __init__()!

\n\n

Example:

\n\n
\n
\n
\n

from typing import Generic, TypeVar\n T = TypeVar('T')\n U = TypeVar('U')\n class Foo(Generic[T, U], GenericMixin):\n ... values: list[T]\n ... value: U\n f = Foostr, int\n f.type_vars\n {~T: , ~U: }

\n
\n
\n
\n", "annotation": ": dict[typing.TypeVar, type]"}, {"fullname": "pedantic.InvalidHeader", "modulename": "pedantic", "qualname": "InvalidHeader", "kind": "class", "doc": "

Is raised if there is a validation error in a FlaskHeaderParameter.

\n", "bases": "pedantic.decorators.fn_deco_validate.exceptions.ParameterException"}, {"fullname": "pedantic.IsEnum", "modulename": "pedantic", "qualname": "IsEnum", "kind": "class", "doc": "

Base class for validator classes.

\n", "bases": "pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator"}, {"fullname": "pedantic.IsEnum.__init__", "modulename": "pedantic", "qualname": "IsEnum.__init__", "kind": "function", "doc": "

\n", "signature": "(\tenum: enum.EnumType,\tconvert: bool = True,\tto_upper_case: bool = True)"}, {"fullname": "pedantic.IsEnum.validate", "modulename": "pedantic", "qualname": "IsEnum.validate", "kind": "function", "doc": "

Validates and convert the value.\nRaises an [ValidatorException] in case of an invalid value.\nTo raise this you can simply call self.raise_exception().

\n", "signature": "(self, value: Any) -> Any:", "funcdef": "def"}, {"fullname": "pedantic.IsUuid", "modulename": "pedantic", "qualname": "IsUuid", "kind": "class", "doc": "

Base class for validator classes.

\n", "bases": "pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator"}, {"fullname": "pedantic.IsUuid.__init__", "modulename": "pedantic", "qualname": "IsUuid.__init__", "kind": "function", "doc": "

\n", "signature": "(convert: bool = False)"}, {"fullname": "pedantic.IsUuid.validate", "modulename": "pedantic", "qualname": "IsUuid.validate", "kind": "function", "doc": "

Validates and convert the value.\nRaises an [ValidatorException] in case of an invalid value.\nTo raise this you can simply call self.raise_exception().

\n", "signature": "(self, value: str) -> str:", "funcdef": "def"}, {"fullname": "pedantic.MatchPattern", "modulename": "pedantic", "qualname": "MatchPattern", "kind": "class", "doc": "

Base class for validator classes.

\n", "bases": "pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator"}, {"fullname": "pedantic.MatchPattern.__init__", "modulename": "pedantic", "qualname": "MatchPattern.__init__", "kind": "function", "doc": "

\n", "signature": "(pattern: str)"}, {"fullname": "pedantic.MatchPattern.validate", "modulename": "pedantic", "qualname": "MatchPattern.validate", "kind": "function", "doc": "

Validates and convert the value.\nRaises an [ValidatorException] in case of an invalid value.\nTo raise this you can simply call self.raise_exception().

\n", "signature": "(self, value: str) -> str:", "funcdef": "def"}, {"fullname": "pedantic.Max", "modulename": "pedantic", "qualname": "Max", "kind": "class", "doc": "

Base class for validator classes.

\n", "bases": "pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator"}, {"fullname": "pedantic.Max.__init__", "modulename": "pedantic", "qualname": "Max.__init__", "kind": "function", "doc": "
\n
>>> Max(7, True).validate(7)\n7\n>>> Max(7, False).validate(7)  # doctest: +IGNORE_EXCEPTION_DETAIL\nTraceback (most recent call last):\nValidatorException: ...\n>>> Max(7, False).validate(6.999)\n6.999\n
\n
\n", "signature": "(value: float, include_boundary: bool = True)"}, {"fullname": "pedantic.Max.validate", "modulename": "pedantic", "qualname": "Max.validate", "kind": "function", "doc": "

Validates and convert the value.\nRaises an [ValidatorException] in case of an invalid value.\nTo raise this you can simply call self.raise_exception().

\n", "signature": "(self, value: float) -> int | float:", "funcdef": "def"}, {"fullname": "pedantic.MaxLength", "modulename": "pedantic", "qualname": "MaxLength", "kind": "class", "doc": "

Base class for validator classes.

\n", "bases": "pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator"}, {"fullname": "pedantic.MaxLength.__init__", "modulename": "pedantic", "qualname": "MaxLength.__init__", "kind": "function", "doc": "

\n", "signature": "(length: int)"}, {"fullname": "pedantic.MaxLength.validate", "modulename": "pedantic", "qualname": "MaxLength.validate", "kind": "function", "doc": "

Validates and convert the value.\nRaises an [ValidatorException] in case of an invalid value.\nTo raise this you can simply call self.raise_exception().

\n", "signature": "(self, value: Sized) -> Any:", "funcdef": "def"}, {"fullname": "pedantic.Min", "modulename": "pedantic", "qualname": "Min", "kind": "class", "doc": "

Base class for validator classes.

\n", "bases": "pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator"}, {"fullname": "pedantic.Min.__init__", "modulename": "pedantic", "qualname": "Min.__init__", "kind": "function", "doc": "
\n
>>> Min(7, True).validate(7)\n7\n>>> Min(7, False).validate(7)  # doctest: +IGNORE_EXCEPTION_DETAIL\nTraceback (most recent call last):\nValidatorException: ...\n>>> Min(7, False).validate(7.001)\n7.001\n
\n
\n", "signature": "(value: float, include_boundary: bool = True)"}, {"fullname": "pedantic.Min.validate", "modulename": "pedantic", "qualname": "Min.validate", "kind": "function", "doc": "

Validates and convert the value.\nRaises an [ValidatorException] in case of an invalid value.\nTo raise this you can simply call self.raise_exception().

\n", "signature": "(self, value: float) -> int | float:", "funcdef": "def"}, {"fullname": "pedantic.MinLength", "modulename": "pedantic", "qualname": "MinLength", "kind": "class", "doc": "

Base class for validator classes.

\n", "bases": "pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator"}, {"fullname": "pedantic.MinLength.__init__", "modulename": "pedantic", "qualname": "MinLength.__init__", "kind": "function", "doc": "

\n", "signature": "(length: int)"}, {"fullname": "pedantic.MinLength.validate", "modulename": "pedantic", "qualname": "MinLength.validate", "kind": "function", "doc": "

Validates and convert the value.\nRaises an [ValidatorException] in case of an invalid value.\nTo raise this you can simply call self.raise_exception().

\n", "signature": "(self, value: Sized) -> Any:", "funcdef": "def"}, {"fullname": "pedantic.NotEmpty", "modulename": "pedantic", "qualname": "NotEmpty", "kind": "class", "doc": "

Validates that the given value is not empty.

\n", "bases": "pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator"}, {"fullname": "pedantic.NotEmpty.__init__", "modulename": "pedantic", "qualname": "NotEmpty.__init__", "kind": "function", "doc": "

If strip is True, the leading and trailing whitespace will be removed.

\n", "signature": "(strip: bool = True)"}, {"fullname": "pedantic.NotEmpty.strip", "modulename": "pedantic", "qualname": "NotEmpty.strip", "kind": "variable", "doc": "

\n"}, {"fullname": "pedantic.NotEmpty.validate", "modulename": "pedantic", "qualname": "NotEmpty.validate", "kind": "function", "doc": "

Throws a ValidationError if the sequence is empty.\nIf the sequence is a string, it removes all leading and trailing whitespace.

\n", "signature": "(self, value: Sequence) -> Sequence:", "funcdef": "def"}, {"fullname": "pedantic.Parameter", "modulename": "pedantic", "qualname": "Parameter", "kind": "class", "doc": "

\n"}, {"fullname": "pedantic.Parameter.__init__", "modulename": "pedantic", "qualname": "Parameter.__init__", "kind": "function", "doc": "

\n", "signature": "(\tname: str,\tvalue_type: type[bool | int | float | str | dict | list] | None = None,\tvalidators: Iterable[pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator] | None = None,\tdefault: Any = <class 'pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.NoValue'>,\trequired: bool = True)"}, {"fullname": "pedantic.Parameter.exception_type", "modulename": "pedantic", "qualname": "Parameter.exception_type", "kind": "variable", "doc": "

\n", "annotation": ": type[pedantic.decorators.fn_deco_validate.exceptions.ParameterException]", "default_value": "<class 'pedantic.decorators.fn_deco_validate.exceptions.ParameterException'>"}, {"fullname": "pedantic.Parameter.name", "modulename": "pedantic", "qualname": "Parameter.name", "kind": "variable", "doc": "

\n"}, {"fullname": "pedantic.Parameter.validators", "modulename": "pedantic", "qualname": "Parameter.validators", "kind": "variable", "doc": "

\n"}, {"fullname": "pedantic.Parameter.default_value", "modulename": "pedantic", "qualname": "Parameter.default_value", "kind": "variable", "doc": "

\n"}, {"fullname": "pedantic.Parameter.value_type", "modulename": "pedantic", "qualname": "Parameter.value_type", "kind": "variable", "doc": "

\n"}, {"fullname": "pedantic.Parameter.is_required", "modulename": "pedantic", "qualname": "Parameter.is_required", "kind": "variable", "doc": "

\n"}, {"fullname": "pedantic.Parameter.validate", "modulename": "pedantic", "qualname": "Parameter.validate", "kind": "function", "doc": "

Apply all validators to the given value and collect all ValidationErrors.

\n", "signature": "(self, value: Any) -> Any:", "funcdef": "def"}, {"fullname": "pedantic.Parameter.raise_exception", "modulename": "pedantic", "qualname": "Parameter.raise_exception", "kind": "function", "doc": "

\n", "signature": "(\tself,\tmsg: str,\tvalue: Any = None,\tvalidator: pedantic.decorators.fn_deco_validate.validators.abstract_validator.Validator | None = None) -> NoReturn:", "funcdef": "def"}, {"fullname": "pedantic.ParameterException", "modulename": "pedantic", "qualname": "ParameterException", "kind": "class", "doc": "

An exception that is raised inside a Parameter.

\n", "bases": "pedantic.decorators.fn_deco_validate.exceptions.ValidateException"}, {"fullname": "pedantic.ParameterException.__init__", "modulename": "pedantic", "qualname": "ParameterException.__init__", "kind": "function", "doc": "

\n", "signature": "(\tmsg: str,\tparameter_name: str,\tvalue: typing.Any | None = None,\tvalidator_name: str | None = None)"}, {"fullname": "pedantic.ParameterException.validator_name", "modulename": "pedantic", "qualname": "ParameterException.validator_name", "kind": "variable", "doc": "

\n"}, {"fullname": "pedantic.ParameterException.parameter_name", "modulename": "pedantic", "qualname": "ParameterException.parameter_name", "kind": "variable", "doc": "

\n"}, {"fullname": "pedantic.ParameterException.value", "modulename": "pedantic", "qualname": "ParameterException.value", "kind": "variable", "doc": "

\n"}, {"fullname": "pedantic.ParameterException.from_validator_exception", "modulename": "pedantic", "qualname": "ParameterException.from_validator_exception", "kind": "function", "doc": "

Creates a parameter exception from a validator exception.

\n", "signature": "(\tcls,\texception: pedantic.decorators.fn_deco_validate.exceptions.ValidatorException,\tparameter_name: str = '') -> pedantic.decorators.fn_deco_validate.exceptions.ParameterException:", "funcdef": "def"}, {"fullname": "pedantic.ParameterException.to_dict", "modulename": "pedantic", "qualname": "ParameterException.to_dict", "kind": "variable", "doc": "

\n", "annotation": ": dict[str, str]"}, {"fullname": "pedantic.ReturnAs", "modulename": "pedantic", "qualname": "ReturnAs", "kind": "class", "doc": "

\n", "bases": "enum.Enum"}, {"fullname": "pedantic.ReturnAs.ARGS", "modulename": "pedantic", "qualname": "ReturnAs.ARGS", "kind": "variable", "doc": "

\n", "default_value": "<ReturnAs.ARGS: 'ARGS'>"}, {"fullname": "pedantic.ReturnAs.KWARGS_WITH_NONE", "modulename": "pedantic", "qualname": "ReturnAs.KWARGS_WITH_NONE", "kind": "variable", "doc": "

\n", "default_value": "<ReturnAs.KWARGS_WITH_NONE: 'KWARGS_WITH_NONE'>"}, {"fullname": "pedantic.ReturnAs.KWARGS_WITHOUT_NONE", "modulename": "pedantic", "qualname": "ReturnAs.KWARGS_WITHOUT_NONE", "kind": "variable", "doc": "

\n", "default_value": "<ReturnAs.KWARGS_WITHOUT_NONE: 'KWARGS_WITHOUT_NONE'>"}, {"fullname": "pedantic.TooManyArguments", "modulename": "pedantic", "qualname": "TooManyArguments", "kind": "class", "doc": "

Is raised if the function got more arguments than expected.

\n", "bases": "pedantic.decorators.fn_deco_validate.exceptions.ValidateException"}, {"fullname": "pedantic.ValidateException", "modulename": "pedantic", "qualname": "ValidateException", "kind": "class", "doc": "

The base class for all exception thrown by the validate decorator.

\n", "bases": "builtins.Exception"}, {"fullname": "pedantic.ValidateException.__init__", "modulename": "pedantic", "qualname": "ValidateException.__init__", "kind": "function", "doc": "

\n", "signature": "(msg: str)"}, {"fullname": "pedantic.ValidateException.message", "modulename": "pedantic", "qualname": "ValidateException.message", "kind": "variable", "doc": "

\n"}, {"fullname": "pedantic.Validator", "modulename": "pedantic", "qualname": "Validator", "kind": "class", "doc": "

Base class for validator classes.

\n", "bases": "abc.ABC"}, {"fullname": "pedantic.Validator.validate", "modulename": "pedantic", "qualname": "Validator.validate", "kind": "function", "doc": "

Validates and convert the value.\nRaises an [ValidatorException] in case of an invalid value.\nTo raise this you can simply call self.raise_exception().

\n", "signature": "(self, value: Any) -> Any:", "funcdef": "def"}, {"fullname": "pedantic.Validator.validate_param", "modulename": "pedantic", "qualname": "Validator.validate_param", "kind": "function", "doc": "

Validates and converts the value, just like [validate()].\nThe difference is that a parameter_name is included in the exception, if an exception is raised.

\n", "signature": "(self, value: Any, parameter_name: str) -> Any:", "funcdef": "def"}, {"fullname": "pedantic.Validator.raise_exception", "modulename": "pedantic", "qualname": "Validator.raise_exception", "kind": "function", "doc": "

\n", "signature": "(self, value: Any, msg: str) -> NoReturn:", "funcdef": "def"}, {"fullname": "pedantic.Validator.name", "modulename": "pedantic", "qualname": "Validator.name", "kind": "variable", "doc": "

\n", "annotation": ": str"}, {"fullname": "pedantic.ValidatorException", "modulename": "pedantic", "qualname": "ValidatorException", "kind": "class", "doc": "

An exception that is raised inside the validate() function of a Validator.

\n", "bases": "pedantic.decorators.fn_deco_validate.exceptions.ValidateException"}, {"fullname": "pedantic.ValidatorException.__init__", "modulename": "pedantic", "qualname": "ValidatorException.__init__", "kind": "function", "doc": "

\n", "signature": "(msg: str, validator_name: str, value: Any, parameter_name: str = '')"}, {"fullname": "pedantic.ValidatorException.validator_name", "modulename": "pedantic", "qualname": "ValidatorException.validator_name", "kind": "variable", "doc": "

\n"}, {"fullname": "pedantic.ValidatorException.value", "modulename": "pedantic", "qualname": "ValidatorException.value", "kind": "variable", "doc": "

\n"}, {"fullname": "pedantic.ValidatorException.parameter_name", "modulename": "pedantic", "qualname": "ValidatorException.parameter_name", "kind": "variable", "doc": "

\n"}, {"fullname": "pedantic.WithDecoratedMethods", "modulename": "pedantic", "qualname": "WithDecoratedMethods", "kind": "class", "doc": "

A mixin that is used to figure out which method is decorated with custom parameterized decorators.

\n\n

Example:

\n\n
\n
\n
\n

class Decorators(DecoratorType):\n ... FOO = '_foo'\n ... BAR = '_bar'\n foo = create_decorator(decorator_type=Decorators.FOO)\n bar = create_decorator(decorator_type=Decorators.BAR)\n class MyClass(WithDecoratedMethods[Decorators]):\n ... @foo(42)\n ... def m1(self) -> None:\n ... print('bar')\n ...\n ... @foo(value=43)\n ... def m2(self) -> None:\n ... print('bar')\n ...\n ... @bar(value=44)\n ... def m3(self) -> None:\n ... print('bar')\n instance = MyClass()\n instance.get_decorated_functions() # doctest: +SKIP\n {\n : {\n >: 42,\n >: 43,\n },\n : {\n >: 44,\n }\n }

\n
\n
\n
\n", "bases": "abc.ABC, pedantic.mixins.generic_mixin.GenericMixin, typing.Generic[~DecoratorTypeVar]"}, {"fullname": "pedantic.WithDecoratedMethods.get_decorated_functions", "modulename": "pedantic", "qualname": "WithDecoratedMethods.get_decorated_functions", "kind": "function", "doc": "

Returns a mapping of all functions that are decorated by the given decorator type.

\n", "signature": "(self) -> dict[~DecoratorTypeVar, dict[~C, ~T]]:", "funcdef": "def"}, {"fullname": "pedantic.assert_value_matches_type", "modulename": "pedantic", "qualname": "assert_value_matches_type", "kind": "function", "doc": "

Checks that the given value matches the given type.

\n", "signature": "(\tvalue: Any,\ttype_: Any,\terr: str,\ttype_vars: Dict[TypeVar, Any],\tkey: str | None = None,\tmsg: str | None = None,\tcontext: Optional[Dict[str, Any]] = None) -> None:", "funcdef": "def"}, {"fullname": "pedantic.calculate_in_subprocess", "modulename": "pedantic", "qualname": "calculate_in_subprocess", "kind": "function", "doc": "

Calculates the result of a synchronous function in subprocess without blocking the current thread.

\n\n

Arguments:\n func: The function that will be called in a subprocess.\n args: Positional arguments that will be passed to the function.\n kwargs: Keyword arguments that will be passed to the function.

\n\n

Returns:\n The calculated result of the function \"func\".

\n\n

Raises:\n Any Exception that is raised inside [func].

\n\n

Further reading: https://medium.com/devopss-hole/python-multiprocessing-pickle-issue-e2d35ccf96a9

\n\n

Example:

\n\n
\n
\n
\n

import time\n import asyncio\n def f(value: int) -> int:\n ... time.sleep(0.1) # a long taking synchronous blocking calculation\n ... return 2 * value\n asyncio.run(calculate_in_subprocess(func=f, value=42))\n 84

\n
\n
\n
\n", "signature": "(\tfunc: Callable[..., typing.Union[~T, Awaitable[~T]]],\t*args: Any,\t**kwargs: Any) -> ~T:", "funcdef": "async def"}, {"fullname": "pedantic.create_decorator", "modulename": "pedantic", "qualname": "create_decorator", "kind": "function", "doc": "

Creates a new decorator that is parametrized with one argument of an arbitrary type.

\n\n

You can also pass an arbitrary [transformation] to add custom behavior to the decorator.

\n", "signature": "(\tdecorator_type: pedantic.mixins.with_decorated_methods.DecoratorType,\ttransformation: Callable[[~C, pedantic.mixins.with_decorated_methods.DecoratorType, ~T], ~C] | None = None) -> Callable[[~T], Callable[[~C], ~C]]:", "funcdef": "def"}, {"fullname": "pedantic.deprecated", "modulename": "pedantic", "qualname": "deprecated", "kind": "function", "doc": "

Use this decorator to mark a function as deprecated. It will raise a warning when the function is called.\nYou can specify an optional reason or message to display with the warning.

\n\n

If you use Python 3.13 or newer, consider using warnings.deprecated instead from the standard library.

\n\n

Example:

\n\n
\n
>>> @deprecated\n... def my_function(a, b, c):\n...     pass\n>>> my_function(5, 4, 3)  # doctest: +SKIP\n>>> @deprecated(message='Will be removed soon. Please use my_function_new_instead.')\n... def my_function(a, b, c):\n...     pass\n>>> my_function(5, 4, 3)  # doctest: +SKIP\n
\n
\n", "signature": "(\tfunc: Callable[..., ~ReturnType] | None = None,\tmessage: str = '') -> Callable[..., ~ReturnType] | Callable[[Callable[..., ~ReturnType]], Callable[..., ~ReturnType]]:", "funcdef": "def"}, {"fullname": "pedantic.for_all_methods", "modulename": "pedantic", "qualname": "for_all_methods", "kind": "function", "doc": "

Applies a decorator to all methods of a class.

\n\n

Example:

\n\n
\n
>>> @for_all_methods(pedantic)\n... class MyClass(object):\n...     def m1(self): pass\n...     def m2(self, x): pass\n
\n
\n", "signature": "(decorator: Callable[..., ~ReturnType]) -> Callable[[type[~C]], type[~C]]:", "funcdef": "def"}, {"fullname": "pedantic.frozen_dataclass", "modulename": "pedantic", "qualname": "frozen_dataclass", "kind": "function", "doc": "

Makes the decorated class immutable and a dataclass by adding the [@dataclass(frozen=True)]\ndecorator. Also adds useful copy_with() and validate_types() instance methods to this class (see below).

\n\n

If [type_safe] is True, a type check is performed for each field after the __post_init__ method was called\nwhich itself s directly called after the __init__ constructor.\nNote this have a negative impact on the performance. It's recommend to use this for debugging and testing only.

\n\n

In a nutshell, the followings methods will be added to the decorated class automatically:

\n\n
    \n
  • __init__() gives you a simple constructor like \"Foo(a=6, b='hi', c=True)\"
  • \n
  • __eq__() lets you compare objects easily with \"a == b\"
  • \n
  • __hash__() is also needed for instance comparison
  • \n
  • __repr__() gives you a nice output when you call \"print(foo)\"
  • \n
  • copy_with() allows you to quickly create new similar frozen instances. Use this instead of setters.
  • \n
  • deep_copy_with() allows you to create deep copies and modify them.
  • \n
  • validate_types() allows you to validate the types of the dataclass.\nThis is called automatically when [type_safe] is True.
  • \n
\n\n

If the [order] parameter is True (default is False), the following comparison methods\nwill be added additionally:

\n\n
    \n
  • __lt__() lets you compare instance like \"a < b\"
  • \n
  • __le__() lets you compare instance like \"a <= b\"
  • \n
  • __gt__() lets you compare instance like \"a > b\"
  • \n
  • __ge__() lets you compare instance like \"a >= b\"
  • \n
\n\n

These compare the class as if it were a tuple of its fields, in order.\nBoth instances in the comparison must be of the identical type.

\n\n

The parameters slots and kw_only are only applied if the Python version is greater or equal to 3.10.

\n\n

Example:

\n\n
\n
>>> @frozen_dataclass\n... class Foo:\n...     a: int\n...     b: str\n...     c: bool\n>>> foo = Foo(a=6, b='hi', c=True)\n>>> print(foo)\nFoo(a=6, b='hi', c=True)\n>>> print(foo.copy_with())\nFoo(a=6, b='hi', c=True)\n>>> print(foo.copy_with(a=42))\nFoo(a=42, b='hi', c=True)\n>>> print(foo.copy_with(b='Hello'))\nFoo(a=6, b='Hello', c=True)\n>>> print(foo.copy_with(c=False))\nFoo(a=6, b='hi', c=False)\n>>> print(foo.copy_with(a=676676, b='new', c=False))\nFoo(a=676676, b='new', c=False)\n
\n
\n", "signature": "(\tcls: type[~T] | None = None,\ttype_safe: bool = False,\torder: bool = False,\tkw_only: bool = True,\tslots: bool = False) -> type[~T] | Callable[[type[~T]], type[~T]]:", "funcdef": "def"}, {"fullname": "pedantic.frozen_type_safe_dataclass", "modulename": "pedantic", "qualname": "frozen_type_safe_dataclass", "kind": "function", "doc": "

Shortcut for @frozen_dataclass(type_safe=True)

\n", "signature": "(cls: type[~T]) -> type[~T]:", "funcdef": "def"}, {"fullname": "pedantic.in_subprocess", "modulename": "pedantic", "qualname": "in_subprocess", "kind": "function", "doc": "

Executes the decorated function in a subprocess and returns the return value of it.\nNote that the decorated function will be replaced with an async function which returns\na coroutine that needs to be awaited.\nThis purpose of this is doing long-taking calculations without blocking the main thread\nof your application synchronously. That ensures that other asyncio.Tasks can work without any problem\nat the same time.

\n\n

Example:

\n\n
\n
\n
\n

import time\n import asyncio\n @in_subprocess\n ... def f(value: int) -> int:\n ... time.sleep(0.1) # a long taking synchronous blocking calculation\n ... return 2 * value\n asyncio.run(f(value=42))\n 84

\n
\n
\n
\n", "signature": "(\tfunc: Callable[..., typing.Union[~T, Awaitable[~T]]]) -> Callable[..., Awaitable[~T]]:", "funcdef": "def"}, {"fullname": "pedantic.overrides", "modulename": "pedantic", "qualname": "overrides", "kind": "function", "doc": "

This is used for marking methods that overrides methods of the base class which makes the code more readable.\nThis decorator raises an Exception if the decorated method is not a method in the parent class.

\n\n

Example:

\n\n
\n
>>> class Parent:\n...     def my_instance_method(self):\n...         pass\n>>> class Child(Parent):\n...     @overrides(Parent)\n...     def my_instance_method(self):\n...         print('hello world')\n
\n
\n", "signature": "(base_class: type) -> Callable[..., ~ReturnType]:", "funcdef": "def"}, {"fullname": "pedantic.pedantic", "modulename": "pedantic", "qualname": "pedantic", "kind": "function", "doc": "

A PedanticException is raised if one of the following happened:

\n\n
    \n
  • The decorated function is called with positional arguments.
  • \n
  • The function has no type annotation for their return type or one or more parameters do not have type\nannotations.
  • \n
  • A type annotation is incorrect.
  • \n
  • A type annotation misses type arguments, e.g. typing.List instead of typing.List[int].
  • \n
  • The documented arguments do not match the argument list or their type annotations.
  • \n
\n\n

Example:

\n\n
\n
>>> @pedantic\n... def my_function(a: int, b: float, c: str) -> bool:\n...     return float(a) == b and str(b) == c\n>>> my_function(a=42.0, b=14.0, c='hi')\nTraceback (most recent call last):\n...\npedantic.exceptions.PedanticTypeCheckException: In function my_function:\nType hint is incorrect: Argument a=42.0 of type <class 'float'> does not match expected type <class 'int'>.\n>>> my_function(a=42, b=None, c='hi')\nTraceback (most recent call last):\n...\npedantic.exceptions.PedanticTypeCheckException: In function my_function:\nType hint is incorrect: Argument b=None of type <class 'NoneType'> does not match expected type <class 'float'>.\n>>> my_function(a=42, b=42, c='hi')\nTraceback (most recent call last):\n...\npedantic.exceptions.PedanticTypeCheckException: In function my_function:\nType hint is incorrect: Argument b=42 of type <class 'int'> does not match expected type <class 'float'>.\n>>> my_function(5, 4.0, 'hi')\nTraceback (most recent call last):\n...\npedantic.exceptions.PedanticCallWithArgsException: In function my_function:\nUse kwargs when you call function my_function. Args: (5, 4.0, 'hi')\n
\n
\n", "signature": "(\tfunc: Callable[..., ~ReturnType] | None = None,\trequire_docstring: bool = False) -> Callable[..., ~ReturnType]:", "funcdef": "def"}, {"fullname": "pedantic.pedantic_class", "modulename": "pedantic", "qualname": "pedantic_class", "kind": "function", "doc": "

Shortcut for @for_all_methods(pedantic)

\n", "signature": "(cls: ~C) -> ~C:", "funcdef": "def"}, {"fullname": "pedantic.pedantic_class_require_docstring", "modulename": "pedantic", "qualname": "pedantic_class_require_docstring", "kind": "function", "doc": "

Shortcut for @for_all_methods(pedantic_require_docstring)

\n", "signature": "(cls: ~C) -> ~C:", "funcdef": "def"}, {"fullname": "pedantic.pedantic_require_docstring", "modulename": "pedantic", "qualname": "pedantic_require_docstring", "kind": "function", "doc": "

Shortcut for @pedantic(require_docstring=True)

\n", "signature": "(\tfunc: Callable[..., ~ReturnType] | None = None) -> Callable[..., ~ReturnType]:", "funcdef": "def"}, {"fullname": "pedantic.resolve_forward_ref", "modulename": "pedantic", "qualname": "resolve_forward_ref", "kind": "function", "doc": "

Resolve a type annotation that is a string.

\n\n

Raises:\n NameError: in case of [type_] cannot be resolved.

\n", "signature": "(\ttype_: str,\tglobals_: dict[str, typing.Any] | None = None,\tcontext: dict | None = None) -> type:", "funcdef": "def"}, {"fullname": "pedantic.retry", "modulename": "pedantic", "qualname": "retry", "kind": "function", "doc": "

Retries the wrapped function/method attempts times if the exceptions listed\nin [exceptions] are thrown.

\n\n

Args:\n attempts: The number of times to repeat the wrapped function/method\n exceptions: Lists of exceptions that trigger a retry attempt.\n sleep_time: The time to wait between the retry attempts.\n logger: The logger used for logging.

\n\n

Example:

\n\n
\n
\n
\n

@retry(attempts=3, exceptions=(ValueError, TypeError))\n ... def foo():\n ... raise ValueError('Some error')\n foo() # doctest: +SKIP

\n
\n
\n
\n", "signature": "(\t*,\tattempts: int,\texceptions: type[Exception] | tuple[type[Exception], ...] = <class 'Exception'>,\tsleep_time: datetime.timedelta = datetime.timedelta(0),\tlogger: logging.Logger | None = None) -> Callable[[~C], ~C]:", "funcdef": "def"}, {"fullname": "pedantic.run_doctest_of_single_function", "modulename": "pedantic", "qualname": "run_doctest_of_single_function", "kind": "function", "doc": "

Useful for debugging a function with doctests.

\n", "signature": "(f: Callable) -> None:", "funcdef": "def"}, {"fullname": "pedantic.trace", "modulename": "pedantic", "qualname": "trace", "kind": "function", "doc": "

Prints the passed arguments and the returned value on each function call.

\n\n

Example:

\n\n
\n
>>> @trace\n... def my_function(a, b, c):\n...     return a + b + c\n>>> my_function(4, 5, 6)\n15\n
\n
\n", "signature": "(func: Callable[..., ~ReturnType]) -> Callable[..., ~ReturnType]:", "funcdef": "def"}, {"fullname": "pedantic.trace_class", "modulename": "pedantic", "qualname": "trace_class", "kind": "function", "doc": "

Shortcut for @for_all_methods(trace)

\n", "signature": "(cls: ~C) -> ~C:", "funcdef": "def"}, {"fullname": "pedantic.validate", "modulename": "pedantic", "qualname": "validate", "kind": "function", "doc": "

Validates the values that are passed to the function by using the validators in the given parameters.\nThe decorated function could also be async or an instance method as well as a normal function.

\n\n

Args:\n parameters (multiple Parameter): The parameters that will be validated.\n return_as (ReturnAs): Pass the arguments as kwargs to the decorated function if ReturnAs.KWARGS.\n Positional arguments are used otherwise.\n strict (bool): If strict is true, you have to define a Parameter for each of the\n arguments the decorated function takes.\n ignore_input (bool): If True, all given arguments passed to this decorator are ignored.\n This can be useful if you use only ExternalParameters.

\n\n

Returns:\n Callable: The decorated function.

\n", "signature": "(\t*parameters: pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.Parameter,\treturn_as: pedantic.decorators.fn_deco_validate.fn_deco_validate.ReturnAs = <ReturnAs.ARGS: 'ARGS'>,\tstrict: bool = True,\tignore_input: bool = False) -> Callable:", "funcdef": "def"}, {"fullname": "pedantic.FlaskFormParameter", "modulename": "pedantic", "qualname": "FlaskFormParameter", "kind": "class", "doc": "

The interface for all external parameters.

\n", "bases": "pedantic.decorators.fn_deco_validate.parameters.flask_parameters.FlaskParameter"}, {"fullname": "pedantic.FlaskFormParameter.get_dict", "modulename": "pedantic", "qualname": "FlaskFormParameter.get_dict", "kind": "function", "doc": "

Returns the actual values as a dictionary.

\n", "signature": "(self) -> dict:", "funcdef": "def"}, {"fullname": "pedantic.FlaskGetParameter", "modulename": "pedantic", "qualname": "FlaskGetParameter", "kind": "class", "doc": "

The interface for all external parameters.

\n", "bases": "pedantic.decorators.fn_deco_validate.parameters.flask_parameters.FlaskParameter"}, {"fullname": "pedantic.FlaskGetParameter.get_dict", "modulename": "pedantic", "qualname": "FlaskGetParameter.get_dict", "kind": "function", "doc": "

Returns the actual values as a dictionary.

\n", "signature": "(self) -> dict:", "funcdef": "def"}, {"fullname": "pedantic.FlaskGetParameter.load_value", "modulename": "pedantic", "qualname": "FlaskGetParameter.load_value", "kind": "function", "doc": "

Loads a value and returns it.

\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "pedantic.FlaskHeaderParameter", "modulename": "pedantic", "qualname": "FlaskHeaderParameter", "kind": "class", "doc": "

The interface for all external parameters.

\n", "bases": "pedantic.decorators.fn_deco_validate.parameters.flask_parameters.FlaskParameter"}, {"fullname": "pedantic.FlaskHeaderParameter.exception_type", "modulename": "pedantic", "qualname": "FlaskHeaderParameter.exception_type", "kind": "variable", "doc": "

\n", "default_value": "<class 'pedantic.decorators.fn_deco_validate.exceptions.InvalidHeader'>"}, {"fullname": "pedantic.FlaskHeaderParameter.get_dict", "modulename": "pedantic", "qualname": "FlaskHeaderParameter.get_dict", "kind": "function", "doc": "

Returns the actual values as a dictionary.

\n", "signature": "(self) -> dict:", "funcdef": "def"}, {"fullname": "pedantic.FlaskJsonParameter", "modulename": "pedantic", "qualname": "FlaskJsonParameter", "kind": "class", "doc": "

The interface for all external parameters.

\n", "bases": "pedantic.decorators.fn_deco_validate.parameters.flask_parameters.FlaskParameter"}, {"fullname": "pedantic.FlaskJsonParameter.get_dict", "modulename": "pedantic", "qualname": "FlaskJsonParameter.get_dict", "kind": "function", "doc": "

Returns the actual values as a dictionary.

\n", "signature": "(self) -> dict:", "funcdef": "def"}, {"fullname": "pedantic.FlaskParameter", "modulename": "pedantic", "qualname": "FlaskParameter", "kind": "class", "doc": "

The interface for all external parameters.

\n", "bases": "pedantic.decorators.fn_deco_validate.parameters.abstract_external_parameter.ExternalParameter, abc.ABC"}, {"fullname": "pedantic.FlaskParameter.get_dict", "modulename": "pedantic", "qualname": "FlaskParameter.get_dict", "kind": "function", "doc": "

Returns the actual values as a dictionary.

\n", "signature": "(self) -> dict[str, typing.Any]:", "funcdef": "def"}, {"fullname": "pedantic.FlaskParameter.has_value", "modulename": "pedantic", "qualname": "FlaskParameter.has_value", "kind": "function", "doc": "

Returns True if the value can be fetched.

\n", "signature": "(self) -> bool:", "funcdef": "def"}, {"fullname": "pedantic.FlaskParameter.load_value", "modulename": "pedantic", "qualname": "FlaskParameter.load_value", "kind": "function", "doc": "

Loads a value and returns it.

\n", "signature": "(self) -> Any:", "funcdef": "def"}, {"fullname": "pedantic.FlaskPathParameter", "modulename": "pedantic", "qualname": "FlaskPathParameter", "kind": "class", "doc": "

This is a special case because Flask passes path parameter as kwargs to validate().\nTherefore, this doesn't need to be an ExternalParameter.

\n", "bases": "pedantic.decorators.fn_deco_validate.parameters.abstract_parameter.Parameter"}, {"fullname": "pedantic.GenericFlaskDeserializer", "modulename": "pedantic", "qualname": "GenericFlaskDeserializer", "kind": "class", "doc": "

A JSON deserializer for classes which implements the [Deserializable] interface.

\n\n

Further reading: https://github.com/LostInDarkMath/pedantic-python-decorators/issues/55

\n", "bases": "pedantic.decorators.fn_deco_validate.parameters.abstract_external_parameter.ExternalParameter"}, {"fullname": "pedantic.GenericFlaskDeserializer.__init__", "modulename": "pedantic", "qualname": "GenericFlaskDeserializer.__init__", "kind": "function", "doc": "

\n", "signature": "(\tcls: type[pedantic.decorators.fn_deco_validate.parameters.deserializable.Deserializable],\tcatch_exception: bool = True,\t**kwargs: Any)"}, {"fullname": "pedantic.GenericFlaskDeserializer.has_value", "modulename": "pedantic", "qualname": "GenericFlaskDeserializer.has_value", "kind": "function", "doc": "

Returns True if the value can be fetched.

\n", "signature": "(self) -> bool:", "funcdef": "def"}, {"fullname": "pedantic.GenericFlaskDeserializer.load_value", "modulename": "pedantic", "qualname": "GenericFlaskDeserializer.load_value", "kind": "function", "doc": "

Loads a value and returns it.

\n", "signature": "(self) -> Any:", "funcdef": "def"}]; + + // mirrored in build-search-index.js (part 1) + // Also split on html tags. this is a cheap heuristic, but good enough. + elasticlunr.tokenizer.setSeperator(/[\s\-.;&_'"=,()]+|<[^>]*>/); + + let searchIndex; + if (docs._isPrebuiltIndex) { + console.info("using precompiled search index"); + searchIndex = elasticlunr.Index.load(docs); + } else { + console.time("building search index"); + // mirrored in build-search-index.js (part 2) + searchIndex = elasticlunr(function () { + this.pipeline.remove(elasticlunr.stemmer); + this.pipeline.remove(elasticlunr.stopWordFilter); + this.addField("qualname"); + this.addField("fullname"); + this.addField("annotation"); + this.addField("default_value"); + this.addField("signature"); + this.addField("bases"); + this.addField("doc"); + this.setRef("fullname"); + }); + for (let doc of docs) { + searchIndex.addDoc(doc); + } + console.timeEnd("building search index"); + } + + return (term) => searchIndex.search(term, { + fields: { + qualname: {boost: 4}, + fullname: {boost: 2}, + annotation: {boost: 2}, + default_value: {boost: 2}, + signature: {boost: 2}, + bases: {boost: 2}, + doc: {boost: 1}, + }, + expand: true + }); +})(); \ No newline at end of file diff --git a/pedantic/__init__.py b/pedantic/__init__.py index d3319863..d9fa5f36 100644 --- a/pedantic/__init__.py +++ b/pedantic/__init__.py @@ -1,18 +1,132 @@ -from pedantic.decorators import overrides, rename_kwargs, timer, count_calls, trace, trace_if_returns, \ - does_same_as_function, deprecated, unimplemented, require_kwargs, pedantic, \ - pedantic_require_docstring, for_all_methods, trace_class, timer_class, pedantic_class, \ - pedantic_class_require_docstring, Rename, mock, frozen_dataclass, frozen_type_safe_dataclass, in_subprocess, \ - calculate_in_subprocess, retry +from pedantic.decorators import ( + calculate_in_subprocess, + deprecated, + for_all_methods, + frozen_dataclass, + frozen_type_safe_dataclass, + in_subprocess, + overrides, + pedantic, + pedantic_class, + pedantic_class_require_docstring, + pedantic_require_docstring, + retry, + trace, + trace_class, +) +from pedantic.decorators.fn_deco_validate.exceptions import ( + ConversionError, + InvalidHeader, + ParameterException, + TooManyArguments, + ValidateException, + ValidatorException, +) +from pedantic.decorators.fn_deco_validate.fn_deco_validate import ( + ReturnAs, + validate, +) +from pedantic.decorators.fn_deco_validate.parameters import ( + Deserializable, + EnvironmentVariableParameter, + ExternalParameter, + Parameter, +) +from pedantic.decorators.fn_deco_validate.validators import ( + DatetimeIsoFormat, + DateTimeUnixTimestamp, + Email, + ForEach, + IsEnum, + IsUuid, + MatchPattern, + Max, + MaxLength, + Min, + MinLength, + NotEmpty, + Validator, +) +from pedantic.helper_fn import run_doctest_of_single_function +from pedantic.mixins import ( + DecoratorType, + GenericMixin, + WithDecoratedMethods, + create_decorator, +) +from pedantic.type_checking_logic import ( + assert_value_matches_type, + resolve_forward_ref, +) -from pedantic.mixins import GenericMixin, create_decorator, DecoratorType, WithDecoratedMethods +__all__ = [ + 'ConversionError', + 'DateTimeUnixTimestamp', + 'DatetimeIsoFormat', + 'DecoratorType', + 'Deserializable', + 'Email', + 'EnvironmentVariableParameter', + 'ExternalParameter', + 'ForEach', + 'GenericMixin', + 'InvalidHeader', + 'IsEnum', + 'IsUuid', + 'MatchPattern', + 'Max', + 'MaxLength', + 'Min', + 'MinLength', + 'NotEmpty', + 'Parameter', + 'ParameterException', + 'ReturnAs', + 'TooManyArguments', + 'ValidateException', + 'Validator', + 'ValidatorException', + 'WithDecoratedMethods', + 'assert_value_matches_type', + 'calculate_in_subprocess', + 'create_decorator', + 'deprecated', + 'for_all_methods', + 'frozen_dataclass', + 'frozen_type_safe_dataclass', + 'in_subprocess', + 'overrides', + 'pedantic', + 'pedantic_class', + 'pedantic_class_require_docstring', + 'pedantic_require_docstring', + 'resolve_forward_ref', + 'retry', + 'run_doctest_of_single_function', + 'trace', + 'trace_class', + 'validate', +] -from pedantic.type_checking_logic import assert_value_matches_type, resolve_forward_ref +try: + from pedantic.decorators.fn_deco_validate.parameters import ( + FlaskFormParameter, + FlaskGetParameter, + FlaskHeaderParameter, + FlaskJsonParameter, + FlaskParameter, + FlaskPathParameter, + GenericFlaskDeserializer, + ) -from pedantic.exceptions import NotImplementedException - -from pedantic.env_var_logic import disable_pedantic, enable_pedantic, is_enabled - -from pedantic.decorators.fn_deco_validate.fn_deco_validate import validate, ReturnAs -from pedantic.decorators.fn_deco_validate.exceptions import * -from pedantic.decorators.fn_deco_validate.parameters import * -from pedantic.decorators.fn_deco_validate.validators import * + __all__ +=[ + 'FlaskFormParameter', + 'FlaskGetParameter', + 'FlaskHeaderParameter', + 'FlaskJsonParameter', + 'FlaskParameter', + 'FlaskPathParameter', + 'GenericFlaskDeserializer', + ] +except ImportError: + pass # no Flask installed diff --git a/pedantic/constants.py b/pedantic/constants.py index d173f855..f873ab6e 100644 --- a/pedantic/constants.py +++ b/pedantic/constants.py @@ -1,9 +1,9 @@ -from typing import TypeVar as Tv, Callable - +from collections.abc import Callable +from typing import TypeVar as Tv TYPE_VAR_METHOD_NAME = '__pedantic_m42__' TYPE_VAR_ATTR_NAME = '__pedantic_a42__' -TYPE_VAR_SELF = Tv('__pedantic_t42__') +TYPE_VAR_SELF = Tv('__pedantic_t42__') # noqa: PLC0132 ATTR_NAME_GENERIC_INSTANCE_ALREADY_CHECKED = '__pedantic_g42__' TypeVar = Tv diff --git a/pedantic/decorators/__init__.py b/pedantic/decorators/__init__.py index e7fdcda0..c24ad66a 100644 --- a/pedantic/decorators/__init__.py +++ b/pedantic/decorators/__init__.py @@ -1,18 +1,30 @@ -from .fn_deco_context_manager import safe_contextmanager, safe_async_contextmanager -from .fn_deco_count_calls import count_calls +from .class_decorators import for_all_methods, pedantic_class, pedantic_class_require_docstring, trace_class +from .cls_deco_frozen_dataclass import frozen_dataclass, frozen_type_safe_dataclass +from .fn_deco_context_manager import safe_async_contextmanager, safe_contextmanager from .fn_deco_deprecated import deprecated -from .fn_deco_does_same_as_function import does_same_as_function -from .fn_deco_in_subprocess import in_subprocess, calculate_in_subprocess -from .fn_deco_mock import mock +from .fn_deco_in_subprocess import calculate_in_subprocess, in_subprocess from .fn_deco_overrides import overrides from .fn_deco_pedantic import pedantic, pedantic_require_docstring -from .fn_deco_rename_kwargs import rename_kwargs, Rename -from .fn_deco_require_kwargs import require_kwargs from .fn_deco_retry import retry, retry_func -from .fn_deco_timer import timer from .fn_deco_trace import trace -from .fn_deco_trace_if_returns import trace_if_returns -from .fn_deco_unimplemented import unimplemented -from .class_decorators import pedantic_class, pedantic_class_require_docstring, timer_class, trace_class, \ - for_all_methods -from .cls_deco_frozen_dataclass import frozen_dataclass, frozen_type_safe_dataclass + +__all__ = [ + 'calculate_in_subprocess', + 'deprecated', + 'deprecated', + 'for_all_methods', + 'frozen_dataclass', + 'frozen_type_safe_dataclass', + 'in_subprocess', + 'overrides', + 'pedantic', + 'pedantic_class', + 'pedantic_class_require_docstring', + 'pedantic_require_docstring', + 'retry', + 'retry_func', + 'safe_async_contextmanager', + 'safe_contextmanager', + 'trace', + 'trace_class', +] diff --git a/pedantic/decorators/class_decorators.py b/pedantic/decorators/class_decorators.py index dca6cd16..0f96440e 100644 --- a/pedantic/decorators/class_decorators.py +++ b/pedantic/decorators/class_decorators.py @@ -1,32 +1,29 @@ import enum import types +from collections.abc import Callable from dataclasses import is_dataclass -from typing import Callable, Optional, Dict, Type -from pedantic.constants import TYPE_VAR_ATTR_NAME, TYPE_VAR_METHOD_NAME, F, C, TYPE_VAR_SELF -from pedantic.decorators import timer, trace +from pedantic.constants import TYPE_VAR_ATTR_NAME, TYPE_VAR_METHOD_NAME, TYPE_VAR_SELF, C, F from pedantic.decorators.fn_deco_pedantic import pedantic, pedantic_require_docstring -from pedantic.env_var_logic import is_enabled +from pedantic.decorators.fn_deco_trace import trace from pedantic.exceptions import PedanticTypeCheckException -from pedantic.type_checking_logic.check_generic_classes import check_instance_of_generic_class_and_get_type_vars, \ - is_instance_of_generic_class +from pedantic.type_checking_logic.check_generic_classes import ( + check_instance_of_generic_class_and_get_type_vars, + is_instance_of_generic_class, +) -def for_all_methods(decorator: F) -> Callable[[Type[C]], Type[C]]: +def for_all_methods(decorator: F) -> Callable[[type[C]], type[C]]: """ - Applies a decorator to all methods of a class. + Applies a decorator to all methods of a class. - Example: - - >>> @for_all_methods(pedantic) - ... class MyClass(object): - ... def m1(self): pass - ... def m2(self, x): pass + Example: + >>> @for_all_methods(pedantic) + ... class MyClass(object): + ... def m1(self): pass + ... def m2(self, x): pass """ def decorate(cls: C) -> C: - if not is_enabled(): - return cls - if issubclass(cls, enum.Enum): raise PedanticTypeCheckException(f'Enum "{cls}" cannot be decorated with "@pedantic_class". ' f'Enums are not supported yet.') @@ -54,35 +51,30 @@ def decorate(cls: C) -> C: def pedantic_class(cls: C) -> C: - """ Shortcut for @for_all_methods(pedantic) """ + """Shortcut for @for_all_methods(pedantic)""" return for_all_methods(decorator=pedantic)(cls=cls) def pedantic_class_require_docstring(cls: C) -> C: - """ Shortcut for @for_all_methods(pedantic_require_docstring) """ + """Shortcut for @for_all_methods(pedantic_require_docstring)""" return for_all_methods(decorator=pedantic_require_docstring)(cls=cls) def trace_class(cls: C) -> C: - """ Shortcut for @for_all_methods(trace) """ + """Shortcut for @for_all_methods(trace)""" return for_all_methods(decorator=trace)(cls=cls) -def timer_class(cls: C) -> C: - """ Shortcut for @for_all_methods(timer) """ - return for_all_methods(decorator=timer)(cls=cls) - - -def _get_wrapped(prop: Optional[F], decorator: F) -> Optional[F]: +def _get_wrapped(prop: F | None, decorator: F) -> F | None: return decorator(prop) if prop is not None else None def _add_type_var_attr_and_method_to_class(cls: C) -> None: - def type_vars(self) -> Dict: + def type_vars(self: C) -> dict: t_vars = {TYPE_VAR_SELF: cls} if is_instance_of_generic_class(instance=self): - type_vars_fifo = getattr(self, TYPE_VAR_ATTR_NAME, dict()) + type_vars_fifo = getattr(self, TYPE_VAR_ATTR_NAME, {}) type_vars_generics = check_instance_of_generic_class_and_get_type_vars(instance=self) setattr(self, TYPE_VAR_ATTR_NAME, {**type_vars_fifo, **type_vars_generics, **t_vars}) else: diff --git a/pedantic/decorators/cls_deco_frozen_dataclass.py b/pedantic/decorators/cls_deco_frozen_dataclass.py index 70e90354..2242715a 100644 --- a/pedantic/decorators/cls_deco_frozen_dataclass.py +++ b/pedantic/decorators/cls_deco_frozen_dataclass.py @@ -1,6 +1,7 @@ +from collections.abc import Callable from copy import deepcopy from dataclasses import dataclass, fields, replace -from typing import Type, TypeVar, Any, Union, Callable, Dict +from typing import Any, TypeVar from pedantic.get_context import get_context from pedantic.type_checking_logic.check_types import assert_value_matches_type @@ -8,78 +9,77 @@ T = TypeVar('T') -def frozen_type_safe_dataclass(cls: Type[T]) -> Type[T]: - """ Shortcut for @frozen_dataclass(type_safe=True) """ +def frozen_type_safe_dataclass(cls: type[T]) -> type[T]: + """Shortcut for @frozen_dataclass(type_safe=True)""" return frozen_dataclass(type_safe=True)(cls) -def frozen_dataclass( - cls: Type[T] = None, - type_safe: bool = False, - order: bool = False, - kw_only: bool = True, - slots: bool = False, -) -> Union[Type[T], Callable[[Type[T]], Type[T]]]: +def frozen_dataclass( # noqa: C901 + cls: type[T] | None = None, + type_safe: bool = False, + order: bool = False, + kw_only: bool = True, + slots: bool = False, +) -> type[T] | Callable[[type[T]], type[T]]: """ - Makes the decorated class immutable and a dataclass by adding the [@dataclass(frozen=True)] - decorator. Also adds useful copy_with() and validate_types() instance methods to this class (see below). - - If [type_safe] is True, a type check is performed for each field after the __post_init__ method was called - which itself s directly called after the __init__ constructor. - Note this have a negative impact on the performance. It's recommend to use this for debugging and testing only. - - In a nutshell, the followings methods will be added to the decorated class automatically: - - __init__() gives you a simple constructor like "Foo(a=6, b='hi', c=True)" - - __eq__() lets you compare objects easily with "a == b" - - __hash__() is also needed for instance comparison - - __repr__() gives you a nice output when you call "print(foo)" - - copy_with() allows you to quickly create new similar frozen instances. Use this instead of setters. - - deep_copy_with() allows you to create deep copies and modify them. - - validate_types() allows you to validate the types of the dataclass. - This is called automatically when [type_safe] is True. - - If the [order] parameter is True (default is False), the following comparison methods - will be added additionally: - - __lt__() lets you compare instance like "a < b" - - __le__() lets you compare instance like "a <= b" - - __gt__() lets you compare instance like "a > b" - - __ge__() lets you compare instance like "a >= b" - - These compare the class as if it were a tuple of its fields, in order. - Both instances in the comparison must be of the identical type. - - The parameters slots and kw_only are only applied if the Python version is greater or equal to 3.10. - - Example: - - >>> @frozen_dataclass - ... class Foo: - ... a: int - ... b: str - ... c: bool - >>> foo = Foo(a=6, b='hi', c=True) - >>> print(foo) - Foo(a=6, b='hi', c=True) - >>> print(foo.copy_with()) - Foo(a=6, b='hi', c=True) - >>> print(foo.copy_with(a=42)) - Foo(a=42, b='hi', c=True) - >>> print(foo.copy_with(b='Hello')) - Foo(a=6, b='Hello', c=True) - >>> print(foo.copy_with(c=False)) - Foo(a=6, b='hi', c=False) - >>> print(foo.copy_with(a=676676, b='new', c=False)) - Foo(a=676676, b='new', c=False) + Makes the decorated class immutable and a dataclass by adding the [@dataclass(frozen=True)] + decorator. Also adds useful copy_with() and validate_types() instance methods to this class (see below). + + If [type_safe] is True, a type check is performed for each field after the __post_init__ method was called + which itself s directly called after the __init__ constructor. + Note this have a negative impact on the performance. It's recommend to use this for debugging and testing only. + + In a nutshell, the followings methods will be added to the decorated class automatically: + - __init__() gives you a simple constructor like "Foo(a=6, b='hi', c=True)" + - __eq__() lets you compare objects easily with "a == b" + - __hash__() is also needed for instance comparison + - __repr__() gives you a nice output when you call "print(foo)" + - copy_with() allows you to quickly create new similar frozen instances. Use this instead of setters. + - deep_copy_with() allows you to create deep copies and modify them. + - validate_types() allows you to validate the types of the dataclass. + This is called automatically when [type_safe] is True. + + If the [order] parameter is True (default is False), the following comparison methods + will be added additionally: + - __lt__() lets you compare instance like "a < b" + - __le__() lets you compare instance like "a <= b" + - __gt__() lets you compare instance like "a > b" + - __ge__() lets you compare instance like "a >= b" + + These compare the class as if it were a tuple of its fields, in order. + Both instances in the comparison must be of the identical type. + + The parameters slots and kw_only are only applied if the Python version is greater or equal to 3.10. + + Example: + >>> @frozen_dataclass + ... class Foo: + ... a: int + ... b: str + ... c: bool + >>> foo = Foo(a=6, b='hi', c=True) + >>> print(foo) + Foo(a=6, b='hi', c=True) + >>> print(foo.copy_with()) + Foo(a=6, b='hi', c=True) + >>> print(foo.copy_with(a=42)) + Foo(a=42, b='hi', c=True) + >>> print(foo.copy_with(b='Hello')) + Foo(a=6, b='Hello', c=True) + >>> print(foo.copy_with(c=False)) + Foo(a=6, b='hi', c=False) + >>> print(foo.copy_with(a=676676, b='new', c=False)) + Foo(a=676676, b='new', c=False) """ - def decorator(cls_: Type[T]) -> Type[T]: + def decorator(cls_: type[T]) -> type[T]: args = {'frozen': True, 'order': order, 'kw_only': kw_only, 'slots': slots} if type_safe: old_post_init = getattr(cls_, '__post_init__', lambda _: None) - def new_post_init(self) -> None: + def new_post_init(self: T) -> None: old_post_init(self) context = get_context(depth=3, increase_depth_if_name_matches=[ copy_with.__name__, @@ -87,31 +87,31 @@ def new_post_init(self) -> None: ]) self.validate_types(_context=context) - setattr(cls_, '__post_init__', new_post_init) # must be done before applying dataclass() + cls_.__post_init__ = new_post_init # must be done before applying dataclass() new_class = dataclass(**args)(cls_) # slots = True will create a new class! - def copy_with(self, **kwargs: Any) -> T: + def copy_with(self: T, **kwargs: Any) -> T: """ - Creates a new immutable instance that by copying all fields of this instance replaced by the new values. - Keep in mind that this is a shallow copy! + Creates a new immutable instance that by copying all fields of this instance replaced by the new values. + Keep in mind that this is a shallow copy! """ return replace(self, **kwargs) - def deep_copy_with(self, **kwargs: Any) -> T: + def deep_copy_with(self: T, **kwargs: Any) -> T: """ - Creates a new immutable instance that by deep copying all fields of - this instance replaced by the new values. + Creates a new immutable instance that by deep copying all fields of + this instance replaced by the new values. """ current_values = {field.name: deepcopy(getattr(self, field.name)) for field in fields(self)} return new_class(**{**current_values, **kwargs}) - def validate_types(self, *, _context: Dict[str, Type] = None) -> None: + def validate_types(self: T, *, _context: dict[str, type] | None = None) -> None: """ - Checks that all instance variable have the correct type. - Raises a [PedanticTypeCheckException] if at least one type is incorrect. + Checks that all instance variable have the correct type. + Raises a [PedanticTypeCheckException] if at least one type is incorrect. """ props = fields(new_class) diff --git a/pedantic/decorators/fn_deco_context_manager.py b/pedantic/decorators/fn_deco_context_manager.py index 5dca285d..e8502b36 100644 --- a/pedantic/decorators/fn_deco_context_manager.py +++ b/pedantic/decorators/fn_deco_context_manager.py @@ -1,12 +1,13 @@ -from contextlib import contextmanager, asynccontextmanager +from collections.abc import AsyncIterator, Callable, Iterator +from contextlib import AbstractAsyncContextManager, AbstractContextManager, asynccontextmanager, contextmanager from functools import wraps from inspect import isasyncgenfunction, isgeneratorfunction -from typing import Callable, TypeVar, Iterator, ContextManager, AsyncContextManager, AsyncIterator +from typing import Any, TypeVar T = TypeVar('T') -def safe_contextmanager(f: Callable[..., Iterator[T]]) -> Callable[..., ContextManager[T]]: +def safe_contextmanager(f: Callable[..., Iterator[T]]) -> Callable[..., AbstractContextManager[T]]: """ @safe_contextmanager decorator. @@ -49,21 +50,21 @@ def some_generator(): raise AssertionError(f'{f.__name__} is not a generator.') @wraps(f) - def wrapper(*args, **kwargs) -> Iterator[T]: + def wrapper(*args: Any, **kwargs: Any) -> Iterator[T]: iterator = f(*args, **kwargs) try: yield next(iterator) finally: - try: + try: # noqa: SIM105 next(iterator) except StopIteration: pass # this is intended - return contextmanager(wrapper) # type: ignore + return contextmanager(wrapper) -def safe_async_contextmanager(f: Callable[..., AsyncIterator[T]]) -> Callable[..., AsyncContextManager[T]]: +def safe_async_contextmanager(f: Callable[..., AsyncIterator[T]]) -> Callable[..., AbstractAsyncContextManager[T]]: """ @safe_async_contextmanager decorator. @@ -100,7 +101,7 @@ async def some_async_generator(): finally: - """ + """ if not isasyncgenfunction(f): if not isgeneratorfunction(f): @@ -110,15 +111,15 @@ async def some_async_generator(): f'So you need to use "safe_contextmanager" instead.') @wraps(f) - async def wrapper(*args, **kwargs) -> Iterator[T]: + async def wrapper(*args: Any, **kwargs: Any) -> Iterator[T]: iterator = f(*args, **kwargs) try: yield await anext(iterator) finally: - try: + try: # noqa: SIM105 await anext(iterator) except StopAsyncIteration: - pass # this is intended + pass - return asynccontextmanager(wrapper) # type: ignore + return asynccontextmanager(wrapper) diff --git a/pedantic/decorators/fn_deco_count_calls.py b/pedantic/decorators/fn_deco_count_calls.py deleted file mode 100644 index 3fc1ebd0..00000000 --- a/pedantic/decorators/fn_deco_count_calls.py +++ /dev/null @@ -1,32 +0,0 @@ -from datetime import datetime -from functools import wraps -from typing import Any - -from pedantic.constants import F, ReturnType - - -def count_calls(func: F) -> F: - """ - Prints how often the method is called during program execution. - - Example: - - >>> @count_calls - ... def often_used_method(): - ... return 42 - >>> often_used_method() - Count Calls: Call 1 of function 'often_used_method' at ... - >>> often_used_method() - Count Calls: Call 2 of function 'often_used_method' at ... - >>> often_used_method() - Count Calls: Call 3 of function 'often_used_method' at ... - """ - - @wraps(func) - def wrapper(*args: Any, **kwargs: Any) -> ReturnType: - wrapper.num_calls += 1 - print(f"Count Calls: Call {wrapper.num_calls} of function {func.__name__!r} at {datetime.now()}.") - return func(*args, **kwargs) - - wrapper.num_calls = 0 - return wrapper diff --git a/pedantic/decorators/fn_deco_deprecated.py b/pedantic/decorators/fn_deco_deprecated.py index 62772466..fa23a601 100644 --- a/pedantic/decorators/fn_deco_deprecated.py +++ b/pedantic/decorators/fn_deco_deprecated.py @@ -1,9 +1,11 @@ import warnings +from collections.abc import Callable from functools import wraps -from typing import Any, Callable, overload +from typing import Any, overload from pedantic.constants import F, ReturnType + @overload def deprecated(func: F) -> F: ... @@ -12,18 +14,20 @@ def deprecated(*, message: str = '') -> Callable[[F], F]: ... def deprecated(func: F | None = None, message: str = '') -> F | Callable[[F], F]: """ - Use this decorator to mark a function as deprecated. It will raise a warning when the function is called. - You can specify an optional reason or message to display with the warning. - - Example: - >>> @deprecated - ... def my_function(a, b, c): - ... pass - >>> my_function(5, 4, 3) # doctest: +SKIP - >>> @deprecated(message='Will be removed soon. Please use my_function_new_instead.') - ... def my_function(a, b, c): - ... pass - >>> my_function(5, 4, 3) # doctest: +SKIP + Use this decorator to mark a function as deprecated. It will raise a warning when the function is called. + You can specify an optional reason or message to display with the warning. + + If you use Python 3.13 or newer, consider using warnings.deprecated instead from the standard library. + + Example: + >>> @deprecated + ... def my_function(a, b, c): + ... pass + >>> my_function(5, 4, 3) # doctest: +SKIP + >>> @deprecated(message='Will be removed soon. Please use my_function_new_instead.') + ... def my_function(a, b, c): + ... pass + >>> my_function(5, 4, 3) # doctest: +SKIP """ def decorator(fun: F) -> F: diff --git a/pedantic/decorators/fn_deco_does_same_as_function.py b/pedantic/decorators/fn_deco_does_same_as_function.py deleted file mode 100644 index 0ce47eaa..00000000 --- a/pedantic/decorators/fn_deco_does_same_as_function.py +++ /dev/null @@ -1,54 +0,0 @@ -import inspect -from functools import wraps -from typing import Any - -from pedantic.constants import F, ReturnType - - -def does_same_as_function(other_func: F) -> F: - """ - Each time the decorated function is executed, the function other_func is also executed and the results - are compared. An AssertionError is raised if the results are not equal. - - Example: - - >>> def other_calculation(a, b, c): - ... return c + b + a - >>> @does_same_as_function(other_calculation) - ... def some_calculation(a, b, c): - ... return a + b + c - >>> some_calculation(1, 2, 3) - 6 - """ - - def decorator(decorated_func: F) -> F: - @wraps(decorated_func) - def wrapper(*args: Any, **kwargs: Any) -> ReturnType: - result = decorated_func(*args, **kwargs) - other = other_func(*args, **kwargs) - - if other != result: - raise AssertionError(f'Different outputs: Function "{decorated_func.__name__}" returns {result} and ' - f'function "{other_func.__name__}" returns {other} for parameters {args} {kwargs}') - return result - - @wraps(decorated_func) - async def async_wrapper(*args: Any, **kwargs: Any) -> ReturnType: - result = await decorated_func(*args, **kwargs) - - if inspect.iscoroutinefunction(other_func): - other = await other_func(*args, **kwargs) - else: - other = other_func(*args, **kwargs) - - if other != result: - raise AssertionError(f'Different outputs: Function "{decorated_func.__name__}" returns {result} and ' - f'function "{other_func.__name__}" returns {other} for parameters {args} {kwargs}') - return result - - if inspect.iscoroutinefunction(decorated_func): - return async_wrapper - else: - return wrapper - - return decorator diff --git a/pedantic/decorators/fn_deco_in_subprocess.py b/pedantic/decorators/fn_deco_in_subprocess.py index b308acb0..d3f86f1b 100644 --- a/pedantic/decorators/fn_deco_in_subprocess.py +++ b/pedantic/decorators/fn_deco_in_subprocess.py @@ -1,44 +1,45 @@ import asyncio import inspect +from collections.abc import Awaitable, Callable from functools import wraps -from typing import Callable, TypeVar, Any, Awaitable, Optional, Type, Union +from typing import Any, TypeVar try: - from multiprocess import Process, Pipe + from multiprocess import Pipe, Process from multiprocess.connection import Connection except ImportError: - Process: Optional[Type] = None - Pipe: Optional[Type] = None - Connection: Optional[Type] = None + Process: type | None = None + Pipe: type | None = None + Connection: type | None = None T = TypeVar('T') class SubprocessError: - """ Is returned by the subprocess if an error occurs in the subprocess. """ + """Is returned by the subprocess if an error occurs in the subprocess.""" - def __init__(self, ex: Exception) -> None: + def __init__(self, ex: Exception) -> None: # noqa: D107 self.exception = ex -def in_subprocess(func: Callable[..., Union[T, Awaitable[T]]]) -> Callable[..., Awaitable[T]]: +def in_subprocess(func: Callable[..., T | Awaitable[T]]) -> Callable[..., Awaitable[T]]: """ - Executes the decorated function in a subprocess and returns the return value of it. - Note that the decorated function will be replaced with an async function which returns - a coroutine that needs to be awaited. - This purpose of this is doing long-taking calculations without blocking the main thread - of your application synchronously. That ensures that other asyncio.Tasks can work without any problem - at the same time. - - Example: - >>> import time - >>> import asyncio - >>> @in_subprocess - ... def f(value: int) -> int: - ... time.sleep(0.1) # a long taking synchronous blocking calculation - ... return 2 * value - >>> asyncio.run(f(value=42)) - 84 + Executes the decorated function in a subprocess and returns the return value of it. + Note that the decorated function will be replaced with an async function which returns + a coroutine that needs to be awaited. + This purpose of this is doing long-taking calculations without blocking the main thread + of your application synchronously. That ensures that other asyncio.Tasks can work without any problem + at the same time. + + Example: + >>> import time + >>> import asyncio + >>> @in_subprocess + ... def f(value: int) -> int: + ... time.sleep(0.1) # a long taking synchronous blocking calculation + ... return 2 * value + >>> asyncio.run(f(value=42)) + 84 """ @wraps(func) @@ -48,31 +49,31 @@ async def wrapper(*args: Any, **kwargs: Any) -> T: return wrapper -async def calculate_in_subprocess(func: Callable[..., Union[T, Awaitable[T]]], *args: Any, **kwargs: Any) -> T: +async def calculate_in_subprocess(func: Callable[..., T | Awaitable[T]], *args: Any, **kwargs: Any) -> T: """ - Calculates the result of a synchronous function in subprocess without blocking the current thread. + Calculates the result of a synchronous function in subprocess without blocking the current thread. - Arguments: - func: The function that will be called in a subprocess. - args: Positional arguments that will be passed to the function. - kwargs: Keyword arguments that will be passed to the function. + Arguments: + func: The function that will be called in a subprocess. + args: Positional arguments that will be passed to the function. + kwargs: Keyword arguments that will be passed to the function. - Returns: - The calculated result of the function "func". + Returns: + The calculated result of the function "func". - Raises: - Any Exception that is raised inside [func]. + Raises: + Any Exception that is raised inside [func]. - Further reading: https://medium.com/devopss-hole/python-multiprocessing-pickle-issue-e2d35ccf96a9 + Further reading: https://medium.com/devopss-hole/python-multiprocessing-pickle-issue-e2d35ccf96a9 - Example: - >>> import time - >>> import asyncio - >>> def f(value: int) -> int: - ... time.sleep(0.1) # a long taking synchronous blocking calculation - ... return 2 * value - >>> asyncio.run(calculate_in_subprocess(func=f, value=42)) - 84 + Example: + >>> import time + >>> import asyncio + >>> def f(value: int) -> int: + ... time.sleep(0.1) # a long taking synchronous blocking calculation + ... return 2 * value + >>> asyncio.run(calculate_in_subprocess(func=f, value=42)) + 84 """ if Pipe is None: @@ -103,8 +104,8 @@ async def calculate_in_subprocess(func: Callable[..., Union[T, Awaitable[T]]], * return result -def _inner(tx: Connection, fun: Callable[..., Union[T, Awaitable[T]]], *a, **kw_args) -> None: - """ This runs in another process. """ +def _inner(tx: Connection, fun: Callable[..., T | Awaitable[T]], *a: Any, **kw_args: Any) -> None: + """This runs in another process.""" event_loop = None if inspect.iscoroutinefunction(fun): @@ -116,7 +117,7 @@ def _inner(tx: Connection, fun: Callable[..., Union[T, Awaitable[T]]], *a, **kw_ res = event_loop.run_until_complete(fun(*a, **kw_args)) else: res = fun(*a, **kw_args) - except Exception as ex: + except Exception as ex: # noqa: BLE001 tx.send(SubprocessError(ex=ex)) else: tx.send(res) diff --git a/pedantic/decorators/fn_deco_mock.py b/pedantic/decorators/fn_deco_mock.py deleted file mode 100644 index 75639183..00000000 --- a/pedantic/decorators/fn_deco_mock.py +++ /dev/null @@ -1,38 +0,0 @@ -import inspect -from functools import wraps -from typing import Any - -from pedantic.constants import ReturnType, F - - -def mock(return_value: ReturnType) -> F: - """ - Skip the execution of the function and simply return the given return value instead. - This can be useful you want to check quickly if the behavior of the function causes a specific problem. - Without this decorator you actually need to change the implementation of the function temporarily. - - Example: - - >>> @mock(return_value=42) - ... def my_function(a, b, c): - ... return a + b + c - >>> my_function(1, 2, 3) - 42 - >>> my_function(1000, 88, 204) - 42 - """ - - def decorator(func: F) -> F: - @wraps(func) - def wrapper(*args: Any, **kwargs: Any) -> ReturnType: - return return_value - - @wraps(func) - async def async_wrapper(*args: Any, **kwargs: Any) -> ReturnType: - return return_value - - if inspect.iscoroutinefunction(func): - return async_wrapper - else: - return wrapper - return decorator diff --git a/pedantic/decorators/fn_deco_overrides.py b/pedantic/decorators/fn_deco_overrides.py index cdfa850f..6ee5ba73 100644 --- a/pedantic/decorators/fn_deco_overrides.py +++ b/pedantic/decorators/fn_deco_overrides.py @@ -1,23 +1,21 @@ -from typing import Type from pedantic.constants import F from pedantic.exceptions import PedanticOverrideException -def overrides(base_class: Type) -> F: +def overrides(base_class: type) -> F: """ - This is used for marking methods that overrides methods of the base class which makes the code more readable. - This decorator raises an Exception if the decorated method is not a method in the parent class. + This is used for marking methods that overrides methods of the base class which makes the code more readable. + This decorator raises an Exception if the decorated method is not a method in the parent class. - Example: - - >>> class Parent: - ... def my_instance_method(self): - ... pass - >>> class Child(Parent): - ... @overrides(Parent) - ... def my_instance_method(self): - ... print('hello world') + Example: + >>> class Parent: + ... def my_instance_method(self): + ... pass + >>> class Child(Parent): + ... @overrides(Parent) + ... def my_instance_method(self): + ... print('hello world') """ def decorator(func: F) -> F: diff --git a/pedantic/decorators/fn_deco_pedantic.py b/pedantic/decorators/fn_deco_pedantic.py index 1ea79359..a53cc07f 100644 --- a/pedantic/decorators/fn_deco_pedantic.py +++ b/pedantic/decorators/fn_deco_pedantic.py @@ -1,55 +1,50 @@ from functools import wraps -from typing import Any, Optional +from typing import Any +from pedantic.constants import F, ReturnType from pedantic.get_context import get_context -from pedantic.type_checking_logic.check_docstring import _check_docstring -from pedantic.constants import ReturnType, F from pedantic.models.decorated_function import DecoratedFunction from pedantic.models.function_call import FunctionCall -from pedantic.env_var_logic import is_enabled +from pedantic.type_checking_logic.check_docstring import _check_docstring -def pedantic(func: Optional[F] = None, require_docstring: bool = False) -> F: +def pedantic(func: F | None = None, require_docstring: bool = False) -> F: """ - A PedanticException is raised if one of the following happened: - - The decorated function is called with positional arguments. - - The function has no type annotation for their return type or one or more parameters do not have type - annotations. - - A type annotation is incorrect. - - A type annotation misses type arguments, e.g. typing.List instead of typing.List[int]. - - The documented arguments do not match the argument list or their type annotations. - - Example: + A PedanticException is raised if one of the following happened: + - The decorated function is called with positional arguments. + - The function has no type annotation for their return type or one or more parameters do not have type + annotations. + - A type annotation is incorrect. + - A type annotation misses type arguments, e.g. typing.List instead of typing.List[int]. + - The documented arguments do not match the argument list or their type annotations. - >>> @pedantic - ... def my_function(a: int, b: float, c: str) -> bool: - ... return float(a) == b and str(b) == c - >>> my_function(a=42.0, b=14.0, c='hi') - Traceback (most recent call last): - ... - pedantic.exceptions.PedanticTypeCheckException: In function my_function: - Type hint is incorrect: Argument a=42.0 of type does not match expected type . - >>> my_function(a=42, b=None, c='hi') - Traceback (most recent call last): - ... - pedantic.exceptions.PedanticTypeCheckException: In function my_function: - Type hint is incorrect: Argument b=None of type does not match expected type . - >>> my_function(a=42, b=42, c='hi') - Traceback (most recent call last): - ... - pedantic.exceptions.PedanticTypeCheckException: In function my_function: - Type hint is incorrect: Argument b=42 of type does not match expected type . - >>> my_function(5, 4.0, 'hi') - Traceback (most recent call last): - ... - pedantic.exceptions.PedanticCallWithArgsException: In function my_function: - Use kwargs when you call function my_function. Args: (5, 4.0, 'hi') - """ + Example: + >>> @pedantic + ... def my_function(a: int, b: float, c: str) -> bool: + ... return float(a) == b and str(b) == c + >>> my_function(a=42.0, b=14.0, c='hi') + Traceback (most recent call last): + ... + pedantic.exceptions.PedanticTypeCheckException: In function my_function: + Type hint is incorrect: Argument a=42.0 of type does not match expected type . + >>> my_function(a=42, b=None, c='hi') + Traceback (most recent call last): + ... + pedantic.exceptions.PedanticTypeCheckException: In function my_function: + Type hint is incorrect: Argument b=None of type does not match expected type . + >>> my_function(a=42, b=42, c='hi') + Traceback (most recent call last): + ... + pedantic.exceptions.PedanticTypeCheckException: In function my_function: + Type hint is incorrect: Argument b=42 of type does not match expected type . + >>> my_function(5, 4.0, 'hi') + Traceback (most recent call last): + ... + pedantic.exceptions.PedanticCallWithArgsException: In function my_function: + Use kwargs when you call function my_function. Args: (5, 4.0, 'hi') + """ def decorator(f: F) -> F: - if not is_enabled(): - return f - decorated_func = DecoratedFunction(func=f) if decorated_func.docstring is not None and (require_docstring or len(decorated_func.docstring.params)) > 0: @@ -68,12 +63,11 @@ async def async_wrapper(*args: Any, **kwargs: Any) -> ReturnType: if decorated_func.is_coroutine: return async_wrapper - else: - return wrapper + return wrapper return decorator if func is None else decorator(f=func) -def pedantic_require_docstring(func: Optional[F] = None) -> F: - """Shortcut for @pedantic(require_docstring=True) """ +def pedantic_require_docstring(func: F | None = None) -> F: + """Shortcut for @pedantic(require_docstring=True)""" return pedantic(func=func, require_docstring=True) diff --git a/pedantic/decorators/fn_deco_rename_kwargs.py b/pedantic/decorators/fn_deco_rename_kwargs.py deleted file mode 100644 index b529a22c..00000000 --- a/pedantic/decorators/fn_deco_rename_kwargs.py +++ /dev/null @@ -1,47 +0,0 @@ -from functools import wraps -from typing import Callable - -from pedantic.constants import F, ReturnType - - -class Rename: - def __init__(self, from_: str, to: str) -> None: - self.from_ = from_ - self.to = to - - -def rename_kwargs(*params: Rename) -> Callable[[F], F]: - """ - Renames the keyword arguments based on the given "Rename" rules when the decorated function is called. - You can also use this to define aliases for keyword arguments. - - Example: - - >>> @rename_kwargs( - ... Rename(from_='firstname', to='a'), - ... Rename(from_='lastname', to='b'), - ... ) - ... def my_function(a, b): - ... return a + ' ' + b - >>> my_function(a='egon', b='olsen') # the normal way - 'egon olsen' - >>> my_function(firstname='egon', lastname='olsen') # using new defined keyword arguments - 'egon olsen' - """ - - param_dict = {p.from_: p.to for p in params} - - def decorator(func: F) -> F: - @wraps(func) - def wrapper(*args, **kwargs) -> ReturnType: - result_kwargs = {} - - for k, v in kwargs.items(): - if k in param_dict: - result_kwargs[param_dict[k]] = kwargs[k] - else: - result_kwargs[k] = kwargs[k] - - return func(*args, **result_kwargs) - return wrapper - return decorator diff --git a/pedantic/decorators/fn_deco_require_kwargs.py b/pedantic/decorators/fn_deco_require_kwargs.py deleted file mode 100644 index f763b31c..00000000 --- a/pedantic/decorators/fn_deco_require_kwargs.py +++ /dev/null @@ -1,33 +0,0 @@ -from functools import wraps -from typing import Any - -from pedantic.constants import F, ReturnType -from pedantic.models.decorated_function import DecoratedFunction -from pedantic.models.function_call import FunctionCall - - -def require_kwargs(func: F) -> F: - """ - Checks that each passed argument is a keyword argument. - - Example: - - >>> @require_kwargs - ... def my_function(a, b, c): - ... return a + b + c - >>> my_function(5, 4, 3) - Traceback (most recent call last): - ... - pedantic.exceptions.PedanticCallWithArgsException: In function my_function: - Use kwargs when you call function my_function. Args: (5, 4, 3) - >>> my_function(a=5, b=4, c=3) - 12 - """ - - @wraps(func) - def wrapper(*args: Any, **kwargs: Any) -> ReturnType: - decorated_func = DecoratedFunction(func=func) - call = FunctionCall(func=decorated_func, args=args, kwargs=kwargs, context={}) - call.assert_uses_kwargs() - return func(*args, **kwargs) - return wrapper diff --git a/pedantic/decorators/fn_deco_retry.py b/pedantic/decorators/fn_deco_retry.py index 10fdb75b..95deecac 100644 --- a/pedantic/decorators/fn_deco_retry.py +++ b/pedantic/decorators/fn_deco_retry.py @@ -1,9 +1,10 @@ import logging import time +from collections.abc import Callable from datetime import timedelta from functools import wraps from logging import Logger -from typing import Callable, TypeVar, Any, ParamSpec +from typing import Any, ParamSpec, TypeVar C = TypeVar('C', bound=Callable) P = ParamSpec('P') @@ -15,13 +16,13 @@ def retry( attempts: int, exceptions: type[Exception] | tuple[type[Exception], ...] = Exception, sleep_time: timedelta = timedelta(seconds=0), - logger: Logger = None, + logger: Logger | None = None, ) -> Callable[[C], C]: """ Retries the wrapped function/method `attempts` times if the exceptions listed in [exceptions] are thrown. - Parameters: + Args: attempts: The number of times to repeat the wrapped function/method exceptions: Lists of exceptions that trigger a retry attempt. sleep_time: The time to wait between the retry attempts. @@ -36,7 +37,7 @@ def retry( def decorator(func: C) -> C: @wraps(func) - def wrapper(*args, **kwargs) -> Any: + def wrapper(*args: P.args, **kwargs: P.kwargs) -> Any: return retry_func( func, *args, @@ -56,9 +57,37 @@ def retry_func( attempts: int, exceptions: type[Exception] | tuple[type[Exception], ...] = Exception, sleep_time: timedelta = timedelta(seconds=0), - logger: Logger = None, + logger: Logger | None = None, **kwargs: P.kwargs, ) -> R: + """ + Execute a function with retry logic. + + The function ``func`` is executed and retried up to ``attempts`` times if one of the + specified exceptions is raised. Between retries, the function waits for the + duration defined by ``sleep_time``. A warning is logged for each failed attempt + except for the final one. + + Args: + func: The callable to execute. + *args: Positional arguments forwarded to ``func``. + attempts: Total number of attempts before the exception is allowed to + propagate. + exceptions: Exception type or tuple of exception types that should trigger + a retry. Defaults to ``Exception``. + sleep_time: Time to wait between retry attempts. Defaults to zero seconds. + logger: Logger used to emit warnings when a retry occurs. If ``None``, + the root logger is used. + **kwargs: Keyword arguments forwarded to ``func``. + + Returns: + The return value of ``func``. + + Raises: + Exception: Re-raises the last encountered exception if all retry attempts + fail. + """ + attempt = 1 if logger is None: @@ -68,7 +97,7 @@ def retry_func( try: return func(*args, **kwargs) except exceptions: - logger.warning(f'Exception thrown when attempting to run {func.__name__}, ' + logger.warning(f'Exception thrown when attempting to run {func.__name__}, ' # noqa: G004 f'attempt {attempt} of {attempts}') attempt += 1 time.sleep(sleep_time.total_seconds()) diff --git a/pedantic/decorators/fn_deco_timer.py b/pedantic/decorators/fn_deco_timer.py deleted file mode 100644 index 843fc477..00000000 --- a/pedantic/decorators/fn_deco_timer.py +++ /dev/null @@ -1,44 +0,0 @@ -import inspect -from datetime import datetime -from functools import wraps -from typing import Any - -from pedantic.constants import F, ReturnType - - -def timer(func: F) -> F: - """ - Prints how long the execution of the decorated function takes. - - Example: - - >>> @timer - ... def long_taking_calculation(): - ... return 42 - >>> long_taking_calculation() - Timer: Finished function "long_taking_calculation" in 0:00:00... - 42 - """ - - @wraps(func) - def wrapper(*args: Any, **kwargs: Any) -> ReturnType: - start_time: datetime = datetime.now() - value = func(*args, **kwargs) - end_time = datetime.now() - run_time = end_time - start_time - print(f'Timer: Finished function "{func.__name__}" in {run_time}.') - return value - - @wraps(func) - async def async_wrapper(*args: Any, **kwargs: Any) -> ReturnType: - start_time: datetime = datetime.now() - value = await func(*args, **kwargs) - end_time = datetime.now() - run_time = end_time - start_time - print(f'Timer: Finished function "{func.__name__}" in {run_time}.') - return value - - if inspect.iscoroutinefunction(func): - return async_wrapper - else: - return wrapper diff --git a/pedantic/decorators/fn_deco_trace.py b/pedantic/decorators/fn_deco_trace.py index aab72668..24d62a70 100644 --- a/pedantic/decorators/fn_deco_trace.py +++ b/pedantic/decorators/fn_deco_trace.py @@ -1,41 +1,44 @@ import inspect -from datetime import datetime +import logging +from datetime import UTC, datetime from functools import wraps from typing import Any from pedantic.constants import F, ReturnType +logger = logging.getLogger(__name__) +# ruff: noqa: G004 def trace(func: F) -> F: """ - Prints the passed arguments and the returned value on each function call. - - Example: - - >>> @trace - ... def my_function(a, b, c): - ... return a + b + c - >>> my_function(4, 5, 6) - Trace: ... calling my_function() with (4, 5, 6), {} - Trace: ... my_function() returned 15 - 15 + Prints the passed arguments and the returned value on each function call. + + Example: + >>> @trace + ... def my_function(a, b, c): + ... return a + b + c + >>> my_function(4, 5, 6) + 15 """ @wraps(func) def wrapper(*args: Any, **kwargs: Any) -> ReturnType: - print(f'Trace: {datetime.now()} calling {func.__name__}() with {args}, {kwargs}') + logger.info(f'Trace: {_get_now()} calling {func.__name__}() with {args}, {kwargs}') original_result = func(*args, **kwargs) - print(f'Trace: {datetime.now()} {func.__name__}() returned {original_result!r}') + logger.info(f'Trace: {_get_now()} {func.__name__}() returned {original_result!r}') return original_result @wraps(func) async def async_wrapper(*args: Any, **kwargs: Any) -> ReturnType: - print(f'Trace: {datetime.now()} calling {func.__name__}() with {args}, {kwargs}') + logger.info(f'Trace: {_get_now()} calling {func.__name__}() with {args}, {kwargs}') original_result = await func(*args, **kwargs) - print(f'Trace: {datetime.now()} {func.__name__}() returned {original_result!r}') + logger.info(f'Trace: {_get_now()} {func.__name__}() returned {original_result!r}') return original_result if inspect.iscoroutinefunction(func): return async_wrapper - else: - return wrapper + return wrapper + + +def _get_now() -> datetime: + return datetime.now(tz=UTC) diff --git a/pedantic/decorators/fn_deco_trace_if_returns.py b/pedantic/decorators/fn_deco_trace_if_returns.py deleted file mode 100644 index 5ef3a693..00000000 --- a/pedantic/decorators/fn_deco_trace_if_returns.py +++ /dev/null @@ -1,48 +0,0 @@ -import inspect -from functools import wraps -from typing import Any - -from pedantic.constants import ReturnType, F - - -def trace_if_returns(return_value: ReturnType) -> F: - """ - Prints the passed arguments if and only if the decorated function returned the given return_value. - This is useful if you want to figure out which input arguments leads to a special return value. - - Example: - - >>> @trace_if_returns(42) - ... def my_function(a, b, c): - ... return a + b + c - >>> my_function(1, 2, 3) - 6 - >>> my_function(10, 8, 24) - Function my_function returned value 42 for args: (10, 8, 24) and kwargs: {} - 42 - """ - - def decorator(func: F) -> F: - @wraps(func) - def wrapper(*args: Any, **kwargs: Any) -> ReturnType: - result = func(*args, **kwargs) - - if result == return_value: - print(f'Function {func.__name__} returned value {result} for args: {args} and kwargs: {kwargs}') - - return result - - @wraps(func) - async def async_wrapper(*args: Any, **kwargs: Any) -> ReturnType: - result = await func(*args, **kwargs) - - if result == return_value: - print(f'Function {func.__name__} returned value {result} for args: {args} and kwargs: {kwargs}') - - return result - - if inspect.iscoroutinefunction(func): - return async_wrapper - else: - return wrapper - return decorator diff --git a/pedantic/decorators/fn_deco_unimplemented.py b/pedantic/decorators/fn_deco_unimplemented.py deleted file mode 100644 index e84e513d..00000000 --- a/pedantic/decorators/fn_deco_unimplemented.py +++ /dev/null @@ -1,26 +0,0 @@ -from functools import wraps -from typing import Any - -from pedantic.exceptions import NotImplementedException -from pedantic.constants import F, ReturnType - - -def unimplemented(func: F) -> F: - """ - For documentation purposes. Throw NotImplementedException if the function is called. - - Example: - - >>> @unimplemented - ... def my_function(a, b, c): - ... pass - >>> my_function(5, 4, 3) - Traceback (most recent call last): - ... - pedantic.exceptions.NotImplementedException: Function "my_function" is not implemented yet! - """ - - @wraps(func) - def wrapper(*args: Any, **kwargs: Any) -> ReturnType: - raise NotImplementedException(f'Function "{func.__qualname__}" is not implemented yet!') - return wrapper diff --git a/pedantic/decorators/fn_deco_validate/convert_value.py b/pedantic/decorators/fn_deco_validate/convert_value.py index 29e0be22..dfd710bf 100644 --- a/pedantic/decorators/fn_deco_validate/convert_value.py +++ b/pedantic/decorators/fn_deco_validate/convert_value.py @@ -1,30 +1,30 @@ -from typing import Type, Any, Union +from typing import Any from pedantic.decorators.fn_deco_validate.exceptions import ConversionError -T = Union[bool, int, float, str, dict, list] +T = bool | int | float | str | dict | list -def convert_value(value: Any, target_type: Type[T]) -> T: +def convert_value(value: Any, target_type: type[T]) -> T: # noqa: D103 if isinstance(value, target_type): return value value = str(value).strip().lower() - if target_type == bool: + if target_type is bool: if value in ['true', '1']: return True - elif value in ['false', '0']: + if value in ['false', '0']: return False raise ConversionError(f'Value {value} cannot be converted to bool.') try: - if target_type == list: + if target_type is list: return [item.strip() for item in value.split(',')] - elif target_type == dict: + if target_type is dict: value = {item.split(':')[0].strip(): item.partition(':')[-1].strip() for item in value.split(',')} return target_type(value) - except ValueError: - raise ConversionError(f'Value {value} cannot be converted to {target_type}.') + except ValueError as ex: + raise ConversionError(f'Value {value} cannot be converted to {target_type}.') from ex diff --git a/pedantic/decorators/fn_deco_validate/exceptions.py b/pedantic/decorators/fn_deco_validate/exceptions.py index 34271af3..b275be20 100644 --- a/pedantic/decorators/fn_deco_validate/exceptions.py +++ b/pedantic/decorators/fn_deco_validate/exceptions.py @@ -1,24 +1,24 @@ -from typing import Any, Dict, Optional +from typing import Any -class ExceptionDictKey: +class ExceptionDictKey: # noqa: D101 VALUE = 'VALUE' MESSAGE = 'MESSAGE' PARAMETER = 'PARAMETER' VALIDATOR = 'VALIDATOR' -class ValidateException(Exception): - """ The base class for all exception thrown by the validate decorator. """ +class ValidateException(Exception): # noqa: N818 + """The base class for all exception thrown by the validate decorator.""" - def __init__(self, msg: str) -> None: + def __init__(self, msg: str) -> None: # noqa: D107 self.message = msg class ValidatorException(ValidateException): - """ An exception that is raised inside the validate() function of a Validator. """ + """An exception that is raised inside the validate() function of a Validator.""" - def __init__(self, msg: str, validator_name: str, value: Any, parameter_name: str = '') -> None: + def __init__(self, msg: str, validator_name: str, value: Any, parameter_name: str = '') -> None: # noqa: D107 super().__init__(msg=msg) self.validator_name = validator_name self.value = value @@ -29,10 +29,15 @@ def __str__(self) -> str: class ParameterException(ValidateException): - """ An exception that is raised inside a Parameter. """ - - def __init__(self, msg: str, parameter_name: str, - value: Optional[Any] = None, validator_name: Optional[str] = None) -> None: + """An exception that is raised inside a Parameter.""" + + def __init__( # noqa: D107 + self, + msg: str, + parameter_name: str, + value: Any | None = None, + validator_name: str | None = None, + ) -> None: super().__init__(msg=msg) self.validator_name = validator_name self.parameter_name = parameter_name @@ -40,7 +45,7 @@ def __init__(self, msg: str, parameter_name: str, @classmethod def from_validator_exception(cls, exception: ValidatorException, parameter_name: str = '') -> 'ParameterException': - """ Creates a parameter exception from a validator exception. """ + """Creates a parameter exception from a validator exception.""" return cls( value=exception.value, msg=exception.message, @@ -52,7 +57,7 @@ def __str__(self) -> str: return str(self.to_dict) @property - def to_dict(self) -> Dict[str, str]: + def to_dict(self) -> dict[str, str]: # noqa: D102 return { ExceptionDictKey.VALUE: str(self.value), ExceptionDictKey.MESSAGE: self.message, @@ -62,12 +67,12 @@ def to_dict(self) -> Dict[str, str]: class InvalidHeader(ParameterException): - """ Is raised if there is a validation error in a FlaskHeaderParameter. """ + """Is raised if there is a validation error in a FlaskHeaderParameter.""" class TooManyArguments(ValidateException): - """ Is raised if the function got more arguments than expected. """ + """Is raised if the function got more arguments than expected.""" class ConversionError(ValidateException): - """ Is raised if a type cast failed. """ + """Is raised if a type cast failed.""" diff --git a/pedantic/decorators/fn_deco_validate/fn_deco_validate.py b/pedantic/decorators/fn_deco_validate/fn_deco_validate.py index 06d4b731..d68bf28d 100644 --- a/pedantic/decorators/fn_deco_validate/fn_deco_validate.py +++ b/pedantic/decorators/fn_deco_validate/fn_deco_validate.py @@ -1,54 +1,56 @@ import inspect +from collections.abc import Callable from enum import Enum from functools import wraps -from typing import Any, Callable, List, Dict +from typing import Any -from pedantic.decorators.fn_deco_validate.exceptions import ValidateException, TooManyArguments -from pedantic.decorators.fn_deco_validate.parameters import Parameter, ExternalParameter +from pedantic.decorators.fn_deco_validate.exceptions import TooManyArguments, ValidateException +from pedantic.decorators.fn_deco_validate.parameters import ExternalParameter, Parameter from pedantic.decorators.fn_deco_validate.parameters.abstract_parameter import NoValue try: from flask import request + from pedantic.decorators.fn_deco_validate.parameters.flask_parameters import FlaskJsonParameter IS_FLASK_INSTALLED = True except ImportError: IS_FLASK_INSTALLED = False -class ReturnAs(Enum): +class ReturnAs(Enum): # noqa: D101 ARGS = 'ARGS' KWARGS_WITH_NONE = 'KWARGS_WITH_NONE' KWARGS_WITHOUT_NONE = 'KWARGS_WITHOUT_NONE' -def validate( - *parameters: Parameter, - return_as: ReturnAs = ReturnAs.ARGS, - strict: bool = True, - ignore_input: bool = False, +def validate( # noqa: PLR0915, C901 + *parameters: Parameter, + return_as: ReturnAs = ReturnAs.ARGS, + strict: bool = True, + ignore_input: bool = False, ) -> Callable: """ - Validates the values that are passed to the function by using the validators in the given parameters. - The decorated function could also be async or an instance method as well as a normal function. - - Args: - parameters (multiple Parameter): The parameters that will be validated. - return_as (ReturnAs): Pass the arguments as kwargs to the decorated function if ReturnAs.KWARGS. - Positional arguments are used otherwise. - strict (bool): If strict is true, you have to define a Parameter for each of the - arguments the decorated function takes. - ignore_input (bool): If True, all given arguments passed to this decorator are ignored. - This can be useful if you use only ExternalParameters. - - Returns: - Callable: The decorated function. + Validates the values that are passed to the function by using the validators in the given parameters. + The decorated function could also be async or an instance method as well as a normal function. + + Args: + parameters (multiple Parameter): The parameters that will be validated. + return_as (ReturnAs): Pass the arguments as kwargs to the decorated function if ReturnAs.KWARGS. + Positional arguments are used otherwise. + strict (bool): If strict is true, you have to define a Parameter for each of the + arguments the decorated function takes. + ignore_input (bool): If True, all given arguments passed to this decorator are ignored. + This can be useful if you use only ExternalParameters. + + Returns: + Callable: The decorated function. """ - def validator(func: Callable) -> Callable: + def validator(func: Callable) -> Callable: # noqa: PLR0915, C901 is_coroutine = inspect.iscoroutinefunction(func) @wraps(func) - def wrapper(*args, **kwargs) -> Any: + def wrapper(*args: Any, **kwargs: Any) -> Any: result = _wrapper_content(*args, **kwargs) if return_as == ReturnAs.ARGS: @@ -66,7 +68,7 @@ def wrapper(*args, **kwargs) -> Any: return func(**result) @wraps(func) - async def async_wrapper(*args, **kwargs) -> Any: + async def async_wrapper(*args: Any, **kwargs: Any) -> Any: result = _wrapper_content(*args, **kwargs) if return_as == ReturnAs.ARGS: @@ -83,10 +85,10 @@ async def async_wrapper(*args, **kwargs) -> Any: return await func(**result) - def _wrapper_content(*args, **kwargs) -> Dict[str, Any]: + def _wrapper_content(*args: Any, **kwargs: Any) -> dict[str, Any]: # noqa: PLR0912, C901 result = {} parameter_dict = {parameter.name: parameter for parameter in parameters} - used_parameter_names: List[str] = [] + used_parameter_names: list[str] = [] signature = inspect.signature(func) if not ignore_input: @@ -95,11 +97,10 @@ def _wrapper_content(*args, **kwargs) -> Dict[str, Any]: parameter = parameter_dict[k] result[k] = parameter.validate(value=v) used_parameter_names.append(parameter.name) + elif strict: + raise TooManyArguments(f'Got more arguments expected: No parameter found for argument {k}') else: - if strict: - raise TooManyArguments(f'Got more arguments expected: No parameter found for argument {k}') - else: - result[k] = v + result[k] = v wants_args = '*args' in str(signature) used_args = [] @@ -107,15 +108,15 @@ def _wrapper_content(*args, **kwargs) -> Dict[str, Any]: try: bound_args = signature.bind_partial(*args).arguments except TypeError as ex: - raise ValidateException(str(ex)) + raise ValidateException(str(ex)) from ex for k in bound_args: if k == 'args' and wants_args: for arg, parameter in zip( - [a for a in args if a not in used_args], - [p for p in parameters if p.name not in used_parameter_names] + [a for a in args if a not in used_args], + [p for p in parameters if p.name not in used_parameter_names], + strict=True, ): - print(f'Validate value {arg} with {parameter}') result[parameter.name] = parameter.validate(arg) used_parameter_names.append(parameter.name) elif k in parameter_dict: @@ -123,24 +124,22 @@ def _wrapper_content(*args, **kwargs) -> Dict[str, Any]: result[k] = parameter.validate(value=bound_args[k]) used_parameter_names.append(parameter.name) used_args.append(bound_args[k]) + elif strict and k != 'self': + raise TooManyArguments(f'Got more arguments expected: No parameter found for argument {k}') else: - if strict and k != 'self': - raise TooManyArguments(f'Got more arguments expected: No parameter found for argument {k}') - else: - result[k] = bound_args[k] + result[k] = bound_args[k] unused_parameters = [parameter for parameter in parameters if parameter.name not in used_parameter_names] for parameter in unused_parameters: - if isinstance(parameter, ExternalParameter): - if parameter.has_value(): - v = parameter.load_value() - result[parameter.name] = parameter.validate(value=v) - continue + if isinstance(parameter, ExternalParameter) and parameter.has_value(): + v = parameter.load_value() + result[parameter.name] = parameter.validate(value=v) + continue if parameter.is_required: return parameter.raise_exception(msg=f'Value for parameter {parameter.name} is required.') - elif parameter.default_value == NoValue: + if parameter.default_value == NoValue: if parameter.name in signature.parameters and \ signature.parameters[parameter.name].default is not signature.empty: value = signature.parameters[parameter.name].default @@ -152,17 +151,19 @@ def _wrapper_content(*args, **kwargs) -> Dict[str, Any]: result[parameter.name] = value # this is ugly, but I really want this behavior - if strict and IS_FLASK_INSTALLED: - if all([isinstance(p, FlaskJsonParameter) for p in parameter_dict.values()]) and request.is_json: - unexpected_args = [k for k in request.json if k not in parameter_dict] + if ( + strict and IS_FLASK_INSTALLED and + all(isinstance(p, FlaskJsonParameter) for p in parameter_dict.values()) + and request.is_json # this check must come last + ): + unexpected_args = [k for k in request.json if k not in parameter_dict] - if unexpected_args: - raise TooManyArguments(f'Got unexpected arguments: {unexpected_args}') + if unexpected_args: + raise TooManyArguments(f'Got unexpected arguments: {unexpected_args}') return result if is_coroutine: return async_wrapper - else: - return wrapper + return wrapper return validator diff --git a/pedantic/decorators/fn_deco_validate/parameters/__init__.py b/pedantic/decorators/fn_deco_validate/parameters/__init__.py index 152ba32d..8a549492 100644 --- a/pedantic/decorators/fn_deco_validate/parameters/__init__.py +++ b/pedantic/decorators/fn_deco_validate/parameters/__init__.py @@ -1,10 +1,34 @@ -from .abstract_parameter import Parameter from .abstract_external_parameter import ExternalParameter +from .abstract_parameter import Parameter from .deserializable import Deserializable from .environment_variable_parameter import EnvironmentVariableParameter +__all__ = [ + 'Deserializable', + 'EnvironmentVariableParameter', + 'ExternalParameter', + 'Parameter', +] + try: - from .flask_parameters import FlaskJsonParameter, FlaskFormParameter, FlaskParameter, FlaskGetParameter, \ - FlaskPathParameter, FlaskHeaderParameter, GenericFlaskDeserializer + from .flask_parameters import ( + FlaskFormParameter, + FlaskGetParameter, + FlaskHeaderParameter, + FlaskJsonParameter, + FlaskParameter, + FlaskPathParameter, + GenericFlaskDeserializer, + ) + + __all__ += [ + 'FlaskFormParameter', + 'FlaskGetParameter', + 'FlaskHeaderParameter', + 'FlaskJsonParameter', + 'FlaskParameter', + 'FlaskPathParameter', + 'GenericFlaskDeserializer', + ] except ImportError: - pass + pass # no Flask installed diff --git a/pedantic/decorators/fn_deco_validate/parameters/abstract_external_parameter.py b/pedantic/decorators/fn_deco_validate/parameters/abstract_external_parameter.py index e5889090..0f5ded73 100644 --- a/pedantic/decorators/fn_deco_validate/parameters/abstract_external_parameter.py +++ b/pedantic/decorators/fn_deco_validate/parameters/abstract_external_parameter.py @@ -5,9 +5,11 @@ class ExternalParameter(Parameter, ABC): + """The interface for all external parameters.""" + @abstractmethod def has_value(self) -> bool: - """ Returns True if the value can be fetched. """ + """Returns True if the value can be fetched.""" @abstractmethod def load_value(self) -> Any: diff --git a/pedantic/decorators/fn_deco_validate/parameters/abstract_parameter.py b/pedantic/decorators/fn_deco_validate/parameters/abstract_parameter.py index 527869de..d69ace81 100644 --- a/pedantic/decorators/fn_deco_validate/parameters/abstract_parameter.py +++ b/pedantic/decorators/fn_deco_validate/parameters/abstract_parameter.py @@ -1,36 +1,37 @@ -from typing import Iterable, Any, Type, Union, NoReturn, Optional +from collections.abc import Iterable +from typing import Any, NoReturn from pedantic.decorators.fn_deco_validate.convert_value import convert_value -from pedantic.decorators.fn_deco_validate.exceptions import ConversionError, ValidatorException, \ - ParameterException +from pedantic.decorators.fn_deco_validate.exceptions import ConversionError, ParameterException, ValidatorException from pedantic.decorators.fn_deco_validate.validators.abstract_validator import Validator class NoValue: - pass + """An alternative to None.""" -class Parameter: - exception_type: Type[ParameterException] = ParameterException +class Parameter: # noqa: D101 + exception_type: type[ParameterException] = ParameterException - def __init__(self, - name: str, - value_type: Type[Union[bool, int, float, str, dict, list]] = None, - validators: Iterable[Validator] = None, - default: Any = NoValue, - required: bool = True, - ) -> None: + def __init__( # noqa: D107 + self, + name: str, + value_type: type[bool | int | float | str | dict | list] | None = None, + validators: Iterable[Validator] | None = None, + default: Any = NoValue, + required: bool = True, + ) -> None: self.name = name - self.validators = validators if validators else [] + self.validators = validators or [] self.default_value = default self.value_type = value_type self.is_required = False if default != NoValue else required if value_type not in [str, bool, int, float, dict, list, None]: - raise AssertionError(f'value_type needs to be one of these: str, bool, int, float, dict & list') + raise AssertionError('value_type needs to be one of these: str, bool, int, float, dict & list') def validate(self, value: Any) -> Any: - """ Apply all validators to the given value and collect all ValidationErrors. """ + """Apply all validators to the given value and collect all ValidationErrors.""" if value is None: if self.is_required: @@ -50,13 +51,17 @@ def validate(self, value: Any) -> Any: try: result_value = validator.validate(result_value) except ValidatorException as e: - raise self.exception_type.from_validator_exception(exception=e, parameter_name=self.name) + raise self.exception_type.from_validator_exception(exception=e, parameter_name=self.name) from e return result_value - def raise_exception(self, msg: str, value: Any = None, validator: Optional[Validator] = None) -> NoReturn: - raise self.exception_type(value=value, parameter_name=self.name, msg=msg, - validator_name=validator.name if validator else None) + def raise_exception(self, msg: str, value: Any = None, validator: Validator | None = None) -> NoReturn: # noqa: D102 + raise self.exception_type( + value=value, + parameter_name=self.name, + msg=msg, + validator_name=validator.name if validator else None, + ) def __str__(self) -> str: return self.__class__.__name__ + ' name=' + self.name diff --git a/pedantic/decorators/fn_deco_validate/parameters/deserializable.py b/pedantic/decorators/fn_deco_validate/parameters/deserializable.py index 9d88f3c9..0bc4d88a 100644 --- a/pedantic/decorators/fn_deco_validate/parameters/deserializable.py +++ b/pedantic/decorators/fn_deco_validate/parameters/deserializable.py @@ -1,11 +1,11 @@ from abc import ABC, abstractmethod -from typing import Any, Dict +from typing import Any class Deserializable(ABC): - """ A tiny interface which has a static from_json() method which acts like a named constructor. """ + """A tiny interface which has a static from_json() method which acts like a named constructor.""" @staticmethod @abstractmethod - def from_json(data: Dict[str, Any]) -> 'Deserializable': - """ A named constructor which creates an object from JSON. """ + def from_json(data: dict[str, Any]) -> 'Deserializable': + """A named constructor which creates an object from JSON.""" diff --git a/pedantic/decorators/fn_deco_validate/parameters/environment_variable_parameter.py b/pedantic/decorators/fn_deco_validate/parameters/environment_variable_parameter.py index f9713e3c..f8da91aa 100644 --- a/pedantic/decorators/fn_deco_validate/parameters/environment_variable_parameter.py +++ b/pedantic/decorators/fn_deco_validate/parameters/environment_variable_parameter.py @@ -1,5 +1,6 @@ import os -from typing import Any, Type, Iterable, Union +from collections.abc import Iterable +from typing import Any from pedantic.decorators.fn_deco_overrides import overrides from pedantic.decorators.fn_deco_validate.parameters import ExternalParameter @@ -7,19 +8,20 @@ from pedantic.decorators.fn_deco_validate.validators import Validator -class EnvironmentVariableParameter(ExternalParameter): - def __init__(self, - name: str, - env_var_name: str = None, - value_type: Type[Union[str, bool, int, float]] = str, - validators: Iterable[Validator] = None, - required: bool = True, - default: Any = NoValue, - ) -> None: +class EnvironmentVariableParameter(ExternalParameter): # noqa: D101 + def __init__( # noqa: D107, PLR0913 + self, + name: str, + env_var_name: str | None = None, + value_type: type[str | bool | int | float] = str, + validators: Iterable[Validator] | None = None, + required: bool = True, +default: Any = NoValue, + ) -> None: super().__init__(name=name, validators=validators, default=default, value_type=value_type, required=required) if value_type not in [str, bool, int, float]: - raise AssertionError(f'value_type needs to be one of these: str, bool, int & float') + raise AssertionError('value_type needs to be one of these: str, bool, int & float') if env_var_name is None: self._env_var_name = name @@ -27,9 +29,9 @@ def __init__(self, self._env_var_name = env_var_name @overrides(ExternalParameter) - def has_value(self) -> bool: + def has_value(self) -> bool: # noqa: D102 return self._env_var_name in os.environ @overrides(ExternalParameter) - def load_value(self) -> Any: + def load_value(self) -> Any: # noqa: D102 return os.environ[self._env_var_name].strip() diff --git a/pedantic/decorators/fn_deco_validate/parameters/flask_parameters.py b/pedantic/decorators/fn_deco_validate/parameters/flask_parameters.py index 9b5a68ae..94c234ac 100644 --- a/pedantic/decorators/fn_deco_validate/parameters/flask_parameters.py +++ b/pedantic/decorators/fn_deco_validate/parameters/flask_parameters.py @@ -1,42 +1,42 @@ from abc import ABC, abstractmethod -from typing import Any, Dict, Type +from typing import Any from flask import request -from pedantic.decorators.fn_deco_validate.exceptions import InvalidHeader, ParameterException, ValidatorException from pedantic.decorators.fn_deco_overrides import overrides +from pedantic.decorators.fn_deco_validate.exceptions import InvalidHeader, ParameterException, ValidatorException from pedantic.decorators.fn_deco_validate.parameters import ExternalParameter, Parameter from pedantic.decorators.fn_deco_validate.parameters.deserializable import Deserializable -class FlaskParameter(ExternalParameter, ABC): +class FlaskParameter(ExternalParameter, ABC): # noqa: D101 @abstractmethod - def get_dict(self) -> Dict[str, Any]: - """ Returns the actual values as a dictionary. """ + def get_dict(self) -> dict[str, Any]: + """Returns the actual values as a dictionary.""" @overrides(ExternalParameter) - def has_value(self) -> bool: + def has_value(self) -> bool: # noqa: D102 dict_ = self.get_dict() return dict_ is not None and self.name in dict_ @overrides(ExternalParameter) - def load_value(self) -> Any: + def load_value(self) -> Any: # noqa: D102 dict_ = self.get_dict() return dict_[self.name] -class FlaskJsonParameter(FlaskParameter): +class FlaskJsonParameter(FlaskParameter): # noqa: D101 @overrides(FlaskParameter) - def get_dict(self) -> Dict: + def get_dict(self) -> dict: # noqa: D102 if not request.is_json: return {} return request.json -class FlaskFormParameter(FlaskParameter): +class FlaskFormParameter(FlaskParameter): # noqa: D101 @overrides(FlaskParameter) - def get_dict(self) -> Dict: + def get_dict(self) -> dict: # noqa: D102 return request.form @@ -47,53 +47,53 @@ class FlaskPathParameter(Parameter): """ -class FlaskGetParameter(FlaskParameter): +class FlaskGetParameter(FlaskParameter): # noqa: D101 @overrides(FlaskParameter) - def get_dict(self) -> Dict: + def get_dict(self) -> dict: # noqa: D102 return request.args @overrides(ExternalParameter) - def load_value(self) -> Any: + def load_value(self) -> Any: # noqa: D102 value = request.args.getlist(self.name) - if self.value_type == list: + if self.value_type is list: return value return value[0] -class FlaskHeaderParameter(FlaskParameter): +class FlaskHeaderParameter(FlaskParameter): # noqa: D101 exception_type = InvalidHeader @overrides(FlaskParameter) - def get_dict(self) -> Dict: + def get_dict(self) -> dict: # noqa: D102 return request.headers class GenericFlaskDeserializer(ExternalParameter): """ - A JSON deserializer for classes which implements the [Deserializable] interface. + A JSON deserializer for classes which implements the [Deserializable] interface. - Further reading: https://github.com/LostInDarkMath/pedantic-python-decorators/issues/55 + Further reading: https://github.com/LostInDarkMath/pedantic-python-decorators/issues/55 """ - def __init__(self, cls: Type[Deserializable], catch_exception: bool = True, **kwargs) -> None: + def __init__(self, cls: type[Deserializable], catch_exception: bool = True, **kwargs: Any) -> None: # noqa: D107 super().__init__(**kwargs) self._cls = cls self._catch_exceptions = catch_exception @overrides(ExternalParameter) - def has_value(self) -> bool: + def has_value(self) -> bool: # noqa: D102 return request.is_json @overrides(ExternalParameter) - def load_value(self) -> Any: + def load_value(self) -> Any: # noqa: D102 try: return self._cls.from_json(request.json) except ValidatorException as ex: - raise ParameterException.from_validator_exception(exception=ex, parameter_name='') + raise ParameterException.from_validator_exception(exception=ex, parameter_name='') from ex except Exception as ex: if self._catch_exceptions: self.raise_exception(msg=str(ex)) - raise ex + raise diff --git a/pedantic/decorators/fn_deco_validate/validators/__init__.py b/pedantic/decorators/fn_deco_validate/validators/__init__.py index 5595b5ab..93b6f732 100644 --- a/pedantic/decorators/fn_deco_validate/validators/__init__.py +++ b/pedantic/decorators/fn_deco_validate/validators/__init__.py @@ -1,5 +1,4 @@ from .abstract_validator import Validator -from .composite_validator import Composite from .datetime_isoformat import DatetimeIsoFormat from .datetime_unix_timestamp import DateTimeUnixTimestamp from .email import Email @@ -12,3 +11,19 @@ from .min import Min from .min_length import MinLength from .not_empty import NotEmpty + +__all__ = [ + 'DateTimeUnixTimestamp', + 'DatetimeIsoFormat', + 'Email', + 'ForEach', + 'IsEnum', + 'IsUuid', + 'MatchPattern', + 'Max', + 'MaxLength', + 'Min', + 'MinLength', + 'NotEmpty', + 'Validator', +] diff --git a/pedantic/decorators/fn_deco_validate/validators/abstract_validator.py b/pedantic/decorators/fn_deco_validate/validators/abstract_validator.py index a4d72839..c321ada7 100644 --- a/pedantic/decorators/fn_deco_validate/validators/abstract_validator.py +++ b/pedantic/decorators/fn_deco_validate/validators/abstract_validator.py @@ -5,29 +5,31 @@ class Validator(ABC): + """Base class for validator classes.""" + @abstractmethod def validate(self, value: Any) -> Any: """ - Validates and convert the value. - Raises an [ValidatorException] in case of an invalid value. - To raise this you can simply call self.raise_exception(). + Validates and convert the value. + Raises an [ValidatorException] in case of an invalid value. + To raise this you can simply call self.raise_exception(). """ def validate_param(self, value: Any, parameter_name: str) -> Any: """ - Validates and converts the value, just like [validate()]. - The difference is that a parameter_name is included in the exception, if an exception is raised. + Validates and converts the value, just like [validate()]. + The difference is that a parameter_name is included in the exception, if an exception is raised. """ try: return self.validate(value=value) except ValidatorException as ex: ex.parameter_name = parameter_name - raise ex + raise - def raise_exception(self, value: Any, msg: str) -> NoReturn: + def raise_exception(self, value: Any, msg: str) -> NoReturn: # noqa: D102 raise ValidatorException(value=value, validator_name=self.name, msg=msg) @property - def name(self) -> str: + def name(self) -> str: # noqa: D102 return self.__class__.__name__ diff --git a/pedantic/decorators/fn_deco_validate/validators/composite_validator.py b/pedantic/decorators/fn_deco_validate/validators/composite_validator.py deleted file mode 100644 index 44737bc9..00000000 --- a/pedantic/decorators/fn_deco_validate/validators/composite_validator.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Iterable, Iterator, Any - -from pedantic import overrides -from pedantic.decorators.fn_deco_validate.validators import Validator - - -class Composite(Validator): - def __init__(self, validators: Iterable[Validator]) -> None: - self._validators = validators - - def __iter__(self) -> Iterator[Validator]: - for validator in self._validators: - yield validator - - @overrides(Validator) - def validate(self, value: Any) -> Any: - for validator in self: - validator.validate(value) - - return value diff --git a/pedantic/decorators/fn_deco_validate/validators/datetime_isoformat.py b/pedantic/decorators/fn_deco_validate/validators/datetime_isoformat.py index 5e1c6bee..7310ff41 100644 --- a/pedantic/decorators/fn_deco_validate/validators/datetime_isoformat.py +++ b/pedantic/decorators/fn_deco_validate/validators/datetime_isoformat.py @@ -4,9 +4,9 @@ from pedantic.decorators.fn_deco_validate.validators import Validator -class DatetimeIsoFormat(Validator): +class DatetimeIsoFormat(Validator): # noqa: D101 @overrides(Validator) - def validate(self, value: str) -> datetime: + def validate(self, value: str) -> datetime: # noqa: D102 try: value = datetime.fromisoformat(value) except (TypeError, ValueError, AttributeError): diff --git a/pedantic/decorators/fn_deco_validate/validators/datetime_unix_timestamp.py b/pedantic/decorators/fn_deco_validate/validators/datetime_unix_timestamp.py index e62d20e6..c40da141 100644 --- a/pedantic/decorators/fn_deco_validate/validators/datetime_unix_timestamp.py +++ b/pedantic/decorators/fn_deco_validate/validators/datetime_unix_timestamp.py @@ -1,13 +1,12 @@ -from datetime import datetime, timedelta -from typing import Union +from datetime import UTC, datetime, timedelta from pedantic import overrides from pedantic.decorators.fn_deco_validate.validators import Validator -class DateTimeUnixTimestamp(Validator): +class DateTimeUnixTimestamp(Validator): # noqa: D101 @overrides(Validator) - def validate(self, value: Union[int, float, str]) -> datetime: + def validate(self, value: float | str) -> datetime: # noqa: D102 if not isinstance(value, (int, float, str)): self.raise_exception(msg=f'Invalid seconds since 1970: {value}', value=value) @@ -17,7 +16,7 @@ def validate(self, value: Union[int, float, str]) -> datetime: return self.raise_exception(msg=f'Could parse {value} to float.', value=value) try: - return datetime(year=1970, month=1, day=1) + timedelta(seconds=seconds) + return datetime(year=1970, month=1, day=1, tzinfo=UTC) + timedelta(seconds=seconds) except OverflowError: return self.raise_exception( msg=f'Date value out of range. Make sure you send SECONDS since 1970. Got: {value}', value=value) diff --git a/pedantic/decorators/fn_deco_validate/validators/email.py b/pedantic/decorators/fn_deco_validate/validators/email.py index 3b0401a6..ac848d8e 100644 --- a/pedantic/decorators/fn_deco_validate/validators/email.py +++ b/pedantic/decorators/fn_deco_validate/validators/email.py @@ -1,19 +1,19 @@ import re -from typing import Callable +from collections.abc import Callable from pedantic import overrides from pedantic.decorators.fn_deco_validate.validators import Validator -REGEX_EMAIL = r"[^@\s]+@[^@\s]+\.[a-zA-Z0-9]+$" +REGEX_EMAIL = r'[^@\s]+@[^@\s]+\.[a-zA-Z0-9]+$' -class Email(Validator): - def __init__(self, email_pattern: str = REGEX_EMAIL, post_processor: Callable[[str], str] = lambda x: x) -> None: +class Email(Validator): # noqa: D101 + def __init__(self, email_pattern: str = REGEX_EMAIL, post_processor: Callable[[str], str] = lambda x: x) -> None: # noqa: D107 self._pattern = email_pattern self._post_processor = post_processor @overrides(Validator) - def validate(self, value: str) -> str: + def validate(self, value: str) -> str: # noqa: D102 if not re.fullmatch(pattern=self._pattern, string=value): self.raise_exception(msg=f'invalid email address: {value}', value=value) diff --git a/pedantic/decorators/fn_deco_validate/validators/enum.py b/pedantic/decorators/fn_deco_validate/validators/enum.py index 611071e2..8fa4cc2c 100644 --- a/pedantic/decorators/fn_deco_validate/validators/enum.py +++ b/pedantic/decorators/fn_deco_validate/validators/enum.py @@ -5,14 +5,14 @@ from pedantic.decorators.fn_deco_validate.validators import Validator -class IsEnum(Validator): - def __init__(self, enum: EnumMeta, convert: bool = True, to_upper_case: bool = True) -> None: +class IsEnum(Validator): # noqa: D101 + def __init__(self, enum: EnumMeta, convert: bool = True, to_upper_case: bool = True) -> None: # noqa: D107 self._enum = enum self._convert = convert self._to_upper_case = to_upper_case @overrides(Validator) - def validate(self, value: Any) -> Any: + def validate(self, value: Any) -> Any: # noqa: D102 try: if isinstance(value, str) and self._to_upper_case: value = value.upper() diff --git a/pedantic/decorators/fn_deco_validate/validators/for_each.py b/pedantic/decorators/fn_deco_validate/validators/for_each.py index 8561e060..3b248142 100644 --- a/pedantic/decorators/fn_deco_validate/validators/for_each.py +++ b/pedantic/decorators/fn_deco_validate/validators/for_each.py @@ -1,19 +1,20 @@ import collections -from typing import Any, Iterable, List, Union +from collections.abc import Iterable +from typing import Any from pedantic import overrides from pedantic.decorators.fn_deco_validate.validators import Validator -class ForEach(Validator): - def __init__(self, validators: Union[Validator, Iterable[Validator]]) -> None: +class ForEach(Validator): # noqa: D101 + def __init__(self, validators: Validator | Iterable[Validator]) -> None: # noqa: D107 if isinstance(validators, Validator): self._validators = [validators] else: self._validators = validators @overrides(Validator) - def validate(self, value: Iterable[Any]) -> List[Any]: + def validate(self, value: Iterable[Any]) -> list[Any]: # noqa: D102 if not isinstance(value, collections.abc.Iterable): self.raise_exception(msg=f'{value} is not iterable.', value=value) @@ -21,7 +22,7 @@ def validate(self, value: Iterable[Any]) -> List[Any]: for item in value: for validator in self._validators: - item = validator.validate(item) + item = validator.validate(item) # noqa: PLW2901 results.append(item) diff --git a/pedantic/decorators/fn_deco_validate/validators/is_uuid.py b/pedantic/decorators/fn_deco_validate/validators/is_uuid.py index 9ee559b6..e9077df3 100644 --- a/pedantic/decorators/fn_deco_validate/validators/is_uuid.py +++ b/pedantic/decorators/fn_deco_validate/validators/is_uuid.py @@ -4,12 +4,12 @@ from pedantic.decorators.fn_deco_validate.validators import Validator -class IsUuid(Validator): - def __init__(self, convert: bool = False) -> None: +class IsUuid(Validator): # noqa: D101 + def __init__(self, convert: bool = False) -> None: # noqa: D107 self._convert = convert @overrides(Validator) - def validate(self, value: str) -> str: + def validate(self, value: str) -> str: # noqa: D102 try: converted_value = UUID(str(value)) except ValueError: diff --git a/pedantic/decorators/fn_deco_validate/validators/match_pattern.py b/pedantic/decorators/fn_deco_validate/validators/match_pattern.py index bc8543e2..641d3d2a 100644 --- a/pedantic/decorators/fn_deco_validate/validators/match_pattern.py +++ b/pedantic/decorators/fn_deco_validate/validators/match_pattern.py @@ -4,12 +4,12 @@ from pedantic.decorators.fn_deco_validate.validators import Validator -class MatchPattern(Validator): - def __init__(self, pattern: str) -> None: +class MatchPattern(Validator): # noqa: D101 + def __init__(self, pattern: str) -> None: # noqa: D107 self._pattern = re.compile(pattern=pattern) @overrides(Validator) - def validate(self, value: str) -> str: + def validate(self, value: str) -> str: # noqa: D102 if not self._pattern.search(string=str(value)): self.raise_exception(msg=f'Value "{value}" does not match pattern {self._pattern.pattern}.', value=value) diff --git a/pedantic/decorators/fn_deco_validate/validators/max.py b/pedantic/decorators/fn_deco_validate/validators/max.py index c687d0f1..174c7f87 100644 --- a/pedantic/decorators/fn_deco_validate/validators/max.py +++ b/pedantic/decorators/fn_deco_validate/validators/max.py @@ -1,25 +1,24 @@ -from typing import Union from pedantic import overrides from pedantic.decorators.fn_deco_validate.validators import Validator -class Max(Validator): - def __init__(self, value: Union[int, float], include_boundary: bool = True) -> None: +class Max(Validator): # noqa: D101 + def __init__(self, value: float, include_boundary: bool = True) -> None: """ - >>> Max(7, True).validate(7) - 7 - >>> Max(7, False).validate(7) # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ValidatorException: ... - >>> Max(7, False).validate(6.999) - 6.999 + >>> Max(7, True).validate(7) + 7 + >>> Max(7, False).validate(7) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ValidatorException: ... + >>> Max(7, False).validate(6.999) + 6.999 """ self._value = value self._include_boundary = include_boundary @overrides(Validator) - def validate(self, value: Union[int, float]) -> Union[int, float]: + def validate(self, value: float) -> int | float: # noqa: D102 if value > self._value and self._include_boundary: self.raise_exception(msg=f'greater then allowed: {value} is not <= {self._value}', value=value) elif value >= self._value and not self._include_boundary: diff --git a/pedantic/decorators/fn_deco_validate/validators/max_length.py b/pedantic/decorators/fn_deco_validate/validators/max_length.py index 6174602c..97621b26 100644 --- a/pedantic/decorators/fn_deco_validate/validators/max_length.py +++ b/pedantic/decorators/fn_deco_validate/validators/max_length.py @@ -1,16 +1,17 @@ import collections -from typing import Sized, Any +from collections.abc import Sized +from typing import Any from pedantic import overrides from pedantic.decorators.fn_deco_validate.validators.abstract_validator import Validator -class MaxLength(Validator): - def __init__(self, length: int) -> None: +class MaxLength(Validator): # noqa: D101 + def __init__(self, length: int) -> None: # noqa: D107 self._length = length @overrides(Validator) - def validate(self, value: Sized) -> Any: + def validate(self, value: Sized) -> Any: # noqa: D102 if not isinstance(value, collections.abc.Sized): self.raise_exception(msg=f'{value} has no length.', value=value) diff --git a/pedantic/decorators/fn_deco_validate/validators/min.py b/pedantic/decorators/fn_deco_validate/validators/min.py index 8a8e3550..ec14d318 100644 --- a/pedantic/decorators/fn_deco_validate/validators/min.py +++ b/pedantic/decorators/fn_deco_validate/validators/min.py @@ -1,25 +1,24 @@ -from typing import Union from pedantic import overrides from pedantic.decorators.fn_deco_validate.validators import Validator -class Min(Validator): - def __init__(self, value: Union[int, float], include_boundary: bool = True) -> None: +class Min(Validator): # noqa: D101 + def __init__(self, value: float, include_boundary: bool = True) -> None: """ - >>> Min(7, True).validate(7) - 7 - >>> Min(7, False).validate(7) # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ValidatorException: ... - >>> Min(7, False).validate(7.001) - 7.001 + >>> Min(7, True).validate(7) + 7 + >>> Min(7, False).validate(7) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ValidatorException: ... + >>> Min(7, False).validate(7.001) + 7.001 """ self._value = value self._include_boundary = include_boundary @overrides(Validator) - def validate(self, value: Union[int, float]) -> Union[int, float]: + def validate(self, value: float) -> int | float: # noqa: D102 if value < self._value and self._include_boundary: self.raise_exception(msg=f'smaller then allowed: {value} is not >= {self._value}', value=value) elif value <= self._value and not self._include_boundary: diff --git a/pedantic/decorators/fn_deco_validate/validators/min_length.py b/pedantic/decorators/fn_deco_validate/validators/min_length.py index 205c7075..9dd382c0 100644 --- a/pedantic/decorators/fn_deco_validate/validators/min_length.py +++ b/pedantic/decorators/fn_deco_validate/validators/min_length.py @@ -1,16 +1,17 @@ import collections -from typing import Sized, Any +from collections.abc import Sized +from typing import Any from pedantic import overrides from pedantic.decorators.fn_deco_validate.validators.abstract_validator import Validator -class MinLength(Validator): - def __init__(self, length: int) -> None: +class MinLength(Validator): # noqa: D101 + def __init__(self, length: int) -> None: # noqa: D107 self._length = length @overrides(Validator) - def validate(self, value: Sized) -> Any: + def validate(self, value: Sized) -> Any: # noqa: D102 if not isinstance(value, collections.abc.Sized): self.raise_exception(msg=f'{value} has no length.', value=value) diff --git a/pedantic/decorators/fn_deco_validate/validators/not_empty.py b/pedantic/decorators/fn_deco_validate/validators/not_empty.py index 21f53838..45d93c6b 100644 --- a/pedantic/decorators/fn_deco_validate/validators/not_empty.py +++ b/pedantic/decorators/fn_deco_validate/validators/not_empty.py @@ -1,30 +1,33 @@ import collections -from typing import Sequence +from collections.abc import Sequence from pedantic import overrides from pedantic.decorators.fn_deco_validate.validators.abstract_validator import Validator class NotEmpty(Validator): + """Validates that the given value is not empty.""" + def __init__(self, strip: bool = True) -> None: + """If strip is True, the leading and trailing whitespace will be removed.""" self.strip = strip @overrides(Validator) def validate(self, value: Sequence) -> Sequence: """ - Throws a ValidationError if the sequence is empty. - If the sequence is a string, it removes all leading and trailing whitespace. + Throws a ValidationError if the sequence is empty. + If the sequence is a string, it removes all leading and trailing whitespace. """ if isinstance(value, str): if not value.strip(): - self.raise_exception(msg=f'Got empty String which is invalid.', value=value) + self.raise_exception(msg='Got empty String which is invalid.', value=value) return value.strip() if self.strip else value - elif isinstance(value, collections.abc.Sequence): + if isinstance(value, collections.abc.Sequence): if len(value) == 0: - raise self.raise_exception(msg=f'Got empty which is invalid.', value=value) + raise self.raise_exception(msg='Got empty which is invalid.', value=value) return value - self.raise_exception(msg=f'Got {type(value)} which is not a Sequence.', value=value) + return self.raise_exception(msg=f'Got {type(value)} which is not a Sequence.', value=value) diff --git a/pedantic/env_var_logic.py b/pedantic/env_var_logic.py deleted file mode 100644 index 09521f79..00000000 --- a/pedantic/env_var_logic.py +++ /dev/null @@ -1,18 +0,0 @@ -import os - -ENVIRONMENT_VARIABLE_NAME = 'ENABLE_PEDANTIC' - - -def enable_pedantic() -> None: - os.environ[ENVIRONMENT_VARIABLE_NAME] = '1' - - -def disable_pedantic() -> None: - os.environ[ENVIRONMENT_VARIABLE_NAME] = '0' - - -def is_enabled() -> bool: - if ENVIRONMENT_VARIABLE_NAME not in os.environ: - return True - - return os.environ[ENVIRONMENT_VARIABLE_NAME] == '1' diff --git a/pedantic/examples/__init__.py b/pedantic/examples/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pedantic/examples/config.csv b/pedantic/examples/config.csv deleted file mode 100644 index 1b4d6883..00000000 --- a/pedantic/examples/config.csv +++ /dev/null @@ -1,2 +0,0 @@ -42 -0.26 diff --git a/pedantic/examples/validate.py b/pedantic/examples/validate.py deleted file mode 100644 index 08231f60..00000000 --- a/pedantic/examples/validate.py +++ /dev/null @@ -1,87 +0,0 @@ -import os -from dataclasses import dataclass - -from pedantic import validate, ExternalParameter, overrides, Validator, Parameter, Min, ReturnAs - - -@dataclass(frozen=True) -class Configuration: - iterations: int - max_error: float - - -class ConfigurationValidator(Validator): - @overrides(Validator) - def validate(self, value: Configuration) -> Configuration: - if value.iterations < 1 or value.max_error < 0: - self.raise_exception(msg=f'Invalid configuration: {value}', value=value) - - return value - - -class ConfigFromEnvVar(ExternalParameter): - """ Reads the configuration from environment variables. """ - - @overrides(ExternalParameter) - def has_value(self) -> bool: - return 'iterations' in os.environ and 'max_error' in os.environ - - @overrides(ExternalParameter) - def load_value(self) -> Configuration: - return Configuration( - iterations=int(os.environ['iterations']), - max_error=float(os.environ['max_error']), - ) - - -class ConfigFromFile(ExternalParameter): - """ Reads the configuration from a config file. """ - - @overrides(ExternalParameter) - def has_value(self) -> bool: - return os.path.isfile('config.csv') - - @overrides(ExternalParameter) - def load_value(self) -> Configuration: - with open(file='config.csv', mode='r') as file: - content = file.readlines() - return Configuration( - iterations=int(content[0].strip('\n')), - max_error=float(content[1]), - ) - - -# choose your configuration source here: -@validate(ConfigFromEnvVar(name='config', validators=[ConfigurationValidator()]), strict=False, return_as=ReturnAs.KWARGS_WITH_NONE) -# @validate(ConfigFromFile(name='config', validators=[ConfigurationValidator()]), strict=False) - -# with strict_mode = True (which is the default) -# you need to pass a Parameter for each parameter of the decorated function -# @validate( -# Parameter(name='value', validators=[Min(5, include_boundary=False)]), -# ConfigFromFile(name='config', validators=[ConfigurationValidator()]), -# ) -def my_algorithm(value: float, config: Configuration) -> float: - """ - This method calculates something that depends on the given value with considering the configuration. - Note how well this small piece of code is designed: - - Fhe function my_algorithm() need a Configuration but has no knowledge where this come from. - - Furthermore, it need does not care about parameter validation. - - The ConfigurationValidator doesn't now anything about the creation of the data. - - The @validate decorator is the only you need to change, if you want a different configuration source. - """ - print(value) - print(config) - return value - - -if __name__ == '__main__': - # we can call the function with a config like there is no decorator. - # This makes testing extremely easy: no config files, no environment variables or stuff like that - print(my_algorithm(value=2, config=Configuration(iterations=3, max_error=4.4))) - - os.environ['iterations'] = '12' - os.environ['max_error'] = '3.1415' - - # but we also can omit the config and load it implicitly by our custom Parameters - print(my_algorithm(value=42.0)) diff --git a/pedantic/exceptions.py b/pedantic/exceptions.py index c68473e3..4d4a6d81 100644 --- a/pedantic/exceptions.py +++ b/pedantic/exceptions.py @@ -1,27 +1,22 @@ - -class NotImplementedException(Exception): - pass - - -class PedanticException(Exception): - pass +class PedanticException(Exception): # noqa: N818 + """The base exception class for all Pedantic exceptions.""" class PedanticTypeCheckException(PedanticException): - pass + """Raised if a type hint is incorrect.""" class PedanticDocstringException(PedanticException): - pass + """Raised if the docstring is invalid e.g., wrong types""" class PedanticOverrideException(PedanticException): - pass + """Raised when a child class overrides a method that the parent class does not have.""" class PedanticCallWithArgsException(PedanticException): - pass + """Raised if a function is called with kwargs but is called with args.""" class PedanticTypeVarMismatchException(PedanticException): - pass + """Raised if a TypeVar type conflict happens.""" diff --git a/pedantic/get_context.py b/pedantic/get_context.py index 0c8538cf..0c57eb92 100644 --- a/pedantic/get_context.py +++ b/pedantic/get_context.py @@ -1,17 +1,17 @@ import sys -from typing import Type, Dict, List -def get_context(depth: int = 1, increase_depth_if_name_matches: List[str] = None) -> Dict[str, Type]: +def get_context(depth: int = 1, increase_depth_if_name_matches: list[str] | None = None) -> dict[str, type]: """ - Get the context of a frame at the given depth of the current call stack. - See also: https://docs.python.org/3/library/sys.html#sys._getframe + Get the context of a frame at the given depth of the current call stack. + + See also: https://docs.python.org/3/library/sys.html#sys._getframe """ - frame = sys._getframe(depth) + frame = sys._getframe(depth) # noqa: SLF001 name = frame.f_code.co_name if name in (increase_depth_if_name_matches or []): - frame = sys._getframe(depth + 1) + frame = sys._getframe(depth + 1) # noqa: SLF001 return {**frame.f_globals, **frame.f_locals} diff --git a/pedantic/helper_fn.py b/pedantic/helper_fn.py new file mode 100644 index 00000000..1b3a44f5 --- /dev/null +++ b/pedantic/helper_fn.py @@ -0,0 +1,22 @@ +import doctest +from collections.abc import Callable + + +def run_doctest_of_single_function(f: Callable) -> None: + """Useful for debugging a function with doctests.""" + + finder = doctest.DocTestFinder() + runner = doctest.DocTestRunner() + + # Find doctests attached to the function + tests = finder.find(f) + + # Run them + for test in tests: + runner.run(test) + + # Fail the pytest test if any doctest failed + results = runner.summarize() + + if results.failed > 0: + raise AssertionError(f'Failed tests: {results.failed}') diff --git a/pedantic/mixins/__init__.py b/pedantic/mixins/__init__.py index 8b457fb4..308e2d91 100644 --- a/pedantic/mixins/__init__.py +++ b/pedantic/mixins/__init__.py @@ -1,2 +1,9 @@ from .generic_mixin import GenericMixin -from .with_decorated_methods import create_decorator, DecoratorType, WithDecoratedMethods +from .with_decorated_methods import DecoratorType, WithDecoratedMethods, create_decorator + +__all__ = [ + 'DecoratorType', + 'GenericMixin', + 'WithDecoratedMethods', + 'create_decorator', +] diff --git a/pedantic/mixins/generic_mixin.py b/pedantic/mixins/generic_mixin.py index 94ed2987..a9f4243b 100644 --- a/pedantic/mixins/generic_mixin.py +++ b/pedantic/mixins/generic_mixin.py @@ -1,9 +1,28 @@ -from typing import Type, TypeVar, Dict, get_origin, get_args +from typing import TypeVar, get_args, get_origin class GenericMixin: """ - A mixin that provides easy access to given type variables. + A mixin that provides easy access to given type variables. + + Example: + >>> from typing import Generic, TypeVar + >>> T = TypeVar('T') + >>> U = TypeVar('U') + >>> class Foo(Generic[T, U], GenericMixin): + ... values: list[T] + ... value: U + >>> f = Foo[str, int]() + >>> f.type_vars + {~T: , ~U: } + """ + + @property + def type_vars(self) -> dict[TypeVar, type]: + """ + Returns the mapping of type variables to types. + + DO NOT call this inside __init__()! Example: >>> from typing import Generic, TypeVar @@ -15,66 +34,28 @@ class GenericMixin: >>> f = Foo[str, int]() >>> f.type_vars {~T: , ~U: } - """ - - @property - def type_var(self) -> Type: - """ - Get the type variable for this class. - Use this for convenience if your class has only one type parameter. - - DO NOT call this inside __init__()! - - Example: - >>> from typing import Generic, TypeVar - >>> T = TypeVar('T') - >>> class Foo(Generic[T], GenericMixin): - ... value: T - >>> f = Foo[float]() - >>> f.type_var - - """ - - types = self._get_resolved_typevars() - assert len(types) == 1, f'You have multiple type parameters. Please use "type_vars" instead of "type_var".' - return list(types.values())[0] # type: ignore - - @property - def type_vars(self) -> Dict[TypeVar, Type]: - """ - Returns the mapping of type variables to types. - - DO NOT call this inside __init__()! - - Example: - >>> from typing import Generic, TypeVar - >>> T = TypeVar('T') - >>> U = TypeVar('U') - >>> class Foo(Generic[T, U], GenericMixin): - ... values: list[T] - ... value: U - >>> f = Foo[str, int]() - >>> f.type_vars - {~T: , ~U: } """ return self._get_resolved_typevars() - def _get_resolved_typevars(self) -> Dict[TypeVar, Type]: + def _get_resolved_typevars(self) -> dict[TypeVar, type]: # noqa: C901 """ + Returns the resolved type vars. + Do not call this inside the __init__() method, because at that point the relevant information are not present. See also https://github.com/python/cpython/issues/90899' """ mapping: dict[TypeVar, type] = {} + class_name = type(self).__name__ if not hasattr(self, '__orig_bases__'): raise AssertionError( - f'{self.class_name} is not a generic class. To make it generic, declare it like: ' - f'class {self.class_name}(Generic[T], GenericMixin):...' + f'{class_name} is not a generic class. To make it generic, declare it like: ' + f'class {class_name}(Generic[T], GenericMixin):...', ) - def collect(base, substitutions: dict[TypeVar, type]): + def collect(base: type, substitutions: dict[TypeVar, type]) -> None: """Recursively collect type var mappings from a generic base.""" origin = get_origin(base) or base args = get_args(base) @@ -83,11 +64,14 @@ def collect(base, substitutions: dict[TypeVar, type]): # copy substitutions so each recursion has its own view resolved = substitutions.copy() - for param, arg in zip(params, args): + for param, arg in zip(params, args, strict=False): if isinstance(arg, TypeVar): - arg = substitutions.get(arg, arg) - mapping[param] = arg - resolved[param] = arg + processed_arg = substitutions.get(arg, arg) + else: + processed_arg = arg + + mapping[param] = processed_arg + resolved[param] = processed_arg # Recurse into base classes, applying current substitutions for super_base in getattr(origin, '__orig_bases__', []): @@ -128,15 +112,10 @@ def collect(base, substitutions: dict[TypeVar, type]): unresolved = {p for p in all_params if p not in mapping or isinstance(mapping[p], TypeVar)} if unresolved: raise AssertionError( - f'You need to instantiate this class with type parameters! Example: {self.class_name}[int]()\n' + f'You need to instantiate this class with type parameters! Example: {class_name}[int]()\n' f'Also make sure that you do not call this in the __init__() method of your class!\n' f'Unresolved type variables: {unresolved}\n' - f'See also https://github.com/python/cpython/issues/90899' + f'See also https://github.com/python/cpython/issues/90899', ) return mapping - @property - def class_name(self) -> str: - """ Get the name of the class of this instance. """ - - return type(self).__name__ diff --git a/pedantic/mixins/with_decorated_methods.py b/pedantic/mixins/with_decorated_methods.py index f5ecded3..07ab05a5 100644 --- a/pedantic/mixins/with_decorated_methods.py +++ b/pedantic/mixins/with_decorated_methods.py @@ -1,6 +1,7 @@ from abc import ABC +from collections.abc import Callable from enum import StrEnum -from typing import TypeVar, Callable, Generic +from typing import Generic, TypeVar from pedantic.mixins.generic_mixin import GenericMixin @@ -25,10 +26,11 @@ class DecoratorType(StrEnum): def create_decorator( decorator_type: DecoratorType, - transformation: Callable[[C, DecoratorType, T], C] = None, + transformation: Callable[[C, DecoratorType, T], C] | None = None, ) -> Callable[[T], Callable[[C], C]]: """ Creates a new decorator that is parametrized with one argument of an arbitrary type. + You can also pass an arbitrary [transformation] to add custom behavior to the decorator. """ @@ -46,9 +48,10 @@ def fun(f: C) -> C: return decorator -class WithDecoratedMethods(ABC, Generic[DecoratorTypeVar], GenericMixin): +class WithDecoratedMethods(ABC, GenericMixin, Generic[DecoratorTypeVar]): """ A mixin that is used to figure out which method is decorated with custom parameterized decorators. + Example: >>> class Decorators(DecoratorType): ... FOO = '_foo' @@ -81,8 +84,10 @@ class WithDecoratedMethods(ABC, Generic[DecoratorTypeVar], GenericMixin): """ def get_decorated_functions(self) -> dict[DecoratorTypeVar, dict[C, T]]: - decorator_types = self.type_vars[DecoratorTypeVar] - decorated_functions = {t: dict() for t in decorator_types} # type: ignore + """Returns a mapping of all functions that are decorated by the given decorator type.""" + + decorator_types: DecoratorTypeVar = self.type_vars[DecoratorTypeVar] # type: ignore[assignment] + decorated_functions = {t: {} for t in decorator_types} for attribute_name in dir(self): if attribute_name.startswith('__') or attribute_name in ['type_var', 'type_vars']: @@ -90,10 +95,10 @@ def get_decorated_functions(self) -> dict[DecoratorTypeVar, dict[C, T]]: try: attribute = getattr(self, attribute_name) - except BaseException: + except BaseException: # noqa: BLE001 continue # ignore bad attributes - for decorator_type in decorator_types: # type: ignore + for decorator_type in decorator_types: if hasattr(attribute, decorator_type): decorated_functions[decorator_type][attribute] = getattr(attribute, decorator_type) diff --git a/pedantic/models/__init__.py b/pedantic/models/__init__.py index 9fa95f45..8a64385c 100644 --- a/pedantic/models/__init__.py +++ b/pedantic/models/__init__.py @@ -1,3 +1,9 @@ from .decorated_function import DecoratedFunction from .function_call import FunctionCall from .generator_wrapper import GeneratorWrapper + +__all__ = [ + 'DecoratedFunction', + 'FunctionCall', + 'GeneratorWrapper', +] diff --git a/pedantic/models/decorated_function.py b/pedantic/models/decorated_function.py index d057cb5c..b80e8045 100644 --- a/pedantic/models/decorated_function.py +++ b/pedantic/models/decorated_function.py @@ -1,9 +1,10 @@ import inspect import re -from typing import Any, Callable, Dict, Optional +from collections.abc import Callable +from typing import Any try: - from docstring_parser import parse, Docstring + from docstring_parser import Docstring, parse IS_DOCSTRING_PARSER_INSTALLED = True except ImportError: IS_DOCSTRING_PARSER_INSTALLED = False @@ -14,12 +15,14 @@ FUNCTIONS_THAT_REQUIRE_KWARGS = [ '__new__', '__init__', '__str__', '__del__', '__int__', '__float__', '__complex__', '__oct__', '__hex__', - '__index__', '__trunc__', '__repr__', '__unicode__', '__hash__', '__nonzero__', '__dir__', '__sizeof__' + '__index__', '__trunc__', '__repr__', '__unicode__', '__hash__', '__nonzero__', '__dir__', '__sizeof__', ] class DecoratedFunction: - def __init__(self, func: Callable[..., Any]) -> None: + """Wraps a function.""" + + def __init__(self, func: Callable[..., Any]) -> None: # noqa: D107 self._func = func if not callable(func): @@ -42,47 +45,48 @@ def __init__(self, func: Callable[..., Any]) -> None: self._docstring = None @property - def func(self) -> Callable[..., Any]: + def func(self) -> Callable[..., Any]: # noqa: D102 return self._func @property - def annotations(self) -> Dict[str, Any]: + def annotations(self) -> dict[str, Any]: # noqa: D102 return self._full_arg_spec.annotations @property - def docstring(self) -> Optional[Docstring]: + def docstring(self) -> Docstring | None: """ - Returns the docstring if the docstring-parser package is installed else None. - See also https://pypi.org/project/docstring-parser/ + Returns the docstring if the docstring-parser package is installed else None. + + See also https://pypi.org/project/docstring-parser/ """ return self._docstring @property - def raw_doc(self) -> Optional[str]: + def raw_doc(self) -> str | None: # noqa: D102 return self._func.__doc__ @property - def signature(self) -> inspect.Signature: + def signature(self) -> inspect.Signature: # noqa: D102 return self._signature @property - def err(self) -> str: + def err(self) -> str: # noqa: D102 return self._err @property - def source(self) -> str: + def source(self) -> str: # noqa: D102 return self._source @property - def name(self) -> str: + def name(self) -> str: # noqa: D102 if hasattr(self._func, '__name__'): return self._func.__name__ return self._func.func.__name__ @property - def full_name(self) -> str: + def full_name(self) -> str: # noqa: D102 if hasattr(self._func, '__qualname__'): return self._func.__qualname__ @@ -90,7 +94,7 @@ def full_name(self) -> str: @property def is_static_method(self) -> bool: - """ I honestly have no idea how to do this better :( """ + """I honestly have no idea how to do this better :(""" if self.source is None: return False @@ -98,58 +102,59 @@ def is_static_method(self) -> bool: return '@staticmethod' in self.source @property - def wants_args(self) -> bool: + def wants_args(self) -> bool: # noqa: D102 if self.source is None: return False return '*args' in self.source @property - def is_property_setter(self) -> bool: + def is_property_setter(self) -> bool: # noqa: D102 if self.source is None: return False return f'@{self.name}.setter' in self.source @property - def should_have_kwargs(self) -> bool: + def should_have_kwargs(self) -> bool: # noqa: D102 if self.is_property_setter or self.wants_args: return False - elif not self.name.startswith('__') or not self.name.endswith('__'): + if not self.name.startswith('__') or not self.name.endswith('__'): return True return self.name in FUNCTIONS_THAT_REQUIRE_KWARGS @property - def is_instance_method(self) -> bool: + def is_instance_method(self) -> bool: # noqa: D102 return self._full_arg_spec.args != [] and self._full_arg_spec.args[0] == 'self' @property def is_class_method(self) -> bool: """ - Returns true if the function is decoratorated with the @classmethod decorator. - See also: https://stackoverflow.com/questions/19227724/check-if-a-function-uses-classmethod + Returns true if the function is decorated with the @classmethod decorator. + + See also: https://stackoverflow.com/questions/19227724/check-if-a-function-uses-classmethod """ return inspect.ismethod(self._func) @property - def num_of_decorators(self) -> int: + def num_of_decorators(self) -> int: # noqa: D102 if self.source is None: return 0 return len(re.findall('@', self.source.split('def')[0])) @property - def is_pedantic(self) -> bool: + def is_pedantic(self) -> bool: # noqa: D102 if self.source is None: return False - return '@pedantic' in self.source or '@require_kwargs' in self.source + return '@pedantic' in self.source @property - def is_coroutine(self) -> bool: + def is_coroutine(self) -> bool: # noqa: D102 return inspect.iscoroutinefunction(self._func) @property - def is_generator(self) -> bool: + def is_generator(self) -> bool: # noqa: D102 return inspect.isgeneratorfunction(self._func) diff --git a/pedantic/models/function_call.py b/pedantic/models/function_call.py index 7ed8e13c..41a7c9eb 100644 --- a/pedantic/models/function_call.py +++ b/pedantic/models/function_call.py @@ -1,43 +1,51 @@ import inspect -from typing import Dict, Tuple, Any, Union, Type, Optional, ForwardRef +from typing import Any, ForwardRef -from pedantic.constants import TypeVar, TYPE_VAR_METHOD_NAME, ReturnType, TYPE_VAR_SELF +from pedantic.constants import TYPE_VAR_METHOD_NAME, TYPE_VAR_SELF, ReturnType, TypeVar from pedantic.exceptions import PedanticCallWithArgsException, PedanticTypeCheckException -from pedantic.type_checking_logic.check_types import assert_value_matches_type from pedantic.models.decorated_function import DecoratedFunction from pedantic.models.generator_wrapper import GeneratorWrapper +from pedantic.type_checking_logic.check_types import assert_value_matches_type class FunctionCall: - def __init__(self, func: DecoratedFunction, args: Tuple[Any, ...], kwargs: Dict[str, Any], context: Dict[str, Type]) -> None: + """Represents a function call.""" + + def __init__( # noqa: D107 + self, + func: DecoratedFunction, + args: tuple[Any, ...], + kwargs: dict[str, Any], + context: dict[str, type], + ) -> None: self._func = func self._args = args self._kwargs = kwargs self._context = context self._instance = self.args[0] if self.func.is_instance_method else None - self._type_vars = dict() + self._type_vars = {} self._params_without_self = {k: v for k, v in self.func.signature.parameters.items() if v.name != 'self'} self._already_checked_kwargs = [] self._get_type_vars = lambda: self._type_vars @property - def func(self) -> DecoratedFunction: + def func(self) -> DecoratedFunction: # noqa: D102 return self._func @property - def args(self) -> Tuple[Any, ...]: + def args(self) -> tuple[Any, ...]: # noqa: D102 return self._args @property - def kwargs(self) -> Dict[str, Any]: + def kwargs(self) -> dict[str, Any]: # noqa: D102 return self._kwargs @property - def not_yet_check_kwargs(self) -> Dict[str, Any]: + def not_yet_check_kwargs(self) -> dict[str, Any]: # noqa: D102 return {k: v for k, v in self._kwargs.items() if k not in self._already_checked_kwargs} @property - def type_vars(self) -> Dict[TypeVar, Any]: + def type_vars(self) -> dict[TypeVar, Any]: # noqa: D102 if hasattr(self._instance, TYPE_VAR_METHOD_NAME): self._get_type_vars = getattr(self._instance, TYPE_VAR_METHOD_NAME) @@ -49,15 +57,15 @@ def type_vars(self) -> Dict[TypeVar, Any]: return res @property - def clazz(self) -> Optional[Type]: - """ Return the enclosing class of the called function if there is one. """ + def clazz(self) -> type | None: + """Returns the enclosing class of the called function if there is one.""" if self._instance is not None: # case instance method return type(self._instance) - elif self.func.is_class_method: + if self.func.is_class_method: return self.func.func.__self__ - elif self.func.is_static_method: + if self.func.is_static_method: if not self.args: # static method was called on class class_name = self.func.full_name.split('.')[-2] @@ -66,12 +74,14 @@ def clazz(self) -> Optional[Type]: # static method was called on instance return type(self.args[0]) + return None + @property - def params_without_self(self) -> Dict[str, inspect.Parameter]: + def params_without_self(self) -> dict[str, inspect.Parameter]: # noqa: D102 return self._params_without_self @property - def args_without_self(self) -> Tuple[Any, ...]: + def args_without_self(self) -> tuple[Any, ...]: # noqa: D102 max_allowed = 0 if not self.func.is_pedantic else 1 uses_multiple_decorators = self.func.num_of_decorators > max_allowed @@ -79,16 +89,18 @@ def args_without_self(self) -> Tuple[Any, ...]: return self.args[1:] # self is always the first argument if present return self.args - def assert_uses_kwargs(self) -> None: + def assert_uses_kwargs(self) -> None: # noqa: D102 if self.func.should_have_kwargs and self.args_without_self: raise PedanticCallWithArgsException( f'{self.func.err}Use kwargs when you call function {self.func.name}. Args: {self.args_without_self}') def check_types(self) -> ReturnType: + """Performs type checking on return value.""" self._check_types_of_arguments() return self._check_types_return(result=self._get_return_value()) async def async_check_types(self) -> ReturnType: + """Performs type checking on return value.""" self._check_types_of_arguments() return self._check_types_return(result=await self._async_get_return_value()) @@ -98,7 +110,7 @@ def _check_types_of_arguments(self) -> None: self._check_types_args(params={k: v for k, v in d if str(v).startswith('*') and not str(v).startswith('**')}) self._check_types_kwargs(params={k: v for k, v in d if str(v).startswith('**')}) - def _check_type_param(self, params: Dict[str, inspect.Parameter]) -> None: + def _check_type_param(self, params: dict[str, inspect.Parameter]) -> None: arg_index = 1 if self.func.is_instance_method else 0 for key, param in params.items(): @@ -114,11 +126,10 @@ def _check_type_param(self, params: Dict[str, inspect.Parameter]) -> None: else: actual_value = self.args[arg_index] arg_index += 1 + elif key in self.kwargs: + actual_value = self.kwargs[key] else: - if key in self.kwargs: - actual_value = self.kwargs[key] - else: - actual_value = param.default + actual_value = param.default assert_value_matches_type( value=actual_value, @@ -129,11 +140,11 @@ def _check_type_param(self, params: Dict[str, inspect.Parameter]) -> None: context=self._context, ) - def _check_types_args(self, params: Dict[str, inspect.Parameter]) -> None: + def _check_types_args(self, params: dict[str, inspect.Parameter]) -> None: if not params: return - expected = list(params.values())[0].annotation # it's not possible to have more than 1 + expected = next(iter(params.values())).annotation # it's not possible to have more than 1 for arg in self.args: assert_value_matches_type( @@ -144,11 +155,11 @@ def _check_types_args(self, params: Dict[str, inspect.Parameter]) -> None: context=self._context, ) - def _check_types_kwargs(self, params: Dict[str, inspect.Parameter]) -> None: + def _check_types_kwargs(self, params: dict[str, inspect.Parameter]) -> None: if not params: return - param = list(params.values())[0] # it's not possible to have more than 1 + param = next(iter(params.values())) # it's not possible to have more than 1 self._assert_param_has_type_annotation(param=param) for kwarg in self.not_yet_check_kwargs: @@ -162,7 +173,7 @@ def _check_types_kwargs(self, params: Dict[str, inspect.Parameter]) -> None: context=self._context, ) - def _check_types_return(self, result: Any) -> Union[None, GeneratorWrapper]: + def _check_types_return(self, result: Any) -> GeneratorWrapper | None: if self.func.signature.return_annotation is inspect.Signature.empty: raise PedanticTypeCheckException( f'{self.func.err}There should be a type hint for the return type (e.g. None if nothing is returned).') @@ -173,8 +184,10 @@ def _check_types_return(self, result: Any) -> Union[None, GeneratorWrapper]: return GeneratorWrapper( wrapped=result, expected_type=expected_result_type, err_msg=self.func.err, type_vars=self.type_vars) - msg = f'{self.func.err}Type hint of return value is incorrect: Expected type {expected_result_type} ' \ - f'but {result} of type {type(result)} was the return value which does not match.' + msg = ( + f'{self.func.err}Type hint of return value is incorrect: Expected type {expected_result_type} ' + f'but {result} of type {type(result)} was the return value which does not match.' + ) assert_value_matches_type( value=result, type_=expected_result_type, @@ -185,18 +198,18 @@ def _check_types_return(self, result: Any) -> Union[None, GeneratorWrapper]: ) return result - def _assert_param_has_type_annotation(self, param: inspect.Parameter): + def _assert_param_has_type_annotation(self, param: inspect.Parameter) -> None: if param.annotation == inspect.Parameter.empty: raise PedanticTypeCheckException(f'{self.func.err}Parameter "{param.name}" should have a type hint.') def _get_return_value(self) -> Any: if self.func.is_static_method or self.func.is_class_method: return self.func.func(**self.kwargs) - else: - return self.func.func(*self.args, **self.kwargs) + + return self.func.func(*self.args, **self.kwargs) async def _async_get_return_value(self) -> Any: if self.func.is_static_method or self.func.is_class_method: return await self.func.func(**self.kwargs) - else: - return await self.func.func(*self.args, **self.kwargs) + + return await self.func.func(*self.args, **self.kwargs) diff --git a/pedantic/models/generator_wrapper.py b/pedantic/models/generator_wrapper.py index 23252200..b9cf0c54 100644 --- a/pedantic/models/generator_wrapper.py +++ b/pedantic/models/generator_wrapper.py @@ -1,16 +1,21 @@ -from typing import Generator, Any, Dict, Iterable, Iterator, TypeVar +from collections.abc import Generator as ColGenerator +from collections.abc import Iterable as ColIterable +from collections.abc import Iterator as ColIterator +from typing import Any, Generator, Iterable, Iterator, TypeVar # noqa: UP035 -from pedantic.type_checking_logic.check_types import assert_value_matches_type, get_type_arguments, get_base_generic from pedantic.exceptions import PedanticTypeCheckException +from pedantic.type_checking_logic.check_types import assert_value_matches_type, get_base_generic, get_type_arguments class GeneratorWrapper: - def __init__(self, wrapped: Generator, expected_type: Any, err_msg: str, type_vars: Dict[TypeVar, Any]) -> None: + """A wrapper around a generators that handles type checking.""" + + def __init__(self, wrapped: Generator, expected_type: Any, err_msg: str, type_vars: dict[TypeVar, Any]) -> None: # noqa: D107 self._generator = wrapped self._err = err_msg - self._yield_type = None - self._send_type = None - self._return_type = None + self.yield_type = None + self.send_type = None + self.return_type = None self._type_vars = type_vars self._initialized = False @@ -25,15 +30,19 @@ def __next__(self) -> Any: def __getattr__(self, name: str) -> Any: return getattr(self._generator, name) - def throw(self, *args) -> Any: + def throw(self, *args: Any) -> Any: + """Raise an exception in the generator.""" return self._generator.throw(*args) def close(self) -> None: + """Close the generator.""" self._generator.close() - def send(self, obj) -> Any: + def send(self, obj: Any) -> Any: + """Send a value into the generator and check types.""" + if self._initialized: - assert_value_matches_type(value=obj, type_=self._send_type, type_vars=self._type_vars, err=self._err) + assert_value_matches_type(value=obj, type_=self.send_type, type_vars=self._type_vars, err=self._err) else: self._initialized = True @@ -41,13 +50,13 @@ def send(self, obj) -> Any: returned_value = self._generator.send(obj) except StopIteration as ex: assert_value_matches_type(value=ex.value, - type_=self._return_type, + type_=self.return_type, type_vars=self._type_vars, err=self._err) - raise ex + raise assert_value_matches_type(value=returned_value, - type_=self._yield_type, + type_=self.yield_type, type_vars=self._type_vars, err=self._err) return returned_value @@ -55,7 +64,7 @@ def send(self, obj) -> Any: def _set_and_check_return_types(self, expected_return_type: Any) -> Any: base_generic = get_base_generic(cls=expected_return_type) - if base_generic not in [Generator, Iterable, Iterator]: + if base_generic not in (Generator, Iterable, Iterator, ColGenerator, ColIterator, ColIterable): raise PedanticTypeCheckException( f'{self._err}Generator should have type annotation "typing.Generator[]", "typing.Iterator[]" or ' f'"typing.Iterable[]". Got "{expected_return_type}" instead.') @@ -63,11 +72,11 @@ def _set_and_check_return_types(self, expected_return_type: Any) -> Any: result = get_type_arguments(expected_return_type) if len(result) == 1: - self._yield_type = result[0] - elif len(result) == 3: - self._yield_type = result[0] - self._send_type = result[1] - self._return_type = result[2] + self.yield_type = result[0] + elif len(result) == 3: # noqa: PLR2004 + self.yield_type = result[0] + self.send_type = result[1] + self.return_type = result[2] else: raise PedanticTypeCheckException(f'{self._err}Generator should have a type argument. Got: {result}') return result[0] diff --git a/pedantic/type_checking_logic/__init__.py b/pedantic/type_checking_logic/__init__.py index 3113ef6c..5e017c53 100644 --- a/pedantic/type_checking_logic/__init__.py +++ b/pedantic/type_checking_logic/__init__.py @@ -1,2 +1,7 @@ from .check_types import assert_value_matches_type from .resolve_forward_ref import resolve_forward_ref + +__all__ = [ + 'assert_value_matches_type', + 'resolve_forward_ref', +] diff --git a/pedantic/type_checking_logic/check_docstring.py b/pedantic/type_checking_logic/check_docstring.py index f443c4a9..491b2eeb 100644 --- a/pedantic/type_checking_logic/check_docstring.py +++ b/pedantic/type_checking_logic/check_docstring.py @@ -1,14 +1,14 @@ -import sys -import typing -from typing import * # necessary for eval() +from typing import * # noqa: F403 necessary for eval() -from pedantic.type_checking_logic.check_types import get_type_arguments from pedantic.exceptions import PedanticDocstringException from pedantic.models.decorated_function import DecoratedFunction +from pedantic.type_checking_logic.check_types import get_type_arguments +# ruff: noqa: E501, F405 def _check_docstring(decorated_func: DecoratedFunction) -> None: doc = decorated_func.docstring + assert doc is not None, doc # noqa: S101 err = decorated_func.err context = {} @@ -19,7 +19,7 @@ def _check_docstring(decorated_func: DecoratedFunction) -> None: _update_context(context=context, type_=expected_type) if annotation == 'return' and decorated_func.annotations[annotation] is not None: - if len(doc.returns.args) != 2: + if len(doc.returns.args) != 2: # noqa: PLR2004 raise PedanticDocstringException(f'{err} Parsing Error. Only Google style docstrings are supported.') actual_return_type = _parse_documented_type(type_=doc.returns.args[1], context=context, err=err) @@ -28,7 +28,7 @@ def _check_docstring(decorated_func: DecoratedFunction) -> None: raise PedanticDocstringException( f'{err} Documented type is incorrect: Annotation: {expected_type} Documented: {actual_return_type}') elif annotation != 'return': - docstring_param = list(filter(lambda p, a=annotation: p.arg_name == a, doc.params))[0] + docstring_param = next(filter(lambda p, a=annotation: p.arg_name == a, doc.params)) actual_param_type = _parse_documented_type(type_=docstring_param.type_name, context=context, err=err) if expected_type != actual_param_type: @@ -39,35 +39,36 @@ def _check_docstring(decorated_func: DecoratedFunction) -> None: def _assert_docstring_is_complete(func: DecoratedFunction) -> None: """ - >>> def f1(): pass - >>> _assert_docstring_is_complete(DecoratedFunction(f1)) - Traceback (most recent call last): - ... - pedantic.exceptions.PedanticDocstringException: In function f1: - The function should have a docstring! - >>> def f2(): - ... ''' This is a docstring. ''' - ... pass - >>> _assert_docstring_is_complete(DecoratedFunction(f2)) - >>> def f3() -> None: - ... ''' This is a docstring. ''' - ... pass - >>> _assert_docstring_is_complete(DecoratedFunction(f3)) - >>> def f4() -> int: - ... ''' This is a docstring. ''' - ... return 42 - >>> _assert_docstring_is_complete(DecoratedFunction(f4)) - Traceback (most recent call last): - ... - pedantic.exceptions.PedanticDocstringException: In function f4: - The return type is not documented. - >>> def f5() -> int: - ... ''' This is a docstring. - ... Returns: - ... int: a magic number - ... ''' - ... return 42 - >>> _assert_docstring_is_complete(DecoratedFunction(f5)) + Examples: + >>> def f1(): pass + >>> _assert_docstring_is_complete(DecoratedFunction(f1)) + Traceback (most recent call last): + ... + pedantic.exceptions.PedanticDocstringException: In function f1: + The function should have a docstring! + >>> def f2(): + ... ''' This is a docstring. ''' + ... pass + >>> _assert_docstring_is_complete(DecoratedFunction(f2)) + >>> def f3() -> None: + ... ''' This is a docstring. ''' + ... pass + >>> _assert_docstring_is_complete(DecoratedFunction(f3)) + >>> def f4() -> int: + ... ''' This is a docstring. ''' + ... return 42 + >>> _assert_docstring_is_complete(DecoratedFunction(f4)) + Traceback (most recent call last): + ... + pedantic.exceptions.PedanticDocstringException: In function f4: + The return type is not documented. + >>> def f5() -> int: + ... ''' This is a docstring. + ... Returns: + ... int: a magic number + ... ''' + ... return 42 + >>> _assert_docstring_is_complete(DecoratedFunction(f5)) """ if func.raw_doc is None or func.raw_doc == '': raise PedanticDocstringException(f'{func.err} The function should have a docstring!') @@ -89,9 +90,9 @@ def _assert_docstring_is_complete(func: DecoratedFunction) -> None: f'is documented but the function does not return anything.') -def _parse_documented_type(type_: str, context: Dict[str, Any], err: str) -> Any: +def _parse_documented_type(type_: str, context: dict[str, Any], err: str) -> Any: """ - >>> import sys + >>> import sys, typing >>> _parse_documented_type(type_='List[str]', context={}, err='') typing.List[str] >>> _parse_documented_type(type_='float', context={}, err='') @@ -134,44 +135,46 @@ def _parse_documented_type(type_: str, context: Dict[str, Any], err: str) -> Any f'"{type_.replace("typing.", "")}" in the docstring') try: - return eval(type_, globals(), context) - except NameError: - possible_meant_types = [t for t in context.keys() if isinstance(t, str)] + return eval(type_, globals(), context) # noqa: S307 + except NameError as ex: + possible_meant_types = [t for t in context if isinstance(t, str)] if len(possible_meant_types) > 1: msg = f' Maybe you meant one of the following: {possible_meant_types}' elif len(possible_meant_types) == 1: msg = f' Maybe you meant "{possible_meant_types[0]}"' else: msg = '' - raise PedanticDocstringException(f'{err}Documented type "{type_}" was not found.{msg}') + raise PedanticDocstringException(f'{err}Documented type "{type_}" was not found.{msg}') from ex -def _update_context(context: Dict[str, Any], type_: Any) -> Dict[str, Any]: +def _update_context(context: dict[str, Any], type_: Any) -> dict[str, Any]: """ - >>> from typing import List, Union, Optional, Callable - >>> _update_context(type_=None, context={}) - {} - >>> _update_context(type_=None, context={'a': 1, 'b': 2}) - {'a': 1, 'b': 2} - >>> _update_context(type_=float, context={}) - {'float': } - >>> _update_context(type_=List[str], context={}) - {'str': } - >>> _update_context(type_=List[List[bool]], context={}) - {'bool': } - >>> _update_context(type_=Union[int, float, str], context={}) if sys.version_info < (3, 14) else {'int': int, 'float': float, 'str': str} - {'int': , 'float': , 'str': } - >>> {'Union': Union[int, float, str]} == _update_context(type_=Union[int, float, str], context={}) if sys.version_info >= (3, 14) else True - True - >>> _update_context(type_=Callable[[int, bool, str], float], context={}) - {'int': , 'bool': , 'str': , 'float': } - >>> _update_context(type_=Optional[List[Dict[str, float]]], context={}) - {'str': , 'float': , 'NoneType': } - >>> _update_context(type_=Union[List[Dict[str, float]], None], context={}) - {'str': , 'float': , 'NoneType': } - >>> _update_context(type_='MyClass', context={}) - {'MyClass': 'MyClass'} - >>> + Examples: + >>> import sys + >>> from typing import List, Union, Optional, Callable + >>> _update_context(type_=None, context={}) + {} + >>> _update_context(type_=None, context={'a': 1, 'b': 2}) + {'a': 1, 'b': 2} + >>> _update_context(type_=float, context={}) + {'float': } + >>> _update_context(type_=List[str], context={}) + {'str': } + >>> _update_context(type_=List[List[bool]], context={}) + {'bool': } + >>> _update_context(type_=Union[int, float, str], context={}) if sys.version_info < (3, 14) else {'int': int, 'float': float, 'str': str} # noqa: E501 + {'int': , 'float': , 'str': } + >>> {'Union': Union[int, float, str]} == _update_context(type_=Union[int, float, str], context={}) if sys.version_info >= (3, 14) else True + True + >>> _update_context(type_=Callable[[int, bool, str], float], context={}) + {'int': , 'bool': , 'str': , 'float': } + >>> _update_context(type_=Optional[List[Dict[str, float]]], context={}) + {'str': , 'float': , 'NoneType': } + >>> _update_context(type_=Union[List[Dict[str, float]], None], context={}) + {'str': , 'float': , 'NoneType': } + >>> _update_context(type_='MyClass', context={}) + {'MyClass': 'MyClass'} + >>> """ if isinstance(type_, str): diff --git a/pedantic/type_checking_logic/check_generic_classes.py b/pedantic/type_checking_logic/check_generic_classes.py index d0904a6b..e26145d6 100644 --- a/pedantic/type_checking_logic/check_generic_classes.py +++ b/pedantic/type_checking_logic/check_generic_classes.py @@ -1,43 +1,43 @@ import inspect -from typing import Any, Generic, Dict +from typing import Any, Generic +from pedantic.constants import ATTR_NAME_GENERIC_INSTANCE_ALREADY_CHECKED, TypeVar from pedantic.exceptions import PedanticTypeVarMismatchException from pedantic.type_checking_logic.check_types import get_type_arguments -from pedantic.constants import TypeVar, ATTR_NAME_GENERIC_INSTANCE_ALREADY_CHECKED -def check_instance_of_generic_class_and_get_type_vars(instance: Any) -> Dict[TypeVar, Any]: +def check_instance_of_generic_class_and_get_type_vars(instance: Any) -> dict[TypeVar, Any]: """ - >>> from typing import TypeVar, Generic, List - >>> T = TypeVar('T') - >>> class A(Generic[T]): pass - >>> a = A() # would normally raise an error due to _assert_constructor_called_with_generics, but not in doctest - >>> check_instance_of_generic_class_and_get_type_vars(a) - {} - >>> b = A[int]() - >>> check_instance_of_generic_class_and_get_type_vars(b) - {~T: } - >>> c = A[List[int]]() - >>> check_instance_of_generic_class_and_get_type_vars(c) - {~T: typing.List[int]} - >>> S = TypeVar('S') - >>> class B(Generic[T, S]): pass - >>> d = B() - >>> check_instance_of_generic_class_and_get_type_vars(d) - {} - >>> e = B[int]() - Traceback (most recent call last): - ... - TypeError: Too few ...; actual 1, expect... 2 - >>> f = B[int, float]() - >>> check_instance_of_generic_class_and_get_type_vars(f) - {~T: , ~S: } - >>> class C(B): pass - >>> g = C() - >>> check_instance_of_generic_class_and_get_type_vars(g) - {} + >>> from typing import TypeVar, Generic, List + >>> T = TypeVar('T') + >>> class A(Generic[T]): pass + >>> a = A() # would normally raise an error due to _assert_constructor_called_with_generics, but not in doctest + >>> check_instance_of_generic_class_and_get_type_vars(a) + {} + >>> b = A[int]() + >>> check_instance_of_generic_class_and_get_type_vars(b) + {~T: } + >>> c = A[List[int]]() + >>> check_instance_of_generic_class_and_get_type_vars(c) + {~T: typing.List[int]} + >>> S = TypeVar('S') + >>> class B(Generic[T, S]): pass + >>> d = B() + >>> check_instance_of_generic_class_and_get_type_vars(d) + {} + >>> e = B[int]() + Traceback (most recent call last): + ... + TypeError: Too few ...; actual 1, expect... 2 + >>> f = B[int, float]() + >>> check_instance_of_generic_class_and_get_type_vars(f) + {~T: , ~S: } + >>> class C(B): pass + >>> g = C() + >>> check_instance_of_generic_class_and_get_type_vars(g) + {} """ - type_vars = dict() + type_vars = {} _assert_constructor_called_with_generics(instance=instance) # The information I need is set after the object construction in the __orig_class__ attribute. @@ -56,26 +56,27 @@ def check_instance_of_generic_class_and_get_type_vars(instance: Any) -> Dict[Typ def _assert_constructor_called_with_generics(instance: Any) -> None: """ - This is very hacky. Therefore, it is kind of non-aggressive and raises only an error if is sure. - - >>> from typing import TypeVar, Generic, List - >>> T = TypeVar('T') - >>> class A(Generic[T]): pass - >>> a = A() # would normally raise an error due to _assert_constructor_called_with_generics, but not in doctest - >>> _assert_constructor_called_with_generics(a) - >>> b = A[int]() - >>> _assert_constructor_called_with_generics(b) - >>> c = A[List[int]]() - >>> _assert_constructor_called_with_generics(c) - >>> S = TypeVar('S') - >>> class B(Generic[T, S]): pass - >>> d = B() - >>> _assert_constructor_called_with_generics(d) - >>> f = B[int, float]() - >>> _assert_constructor_called_with_generics(f) - >>> class C(B): pass - >>> g = C() - >>> _assert_constructor_called_with_generics(g) + This is very hacky. Therefore, it is kind of non-aggressive and raises only an error if is sure. + + Examples: + >>> from typing import TypeVar, Generic, List + >>> T = TypeVar('T') + >>> class A(Generic[T]): pass + >>> a = A() # would normally raise an error due to _assert_constructor_called_with_generics, but not in doctest + >>> _assert_constructor_called_with_generics(a) + >>> b = A[int]() + >>> _assert_constructor_called_with_generics(b) + >>> c = A[List[int]]() + >>> _assert_constructor_called_with_generics(c) + >>> S = TypeVar('S') + >>> class B(Generic[T, S]): pass + >>> d = B() + >>> _assert_constructor_called_with_generics(d) + >>> f = B[int, float]() + >>> _assert_constructor_called_with_generics(f) + >>> class C(B): pass + >>> g = C() + >>> _assert_constructor_called_with_generics(g) """ if hasattr(instance, ATTR_NAME_GENERIC_INSTANCE_ALREADY_CHECKED): @@ -111,28 +112,29 @@ def _assert_constructor_called_with_generics(instance: Any) -> None: def is_instance_of_generic_class(instance: Any) -> bool: """ - >>> class A: pass - >>> a = A() - >>> is_instance_of_generic_class(a) - False - >>> from typing import TypeVar, Generic - >>> T = TypeVar('T') - >>> class B(Generic[T]): pass - >>> b = B() - >>> is_instance_of_generic_class(b) - True - >>> b2 = B[int]() - >>> is_instance_of_generic_class(b2) - True + >>> class A: pass + >>> a = A() + >>> is_instance_of_generic_class(a) + False + >>> from typing import TypeVar, Generic + >>> T = TypeVar('T') + >>> class B(Generic[T]): pass + >>> b = B() + >>> is_instance_of_generic_class(b) + True + >>> b2 = B[int]() + >>> is_instance_of_generic_class(b2) + True """ return Generic in instance.__class__.__bases__ def _remove_comments_and_spaces_from_src_line(line: str) -> str: """ - >>> _remove_comments_and_spaces_from_src_line('a = 42 # this is a comment') - 'a=42' - >>> _remove_comments_and_spaces_from_src_line('m = MyClass[Parent](a=Child1())') - 'm=MyClass[Parent](a=Child1())' + Example: + >>> _remove_comments_and_spaces_from_src_line('a = 42 # this is a comment') + 'a=42' + >>> _remove_comments_and_spaces_from_src_line('m = MyClass[Parent](a=Child1())') + 'm=MyClass[Parent](a=Child1())' """ - return line.split('#')[0].replace(' ', '') + return line.split('#', maxsplit=1)[0].replace(' ', '') diff --git a/pedantic/type_checking_logic/check_types.py b/pedantic/type_checking_logic/check_types.py index 31f70540..1e8bcc06 100644 --- a/pedantic/type_checking_logic/check_types.py +++ b/pedantic/type_checking_logic/check_types.py @@ -1,27 +1,29 @@ """Idea is taken from: https://stackoverflow.com/a/55504010/10975692""" +import collections import inspect -import sys import types import typing -from io import BytesIO, StringIO, BufferedWriter, TextIOWrapper -from typing import Any, Dict, Iterable, ItemsView, Callable, Optional, Tuple, Mapping, TypeVar, NewType, \ - _ProtocolMeta -import collections +from io import BufferedWriter, BytesIO, StringIO, TextIOWrapper +from typing import Any, Callable, Dict, ItemsView, Iterable, Mapping, NewType, Tuple, TypeVar, _ProtocolMeta +from pedantic.constants import TYPE_VAR_SELF +from pedantic.constants import TypeVar as TypeVar_ +from pedantic.exceptions import PedanticException, PedanticTypeCheckException, PedanticTypeVarMismatchException from pedantic.type_checking_logic.resolve_forward_ref import resolve_forward_ref -from pedantic.constants import TypeVar as TypeVar_, TYPE_VAR_SELF -from pedantic.exceptions import PedanticTypeCheckException, PedanticTypeVarMismatchException, PedanticException - - -def assert_value_matches_type( - value: Any, - type_: Any, - err: str, - type_vars: Dict[TypeVar_, Any], - key: Optional[str] = None, - msg: Optional[str] = None, - context: Dict[str, Any] = None, + +# ruff: noqa: UP006, UP035 + +def assert_value_matches_type( # noqa: PLR0913 + value: Any, + type_: Any, + err: str, + type_vars: Dict[TypeVar_, Any], + key: str | None = None, + msg: str | None = None, + context: Dict[str, Any] | None = None, ) -> None: + """Checks that the given value matches the given type.""" + if not _check_type(value=value, type_=type_, err=err, type_vars=type_vars, context=context): t = type(value) value = f'{key}={value}' if key is not None else str(value) @@ -32,97 +34,99 @@ def assert_value_matches_type( raise PedanticTypeCheckException(msg) -def _check_type(value: Any, type_: Any, err: str, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] = None) -> bool: +def _check_type( + value: Any, type_: Any, err: str, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] | None = None, +) -> bool: """ - >>> from typing import List, Union, Optional, Callable, Any - >>> _check_type(5, int, '', {}) - True - >>> _check_type(5, float, '', {}) - False - >>> _check_type('hi', str, '', {}) - True - >>> _check_type(None, str, '', {}) - False - >>> _check_type(None, Any, '', {}) - True - >>> _check_type(None, None, '', {}) - True - >>> _check_type(5, Any, '', {}) - True - >>> _check_type(3.1415, float, '', {}) - True - >>> _check_type([1, 2, 3, 4], List[int], '', {}) - True - >>> _check_type([1, 2, 3.0, 4], List[int], '', {}) - False - >>> _check_type([1, 2, 3.0, 4], List[float], '', {}) - False - >>> _check_type([1, 2, 3.0, 4], List[Union[float, int]], '', {}) - True - >>> _check_type([[True, False], [False], [True], []], List[List[bool]], '', {}) - True - >>> _check_type([[True, False, 1], [False], [True], []], List[List[bool]], '', {}) - False - >>> _check_type(5, Union[int, float, bool], '', {}) - True - >>> _check_type(5.0, Union[int, float, bool], '', {}) - True - >>> _check_type(False, Union[int, float, bool], '', {}) - True - >>> _check_type('5', Union[int, float, bool], '', {}) - False - >>> def f(a: int, b: bool, c: str) -> float: pass - >>> _check_type(f, Callable[[int, bool, str], float], '', {}) - True - >>> _check_type(None, Optional[List[Dict[str, float]]], '', {}) - True - >>> _check_type([{'a': 1.2, 'b': 3.4}], Optional[List[Dict[str, float]]], '', {}) - True - >>> _check_type([{'a': 1.2, 'b': 3}], Optional[List[Dict[str, float]]], '', {}) - False - >>> _check_type({'a': 1.2, 'b': 3.4}, Optional[List[Dict[str, float]]], '', {}) - False - >>> _check_type([{'a': 1.2, 7: 3.4}], Optional[List[Dict[str, float]]], '', {}) - False - >>> class MyClass: pass - >>> _check_type(MyClass(), 'MyClass', '', {}) - True - >>> _check_type(MyClass(), 'MyClas', '', {}) - False - >>> _check_type([1, 2, 3], list, '', {}) - Traceback (most recent call last): - ... - pedantic.exceptions.PedanticTypeCheckException: Missing type arguments - >>> _check_type((1, 2, 3), tuple, '', {}) - Traceback (most recent call last): - ... - pedantic.exceptions.PedanticTypeCheckException: Missing type arguments - >>> _check_type({1: 1.0, 2: 2.0, 3: 3.0}, dict, '', {}) - Traceback (most recent call last): - ... - pedantic.exceptions.PedanticTypeCheckException: Missing type arguments + >>> from typing import List, Union, Optional, Callable, Any + >>> _check_type(5, int, '', {}) + True + >>> _check_type(5, float, '', {}) + False + >>> _check_type('hi', str, '', {}) + True + >>> _check_type(None, str, '', {}) + False + >>> _check_type(None, Any, '', {}) + True + >>> _check_type(None, None, '', {}) + True + >>> _check_type(5, Any, '', {}) + True + >>> _check_type(3.1415, float, '', {}) + True + >>> _check_type([1, 2, 3, 4], List[int], '', {}) + True + >>> _check_type([1, 2, 3.0, 4], List[int], '', {}) + False + >>> _check_type([1, 2, 3.0, 4], List[float], '', {}) + False + >>> _check_type([1, 2, 3.0, 4], List[Union[float, int]], '', {}) + True + >>> _check_type([[True, False], [False], [True], []], List[List[bool]], '', {}) + True + >>> _check_type([[True, False, 1], [False], [True], []], List[List[bool]], '', {}) + False + >>> _check_type(5, Union[int, float, bool], '', {}) + True + >>> _check_type(5.0, Union[int, float, bool], '', {}) + True + >>> _check_type(False, Union[int, float, bool], '', {}) + True + >>> _check_type('5', Union[int, float, bool], '', {}) + False + >>> def f(a: int, b: bool, c: str) -> float: pass + >>> _check_type(f, Callable[[int, bool, str], float], '', {}) + True + >>> _check_type(None, Optional[List[Dict[str, float]]], '', {}) + True + >>> _check_type([{'a': 1.2, 'b': 3.4}], Optional[List[Dict[str, float]]], '', {}) + True + >>> _check_type([{'a': 1.2, 'b': 3}], Optional[List[Dict[str, float]]], '', {}) + False + >>> _check_type({'a': 1.2, 'b': 3.4}, Optional[List[Dict[str, float]]], '', {}) + False + >>> _check_type([{'a': 1.2, 7: 3.4}], Optional[List[Dict[str, float]]], '', {}) + False + >>> class MyClass: pass + >>> _check_type(MyClass(), 'MyClass', '', {}) + True + >>> _check_type(MyClass(), 'MyClas', '', {}) + False + >>> _check_type([1, 2, 3], list, '', {}) + Traceback (most recent call last): + ... + pedantic.exceptions.PedanticTypeCheckException: Missing type arguments + >>> _check_type((1, 2, 3), tuple, '', {}) + Traceback (most recent call last): + ... + pedantic.exceptions.PedanticTypeCheckException: Missing type arguments + >>> _check_type({1: 1.0, 2: 2.0, 3: 3.0}, dict, '', {}) + Traceback (most recent call last): + ... + pedantic.exceptions.PedanticTypeCheckException: Missing type arguments """ if type_ is None: return value == type_ - elif isinstance(type_, str): + if isinstance(type_, str): class_name = value.__class__.__name__ base_class_name = value.__class__.__base__.__name__ - return class_name == type_ or base_class_name == type_ + return type_ in (class_name, base_class_name) try: return _is_instance(obj=value, type_=type_, type_vars=type_vars, context=context) except PedanticTypeCheckException as ex: - raise PedanticTypeCheckException(f'{err} {ex}') + raise PedanticTypeCheckException(f'{err} {ex}') from ex except PedanticTypeVarMismatchException as ex: - raise PedanticTypeVarMismatchException(f'{err} {ex}') + raise PedanticTypeVarMismatchException(f'{err} {ex}') from ex except (AttributeError, Exception) as ex: raise PedanticTypeCheckException( f'{err}An error occurred during type hint checking. Value: {value} Annotation: ' - f'{type_} Mostly this is caused by an incorrect type annotation. Details: {ex} ') + f'{type_} Mostly this is caused by an incorrect type annotation. Details: {ex} ') from ex -def _is_instance(obj: Any, type_: Any, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] = None) -> bool: +def _is_instance(obj: Any, type_: Any, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] | None = None) -> bool: # noqa: PLR0915, PLR0912, PLR0911, C901 context = context or {} if not _has_required_type_arguments(type_): @@ -142,20 +146,32 @@ def _is_instance(obj: Any, type_: Any, type_vars: Dict[TypeVar_, Any], context: validator = _SPECIAL_INSTANCE_CHECKERS[name] return validator(obj, type_, type_vars, context) + if type_.__module__ == 'collections.abc': + if _is_generic(type_): + origin = get_base_generic(type_) + else: + origin = type_ + + name = _get_name(origin) + + if name in _SPECIAL_INSTANCE_CHECKERS: + validator = _SPECIAL_INSTANCE_CHECKERS[name] + return validator(obj, type_, type_vars, context) + if hasattr(types, 'UnionType') and isinstance(type_, types.UnionType): return _instancecheck_union(value=obj, type_=type_, type_vars=type_vars, context=context) if type_ == typing.BinaryIO: return isinstance(obj, (BytesIO, BufferedWriter)) - elif type_ == typing.TextIO: + if type_ == typing.TextIO: return isinstance(obj, (StringIO, TextIOWrapper)) - elif type_ == typing.NoReturn: + if type_ == typing.NoReturn: return False # we expect an Exception here, but got a value - elif hasattr(typing, 'Never') and type_ == typing.Never: # since Python 3.11 + if hasattr(typing, 'Never') and type_ == typing.Never: # since Python 3.11 return False # we expect an Exception here, but got a value - elif hasattr(typing, 'LiteralString') and type_ == typing.LiteralString: # since Python 3.11 + if hasattr(typing, 'LiteralString') and type_ == typing.LiteralString: # since Python 3.11 return isinstance(obj, str) # we cannot distinguish str and LiteralString at runtime - elif hasattr(typing, 'Self') and type_ == typing.Self: # since Python 3.11 + if hasattr(typing, 'Self') and type_ == typing.Self: # since Python 3.11 t = type_vars[TYPE_VAR_SELF] if t is None: @@ -182,13 +198,12 @@ def _is_instance(obj: Any, type_: Any, type_vars: Dict[TypeVar_, Any], context: if type_.__contravariant__: if not _is_subtype(sub_type=other, super_type=obj.__class__): raise PedanticTypeVarMismatchException( - f'For TypeVar {type_} exists a type conflict: value {obj} has type {type(obj)} but TypeVar {type_} ' - f'was previously matched to type {other}') - else: - if not _is_instance(obj=obj, type_=other, type_vars=type_vars, context=context): - raise PedanticTypeVarMismatchException( - f'For TypeVar {type_} exists a type conflict: value {obj} has type {type(obj)} but TypeVar {type_} ' - f'was previously matched to type {other}') + f'For TypeVar {type_} exists a type conflict: value {obj} has type {type(obj)} ' + f'but TypeVar {type_} was previously matched to type {other}') + elif not _is_instance(obj=obj, type_=other, type_vars=type_vars, context=context): + raise PedanticTypeVarMismatchException( + f'For TypeVar {type_} exists a type conflict: value {obj} has type {type(obj)} ' + f'but TypeVar {type_} was previously matched to type {other}') type_vars[type_] = type(obj) return True @@ -196,7 +211,10 @@ def _is_instance(obj: Any, type_: Any, type_vars: Dict[TypeVar_, Any], context: if hasattr(typing, 'Unpack') and getattr(type_, '__origin__', None) == typing.Unpack: return True # it's too hard to check that at the moment - if _is_generic(type_): + if _is_generic(type_) and hasattr(type_, '__origin__'): + if isinstance(type_, types.GenericAlias): + return _is_instance(obj=obj, type_=convert_to_typing_types(type_), type_vars=type_vars, context=context) + python_type = type_.__origin__ if not isinstance(obj, python_type): @@ -209,7 +227,8 @@ def _is_instance(obj: Any, type_: Any, type_vars: Dict[TypeVar_, Any], context: validator = _ORIGIN_TYPE_CHECKERS[base] return validator(obj, type_args, type_vars, context) - assert base.__base__ == typing.Generic, f'Unknown base: {base}' + if base.__base__ != typing.Generic: + raise RuntimeError(f'Unknown base: {base}') return isinstance(obj, base) if _is_forward_ref(type_=type_): @@ -225,10 +244,11 @@ def _is_instance(obj: Any, type_: Any, type_vars: Dict[TypeVar_, Any], context: else: return False - if not obj._asdict().keys() == field_types.keys(): + if obj._asdict().keys() != field_types.keys(): return False - return all([_is_instance(obj=obj._asdict()[k], type_=v, type_vars=type_vars, context=context) for k, v in field_types.items()]) + return all(_is_instance(obj=obj._asdict()[k], type_=v, type_vars=type_vars, context=context) + for k, v in field_types.items()) if type_ in {list, set, dict, frozenset, tuple, type}: raise PedanticTypeCheckException('Missing type arguments') @@ -239,28 +259,28 @@ def _is_instance(obj: Any, type_: Any, type_vars: Dict[TypeVar_, Any], context: try: return isinstance(obj, type_) except TypeError: - if type(type_) == _ProtocolMeta: + if isinstance(type_, _ProtocolMeta): return True # we do not check this raise def _is_forward_ref(type_: Any) -> bool: - return hasattr(typing, 'ForwardRef') and isinstance(type_, typing.ForwardRef) or \ - hasattr(typing, '_ForwardRef') and isinstance(type_, typing._ForwardRef) + return (hasattr(typing, 'ForwardRef') and isinstance(type_, typing.ForwardRef)) or \ + (hasattr(typing, '_ForwardRef') and isinstance(type_, typing._ForwardRef)) # noqa: SLF001 def _is_type_new_type(type_: Any) -> bool: """ - >>> from typing import Tuple, Callable, Any, List, NewType - >>> _is_type_new_type(int) - False - >>> UserId = NewType('UserId', int) - >>> _is_type_new_type(UserId) - True + >>> from typing import Tuple, Callable, Any, List, NewType + >>> _is_type_new_type(int) + False + >>> UserId = NewType('UserId', int) + >>> _is_type_new_type(UserId) + True """ - if type(type_) == typing.NewType: + if isinstance(type_, typing.NewType): return True return type_.__qualname__ == NewType('name', int).__qualname__ # arguments of NewType() are arbitrary here @@ -268,105 +288,127 @@ def _is_type_new_type(type_: Any) -> bool: def _get_name(cls: Any) -> str: """ - >>> from typing import Tuple, Callable, Any, List - >>> _get_name(int) - 'int' - >>> _get_name(Any) - 'Any' - >>> _get_name(List) - 'List' - >>> _get_name(List[int]) - 'List' - >>> _get_name(List[Any]) - 'List' - >>> _get_name(Tuple) - 'Tuple' - >>> _get_name(Tuple[int, float]) - 'Tuple' - >>> _get_name(Tuple[Any, ...]) - 'Tuple' - >>> _get_name(Callable) - 'Callable' + >>> from typing import Tuple, Callable, Any, List + >>> _get_name(int) + 'int' + >>> _get_name(Any) + 'Any' + >>> _get_name(List) + 'List' + >>> _get_name(List[int]) + 'List' + >>> _get_name(List[Any]) + 'List' + >>> _get_name(Tuple) + 'Tuple' + >>> _get_name(Tuple[int, float]) + 'Tuple' + >>> _get_name(Tuple[Any, ...]) + 'Tuple' + >>> _get_name(Callable) + 'Callable' """ if hasattr(cls, '_name'): return cls._name - elif hasattr(cls, '__name__'): + if hasattr(cls, '__name__'): return cls.__name__ - else: - return type(cls).__name__[1:] + + return type(cls).__name__[1:] def _is_generic(cls: Any) -> bool: """ - >>> from typing import List, Callable, Any, Union - >>> _is_generic(int) - False - >>> _is_generic(List) - True - >>> _is_generic(List[int]) - True - >>> _is_generic(List[Any]) - True - >>> _is_generic(List[List[int]]) - True - >>> _is_generic(Any) - False - >>> _is_generic(Tuple) - True - >>> _is_generic(Tuple[Any, ...]) - True - >>> _is_generic(Tuple[str, float, int]) - True - >>> _is_generic(Callable) - True - >>> _is_generic(Callable[[int], int]) - True - >>> _is_generic(Union) - True - >>> _is_generic(Union[int, float, str]) - True - >>> _is_generic(Dict) - True - >>> _is_generic(Dict[str, str]) - True + >>> from typing import List, Callable, Any, Union, Generic, TypeVar + >>> from collections.abc import Callable as ColCallable + >>> _is_generic(int) + False + >>> _is_generic(List) + True + >>> _is_generic(list) + True + >>> _is_generic(List[int]) + True + >>> _is_generic(list[int]) + True + >>> _is_generic(List[Any]) + True + >>> _is_generic(List[List[int]]) + True + >>> _is_generic(Any) + False + >>> _is_generic(Tuple) + True + >>> _is_generic(Tuple[Any, ...]) + True + >>> _is_generic(Tuple[str, float, int]) + True + >>> _is_generic(Callable) + True + >>> _is_generic(ColCallable) + True + >>> _is_generic(Callable[[int], int]) + True + >>> _is_generic(ColCallable[[int], int]) + True + >>> _is_generic(Union) + True + >>> _is_generic(Union[int, float, str]) + True + >>> _is_generic(Dict) + True + >>> _is_generic(Dict[str, str]) + True + >>> T = TypeVar("T") + >>> class A(Generic[T]): pass + >>> class B(A[int]): pass + >>> _is_generic(A) + True + >>> _is_generic(B) + True """ - if hasattr(typing, '_SpecialGenericAlias') and isinstance(cls, typing._SpecialGenericAlias): - return True - elif isinstance(cls, typing._GenericAlias): + origin = typing.get_origin(cls) + + # Parameterized generics like List[int], Callable[[...], ...], etc. + if origin is not None: return True - elif isinstance(cls, typing._SpecialForm): - return cls not in {Any} - elif cls is typing.Union or type(cls) is typing.Union: # for python >= 3.14 Union is no longer a typing._SpecialForm + + # Bare generics like List, Dict, Tuple, Callable, Union + if isinstance(cls, typing._SpecialForm): # noqa: SLF001 still needed for e.g. Union + return cls is not Any + + # collections.abc.Callable and similar + if hasattr(cls, '__class_getitem__'): # noqa: SIM103 return True + return False def _has_required_type_arguments(cls: Any) -> bool: """ - >>> from typing import List, Callable, Tuple, Any - >>> _has_required_type_arguments(int) - True - >>> _has_required_type_arguments(List) - False - >>> _has_required_type_arguments(List[int]) - True - >>> _has_required_type_arguments(List[List[int]]) - True - >>> _has_required_type_arguments(Tuple) - False - >>> _has_required_type_arguments(Tuple[int]) - True - >>> _has_required_type_arguments(Tuple[int, float, str]) - True - >>> _has_required_type_arguments(Callable) - False - >>> _has_required_type_arguments(Callable[[int, float], Tuple[float, str]]) - True - >>> _has_required_type_arguments(Callable[..., Any]) - True - >>> _has_required_type_arguments(Callable[[typing.Any], Tuple[typing.Any, ...]],) - True + >>> from typing import List, Callable, Tuple, Any + >>> _has_required_type_arguments(int) + True + >>> _has_required_type_arguments(List) + False + >>> _has_required_type_arguments(List[int]) + True + >>> _has_required_type_arguments(List[List[int]]) + True + >>> _has_required_type_arguments(Tuple) + False + >>> _has_required_type_arguments(Tuple[int]) + True + >>> _has_required_type_arguments(Tuple[int, float, str]) + True + >>> _has_required_type_arguments(Callable) + False + >>> _has_required_type_arguments(Callable[[int, float], Tuple[float, str]]) + True + >>> _has_required_type_arguments(Callable[..., Any]) + True + >>> _has_required_type_arguments(Callable[[typing.Any], Tuple[typing.Any, ...]],) + True """ base: str = _get_name(cls=cls) @@ -374,54 +416,55 @@ def _has_required_type_arguments(cls: Any) -> bool: if base in NUM_OF_REQUIRED_TYPE_ARGS_EXACT: return NUM_OF_REQUIRED_TYPE_ARGS_EXACT[base] == num_type_args - elif base in NUM_OF_REQUIRED_TYPE_ARGS_MIN: + if base in NUM_OF_REQUIRED_TYPE_ARGS_MIN: return NUM_OF_REQUIRED_TYPE_ARGS_MIN[base] <= num_type_args return True def get_type_arguments(cls: Any) -> Tuple[Any, ...]: - """ Works similar to typing.args() - >>> from typing import Tuple, List, Union, Callable, Any, NewType, TypeVar, Optional, Awaitable, Coroutine - >>> get_type_arguments(int) - () - >>> get_type_arguments(List[float]) - (,) - >>> get_type_arguments(List[int]) - (,) - >>> UserId = NewType('UserId', int) - >>> get_type_arguments(List[UserId]) - (pedantic.type_checking_logic.check_types.UserId,) - >>> get_type_arguments(List) - () - >>> T = TypeVar('T') - >>> get_type_arguments(List[T]) - (~T,) - >>> get_type_arguments(List[List[int]]) - (typing.List[int],) - >>> get_type_arguments(List[List[List[int]]]) - (typing.List[typing.List[int]],) - >>> get_type_arguments(List[Tuple[float, str]]) - (typing.Tuple[float, str],) - >>> get_type_arguments(List[Tuple[Any, ...]]) - (typing.Tuple[typing.Any, ...],) - >>> get_type_arguments(Union[str, float, int]) - (, , ) - >>> get_type_arguments(Union[str, float, List[int], int]) - (, , typing.List[int], ) - >>> get_type_arguments(Callable) - () - >>> get_type_arguments(Callable[[int, float], Tuple[float, str]]) - ([, ], typing.Tuple[float, str]) - >>> get_type_arguments(Callable[..., str]) - (Ellipsis, ) - >>> get_type_arguments(Optional[int]) - (, ) - >>> get_type_arguments(str | int) - (, ) - >>> get_type_arguments(Awaitable[str]) - (,) - >>> get_type_arguments(Coroutine[int, bool, str]) - (, , ) + """ + Works similar to typing.args() + >>> from typing import Tuple, List, Union, Callable, Any, NewType, TypeVar, Optional, Awaitable, Coroutine + >>> get_type_arguments(int) + () + >>> get_type_arguments(List[float]) + (,) + >>> get_type_arguments(List[int]) + (,) + >>> UserId = NewType('UserId', int) + >>> get_type_arguments(List[UserId]) + (pedantic.type_checking_logic.check_types.UserId,) + >>> get_type_arguments(List) + () + >>> T = TypeVar('T') + >>> get_type_arguments(List[T]) + (~T,) + >>> get_type_arguments(List[List[int]]) + (typing.List[int],) + >>> get_type_arguments(List[List[List[int]]]) + (typing.List[typing.List[int]],) + >>> get_type_arguments(List[Tuple[float, str]]) + (typing.Tuple[float, str],) + >>> get_type_arguments(List[Tuple[Any, ...]]) + (typing.Tuple[typing.Any, ...],) + >>> get_type_arguments(Union[str, float, int]) + (, , ) + >>> get_type_arguments(Union[str, float, List[int], int]) + (, , typing.List[int], ) + >>> get_type_arguments(Callable) + () + >>> get_type_arguments(Callable[[int, float], Tuple[float, str]]) + ([, ], typing.Tuple[float, str]) + >>> get_type_arguments(Callable[..., str]) + (Ellipsis, ) + >>> get_type_arguments(Optional[int]) + (, ) + >>> get_type_arguments(str | int) + (, ) + >>> get_type_arguments(Awaitable[str]) + (,) + >>> get_type_arguments(Coroutine[int, bool, str]) + (, , ) """ result = () @@ -439,7 +482,7 @@ def get_type_arguments(cls: Any) -> Tuple[Any, ...]: if hasattr(types, 'UnionType') and isinstance(cls, types.UnionType): return result - elif '[' in str(cls): + if '[' in str(cls): return result return () @@ -447,41 +490,41 @@ def get_type_arguments(cls: Any) -> Tuple[Any, ...]: def get_base_generic(cls: Any) -> Any: """ - >>> from typing import List, Union, Tuple, Callable, Dict, Set, Awaitable, Coroutine - >>> get_base_generic(List) - typing.List - >>> get_base_generic(List[float]) - typing.List - >>> get_base_generic(List[List[float]]) - typing.List - >>> get_base_generic(List[Union[int, float]]) - typing.List - >>> get_base_generic(Tuple) - typing.Tuple - >>> get_base_generic(Tuple[float, int]) - typing.Tuple - >>> get_base_generic(Tuple[Union[int, float], str]) - typing.Tuple - >>> get_base_generic(Callable[..., int]) - typing.Callable - >>> get_base_generic(Callable[[Union[int, str], float], int]) - typing.Callable - >>> get_base_generic(Dict) - typing.Dict - >>> get_base_generic(Dict[str, str]) - typing.Dict - >>> 'typing.Union' in str(get_base_generic(Union)) # 3.13: typing.Union 3.14: - True - >>> 'typing.Union' in str(get_base_generic(Union[float, int, str])) # 3.13: typing.Union 3.14: - True - >>> get_base_generic(Set) - typing.Set - >>> get_base_generic(Set[int]) - typing.Set - >>> get_base_generic(Awaitable[int]) - typing.Awaitable - >>> get_base_generic(Coroutine[None, None, int]) - typing.Coroutine + >>> from typing import List, Union, Tuple, Callable, Dict, Set, Awaitable, Coroutine + >>> get_base_generic(List) + typing.List + >>> get_base_generic(List[float]) + typing.List + >>> get_base_generic(List[List[float]]) + typing.List + >>> get_base_generic(List[Union[int, float]]) + typing.List + >>> get_base_generic(Tuple) + typing.Tuple + >>> get_base_generic(Tuple[float, int]) + typing.Tuple + >>> get_base_generic(Tuple[Union[int, float], str]) + typing.Tuple + >>> get_base_generic(Callable[..., int]) + typing.Callable + >>> get_base_generic(Callable[[Union[int, str], float], int]) + typing.Callable + >>> get_base_generic(Dict) + typing.Dict + >>> get_base_generic(Dict[str, str]) + typing.Dict + >>> 'typing.Union' in str(get_base_generic(Union)) # 3.13: typing.Union 3.14: + True + >>> 'typing.Union' in str(get_base_generic(Union[float, int, str])) # 3.13: typing.Union 3.14: + True + >>> get_base_generic(Set) + typing.Set + >>> get_base_generic(Set[int]) + typing.Set + >>> get_base_generic(Awaitable[int]) + typing.Awaitable + >>> get_base_generic(Coroutine[None, None, int]) + typing.Coroutine """ origin = cls.__origin__ if hasattr(cls, '__origin__') else None @@ -489,81 +532,85 @@ def get_base_generic(cls: Any) -> Any: if name is not None: return getattr(typing, name) - elif origin is not None and cls is not typing.Union: + if origin is not None and cls is not typing.Union: return origin return cls -def _is_subtype(sub_type: Any, super_type: Any, context: Dict[str, Any] = None) -> bool: +def _is_subtype(sub_type: Any, super_type: Any, context: Dict[str, Any] | None = None) -> bool: # noqa: PLR0911 """ - >>> from typing import Any, List, Callable, Tuple, Union, Optional, Iterable - >>> _is_subtype(float, float) - True - >>> _is_subtype(int, float) - False - >>> _is_subtype(float, int) - False - >>> _is_subtype(int, Any) - True - >>> _is_subtype(Any, int) - False - >>> _is_subtype(Any, Any) - True - >>> _is_subtype(Ellipsis, Ellipsis) - True - >>> _is_subtype(Tuple[float, str], Tuple[float, str]) - True - >>> _is_subtype(Tuple[float], Tuple[float, str]) - False - >>> _is_subtype(Tuple[float, str], Tuple[str]) - False - >>> _is_subtype(Tuple[float, str], Tuple[Any, ...]) - True - >>> _is_subtype(Tuple[Any, ...], Tuple[float, str]) - False - >>> _is_subtype(Tuple[float, str], Tuple[int, ...]) - False - >>> _is_subtype(Tuple[int, str], Tuple[int, ...]) - True - >>> _is_subtype(Tuple[int, ...], Tuple[int, str]) - False - >>> _is_subtype(Tuple[float, str, bool, int], Tuple[Any, ...]) - True - >>> _is_subtype(int, Union[int, float]) - True - >>> _is_subtype(int, Union[str, float]) - False - >>> _is_subtype(List[int], List[Union[int, float]]) - True - >>> _is_subtype(List[Union[int, float]], List[int]) if sys.version_info >= (3, 14) else False - False - >>> class Parent: pass - >>> class Child(Parent): pass - >>> _is_subtype(List[Child], List[Parent]) - True - >>> _is_subtype(List[Parent], List[Child]) - False - >>> _is_subtype(List[int], Iterable[int]) - True - >>> _is_subtype(Iterable[int], List[int]) - False - >>> class MyClass: pass - >>> _is_subtype(MyClass, Union[str, MyClass]) - True - >>> _is_subtype(None, type(None)) - True - >>> _is_subtype(None, Any) - True - >>> _is_subtype(Optional[int], Optional[int]) - True - >>> _is_subtype(Optional[int], Union[int, float, None]) - True - >>> _is_subtype(int | None, int | None) - True - >>> _is_subtype(int, int | None) - True - >>> _is_subtype(int | None, int) - False + Examples: + >>> import sys + >>> from typing import Any, List, Callable, Tuple, Union, Optional, Iterable + >>> _is_subtype(float, float) + True + >>> _is_subtype(int, float) + False + >>> _is_subtype(float, int) + False + >>> _is_subtype(int, Any) + True + >>> _is_subtype(Any, int) + False + >>> _is_subtype(Any, Any) + True + >>> _is_subtype(Ellipsis, Ellipsis) + True + >>> _is_subtype(Tuple[float, str], Tuple[float, str]) + True + >>> _is_subtype(Tuple[float], Tuple[float, str]) + False + >>> _is_subtype(Tuple[float, str], Tuple[str]) + False + >>> _is_subtype(Tuple[float, str], Tuple[Any, ...]) + True + >>> _is_subtype(Tuple[Any, ...], Tuple[float, str]) + False + >>> _is_subtype(Tuple[float, str], Tuple[int, ...]) + False + >>> _is_subtype(Tuple[int, str], Tuple[int, ...]) + True + >>> _is_subtype(Tuple[int, ...], Tuple[int, str]) + False + >>> _is_subtype(Tuple[float, str, bool, int], Tuple[Any, ...]) + True + >>> _is_subtype(int, Union[int, float]) + True + >>> _is_subtype(int, Union[str, float]) + False + >>> _is_subtype(List[int], List[Union[int, float]]) + True + >>> _is_subtype(List[Union[int, float]], List[int]) if sys.version_info >= (3, 14) else False + False + >>> class Parent: pass + >>> class Child(Parent): pass + >>> _is_subtype(List[Child], List[Parent]) + True + >>> _is_subtype(List[Parent], List[Child]) + False + >>> _is_subtype(List[int], Iterable[int]) + True + >>> _is_subtype(Iterable[int], List[int]) + False + >>> class MyClass: pass + >>> _is_subtype(MyClass, Union[str, MyClass]) + True + >>> _is_subtype(None, type(None)) + True + >>> _is_subtype(None, Any) + True + >>> _is_subtype(Optional[int], Optional[int]) + True + >>> _is_subtype(Optional[int], Union[int, float, None]) + True + >>> _is_subtype(int | None, int | None) + True + >>> _is_subtype(int, int | None) + True + >>> _is_subtype(int | None, int) + False + >>> _is_subtype(Optional[int], int) + False """ if sub_type is None: @@ -580,9 +627,9 @@ def _is_subtype(sub_type: Any, super_type: Any, context: Dict[str, Any] = None) if python_sub == typing.Union or isinstance(python_sub, types.UnionType): sub_type_args = get_type_arguments(cls=sub_type) - return all([x in type_args for x in sub_type_args]) + return all(x in type_args for x in sub_type_args) - if any([type(ta) == _ProtocolMeta for ta in type_args]): + if any(isinstance(ta, _ProtocolMeta) for ta in type_args): return True # shortcut return sub_type in type_args @@ -591,13 +638,9 @@ def _is_subtype(sub_type: Any, super_type: Any, context: Dict[str, Any] = None) try: return issubclass(python_sub, python_super) except TypeError: - if type(python_super) == _ProtocolMeta: - return True + return isinstance(python_super, _ProtocolMeta) - return False - if not issubclass(python_sub, python_super): - return False sub_args = get_type_arguments(cls=sub_type) super_args = get_type_arguments(cls=super_type) @@ -605,113 +648,127 @@ def _is_subtype(sub_type: Any, super_type: Any, context: Dict[str, Any] = None) if len(sub_args) != len(super_args) and Ellipsis not in sub_args + super_args: return False - return all(_is_subtype(sub_type=sub_arg, super_type=super_arg, context=context) for sub_arg, super_arg in zip(sub_args, super_args)) + if not issubclass(python_sub, python_super): + return False + + return all(_is_subtype(sub_type=sub_arg, super_type=super_arg, context=context) + for sub_arg, super_arg in zip(sub_args, super_args, strict=False)) def _get_class_of_type_annotation(annotation: Any) -> Any: """ - >>> from typing import Dict, List, Any, Tuple, Callable, Union - >>> _get_class_of_type_annotation(int) - - >>> _get_class_of_type_annotation(Any) - - >>> _get_class_of_type_annotation(Ellipsis) - - >>> _get_class_of_type_annotation(Dict) - - >>> _get_class_of_type_annotation(Dict[str, int]) - - >>> _get_class_of_type_annotation(List) - - >>> _get_class_of_type_annotation(List[int]) - - >>> _get_class_of_type_annotation(Tuple) - - >>> _get_class_of_type_annotation(Tuple[int, int]) - - >>> _get_class_of_type_annotation(Callable[[int], int]) - - >>> _get_class_of_type_annotation(Callable) - + >>> from typing import Dict, List, Any, Tuple, Callable, Union + >>> _get_class_of_type_annotation(int) + + >>> _get_class_of_type_annotation(Any) + + >>> _get_class_of_type_annotation(Ellipsis) + + >>> _get_class_of_type_annotation(Dict) + + >>> _get_class_of_type_annotation(Dict[str, int]) + + >>> _get_class_of_type_annotation(List) + + >>> _get_class_of_type_annotation(List[int]) + + >>> _get_class_of_type_annotation(Tuple) + + >>> _get_class_of_type_annotation(Tuple[int, int]) + + >>> _get_class_of_type_annotation(Callable[[int], int]) + + >>> _get_class_of_type_annotation(Callable) + """ if annotation in [Any, Ellipsis]: return object - elif annotation.__module__ == 'typing' and annotation.__origin__ is not None: + if annotation.__module__ == 'typing' and annotation.__origin__ is not None: return annotation.__origin__ return annotation -def _instancecheck_iterable(iterable: Iterable, type_args: Tuple, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] = None) -> bool: +def _instancecheck_iterable( + iterable: Iterable, type_args: Tuple, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] | None = None, +) -> bool: """ - >>> from typing import List, Any, Union - >>> _instancecheck_iterable([1.0, -4.2, 5.4], (float,), {}) - True - >>> _instancecheck_iterable([1.0, -4.2, 5], (float,), {}) - False - >>> _instancecheck_iterable(['1.0', -4.2, 5], (Any,), {}) - True - >>> _instancecheck_iterable(['1.0', -4.2, 5], (Union[int, float],), {}) - False - >>> _instancecheck_iterable(['1.0', -4.2, 5], (Union[int, float, str],), {}) - True - >>> _instancecheck_iterable([[], [], [[42]], [[]]], (List[int],), {}) - False - >>> _instancecheck_iterable([[], [], [[42]], [[]]], (List[List[int]],), {}) - True - >>> _instancecheck_iterable([[], [], [[42]], [[]]], (List[List[float]],), {}) - False + >>> from typing import List, Any, Union + >>> _instancecheck_iterable([1.0, -4.2, 5.4], (float,), {}) + True + >>> _instancecheck_iterable([1.0, -4.2, 5], (float,), {}) + False + >>> _instancecheck_iterable(['1.0', -4.2, 5], (Any,), {}) + True + >>> _instancecheck_iterable(['1.0', -4.2, 5], (Union[int, float],), {}) + False + >>> _instancecheck_iterable(['1.0', -4.2, 5], (Union[int, float, str],), {}) + True + >>> _instancecheck_iterable([[], [], [[42]], [[]]], (List[int],), {}) + False + >>> _instancecheck_iterable([[], [], [[42]], [[]]], (List[List[int]],), {}) + True + >>> _instancecheck_iterable([[], [], [[42]], [[]]], (List[List[float]],), {}) + False """ type_ = type_args[0] return all(_is_instance(val, type_, type_vars=type_vars, context=context) for val in iterable) -def _instancecheck_generator(generator: typing.Generator, type_args: Tuple, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] = None) -> bool: - from pedantic.models import GeneratorWrapper - - assert isinstance(generator, GeneratorWrapper) - return generator._yield_type == type_args[0] and generator._send_type == type_args[1] and generator._return_type == type_args[2] +def _instancecheck_generator( + generator: typing.Generator, type_args: Tuple, _: Dict[TypeVar_, Any], __: Dict[str, Any] | None = None, +) -> bool: + from pedantic.models import GeneratorWrapper # noqa: PLC0415 must be local due to circular imports + if not isinstance(generator, GeneratorWrapper): + raise TypeError(generator) + return (generator.yield_type == type_args[0] + and generator.send_type == type_args[1] + and generator.return_type == type_args[2]) -def _instancecheck_mapping(mapping: Mapping, type_args: Tuple, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] = None) -> bool: +def _instancecheck_mapping( + mapping: Mapping, type_args: Tuple, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] | None = None, +) -> bool: """ - >>> from typing import Any, Optional - >>> _instancecheck_mapping({0: 1, 1: 2, 2: 3}, (int, Any), {}) - True - >>> _instancecheck_mapping({0: 1, 1: 2, 2: 3}, (int, int), {}) - True - >>> _instancecheck_mapping({0: 1, 1: 2, 2: 3.0}, (int, int), {}) - False - >>> _instancecheck_mapping({0: 1, 1.0: 2, 2: 3}, (int, int), {}) - False - >>> _instancecheck_mapping({0: '1', 1: 2, 2: 3}, (int, int), {}) - False - >>> _instancecheck_mapping({0: 1, 1: 2, None: 3.0}, (int, int), {}) - False - >>> _instancecheck_mapping({0: 1, 1: 2, None: 3.0}, (int, Optional[int]), {}) - False + >>> from typing import Any, Optional + >>> _instancecheck_mapping({0: 1, 1: 2, 2: 3}, (int, Any), {}) + True + >>> _instancecheck_mapping({0: 1, 1: 2, 2: 3}, (int, int), {}) + True + >>> _instancecheck_mapping({0: 1, 1: 2, 2: 3.0}, (int, int), {}) + False + >>> _instancecheck_mapping({0: 1, 1.0: 2, 2: 3}, (int, int), {}) + False + >>> _instancecheck_mapping({0: '1', 1: 2, 2: 3}, (int, int), {}) + False + >>> _instancecheck_mapping({0: 1, 1: 2, None: 3.0}, (int, int), {}) + False + >>> _instancecheck_mapping({0: 1, 1: 2, None: 3.0}, (int, Optional[int]), {}) + False """ return _instancecheck_items_view(mapping.items(), type_args, type_vars=type_vars, context=context) -def _instancecheck_items_view(items_view: ItemsView, type_args: Tuple, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] = None) -> bool: +def _instancecheck_items_view( + items_view: ItemsView, type_args: Tuple, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] | None = None, +) -> bool: """ - >>> from typing import Any, Optional - >>> _instancecheck_items_view({0: 1, 1: 2, 2: 3}.items(), (int, Any), {}) - True - >>> _instancecheck_items_view({0: 1, 1: 2, 2: 3}.items(), (int, int), {}) - True - >>> _instancecheck_items_view({0: 1, 1: 2, 2: 3.0}.items(), (int, int), {}) - False - >>> _instancecheck_items_view({0: 1, 1.0: 2, 2: 3}.items(), (int, int), {}) - False - >>> _instancecheck_items_view({0: '1', 1: 2, 2: 3}.items(), (int, int), {}) - False - >>> _instancecheck_items_view({0: 1, 1: 2, None: 3.0}.items(), (int, int), {}) - False - >>> _instancecheck_items_view({0: 1, 1: 2, None: 3.0}.items(), (int, Optional[int]), {}) - False + >>> from typing import Any, Optional + >>> _instancecheck_items_view({0: 1, 1: 2, 2: 3}.items(), (int, Any), {}) + True + >>> _instancecheck_items_view({0: 1, 1: 2, 2: 3}.items(), (int, int), {}) + True + >>> _instancecheck_items_view({0: 1, 1: 2, 2: 3.0}.items(), (int, int), {}) + False + >>> _instancecheck_items_view({0: 1, 1.0: 2, 2: 3}.items(), (int, int), {}) + False + >>> _instancecheck_items_view({0: '1', 1: 2, 2: 3}.items(), (int, int), {}) + False + >>> _instancecheck_items_view({0: 1, 1: 2, None: 3.0}.items(), (int, int), {}) + False + >>> _instancecheck_items_view({0: 1, 1: 2, None: 3.0}.items(), (int, Optional[int]), {}) + False """ key_type, value_type = type_args return all(_is_instance(obj=key, type_=key_type, type_vars=type_vars, context=context) and @@ -719,19 +776,21 @@ def _instancecheck_items_view(items_view: ItemsView, type_args: Tuple, type_vars for key, val in items_view) -def _instancecheck_tuple(tup: Tuple, type_args: Any, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] = None) -> bool: +def _instancecheck_tuple( + tup: Tuple, type_args: Any, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] | None = None, +) -> bool: """ - >>> from typing import Any - >>> _instancecheck_tuple(tup=(42.0, 43, 'hi', 'you'), type_args=(Any, Ellipsis), type_vars={}) - True - >>> _instancecheck_tuple(tup=(42.0, 43, 'hi', 'you'), type_args=(Any,), type_vars={}) - False - >>> _instancecheck_tuple(tup=(42.0, 43, 'hi', 'you'), type_args=(float, int, str, str), type_vars={}) - True - >>> _instancecheck_tuple(tup=(42.0, 43, 'hi', 'you'), type_args=(float, float, str, str), type_vars={}) - False - >>> _instancecheck_tuple(tup=(42.0, 43, 'hi', 'you'), type_args=(float, int, str, int), type_vars={}) - False + >>> from typing import Any + >>> _instancecheck_tuple(tup=(42.0, 43, 'hi', 'you'), type_args=(Any, Ellipsis), type_vars={}) + True + >>> _instancecheck_tuple(tup=(42.0, 43, 'hi', 'you'), type_args=(Any,), type_vars={}) + False + >>> _instancecheck_tuple(tup=(42.0, 43, 'hi', 'you'), type_args=(float, int, str, str), type_vars={}) + True + >>> _instancecheck_tuple(tup=(42.0, 43, 'hi', 'you'), type_args=(float, float, str, str), type_vars={}) + False + >>> _instancecheck_tuple(tup=(42.0, 43, 'hi', 'you'), type_args=(float, int, str, int), type_vars={}) + False """ if Ellipsis in type_args: return all(_is_instance(obj=val, type_=type_args[0], type_vars=type_vars, context=context) for val in tup) @@ -739,119 +798,127 @@ def _instancecheck_tuple(tup: Tuple, type_args: Any, type_vars: Dict[TypeVar_, A if len(tup) != len(type_args): return False - return all(_is_instance(obj=val, type_=type_, type_vars=type_vars, context=context) for val, type_ in zip(tup, type_args)) + return all(_is_instance(obj=val, type_=type_, type_vars=type_vars, context=context) + for val, type_ in zip(tup, type_args, strict=True)) -def _instancecheck_union(value: Any, type_: Any, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] = None) -> bool: +def _instancecheck_union( + value: Any, type_: Any, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] | None = None, +) -> bool: """ - >>> from typing import Union, TypeVar, Any - >>> NoneType = type(None) - >>> _instancecheck_union(3.0, Union[int, float], {}) - True - >>> _instancecheck_union(3, Union[int, float], {}) - True - >>> _instancecheck_union('3', Union[int, float], {}) - False - >>> _instancecheck_union(None, Union[int, NoneType], {}) - True - >>> _instancecheck_union(None, Union[float, NoneType], {}) - True - >>> S = TypeVar('S') - >>> T = TypeVar('T') - >>> U = TypeVar('U') - >>> _instancecheck_union(42, Union[T, NoneType], {}) - True - >>> _instancecheck_union(None, Union[T, NoneType], {}) - True - >>> _instancecheck_union(None, Union[T, NoneType], {T: int}) - True - >>> _instancecheck_union('None', Union[T, NoneType], {T: int}) - False - >>> _instancecheck_union(42, Union[T, S], {}) - True - >>> _instancecheck_union(42, Union[T, S], {T: int}) - True - >>> _instancecheck_union(42, Union[T, S], {T: str}) - True - >>> _instancecheck_union(42, Union[T, S], {T: int, S: float}) - True - >>> _instancecheck_union(42, Union[T, S], {T: str, S: float}) - False - >>> _instancecheck_union(42.8, Union[T, S], {T: str, S: float}) - True - >>> _instancecheck_union(None, Union[T, S], {T: str, S: float}) - False - >>> _instancecheck_union(None, Union[T, S], {}) - True - >>> _instancecheck_union(None, Union[T, NoneType], {T: int}) - True - >>> _instancecheck_union('None', Union[T, NoneType, S], {T: int}) - True - >>> _instancecheck_union(42, Union[T, Any], {}) - True - >>> _instancecheck_union(42, Union[T, Any], {T: float}) - True - >>> _instancecheck_union(None, Optional[Callable[[float], float]], {}) - True - >>> _instancecheck_union(3.0, int | float, {}) - True - >>> _instancecheck_union(3, int | float, {}) - True - >>> _instancecheck_union('3', int | float, {}) - False - >>> _instancecheck_union(None, int | NoneType, {}) - True - >>> _instancecheck_union(None, float | NoneType, {}) - True - >>> S = TypeVar('S') - >>> T = TypeVar('T') - >>> U = TypeVar('U') - >>> _instancecheck_union(42, T | NoneType, {}) - True - >>> _instancecheck_union(None, T | NoneType, {}) - True - >>> _instancecheck_union(None, T | NoneType, {T: int}) - True - >>> _instancecheck_union('None', T | NoneType, {T: int}) - False - >>> _instancecheck_union(42, T | S, {}) - True - >>> _instancecheck_union(42, T | S, {T: int}) - True - >>> _instancecheck_union(42, T | S, {T: str}) - True - >>> _instancecheck_union(42, T | S, {T: int, S: float}) - True - >>> _instancecheck_union(42, T | S, {T: str, S: float}) - False - >>> _instancecheck_union(42.8, T | S, {T: str, S: float}) - True - >>> _instancecheck_union(None, T | S, {T: str, S: float}) - False - >>> _instancecheck_union(None, T | S, {}) - True - >>> _instancecheck_union(None, T | NoneType, {T: int}) - True - >>> _instancecheck_union('None', T | NoneType | S, {T: int}) - True - >>> _instancecheck_union(42, T | Any, {}) - True - >>> _instancecheck_union(42, T | Any, {T: float}) - True - >>> _instancecheck_union(None, Optional[Callable[[float], float]], {}) - True + >>> from typing import Union, TypeVar, Any, Optional + >>> NoneType = type(None) + >>> _instancecheck_union(3.0, Union[int, float], {}) + True + >>> _instancecheck_union(3, Union[int, float], {}) + True + >>> _instancecheck_union('3', Union[int, float], {}) + False + >>> _instancecheck_union(None, Union[int, NoneType], {}) + True + >>> _instancecheck_union(None, Union[float, NoneType], {}) + True + >>> S = TypeVar('S') + >>> T = TypeVar('T') + >>> U = TypeVar('U') + >>> _instancecheck_union(42, Union[T, NoneType], {}) + True + >>> _instancecheck_union(None, Union[T, NoneType], {}) + True + >>> _instancecheck_union(None, Union[T, NoneType], {T: int}) + True + >>> _instancecheck_union('None', Union[T, NoneType], {T: int}) + False + >>> _instancecheck_union(42, Union[T, S], {}) + True + >>> _instancecheck_union(42, Union[T, S], {T: int}) + True + >>> _instancecheck_union(42, Union[T, S], {T: str}) + True + >>> _instancecheck_union(42, Union[T, S], {T: int, S: float}) + True + >>> _instancecheck_union(42, Union[T, S], {T: str, S: float}) + False + >>> _instancecheck_union(42.8, Union[T, S], {T: str, S: float}) + True + >>> _instancecheck_union(None, Union[T, S], {T: str, S: float}) + False + >>> _instancecheck_union(None, Union[T, S], {}) + True + >>> _instancecheck_union(None, Union[T, NoneType], {T: int}) + True + >>> _instancecheck_union('None', Union[T, NoneType, S], {T: int}) + True + >>> _instancecheck_union(42, Union[T, Any], {}) + True + >>> _instancecheck_union(42, Union[T, Any], {T: float}) + True + >>> _instancecheck_union(None, Optional[Callable[[float], float]], {}) + True + >>> _instancecheck_union(3.0, int | float, {}) + True + >>> _instancecheck_union(3, int | float, {}) + True + >>> _instancecheck_union('3', int | float, {}) + False + >>> _instancecheck_union(None, int | NoneType, {}) + True + >>> _instancecheck_union(None, float | NoneType, {}) + True + >>> S = TypeVar('S') + >>> T = TypeVar('T') + >>> U = TypeVar('U') + >>> _instancecheck_union(42, T | NoneType, {}) + True + >>> _instancecheck_union(None, T | NoneType, {}) + True + >>> _instancecheck_union(None, T | NoneType, {T: int}) + True + >>> _instancecheck_union('None', T | NoneType, {T: int}) + False + >>> _instancecheck_union(42, T | S, {}) + True + >>> _instancecheck_union(42, T | S, {T: int}) + True + >>> _instancecheck_union(42, T | S, {T: str}) + True + >>> _instancecheck_union(42, T | S, {T: int, S: float}) + True + >>> _instancecheck_union(42, T | S, {T: str, S: float}) + False + >>> _instancecheck_union(42.8, T | S, {T: str, S: float}) + True + >>> _instancecheck_union(None, T | S, {T: str, S: float}) + False + >>> _instancecheck_union(None, T | S, {}) + True + >>> _instancecheck_union(None, T | NoneType, {T: int}) + True + >>> _instancecheck_union('None', T | NoneType | S, {T: int}) + True + >>> _instancecheck_union(42, T | Any, {}) + True + >>> _instancecheck_union(42, T | Any, {T: float}) + True + >>> _instancecheck_union(None, Optional[Callable[[float], float]], {}) + True """ type_args = get_type_arguments(cls=type_) return _check_union(value=value, type_args=type_args, type_vars=type_vars, context=context) -def _check_union(value: Any, type_args: Tuple[Any, ...], type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] = None) -> bool: +def _check_union( + value: Any, type_args: Tuple[Any, ...], type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] | None = None, +) -> bool: args_non_type_vars = [type_arg for type_arg in type_args if not isinstance(type_arg, TypeVar)] args_type_vars = [type_arg for type_arg in type_args if isinstance(type_arg, TypeVar)] args_type_vars_bounded = [type_var for type_var in args_type_vars if type_var in type_vars] args_type_vars_unbounded = [type_var for type_var in args_type_vars if type_var not in args_type_vars_bounded] - matches_non_type_var = any([_is_instance(obj=value, type_=typ, type_vars=type_vars, context=context) for typ in args_non_type_vars]) + matches_non_type_var = any( + _is_instance(obj=value, type_=typ, type_vars=type_vars, context=context) + for typ in args_non_type_vars + ) if matches_non_type_var: return True @@ -859,9 +926,11 @@ def _check_union(value: Any, type_args: Tuple[Any, ...], type_vars: Dict[TypeVar for bounded_type_var in args_type_vars_bounded: try: _is_instance(obj=value, type_=bounded_type_var, type_vars=type_vars, context=context) - return True + except PedanticException: pass + else: + return True if not args_type_vars_unbounded: return False @@ -870,32 +939,35 @@ def _check_union(value: Any, type_args: Tuple[Any, ...], type_vars: Dict[TypeVar return True # it is impossible to figure out, how to bound these type variables correctly -def _instancecheck_literal(value: Any, type_: Any, type_vars: Dict[TypeVar_, Any], context: Dict[str, Any] = None) -> bool: +def _instancecheck_literal(value: Any, type_: Any, _: Dict[TypeVar_, Any], __: Dict[str, Any] | None = None) -> bool: type_args = get_type_arguments(cls=type_) return value in type_args -def _instancecheck_callable(value: Optional[Callable], type_: Any, _, context: Dict[str, Any] = None) -> bool: +def _instancecheck_callable( # noqa: PLR0911, C901 + value: Callable | None, type_: Any, _: dict[TypeVar, Any], __: Dict[str, Any] | None = None, +) -> bool: """ - >>> from typing import Tuple, Callable, Any - >>> def f(x: int, y: float) -> Tuple[float, str]: - ... return float(x), str(y) - >>> _instancecheck_callable(f, Callable[[int, float], Tuple[float, str]], {}) - True - >>> _instancecheck_callable(f, Callable[[int, float], Tuple[int, str]], {}) - False - >>> _instancecheck_callable(f, Callable[[int, int], Tuple[float, str]], {}) - False - >>> _instancecheck_callable(f, Callable[..., Tuple[float, str]], {}) - True - >>> _instancecheck_callable(f, Callable[..., Tuple[int, str]], {}) - False - >>> _instancecheck_callable(f, Callable[..., Any], {}) - True - >>> _instancecheck_callable(f, Callable[[int, int, int], Tuple[float, str]], {}) - False - >>> _instancecheck_callable(None, Callable[..., Any], {}) - False + Examples: + >>> from typing import Tuple, Callable, Any + >>> def f(x: int, y: float) -> Tuple[float, str]: + ... return float(x), str(y) + >>> _instancecheck_callable(f, Callable[[int, float], Tuple[float, str]], {}) + True + >>> _instancecheck_callable(f, Callable[[int, float], Tuple[int, str]], {}) + False + >>> _instancecheck_callable(f, Callable[[int, int], Tuple[float, str]], {}) + False + >>> _instancecheck_callable(f, Callable[..., Tuple[float, str]], {}) + True + >>> _instancecheck_callable(f, Callable[..., Tuple[int, str]], {}) + False + >>> _instancecheck_callable(f, Callable[..., Any], {}) + True + >>> _instancecheck_callable(f, Callable[[int, int, int], Tuple[float, str]], {}) + False + >>> _instancecheck_callable(None, Callable[..., Any], {}) + False """ if value is None: @@ -917,7 +989,7 @@ def _instancecheck_callable(value: Optional[Callable], type_: Any, _, context: D if len(param_types) != len(non_optional_params): return False - for param, expected_type in zip(sig.parameters.values(), param_types): + for param, expected_type in zip(sig.parameters.values(), param_types, strict=False): if not _is_subtype(sub_type=param.annotation, super_type=expected_type): return False @@ -940,7 +1012,7 @@ def _is_lambda(obj: Any) -> bool: return callable(obj) and obj.__name__ == '' -def _instancecheck_type(value: Any, type_: Any, type_vars: Dict, context: Dict[str, Any] = None) -> bool: +def _instancecheck_type(value: Any, type_: Any, _: dict, context: dict[str, Any] | None = None) -> bool: type_ = type_[0] if type_ == Any or isinstance(type_, typing.TypeVar): @@ -980,7 +1052,7 @@ def _instancecheck_type(value: Any, type_: Any, type_vars: Dict, context: Dict[s 'typing.Generator': _instancecheck_generator, }.items(): - class_ = eval(class_path) + class_ = eval(class_path) # noqa: S307 _ORIGIN_TYPE_CHECKERS[class_] = _check_func _SPECIAL_INSTANCE_CHECKERS = { @@ -988,7 +1060,7 @@ def _instancecheck_type(value: Any, type_: Any, type_vars: Dict, context: Dict[s 'Optional': _instancecheck_union, 'Literal': _instancecheck_literal, 'Callable': _instancecheck_callable, - 'Any': lambda v, t, tv, c: True, + 'Any': lambda _, __, ___, ____: True, } NUM_OF_REQUIRED_TYPE_ARGS_EXACT = { @@ -1007,35 +1079,37 @@ def _instancecheck_type(value: Any, type_: Any, type_vars: Dict, context: Dict[s } -def convert_to_typing_types(x: typing.Type) -> typing.Type: +def convert_to_typing_types(x: type) -> type: # noqa: PLR0911 """ - Example: - >>> convert_to_typing_types(int) - - >>> convert_to_typing_types(list) - Traceback (most recent call last): - ... - ValueError: Missing type arguments - >>> convert_to_typing_types(list[int]) - typing.List[int] - >>> convert_to_typing_types(set[int]) - typing.Set[int] - >>> convert_to_typing_types(frozenset[int]) - typing.FrozenSet[int] - >>> convert_to_typing_types(tuple[int]) - typing.Tuple[int] - >>> convert_to_typing_types(type[int]) - typing.Type[int] - >>> convert_to_typing_types(type[int | float]) - typing.Type[int | float] - >>> convert_to_typing_types(tuple[int, float]) - typing.Tuple[int, float] - >>> convert_to_typing_types(dict[int, float]) - typing.Dict[int, float] - >>> convert_to_typing_types(list[dict[int, float]]) - typing.List[typing.Dict[int, float]] - >>> convert_to_typing_types(list[dict[int, tuple[float, str]]]) - typing.List[typing.Dict[int, typing.Tuple[float, str]]] + Converts a given type to the typing module equivalent type. + + Example: + >>> convert_to_typing_types(int) + + >>> convert_to_typing_types(list) + Traceback (most recent call last): + ... + ValueError: Missing type arguments + >>> convert_to_typing_types(list[int]) + typing.List[int] + >>> convert_to_typing_types(set[int]) + typing.Set[int] + >>> convert_to_typing_types(frozenset[int]) + typing.FrozenSet[int] + >>> convert_to_typing_types(tuple[int]) + typing.Tuple[int] + >>> convert_to_typing_types(type[int]) + typing.Type[int] + >>> convert_to_typing_types(type[int | float]) + typing.Type[int | float] + >>> convert_to_typing_types(tuple[int, float]) + typing.Tuple[int, float] + >>> convert_to_typing_types(dict[int, float]) + typing.Dict[int, float] + >>> convert_to_typing_types(list[dict[int, float]]) + typing.List[typing.Dict[int, float]] + >>> convert_to_typing_types(list[dict[int, tuple[float, str]]]) + typing.List[typing.Dict[int, typing.Tuple[float, str]]] """ if x in {list, set, dict, frozenset, tuple, type}: @@ -1044,22 +1118,22 @@ def convert_to_typing_types(x: typing.Type) -> typing.Type: if not hasattr(x, '__origin__'): return x - origin = x.__origin__ # type: ignore # checked above - args = [convert_to_typing_types(a) for a in x.__args__] # type: ignore + origin = x.__origin__ + args = [convert_to_typing_types(a) for a in x.__args__] if origin is list: return typing.List[tuple(args)] - elif origin is set: + if origin is set: return typing.Set[tuple(args)] - elif origin is dict: + if origin is dict: return typing.Dict[tuple(args)] - elif origin is tuple: + if origin is tuple: return typing.Tuple[tuple(args)] - elif origin is frozenset: + if origin is frozenset: return typing.FrozenSet[tuple(args)] - elif origin is type: + if origin is type: return typing.Type[tuple(args)] - elif origin is typing.Union: + if origin is typing.Union: return x # new since Python 3.14 raise RuntimeError(x) diff --git a/pedantic/type_checking_logic/resolve_forward_ref.py b/pedantic/type_checking_logic/resolve_forward_ref.py index 5c2eae34..f3ba6548 100644 --- a/pedantic/type_checking_logic/resolve_forward_ref.py +++ b/pedantic/type_checking_logic/resolve_forward_ref.py @@ -1,12 +1,12 @@ -from typing import * # useful for globals(), see below +from typing import * # noqa: F403, useful for globals(), see below -def resolve_forward_ref(type_: str, globals_: Dict[str, Any] = None, context: Dict = None) -> Type: +def resolve_forward_ref(type_: str, globals_: dict[str, Any] | None = None, context: dict | None = None) -> type: # noqa: F405 """ - Resolve a type annotation that is a string. + Resolve a type annotation that is a string. - Raises: - NameError: in case of [type_] cannot be resolved. + Raises: + NameError: in case of [type_] cannot be resolved. """ - return eval(str(type_), globals_ or globals(), context or {}) + return eval(str(type_), globals_ or globals(), context or {}) # # noqa: S307 diff --git a/poetry.lock b/poetry.lock index cb350437..1b9540a2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -215,15 +215,15 @@ test = ["pytest"] [[package]] name = "flask" -version = "3.1.2" +version = "3.1.3" description = "A simple framework for building complex web applications." optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "flask-3.1.2-py3-none-any.whl", hash = "sha256:ca1d8112ec8a6158cc29ea4858963350011b5c846a414cdb7a954aa9e967d03c"}, - {file = "flask-3.1.2.tar.gz", hash = "sha256:bf656c15c80190ed628ad08cdfd3aaa35beb087855e2f494910aa3774cc4fd87"}, + {file = "flask-3.1.3-py3-none-any.whl", hash = "sha256:f4bcbefc124291925f1a26446da31a5178f9483862233b23c0c96a20701f670c"}, + {file = "flask-3.1.3.tar.gz", hash = "sha256:0ef0e52b8a9cd932855379197dd8f94047b359ca0a78695144304cb45f87c9eb"}, ] [package.dependencies] @@ -506,15 +506,15 @@ testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] name = "pytest-cov" -version = "7.0.0" +version = "7.1.0" description = "Pytest plugin for measuring coverage." optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861"}, - {file = "pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1"}, + {file = "pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678"}, + {file = "pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2"}, ] [package.dependencies] @@ -525,6 +525,35 @@ pytest = ">=7" [package.extras] testing = ["process-tests", "pytest-xdist", "virtualenv"] +[[package]] +name = "ruff" +version = "0.15.9" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"dev\"" +files = [ + {file = "ruff-0.15.9-py3-none-linux_armv6l.whl", hash = "sha256:6efbe303983441c51975c243e26dff328aca11f94b70992f35b093c2e71801e1"}, + {file = "ruff-0.15.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4965bac6ac9ea86772f4e23587746f0b7a395eccabb823eb8bfacc3fa06069f7"}, + {file = "ruff-0.15.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eaf05aad70ca5b5a0a4b0e080df3a6b699803916d88f006efd1f5b46302daab8"}, + {file = "ruff-0.15.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9439a342adb8725f32f92732e2bafb6d5246bd7a5021101166b223d312e8fc59"}, + {file = "ruff-0.15.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c5e6faf9d97c8edc43877c3f406f47446fc48c40e1442d58cfcdaba2acea745"}, + {file = "ruff-0.15.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b34a9766aeec27a222373d0b055722900fbc0582b24f39661aa96f3fe6ad901"}, + {file = "ruff-0.15.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89dd695bc72ae76ff484ae54b7e8b0f6b50f49046e198355e44ea656e521fef9"}, + {file = "ruff-0.15.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce187224ef1de1bd225bc9a152ac7102a6171107f026e81f317e4257052916d5"}, + {file = "ruff-0.15.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b0c7c341f68adb01c488c3b7d4b49aa8ea97409eae6462d860a79cf55f431b6"}, + {file = "ruff-0.15.9-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:55cc15eee27dc0eebdfcb0d185a6153420efbedc15eb1d38fe5e685657b0f840"}, + {file = "ruff-0.15.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a6537f6eed5cda688c81073d46ffdfb962a5f29ecb6f7e770b2dc920598997ed"}, + {file = "ruff-0.15.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6d3fcbca7388b066139c523bda744c822258ebdcfbba7d24410c3f454cc9af71"}, + {file = "ruff-0.15.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:058d8e99e1bfe79d8a0def0b481c56059ee6716214f7e425d8e737e412d69677"}, + {file = "ruff-0.15.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:8e1ddb11dbd61d5983fa2d7d6370ef3eb210951e443cace19594c01c72abab4c"}, + {file = "ruff-0.15.9-py3-none-win32.whl", hash = "sha256:bde6ff36eaf72b700f32b7196088970bf8fdb2b917b7accd8c371bfc0fd573ec"}, + {file = "ruff-0.15.9-py3-none-win_amd64.whl", hash = "sha256:45a70921b80e1c10cf0b734ef09421f71b5aa11d27404edc89d7e8a69505e43d"}, + {file = "ruff-0.15.9-py3-none-win_arm64.whl", hash = "sha256:0694e601c028fd97dc5c6ee244675bc241aeefced7ef80cd9c6935a871078f53"}, + {file = "ruff-0.15.9.tar.gz", hash = "sha256:29cbb1255a9797903f6dde5ba0188c707907ff44a9006eb273b5a17bfa0739a2"}, +] + [[package]] name = "typing-extensions" version = "4.15.0" @@ -540,15 +569,15 @@ files = [ [[package]] name = "werkzeug" -version = "3.1.5" +version = "3.1.8" description = "The comprehensive WSGI web application library." optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "werkzeug-3.1.5-py3-none-any.whl", hash = "sha256:5111e36e91086ece91f93268bb39b4a35c1e6f1feac762c9c822ded0a4e322dc"}, - {file = "werkzeug-3.1.5.tar.gz", hash = "sha256:6a548b0e88955dd07ccb25539d7d0cc97417ee9e179677d22c7041c8f078ce67"}, + {file = "werkzeug-3.1.8-py3-none-any.whl", hash = "sha256:63a77fb8892bf28ebc3178683445222aa500e48ebad5ec77b0ad80f8726b1f50"}, + {file = "werkzeug-3.1.8.tar.gz", hash = "sha256:9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44"}, ] [package.dependencies] @@ -558,9 +587,9 @@ markupsafe = ">=2.1.1" watchdog = ["watchdog (>=2.3)"] [extras] -dev = ["Flask", "Werkzeug", "docstring-parser", "multiprocess", "pytest", "pytest-asyncio", "pytest-cov"] +dev = ["Flask", "Werkzeug", "docstring-parser", "multiprocess", "pytest", "pytest-asyncio", "pytest-cov", "ruff"] [metadata] lock-version = "2.1" python-versions = ">=3.11" -content-hash = "e0f6b68dabc193cb34037f3420dec19fd1b2babea9d700de9471a810499546d8" +content-hash = "9f86cac02ce1f4054f1c8c6f41aa2257d43ff9e1a3f19a02ec88e9bc388ae533" diff --git a/pyproject.toml b/pyproject.toml index 6a29fcb3..16c428fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "pedantic" -version = "2.4.0" +version = "3.0.0" description = "Some useful Python decorators for cleaner software development." readme = "README.md" requires-python = ">=3.11" @@ -33,10 +33,11 @@ dev = [ "docstring-parser==0.17", "pytest==9.0.2", "pytest-asyncio==1.3.0", - "pytest-cov==7.0.0", - "Flask[async]==3.1.2", + "pytest-cov==7.1.0", + "Flask[async]==3.1.3", "multiprocess==0.70.19", - "Werkzeug==3.1.5", + "ruff==0.15.9", + "Werkzeug==3.1.8", ] [tool.setuptools.packages.find] @@ -45,3 +46,57 @@ where = ["."] [tool.pytest.ini_options] addopts = "--doctest-modules" python_files = ["*.py"] + +[tool.ruff] +target-version = "py311" +line-length = 120 + +[tool.ruff.format] +quote-style = "single" + +[tool.ruff.lint.flake8-quotes] +inline-quotes = "single" + +[tool.ruff.lint] +select = ["ALL"] +ignore = [ + "ANN401", # Dynamically typed expressions (typing.Any) are disallowed in + "D100", # Missing docstring in public module + "D104", # Missing docstring in public package + "D105", # Missing docstring in magic method + "D202", # No blank lines allowed after function docstring (found 1) + "D203", # incorrect-blank-line-before-class + "D404", # D404 First word of the docstring should not be "This" => free docstrings + "D205", # 1 blank line required between summary line and description => free docstrings + "D212", # multi-line-summary-first-line + "D400", # First line should end with a period + "D401", # First line of docstring should be in imperative mood: "Converts a given type to the typing module equivalent type." + "D413", # Missing blank line after last section ("Raises") + "D415", # First line should end with a period, question mark, or exclamation point + "EM101", # Exception must not use a string literal, assign to variable first + "EM102", # Exception must not use an f-string literal, assign to variable first + "FBT001", # Boolean-typed positional argument in function definition => bool params aren't that bad + "FBT002", # Boolean default positional argument in function definition => bool params aren't that bad + "S112", # `try`-`except`-`continue` detected, consider logging the exception + "SIM108", # Use ternary operator `processed_arg = substitutions.get(arg, arg) if isinstance(arg, TypeVar) else arg` instead of `if`-`else`-block + "TRY003", # Avoid specifying long messages outside the exception class +] + +[tool.ruff.lint.per-file-ignores] +"tests/*" = [ + "ANN001", # Missing type annotation for function argument + "ANN002", # Missing type annotation for *args + "ANN003", # Missing type annotation for **kwargs + "ANN202", # Missing return type annotation for private function + "ANN201", # Missing return type annotation for public function + "ANN204", # Missing return type annotation for special method + "ANN205", # Missing return type annotation for staticmethod + "ANN206", # Missing return type annotation for classmethod + "D101", # Missing docstring in public class + "D102", # Missing docstring in public method + "D103", # Missing docstring in public function + "E501", # Line too long (138 > 120) + "FBT003", # Boolean positional value in function call + "PLR2004", # Magic value used in comparison, consider replacing `3` with a constant variable + "S101", # Use of `assert` detected +] diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index f9c8b682..00000000 --- a/tests/conftest.py +++ /dev/null @@ -1,12 +0,0 @@ -import os - -import pytest - -from pedantic.env_var_logic import ENVIRONMENT_VARIABLE_NAME - - -@pytest.fixture(autouse=True) -def cleanup_env_vars() -> None: - for env_var in [ENVIRONMENT_VARIABLE_NAME, 'foo']: - if env_var in os.environ: - del os.environ[env_var] diff --git a/tests/decorators/pedantic/test_generator.py b/tests/decorators/pedantic/test_generator.py index ed64717d..5cf16d54 100644 --- a/tests/decorators/pedantic/test_generator.py +++ b/tests/decorators/pedantic/test_generator.py @@ -1,9 +1,12 @@ -from typing import Generator, Iterator, Iterable, List +from collections.abc import Generator as ColGenerator +from collections.abc import Iterable as ColIterable +from collections.abc import Iterator as ColIterator +from typing import Generator, Iterable, Iterator # noqa: UP035 import pytest -from pedantic.exceptions import PedanticTypeCheckException from pedantic.decorators.fn_deco_pedantic import pedantic +from pedantic.exceptions import PedanticTypeCheckException def test_iterator(): @@ -48,7 +51,7 @@ def genfunc() -> Iterator: def test_iterator_completely_wrong_type_hint(): @pedantic - def gen_func() -> List[int]: + def gen_func() -> list[int]: num = 0 while num < 100: @@ -111,3 +114,90 @@ def gen_func() -> Generator: with pytest.raises(expected_exception=PedanticTypeCheckException): gen_func() + + +def test_iterable_from_collections_green(): + @pedantic + def gen_func() -> ColIterable[int]: + num = 0 + + while num < 100: + yield num + num += 1 + + gen = gen_func() + next(gen) + + +def test_iterable_from_collections_red(): + @pedantic + def gen_func() -> ColIterable[str]: + num = 0 + + while num < 100: + yield num + num += 1 + + gen = gen_func() + + with pytest.raises(expected_exception=PedanticTypeCheckException, match="ype hint is incorrect: Argument 0 of type does not match expected type "): + next(gen) + + +def test_iterator_from_collections_green(): + @pedantic + def gen_func() -> ColIterator[int]: + num = 0 + + while num < 100: + yield num + num += 1 + + gen = gen_func() + next(gen) + + +def test_iterator_from_collections_red(): + @pedantic + def gen_func() -> ColIterator[str]: + num = 0 + + while num < 100: + yield num + num += 1 + + gen = gen_func() + + with pytest.raises(expected_exception=PedanticTypeCheckException, match="ype hint is incorrect: Argument 0 of type does not match expected type "): + next(gen) + + +def test_generator_from_collections_green(): + @pedantic + def gen_func() -> ColGenerator[int, None, str]: + num = 0 + + while num < 100: + yield num + num += 1 + return 'Done' + + gen = gen_func() + next(gen) + + +def test_generator_from_collections_red(): + @pedantic + def gen_func() -> ColGenerator[str, None, str]: + num = 0 + + while num < 100: + yield num + num += 1 + return 'Done' + + gen = gen_func() + + with pytest.raises(expected_exception=PedanticTypeCheckException, + match="ype hint is incorrect: Argument 0 of type does not match expected type "): + next(gen) diff --git a/tests/decorators/pedantic/test_generic_classes.py b/tests/decorators/pedantic/test_generic_classes.py index f487d8c3..b2395efc 100644 --- a/tests/decorators/pedantic/test_generic_classes.py +++ b/tests/decorators/pedantic/test_generic_classes.py @@ -1,4 +1,6 @@ -from typing import Generic, TypeVar, Any, List, Optional, Union +# ruff: noqa: UP007, UP045 + +from typing import Any, Generic, Optional, TypeVar, Union import pytest @@ -40,7 +42,7 @@ def test_stack(): @pedantic_class class Stack(Generic[T]): def __init__(self) -> None: - self.items: List[T] = [] + self.items: list[T] = [] def push(self, item: T) -> None: self.items.append(item) @@ -54,8 +56,7 @@ def empty(self) -> bool: def top(self) -> Optional[T]: if len(self.items) > 0: return self.items[len(self.items) - 1] - else: - return None + return None my_stack = Stack[str]() get_type_vars = getattr(my_stack, TYPE_VAR_METHOD_NAME) @@ -175,11 +176,11 @@ def set_a(self, val: T) -> None: a.set_a(val='hi') -def test_recursion_depth_exceeded(): +def test_recursion_depth_exceeded(): # noqa: C901 @pedantic_class class Stack(Generic[T]): def __init__(self) -> None: - self.items: List[T] = [] + self.items: list[T] = [] def len(self) -> int: return len(self.items) @@ -190,8 +191,7 @@ def push(self, item: T) -> None: def pop(self) -> T: if len(self.items) > 0: return self.items.pop() - else: - raise ValueError() + raise ValueError def empty(self) -> bool: return not self.items @@ -199,23 +199,20 @@ def empty(self) -> bool: def top(self) -> Optional[T]: if len(self.items) > 0: return self.items[len(self.items) - 1] - else: - return None + return None def __len__(self) -> int: return len(self.items) def create_stack(): stack = Stack[int]() - return stack + return stack # noqa: RET504, the unnecessary assignment here is important, lol with pytest.raises(expected_exception=PedanticTypeVarMismatchException): - stack: Stack[int] = Stack() - stack.empty() + _: Stack[int] = Stack() with pytest.raises(expected_exception=PedanticTypeVarMismatchException): - stack = Stack() - stack.empty() + Stack() stack = create_stack() assert stack.empty() @@ -225,7 +222,7 @@ def test_generic_union(): @pedantic_class class Stack(Generic[T]): def __init__(self) -> None: - self.items: List[T] = [] + self.items: list[T] = [] def len(self) -> int: return len(self.items) @@ -236,8 +233,7 @@ def push(self, item: T) -> None: def pop(self) -> T: if len(self.items) > 0: return self.items.pop() - else: - raise ValueError() + raise ValueError def empty(self) -> bool: return not self.items @@ -245,8 +241,7 @@ def empty(self) -> bool: def top(self) -> Optional[T]: if len(self.items) > 0: return self.items[len(self.items) - 1] - else: - return None + return None def __len__(self) -> int: return len(self.items) @@ -264,7 +259,7 @@ def test_inheritance(): @pedantic_class class Stack(Generic[T]): def __init__(self) -> None: - self.items: List[T] = [] + self.items: list[T] = [] def len(self) -> int: return len(self.items) @@ -275,8 +270,7 @@ def push(self, item: T) -> None: def pop(self) -> T: if len(self.items) > 0: return self.items.pop() - else: - raise ValueError() + raise ValueError def empty(self) -> bool: return not self.items @@ -284,8 +278,7 @@ def empty(self) -> bool: def top(self) -> Optional[T]: if len(self.items) > 0: return self.items[len(self.items) - 1] - else: - return None + return None def __len__(self) -> int: return len(self.items) diff --git a/tests/decorators/pedantic/test_pedantic.py b/tests/decorators/pedantic/test_pedantic.py index 273cfde7..8bb2a56f 100644 --- a/tests/decorators/pedantic/test_pedantic.py +++ b/tests/decorators/pedantic/test_pedantic.py @@ -1,23 +1,59 @@ -import os.path +# ruff: noqa: PYI041, UP006, UP007, UP014, UP035, UP045 import types -import typing +from collections.abc import Callable as CollectionCallable from dataclasses import dataclass -from datetime import datetime, date -from functools import wraps, partial -from io import BytesIO, StringIO -from typing import List, Tuple, Callable, Any, Optional, Union, Dict, Set, FrozenSet, NewType, TypeVar, Sequence, \ - AbstractSet, Iterator, NamedTuple, Collection, Type, Generator, Generic, BinaryIO, TextIO, Iterable, Container, \ - NoReturn, ClassVar, Literal +from datetime import UTC, date, datetime from enum import Enum, IntEnum +from functools import partial, wraps +from io import BytesIO, StringIO +from pathlib import Path +from typing import ( + AbstractSet, + Any, + BinaryIO, + Callable, + ClassVar, + Collection, + Container, + Dict, + FrozenSet, + Generator, + Generic, + Iterable, + Iterator, + List, + Literal, + LiteralString, + NamedTuple, + Never, + NewType, + NoReturn, + Optional, + Protocol, + Self, + Sequence, + Set, + TextIO, + Tuple, + Type, + TypeVar, + TypeVarTuple, + Union, +) import pytest from pedantic import pedantic_class -from pedantic.exceptions import PedanticTypeCheckException, PedanticException, PedanticCallWithArgsException, \ - PedanticTypeVarMismatchException from pedantic.decorators.fn_deco_pedantic import pedantic +from pedantic.exceptions import ( + PedanticCallWithArgsException, + PedanticException, + PedanticTypeCheckException, + PedanticTypeVarMismatchException, +) -TEST_FILE = 'test.txt' +Ts = TypeVarTuple('Ts') +TEST_FILE = 'test_file.txt' class Parent: @@ -314,8 +350,7 @@ def calc(n: int, m: int, i: int) -> None: def test_wrong_type_hint_corrected(): @pedantic - def calc(n: int, m: int, i: int) -> None: - print(n + m + i) + def calc(n: int, m: int, i: int) -> None: pass calc(n=42, m=40, i=38) @@ -323,8 +358,7 @@ def calc(n: int, m: int, i: int) -> None: def test_wrong_type_hint_4(): """Problem here: None != int""" @pedantic - def calc(n: int, m: int, i: int) -> int: - print(n + m + i) + def calc(n: int, m: int, i: int) -> int: pass with pytest.raises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=38) @@ -649,7 +683,7 @@ def calc(i: Callable[..., int]) -> int: @pedantic def call(x: float, y: int) -> int: - return 42 + return int(x) + y calc(i=call) @@ -661,8 +695,8 @@ def calc(i: Callable[..., int]) -> int: return i(x=3.14) @pedantic - def call(x: float, y: int) -> int: - return 42 + def call(x: float, _: int) -> int: + return int(x) with pytest.raises(expected_exception=PedanticException): calc(i=call) @@ -735,7 +769,7 @@ def calc(d: Optional[Dict[int, int]] = None) -> Optional[int]: def test_optional_args_6(): - """"Problem here: str != int""" + """Problem here: str != int""" @pedantic def calc(d: int = 42) -> int: return int(d) @@ -754,8 +788,7 @@ class MyEnum(Enum): class MyClass: @pedantic - def operation(self, a: MyEnum.GAMMA) -> None: - print(a) + def operation(self, a: MyEnum.GAMMA) -> None: pass m = MyClass() with pytest.raises(expected_exception=PedanticTypeCheckException): @@ -769,8 +802,7 @@ class MyEnum(Enum): GAMMA = 'sequenceFlow' @pedantic - def operation(a: MyEnum) -> None: - print(a) + def operation(a: MyEnum) -> None: pass operation(a=MyEnum.GAMMA) @@ -925,7 +957,7 @@ def calc(ls: Tuple[Any, ...]) -> int: def test_any(): @pedantic def calc(ls: List[Any]) -> Dict[int, Any]: - return {i: ls[i] for i in range(0, len(ls))} + return {i: ls[i] for i in range(len(ls))} calc(ls=[1, 2, 3]) calc(ls=[1.11, 2.0, 3.0]) @@ -934,7 +966,7 @@ def calc(ls: List[Any]) -> Dict[int, Any]: def test_aliases(): - Vector = List[float] + Vector = List[float] # noqa: N806 @pedantic def scale(scalar: float, vector: Vector) -> Vector: @@ -955,7 +987,7 @@ def get_user_name(user_id: UserId) -> str: # the following would be desirable but impossible to check at runtime: # with pytest.raises(expected_exception=AssertionError): - # get_user_name(user_id=-1) + # get_user_name(user_id=-1) # noqa: ERA001 def test_list_of_new_type(): @@ -1048,9 +1080,7 @@ def wrapper_method(*args: Union[int, float], **kwargs: Union[int, float]) -> flo def test_args_kwargs_no_type_hint(): @pedantic - def method_no_type_hint(*args, **kwargs) -> None: - print(args) - print(kwargs) + def method_no_type_hint(*args, **kwargs) -> None: pass with pytest.raises(expected_exception=PedanticTypeCheckException): method_no_type_hint(a=3, b=3.0) @@ -1061,9 +1091,7 @@ def method_no_type_hint(*args, **kwargs) -> None: def test_args_kwargs_wrong_type_hint(): """See: https://www.python.org/dev/peps/pep-0484/#arbitrary-argument-lists-and-default-argument-values""" @pedantic - def wrapper_method(*args: str, **kwargs: str) -> None: - print(args) - print(kwargs) + def wrapper_method(*args: str, **kwargs: str) -> None: pass wrapper_method() wrapper_method('hi', 'you', ':)') @@ -1079,7 +1107,7 @@ def wrapper_method(*args: str, **kwargs: str) -> None: def test_additional_kwargs(): @pedantic def some_method(a: int, b: float = 0.0, **kwargs: int) -> float: - return sum([a, b]) + return sum([a, b, *list(kwargs.values())]) some_method(a=5) some_method(a=5, b=0.1) @@ -1095,9 +1123,7 @@ def some_method(a: int, b: float = 0.0, **kwargs: int) -> float: def test_args_kwargs_different_types(): @pedantic - def foo(*args: str, **kwds: int) -> None: - print(args) - print(kwds) + def foo(*args: str, **kwds: int) -> None: pass foo('a', 'b', 'c') foo(x=1, y=2) @@ -1105,20 +1131,23 @@ def foo(*args: str, **kwds: int) -> None: def test_pedantic_on_class(): + @pedantic + class MyClass: + pass + with pytest.raises(expected_exception=PedanticTypeCheckException): - @pedantic - class MyClass: - pass MyClass() def test_is_subtype_tuple(): + @pedantic + def foo() -> Callable[[Tuple[float, str]], Tuple[int]]: + def bar(a: Tuple[float]) -> Tuple[int]: + return (len(a[1]) + int(a[0]),) + + return bar + with pytest.raises(expected_exception=PedanticTypeCheckException): - @pedantic - def foo() -> Callable[[Tuple[float, str]], Tuple[int]]: - def bar(a: Tuple[float]) -> Tuple[int]: - return len(a[1]) + int(a[0]), - return bar foo() @@ -1126,8 +1155,9 @@ def test_is_subtype_tuple_corrected(): @pedantic def foo() -> Callable[[Tuple[float, str]], Tuple[int]]: def bar(a: Tuple[float, str]) -> Tuple[int]: - return len(a[1]) + int(a[0]), + return (len(a[1]) + int(a[0]),) return bar + foo() @@ -1146,10 +1176,7 @@ def test_alternative_list_type_hint(): @pedantic def _is_digit_in_int(digit: [int], num: int) -> bool: num_str = str(num) - for i in num_str: - if int(i) == digit: - return True - return False + return any(int(i) == digit for i in num_str) with pytest.raises(expected_exception=PedanticTypeCheckException): _is_digit_in_int(digit=4, num=42) @@ -1177,23 +1204,15 @@ def get_server_info() -> str: def test_pedantic(): @pedantic def foo(a: int, b: str) -> str: - return 'abc' + return str(a) + b - assert foo(a=4, b='abc') == 'abc' - - -def test_pedantic_always(): - @pedantic - def foo(a: int, b: str) -> str: - return 'abc' - - assert foo(a=4, b='abc') == 'abc' + assert foo(a=4, b='abc') == '4abc' def test_pedantic_arguments_fail(): @pedantic def foo(a: int, b: str) -> str: - return 'abc' + return str(a) + b with pytest.raises(expected_exception=PedanticTypeCheckException): foo(a=4, b=5) @@ -1202,7 +1221,7 @@ def foo(a: int, b: str) -> str: def test_pedantic_return_type_fail(): @pedantic def foo(a: int, b: str) -> str: - return 6 + return a + len(b) with pytest.raises(expected_exception=PedanticTypeCheckException): foo(a=4, b='abc') @@ -1225,6 +1244,9 @@ def __init__(self, val: int) -> None: def __eq__(self, other: 'A') -> bool: # other: A and all subclasses return self.val == other.val + def __hash__(self) -> int: + return hash(self.val) + @pedantic_class class B(A): def __init__(self, val: int) -> None: @@ -1249,8 +1271,8 @@ def test_date_datetime(): def foo(a: datetime, b: date) -> None: pass - foo(a=datetime(1995, 2, 5), b=date(1987, 8, 7)) - foo(a=datetime(1995, 2, 5), b=datetime(1987, 8, 7)) + foo(a=datetime(1995, 2, 5, tzinfo=UTC), b=date(1987, 8, 7)) + foo(a=datetime(1995, 2, 5, tzinfo=UTC), b=datetime(1987, 8, 7, tzinfo=UTC)) with pytest.raises(expected_exception=PedanticTypeCheckException): foo(a=date(1995, 2, 5), b=date(1987, 8, 7)) @@ -1490,8 +1512,7 @@ def foo(a: Set[int]) -> None: def test_tuple_bad_type(): @pedantic - def foo(a: Tuple[int]) -> None: - pass + def foo(a: Tuple[int]) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=5) @@ -1499,8 +1520,7 @@ def foo(a: Tuple[int]) -> None: def test_tuple_too_many_elements(): @pedantic - def foo(a: Tuple[int, str]) -> None: - pass + def foo(a: Tuple[int, str]) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=(1, 'aa', 2)) @@ -1508,8 +1528,7 @@ def foo(a: Tuple[int, str]) -> None: def test_tuple_too_few_elements(): @pedantic - def foo(a: Tuple[int, str]) -> None: - pass + def foo(a: Tuple[int, str]) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=(1,)) @@ -1517,8 +1536,7 @@ def foo(a: Tuple[int, str]) -> None: def test_tuple_bad_element(): @pedantic - def foo(a: Tuple[int, str]) -> None: - pass + def foo(a: Tuple[int, str]) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=(1, 2)) @@ -1526,8 +1544,7 @@ def foo(a: Tuple[int, str]) -> None: def test_tuple_ellipsis_bad_element(): @pedantic - def foo(a: Tuple[int, ...]) -> None: - pass + def foo(a: Tuple[int, ...]) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=(1, 2, 'blah')) @@ -1537,8 +1554,7 @@ def test_namedtuple(): Employee = NamedTuple('Employee', [('name', str), ('id', int)]) @pedantic - def foo(bar: Employee) -> None: - print(bar) + def foo(bar: Employee) -> None: pass foo(bar=Employee('bob', 1)) @@ -1548,8 +1564,7 @@ def test_namedtuple_key_mismatch(): Employee2 = NamedTuple('Employee', [('firstname', str), ('id', int)]) @pedantic - def foo(bar: Employee1) -> None: - print(bar) + def foo(bar: Employee1) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(bar=Employee2('bob', 1)) @@ -1559,8 +1574,7 @@ def test_namedtuple_type_mismatch(): Employee = NamedTuple('Employee', [('name', str), ('id', int)]) @pedantic - def foo(bar: Employee) -> None: - print(bar) + def foo(bar: Employee) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(bar=('bob', 1)) @@ -1570,8 +1584,7 @@ def test_namedtuple_huge_type_mismatch(): Employee = NamedTuple('Employee', [('name', str), ('id', int)]) @pedantic - def foo(bar: int) -> None: - print(bar) + def foo(bar: int) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(bar=foo(bar=Employee('bob', 1))) @@ -1581,8 +1594,7 @@ def test_namedtuple_wrong_field_type(): Employee = NamedTuple('Employee', [('name', str), ('id', int)]) @pedantic - def foo(bar: Employee) -> None: - pass + def foo(bar: Employee) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(bar=Employee(2, 1)) @@ -1590,8 +1602,7 @@ def foo(bar: Employee) -> None: def test_union(): @pedantic - def foo(a: Union[str, int]) -> None: - pass + def foo(a: Union[str, int]) -> None: pass for value in [6, 'xa']: foo(a=value) @@ -1599,8 +1610,7 @@ def foo(a: Union[str, int]) -> None: def test_union_new_syntax(): @pedantic - def foo(a: str | int) -> None: - pass + def foo(a: str | int) -> None: pass for value in [6, 'xa']: foo(a=value) @@ -1611,8 +1621,7 @@ def foo(a: str | int) -> None: def test_union_typing_type(): @pedantic - def foo(a: Union[str, Collection]) -> None: - pass + def foo(a: Union[str, Collection]) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=1) @@ -1620,8 +1629,7 @@ def foo(a: Union[str, Collection]) -> None: def test_union_fail(): @pedantic - def foo(a: Union[str, int]) -> None: - pass + def foo(a: Union[str, int]) -> None: pass for value in [5.6, b'xa']: with pytest.raises(PedanticTypeCheckException): @@ -1632,12 +1640,11 @@ def test_type_var_constraints(): T = TypeVar('T', int, str) @pedantic - def foo(a: T, b: T) -> None: - pass + def foo(a: T, b: T) -> None: pass for values in [ {'a': 6, 'b': 7}, - {'a': 'aa', 'b': "bb"}, + {'a': 'aa', 'b': 'bb'}, ]: foo(**values) @@ -1646,8 +1653,7 @@ def test_type_var_constraints_fail_typing_type(): T = TypeVar('T', int, Collection) @pedantic - def foo(a: T, b: T) -> None: - pass + def foo(a: T, b: T) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a='aa', b='bb') @@ -1657,8 +1663,7 @@ def test_typevar_constraints_fail(): T = TypeVar('T', int, str) @pedantic - def foo(a: T, b: T) -> None: - pass + def foo(a: T, b: T) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=2.5, b='aa') @@ -1668,8 +1673,7 @@ def test_typevar_bound(): T = TypeVar('T', bound=Parent) @pedantic - def foo(a: T, b: T) -> None: - pass + def foo(a: T, b: T) -> None: pass foo(a=Child(), b=Child()) @@ -1678,8 +1682,7 @@ def test_type_var_bound_fail(): T = TypeVar('T', bound=Child) @pedantic - def foo(a: T, b: T) -> None: - pass + def foo(a: T, b: T) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=Parent(), b=Parent()) @@ -1689,50 +1692,45 @@ def test_type_var_invariant_fail(): T = TypeVar('T', int, str) @pedantic - def foo(a: T, b: T) -> None: - pass + def foo(a: T, b: T) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=2, b=3.6) def test_type_var_covariant(): - T = TypeVar('T', covariant=True) + T_co = TypeVar('T_co', covariant=True) @pedantic - def foo(a: T, b: T) -> None: - pass + def foo(a: T_co, b: T_co) -> None: pass foo(a=Parent(), b=Child()) def test_type_var_covariant_fail(): - T = TypeVar('T', covariant=True) + T_co = TypeVar('T_co', covariant=True) @pedantic - def foo(a: T, b: T) -> None: - pass + def foo(a: T_co, b: T_co) -> None: pass with pytest.raises(PedanticTypeVarMismatchException): foo(a=Child(), b=Parent()) def test_type_var_contravariant(): - T = TypeVar('T', contravariant=True) + T_contra = TypeVar('T_contra', contravariant=True) @pedantic - def foo(a: T, b: T) -> None: - pass + def foo(a: T_contra, b: T_contra) -> None: pass foo(a=Child(), b=Parent()) def test_type_var_contravariant_fail(): - T = TypeVar('T', contravariant=True) + T_contra = TypeVar('T_contra', contravariant=True) @pedantic - def foo(a: T, b: T) -> None: - pass + def foo(a: T_contra, b: T_contra) -> None: pass with pytest.raises(PedanticTypeVarMismatchException): foo(a=Parent(), b=Child()) @@ -1740,8 +1738,7 @@ def foo(a: T, b: T) -> None: def test_class_bad_subclass(): @pedantic - def foo(a: Type[Child]) -> None: - pass + def foo(a: Type[Child]) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=Parent) @@ -1749,8 +1746,7 @@ def foo(a: Type[Child]) -> None: def test_class_any(): @pedantic - def foo(a: Type[Any]) -> None: - pass + def foo(a: Type[Any]) -> None: pass foo(a=str) @@ -1764,8 +1760,7 @@ def wrapper(*args, **kwargs): @pedantic @decorator - def foo(a: 'Child') -> None: - pass + def foo(a: 'Child') -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=Parent()) @@ -1773,21 +1768,16 @@ def foo(a: 'Child') -> None: def test_mismatching_default_type(): @pedantic - def foo(a: str = 1) -> None: - pass + def foo(a: str = 1) -> None: pass with pytest.raises(PedanticTypeCheckException): foo() def test_implicit_default_none(): - """ - Test that if the default value is ``None``, a ``None`` argument can be passed. - - """ + """Test that if the default value is ``None``, a ``None`` argument can be passed.""" @pedantic - def foo(a: Optional[str] = None) -> None: - pass + def foo(a: Optional[str] = None) -> None: pass foo() @@ -1816,16 +1806,14 @@ def generate(a: int) -> Generator[int, int, None]: def test_varargs(): @pedantic - def foo(*args: int) -> None: - pass + def foo(*args: int) -> None: pass foo(1, 2) def test_varargs_fail(): @pedantic - def foo(*args: int) -> None: - pass + def foo(*args: int) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(1, 'a') @@ -1833,16 +1821,14 @@ def foo(*args: int) -> None: def test_kwargs(): @pedantic - def foo(**kwargs: int) -> None: - pass + def foo(**kwargs: int) -> None: pass foo(a=1, b=2) def test_kwargs_fail(): @pedantic - def foo(**kwargs: int) -> None: - pass + def foo(**kwargs: int) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=1, b='a') @@ -1855,29 +1841,27 @@ class FooGeneric(Generic[T_Foo]): pass @pedantic - def foo(a: FooGeneric[str]) -> None: - print(a) + def foo(a: FooGeneric[str]) -> None: pass foo(a=FooGeneric[str]()) def test_newtype(): - myint = NewType("myint", int) + myint = NewType('myint', int) @pedantic def foo(a: myint) -> int: - return 42 + return a - assert foo(a=1) == 42 + assert foo(a=1) == 1 with pytest.raises(PedanticTypeCheckException): - foo(a="a") + foo(a='a') def test_collection(): @pedantic - def foo(a: Collection) -> None: - pass + def foo(a: Collection) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=True) @@ -1885,24 +1869,21 @@ def foo(a: Collection) -> None: def test_binary_io(): @pedantic - def foo(a: BinaryIO) -> None: - print(a) + def foo(a: BinaryIO) -> None: pass foo(a=BytesIO()) def test_text_io(): @pedantic - def foo(a: TextIO) -> None: - print(a) + def foo(a: TextIO) -> None: pass foo(a=StringIO()) def test_binary_io_fail(): @pedantic - def foo(a: TextIO) -> None: - print(a) + def foo(a: TextIO) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=BytesIO()) @@ -1910,8 +1891,7 @@ def foo(a: TextIO) -> None: def test_text_io_fail(): @pedantic - def foo(a: BinaryIO) -> None: - print(a) + def foo(a: BinaryIO) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=StringIO()) @@ -1919,24 +1899,22 @@ def foo(a: BinaryIO) -> None: def test_binary_io_real_file(): @pedantic - def foo(a: BinaryIO) -> None: - print(a) + def foo(a: BinaryIO) -> None: pass - with open(file=TEST_FILE, mode='wb') as f: + with Path(TEST_FILE).open(mode='wb') as f: foo(a=f) - os.remove(TEST_FILE) + Path(TEST_FILE).unlink(missing_ok=True) def test_text_io_real_file(): @pedantic - def foo(a: TextIO) -> None: - print(a) + def foo(a: TextIO) -> None: pass - with open(file=TEST_FILE, mode='w') as f: + with Path(TEST_FILE).open(mode='w') as f: foo(a=f) - os.remove(TEST_FILE) + Path(TEST_FILE).unlink() def test_pedantic_return_type_var_fail(): @@ -1944,7 +1922,7 @@ def test_pedantic_return_type_var_fail(): @pedantic def foo(a: T, b: T) -> T: - return 'a' + return str(a) + str(b) with pytest.raises(PedanticTypeCheckException): foo(a=4, b=2) @@ -1952,12 +1930,10 @@ def foo(a: T, b: T) -> T: def test_callable(): @pedantic - def foo_1(a: Callable[..., int]) -> None: - print(a) + def foo_1(a: Callable[..., int]) -> None: pass @pedantic - def foo_2(a: Callable) -> None: - print(a) + def foo_2(a: Callable) -> None: pass def some_callable() -> int: return 4 @@ -1970,20 +1946,16 @@ def some_callable() -> int: def test_list(): @pedantic - def foo_1(a: List[int]) -> None: - print(a) + def foo_1(a: List[int]) -> None: pass @pedantic - def foo_2(a: List) -> None: - print(a) + def foo_2(a: List) -> None: pass @pedantic - def foo_3(a: list) -> None: - print(a) + def foo_3(a: list) -> None: pass @pedantic - def foo_4(a: list[int]) -> None: - print(a) + def foo_4(a: list[int]) -> None: pass foo_1(a=[1, 2]) @@ -1998,20 +1970,16 @@ def foo_4(a: list[int]) -> None: def test_dict(): @pedantic - def foo_1(a: Dict[str, int]) -> None: - print(a) + def foo_1(a: Dict[str, int]) -> None: pass @pedantic - def foo_2(a: Dict) -> None: - print(a) + def foo_2(a: Dict) -> None: pass @pedantic - def foo_3(a: dict) -> None: - print(a) + def foo_3(a: dict) -> None: pass @pedantic - def foo_4(a: dict[str, int]) -> None: - print(a) + def foo_4(a: dict[str, int]) -> None: pass foo_1(a={'x': 2}) @@ -2026,8 +1994,7 @@ def foo_4(a: dict[str, int]) -> None: def test_sequence(): @pedantic - def foo(a: Sequence[str]) -> None: - print(a) + def foo(a: Sequence[str]) -> None: pass for value in [('a', 'b'), ['a', 'b'], 'abc']: foo(a=value) @@ -2035,8 +2002,7 @@ def foo(a: Sequence[str]) -> None: def test_sequence_no_type_args(): @pedantic - def foo(a: Sequence) -> None: - print(a) + def foo(a: Sequence) -> None: pass for value in [('a', 'b'), ['a', 'b'], 'abc']: with pytest.raises(PedanticTypeCheckException): @@ -2045,8 +2011,7 @@ def foo(a: Sequence) -> None: def test_iterable(): @pedantic - def foo(a: Iterable[str]) -> None: - print(a) + def foo(a: Iterable[str]) -> None: pass for value in [('a', 'b'), ['a', 'b'], 'abc']: foo(a=value) @@ -2054,8 +2019,7 @@ def foo(a: Iterable[str]) -> None: def test_iterable_no_type_args(): @pedantic - def foo(a: Iterable) -> None: - print(a) + def foo(a: Iterable) -> None: pass for value in [('a', 'b'), ['a', 'b'], 'abc']: with pytest.raises(PedanticTypeCheckException): @@ -2064,8 +2028,7 @@ def foo(a: Iterable) -> None: def test_container(): @pedantic - def foo(a: Container[str]) -> None: - print(a) + def foo(a: Container[str]) -> None: pass for value in [('a', 'b'), ['a', 'b'], 'abc']: foo(a=value) @@ -2073,8 +2036,7 @@ def foo(a: Container[str]) -> None: def test_container_no_type_args(): @pedantic - def foo(a: Container) -> None: - print(a) + def foo(a: Container) -> None: pass for value in [('a', 'b'), ['a', 'b'], 'abc']: with pytest.raises(PedanticTypeCheckException): @@ -2083,12 +2045,10 @@ def foo(a: Container) -> None: def test_set(): @pedantic - def foo_1(a: AbstractSet[int]) -> None: - print(a) + def foo_1(a: AbstractSet[int]) -> None: pass @pedantic - def foo_2(a: Set[int]) -> None: - print(a) + def foo_2(a: Set[int]) -> None: pass for value in [set(), {6}]: foo_1(a=value) @@ -2097,16 +2057,13 @@ def foo_2(a: Set[int]) -> None: def test_set_no_type_args(): @pedantic - def foo_1(a: AbstractSet) -> None: - print(a) + def foo_1(a: AbstractSet) -> None: pass @pedantic - def foo_2(a: Set) -> None: - print(a) + def foo_2(a: Set) -> None: pass @pedantic - def foo_3(a: set) -> None: - print(a) + def foo_3(a: set) -> None: pass for value in [set(), {6}]: with pytest.raises(PedanticTypeCheckException): @@ -2121,12 +2078,10 @@ def foo_3(a: set) -> None: def test_tuple(): @pedantic - def foo_1(a: Tuple[int, int]) -> None: - print(a) + def foo_1(a: Tuple[int, int]) -> None: pass @pedantic - def foo_2(a: Tuple[int, ...]) -> None: - print(a) + def foo_2(a: Tuple[int, ...]) -> None: pass foo_1(a=(1, 2)) foo_2(a=(1, 2)) @@ -2134,12 +2089,10 @@ def foo_2(a: Tuple[int, ...]) -> None: def test_tuple_no_type_args(): @pedantic - def foo_1(a: Tuple) -> None: - print(a) + def foo_1(a: Tuple) -> None: pass @pedantic - def foo_2(a: tuple) -> None: - print(a) + def foo_2(a: tuple) -> None: pass with pytest.raises(PedanticTypeCheckException): foo_1(a=(1, 2)) @@ -2150,8 +2103,7 @@ def foo_2(a: tuple) -> None: def test_empty_tuple(): @pedantic - def foo(a: Tuple[()]) -> None: - print(a) + def foo(a: Tuple[()]) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=()) @@ -2159,16 +2111,13 @@ def foo(a: Tuple[()]) -> None: def test_class(): @pedantic - def foo_1(a: Type[Parent]) -> None: - print(a) + def foo_1(a: Type[Parent]) -> None: pass @pedantic - def foo_2(a: Type[TypeVar('UnboundType')]) -> None: - print(a) + def foo_2(a: Type[TypeVar('UnboundType')]) -> None: pass @pedantic - def foo_3(a: Type[TypeVar('BoundType', bound=Parent)]) -> None: - print(a) + def foo_3(a: Type[TypeVar('BoundType', bound=Parent)]) -> None: pass foo_1(a=Child) foo_2(a=Child) @@ -2177,12 +2126,10 @@ def foo_3(a: Type[TypeVar('BoundType', bound=Parent)]) -> None: def test_class_no_type_vars(): @pedantic - def foo_1(a: Type) -> None: - print(a) + def foo_1(a: Type) -> None: pass @pedantic - def foo_2(a: type) -> None: - print(a) + def foo_2(a: type) -> None: pass with pytest.raises(PedanticTypeCheckException): foo_1(a=Child) @@ -2193,8 +2140,7 @@ def foo_2(a: type) -> None: def test_class_not_a_class(): @pedantic - def foo(a: Type[Parent]) -> None: - print(a) + def foo(a: Type[Parent]) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=1) @@ -2202,8 +2148,7 @@ def foo(a: Type[Parent]) -> None: def test_complex(): @pedantic - def foo(a: complex) -> None: - print(a) + def foo(a: complex) -> None: pass foo(a=complex(1, 5)) @@ -2213,8 +2158,7 @@ def foo(a: complex) -> None: def test_float(): @pedantic - def foo(a: float) -> None: - print(a) + def foo(a: float) -> None: pass foo(a=1.5) @@ -2286,7 +2230,7 @@ def genfunc() -> Generator[int, str, List[str]]: gen = genfunc() - with pytest.raises(StopIteration): + with pytest.raises(StopIteration): # noqa: PT012 value = next(gen) while True: value = gen.send(str(value)) @@ -2315,7 +2259,7 @@ def genfunc() -> Iterator[int]: gen = genfunc() - with pytest.raises(PedanticTypeCheckException): + with pytest.raises(PedanticTypeCheckException): # noqa: PT012 value = next(gen) while True: value = gen.send(str(value)) @@ -2344,8 +2288,9 @@ def genfunc() -> Iterable[int]: gen = genfunc() - with pytest.raises(PedanticTypeCheckException): - value = next(gen) + value = next(gen) + + with pytest.raises(PedanticTypeCheckException): # noqa: PT012 while True: value = gen.send(str(value)) assert isinstance(value, int) @@ -2473,13 +2418,13 @@ def test_inherited_class_method(): class Parent: @classmethod def foo(cls, x: str) -> str: - return cls.__name__ + return cls.__name__ + x @pedantic_class class Child(Parent): pass - assert Child.foo(x='bar') == 'Parent' + assert Child.foo(x='bar') == 'Parentbar' with pytest.raises(PedanticTypeCheckException): Child.foo(x=1) @@ -2516,8 +2461,7 @@ def bar() -> NoReturn: def test_literal(): @pedantic - def foo(a: Literal[1, True, 'x', b'y', 404]) -> None: - print(a) + def foo(a: Literal[1, True, 'x', b'y', 404]) -> None: pass foo(a=404) foo(a=True) @@ -2529,8 +2473,7 @@ def foo(a: Literal[1, True, 'x', b'y', 404]) -> None: def test_literal_union(): @pedantic - def foo(a: Union[str, Literal[1, 6, 8]]) -> None: - print(a) + def foo(a: Union[str, Literal[1, 6, 8]]) -> None: pass foo(a=6) @@ -2540,8 +2483,7 @@ def foo(a: Union[str, Literal[1, 6, 8]]) -> None: def test_literal_illegal_value(): @pedantic - def foo(a: Literal[1, 1.1]) -> None: - print(a) + def foo(a: Literal[1, 1.1]) -> None: pass with pytest.raises(PedanticTypeCheckException): foo(a=4) @@ -2554,7 +2496,7 @@ class MyEnum(Enum): A = 'a' -def test_enum_aggregate(): +def test_enum_aggregate(): # noqa: C901 T = TypeVar('T', bound=IntEnum) @pedantic_class @@ -2565,7 +2507,7 @@ def __init__(self, value: Union[int, str, List[T]]) -> None: assert len(self.enum) < 10 if value == '': - raise ValueError(f'Parameter "value" cannot be empty!') + raise ValueError('Parameter "value" cannot be empty!') if isinstance(value, list): self._value = ''.join([str(x.value) for x in value]) @@ -2584,6 +2526,9 @@ def __eq__(self, other: Union['EnumAggregate', str]) -> bool: return self._value == other._value + def __hash__(self): + return hash(self._value) + def __str__(self) -> str: return self._value @@ -2631,7 +2576,7 @@ def f(x: list[dict[int, tuple[float, str]]]) -> list[Any]: def test_dataclass_protocol(): - class IsDataclass(typing.Protocol): + class IsDataclass(Protocol): __dataclass_fields__: ClassVar[Dict] @dataclass @@ -2646,7 +2591,7 @@ def foo(x: IsDataclass) -> IsDataclass: def test_dataclass_protocol_in_type(): - class IsDataclass(typing.Protocol): + class IsDataclass(Protocol): __dataclass_fields__: ClassVar[Dict] @dataclass @@ -2661,7 +2606,7 @@ def foo(x: type[IsDataclass]) -> IsDataclass: def test_dataclass_protocol_in_type_with_union(): - class IsDataclass(typing.Protocol): + class IsDataclass(Protocol): __dataclass_fields__: ClassVar[Dict] @dataclass @@ -2693,8 +2638,6 @@ def f(a: int, b: int) -> int: def test_typing_never(): - from typing import Never - @pedantic def never_call_me(arg: Never) -> None: pass @@ -2713,13 +2656,11 @@ def bar() -> Never: with pytest.raises(PedanticTypeCheckException): foo() - with pytest.raises(expected_exception=PedanticTypeCheckException) as exc: + with pytest.raises(expected_exception=PedanticTypeCheckException): never_call_me(arg='42') def test_literal_string(): - from typing import LiteralString - @pedantic def foo(s: LiteralString) -> None: pass @@ -2732,8 +2673,6 @@ def foo(s: LiteralString) -> None: def test_self_type(): - from typing import Self - class Bar: pass @@ -2785,8 +2724,6 @@ def h_2(cls) -> Self: def test_using_self_type_annotation_outside_class(): - from typing import Self - @pedantic def f() -> Self: return 'hi' @@ -2796,24 +2733,31 @@ def f() -> Self: def test_type_var_tuple(): - from typing import TypeVarTuple, Generic - - Ts = TypeVarTuple('Ts') - @pedantic_class class Array(Generic[*Ts]): def __init__(self, *args: *Ts) -> None: - self._values = args + self.values = args @pedantic def add_dimension(a: Array[*Ts], value: int) -> Array[int, *Ts]: - return Array[int, *Ts](value, *a._values) + return Array[int, *Ts](value, *a.values) array = Array[int, float](42, 3.4) - array_2 = Array[bool, int, float, str](True, 4, 3.4, 'hi') + Array[bool, int, float, str](True, 4, 3.4, 'hi') extended_array = add_dimension(a=array, value=42) - assert extended_array._values == (42, 42, 3.4) + assert extended_array.values == (42, 42, 3.4) # this is too complicated at the moment # with pytest.raises(expected_exception=PedanticTypeCheckException): - # Array[int, float](4.2, 3.4) + # Array[int, float](4.2, 3.4) # noqa: ERA001 + + +def test_callable_imported_from_collections(): + @pedantic + def foo(f: CollectionCallable[[int], int]) -> int: + return f(2) + + assert foo(f=lambda x: x) == 2 + + with pytest.raises(expected_exception=PedanticTypeCheckException, match=r"Expected type but 2 of type was the return value which does not match."): + foo(f=lambda x: str(x)) # noqa: PLW0108 diff --git a/tests/decorators/pedantic/test_pedantic_async.py b/tests/decorators/pedantic/test_pedantic_async.py index aa9b9221..c6a78391 100644 --- a/tests/decorators/pedantic/test_pedantic_async.py +++ b/tests/decorators/pedantic/test_pedantic_async.py @@ -3,8 +3,8 @@ import pytest from pedantic.decorators.class_decorators import pedantic_class -from pedantic.exceptions import PedanticTypeCheckException from pedantic.decorators.fn_deco_pedantic import pedantic +from pedantic.exceptions import PedanticTypeCheckException @pytest.mark.asyncio diff --git a/tests/decorators/pedantic/test_pedantic_class.py b/tests/decorators/pedantic/test_pedantic_class.py index c63bf9c4..3c292cc0 100644 --- a/tests/decorators/pedantic/test_pedantic_class.py +++ b/tests/decorators/pedantic/test_pedantic_class.py @@ -1,15 +1,15 @@ +# ruff: noqa: PYI041, UP006, UP007, UP035, UP045 + from abc import ABC, abstractmethod from dataclasses import dataclass from enum import IntEnum -from typing import Any, Optional, Callable, Union, Dict, List +from typing import Any, Callable, List, Optional, Union import pytest -from pedantic.env_var_logic import disable_pedantic from pedantic import overrides from pedantic.decorators.class_decorators import pedantic_class -from pedantic.exceptions import PedanticOverrideException, PedanticTypeCheckException, \ - PedanticCallWithArgsException +from pedantic.exceptions import PedanticCallWithArgsException, PedanticOverrideException, PedanticTypeCheckException def test_constructor(): @@ -84,8 +84,7 @@ def __init__(self, a: int) -> None: def calc(self, b: int) -> int: return self.a - b - def print(self, s: str) -> None: - print(f'{self.a} and {s}') + def print(self, s: str) -> None: pass m = MyClass(a=5) m.calc(b=42) @@ -110,8 +109,7 @@ def calc(self, b: int) -> float: def dream(self, b) -> int: return self.a * b - def print(self, s: str): - print(f'{self.a} and {s}') + def print(self, s: str): pass m = MyClass(a=5) with pytest.raises(expected_exception=PedanticTypeCheckException): @@ -142,7 +140,7 @@ def __init__(self, s: str) -> None: self.s = s @staticmethod - def generator() -> 'MyClas': + def generator() -> 'MyClas': # noqa: F821 return MyClass(s='generated') with pytest.raises(expected_exception=PedanticTypeCheckException): @@ -156,15 +154,16 @@ def __contains__(self, item: int) -> bool: return True m = MyClass() - print(42 in m) + assert (42 in m) is True + with pytest.raises(expected_exception=PedanticTypeCheckException): - print('something' in m) + assert 'something' in m def test_type_annotation_string_typo(): @pedantic_class class MyClass: - def compare(self, other: 'MyClas') -> bool: + def compare(self, other: 'MyClas') -> bool: # noqa: F821 return self == other def fixed_compare(self, other: 'MyClass') -> bool: @@ -185,9 +184,11 @@ def __init__(self, a: int) -> None: def bunk(self) -> int: ''' Function with correct docstring. Yes, single-quoted docstrings are allowed too. + Returns: int: 42 - ''' + ''' # noqa: D300, Q002 + return self.a foo = Foo(a=10) @@ -307,10 +308,6 @@ def funcy(self, b: str) -> str: def bunk(self) -> int: return self.a - f = Foo(a=40002) - f.func(b='Hi') - f.bunk() - p = Parent() p.func(b='Hi') p.bunk() @@ -320,8 +317,8 @@ def test_static_method_with_sloppy_type_annotation(): @pedantic_class class MyStaticClass: @staticmethod - def double_func(a: int) -> int: - x, y = MyStaticClass.static_bar() + def double_func(a: int) -> int: # noqa: ARG004 + x, _ = MyStaticClass.static_bar() return x @staticmethod @@ -329,12 +326,12 @@ def static_bar() -> (int, int): # this is wrong. Correct would be Tuple[int, in return 0, 1 with pytest.raises(expected_exception=PedanticTypeCheckException): - print(MyStaticClass.double_func(a=0)) + MyStaticClass.double_func(a=0) def test_property(): @pedantic_class - class MyClass(object): + class MyClass: def __init__(self, some_arg: Any) -> None: self._some_attribute = some_arg @@ -360,16 +357,16 @@ def calc(self, value: float) -> float: assert m.some_attribute == 42 m.some_attribute = '100' - assert m._some_attribute == '100' + assert m._some_attribute == '100' # noqa: SLF001 m.calc(value=42.0) with pytest.raises(expected_exception=PedanticTypeCheckException): - print(m.some_attribute) + m.some_attribute # noqa: B018 def test_property_getter_and_setter_misses_type_hints(): @pedantic_class - class MyClass(object): + class MyClass: def __init__(self, some_arg: int) -> None: self._some_attribute = some_arg @@ -392,7 +389,8 @@ def calc(self, value: float) -> float: m.some_attribute = 100 with pytest.raises(expected_exception=PedanticTypeCheckException): - print(m.some_attribute) + m.some_attribute # noqa: B018 + m.calc(value=42.0) with pytest.raises(expected_exception=PedanticTypeCheckException): m.calc(value=42) @@ -432,8 +430,7 @@ def test_class_method_type_annotation_missing(): @pedantic_class class MyClass: @classmethod - def do(cls): - print('i did something') + def do(cls): pass with pytest.raises(expected_exception=PedanticTypeCheckException): MyClass.do() @@ -443,8 +440,7 @@ def test_class_method_type_annotation(): @pedantic_class class MyClass: @classmethod - def do(cls) -> None: - print('i did something') + def do(cls) -> None: pass @classmethod def calc(cls, x: Union[int, float]) -> int: @@ -522,44 +518,3 @@ def method(self) -> int: Foo.classmethod() with pytest.raises(expected_exception=PedanticTypeCheckException): Foo().method() - - -def test_pedantic_class_disable_pedantic(): - disable_pedantic() - - @pedantic_class - class MyClass: - def __init__(self, pw, **kwargs): - self._validate_str_len(new_values=kwargs) - - @staticmethod - def _validate_str_len(new_values: Dict[str, Any]) -> None: - return 42 - - def method(pw, **kwargs): - MyClass._validate_str_len(new_values=kwargs) - - MyClass._validate_str_len(None) - MyClass._validate_str_len(new_values={1: 1, 2: 2}) - MyClass(name='hi', age=12, pw='123') - - -def test_disable_pedantic_2(): - """ https://github.com/LostInDarkMath/pedantic-python-decorators/issues/37 """ - - disable_pedantic() - - @pedantic_class - class Foo: - def __init__(self) -> None: - self._value = 42 - - def do(self) -> None: - print(self.bar(value=self._value)) - - @staticmethod - def bar(value: int) -> int: - return value + 75 - - f = Foo() - f.do() diff --git a/tests/decorators/pedantic/test_pedantic_class_docstring.py b/tests/decorators/pedantic/test_pedantic_class_docstring.py index 7d81a7da..4539adc5 100644 --- a/tests/decorators/pedantic/test_pedantic_class_docstring.py +++ b/tests/decorators/pedantic/test_pedantic_class_docstring.py @@ -8,15 +8,18 @@ def test_require_docstring(): @pedantic_class_require_docstring class MyClass: def __init__(self, s: str) -> None: - """Constructor + """ + Constructor Args: s (str): name """ + self.s = s def double(self, b: int) -> str: - """some method + """ + Some method Args: b (int): magic number @@ -25,15 +28,18 @@ def double(self, b: int) -> str: str: cool stuff """ + return self.s + str(b) @staticmethod def generator() -> 'MyClass': - """Static + """ + Static Returns: MyClass: instance """ + return MyClass(s='generated') m = MyClass.generator() @@ -45,20 +51,24 @@ def test_typo_docstring(): @pedantic_class_require_docstring class MyClass: def __init__(self, s: str) -> None: - """Constructor + """ + Constructor Args: s (str): name """ + self.s = s @staticmethod def generator() -> 'MyClass': - """Static + """ + Static Returns: MyClas: instance """ + return MyClass(s='generated') @@ -67,21 +77,24 @@ def test_wrong_docstring(): @pedantic_class_require_docstring class MyClass: def __init__(self, s: str) -> None: - """Constructor + """ + Constructor Args: s (str): name """ + self.s = s def double(self, b: int) -> str: - """some method + """ + Some method Args: b (float): magic number Returns: str: cool stuff - """ + return self.s + str(b) diff --git a/tests/decorators/test_async_context_manager.py b/tests/decorators/test_async_context_manager.py index bd0f167b..c0202f29 100644 --- a/tests/decorators/test_async_context_manager.py +++ b/tests/decorators/test_async_context_manager.py @@ -42,7 +42,7 @@ async def foo(): assert before is False assert after is False - with pytest.raises(expected_exception=ValueError): + with pytest.raises(expected_exception=ValueError, match='oh no'): # noqa: PT012 async with foo() as f: assert before is True assert after is False diff --git a/tests/decorators/test_class_decorators.py b/tests/decorators/test_class_decorators.py index 08162bcd..cb4f858f 100644 --- a/tests/decorators/test_class_decorators.py +++ b/tests/decorators/test_class_decorators.py @@ -1,4 +1,4 @@ -from pedantic.decorators.class_decorators import trace_class, timer_class +from pedantic.decorators.class_decorators import trace_class def test_trace_class(): @@ -17,19 +17,3 @@ def generator() -> 'MyClass': m = MyClass.generator() m.double(b=42) - -def test_timer_class(): - @timer_class - class MyClass: - def __init__(self, s: str) -> None: - self.s = s - - def double(self, b: int) -> str: - return self.s + str(b) - - @staticmethod - def generator() -> 'MyClass': - return MyClass(s='generated') - - m = MyClass.generator() - m.double(b=42) diff --git a/tests/decorators/test_combination_of_decorators.py b/tests/decorators/test_combination_of_decorators.py index 3768b81c..aadb73cb 100644 --- a/tests/decorators/test_combination_of_decorators.py +++ b/tests/decorators/test_combination_of_decorators.py @@ -2,13 +2,13 @@ import pytest -from pedantic.decorators.class_decorators import pedantic_class, for_all_methods +from pedantic import overrides +from pedantic.decorators.class_decorators import for_all_methods, pedantic_class +from pedantic.decorators.fn_deco_pedantic import pedantic from pedantic.decorators.fn_deco_validate.exceptions import ParameterException +from pedantic.decorators.fn_deco_validate.fn_deco_validate import Parameter, ReturnAs, validate from pedantic.decorators.fn_deco_validate.validators import Min -from pedantic.exceptions import PedanticException, PedanticTypeCheckException, PedanticCallWithArgsException -from pedantic.decorators.fn_deco_pedantic import pedantic -from pedantic import overrides -from pedantic.decorators.fn_deco_validate.fn_deco_validate import validate, Parameter, ReturnAs +from pedantic.exceptions import PedanticCallWithArgsException, PedanticException, PedanticTypeCheckException def test_pedantic_overrides(): @@ -150,7 +150,7 @@ def test_pedantic_class_static_method_2(): @for_all_methods(staticmethod) @pedantic_class class MyClass: - def some_calculation(x: int) -> int: + def some_calculation(x: int) -> int: # noqa: N805 return x m = MyClass() diff --git a/tests/decorators/test_context_manager.py b/tests/decorators/test_context_manager.py index c4a0c4b1..a07115da 100644 --- a/tests/decorators/test_context_manager.py +++ b/tests/decorators/test_context_manager.py @@ -40,7 +40,7 @@ def foo(): assert before is False assert after is False - with pytest.raises(expected_exception=ValueError): + with pytest.raises(expected_exception=ValueError, match='oh no'): # noqa: SIM117, PT012 with foo() as f: assert before is True assert after is False diff --git a/tests/decorators/test_deprecated.py b/tests/decorators/test_deprecated.py index d5a4fd5c..5a42a8f0 100644 --- a/tests/decorators/test_deprecated.py +++ b/tests/decorators/test_deprecated.py @@ -7,16 +7,16 @@ def test_deprecated_no_args(): @deprecated def old_method(i: int) -> str: return str(i) - with pytest.warns(DeprecationWarning, match="deprecated"): + with pytest.warns(DeprecationWarning, match='deprecated'): old_method(42) def test_deprecated_with_args(): - @deprecated(message="my deprecation message") + @deprecated(message='my deprecation message') def old_method(i: int) -> str: return str(i) - with pytest.warns(DeprecationWarning, match="my deprecation message"): + with pytest.warns(DeprecationWarning, match='my deprecation message'): old_method(42) @@ -26,5 +26,5 @@ async def test_deprecated_async(): async def old_method(i: int) -> str: return str(i) - with pytest.warns(DeprecationWarning, match="deprecated"): + with pytest.warns(DeprecationWarning, match='deprecated'): await old_method(42) diff --git a/tests/decorators/test_docstring.py b/tests/decorators/test_docstring.py index 34fc2a4c..0bdaaf16 100644 --- a/tests/decorators/test_docstring.py +++ b/tests/decorators/test_docstring.py @@ -1,16 +1,15 @@ +# ruff: noqa: D411, D414, D417, D213, UP006, UP035, UP045 + from typing import List, Optional import pytest -from pedantic import is_enabled -from pedantic.exceptions import PedanticTypeCheckException, PedanticDocstringException -from pedantic.decorators.fn_deco_pedantic import pedantic_require_docstring, pedantic -from pedantic.decorators.class_decorators import pedantic_class_require_docstring, pedantic_class +from pedantic.decorators.class_decorators import pedantic_class, pedantic_class_require_docstring +from pedantic.decorators.fn_deco_pedantic import pedantic, pedantic_require_docstring +from pedantic.exceptions import PedanticDocstringException, PedanticTypeCheckException def test_no_docstring(): - assert is_enabled() - with pytest.raises(expected_exception=PedanticDocstringException): @pedantic_require_docstring def calc(n: int, m: int, i: int) -> int: @@ -171,7 +170,6 @@ def test_keep_it_simple(): @pedantic_require_docstring def calc() -> None: """Gets and prints the spreadsheet's header columns""" - pass calc() @@ -181,7 +179,6 @@ def test_docstring_misses_argument(): @pedantic_require_docstring def calc(name: str) -> None: """Gets and prints the spreadsheet's header columns""" - print('hi ' + name) def test_keep_it_simple_2_corrected(): @@ -192,7 +189,6 @@ def calc(name: str) -> None: Args: name (str): the name """ - print('hi ' + name) calc(name='maria') @@ -264,7 +260,6 @@ def calc(file_loc: str, print_cols: bool): Returns: list: a list of strings representing the header columns """ - print([file_loc, str(print_cols)]) def test_return_nothing_but_document_return_value_2(): @@ -281,7 +276,6 @@ def calc(file_loc: str, print_cols: bool) -> None: Returns: list: a list of strings representing the header columns """ - print([file_loc, str(print_cols)]) def test_return_value_1_corrected(): @@ -295,7 +289,6 @@ def calc(file_loc: str, print_cols: bool) -> None: (default is False) """ - a = [file_loc, str(print_cols)] calc(file_loc='Hi', print_cols=False) @@ -369,7 +362,7 @@ def __contains__(self, substring: str) -> bool: def test_undocumented_arg_3(): - with pytest.raises(expected_exception=PedanticDocstringException): + with pytest.raises(expected_exception=PedanticDocstringException, match=r'There are 2 argument\(s\) documented, but 3 are actually taken'): @pedantic def calc(a: int, b: float, c: str) -> str: """Returns some cool string @@ -383,8 +376,6 @@ def calc(a: int, b: float, c: str) -> str: """ return str(a) + str(b) + c - calc(a=42, b=3.14, c='hi') - def test_pedantic_1_corrected(): @pedantic @@ -408,12 +399,11 @@ def test_documented_none_as_return_type(): with pytest.raises(expected_exception=PedanticDocstringException): @pedantic_require_docstring def calc() -> None: - """some cool stuff + """Some cool stuff Returns: None: the evil void """ - pass def test_exception_in_docstring_parser(): diff --git a/tests/decorators/test_frozen_dataclass.py b/tests/decorators/test_frozen_dataclass.py index 0d9b892a..25955d3e 100644 --- a/tests/decorators/test_frozen_dataclass.py +++ b/tests/decorators/test_frozen_dataclass.py @@ -1,6 +1,7 @@ +# ruff: noqa: UP035 from abc import ABC -from dataclasses import dataclass, FrozenInstanceError -from typing import List, Dict, Set, Tuple, Awaitable, Callable, Generic, TypeVar, Optional +from dataclasses import FrozenInstanceError, dataclass +from typing import Awaitable, Callable, Generic, Optional, TypeVar import pytest @@ -17,14 +18,14 @@ class Foo: @frozen_type_safe_dataclass class B: - v: Set[int] + v: set[int] @frozen_type_safe_dataclass class A: - foo: List[int] - bar: Dict[str, str] - values: Tuple[B, B] + foo: list[int] + bar: dict[str, str] + values: tuple[B, B] def test_equals_and_hash(): @@ -78,8 +79,8 @@ def test_validate_types(): with pytest.raises(expected_exception=PedanticTypeCheckException) as err: bar.validate_types() - expected = 'In dataclass "Foo" in field "a": Type hint is incorrect: Argument 6.6 of type ' \ - 'does not match expected type .' + expected = ("In dataclass \"Foo\" in field \"a\": Type hint is incorrect: Argument 6.6 of type " + "does not match expected type .") assert err.value.args[0] == expected @@ -134,8 +135,8 @@ def __post_init__(self) -> None: with pytest.raises(expected_exception=PedanticTypeCheckException) as err: A(foo=42.7) - assert err.value.args[0] == ('In dataclass "A" in field "foo": Type hint is incorrect: Argument 42.7 of type' - ' does not match expected type .') + assert err.value.args[0] == ("In dataclass \"A\" in field \"foo\": Type hint is incorrect: Argument 42.7 of type" + " does not match expected type .") # we check that the __post_init__ method is executed assert b == 33 @@ -149,8 +150,8 @@ class A: with pytest.raises(expected_exception=PedanticTypeCheckException) as err: A(foo=42.7) - assert err.value.args[0] == ('In dataclass "A" in field "foo": Type hint is incorrect: Argument 42.7 of type ' - ' does not match expected type .') + assert err.value.args[0] == ("In dataclass \"A\" in field \"foo\": Type hint is incorrect: Argument 42.7 of type " + " does not match expected type .") def test_frozen_dataclass_with_empty_braces(): @@ -241,7 +242,6 @@ class A: def __post_init__(self): nonlocal i i += 1 - print('hello a') @frozen_type_safe_dataclass class B(A): @@ -250,7 +250,6 @@ class B(A): def __post_init__(self): nonlocal i i *= 10 - print('hello b') A(bar=3) assert i == 2 @@ -275,7 +274,6 @@ class A: def __post_init__(self): nonlocal i i += 1 - print('hello a') @frozen_type_safe_dataclass class B(A): @@ -313,10 +311,10 @@ async def _cb_2() -> str: def test_type_safe_frozen_dataclass_with_forward_ref(): T = TypeVar('T') - class State(Generic[T], ABC): + class State(ABC, Generic[T]): pass - class StateMachine(Generic[T], ABC): + class StateMachine(ABC, Generic[T]): pass @frozen_type_safe_dataclass @@ -344,11 +342,11 @@ class MachineStateMachine(StateMachine[MachineState]): def test_forward_ref_to_itself(): - """ Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/72 """ + """Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/72""" @frozen_type_safe_dataclass class Comment: - replies: List['Comment'] + replies: list['Comment'] comment = Comment(replies=[Comment(replies=[])]) comment.copy_with(replies=[Comment(replies=[])]) @@ -356,12 +354,12 @@ class Comment: def test_forward_ref_to_itself_while_class_not_in_scope(): - """ Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/72 """ + """Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/72""" def _scope(): @frozen_type_safe_dataclass class Comment: - replies: List['Comment'] + replies: list['Comment'] def _make(replies=None): return Comment(replies=replies or []) diff --git a/tests/decorators/test_in_subprocess.py b/tests/decorators/test_in_subprocess.py index a8e9a8cd..5bd856eb 100644 --- a/tests/decorators/test_in_subprocess.py +++ b/tests/decorators/test_in_subprocess.py @@ -6,7 +6,7 @@ from multiprocess import Pipe from pedantic import in_subprocess -from pedantic.decorators.fn_deco_in_subprocess import _inner, SubprocessError +from pedantic.decorators.fn_deco_in_subprocess import SubprocessError, _inner @pytest.mark.asyncio @@ -22,13 +22,13 @@ def f() -> int: async def test_in_subprocess_custom_object(): class Foo: def __init__(self, v) -> None: - self._value = v + self.value = v @in_subprocess def f() -> Foo: return Foo(v=42) - assert (await f())._value == 42 + assert (await f()).value == 42 @pytest.mark.asyncio @@ -82,7 +82,7 @@ def f() -> NoReturn: @pytest.mark.asyncio async def test_not_in_subprocess_blocks(): async def f() -> int: - time.sleep(0.1) + time.sleep(0.1) # noqa: ASYNC251 return 42 async def t() -> None: @@ -109,7 +109,7 @@ def f(a: int, b: int) -> int: def test_inner_function_sync(): - """ Needed for line coverage""" + """Needed for line coverage""" rx, tx = Pipe(duplex=False) _inner(tx, lambda x: 1 / x, x=42) @@ -121,7 +121,7 @@ def test_inner_function_sync(): def test_inner_function_async(): - """ Needed for line coverage""" + """Needed for line coverage""" async def foo(x): return 1/x diff --git a/tests/decorators/test_mock.py b/tests/decorators/test_mock.py deleted file mode 100644 index 07c78546..00000000 --- a/tests/decorators/test_mock.py +++ /dev/null @@ -1,10 +0,0 @@ -from pedantic import mock - - -def test_mock() -> None: - @mock(return_value=42) - def my_function(a, b, c): - return a + b + c - - assert my_function(1, 2, 3) == 42 - assert my_function(100, 200, 300) == 42 diff --git a/tests/decorators/test_overrides.py b/tests/decorators/test_overrides.py index fb234870..037d448e 100644 --- a/tests/decorators/test_overrides.py +++ b/tests/decorators/test_overrides.py @@ -1,5 +1,5 @@ import asyncio -from abc import abstractmethod, ABC +from abc import ABC, abstractmethod import pytest diff --git a/tests/decorators/test_rename_kwargs.py b/tests/decorators/test_rename_kwargs.py deleted file mode 100644 index 3f5e9911..00000000 --- a/tests/decorators/test_rename_kwargs.py +++ /dev/null @@ -1,15 +0,0 @@ -from pedantic import rename_kwargs, Rename - - -def test_rename_kwargs(): - @rename_kwargs( - Rename(from_='x', to='a'), - Rename(from_='y', to='b'), - ) - def operation(a: int, b: int) -> int: - return a + b - - operation(4, 5) - operation(a=4, b=5) - operation(x=4, y=5) - operation(x=4, b=5) diff --git a/tests/decorators/test_require_kwargs.py b/tests/decorators/test_require_kwargs.py deleted file mode 100644 index 8b2feb09..00000000 --- a/tests/decorators/test_require_kwargs.py +++ /dev/null @@ -1,29 +0,0 @@ -import pytest - -from pedantic.exceptions import PedanticCallWithArgsException -from pedantic import require_kwargs - - -def test_kwargs(): - @require_kwargs - def calc(n: int, m: int, i: int) -> int: - return n + m + i - - calc(n=1, m=2, i=3) - - -def test_no_kwargs_1(): - @require_kwargs - def calc(n: int, m: int, i: int) -> int: - return n + m + i - - with pytest.raises(expected_exception=PedanticCallWithArgsException): - calc(1, m=2, i=3) - -def test_no_kwargs_2(): - @require_kwargs - def calc(n: int, m: int, i: int) -> int: - return n + m + i - - with pytest.raises(expected_exception=PedanticCallWithArgsException): - calc(1, 2, 3) diff --git a/tests/decorators/test_retry_decorator.py b/tests/decorators/test_retry_decorator.py index eda7bd54..99990e10 100644 --- a/tests/decorators/test_retry_decorator.py +++ b/tests/decorators/test_retry_decorator.py @@ -36,7 +36,7 @@ def foo(): count += 1 raise ValueError('foo') - with pytest.raises(ValueError): + with pytest.raises(ValueError, match='foo'): foo() assert count == 5 @@ -51,7 +51,7 @@ def foo(): count += 1 raise ValueError('foo') - with pytest.raises(ValueError): + with pytest.raises(ValueError, match='foo'): foo() assert count == 1 diff --git a/tests/decorators/test_retry_func.py b/tests/decorators/test_retry_func.py index a42b2438..f953df4d 100644 --- a/tests/decorators/test_retry_func.py +++ b/tests/decorators/test_retry_func.py @@ -2,6 +2,7 @@ from pedantic.decorators.fn_deco_retry import retry_func + def test_retry_positive_no_args(): count = 0 @@ -32,7 +33,7 @@ def foo(): count += 1 raise ValueError('foo') - with pytest.raises(ValueError): + with pytest.raises(ValueError, match='foo'): retry_func(func=foo, attempts=5) assert count == 5 @@ -46,7 +47,7 @@ def foo(): count += 1 raise ValueError('foo') - with pytest.raises(ValueError): + with pytest.raises(ValueError, match='foo'): retry_func(func=foo, attempts=5, exceptions=AssertionError) assert count == 1 diff --git a/tests/decorators/test_small_method_decorators.py b/tests/decorators/test_small_method_decorators.py index fd810067..e32f2bd0 100644 --- a/tests/decorators/test_small_method_decorators.py +++ b/tests/decorators/test_small_method_decorators.py @@ -1,36 +1,8 @@ import asyncio -import warnings import pytest -from pedantic import timer, count_calls, trace, trace_if_returns, does_same_as_function, deprecated, \ - unimplemented, mock, require_kwargs -from pedantic.exceptions import NotImplementedException, PedanticCallWithArgsException - - -def test_unimplemented(): - @unimplemented - def dirt(i: int) -> str: - return str(i) - - with pytest.raises(expected_exception=NotImplementedException): - dirt(42) - - -def test_timer(): - @timer - def operation(i: int) -> str: - return str(i) - - operation(42) - - -def test_count_calls(): - @count_calls - def operation(i: int) -> str: - return str(i) - - operation(42) +from pedantic import trace def test_trace(): @@ -41,51 +13,6 @@ def some_method(x, y): assert some_method(42, 99) == traced_method(42, 99) -def test_trace_if_returns(): - def some_method(x, y): - return x + y - - traced_method = trace_if_returns(100)(some_method) - assert some_method(42, 99) == traced_method(42, 99) - assert some_method(42, 58) == traced_method(42, 58) - - -def test_does_same_as_function(): - def some_method(x, y, z): - return x * (y + z) - - @does_same_as_function(some_method) - def other_method(x, y, z): - return x * y + x * z - - other_method(1, 2, 3) - other_method(4, 5, 6) - - -def test_does_same_as_function_wrong(): - def some_method(x, y, z): - return x * (y + z) - - @does_same_as_function(some_method) - def other_method(x, y, z): - return x * y + z - - other_method(0, 2, 0) - with pytest.raises(expected_exception=AssertionError): - other_method(4, 5, 6) - - -@pytest.mark.asyncio -async def test_count_calls_async(): - @count_calls - async def operation(i: int) -> str: - await asyncio.sleep(0) - return str(i) - - res = await operation(42) - assert res == '42' - - @pytest.mark.asyncio async def test_trace_async(): async def some_method(x, y): @@ -94,91 +21,3 @@ async def some_method(x, y): traced_method = trace(some_method) assert await some_method(42, 99) == await traced_method(42, 99) - - -@pytest.mark.asyncio -async def test_trace_if_returns_async(): - async def some_method(x, y): - await asyncio.sleep(0) - return x + y - - traced_method = trace_if_returns(100)(some_method) - assert await some_method(42, 99) == await traced_method(42, 99) - assert await some_method(42, 58), await traced_method(42, 58) - - -@pytest.mark.asyncio -async def test_timer_async(): - @timer - async def operation(i: int) -> str: - await asyncio.sleep(0.05) - return str(i) - - await operation(42) - - -@pytest.mark.asyncio -async def test_does_same_as_function_async(): - async def some_method(x, y, z): - await asyncio.sleep(0) - return x * (y + z) - - @does_same_as_function(some_method) - async def other_method(x, y, z): - await asyncio.sleep(0) - return x * y + x * z - - await other_method(1, 2, 3) - await other_method(4, 5, 6) - - -@pytest.mark.asyncio -async def test_does_same_as_function_async_and_sync(): - def some_method(x, y, z): - return x * (y + z) - - @does_same_as_function(some_method) - async def other_method(x, y, z): - await asyncio.sleep(0) - return x * y + x * z - - await other_method(1, 2, 3) - await other_method(4, 5, 6) - - -@pytest.mark.asyncio -async def test_does_same_as_function_wrong(): - async def some_method(x, y, z): - await asyncio.sleep(0) - return x * (y + z) - - @does_same_as_function(some_method) - async def other_method(x, y, z): - await asyncio.sleep(0) - return x * y + z - - await other_method(0, 2, 0) - - with pytest.raises(expected_exception=AssertionError): - await other_method(4, 5, 6) - - -@pytest.mark.asyncio -async def test_mock_async(): - @mock(return_value=42) - async def my_function(a, b, c): return a + b + c - - assert await my_function(1, 2, 3) == 42 - assert await my_function(100, 200, 300) == 42 - - -@pytest.mark.asyncio -async def test_require_kwargs(): - @require_kwargs - async def calc(n: int, m: int, i: int) -> int: - return n + m + i - - await calc(n=1, m=2, i=3) - - with pytest.raises(expected_exception=PedanticCallWithArgsException): - await calc(1, m=2, i=3) diff --git a/tests/decorators/validate/conftest.py b/tests/decorators/validate/conftest.py new file mode 100644 index 00000000..d4b460a5 --- /dev/null +++ b/tests/decorators/validate/conftest.py @@ -0,0 +1,9 @@ +import os + +import pytest + + +@pytest.fixture(autouse=True) +def cleanup_env_vars() -> None: + if 'FOO' in os.environ: + del os.environ['FOO'] diff --git a/tests/decorators/validate/test_convert_value.py b/tests/decorators/validate/test_convert_value.py index c5ebfa88..c8e13f52 100644 --- a/tests/decorators/validate/test_convert_value.py +++ b/tests/decorators/validate/test_convert_value.py @@ -1,7 +1,7 @@ import pytest -from pedantic.decorators.fn_deco_validate.exceptions import ConversionError from pedantic.decorators.fn_deco_validate.convert_value import convert_value +from pedantic.decorators.fn_deco_validate.exceptions import ConversionError def test_convert_to_bool(): diff --git a/tests/decorators/validate/test_datetime_isoformat.py b/tests/decorators/validate/test_datetime_isoformat.py index d0935d08..f6c6d755 100644 --- a/tests/decorators/validate/test_datetime_isoformat.py +++ b/tests/decorators/validate/test_datetime_isoformat.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta +from datetime import UTC, datetime, timedelta import pytest @@ -13,7 +13,7 @@ def test_validator_datetime_iso_format(): def foo(x): return x - now = datetime.now() + now = datetime.now(tz=UTC) assert abs(now - foo(now.isoformat()) )< timedelta(milliseconds=1) with pytest.raises(expected_exception=ParameterException): diff --git a/tests/decorators/validate/test_flask_parameters.py b/tests/decorators/validate/test_flask_parameters.py index b8573469..ac3f4df3 100644 --- a/tests/decorators/validate/test_flask_parameters.py +++ b/tests/decorators/validate/test_flask_parameters.py @@ -1,17 +1,29 @@ import json from dataclasses import dataclass -from typing import List, Dict, Any +from typing import Any import pytest from flask import Flask, Response, jsonify from pedantic import Email, overrides -from pedantic.decorators.fn_deco_validate.exceptions import ValidateException, TooManyArguments, \ - ParameterException, ExceptionDictKey, InvalidHeader -from pedantic.decorators.fn_deco_validate.fn_deco_validate import validate, ReturnAs -from pedantic.decorators.fn_deco_validate.parameters.flask_parameters import FlaskJsonParameter, FlaskFormParameter, \ - FlaskHeaderParameter, FlaskGetParameter, FlaskPathParameter, Deserializable, GenericFlaskDeserializer -from pedantic.decorators.fn_deco_validate.validators import NotEmpty, Min +from pedantic.decorators.fn_deco_validate.exceptions import ( + ExceptionDictKey, + InvalidHeader, + ParameterException, + TooManyArguments, + ValidateException, +) +from pedantic.decorators.fn_deco_validate.fn_deco_validate import ReturnAs, validate +from pedantic.decorators.fn_deco_validate.parameters.flask_parameters import ( + Deserializable, + FlaskFormParameter, + FlaskGetParameter, + FlaskHeaderParameter, + FlaskJsonParameter, + FlaskPathParameter, + GenericFlaskDeserializer, +) +from pedantic.decorators.fn_deco_validate.validators import Min, NotEmpty JSON = 'application/json' OK = 200 @@ -51,13 +63,13 @@ def required_params(required, not_required, not_required_with_default) -> Respon FlaskJsonParameter(name='list_param', value_type=list), FlaskJsonParameter(name='dict_param', value_type=dict), ) - def different_types( - bool_param, - int_param, - float_param, - str_param, - list_param, - dict_param, + def different_types( # noqa: PLR0913 + bool_param, + int_param, + float_param, + str_param, + list_param, + dict_param, ) -> Response: return jsonify({ 'bool_param': bool_param, @@ -81,15 +93,13 @@ def names_do_not_need_to_match(my_key: str, another: str) -> Response: }) @app.errorhandler(ParameterException) - def handle_validation_error(exception: ParameterException) -> Response: - print(str(exception)) + def handle_parameter_exception(exception: ParameterException) -> Response: response = jsonify(exception.to_dict) response.status_code = INVALID return response @app.errorhandler(TooManyArguments) - def handle_validation_error(exception: TooManyArguments) -> Response: - print(str(exception)) + def handle_too_many_arguments(exception: TooManyArguments) -> Response: response = jsonify(str(exception)) response.status_code = TOO_MANY_ARGS return response @@ -128,7 +138,6 @@ def hello_world(key: str) -> Response: @app.errorhandler(ParameterException) def handle_validation_error(exception: ParameterException) -> Response: - print(str(exception)) response = jsonify(exception.to_dict) response.status_code = INVALID return response @@ -159,7 +168,6 @@ def hello_world(key: str) -> Response: @app.errorhandler(InvalidHeader) def handle_validation_error(exception: InvalidHeader) -> Response: - print(str(exception)) response = jsonify(exception.to_dict) response.status_code = INVALID return response @@ -185,7 +193,7 @@ def test_validator_flask_header_optional_parameter(): @app.route('/') @validate(FlaskHeaderParameter(name='key', validators=[NotEmpty()], required=False)) - def hello_world(key: str = None) -> Response: + def hello_world(key: str | None = None) -> Response: return jsonify(key) with app.test_client() as client: @@ -208,7 +216,6 @@ def hello_world(key: str) -> Response: @app.errorhandler(ParameterException) def handle_validation_error(exception: ParameterException) -> Response: - print(str(exception)) response = jsonify(exception.to_dict) response.status_code = INVALID return response @@ -238,7 +245,7 @@ def test_validator_flask_get_multiple_values_for_same_key(): @app.route('/') @validate(FlaskGetParameter(name='key', value_type=list, validators=[NotEmpty()])) - def hello_world(key: List[str]) -> Response: + def hello_world(key: list[str]) -> Response: return jsonify(key) with app.test_client() as client: @@ -257,7 +264,6 @@ def hello_world(key: str) -> Response: @app.errorhandler(ParameterException) def handle_validation_error(exception: ParameterException) -> Response: - print(str(exception)) response = jsonify(exception.to_dict) response.status_code = INVALID return response @@ -302,7 +308,6 @@ def hello_world(key: str) -> Response: @app.errorhandler(ValidateException) def handle_validation_error(exception: ValidateException) -> Response: - print(str(exception)) response = jsonify(str(exception)) response.status_code = INVALID return response @@ -381,7 +386,6 @@ def hello_world(key: str) -> Response: @app.errorhandler(ParameterException) def handle_validation_error(exception: ParameterException) -> Response: - print(str(exception)) response = jsonify(exception.to_dict) response.status_code = INVALID return response @@ -412,7 +416,6 @@ def hello_world(key: str) -> Response: @app.errorhandler(ParameterException) def handle_validation_error(exception: ParameterException) -> Response: - print(str(exception)) response = jsonify(exception.to_dict) response.status_code = INVALID return response @@ -453,7 +456,6 @@ def hello_world(**kwargs) -> Response: @app.errorhandler(TooManyArguments) def handle_validation_error(exception: TooManyArguments) -> Response: - print(str(exception)) response = jsonify(str(exception)) response.status_code = INVALID return response @@ -512,16 +514,16 @@ def handle_validation_error(exception: ParameterException) -> Response: return response with app.test_client() as client: - res = client.get(path=f'/45') + res = client.get(path='/45') assert res.status_code == OK - res = client.get(path=f'/foo/45') + res = client.get(path='/foo/45') assert res.status_code == OK - res = client.get(path=f'/bar/45') + res = client.get(path='/bar/45') assert res.status_code == OK - res = client.get(path=f'/41') + res = client.get(path='/41') assert res.status_code == INVALID expected = { ExceptionDictKey.MESSAGE: 'smaller then allowed: 41 is not >= 42', @@ -544,7 +546,7 @@ def testing_send_system_message(email: str, content: str) -> Response: return jsonify({'email': email, 'content': content}) with app.test_client() as client: - res = client.post(path=f'/testing/message/adam@eva.de') + res = client.post(path='/testing/message/adam@eva.de') assert res.status_code == OK expected = { 'email': 'adam@eva.de', @@ -552,7 +554,7 @@ def testing_send_system_message(email: str, content: str) -> Response: } assert res.json == expected - res = client.post(path=f'/testing/message/adam@eva.de', json={'content': 'hello world'}) + res = client.post(path='/testing/message/adam@eva.de', json={'content': 'hello world'}) assert res.status_code == OK expected = { 'email': 'adam@eva.de', @@ -570,7 +572,7 @@ class User(Deserializable): @staticmethod @overrides(Deserializable) - def from_json(data: Dict[str, Any]) -> 'User': + def from_json(data: dict[str, Any]) -> 'User': return User( firstname=data['firstname'], lastname=data['lastname'], @@ -605,19 +607,19 @@ def handle_validation_error(exception: ParameterException) -> Response: 'lastname': 'Einstein', 'age': '56', } - res = client.post(path=f'/foo', json=data) + res = client.post(path='/foo', json=data) assert res.status_code == 200 assert res.json == {'name': 'Albert'} data.pop('age') - res = client.post(path=f'/foo', json=data) + res = client.post(path='/foo', json=data) assert res.status_code == 422 - res = client.post(path=f'/bar', json=data) + res = client.post(path='/bar', json=data) assert res.status_code == 500 data['age'] = '16' - res = client.post(path=f'/foo', json=data) + res = client.post(path='/foo', json=data) assert res.status_code == 422 expected = { ExceptionDictKey.MESSAGE: 'smaller then allowed: 16 is not >= 18', diff --git a/tests/decorators/validate/test_parameter.py b/tests/decorators/validate/test_parameter.py new file mode 100644 index 00000000..b582dea7 --- /dev/null +++ b/tests/decorators/validate/test_parameter.py @@ -0,0 +1,5 @@ +from pedantic import Parameter + + +def test_parameter_str(): + assert str(Parameter(name='a')) == 'Parameter name=a' diff --git a/tests/decorators/validate/test_parameter_environment_variable.py b/tests/decorators/validate/test_parameter_environment_variable.py index c79b16ff..9cff69a8 100644 --- a/tests/decorators/validate/test_parameter_environment_variable.py +++ b/tests/decorators/validate/test_parameter_environment_variable.py @@ -8,53 +8,53 @@ def test_parameter_environment_variable_str(): - @validate(EnvironmentVariableParameter(name='foo', value_type=str)) + @validate(EnvironmentVariableParameter(name='FOO', value_type=str)) def bar(foo): return foo - os.environ['foo'] = '42' + os.environ['FOO'] = '42' assert bar() == '42' def test_parameter_environment_variable_int(): - @validate(EnvironmentVariableParameter(name='foo', value_type=int)) + @validate(EnvironmentVariableParameter(name='FOO', value_type=int)) def bar(foo): return foo - os.environ['foo'] = '42' + os.environ['FOO'] = '42' assert bar() == 42 def test_parameter_environment_variable_float(): - @validate(EnvironmentVariableParameter(name='foo', value_type=float)) + @validate(EnvironmentVariableParameter(name='FOO', value_type=float)) def bar(foo): return foo - os.environ['foo'] = '42.7' + os.environ['FOO'] = '42.7' assert bar() == 42.7 def test_parameter_environment_variable_bool(): - @validate(EnvironmentVariableParameter(name='foo', value_type=bool)) + @validate(EnvironmentVariableParameter(name='FOO', value_type=bool)) def bar(foo): return foo for value in ['true', 'True', 'TRUE']: - os.environ['foo'] = value + os.environ['FOO'] = value assert bar() is True for value in ['false', 'False', 'FALSE']: - os.environ['foo'] = value + os.environ['FOO'] = value assert bar() is False for value in ['invalid', 'frue', 'talse']: - os.environ['foo'] = value + os.environ['FOO'] = value with pytest.raises(expected_exception=ParameterException): bar() def test_parameter_environment_variable_not_set(): - @validate(EnvironmentVariableParameter(name='foo')) + @validate(EnvironmentVariableParameter(name='FOO')) def bar(foo): return foo @@ -64,24 +64,24 @@ def bar(foo): def test_invalid_value_type(): with pytest.raises(expected_exception=AssertionError): - @validate(EnvironmentVariableParameter(name='foo', value_type=dict)) + @validate(EnvironmentVariableParameter(name='FOO', value_type=dict)) def bar(foo): return foo def test_parameter_environment_variable_different_name(): - @validate(EnvironmentVariableParameter(name='foo', env_var_name='fuu', value_type=str)) + @validate(EnvironmentVariableParameter(name='foo', env_var_name='FUU', value_type=str)) def bar(foo): return foo - os.environ['fuu'] = '42' + os.environ['FUU'] = '42' assert bar() == '42' def test_two_parameters(): - @validate(EnvironmentVariableParameter(name='a'), strict=False) + @validate(EnvironmentVariableParameter(name='A'), strict=False) def foo(a: float, b: int) -> str: return f'{a} and {b}' - os.environ['a'] = '42' + os.environ['A'] = '42' assert foo(b=42) == '42 and 42' diff --git a/tests/decorators/validate/test_validate.py b/tests/decorators/validate/test_validate.py index ba7ebe86..c08c8e93 100644 --- a/tests/decorators/validate/test_validate.py +++ b/tests/decorators/validate/test_validate.py @@ -1,21 +1,20 @@ import os -from datetime import datetime -from typing import Optional, Any +from datetime import UTC, datetime +from typing import Any import pytest from pedantic import DateTimeUnixTimestamp -from pedantic.decorators.fn_deco_validate.exceptions import ValidateException, ParameterException, \ -ValidatorException -from pedantic.decorators.fn_deco_validate.fn_deco_validate import validate, ReturnAs -from pedantic.decorators.fn_deco_validate.parameters import Parameter, EnvironmentVariableParameter -from pedantic.decorators.fn_deco_validate.validators import MaxLength, Min, Max, Email, Validator +from pedantic.decorators.fn_deco_validate.exceptions import ParameterException, ValidateException, ValidatorException +from pedantic.decorators.fn_deco_validate.fn_deco_validate import ReturnAs, validate +from pedantic.decorators.fn_deco_validate.parameters import EnvironmentVariableParameter, Parameter +from pedantic.decorators.fn_deco_validate.validators import Email, Max, MaxLength, Min, Validator def test_single_validator(): validator = MaxLength(3) converted_value = validator.validate(value='hed') - assert 'hed' == converted_value + assert converted_value == 'hed' with pytest.raises(expected_exception=ValidatorException) as ex: validator.validate(value='hello world') @@ -27,7 +26,7 @@ def test_single_validator(): def test_single_parameter(): parameter = Parameter(name='x', validators=[MaxLength(3)]) converted_value = parameter.validate(value='hed') - assert 'hed' == converted_value + assert converted_value == 'hed' with pytest.raises(expected_exception=ParameterException): parameter.validate(value='hello world') @@ -96,7 +95,7 @@ def some_calculation_2(self, x: int) -> int: def test_validate_static_method(): - """ The @staticmethod decorator have to be ABOVE the @validate decorator. """ + """The @staticmethod decorator have to be ABOVE the @validate decorator.""" class MyClass: @staticmethod @@ -135,7 +134,7 @@ def test_empty_parameter_kwargs_with_none(): Parameter(name='a', required=False), Parameter(name='b', required=True), Parameter(name='c', required=False), - return_as=ReturnAs.KWARGS_WITH_NONE + return_as=ReturnAs.KWARGS_WITH_NONE, ) def some_calculation(a, b, c): return str(a) + str(b) + str(c) @@ -149,9 +148,9 @@ def test_empty_parameter_kwargs_without_none(): Parameter(name='a', required=False), Parameter(name='b', required=True), Parameter(name='c', required=False), - return_as=ReturnAs.KWARGS_WITHOUT_NONE + return_as=ReturnAs.KWARGS_WITHOUT_NONE, ) - def some_calculation(a: Optional[int] = 1, b: Optional[int] = 2, c: Optional[int] = 3): + def some_calculation(a: int | None = 1, b: int | None = 2, c: int | None = 3): return str(a) + str(b) + str(c) assert some_calculation(43, 0, -50) == '430-50' @@ -193,11 +192,11 @@ def bar(foo): def test_external_parameter_ignores_value_when_given(): - @validate(EnvironmentVariableParameter(name='foo'), ignore_input=True) + @validate(EnvironmentVariableParameter(name='FOO'), ignore_input=True) def bar(foo): return foo - os.environ['foo'] = '1' + os.environ['FOO'] = '1' assert bar('42') == '1' assert bar(foo='42') == '1' @@ -214,7 +213,7 @@ def bar(foo, footer): assert bar('42', 3) == ('42', 3) - os.environ['foo'] = '42' + os.environ['foo'] = '42' # noqa: SIM112 assert bar(footer=3) == ('42', 3) @@ -348,7 +347,7 @@ def bar(*args, **kwargs): def test_none_is_not_validated_if_not_required_kwargs_with_none(): @validate(Parameter(name='a', validators=[Email()], required=False), return_as=ReturnAs.KWARGS_WITH_NONE) - def bar(a: Optional[str]): + def bar(a: str | None): return a assert bar(a=None) is None @@ -360,7 +359,7 @@ def bar(a: Optional[str]): def test_none_is_not_validated_if_not_required_kwargs_without_none(): @validate(Parameter(name='a', validators=[Email()], required=False), return_as=ReturnAs.KWARGS_WITHOUT_NONE) - def bar(a: Optional[str] = None): + def bar(a: str | None = None): return a assert bar(a=None) is None @@ -394,8 +393,8 @@ def bar(a: int = 42): def test_default_value_is_not_validated_internal_parameter(): - t = datetime(year=2021, month=11, day=24) - unix_timestamp = (t - datetime(year=1970, month=1, day=1)).total_seconds() + t = datetime(year=2021, month=11, day=24, tzinfo=UTC) + unix_timestamp = (t - datetime(year=1970, month=1, day=1, tzinfo=UTC)).total_seconds() @validate(Parameter(name='a', required=False, default=t, validators=[DateTimeUnixTimestamp()])) def bar(a: datetime) -> datetime: @@ -415,12 +414,12 @@ def bar(a: datetime) -> datetime: def test_default_value_is_not_validated_external_parameter(): - t = datetime(year=2021, month=11, day=24) + t = datetime(year=2021, month=11, day=24, tzinfo=UTC) - if 'a' in os.environ: - del os.environ['a'] + if 'A' in os.environ: + del os.environ['A'] - @validate(EnvironmentVariableParameter(name='a', default=t, validators=[DateTimeUnixTimestamp()], required=False)) + @validate(EnvironmentVariableParameter(name='A', default=t, validators=[DateTimeUnixTimestamp()], required=False)) def bar(a: datetime) -> datetime: return a diff --git a/tests/decorators/validate/test_validator_composite.py b/tests/decorators/validate/test_validator_composite.py deleted file mode 100644 index b80c5dae..00000000 --- a/tests/decorators/validate/test_validator_composite.py +++ /dev/null @@ -1,22 +0,0 @@ -import pytest - -from pedantic.decorators.fn_deco_validate.exceptions import ParameterException -from pedantic.decorators.fn_deco_validate.fn_deco_validate import validate -from pedantic.decorators.fn_deco_validate.parameters import Parameter -from pedantic.decorators.fn_deco_validate.validators import Composite, Max, Min - - -def test_validator_composite(): - @validate(Parameter(name='x', validators=[Composite([Min(3), Max(5)])])) - def foo(x): - return x - - assert foo(3) == 3 - assert foo(4) == 4 - assert foo(5) == 5 - - with pytest.raises(expected_exception=ParameterException): - foo(5.0001) - - with pytest.raises(expected_exception=ParameterException): - foo(2.9999) diff --git a/tests/decorators/validate/test_validator_datetime_unix_timestamp.py b/tests/decorators/validate/test_validator_datetime_unix_timestamp.py index eac55138..f6591e8a 100644 --- a/tests/decorators/validate/test_validator_datetime_unix_timestamp.py +++ b/tests/decorators/validate/test_validator_datetime_unix_timestamp.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import UTC, datetime import pytest @@ -13,8 +13,8 @@ def test_validator_datetime_unix_timestamp(): def foo(x): return x - now = datetime.now() - unix_timestamp = (now - datetime(year=1970, month=1, day=1)).total_seconds() + now = datetime.now(tz=UTC) + unix_timestamp = (now - datetime(year=1970, month=1, day=1, tzinfo=UTC)).total_seconds() assert foo(unix_timestamp) == now assert foo(str(unix_timestamp)) == now diff --git a/tests/decorators/validate/test_validator_for_each.py b/tests/decorators/validate/test_validator_for_each.py index 082fd6a3..fd709654 100644 --- a/tests/decorators/validate/test_validator_for_each.py +++ b/tests/decorators/validate/test_validator_for_each.py @@ -3,7 +3,7 @@ from pedantic.decorators.fn_deco_validate.exceptions import ParameterException from pedantic.decorators.fn_deco_validate.fn_deco_validate import validate from pedantic.decorators.fn_deco_validate.parameters import Parameter -from pedantic.decorators.fn_deco_validate.validators import ForEach, Min, Max +from pedantic.decorators.fn_deco_validate.validators import ForEach, Max, Min def test_validator_for_each_single_child(): diff --git a/tests/decorators/validate/test_validator_is_enum.py b/tests/decorators/validate/test_validator_is_enum.py index 646f5843..6a4a9145 100644 --- a/tests/decorators/validate/test_validator_is_enum.py +++ b/tests/decorators/validate/test_validator_is_enum.py @@ -71,7 +71,7 @@ def foo(x): def test_validator_is_enum_to_upper_case_disabled(): @validate(Parameter(name='x', validators=[IsEnum(MyEnum, convert=False, to_upper_case=False)])) - def foo(x): print(x) + def foo(x): print(x) # noqa: T201 for value in ['red', 'blue', 'Red', 'bLUe']: with pytest.raises(expected_exception=ParameterException): diff --git a/tests/mixins/test_generic_mixin.py b/tests/mixins/test_generic_mixin.py index b1c44f2f..e46f4492 100644 --- a/tests/mixins/test_generic_mixin.py +++ b/tests/mixins/test_generic_mixin.py @@ -1,4 +1,4 @@ -from typing import TypeVar, Generic, List, Type +from typing import Generic, TypeVar import pytest @@ -12,39 +12,33 @@ def test_single_type_var(): - class Foo(Generic[T], GenericMixin): + class Foo(GenericMixin, Generic[T]): value: T foo = Foo[str]() - assert foo.type_var == str assert foo.type_vars == {T: str} invalid = Foo() with pytest.raises(expected_exception=AssertionError) as err: - invalid.type_var + invalid.type_vars # noqa: B018 - assert f'You need to instantiate this class with type parameters! Example: Foo[int]()' in err.value.args[0] + assert 'You need to instantiate this class with type parameters! Example: Foo[int]()' in err.value.args[0] def test_multiple_type_vars(): - class Foo(Generic[T, U], GenericMixin): + class Foo(GenericMixin, Generic[T, U]): value: T - values: List[U] + values: list[U] foo = Foo[str, int]() - with pytest.raises(expected_exception=AssertionError) as err: - foo.type_var - - assert 'You have multiple type parameters. Please use "type_vars" instead of "type_var".' in err.value.args[0] - assert foo.type_vars == {T: str, U: int} invalid = Foo() with pytest.raises(expected_exception=AssertionError) as err: - invalid.type_var + invalid.type_vars # noqa: B018 assert 'You need to instantiate this class with type parameters! Example: Foo[int]()' in err.value.args[0] @@ -56,15 +50,15 @@ class Foo(GenericMixin): invalid = Foo() with pytest.raises(expected_exception=AssertionError) as err: - invalid.type_var + invalid.type_vars # noqa: B018 assert err.value.args[0] == 'Foo is not a generic class. To make it generic, declare it like: class Foo(Generic[T], GenericMixin):...' -def test_call_type_var_in_constructor(): - class Foo(Generic[T], GenericMixin): +def test_call_type_vars_in_constructor(): + class Foo(GenericMixin, Generic[T]): def __init__(self) -> None: - self.x = self.type_var() + self.x = self.type_vars with pytest.raises(expected_exception=AssertionError) as err: Foo[str]() @@ -73,11 +67,11 @@ def __init__(self) -> None: def test_subclass_set_type_variable(): - class Gen(Generic[T], GenericMixin): + class Gen(GenericMixin, Generic[T]): def __init__(self, value: T) -> None: self.value = value - def get_type(self) -> dict[TypeVar, Type]: + def get_type(self) -> dict[TypeVar, type]: return self.type_vars class MyClass(Gen[int]): @@ -91,11 +85,11 @@ class MyClass(Gen[int]): def test_subclass_with_multiple_parents(): - class Gen(Generic[T], GenericMixin): + class Gen(GenericMixin, Generic[T]): def __init__(self, value: T) -> None: self.value = value - def get_type(self) -> dict[TypeVar, Type]: + def get_type(self) -> dict[TypeVar, type]: return self.type_vars class MyMixin: @@ -113,22 +107,20 @@ class MyClass(MyMixin, Gen[int]): def test_resolved_type_var_inheritance(): class Foo(Generic[T]): ... - - class Bar(Foo[int], Generic[U], GenericMixin): ... + class Bar(Foo[int], GenericMixin, Generic[U]): ... bar = Bar[str]() assert bar.type_vars == {T: int, U: str} def test_resolved_type_var_inheritance_2(): - class Foo(Generic[T], GenericMixin): ... - + class Foo(GenericMixin, Generic[T]): ... class Bar(Foo[int], Generic[U]): ... bar = Bar[str]() assert bar.type_vars == {T: int, U: str} def test_very_complex_inheritance(): - class Foo(Generic[E], GenericMixin): ... + class Foo(GenericMixin, Generic[E]): ... class Bar(Foo[int], Generic[S]): ... class Baz(Foo[int]): ... class Deep(Baz): ... @@ -155,13 +147,13 @@ class Deeper(Baz, Generic[T]): ... assert actual == {E: int, T: bool} with pytest.raises(expected_exception=AssertionError) as err: - Foo().type_vars + Foo().type_vars # noqa: B018 assert 'You need to instantiate this class with type parameters! Example: Foo[int]()' in err.value.args[0] def test_substitution_lookup_hits(): - class Base(Generic[A], GenericMixin): ... + class Base(GenericMixin, Generic[A]): ... class Mid(Base[A], Generic[A]): ... class Final(Mid[int]): ... diff --git a/tests/mixins/test_with_decorated_methods.py b/tests/mixins/test_with_decorated_methods.py index 27af82ba..5bf8b672 100644 --- a/tests/mixins/test_with_decorated_methods.py +++ b/tests/mixins/test_with_decorated_methods.py @@ -1,7 +1,7 @@ from functools import wraps -from typing import TypeVar, Generic, NoReturn +from typing import Generic, NoReturn, TypeVar -from pedantic import DecoratorType, create_decorator, WithDecoratedMethods +from pedantic import DecoratorType, WithDecoratedMethods, create_decorator T = TypeVar('T') @@ -35,16 +35,13 @@ def bad(self) -> NoReturn: def test_with_decorated_methods_sync(): class MyClass(WithDecoratedMethods[Decorators]): @foo(42) - def m1(self) -> None: - print('bar') + def m1(self) -> None: pass @foo(value=43) - def m2(self) -> None: - print('bar') + def m2(self) -> None: pass @bar(value=44) - def m3(self) -> None: - print('bar') + def m3(self) -> None: pass instance = MyClass() expected = { @@ -54,7 +51,7 @@ def m3(self) -> None: }, Decorators.BAR: { instance.m3: 44, - } + }, } assert instance.get_decorated_functions() == expected @@ -62,16 +59,13 @@ def m3(self) -> None: def test_with_decorated_methods_async(): class MyClass(WithDecoratedMethods[Decorators]): @foo(42) - async def m1(self) -> None: - print('bar') + async def m1(self) -> None: pass @foo(value=43) - async def m2(self) -> None: - print('bar') + async def m2(self) -> None: pass @bar(value=44) - async def m3(self) -> None: - print('bar') + async def m3(self) -> None: pass instance = MyClass() expected = { @@ -81,7 +75,7 @@ async def m3(self) -> None: }, Decorators.BAR: { instance.m3: 44, - } + }, } assert instance.get_decorated_functions() == expected @@ -118,7 +112,7 @@ def m1(self) -> int: def test_with_decorated_methods_can_have_generic_child_class(): - class MyClass(Generic[T], WithDecoratedMethods[Decorators]): + class MyClass(WithDecoratedMethods[Decorators], Generic[T]): @foo(42) def m1(self) -> None: ... diff --git a/tests/models/test_generator_wrapper.py b/tests/models/test_generator_wrapper.py index 76ec6774..240f1789 100644 --- a/tests/models/test_generator_wrapper.py +++ b/tests/models/test_generator_wrapper.py @@ -1,4 +1,4 @@ -from typing import Iterator +from typing import Iterator # noqa: UP035 import pytest @@ -22,12 +22,12 @@ def gen_func() -> Iterator[int]: type_vars={}, ) - print(sum([x for x in g])) + assert sum(x for x in g) == 4950 - with pytest.raises(expected_exception=Exception): - g.throw(Exception('error')) + with pytest.raises(expected_exception=ValueError, match='error'): + g.throw(ValueError('error')) with pytest.raises(expected_exception=AttributeError): - g.invalid + g.invalid # noqa: B018 g.close() diff --git a/tests/test_environment_variables.py b/tests/test_environment_variables.py deleted file mode 100644 index 5166427c..00000000 --- a/tests/test_environment_variables.py +++ /dev/null @@ -1,35 +0,0 @@ -import pytest - -from pedantic.exceptions import PedanticTypeCheckException -from pedantic.env_var_logic import enable_pedantic, disable_pedantic, is_enabled -from pedantic.decorators.fn_deco_pedantic import pedantic - - -def test_pedantic_enabled(): - enable_pedantic() - - @pedantic - def some_method(): - return 42 - - with pytest.raises(expected_exception=PedanticTypeCheckException): - some_method() - - -def test_pedantic_disabled(): - disable_pedantic() - - @pedantic - def some_method(): - return 42 - - some_method() - - -def test_enable_disable(): - enable_pedantic() - assert is_enabled() is True - disable_pedantic() - assert is_enabled() is False - enable_pedantic() - assert is_enabled() is True diff --git a/tests/test_helper_fn.py b/tests/test_helper_fn.py new file mode 100644 index 00000000..0b6a5955 --- /dev/null +++ b/tests/test_helper_fn.py @@ -0,0 +1,33 @@ +import pytest + +from pedantic import run_doctest_of_single_function + + +def foo(x): + """ + Examples: + >>> foo(1) + 1 + >>> foo(2) + 2 + """ + return x + + +def test_run_doctests_single_green(): + run_doctest_of_single_function(foo) + + +def test_run_doctests_single_red(): + foo.__doc__ = """ + Examples: + >>> foo(1) + 1 + >>> foo(2) + 2 + >>> foo(3) + 4 + """ + + with pytest.raises(AssertionError, match=r'Failed tests: 1'): + run_doctest_of_single_function(foo) diff --git a/tests/test_the_tests.py b/tests/test_the_tests.py index 2335f578..57594b1c 100644 --- a/tests/test_the_tests.py +++ b/tests/test_the_tests.py @@ -1,19 +1,20 @@ from pathlib import Path + def test_all_test_files_follow_pytest_naming_convention(): tests_dir = Path(__file__).parent invalid_files = [] - for path in tests_dir.rglob("*.py"): + for path in tests_dir.rglob('*.py'): name = path.name - if name in {"__init__.py", "conftest.py"}: + if name in ['__init__.py', 'conftest.py']: continue - if not name.startswith("test_"): + if not name.startswith('test_'): invalid_files.append(path.relative_to(tests_dir)) assert not invalid_files, ( - "Found Python files in tests/ that do not follow pytest naming conventions:\n" - + "\n".join(str(p) for p in invalid_files) + 'Found Python files in tests/ that do not follow pytest naming conventions:\n' + + '\n'.join(str(p) for p in invalid_files) ) diff --git a/tests/type_checking_logic/test_assert_value_matches_type.py b/tests/type_checking_logic/test_assert_value_matches_type.py index 30240ff9..60e1ead8 100644 --- a/tests/type_checking_logic/test_assert_value_matches_type.py +++ b/tests/type_checking_logic/test_assert_value_matches_type.py @@ -1,7 +1,9 @@ +# ruff: noqa: UP006, UP007, UP035 + from abc import ABC from dataclasses import dataclass -from datetime import datetime -from typing import Callable, Awaitable, Coroutine, Any, Union, Optional, Generic, TypeVar, Tuple +from datetime import UTC, datetime +from typing import Any, Awaitable, Callable, Coroutine, Generic, Optional, Tuple, TypeVar, Union import pytest @@ -34,8 +36,8 @@ def _cb(foo: Foo) -> str: ) def test_callable_return_type_none(): - def _cb(foo: Foo) -> None: - return print(foo) + def _cb(_: Foo) -> None: + return assert_value_matches_type( value=_cb, @@ -100,8 +102,7 @@ async def _cb(foo: Foo) -> str: def test_callable_awaitable_with_none_return_type(): - async def _cb(foo: Foo) -> None: - print(foo) + async def _cb(foo: Foo) -> None: pass assert_value_matches_type( value=_cb, @@ -168,10 +169,10 @@ async def _cb(_: str) -> int | None: def test_forward_ref_inheritance(): T = TypeVar('T') - class State(Generic[T], ABC): + class State(ABC, Generic[T]): pass - class StateMachine(Generic[T], ABC): + class StateMachine(ABC, Generic[T]): pass class MachineState(State['MachineStateMachine']): @@ -193,7 +194,7 @@ class MachineStateMachine(StateMachine[MachineState]): def test_tuple_with_ellipsis(): - """ Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/75 """ + """Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/75""" assert_value_matches_type( value=(1, 2.0, 'hello'), @@ -205,10 +206,10 @@ def test_tuple_with_ellipsis(): def test_union_of_callable(): - """ Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/74 """ + """Regression test for https://github.com/LostInDarkMath/pedantic-python-decorators/issues/74""" assert_value_matches_type( - value=datetime.now(), + value=datetime.now(tz=UTC), type_=Union[datetime, Callable[[], datetime]], err='', type_vars={}, diff --git a/tests/type_checking_logic/test_resolve_forward_ref.py b/tests/type_checking_logic/test_resolve_forward_ref.py index 003a8879..9b0a2a44 100644 --- a/tests/type_checking_logic/test_resolve_forward_ref.py +++ b/tests/type_checking_logic/test_resolve_forward_ref.py @@ -1,3 +1,5 @@ +# ruff: noqa: E721, UP006, UP007, UP035, UP045 + from typing import List, Optional, Union import pytest