pax_global_header 0000666 0000000 0000000 00000000064 15151413152 0014510 g ustar 00root root 0000000 0000000 52 comment=d495c03c1beffd03dfa893acad70c6af6d5bf906
python-pytest-cases-3.10.1/ 0000775 0000000 0000000 00000000000 15151413152 0015535 5 ustar 00root root 0000000 0000000 python-pytest-cases-3.10.1/.github/ 0000775 0000000 0000000 00000000000 15151413152 0017075 5 ustar 00root root 0000000 0000000 python-pytest-cases-3.10.1/.github/workflows/ 0000775 0000000 0000000 00000000000 15151413152 0021132 5 ustar 00root root 0000000 0000000 python-pytest-cases-3.10.1/.github/workflows/base.yml 0000664 0000000 0000000 00000020510 15151413152 0022565 0 ustar 00root root 0000000 0000000 # .github/workflows/base.yml
name: Build
on:
# this one is to trigger the workflow manually from the interface
workflow_dispatch:
push:
tags:
- '*'
branches:
- main
pull_request:
branches:
- main
defaults:
run:
shell: bash -l {0}
jobs:
# pre-job to read nox tests matrix - see https://stackoverflow.com/q/66747359/7262247
list_nox_test_sessions:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install python 3.11
uses: actions/setup-python@v5
with:
python-version: 3.11
architecture: x64
- name: Install noxfile requirements
run: pip install -r noxfile-requirements.txt
- name: List 'tests' nox sessions and required python versions
id: set-matrix
run: echo "matrix=$(nox --json -l -s tests -v)" >> $GITHUB_OUTPUT
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }} # save nox sessions list to outputs
run_all_tests:
needs: list_nox_test_sessions
strategy:
fail-fast: false
matrix:
# see https://github.com/actions/setup-python/issues/544
# os: [ ubuntu-20.04 ]
os: [ ubuntu-latest ] # , macos-latest, windows-latest]
# all nox sessions: manually > dynamically from previous job
# nox_session: ["tests-2.7(env='pytest2.x')", "tests-3.7(env='pytest-latest')"]
nox_session: ${{ fromJson(needs.list_nox_test_sessions.outputs.matrix) }}
name: ${{ matrix.os }} ${{ matrix.nox_session.python }} ${{ matrix.nox_session.session }} # ${{ matrix.name_suffix }}
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
# General case
- name: Install python ${{ matrix.nox_session.python }} for tests (not 3.5 not 3.14)
if: ${{ ! contains(fromJson('["3.5", "3.14"]'), matrix.nox_session.python ) }}
uses: MatteoH2O1999/setup-python@v4 # actions/setup-python@v5.0.0
id: set-py
with:
python-version: ${{ matrix.nox_session.python }}
architecture: x64
allow-build: info
cache-build: true
# Particular case of issue with 3.5
- name: Install python ${{ matrix.nox_session.python }} for tests (3.5)
if: contains(fromJson('["3.5"]'), matrix.nox_session.python )
uses: MatteoH2O1999/setup-python@v4 # actions/setup-python@v5.0.0
id: set-py-35
with:
python-version: ${{ matrix.nox_session.python }}
architecture: x64
allow-build: info
cache-build: true
env:
# workaround found in https://github.com/actions/setup-python/issues/866
# for issue "[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:728)" on Python 3.5
PIP_TRUSTED_HOST: "pypi.python.org pypi.org files.pythonhosted.org"
- name: Install python ${{ matrix.nox_session.python }} for tests (3.14)
if: contains(fromJson('["3.14"]'), matrix.nox_session.python )
uses: actions/setup-python@v5
id: set-py-latest
with:
# Include all versions including pre releases
# See https://github.com/actions/setup-python/blob/main/docs/advanced-usage.md#specifying-a-python-version
python-version: ${{ format('~{0}.0-alpha.0', matrix.nox_session.python) }}
architecture: x64
allow-build: info
cache-build: true
- name: Install python 3.12 for nox
uses: actions/setup-python@v5
with:
python-version: 3.12
architecture: x64
- name: pin virtualenv==20.15.1 in old python versions
# pinned to keep compatibility with old versions, see https://github.com/MatteoH2O1999/setup-python/issues/28#issuecomment-1745613621
if: contains(fromJson('["2.7", "3.5", "3.6"]'), matrix.nox_session.python )
run: sed -i "s/virtualenv/virtualenv==20.15.1/g" noxfile-requirements.txt
- name: Install noxfile requirements
run: pip install -r noxfile-requirements.txt
- name: Run nox session ${{ matrix.nox_session.session }}
run: nox -s "${{ matrix.nox_session.session }}" -v
# Share ./docs/reports so that they can be deployed with doc in next job
- name: Share reports with other jobs
if: runner.os == 'Linux'
uses: actions/upload-artifact@v4
with:
name: reports_dir
path: ./docs/reports
build_doc:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install python 3.11 for nox
uses: actions/setup-python@v5
with:
python-version: 3.11
architecture: x64
- name: Install noxfile requirements
run: pip install -r noxfile-requirements.txt
- name: Build the doc including example gallery
run: nox -s docs -- build
publish_release:
needs: run_all_tests
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- name: GitHub context to debug conditional steps
env:
GITHUB_CONTEXT: ${{ toJSON(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Checkout with no depth
uses: actions/checkout@v4
with:
fetch-depth: 0 # so that gh-deploy works
# persist-credentials: false # see https://github.com/orgs/community/discussions/25702
- name: Install python 3.11 for nox
uses: actions/setup-python@v5
with:
python-version: 3.11
architecture: x64
# 1) retrieve the reports generated previously
- name: Retrieve reports
uses: actions/download-artifact@v4
with:
name: reports_dir
path: ./docs/reports
# Nox install
- name: Install noxfile requirements
run: pip install -r noxfile-requirements.txt
# 5) Run the flake8 report and badge
- name: Run flake8 analysis and generate corresponding badge
run: nox -s flake8
# -------------- only on Ubuntu + MAIN PUSH (no pull request, no tag) -----------
# 5) Publish the doc and test reports
- name: \[not on TAG\] Publish documentation, tests and coverage reports
if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads') # startsWith(matrix.os,'ubuntu')
run: nox -s publish
# 6) Publish coverage report
- name: \[not on TAG\] Create codecov.yaml with correct paths
if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads')
shell: bash
run: |
cat << EOF > codecov.yml
# codecov.yml
fixes:
- "/home/runner/work/smarie/python-pytest-cases/::" # Correct paths
EOF
- name: \[not on TAG\] Publish coverage report
if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads')
uses: codecov/codecov-action@v4
with:
files: ./docs/reports/coverage/coverage.xml
- name: \[not on TAG\] Build wheel and sdist
if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads')
run: nox -s build
# -------------- only on Ubuntu + TAG PUSH (no pull request) -----------
# 7) Create github release and build the wheel
- name: \[TAG only\] Build wheel and create github release
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
# We would have to use a PAT instead of GITHUB_TOKEN if we want the next job to trigger.
# See https://github.com/orgs/community/discussions/25702
# For now we will rather rely on a "workflow completed" trigger to avoid
# having a token expiration date to manage
run: nox -s release -- ${{ secrets.GITHUB_TOKEN }} # ${{ secrets.WORKFLOW_SECRET}}
# 8) Publish the wheel on PyPi
- name: \[TAG only\] Deploy on PyPi
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
delete-artifacts:
needs: publish_release
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- uses: kolpav/purge-artifacts-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
expire-in: 0 # Setting this to 0 will delete all artifacts
python-pytest-cases-3.10.1/.github/workflows/ghpages.yml 0000664 0000000 0000000 00000003013 15151413152 0023270 0 ustar 00root root 0000000 0000000 # Simple workflow for deploying static content to GitHub Pages
name: Deploy Static Website from gh-pages branch
on:
# Runs on pushes targeting the default branch
push:
branches: ["gh-pages"]
# Since the pushes made by the workflow using GITHUB_TOKEN do not trigger the above,
# Add an explicit trigger for workflow completion
workflow_run:
workflows: ['Build']
types: [completed]
branches:
- 'main'
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
# Single deploy job since we're just deploying
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: gh-pages
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
# Upload entire repository
path: '.'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
python-pytest-cases-3.10.1/.github/workflows/updater.yml 0000664 0000000 0000000 00000001171 15151413152 0023321 0 ustar 00root root 0000000 0000000 name: GitHub Actions Version Updater
# Controls when the action will run.
on:
workflow_dispatch:
schedule:
# Automatically run on every first day of the month
- cron: '0 0 1 * *'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# [Required] Access token with `workflow` scope.
token: ${{ secrets.WORKFLOW_SECRET }}
- name: Run GitHub Actions Version Updater
uses: saadmk11/github-actions-version-updater@v0.8
with:
# [Required] Access token with `workflow` scope.
token: ${{ secrets.WORKFLOW_SECRET }}
python-pytest-cases-3.10.1/.gitignore 0000664 0000000 0000000 00000003635 15151413152 0017534 0 ustar 00root root 0000000 0000000 # Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
src/pytest_cases/_version.py
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv*/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# PyCharm development
/.idea
# OSX
.DS_Store
# JUnit and coverage reports
docs/reports
# ODSClient cache
.odsclient
python-pytest-cases-3.10.1/.zenodo.json 0000664 0000000 0000000 00000002231 15151413152 0020002 0 ustar 00root root 0000000 0000000 {
"title": "pytest-cases: a Python package for reproducible research results (among others)",
"description": "
`pytest-cases` is a Python package leveraging the widely popular `pytest` library (Krekel et al., 2004) to design tests and benchmarks where test data, tested code, and evaluation protocols are separated in a modular fashion. With `pytest-cases` it has never been so easy for researchers to create reproducible results tables, and for software engineers to build powerfull test harnesses !
\n\nThe API for `pytest-cases` is as minimal as possible, so that each concept (evaluation protocols, test data, algorithms candidates, user profiles... ) is a readable python function ; this is in line with the design philosophy of `pytest` itself.
",
"language": "eng",
"license": {
"id": "bsd-license"
},
"keywords": [
"python",
"test",
"case",
"parameter",
"evaluation",
"data",
"benchmark",
"pytest"
],
"creators": [
{
"orcid": "0000-0002-5929-1047",
"affiliation": "Schneider Electric",
"name": "Sylvain Mari\u00e9"
},
{
"name": "Various github contributors"
}
]
}
python-pytest-cases-3.10.1/LICENSE 0000664 0000000 0000000 00000003026 15151413152 0016543 0 ustar 00root root 0000000 0000000 BSD 3-Clause License
Copyright (c) 2018-2025, Sylvain MariƩ, Schneider Electric Industries
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
python-pytest-cases-3.10.1/README.md 0000664 0000000 0000000 00000014663 15151413152 0017026 0 ustar 00root root 0000000 0000000 # pytest-cases
Separate test code from test cases in `pytest`.
[](https://pypi.python.org/pypi/pytest-cases/)  [](https://github.com/smarie/python-pytest-cases/actions/workflows/base.yml) [](https://smarie.github.io/python-pytest-cases/reports/junit/report.html) [](https://smarie.github.io/python-pytest-cases/reports/coverage/index.html) [](https://codecov.io/gh/smarie/python-pytest-cases) [](https://smarie.github.io/python-pytest-cases/reports/flake8/index.html)
[](https://smarie.github.io/python-pytest-cases/) [](https://pypi.python.org/pypi/pytest-cases/) [](https://pepy.tech/project/pytest-cases) [](https://pepy.tech/project/pytest-cases) [](https://github.com/smarie/python-pytest-cases/stargazers) [](https://doi.org/10.5281/zenodo.3937829)
**This is the readme for developers.** The documentation for users is available here: [https://smarie.github.io/python-pytest-cases/](https://smarie.github.io/python-pytest-cases/)
## Want to contribute ?
Contributions are welcome ! Simply fork this project on github, commit your contributions, and create pull requests.
Here is a non-exhaustive list of interesting open topics: [https://github.com/smarie/python-pytest-cases/issues](https://github.com/smarie/python-pytest-cases/issues)
## `nox` setup
This project uses `nox` to define all lifecycle tasks. In order to be able to run those tasks, you should create python 3.7 environment and install the requirements:
```bash
>>> conda create -n noxenv python="3.7"
>>> activate noxenv
(noxenv) >>> pip install -r noxfile-requirements.txt
```
You should then be able to list all available tasks using:
```
>>> nox --list
Sessions defined in \noxfile.py:
* tests-2.7 -> Run the test suite, including test reports generation and coverage reports.
* tests-3.5 -> Run the test suite, including test reports generation and coverage reports.
* tests-3.6 -> Run the test suite, including test reports generation and coverage reports.
* tests-3.8 -> Run the test suite, including test reports generation and coverage reports.
* tests-3.7 -> Run the test suite, including test reports generation and coverage reports.
- docs-3.7 -> Generates the doc and serves it on a local http server. Pass '-- build' to build statically instead.
- publish-3.7 -> Deploy the docs+reports on github pages. Note: this rebuilds the docs
- release-3.7 -> Create a release on github corresponding to the latest tag
```
## Running the tests and generating the reports
This project uses `pytest` so running `pytest` at the root folder will execute all tests on current environment. However it is a bit cumbersome to manage all requirements by hand ; it is easier to use `nox` to run `pytest` on all supported python environments with the correct package requirements:
```bash
nox
```
Tests and coverage reports are automatically generated under `./docs/reports` for one of the sessions (`tests-3.7`).
If you wish to execute tests on a specific environment, use explicit session names, e.g. `nox -s tests-3.6`.
## Editing the documentation
This project uses `mkdocs` to generate its documentation page. Therefore building a local copy of the doc page may be done using `mkdocs build -f docs/mkdocs.yml`. However once again things are easier with `nox`. You can easily build and serve locally a version of the documentation site using:
```bash
>>> nox -s docs
nox > Running session docs-3.7
nox > Creating conda env in .nox\docs-3-7 with python=3.7
nox > [docs] Installing requirements with pip: ['mkdocs-material', 'mkdocs', 'pymdown-extensions', 'pygments']
nox > python -m pip install mkdocs-material mkdocs pymdown-extensions pygments
nox > mkdocs serve -f ./docs/mkdocs.yml
INFO - Building documentation...
INFO - Cleaning site directory
INFO - The following pages exist in the docs directory, but are not included in the "nav" configuration:
- long_description.md
INFO - Documentation built in 1.07 seconds
INFO - Serving on http://127.0.0.1:8000
INFO - Start watching changes
...
```
While this is running, you can edit the files under `./docs/` and browse the automatically refreshed documentation at the local [http://127.0.0.1:8000](http://127.0.0.1:8000) page.
Once you are done, simply hit `` to stop the session.
Publishing the documentation (including tests and coverage reports) is done automatically by [the continuous integration engine](https://github.com/smarie/python-pytest-cases/actions), using the `nox -s publish` session, this is not needed for local development.
## Packaging
This project uses `setuptools_scm` to synchronise the version number. Therefore the following command should be used for development snapshots as well as official releases: `python setup.py sdist bdist_wheel`. However this is not generally needed since [the continuous integration engine](https://github.com/smarie/python-pytest-cases/actions) does it automatically for us on git tags. For reference, this is done in the `nox -s release` session.
### Merging pull requests with edits - memo
Ax explained in github ('get commandline instructions'):
```bash
git checkout -b - main
git pull https://github.com//python-pytest-cases.git --no-commit --ff-only
```
if the second step does not work, do a normal auto-merge (do not use **rebase**!):
```bash
git pull https://github.com//python-pytest-cases.git --no-commit
```
Finally review the changes, possibly perform some modifications, and commit.
python-pytest-cases-3.10.1/ci_tools/ 0000775 0000000 0000000 00000000000 15151413152 0017350 5 ustar 00root root 0000000 0000000 python-pytest-cases-3.10.1/ci_tools/.pylintrc 0000664 0000000 0000000 00000042010 15151413152 0021212 0 ustar 00root root 0000000 0000000 [MASTER]
# Specify a configuration file.
#rcfile=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
# init-hook="import pytest_cases"
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=
# Pickle collected data for later comparisons.
persistent=no
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
# Use multiple processes to speed up Pylint.
# DO NOT CHANGE THIS VALUES >1 HIDE RESULTS!!!!!
jobs=1
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code
extension-pkg-whitelist=
# Allow optimization of some AST trees. This will activate a peephole AST
# optimizer, which will apply various small optimizations. For instance, it can
# be used to obtain the result of joining multiple strings with the addition
# operator. Joining a lot of strings can lead to a maximum recursion error in
# Pylint and this flag can prevent that. It has one side effect, the resulting
# AST will be different than the one from reality.
optimize-ast=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time. See also the "--disable" option for examples.
disable=all
enable=import-error,
import-self,
reimported,
wildcard-import,
misplaced-future,
relative-import,
deprecated-module,
unpacking-non-sequence,
invalid-all-object,
undefined-all-variable,
used-before-assignment,
cell-var-from-loop,
global-variable-undefined,
redefined-builtin,
redefine-in-handler,
unused-import,
unused-wildcard-import,
global-variable-not-assigned,
undefined-loop-variable,
global-statement,
global-at-module-level,
bad-open-mode,
redundant-unittest-assert,
boolean-datetime,
# Has common issues with our style due to
# https://github.com/PyCQA/pylint/issues/210
unused-variable
# Things we'd like to enable someday:
# redefined-outer-name (requires a bunch of work to clean up our code first)
# undefined-variable (re-enable when pylint fixes https://github.com/PyCQA/pylint/issues/760)
# no-name-in-module (giving us spurious warnings https://github.com/PyCQA/pylint/issues/73)
# unused-argument (need to clean up or code a lot, e.g. prefix unused_?)
# Things we'd like to try.
# Procedure:
# 1. Enable a bunch.
# 2. See if there's spurious ones; if so disable.
# 3. Record above.
# 4. Remove from this list.
# deprecated-method,
# anomalous-unicode-escape-in-string,
# anomalous-backslash-in-string,
# not-in-loop,
# function-redefined,
# continue-in-finally,
# abstract-class-instantiated,
# star-needs-assignment-target,
# duplicate-argument-name,
# return-in-init,
# too-many-star-expressions,
# nonlocal-and-global,
# return-outside-function,
# return-arg-in-generator,
# invalid-star-assignment-target,
# bad-reversed-sequence,
# nonexistent-operator,
# yield-outside-function,
# init-is-generator,
# nonlocal-without-binding,
# lost-exception,
# assert-on-tuple,
# dangerous-default-value,
# duplicate-key,
# useless-else-on-loop,
# expression-not-assigned,
# confusing-with-statement,
# unnecessary-lambda,
# pointless-statement,
# pointless-string-statement,
# unnecessary-pass,
# unreachable,
# eval-used,
# exec-used,
# bad-builtin,
# using-constant-test,
# deprecated-lambda,
# bad-super-call,
# missing-super-argument,
# slots-on-old-class,
# super-on-old-class,
# property-on-old-class,
# not-an-iterable,
# not-a-mapping,
# format-needs-mapping,
# truncated-format-string,
# missing-format-string-key,
# mixed-format-string,
# too-few-format-args,
# bad-str-strip-call,
# too-many-format-args,
# bad-format-character,
# format-combined-specification,
# bad-format-string-key,
# bad-format-string,
# missing-format-attribute,
# missing-format-argument-key,
# unused-format-string-argument,
# unused-format-string-key,
# invalid-format-index,
# bad-indentation,
# mixed-indentation,
# unnecessary-semicolon,
# lowercase-l-suffix,
# fixme,
# invalid-encoded-data,
# unpacking-in-except,
# import-star-module-level,
# parameter-unpacking,
# long-suffix,
# old-octal-literal,
# old-ne-operator,
# backtick,
# old-raise-syntax,
# print-statement,
# metaclass-assignment,
# next-method-called,
# dict-iter-method,
# dict-view-method,
# indexing-exception,
# raising-string,
# standarderror-builtin,
# using-cmp-argument,
# cmp-method,
# coerce-method,
# delslice-method,
# getslice-method,
# hex-method,
# nonzero-method,
# oct-method,
# setslice-method,
# apply-builtin,
# basestring-builtin,
# buffer-builtin,
# cmp-builtin,
# coerce-builtin,
# old-division,
# execfile-builtin,
# file-builtin,
# filter-builtin-not-iterating,
# no-absolute-import,
# input-builtin,
# intern-builtin,
# long-builtin,
# map-builtin-not-iterating,
# range-builtin-not-iterating,
# raw_input-builtin,
# reduce-builtin,
# reload-builtin,
# round-builtin,
# unichr-builtin,
# unicode-builtin,
# xrange-builtin,
# zip-builtin-not-iterating,
# logging-format-truncated,
# logging-too-few-args,
# logging-too-many-args,
# logging-unsupported-format,
# logging-not-lazy,
# logging-format-interpolation,
# invalid-unary-operand-type,
# unsupported-binary-operation,
# no-member,
# not-callable,
# redundant-keyword-arg,
# assignment-from-no-return,
# assignment-from-none,
# not-context-manager,
# repeated-keyword,
# missing-kwoa,
# no-value-for-parameter,
# invalid-sequence-index,
# invalid-slice-index,
# too-many-function-args,
# unexpected-keyword-arg,
# unsupported-membership-test,
# unsubscriptable-object,
# access-member-before-definition,
# method-hidden,
# assigning-non-slot,
# duplicate-bases,
# inconsistent-mro,
# inherit-non-class,
# invalid-slots,
# invalid-slots-object,
# no-method-argument,
# no-self-argument,
# unexpected-special-method-signature,
# non-iterator-returned,
# protected-access,
# arguments-differ,
# attribute-defined-outside-init,
# no-init,
# abstract-method,
# signature-differs,
# bad-staticmethod-argument,
# non-parent-init-called,
# super-init-not-called,
# bad-except-order,
# catching-non-exception,
# bad-exception-context,
# notimplemented-raised,
# raising-bad-type,
# raising-non-exception,
# misplaced-bare-raise,
# duplicate-except,
# broad-except,
# nonstandard-exception,
# binary-op-exception,
# bare-except,
# not-async-context-manager,
# yield-inside-async-function,
# ...
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html. You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
output-format=parseable
# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]".
files-output=no
# Tells whether to display a full report or only the messages
reports=no
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
#msg-template=
[LOGGING]
# Logging modules to check that the string format arguments are in logging
# function parameter format
logging-modules=logging
[FORMAT]
# Maximum number of characters on a single line.
max-line-length=100
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )??$
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,dict-separator
# Maximum number of lines in a module
max-module-lines=1000
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=
[TYPECHECK]
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# List of classes names for which member attributes should not be checked
# (useful for classes with attributes dynamically set). This supports can work
# with qualified names.
ignored-classes=
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
[VARIABLES]
# Tells whether we should check for unused import in __init__ files.
init-import=no
# A regular expression matching the name of dummy variables (i.e. expectedly
# not used).
dummy-variables-rgx=^_|^dummy
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,_cb
[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines=4
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
[SPELLING]
# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,XXX,TODO
[BASIC]
# List of builtins function names that should not be used, separated by a comma
bad-functions=map,filter,input
# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,Run,_
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Include a hint for the correct naming format with invalid-name
include-naming-hint=no
# Regular expression matching correct function names
function-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for function names
function-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression matching correct variable names
variable-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for variable names
variable-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression matching correct constant names
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Naming hint for constant names
const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Regular expression matching correct attribute names
attr-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for attribute names
attr-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression matching correct argument names
argument-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for argument names
argument-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression matching correct class attribute names
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Naming hint for class attribute names
class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Regular expression matching correct inline iteration names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Naming hint for inline iteration names
inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
# Regular expression matching correct class names
class-rgx=[A-Z_][a-zA-Z0-9]+$
# Naming hint for class names
class-name-hint=[A-Z_][a-zA-Z0-9]+$
# Regular expression matching correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Naming hint for module names
module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Regular expression matching correct method names
method-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for method names
method-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
[ELIF]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
[IMPORTS]
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub,TERMIOS,Bastion,rexec
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
[DESIGN]
# Maximum number of arguments for function / method
max-args=5
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of branch for function / method body
max-branches=12
# Maximum number of statements in function / method body
max-statements=50
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of attributes for a class (see R0902).
max-attributes=7
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of boolean expressions in a if statement
max-bool-expr=5
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,_fields,_replace,_source,_make
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception
python-pytest-cases-3.10.1/ci_tools/check_python_version.py 0000664 0000000 0000000 00000002372 15151413152 0024151 0 ustar 00root root 0000000 0000000 import sys
if __name__ == "__main__":
# Execute only if run as a script.
# Check the arguments
nbargs = len(sys.argv[1:])
if nbargs != 1:
raise ValueError("a mandatory argument is required: ")
expected_version_str = sys.argv[1]
try:
expected_version = tuple(int(i) for i in expected_version_str.split("."))
except Exception as e:
raise ValueError("Error while parsing expected version %r: %r" % (expected_version, e))
if len(expected_version) < 1:
raise ValueError("At least a major is expected")
if sys.version_info[0] != expected_version[0]:
raise AssertionError("Major version does not match. Expected %r - Actual %r" % (expected_version_str, sys.version))
if len(expected_version) >= 2 and sys.version_info[1] != expected_version[1]:
raise AssertionError("Minor version does not match. Expected %r - Actual %r" % (expected_version_str, sys.version))
if len(expected_version) >= 3 and sys.version_info[2] != expected_version[2]:
raise AssertionError("Patch version does not match. Expected %r - Actual %r" % (expected_version_str, sys.version))
print("SUCCESS - Actual python version %r matches expected one %r" % (sys.version, expected_version_str))
python-pytest-cases-3.10.1/ci_tools/flake8-requirements.txt 0000664 0000000 0000000 00000001007 15151413152 0024002 0 ustar 00root root 0000000 0000000 setuptools_scm>=3,<4
flake8>=3.6,<4
flake8-html>=0.4,<1
flake8-bandit>=2.1.1,<3
bandit<1.7.3 # temporary until this is fixed https://github.com/tylerwince/flake8-bandit/issues/21
pbr # for bandit 1.7.2 to run
flake8-bugbear>=20.1.0,<21.0.0
flake8-docstrings>=1.5,<2
flake8-print>=3.1.1,<4
flake8-tidy-imports>=4.2.1,<5
flake8-copyright==0.2.2 # Internal forked repo to fix an issue, keep specific version
pydocstyle>=5.1.1,<6
pycodestyle>=2.6.0,<3
mccabe>=0.6.1,<1
naming>=0.5.1,<1
pyflakes>=2.2,<3
genbadge[flake8]
python-pytest-cases-3.10.1/ci_tools/github_release.py 0000664 0000000 0000000 00000013223 15151413152 0022705 0 ustar 00root root 0000000 0000000 # a clone of the ruby example https://gist.github.com/valeriomazzeo/5491aee76f758f7352e2e6611ce87ec1
import os
from os import path
import re
import click
from click import Path
from github import Github, UnknownObjectException
# from valid8 import validate not compliant with python 2.7
@click.command()
@click.option('-u', '--user', help='GitHub username')
@click.option('-p', '--pwd', help='GitHub password')
@click.option('-s', '--secret', help='GitHub access token')
@click.option('-r', '--repo-slug', help='Repo slug. i.e.: apple/swift')
@click.option('-cf', '--changelog-file', help='Changelog file path')
@click.option('-d', '--doc-url', help='Documentation url')
@click.option('-df', '--data-file', help='Data file to upload', type=Path(exists=True, file_okay=True, dir_okay=False,
resolve_path=True))
@click.argument('tag')
def create_or_update_release(user, pwd, secret, repo_slug, changelog_file, doc_url, data_file, tag):
"""
Creates or updates (TODO)
a github release corresponding to git tag .
"""
# 1- AUTHENTICATION
if user is not None and secret is None:
# using username and password
# validate('user', user, instance_of=str)
assert isinstance(user, str)
# validate('pwd', pwd, instance_of=str)
assert isinstance(pwd, str)
g = Github(user, pwd)
elif user is None and secret is not None:
# or using an access token
# validate('secret', secret, instance_of=str)
assert isinstance(secret, str)
g = Github(secret)
else:
raise ValueError("You should either provide username/password OR an access token")
click.echo("Logged in as {user_name}".format(user_name=g.get_user()))
# 2- CHANGELOG VALIDATION
regex_pattern = "[\s\S]*[\n][#]+[\s]*(?P[\S ]*%s[\S ]*)[\n]+?(?P[\s\S]*?)[\n]*?(\n#|$)" % re.escape(tag)
changelog_section = re.compile(regex_pattern)
if changelog_file is not None:
# validate('changelog_file', changelog_file, custom=os.path.exists,
# help_msg="changelog file should be a valid file path")
assert os.path.exists(changelog_file), "changelog file should be a valid file path"
with open(changelog_file) as f:
contents = f.read()
match = changelog_section.match(contents).groupdict()
if match is None or len(match) != 2:
raise ValueError("Unable to find changelog section matching regexp pattern in changelog file.")
else:
title = match['title']
message = match['body']
else:
title = tag
message = ''
# append footer if doc url is provided
message += "\n\nSee [documentation page](%s) for details." % doc_url
# 3- REPOSITORY EXPLORATION
# validate('repo_slug', repo_slug, instance_of=str, min_len=1, help_msg="repo_slug should be a non-empty string")
assert isinstance(repo_slug, str) and len(repo_slug) > 0, "repo_slug should be a non-empty string"
repo = g.get_repo(repo_slug)
# -- Is there a tag with that name ?
try:
tag_ref = repo.get_git_ref("tags/" + tag)
except UnknownObjectException:
raise ValueError("No tag with name %s exists in repository %s" % (tag, repo.name))
# -- Is there already a release with that tag name ?
click.echo("Checking if release %s already exists in repository %s" % (tag, repo.name))
try:
release = repo.get_release(tag)
if release is not None:
raise ValueError("Release %s already exists in repository %s. Please set overwrite to True if you wish to "
"update the release (Not yet supported)" % (tag, repo.name))
except UnknownObjectException:
# Release does not exist: we can safely create it.
click.echo("Creating release %s on repo: %s" % (tag, repo.name))
click.echo("Release title: '%s'" % title)
click.echo("Release message:\n--\n%s\n--\n" % message)
repo.create_git_release(tag=tag, name=title,
message=message,
draft=False, prerelease=False)
# add the asset file if needed
if data_file is not None:
release = None
while release is None:
release = repo.get_release(tag)
release.upload_asset(path=data_file, label=path.split(data_file)[1], content_type="application/gzip")
# --- Memo ---
# release.target_commitish # 'master'
# release.tag_name # '0.5.0'
# release.title # 'First public release'
# release.body # markdown body
# release.draft # False
# release.prerelease # False
# #
# release.author
# release.created_at # datetime.datetime(2018, 11, 9, 17, 49, 56)
# release.published_at # datetime.datetime(2018, 11, 9, 20, 11, 10)
# release.last_modified # None
# #
# release.id # 13928525
# release.etag # 'W/"dfab7a13086d1b44fe290d5d04125124"'
# release.url # 'https://api.github.com/repos/smarie/python-pytest-harvest/releases/13928525'
# release.html_url # 'https://github.com/smarie/python-pytest-harvest/releases/tag/0.5.0'
# release.tarball_url # 'https://api.github.com/repos/smarie/python-pytest-harvest/tarball/0.5.0'
# release.zipball_url # 'https://api.github.com/repos/smarie/python-pytest-harvest/zipball/0.5.0'
# release.upload_url # 'https://uploads.github.com/repos/smarie/python-pytest-harvest/releases/13928525/assets{?name,label}'
if __name__ == '__main__':
create_or_update_release()
python-pytest-cases-3.10.1/ci_tools/nox_utils.py 0000664 0000000 0000000 00000016212 15151413152 0021750 0 ustar 00root root 0000000 0000000 from collections import namedtuple
import logging
from pathlib import Path
import shutil
import os
from typing import Sequence, Dict, Union
import nox
nox_logger = logging.getLogger("nox")
PY27, PY35, PY36, PY37, PY38, PY39, PY310, PY311, PY312, PY313, PY314 = (
"2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"
)
DONT_INSTALL = "dont_install"
def install_reqs(
session,
# pre wired phases
setup=False,
install=False,
tests=False,
extras=(),
# custom phase
phase=None,
phase_reqs=None,
versions_dct=None
):
"""
A high-level helper to install requirements from the various project files
- pyproject.toml "[build-system] requires" (if setup=True)
- setup.cfg "[options] setup_requires" (if setup=True)
- setup.cfg "[options] install_requires" (if install=True)
- setup.cfg "[options] test_requires" (if tests=True)
- setup.cfg "[options.extras_require] <...>" (if extras=(a tuple of extras))
Two additional mechanisms are provided in order to customize how packages are installed.
Conda packages
--------------
If the session runs on a conda environment, you can add a [tool.conda] section to your pyproject.toml. This
section should contain a `conda_packages` entry containing the list of package names that should be installed
using conda instead of pip.
```
[tool.conda]
# Declare that the following packages should be installed with conda instead of pip
# Note: this includes packages declared everywhere, here and in setup.cfg
conda_packages = [
"setuptools",
"wheel",
"pip"
]
```
Version constraints
-------------------
In addition to the version constraints in the pyproject.toml and setup.cfg, you can specify additional temporary
constraints with the `versions_dct` argument , for example if you know that this executes on a specific python
version that requires special care.
For this, simply pass a dictionary of {'pkg_name': 'pkg_constraint'} for example {"pip": ">10"}.
"""
# Read requirements from pyproject.toml
toml_setup_reqs, toml_use_conda_for = read_pyproject_toml()
if setup:
install_any(session, "pyproject.toml#build-system", toml_setup_reqs,
use_conda_for=toml_use_conda_for, versions_dct=versions_dct)
# Read test requirements from setup.cfg
setup_cfg = read_setuptools_cfg()
if setup:
install_any(session, "setup.cfg#setup_requires", setup_cfg.setup_requires,
use_conda_for=toml_use_conda_for, versions_dct=versions_dct)
if install:
install_any(session, "setup.cfg#install_requires", setup_cfg.install_requires,
use_conda_for=toml_use_conda_for, versions_dct=versions_dct)
if tests:
install_any(session, "setup.cfg#tests_requires", setup_cfg.tests_requires,
use_conda_for=toml_use_conda_for, versions_dct=versions_dct)
for extra in extras:
install_any(session, "setup.cfg#extras_require#%s" % extra, setup_cfg.extras_require[extra],
use_conda_for=toml_use_conda_for, versions_dct=versions_dct)
if phase is not None:
install_any(session, phase, phase_reqs, use_conda_for=toml_use_conda_for, versions_dct=versions_dct)
def install_any(session,
phase_name: str,
pkgs: Sequence[str],
use_conda_for: Sequence[str] = (),
versions_dct: Dict[str, str] = None,
):
"""Install the `pkgs` provided with `session.install(*pkgs)`, except for those present in `use_conda_for`"""
# use the provided versions dictionary to update the versions
if versions_dct is None:
versions_dct = dict()
pkgs = [pkg + versions_dct.get(pkg, "") for pkg in pkgs if versions_dct.get(pkg, "") != DONT_INSTALL]
nox_logger.debug("\nAbout to install *%s* requirements: %s.\n "
"Conda pkgs are %s" % (phase_name, pkgs, use_conda_for))
# install on conda... if the session uses conda backend
if not isinstance(session.virtualenv, nox.virtualenv.CondaEnv):
conda_pkgs = []
else:
conda_pkgs = [pkg_req for pkg_req in pkgs if any(get_req_pkg_name(pkg_req) == c for c in use_conda_for)]
if len(conda_pkgs) > 0:
nox_logger.info("[%s] Installing requirements with conda: %s" % (phase_name, conda_pkgs))
session.conda_install(*conda_pkgs)
pip_pkgs = [pkg_req for pkg_req in pkgs if pkg_req not in conda_pkgs]
# safety: make sure that nothing went modified or forgotten
assert set(conda_pkgs).union(set(pip_pkgs)) == set(pkgs)
if len(pip_pkgs) > 0:
nox_logger.info("[%s] Installing requirements with pip: %s" % (phase_name, pip_pkgs))
session.install(*pip_pkgs)
# ------------- requirements related
def read_pyproject_toml() -> Union[list, list]:
"""
Reads the `pyproject.toml` and returns
- a list of setup requirements from [build-system] requires
- sub-list of these requirements that should be installed with conda, from [tool.my_conda] conda_packages
"""
if os.path.exists("pyproject.toml"):
import toml
nox_logger.debug("\nA `pyproject.toml` file exists. Loading it.")
pyproject = toml.load("pyproject.toml")
requires = pyproject['build-system']['requires']
try:
conda_pkgs = pyproject['tool']['conda']['conda_packages']
except KeyError:
conda_pkgs = []
return requires, conda_pkgs
else:
raise FileNotFoundError("No `pyproject.toml` file exists. No dependency will be installed ...")
SetupCfg = namedtuple('SetupCfg', ('setup_requires', 'install_requires', 'tests_requires', 'extras_require'))
def read_setuptools_cfg():
"""
Reads the `setup.cfg` file and extracts the various requirements lists
"""
# see https://stackoverflow.com/a/30679041/7262247
from setuptools import Distribution
dist = Distribution()
dist.parse_config_files()
return SetupCfg(setup_requires=dist.setup_requires,
install_requires=dist.install_requires,
tests_requires=dist.tests_require,
extras_require=dist.extras_require)
def get_req_pkg_name(r):
"""Return the package name part of a python package requirement.
For example
"funcsigs;python<'3.5'" will return "funcsigs"
"pytest>=3" will return "pytest"
"""
return r.replace('<', '=').replace('>', '=').replace(';', '=').split("=")[0]
# ----------- other goodies
def rm_file(folder: Union[str, Path]):
"""Since on windows Path.unlink throws permission error sometimes, os.remove is preferred."""
if isinstance(folder, str):
folder = Path(folder)
if folder.exists():
os.remove(str(folder))
# Folders.site.unlink() --> possible PermissionError
def rm_folder(folder: Union[str, Path]):
"""Since on windows Path.unlink throws permission error sometimes, shutil is preferred."""
if isinstance(folder, str):
folder = Path(folder)
if folder.exists():
shutil.rmtree(str(folder))
# Folders.site.unlink() --> possible PermissionError
python-pytest-cases-3.10.1/docs/ 0000775 0000000 0000000 00000000000 15151413152 0016465 5 ustar 00root root 0000000 0000000 python-pytest-cases-3.10.1/docs/api_reference.md 0000664 0000000 0000000 00000113376 15151413152 0021611 0 ustar 00root root 0000000 0000000 # API reference
In general, using `help(symbol)` is the recommended way to get the latest documentation. In addition, this page provides an overview of the various elements in this package.
## 1 - Fixtures
### `current_cases`
A fixture containing [`get_current_cases(request)`](#get_current_cases).
This is a dictionary containing all case parameters for the currently active `pytest` item. For each test function argument parametrized using a [`@parametrize_with_case(, ...)`](#parametrize_with_cases) this dictionary contains an entry `{: (case_id, case_function, case_params)}`. If several argnames are parametrized this way, a dedicated entry will be present for each argname. The tuple is a `namedtuple` containing
- `id` a string containing the actual case id constructed by `@parametrize_with_cases`.
- `function` the original case function.
- `params` a dictionary, containing the parameters of the case, if itself is parametrized. Note that if the
case is parametrized with `@parametrize_with_cases`, the associated parameter value in the dictionary will also be
`(case_id, case_function, case_params)`.
If a fixture parametrized with cases is active, the dictionary will contain an entry `{: }` where `` is a dictionary `{: (case_id, case_function, case_params)}`.
To get more information on a case function, you can use [`get_case_marks(f)`](#get_case_marks), [`get_case_tags(f)`](#get_case_tags). You can also use [`matches_tag_query`](#matches_tag_query) to check if a case function matches some expectations either concerning its id
or its tags. See [filters and tags documentation](https://smarie.github.io/python-pytest-cases/#filters-and-tags).
## 2 - Case functions
As explained in the [documentation](index.md), case functions have no requirement anymore, and starting from version 2.0.0 of `pytest_cases` they can be parametrized with the usual `@pytest.mark.parametrize` or its improvement [`@parametrize`](#parametrize). Therefore the only remaining decorator is the optional `@case` decorator:
### `@case`
```python
@case(id=None, # type: str # noqa
tags=None, # type: Union[Any, Iterable[Any]]
marks=(), # type: Union[MarkDecorator, Iterable[MarkDecorator]]
)
```
Optional decorator for case functions so as to customize some information.
```python
@case(id='hey')
def case_hi():
return 1
```
**Parameters:**
- `id`: the custom pytest id that should be used when this case is active. Replaces the deprecated `@case_name` decorator from v1. If no id is provided, the id is generated from case functions by removing their prefix, see [`@parametrize_with_cases(prefix='case_')`](#parametrize_with_cases).
- `tags`: custom tags to be used for filtering in [`@parametrize_with_cases(has_tags)`](#parametrize_with_cases). Replaces the deprecated `@case_tags` and `@target` decorators.
- `marks`: optional pytest marks to add on the case. Note that decorating the function directly with the mark also works, and if marks are provided in both places they are merged.
### `@with_case_tags`
```python
@with_case_tags(*tags, # type: Any
):
```
This decorator can be applied to a class defining cases to apply multiple
`*tags` to all case methods defined thereby.
```python
@with_case_tags('tag_1', 'tag_2')
class CasesContainerClass:
def case_one(self, ...):
...
@case(tags='another_tag')
def case_two(self, ...):
...
@case(tags='tag_1')
def case_three(self, ...):
...
```
This is equivalent to:
```python
class CasesContainerClass:
@case(tags=('tag_1', 'tag_2'))
def case_one(self, ...):
...
@case(tags=('another_tag', 'tag_1', 'tag_2'))
def case_two(self, ...):
...
@case(tags=('tag_1', 'tag_2'))
def case_three(self, ...):
...
```
**Parameters:**
- `tags`: custom tags to be added to all case methods. See also [`@case(tags=...)`](#case).
### `copy_case_info`
```python
def copy_case_info(from_fun, # type: Callable
to_fun # type: Callable
):
```
Copies all information from case function `from_fun` to `to_fun`.
### `set_case_id`
```python
def set_case_id(id, # type: str
case_func # type: Callable
):
```
Sets an explicit id on case function `case_func`.
### `get_case_id`
```python
def get_case_id(case_func, # type: Callable
prefix_for_default_ids='case_' # type: str
):
```
Return the case id associated with this case function.
If a custom id is not present, a case id is automatically created from the function name based on removing the provided prefix if present at the beginning of the function name. If the resulting case id is empty, "" will be returned.
**Parameters:**
- `case_func`: the case function to get a case id for.
- `prefix_for_default_ids`: this prefix that will be removed if present on the function name to form the default case id.
### `get_case_marks`
```python
def get_case_marks(case_func, # type: Callable
concatenate_with_fun_marks=False, # type: bool
as_decorators=False # type: bool
):
```
Return the marks that are on the case function.
There are currently two ways to place a mark on a case function: either with `@pytest.mark.` or in `@case(marks=...)`. This function returns a list of marks containing either both (if `concatenate_with_fun_marks` is `True`) or only the ones set with `@case` (`concatenate_with_fun_marks` is `False`, default).
**Parameters:**
- `case_func`: the case function
- `concatenate_with_fun_marks`: if `False` (default) only the marks declared in `@case` will be returned. Otherwise a concatenation of marks in `@case` and on the function (for example directly with `@pytest.mark.`) will be returned.
- `as_decorators`: when `True`, the marks (`MarkInfo`) will be transformed into `MarkDecorators` before being returned. Otherwise (default) the marks are returned as is.
### `get_case_tags`
```python
def get_case_tags(case_func # type: Callable
):
```
Return the tags on this case function or an empty tuple.
**Parameters:**
- `case_func`: the case function
### `matches_tag_query`
```python
def matches_tag_query(case_fun, # type: Callable
has_tag=None, # type: Union[str, Iterable[str]]
filter=None, # type: Union[Callable[[Callable], bool], Iterable[Callable[[Callable], bool]]] # noqa
):
```
This function is the one used by `@parametrize_with_cases` to filter the case functions collected. It can be used manually for tests/debug.
Returns True if the case function is selected by the query:
- if `has_tag` contains one or several tags, they should ALL be present in the tags set on `case_fun` (`get_case_tags`)
- if `filter` contains one or several filter callables, they are all called in sequence and the `case_fun` is only selected if ALL of them return a `True` truth value
**Parameters:**
- `case_fun`: the case function
- `has_tag`: one or several tags that should ALL be present in the tags set on `case_fun` for it to be selected.
- `filter`: one or several filter callables that will be called in sequence. If all of them return a `True` truth value, `case_fun` is selected.
### `is_case_class`
```python
def is_case_class(cls, # type: Any
case_marker_in_name='Case', # type: str
check_name=True # type: bool
):
```
This function is the one used by `@parametrize_with_cases` to collect cases within classes. It can be used manually for tests/debug.
Returns True if the given object is a class and, if `check_name=True` (default), if its name contains `case_marker_in_name`.
**Parameters:**
- `cls`: the object to check
- `case_marker_in_name`: the string that should be present in a class name so that it is selected. Default is 'Case'.
- `check_name`: a boolean (default True) to enforce that the name contains the word `case_marker_in_name`. If False, any class will lead to a `True` result whatever its name.
### `is_case_function`
```python
def is_case_function(f, # type: Any
prefix='case_', # type: str
check_prefix=True # type: bool
):
```
This function is the one used by `@parametrize_with_cases` to collect cases. It can be used manually for tests/debug.
Returns True if the provided object is a function or callable and, if `check_prefix=True` (default), if it starts with `prefix`.
**Parameters:**
- `f`: the object to check
- `prefix`: the string that should be present at the beginning of a function name so that it is selected. Default is 'case_'.
- `check_prefix`: if this boolean is True (default), the prefix will be checked. If False, any function will lead to a `True` result whatever its name.
### The `filters` submodule
This submodule contains symbols to help you create filters for `@parametrize_with_cases(filter=...)`.
All helper filters in this submodule return an instance of `CaseFilter`, so that you can combine them easily with "and" (`&`) "or" (`|`) and "invert" (`~`) in order to create new custom filters.
#### `has_tag`
```python
def has_tag(tag_name: str)
```
Selects cases that have the tag `tag_name`. See `@case(tags=...)` to add tags to a case.
#### `has_tags`
```python
def has_tags(*tag_names: str)
```
Selects cases that have all tags `tag_names`. See `@case(tags=...)` to add tags to a case.
#### `id_has_prefix`
```python
def id_has_prefix(prefix: str)
```
Selects cases that have a case id prefix `prefix`. Note that this is not the prefix of the whole case function name, but the case id, possibly overridden with `@case(id=)`
#### `id_has_suffix`
```python
def id_has_suffix(suffix: str)
```
Selects cases that have a case id suffix `suffix`. Note that this is not the suffix of the whole case function name, but the case id, possibly overridden with `@case(id=)`
#### `id_match_regex`
```python
def id_match_regex(regex: str)
```
Selects cases that have a case id matching regex pattern `regex`. Note that this is not a match of the whole case function name, but the case id, possibly overridden with `@case(id=)`
#### `CaseFilter`
```python
CaseFilter(filter_function: Callable)
```
`CaseFilter` is the class used by all filters above, and implementing logical operations "and" (`&`) "or" (`|`) and "not" (`~`). You can use it to define a composable filter from any callable receiving a single `case` argument and returning a boolean indicating if the `case` is selected.
## 3 - Cases collection
### `@parametrize_with_cases`
```python
CaseType = Union[Callable, Type, ModuleRef]
@parametrize_with_cases(argnames: str,
cases: Union[CaseType, List[CaseType]] = AUTO,
prefix: str = 'case_',
glob: str = None,
has_tag: Union[str, Iterable[str]] = None,
filter: Callable = None,
ids: Union[Callable, Iterable[str]] = None,
idstyle: Union[str, Callable] = None,
scope: str = "function",
import_fixtures: bool = False
)
```
A decorator for test functions or fixtures, to parametrize them based on test cases. It works similarly to [`@pytest.mark.parametrize`](https://docs.pytest.org/en/stable/parametrize.html): argnames represent a coma-separated string of arguments to inject in the decorated test function or fixture. The argument values (`argvalues` in [`@pytest.mark.parametrize`](https://docs.pytest.org/en/stable/parametrize.html)) are collected from the various case functions found according to `cases`, and injected as lazy values so that the case functions are called just before the test or fixture is executed.
By default (`cases=AUTO`) the list of test cases is automatically drawn from the python module file named `test__cases.py` or if not found, `cases_.py`, where `test_` is the current module name.
Finally, the `cases` argument also accepts an explicit case function, cases-containing class, module or module name; or a list containing any mix of these elements. Note that both absolute and relative module names are supported.
Note that `@parametrize_with_cases` collection and parameter creation steps are strictly equivalent to [`get_all_cases`](#get_all_cases) + [`get_parametrize_args`](#get_parametrize_args). This can be handy for debugging purposes.
```python
# Collect all cases
cases_funs = get_all_cases(f, cases=cases, prefix=prefix,
glob=glob, has_tag=has_tag, filter=filter)
# Transform the various functions found
argvalues = get_parametrize_args(host_class_or_module_of_f, cases_funs)
```
**Parameters**
- `argnames`: same than in `@pytest.mark.parametrize`
- `cases`: a case function, a class containing cases, a module object or a module name string (relative module names accepted). Or a list of such items. You may use `THIS_MODULE` or `'.'` to include current module. `AUTO` (default) means that the module named `test__cases.py` or if not found, `cases_.py`, will be loaded, where `test_.py` is the module file of the decorated function. When a module is listed, all of its functions matching the `prefix`, `filter` and `has_tag` are selected, including those functions nested in classes following naming pattern `*Case*`. Nested subclasses are taken into account, as long as they follow the `*Case*` naming pattern. When classes are explicitly provided in the list, they can have any name and do not need to follow this `*Case*` pattern.
- `prefix`: the prefix for case functions. Default is 'case_' but you might wish to use different prefixes to denote different kind of cases, for example 'data_', 'algo_', 'user_', etc.
- `glob`: a matching pattern for case ids, for example `*_success` or `*_failure`. The only special character that can be used for now in this pattern is `*`, it can not be escaped, and it can be used several times in the same expression. The pattern should match the entire case id for the case to be selected. Note that this is applied on the case id, and therefore if it is customized through [`@case(id=...)`](#case) it will be taken into account.
- `has_tag`: a single tag or a tuple, set, list of tags that should be matched by the ones set with the [`@case`](#case) decorator on the case function(s) to be selected.
- `filter`: a callable receiving the case function and returning `True` or a truth value in case the function needs to be selected.
- `ids`: optional custom ids, similar to the one in `pytest.mark.parametrize`. Users may either provide an iterable of string ids, or a callable. If a callable is provided it will receive the case functions. Users may wish to use [`get_case_id`](#get_case_id) or other helpers in the [API](#2-case-functions) to inspect the case functions.
- `idstyle`: This is mostly for debug. Style of ids to be used in the "union" fixtures generated by [`@parametrize`](#parametrize) if some cases are transformed into fixtures behind the scenes. `idstyle` possible values are `'compact'`, `'explicit'` or `None`/`'nostyle'` (default), or a callable. `idstyle` has no effect if no cases are transformed into fixtures. As opposed to `ids`, a callable provided here will receive a `ParamAlternative` object indicating which generated fixture should be used. See [`@parametrize`](#parametrize) for details.
- `scope`: The scope of the union fixture to create if `fixture_ref`s are found in the argvalues
- `import_fixtures`: experimental feature. Turn this to `True` in order to automatically import all fixtures defined in the cases module into the current module.
### `get_current_cases`
```python
def get_current_cases(request_or_item):
```
Returns a dictionary containing all case parameters for the currently active `pytest` item. You can either pass the `pytest` item (available in some hooks) or the `request` (available in hooks, and also directly as a fixture).
For each test function argument parametrized using a [`@parametrize_with_case(, ...)`](#parametrize_with_cases) this dictionary contains an entry `{: (case_id, case_function, case_params)}`. If several argnames are parametrized this way, a dedicated entry will be present for each argname. The tuple is a `namedtuple` containing
- `id` a string containing the actual case id constructed by `@parametrize_with_cases`.
- `function` the original case function.
- `params` a dictionary, containing the parameters of the case, if itself is parametrized. Note that if the
case is parametrized with `@parametrize_with_cases`, the associated parameter value in the dictionary will also be
`(case_id, case_function, case_params)`.
If a fixture parametrized with cases is active, the dictionary will contain an entry `{: }` where `` is a dictionary `{: (case_id, case_function, case_params)}`.
To get more information on a case function, you can use [`get_case_id(f)`](#get_case_id), [`get_case_marks(f)`](#get_case_marks), [`get_case_tags(f)`](#get_case_tags). You can also use [`matches_tag_query`](#matches_tag_query) to check if a case function matches some expectations either concerning its id
or its tags. See [filters and tags documentation](https://smarie.github.io/python-pytest-cases/#filters-and-tags).
Note that you can get the same contents directly by using the [`current_cases`](#current_cases) fixture.
### `get_all_cases`
```python
CaseType = Union[Callable, Type, ModuleRef]
def get_all_cases(parametrization_target: Callable,
cases: Union[CaseType, List[CaseType]] = None,
prefix: str = 'case_',
glob: str = None,
has_tag: Union[str, Iterable[str]] = None,
filter: Callable[[Callable], bool] = None
) -> List[Callable]:
```
Collect all cases as used with [`@parametrize_with_cases`](#parametrize_with_cases). See [`@parametrize_with_cases`](#parametrize_with_cases) for more details on the parameters.
This can be used to lists all desired cases for a given `parametrization_target` (a test function or a fixture) which may be convenient for debugging purposes.
```python
# Get the cases for f that are defined in the current file
cases = get_all_cases(f, cases=".")
# Get the cases from cases_xyz.py or test_xyz_cases.py
import test.test_xyz
xyz_cases = get_all_cases(test.test_xyz)
# Can be used to filter explicit cases, in which case no parametrization_target is needed
filtered_cases = get_all_cases(cases=[case_1, case_2, case_3], has_tag=["banana"])
```
- If using a `cases` argument that requires module information, such as `"."` `AUTO` or a relative module like `".xyz"`, the value of `parametrization_target` will be used to to determine the context.
If `None` or simply left empty, it will use the module from which `get_all_cases` was called.
You can pass an explicit module object or a function, in which case the module in which it's defined will be used.
### `get_parametrize_args`
```python
def get_parametrize_args(host_class_or_module: Union[Type, ModuleType],
cases_funs: List[Callable],
debug: bool = False
) -> List[Union[lazy_value, fixture_ref]]:
```
Transforms a list of cases (obtained from [`get_all_cases`](#get_all_cases)) into a list of argvalues for [`@parametrize`](#parametrize). Each case function `case_fun` is transformed into one or several [`lazy_value`](#lazy_value)(s) or a [`fixture_ref`](#fixture_ref):
- If `case_fun` requires at least on fixture, a fixture will be created if not yet present, and a `fixture_ref` will be returned.
- If `case_fun` is a parametrized case, one `lazy_value` with a partialized version will be created for each parameter combination.
- Otherwise, `case_fun` represents a single case: in that case a single `lazy_value` is returned.
## 4 - Pytest goodies
### `@fixture`
```python
@fixture(scope: str = "function",
autouse: bool = False,
name: str = None,
unpack_into: Iterable[str] = None,
hook: Callable = None,
**kwargs)
```
Identical to `@pytest.fixture` decorator, except that
- when used in a fixture union (either explicit `fixture_union` or indirect through `@parametrize`+`fixture_ref` or `@parametrize_with_cases`), it will not be setup/teardown unnecessarily in tests that do not require it.
- it supports multi-parametrization with `@pytest.mark.parametrize` as requested in [pytest#3960](https://github.com/pytest-dev/pytest/issues/3960). As a consequence it does not support the `params` and `ids` arguments anymore.
- it supports a new argument `unpack_into` where you can provide names for fixtures where to unpack this fixture into.
As a consequence it does not support the `params` and `ids` arguments anymore.
**Parameters:**
- **scope**: the scope for which this fixture is shared, one of "function" (default), "class", "module" or "session".
- **autouse**: if True, the fixture func is activated for all tests that can see it. If False (the default) then an explicitreference is needed to activate the fixture.
- **name**: the name of the fixture. This defaults to the name of the decorated function. Note: If a fixture is used in the same module in which it is defined, the function name of the fixture will be shadowed by the function arg that requests the fixture; one wayto resolve this is to name the decorated function ``fixture_`` and then use ``@pytest.fixture(name='')``.
- **unpack_into**: an optional iterable of names, or string containing coma-separated names, for additional fixtures to create to represent parts of this fixture. See [`unpack_fixture`](#unpack_fixture) for details.
- **hook**: an optional hook to apply to each fixture function that is created during this call. The hook function will be called every time a fixture is about to be created. It will receive a single argument (the function implementing the fixture) and should return the function to use. For example you can use `saved_fixture` from `pytest-harvest` as a hook in order to save all such created fixtures in the fixture store.
- **kwargs**: other keyword arguments for `@pytest.fixture`
### `unpack_fixture`
```python
def unpack_fixture(argnames: str,
fixture: Union[str, Callable],
in_cls: bool = False,
hook: Callable = None
) -> Tuple[, ...]
```
Creates several fixtures with names `argnames` from the source `fixture`. Created fixtures will correspond to elements unpacked from `fixture` in order. For example if `fixture` is a tuple of length 2, `argnames="a,b"` will create two fixtures containing the first and second element respectively.
The created fixtures are automatically registered into the callers' module, but you may wish to assign them to variables for convenience. In that case make sure that you use the same names, e.g. `a, b = unpack_fixture('a,b', 'c')`.
```python
import pytest
from pytest_cases import unpack_fixture, fixture
@fixture
@pytest.mark.parametrize("o", ['hello', 'world'])
def c(o):
return o, o[0]
a, b = unpack_fixture("a,b", c)
def test_function(a, b):
assert a[0] == b
```
You can also use this function inside a class with `in_cls=True`. In that case you MUST assign the output of the function to variables, as the created fixtures won't be registered with the encompassing module.
```python
import pytest
from pytest_cases import unpack_fixture, fixture
@fixture
@pytest.mark.parametrize("o", ['hello', 'world'])
def c(o):
return o, o[0]
class TestClass:
a, b = unpack_fixture("a,b", c, in_cls=True)
def test_function(self, a, b):
assert a[0] == b
```
**Parameters**
- **argnames**: same as `@pytest.mark.parametrize` `argnames`.
- **fixture**: a fixture name string or a fixture symbol. If a fixture symbol is provided, the created fixtures will have the same scope. If a name is provided, they will have scope='function'. Note that in practice the performance loss resulting from using `function` rather than a higher scope is negligible since the created fixtures' body is a one-liner.
- **in_cls**: a boolean (default `False`). You may wish to turn this to `True` to use this function inside a class. If you do so, you **MUST** assign the output to variables in the class.
- **hook**: an optional hook to apply to each fixture function that is created during this call. The hook function will be called every time a fixture is about to be created. It will receive a single argument (the function implementing the fixture) and should return the function to use. For example you can use `saved_fixture` from `pytest-harvest` as a hook in order to save all such created fixtures in the fixture store.
**Outputs:** the created fixtures.
### `fixture_union`
```python
def fixture_union(name: str,
fixtures: Iterable[Union[str, Callable]],
scope: str = "function",
idstyle: Optional[str] = 'compact',
ids: Union[Callable, Iterable[str]] = None,
unpack_into: Iterable[str] = None,
autouse: bool = False,
hook: Callable = None,
**kwargs) ->
```
Creates a fixture that will take all values of the provided fixtures in order. That fixture is automatically registered into the callers' module, but you may wish to assign it to a variable for convenience. In that case make sure that you use the same name, e.g. `a = fixture_union('a', ['b', 'c'])`
The style of test ids corresponding to the union alternatives can be changed with `idstyle`. Three values are allowed:
- `'explicit'` favors readability with names as `/`,
- `'compact'` (default) adds a small mark so that at least one sees which parameters are union alternatives and
which others are normal parameters: `/`
- `None` or `'nostyle'` provides minimalistic ids : ``
See `UnionIdMakers` class for details.
You can also pass a callable `idstyle` that will receive instances of `UnionFixtureAlternative`. For example `str`
leads to very explicit ids: `//`. See `UnionFixtureAlternative` class for details.
**Parameters:**
- `name`: the name of the fixture to create
- `fixtures`: an array-like containing fixture names and/or fixture symbols
- `scope`: the scope of the union. Since the union depends on the sub-fixtures, it should be smaller than the smallest scope of fixtures referenced.
- `idstyle`: The style of test ids corresponding to the union alternatives. One of `'explicit'`, `'compact'`,`'nostyle'`/`None`, or a callable (e.g. `str`) that will receive instances of `UnionFixtureAlternative`.
- `unpack_into`: an optional iterable of names, or string containing coma-separated names, for additional fixtures to create to represent parts of this fixture. See `unpack_fixture` for details.
- `ids`: as in pytest. The default value returns the correct fixture
- `autouse`: as in pytest
- `hook`: an optional hook to apply to each fixture function that is created during this call. The hook function will be called every time a fixture is about to be created. It will receive a single argument (the function implementing the fixture) and should return the function to use. For example you can use `saved_fixture` from `pytest-harvest` as a hook in order to save all such created fixtures in the fixture store.
- `kwargs`: other pytest fixture options. They might not be supported correctly.
**Outputs:** the new fixture. Note: you do not need to capture that output in a symbol, since the fixture is automatically registered in your module. However if you decide to do so make sure that you use the same name.
### `param_fixtures`
```python
def param_fixtures(argnames: str,
argvalues: Iterable[Any],
autouse: bool = False,
ids: Union[Callable, Iterable[str]] = None,
scope: str = "function",
hook: Callable = None,
debug: bool = False,
**kwargs) -> Tuple[]
```
Creates one or several "parameters" fixtures - depending on the number or coma-separated names in `argnames`. The created fixtures are automatically registered into the callers' module, but you may wish to assign them to variables for convenience. In that case make sure that you use the same names, e.g. `p, q = param_fixtures('p,q', [(0, 1), (2, 3)])`.
Note that the `(argnames, argvalues, ids)` signature is similar to `@pytest.mark.parametrize` for consistency, see [pytest doc on parametrize](https://docs.pytest.org/en/latest/reference.html?highlight=pytest.param#pytest-mark-parametrize).
```python
import pytest
from pytest_cases import param_fixtures, param_fixture
# create a 2-tuple parameter fixture
arg1, arg2 = param_fixtures("arg1, arg2", [(1, 2), (3, 4)])
@pytest.fixture
def fixture_uses_param2(arg2):
...
def test_uses_param2(arg1, arg2, fixture_uses_param2):
...
```
**Parameters:**
- `argnames`: same as `@pytest.mark.parametrize` `argnames`.
- `argvalues`: same as `@pytest.mark.parametrize` `argvalues`.
- `autouse`: see fixture `autouse`
- `ids`: same as `@pytest.mark.parametrize` `ids`
- `scope`: see fixture `scope`
- `hook`: an optional hook to apply to each fixture function that is created during this call. The hook function will be called every time a fixture is about to be created. It will receive a single argument (the function implementing the fixture) and should return the function to use. For example you can use `saved_fixture` from `pytest-harvest` as a hook in order to save all such created fixtures in the fixture store.
- `kwargs`: any other argument for the created 'fixtures'
### `param_fixture`
```python
param_fixture(argname, argvalues,
autouse=False, ids=None, hook=None, scope="function", **kwargs)
->
```
Identical to `param_fixtures` but for a single parameter name, so that you can assign its output to a single variable.
### `@parametrize`
```python
def parametrize(argnames: str=None,
argvalues: Iterable[Any]=None,
indirect: bool = False,
ids: Union[Callable, Iterable[str]] = None,
idstyle: Union[str, Callable] = None,
idgen: Union[str, Callable] = _IDGEN,
auto_refs: bool = True,
scope: str = None,
hook: Callable = None,
scope: str = "function",
debug: bool = False,
**args)
```
Equivalent to `@pytest.mark.parametrize` but also supports
**New alternate style for argnames/argvalues**. One can also use `**args` to pass additional `{argnames: argvalues}` in the same parametrization call. This can be handy in combination with `idgen` to master the whole id template associated with several parameters. Note that you can pass coma-separated argnames too, by de-referencing a dict: e.g. `**{'a,b': [(0, True), (1, False)], 'c': [-1, 2]}`.
**New alternate style for ids**. One can use `idgen` instead of `ids`. `idgen` can be a callable receiving all parameters at once (`**args`) and returning an id ; or it can be a string template using the new-style string formatting where the argnames can be used as variables (e.g. `idgen=lambda **args: "a={a}".format(**args)` or `idgen="my_id where a={a}"`). The special `idgen=AUTO` symbol can be used to generate a default string template equivalent to `lambda **args: "-".join("%s=%s" % (n, v) for n, v in args.items())`. This is enabled by default if you use the alternate style for argnames/argvalues (e.g. if `len(args) > 0`), and if there are no `fixture_ref`s in your argvalues.
**New possibilities in argvalues**:
- one can include *references to fixtures* with [`fixture_ref()`](#fixture_ref) where can be the fixture name or fixture function. When such a fixture reference is detected in the argvalues, a new function-scope "union" fixture will be created with a unique name, and the test function will be wrapped so as to be injected with the correct parameters from this fixture. Special test ids will be created to illustrate the switching between the various normal parameters and fixtures. You can see debug print messages about all fixtures created using `debug=True`. New: from version `3.2` on, if `auto_refs=True` (default), `@parametrize` will automatically detect fixture symbols in the list of argvalues, and will create `fixture_ref`s automatically around them so that you don't need to.
- one can include lazy argvalues with [`lazy_value(, [id=..., marks=...])`](#lazy_value). A `lazy_value` is the same thing than a function-scoped fixture, except that the value getter function is not a fixture and therefore can neither be parametrized nor depend on fixtures. It should have no mandatory argument.
Both `fixture_ref` and `lazy_value` can be used to represent a single argvalue, or a whole tuple of argvalues when there are several argnames. Several of them can be used in a tuple.
Finally, `pytest.param` is supported even when there are `fixture_ref` and `lazy_value`.
Here as for all functions above, an optional `hook` can be passed, to apply on each fixture function that is created during this call. The hook function will be called every time a fixture is about to be created. It will receive a single argument (the function implementing the fixture) and should return the function to use. For example you can use `saved_fixture` from `pytest-harvest` as a hook in order to save all such created fixtures in the fixture store.
**Parameters**
- `argnames`: same than in `@pytest.mark.parametrize`
- `argvalues: same as in pytest.mark.parametrize except that `fixture_ref` and `lazy_value` are supported
- `indirect`: same as in pytest.mark.parametrize. Note that it is not recommended and is not guaranteed to work in complex parametrization scenarii.
- `ids`: same as in pytest.mark.parametrize. Note that an alternative way to create ids exists with `idgen`. Only one non-None `ids` or `idgen` should be provided.
- `idgen`: an id formatter. Either a string representing a template, or a callable receiving all argvalues at once (as opposed to the behaviour in pytest ids). This alternative way to generate ids can only be used when `ids` is not provided (None). You can use the special `pytest_cases.AUTO` formatter to generate an automatic id with template `=-=-...`. `AUTO` is enabled by default if you use the alternate style for argnames/argvalues (e.g. if `len(args) > 0`), and if there are no `fixture_ref`s in your argvalues.
- `idstyle`: This is mostly for debug. Style of ids to be used in the "union" fixtures generated by `@parametrize` if at least one `fixture_ref` is found in the argvalues. `idstyle` possible values are 'compact', 'explicit' or None/'nostyle' (default), or a callable. `idstyle` has no effect if no `fixture_ref` are present in the argvalues. As opposed to `ids`, a callable provided here will receive a `ParamAlternative` object indicating which generated fixture should be used.
- `auto_refs`: a boolean. If this is `True` (default), argvalues containing fixture symbols will automatically be wrapped into a `fixture_ref`, for convenience.
- `scope`: The scope of the union fixture to create if `fixture_ref`s are found in the argvalues. Otherwise same as in `pytest.mark.parametrize`.
- `hook`: an optional hook to apply to each fixture function that is created during this call. The hook function will be called every time a fixture is about to be created. It will receive a single argument (the function implementing the fixture) and should return the function to use. For example you can use `saved_fixture` from `pytest-harvest` as a hook in order to save all such created fixtures in the fixture store.
- `debug`: print debug messages on stdout to analyze fixture creation (use pytest -s to see them)
### `lazy_value`
```python
def lazy_value(valuegetter: Callable[[], Any],
id: str = None,
marks: Union[Any, Sequence[Any]] = ()
) -> LazyValue
```
A reference to a value getter (an argvalue-providing callable), to be used in [`@parametrize`](#parametrize).
A `lazy_value` is the same thing than a function-scoped fixture, except that the value getter function is not a fixture and therefore can neither be parametrized nor depend on fixtures. It should have no mandatory argument. The underlying function will be called exactly once per test node.
By default the associated id is the name of the `valuegetter` callable, but a specific `id` can be provided otherwise. Note that this `id` does not take precedence over custom `ids` or `idgen` passed to `@parametrize`.
Note that a `lazy_value` can be included in a `pytest.param` without problem. In that case the id defined by `pytest.param` will take precedence over the one defined in `lazy_value` if any. The marks, however, will all be kept wherever they are defined.
**Parameters**
- `valuegetter`: a callable without mandatory arguments
- `id`: an optional id. Otherwise `valuegetter.__name__` will be used by default
- `marks`: optional marks. `valuegetter` marks will also be preserved.
### `is_lazy`
```python
def is_lazy(argval) -> bool
```
Return `True` if `argval` is the outcome of processing a `lazy_value` through `@parametrize`. This encompasses parameters that are items of lazy tuples that are created when parametrizing several argnames with the same `lazy_value()`.
### `fixture_ref`
```python
def fixture_ref(fixture: Union[str, Fixture]
)
```
A reference to a fixture to be used with [`@parametrize`](#parametrize). Create it with `fixture_ref()` where can be the fixture name or actual fixture function.
python-pytest-cases-3.10.1/docs/changelog.md 0000664 0000000 0000000 00000147273 15151413152 0020754 0 ustar 00root root 0000000 0000000 # Changelog
### 3.10.1 - Accurate metadata on PyPi
- Fixed python version in package metadata. `3.13` was missing.
### 3.10.0 - New `with_case_tags` decorator + pytest 9 compatibility
- Fixed an issue with `pytest 9` related to the fixture closure building fixes
[pytest-dev/pytest#13789](https://github.com/pytest-dev/pytest/pull/13789),
solving [pytest-dev/pytest#13773](https://github.com/pytest-dev/pytest/issues/13773).
Fixed [#374](https://github.com/smarie/python-pytest-cases/issues/374). PR
[#376](https://github.com/smarie/python-pytest-cases/pull/376) by [jammer87](https://github.com/jammer87).
- Added the `with_case_tags` decorator for applying common tags to all cases
defined in a case class. Fixes [#351](https://github.com/smarie/python-pytest-cases/issues/351).
PR [#361](https://github.com/smarie/python-pytest-cases/pull/361)
by [@michele-riva](https://github.com/michele-riva).
### 3.9.1 - support for python 3.14 and pytest 8.4
- Fixed `AttributeError: 'MiniMetafunc' object has no attribute '_params_directness'` when a case function is
parametrized or requires a fixtures, with pytest 8.4.0. Fixed
[#365](https://github.com/smarie/python-pytest-cases/issues/365)
- Fixed `ValueError: The provided fixture function does not seem to be a fixture` with `@fixture_ref` with pytest
8.4.0. Fixed [#364](https://github.com/smarie/python-pytest-cases/issues/364)
- Dropped support for `python<3.9` and `pytest<6`. Fixes
[#362](https://github.com/smarie/python-pytest-cases/issues/362) and fixes
[#186](https://github.com/smarie/python-pytest-cases/issues/186)
- Fixed test suite for python 3.14, officializing the support for this version.
### 3.9.0 - yanked version
This version was yanked. See 3.9.1.
### 3.8.6 - compatibility fix
- Fixed issue with legacy python 2.7 and 3.5. Fixes [#352](https://github.com/smarie/python-pytest-cases/issues/352).
### 3.8.5 - Suppressed annoying warning with pytest 8
- Fixed `PytestRemovedIn9Warning: Marks applied to fixtures have no effect`. Fixed
[#337](https://github.com/smarie/python-pytest-cases/issues/337)
### 3.8.4 - Removed debug logs
- Reverted `DEBUG` flag used for pytest 8 compatibility. Fixed
[#336](https://github.com/smarie/python-pytest-cases/issues/336)
### 3.8.3 - Support for `pytest` version 8
- Fixed compliance with pytest 8. Fixed [#330](https://github.com/smarie/python-pytest-cases/issues/330). PR
[#335](https://github.com/smarie/python-pytest-cases/pull/335) by [smarie](https://github.com/smarie) and
[larsoner](https://github.com/larsoner).
### 3.8.2 - bugfixes and project improvements
- Fixed issue with upcoming `pytest 8.1` release. PR
[#322](https://github.com/smarie/python-pytest-cases/pull/322) by
[@bluetech](https://github.com/bluetech)
- Corrected API documentation (and comments) for the second file-name
pattern for `AUTO`-cases lookup (`cases_.py` instead of
`case_.py`). PR [#320](https://github.com/smarie/python-pytest-cases/pull/320)
by [@michele-riva](https://github.com/michele-riva).
- Fixed `AssertionError` on `AUTO` cases outside a 'normal' test module.
Fixes [#309](https://github.com/smarie/python-pytest-cases/issues/309). PR
[#320](https://github.com/smarie/python-pytest-cases/pull/320) by
[@michele-riva](https://github.com/michele-riva).
- Improved error message in case of cases loading error in `@parametrize_with_cases` when the `cases` argument
is a string refering to a relative or absolute module name. Fixed `import file mismatch` with
pytest 8 when executing our own tests.
Fixes [#323](https://github.com/smarie/python-pytest-cases/issues/323).
- Fixed failing tests in our builds due to the `event_loop_policy` fixture that appeared in `pytest-asyncio` `0.23`.
Fixes part of
[#321](https://github.com/smarie/python-pytest-cases/issues/321).
### 3.8.1 - bugfixes
- Fixed `ScopeMismatch` with parametrized cases in non-trivial test
trees. `scope` is now correctly handled for (i) `fixture` cases, and
(ii) fixtures defined in `conftest.py` files at any depth. Fixes
[#311](https://github.com/smarie/python-pytest-cases/issues/311). PR
[#317](https://github.com/smarie/python-pytest-cases/pull/317) by [@michele-riva](https://github.com/michele-riva).
### 3.8.0 - async, generators and strict-markers
- `@fixture` and `@parametrize` are now async and generator aware. Fixes
[#286](https://github.com/smarie/python-pytest-cases/issues/286). PR
[#301](https://github.com/smarie/python-pytest-cases/pull/301) by [jgersti](https://github.com/jgersti).
- Fixed error with `pytest` `--strict-markers`. Fixes
[#283](https://github.com/smarie/python-pytest-cases/issues/283). PR
[#300](https://github.com/smarie/python-pytest-cases/pull/300) by [chrsmcgrr](https://github.com/chrsmcgrr).
### 3.7.0 - python 3.12
- Added official support for Python 3.10, 3.11 and 3.12. Fixes [#314](https://github.com/smarie/python-pytest-cases/issues/314)
- Fixed `ModuleNotFoundError: distutils` on Python 3.12 thanks to `packaging`. PR
[#312](https://github.com/smarie/python-pytest-cases/pull/312) by [@jayqi](https://github.com/jayqi).
- Internal: switched to virtualenv backend.
### 3.6.14 - bugfixes
- Fixed `AttributeError` issue in `is_case_function` when an inspected symbol is a parametrized type hint
without `__name__`. Fixes [#287](https://github.com/smarie/python-pytest-cases/issues/287)
- Fixed issue with `get_all_cases`: default value for `cases` was wrong. Fixes [#290](https://github.com/smarie/python-pytest-cases/issues/290)
### 3.6.13 - bugfix
- Fixed issue where a lazy value (for example a case function) was not resolved before being injected in a parametrized function, and was therefore appearing as a `_LazyValueCaseParamValue `. Fixed [#274](https://github.com/smarie/python-pytest-cases/issues/274)
### 3.6.12 - type hint fix + enhanced compatibility with pytest plugins
- Improved compatibility with other `pytest` plugins, in particular `pytest-repeat`, by supporting removal from fixture closure tree. Fixed [#269](https://github.com/smarie/python-pytest-cases/issues/269).
- Fixed type hint errors detected by `pyright`. Fixed [#270](https://github.com/smarie/python-pytest-cases/issues/270)
### 3.6.11 - bugfix for pytest-xdist and `get_all_cases` API improvement
- `get_all_cases` can now be called without `parametrization_target` (defaulting to the caller module), and with an explicit module object. Fixed [#258](https://github.com/smarie/python-pytest-cases/issues/258). PR [#260](https://github.com/smarie/python-pytest-cases/pull/260) by [@eddiebergman](https://github.com/eddiebergman).
- Fixed `AttributeError`: module 'pytest_cases' has no attribute 'CasesCollectionWarning' when running `pytest-xdist` and at least one cases class is ignored because of `__init__` or `__new__`. Fixed [#249](https://github.com/smarie/python-pytest-cases/issues/249).
### 3.6.10 - bugfix for pytest 7.1
- Fixed `ImportError` when using `pytest 7.1`. Fixed [#264](https://github.com/smarie/python-pytest-cases/issues/264) and [pytest-dev#9762](https://github.com/pytest-dev/pytest/issues/9762).
### 3.6.9 - Bugfix with pytest 7
- Fixed `FrozenInstanceError` when using `pytest 7.0.0`. Fixed [#251](https://github.com/smarie/python-pytest-cases/issues/251). [PR#253](https://github.com/smarie/python-pytest-cases/pull/253) by [jammer87](https://github.com/jammer87)
### 3.6.8 - Bugfix: support for multiprocessing Pool
- Suppressed warnings in our own tests, to improve packaging maintenance. Fixed [#248](https://github.com/smarie/python-pytest-cases/issues/248)
- Fixed bug where setting `ids` in `@parametrize` without setting explicitly `idgen=None` would raise a `ValueError`. Fixed [#238](https://github.com/smarie/python-pytest-cases/issues/238).
- Fixed bug where case-holding class marks were not propagated to static methods and class methods. Fixed [#246](https://github.com/smarie/python-pytest-cases/issues/246)
- Fixed support for multiprocessing `Pool`. Fixes [#242](https://github.com/smarie/python-pytest-cases/issues/242)
### 3.6.7 - Minor improvements and preparing for pytest 7
- Improved error message when a case function nested in a class has no `self` argument and is not static. Fixes [#243](https://github.com/smarie/python-pytest-cases/issues/243)
- Added support for the new Scopes enum in pytest 7. Fixed [#241](https://github.com/smarie/python-pytest-cases/issues/241)
- Fixed `__version__` in development mode.
### 3.6.6 - Layout change
- Restructured project so that tests are truly independent, to ease rpm/apt/etc. packaging. Fixed [#220](https://github.com/smarie/python-pytest-cases/issues/220).
### 3.6.5 - Bugfix
- Fixed an issue where using keyword `argnames` in `@pytest.mark.parametrize` would cause `IndexError: tuple index out of range` in the tests collection phase. Fixed [#234](https://github.com/smarie/python-pytest-cases/issues/234).
### 3.6.4 - Bugfix
- A case id can now be a reserved keyword without triggering any `SyntaxError`, even if the case is transformed into a fixture. Fixes [#230](https://github.com/smarie/python-pytest-cases/issues/230)
### 3.6.3 - Bugfix
- Fixed an issue where a lazy value would not be resolved. This happens when the "auto-simplify fixture" happens in `@parametrize`. Fixes [#225](https://github.com/smarie/python-pytest-cases/issues/225)
### 3.6.2 - Qualimetry
- Fixed most `flake8` errors and updated documentation to use `genbadge`. Fixes [#223](https://github.com/smarie/python-pytest-cases/issues/223)
### 3.6.1 - bugfix - parametrizing a class with `@parametrize`
- Fixed `ValueError` when `@parametrize` is used to parametrize a class. Also, added a more explicit `TypeError` when `@parametrize` is used to parametrize a class and at least a fixture reference is present. Fixed [#215](https://github.com/smarie/python-pytest-cases/issues/215).
### 3.6.0 - `unpack_fixtures` in classes + `current_cases` improvements
- The `current_cases` fixture now contains case parameters if any. Fixes [#214](https://github.com/smarie/python-pytest-cases/issues/214)
- The `current_cases` fixture entries are now instances of `namedtuple`.
- New `in_cls` argument in `unpack_fixtures` so that it can be used inside classes. Fixes [#201](https://github.com/smarie/python-pytest-cases/issues/201)
- Fixed minor issue where empty entries could be present in `currentcases`. Fixes [#213](https://github.com/smarie/python-pytest-cases/issues/213)
### 3.5.2 - bugfix with the `currentcases` fixture
- Fixed issues where the `currentcases` fixture would not return the correct case function. Fixed [#212](https://github.com/smarie/python-pytest-cases/issues/212)
### 3.5.1 - python 3.10 compatibility + improved error message
- Fixed error message related to misuse of `fixture_ref`. Fixes [#209](https://github.com/smarie/python-pytest-cases/issues/209)
- Fixed import error with python 3.10. Fixes [#207](https://github.com/smarie/python-pytest-cases/issues/207)
### 3.5.0 - New `current_cases` fixture and `get_current_cases` function + Fixes
- New: Users can now easily access the current cases for each parametrized argument thanks to the new `current_cases` fixture. A new helper function `get_current_cases` is also provided, for direct access from a hook. `get_current_case_id` becomes deprecated in favour of these two. Fixes [#195](https://github.com/smarie/python-pytest-cases/issues/195)
- Bugfix: Fixed issue where the cache of a `lazy_value` used for a tuple of parameters (several `argnames`) was not considering the pytest context and thus was wrongly used across pytest nodes. Fixes [#202](https://github.com/smarie/python-pytest-cases/issues/202)
- Improved error message when a fixture parametrized with several argnames as once is not able to unpack the parameter values received (non subscriptable object).
- `parametrize_plus` and `fixture_plus` are now deprecated in favour of `parametrize` and `fixture`, as most users seem to have adopted these names without issues.
- (internal) Replaced the `"used"` parameter with a dedicated singleton `USED`
### 3.4.6 - Increased compatibility with other plugins
- `LazyValue`, `LazyTuple` and `LazyTupleItem` are now hashable. This increases compatibility with plugins hashing the parameter values, such as pytest-steps. See [pytest-steps#41](https://github.com/smarie/python-pytest-steps/issues/41) . Fixes [#199](https://github.com/smarie/python-pytest-cases/issues/199)
### 3.4.5 - Bugfix
- Fixed bug when a test module containing `@parametrize_with_cases` was executed outside of `pytest`, typically through its `__main__`. Fixes [#198](https://github.com/smarie/python-pytest-cases/issues/198)
### 3.4.4 - Bugfix
- Fixed issue when `@parametrize_with_cases` was used on a fixture in a `conftest.py`. Fixes [#196](https://github.com/smarie/python-pytest-cases/issues/196)
### 3.4.3 - Technical release - Zenodo
Technical release to check that Zenodo metadata is now preserved.
Same as 3.4.2, 3.4.1 and 3.4.0.
### 3.4.0 - Goodbye v1 API + Support for unbound cases + Bugfix with marks + Fixtures in case files
- Legacy v1 API was dropped. Fixes [#192](https://github.com/smarie/python-pytest-cases/issues/192)
- Unbound case functions in a class (e.g. `Foo.bar`) can now be directly passed to `parametrize_with_cases` without instantiating the class, e.g. `parametrize_with_cases(cases=Foo.bar)`. Fixes [#159](https://github.com/smarie/python-pytest-cases/issues/159)
- Fixed bug with concatenation of marks on cases. Fixes [#191](https://github.com/smarie/python-pytest-cases/issues/191)
- Fixed an issue where a case transformed into a fixture, with the same name as the fixture it requires, would lead to a `pytest` fixture recursion.
- Fixtures in case files can now be automatically imported using the **experimental** `@parametrize_with_cases(import_fixtures=True)`. Fixes [#193](https://github.com/smarie/python-pytest-cases/issues/193)
### 3.3.0 - Filter helpers, Current id getter, Support for `pytest-asyncio` and other plugins
- Migrated to Github Actions + `nox` for CI/CD.
- New helper function `get_current_case_id` to get the current case id for a given `pytest` request or item. Fixes [#189](https://github.com/smarie/python-pytest-cases/issues/189)
- Extended the support of fixture closure modifications to `remove` and `insert(0, f)`. This in particular solves an issue with `pytest-asyncio`. Fixes [#176](https://github.com/smarie/python-pytest-cases/issues/176)
- New `filters` module providing helper functions `has_tag`, `id_has_prefix`, `id_has_suffix`, `id_match_regex` to easily create custom filters for use in `@parametrize_with_cases(filter=...)`. PR [#184](https://github.com/smarie/python-pytest-cases/pull/184) by [@saroad2](https://github.com/saroad2), (thanks !).
### 3.2.1 - `@fixture` Bugfix
- Fixed `fixture 'self' not found` issue when `@fixture` was used to decorate a class method not explicitly depending on `request`. Fixed [#182](https://github.com/smarie/python-pytest-cases/issues/182)
### 3.2.0 - Automatic `fixture_ref` + test ordering bugfix
- New: from version `3.2` on, if `auto_refs=True` (default), `@parametrize` will automatically detect fixture symbols in the list of argvalues, and will create `fixture_ref`s automatically around them so that you don't need to. Fixes [#177](https://github.com/smarie/python-pytest-cases/issues/177)
- Fixed ordering issue happening on linux targets when several `@parametrize` are used to decorate the same function. Fixes [#180](https://github.com/smarie/python-pytest-cases/issues/180)
### 3.1.2 - Bugfixes with nesting and pytest-asyncio
- Now appending fixtures to the closure once it has been built is supported. This fixes an issue with `pytest-asyncio`. Fixes [#176](https://github.com/smarie/python-pytest-cases/issues/176)
- Fixed issue when `parametrize_with_cases` was used on case functions themselves (nesting/recursion). This was due to a lack of support of the `place_as` magic pytest attribute. Fixes [#179](https://github.com/smarie/python-pytest-cases/issues/179)
- Added a warning concerning usage of indirect in parametrize when fixture references are present. See [#150](https://github.com/smarie/python-pytest-cases/issues/150)
### 3.1.1 - Bugfix with ids
- Fixed issue with Empty id marker leaking to test ids. Fixed [#171](https://github.com/smarie/python-pytest-cases/issues/171)
### 3.1.0 - Improved cases collection
- `@parametrize_with_cases` now by default (`cases=AUTO`) looks for both file naming patterns `test__cases.py` and `cases_.py`. Removed the `AUTO2` constant. Fixed [#140](https://github.com/smarie/python-pytest-cases/issues/140)
- Nested classes containing case functions are now officially supported (they were, but undocumented). Fixed [#160](https://github.com/smarie/python-pytest-cases/issues/160)
- Case functions that are `staticmethod` and `classmethod` are now supported as well. Fixes [#168](https://github.com/smarie/python-pytest-cases/issues/168)
### 3.0.0 - harmonization of ids and public API for cases info
- Major refactoring of the way ids and marks are generated and customized in `fixture_union`, `@parametrize` and `@parametrize_with_cases`. Now `idstyle` has a consistent behaviour across the board, `ids` and `idstyle` can work together correctly, `@parametrize_with_cases` and `@parametrize` have much better default values for ids, and many others. See [documentation](./index.md) for details. Fixed [#154](https://github.com/smarie/python-pytest-cases/issues/154)
- New public API to manipulate information about a case function: `copy_case_info`, `set_case_id`, `get_case_id`, `get_case_marks`, `get_case_tags`, `matches_tag_query`, `is_case_class`, `is_case_function`. See [API reference](./api_reference.md).
- Fixed default behaviour of `idgen` in `@parametrize`: it only defaults to `AUTO` when no `fixture_ref` are used in the argvalues.
### 2.7.2 - Bugfix with doctest
- Fixed `AttributeError: 'DoctestItem' object has no attribute '_request'` when executing doctests. Fixes [#156](https://github.com/smarie/python-pytest-cases/issues/156)
### 2.7.1 - `@pytest.mark.usefixtures` can be used on case functions
- `@pytest.mark.usefixtures` can be now be used on case functions. Fixes [#152](https://github.com/smarie/python-pytest-cases/issues/152).
### 2.7.0 - `@parametrize_with_cases` now supports id customization
- `@parametrize_with_cases` now explicitly supports all id customization methods (`ids`, `idgen` and `idstyle`) supported by `@parametrize` (`ids`, `idgen` and `idstyle`). Updated documentation accordingly. Fixed [#151](https://github.com/smarie/python-pytest-cases/issues/151)
### 2.6.0 - better cache for lazy values and support for infinite id generators
- `lazy_value` parameters are now cached by pytest node id only. So plugins can access the value without triggering an extra function call, but a new call is triggered for each pytest node, so as to prevent mutable object leakage across tests. Fixed [#149](https://github.com/smarie/python-pytest-cases/issues/149) while ensuring no regression for [#143](https://github.com/smarie/python-pytest-cases/issues/143).
- The `ids` argument of `parametrize` now accepts a (possibly infinite) generator of ids, e.g. (`f"foo{i}" for i in itertools.count()`), just as `pytest` does. This was not always the case, inparticular when parametrizing a `@fixture`. The `ids` arguments of `fixture_union`, `param_fixture[s]`, etc. now also support this pattern. Fixed [#148](https://github.com/smarie/python-pytest-cases/issues/148)
### 2.5.0 - case ids `glob` match improvements
- Improved description for the `glob` argument in `@parametrize_with_cases`. Also made the implementation escape all regex special characters so that they can't be used. Finally a pattern should now match the entire case id (previously, a partial match would work if it was at the beginning of the string). One step towards [#147](https://github.com/smarie/python-pytest-cases/issues/147)
### 2.4.0 - various fixes for test ids and lazy values
- `is_lazy` is now part of public API, and `_LazyValue` now has a cache mechanism like `_LazyTuple`. Fixes [#143](https://github.com/smarie/python-pytest-cases/issues/143)
- `@parametrize`: custom `ids` are now correctly taken into account when a single `lazy_value`is used for a tuple of parameters. This issue could be seen also with `@parametrize_with_cases`: `idgen` does not seem to be taken into account when cases are unpacked into a tuple. Fixes [#144](https://github.com/smarie/python-pytest-cases/issues/144).
- Empty case ids are now replaced with `''` to avoid ambiguous interpretation of test ids. Fixes [#142](https://github.com/smarie/python-pytest-cases/issues/142).
### 2.3.0 - better `LazyValue` internal API
- new `clone(self, remove_int_base=False)` API on `LazyValue` and `LazyTupleItem` instances. With this new API, on old `pytest` `< 5.3`, other plugins such as `pytest-harvest` can easily clone the contents from lazy values without having them inherit from `int` - which was a dirty hack used by `pytest-cases` to trick `pytest` to generate acceptable test ids in these old pytest versions. Also improved the `LazyValue`, `LazyTuple` and `LazyTupleItem` object model with equality and repr. Fixes [pytest-harvest#43](https://github.com/smarie/python-pytest-harvest/issues/43)
### 2.2.5 - Marks are now correctly propagated from Case class
- Marks set on a case class are now propagated to cases in the class. So you can use for example [`pytest-pilot`](https://smarie.github.io/python-pytest-pilot/) more easily ! Fixes [#139](https://github.com/smarie/python-pytest-cases/issues/139)
### 2.2.4 - Fixes issue
- Fixed "Created fixture names are not unique, please report" error when duplicate fixture reference is provided in a pytest.param. Fixes [#138](https://github.com/smarie/python-pytest-cases/issues/138).
### 2.2.3 - Fixed issue with pytest `3.X`
- Fixed `TypeError: _idval() got an unexpected keyword argument 'item'` with `pytest` versions between 3.0.0 and 3.7.4. Fixed [#136](https://github.com/smarie/python-pytest-cases/issues/136)
### 2.2.2 - `@parametrize_with_cases` compatibility improvements
- `@parametrize_with_cases` now supports that `argnames` is a list or tuple, just as `@pytest.mark.parametrize` does. PR [#132](https://github.com/smarie/python-pytest-cases/pull/132), by [`@saroad2`](https://github.com/saroad2).
### 2.2.1 - setup.py fix to enforce dependency version
- Now enforcing usage of `makefun` 1.9.3 or above to avoid issue `AttributeError: 'functools.partial' object has no attribute '__module__'` mentioned in [#128](https://github.com/smarie/python-pytest-cases/issues/128)
### 2.2.0 - Doc improvements + bugfix for cases requiring fixtures
- Improved documentation to explain why `@fixture` should be used instead of `@pytest.fixture`. Fixed [#125](https://github.com/smarie/python-pytest-cases/issues/125)
- Fixed ` ValueError: fixture is being applied more than once to the same function` when two functions parametrized with the same cases were sitting in the same file. Improved robustness when cases require fixtures, in particular when parametrized test/fixture sits in a class or when several of them sit in a class/module. Fixed [#126](https://github.com/smarie/python-pytest-cases/issues/126)
### 2.1.3 - Missing deprecation warning
- Added missing deprecation warning on `@cases_generator`. Fixes [#124](https://github.com/smarie/python-pytest-cases/issues/124).
- Removed `target` and `tags` arguments of `@cases_generator` (deprecated api anyway) that were added by mistake in version 2.0.0 but never used.
### 2.1.2 - Compatibility fix
- Added support for pytest items without funcargs. Fixes interoperability with other pytest plugins such as `pytest-black` or `pytest-flake8`. Fixes [#122](https://github.com/smarie/python-pytest-cases/issues/122)
### 2.1.1 - Fixed issue with pytest 6
`pytest` 6 is now supported. Fixes [#121](https://github.com/smarie/python-pytest-cases/issues/121)
### 2.1.0 - Internal engine improvements + bugfixes
Fixed issue with `@parametrize_with_cases` when two cases with the same id and both requiring a fixture were to be created. Fixed [#117](https://github.com/smarie/python-pytest-cases/issues/117).
Fixture closure engine refactoring:
- When no fixture unions are present, the fixture closure is now identical to the default one in `pytest`, to avoid issues originating from other plugins fiddling with the closure. Fixes [#116](https://github.com/smarie/python-pytest-cases/issues/116)
- New `SuperClosure` class representing the "list" facade on top of the fixture tree (instead of `FixtureClosureNode`). In addition, this list facade now better handles editing the order of fixtures when possible. Fixes [#111](https://github.com/smarie/python-pytest-cases/issues/111).
- Session and Module-scoped fixtures that are not used in all union alternatives are not any more torn town/setup across union alternatives. Fixes [#120](https://github.com/smarie/python-pytest-cases/issues/120)
### 2.0.4 - Bugfix
- Fixed `TypeError` with iterable argvalue in standard parametrize. Fixed [#115](https://github.com/smarie/python-pytest-cases/issues/115).
### 2.0.3 - Bugfixes
- Fixed wrong module string decomposition when passed to `cases` argument in `@parametrize_with_cases`. Fixes [#113](https://github.com/smarie/python-pytest-cases/issues/113)
- Autouse fixtures are now correctly used. Fixed [#114](https://github.com/smarie/python-pytest-cases/issues/114)
### 2.0.2 - Better string representation for lazy values
Lazy values (so, test cases) now have a much nicer string representation ; in particular in `pytest-harvest` results tables. Fixes [#112](https://github.com/smarie/python-pytest-cases/issues/112)
### 2.0.1 - Better test ids and theory page
- New documentation page concerning theory of fixture unions. Fixes [#109](https://github.com/smarie/python-pytest-cases/issues/109)
- Using a `fixture_ref` in a new-style `@parametrize` (with `**args` or `idgen`) now outputs a correct id. Fixes [#110](https://github.com/smarie/python-pytest-cases/issues/110)
### 2.0.0 - Less boilerplate & full `pytest` alignment
I am very pleased to announce this new version of `pytest-cases`, providing a lot of **major** improvements. Creating powerful and complex test suites have never been so easy and intuitive !
Below is a complete list of changes, but the user guide has also been updated accordingly so feel free to [have a look](index.md) to get a complete example-based walkthrough.
**A/ More powerful and flexible cases collection**
New [`@parametrize_with_cases`](./api_reference.md#parametrize_with_cases) decorator to replace `@cases_data` (deprecated).
1. Aligned with `pytest`:
- now `argnames` can contain several names, and the case functions are **automatically unpacked** into it. You don't need to perform a `case.get()` in the test anymore !
@parametrize_with_cases("a,b")
def test_foo(a, b):
# use a and b directly !
...
- cases are unpacked at test *setup* time, so *the clock does not run while the case is created* - in case you use `pytest-harvest` to collect the timings.
- `@parametrize_with_cases` can be used on test functions *as well as fixture functions* (it was already the case in v1)
2. Easier to configure:
- the decorator now has a single `cases` argument to indicate the cases, wherever they come from (no `module` argument anymore)
- default (`cases=AUTO`) *automatically looks for cases in the associated case module* named `test_xxx_cases.py`. Users can easily switch to alternate pattern `cases_xxx.py` with `cases=AUTO2`. Fixes [#91](https://github.com/smarie/python-pytest-cases/issues/91).
- **cases can sit inside a class**, like [what you're used to do with `pytest`](https://docs.pytest.org/en/stable/getting-started.html#group-multiple-tests-in-a-class). This additional style makes it much more convenient to organize cases and associated them with tests, when cases sit in the same file than the tests. Fixes [#93](https://github.com/smarie/python-pytest-cases/issues/93).
- an explicit sequence can be provided, *it can mix all kind of sources*: functions, classes, modules, and *module names as strings* (even relative ones!).
@parametrize_with_cases("a", cases=(CasesClass, '.my_extra_cases'))
def test_foo(a):
...
3. More powerful API for filtering:
- a new `prefix` argument (default `case_`) can be used to define case functions for various type of parameters: welcome `user_`, `data_`, `algo_`, `model_` ! Fixes [#108](https://github.com/smarie/python-pytest-cases/issues/108)
- a new `glob` argument receiving a glob-like string can be used to further filter cases based on their names. For example you can distinguish `*_success` from `*_failure` case ids, so as to dispatch them to the appropriate positive or negative test. Fixes [#108](https://github.com/smarie/python-pytest-cases/issues/108)
- finally you can still use `has_tag` and/or provide a `filter` callable, but now the callable will receive the case function, and this case function has a `f._pytestcase` attribute containing the id, tags and marks - it is therefore much easier to implement custom filtering.
**B/ Easier-to-define case functions**
- Case functions can start with different prefixes to denote different kind of data: e.g. `data_`, `user_`, `model_`, etc.
- Case functions can now be parametrized with [`@parametrize`](pytest_goodies.md#parametrize) or `@pytest.mark.parametrize`, just as in pytest ! This includes the ability to put [`pytest` marks](https://docs.pytest.org/en/stable/mark.html) on the whole case, or on some specific parameter values using [`pytest.param`](https://docs.pytest.org/en/stable/example/parametrize.html#set-marks-or-test-id-for-individual-parametrized-test). `@cases_generator` is therefore now deprecated but its alternate style for ids and arguments definition was preserved in `@parametrize`, see below.
- Now case functions can require fixtures ! In that case they will be transformed into fixtures and injected as `fixture_ref` in the parametrization. Fixes [#56](https://github.com/smarie/python-pytest-cases/issues/56).
- New single optional `@case(id=None, tags=(), marks=())` decorator to replace `@case_name` and `@case_tags` (deprecated): a single simple way to customize all aspects of a case function. Also, `@test_target` completely disappears from the picture as it was just a tag like others - this could be misleading.
**C/ Misc / pytest goodies**
- New aliases for readability: `@fixture` for `@fixture_plus`, and`@parametrize` for `@parametrize_plus` (both aliases will coexist with the old names). Fixes [#107](https://github.com/smarie/python-pytest-cases/issues/107).
- `@parametrize` was improved in order to support the alternate parametrization mode that was previously offered by `@cases_generator`, see [api reference](api_reference.md#parametrize). That way, users will be able to choose the style of their choice. Fixes [#57](https://github.com/smarie/python-pytest-cases/issues/57) and [#106](https://github.com/smarie/python-pytest-cases/issues/106).
- `@parametrize` now raises an explicit error message when the user makes a mistake with the argnames. Fixes [#105](https://github.com/smarie/python-pytest-cases/issues/105).
- More readable error messages in `@parametrize` when `lazy_value` does not return the same number of argvalues than expected from the argnames.
- Any error message associated to a `lazy_value` function call is not caught and hidden anymore but is emitted to the user, for easier debugging.
- Fixed issue with `lazy_value` when a single mark is passed in the constructor.
- `lazy_value` used as a tuple for several arguments now have a correct id generated even in old pytest version 2.
- New pytest goodie `assert_exception` that can be used as a context manager. Fixes [#104](https://github.com/smarie/python-pytest-cases/issues/104).
### 1.17.0 - `lazy_value` improvements + annoying warnings suppression
- `lazy_value` are now resolved at pytest `setup` stage, not pytest `call` stage. This is important for execution time recorded in the reports (see also `pytest-harvest` plugin). Fixes [#102](https://github.com/smarie/python-pytest-cases/issues/102)
- A function used as a `lazy_value` can now be marked with pytest marks. Fixes [#99](https://github.com/smarie/python-pytest-cases/issues/99)
- A `lazy_value` now has a nicer id when it is a partial. Fixes [#97](https://github.com/smarie/python-pytest-cases/issues/97)
- Removed annoying `PytestUnknownMarkWarning` warning message when a mark was used on a case. Fixes [#100](https://github.com/smarie/python-pytest-cases/issues/100)
### 1.16.0 - New `lazy_value` for parameters
- New marker `lazy_value` for `parametrize_plus`. Fixes [#92](https://github.com/smarie/python-pytest-cases/issues/92)
### 1.15.0 - better `parametrize_plus` and smaller dependencies
- Better support for `pytest.param` in `parametrize_plus` and also in `fixture_union` and `fixture_param[s]`. Improved corresponding ids. Fixed [#79](https://github.com/smarie/python-pytest-cases/issues/79) and [#86](https://github.com/smarie/python-pytest-cases/issues/86)
- New `@ignore_unused` decorator to protect a fixture function from the "NOT_USED" case happening when the fixture is used in a fixture union.
- Removed `six`, `wrapt` and `enum34` dependencies
- (Internal) submodules reorganization for readability
- (Internal) suppressed a lot of code quality warnings
### 1.14.0 - bugfixes and hook feature
- Fixed `ids` precedence order when using `pytest.mark.parametrize` in a `fixture_plus`. Fixed [#87](https://github.com/smarie/python-pytest-cases/issues/87)
- Fixed issue with `fixture_union` when using the same fixture twice in it. Fixes [#85](https://github.com/smarie/python-pytest-cases/issues/85)
- Added the possibility to pass a `hook` function in all API where fixtures are created behind the scenes, so as to ease debugging and/or save fixtures (with `stored_fixture` from pytest harvest). Fixes [#83](https://github.com/smarie/python-pytest-cases/issues/83)
- Fixture closures now support reordering when no unions are present. This suppressed the annoying warning "WARNING the new order is not taken into account !!" when it was not relevant. Fixes [#81](https://github.com/smarie/python-pytest-cases/issues/81)
### 1.13.1 - packaging improvements
- packaging improvements: set the "universal wheel" flag to 1, and cleaned up the `setup.py`. In particular removed dependency to `six` for setup and added `py.typed` file. Fixes [#78](https://github.com/smarie/python-pytest-cases/issues/78)
### 1.13.0 - `@cases_generator` default `names`
`@cases_generator` now has a default value for the `names` template, based on the parameters. Fixes [#77](https://github.com/smarie/python-pytest-cases/issues/77).
### 1.12.4 - Bugfix
Fixed `ValueError` when a product of unions was used on a test node, for example when two `parametrize_plus` using `fixture_ref`s were used on the same fixture or test function. Fixed [#76](https://github.com/smarie/python-pytest-cases/issues/76)
### 1.12.3 - Improved error messages
Improved error message when something that is not a fixture is used in `unpack_fixture` or `fixture_union`. Fixed [#75](https://github.com/smarie/python-pytest-cases/issues/75)
### 1.12.2 - Warning fix
Fixed deprecation warning [#74](https://github.com/smarie/python-pytest-cases/issues/74)
### 1.12.1 - Bugfixes
- Now using module name and not file path to detect symbols in cases files that are imported from elsewhere and not created locally. Indeed that was causing problems on some ^platforms where a `.pyc` cache file is created. Fixes [#72](https://github.com/smarie/python-pytest-cases/issues/72)
- Fixed `PluginValidationError` when `pytest_fixture_plus` or `pytest_parametrize_plus` were used in a `conftest.py` file. Fixes [#71](https://github.com/smarie/python-pytest-cases/issues/71). According to discussion in [pytest#6475](https://github.com/pytest-dev/pytest/issues/6475), `pytest_fixture_plus` and `pytest_parametrize_plus` are now renamed to `fixture_plus` and `parametrize_plus` in order for pytest (pluggy) not to think they are hooks. Old aliases will stay around for a few versions, with a deprecation warning.
### 1.12.0 - better test ids for parametrized tests with fixture refs + bugfix
- Improved test ids for the cases where `fixture_ref` is used in the parameters list in `@pytest_parametrize_plus`. Fixed [#69](https://github.com/smarie/python-pytest-cases/issues/69). Thanks [`last-partizan`](https://github.com/last-partizan) for the suggestion !
- Fixed `TypeError: got an unexpected keyword argument 'indirect'` with `pytest` 5+. Fixed [#70](https://github.com/smarie/python-pytest-cases/issues/70).
### 1.11.9 - bugfix
`FixtureClosureNode` is now able to properly handle `ignore_args`, and now supports that plugins append fixtures to the closure, such as pytest-asyncio. Added corresponding tests. Fixes [#68](https://github.com/smarie/python-pytest-cases/issues/68)
### 1.11.8 - bugfix
Fixed `KeyError` issue happening when a fixture is not found. Now users will see the "normal" error message from pytest (`"fixture not found"`). Fixed [#67](https://github.com/smarie/python-pytest-cases/issues/67).
### 1.11.7 - bugfix
Fixed `ValueError` issue happening with indirectly parametrized fixtures. Fixed [#64](https://github.com/smarie/python-pytest-cases/issues/64).
### 1.11.6 - pyproject.toml
[raddessi](https://github.com/raddessi) added a `pyproject.toml` - thanks! Fixed [#65](https://github.com/smarie/python-pytest-cases/issues/65).
### 1.11.5 - bugfix
`pytest_parametrize_plus` was not working correctly with test classes, leading to `fixture 'self' not found`. Fixed [#63](https://github.com/smarie/python-pytest-cases/issues/63).
### 1.11.4 - python 2 bugfix
Fixed issue happening with `@pytest.mark.parametrize` with python 2. Fixed [#62](https://github.com/smarie/python-pytest-cases/issues/62).
### 1.11.3 - minor improvements
Better error message when users use `THIS_MODULE` in `cases=` instead of `module=`.
Added `__version__` package-level attribute.
### 1.11.2 - Increased tolerance to other plugins + bugfix
Now when other plugins try to manipulate the fixture closure, warning messages are emitted but no error is raised. Fixed [#55](https://github.com/smarie/python-pytest-cases/issues/55).
Also fixed issue [#58](https://github.com/smarie/python-pytest-cases/issues/58) happening with doctest.
### 1.11.1 - Added `six` dependency explicitly
It was missing from `setup.py`.
### 1.11.0 - `fixture_ref` can now be used inside tuples, leading to cross-products
Fixes [#47](https://github.com/smarie/python-pytest-cases/issues/47).
### 1.10.2 - More intuitive error messages
Now raising an explicit `InvalidParamsList` when pytest parametrize `argvalues` are incorrect. See [#54](https://github.com/smarie/python-pytest-cases/issues/54)
### 1.10.1 - Bugfix
Fixed [#52](https://github.com/smarie/python-pytest-cases/issues/52).
### 1.10.0 - New feature: fixtures unpacking
You can now unpack a fixture iterable into several individual fixtures using `unpack_fixture` or using `@pytest_fixture_plus(unpack_into=)`. This is also available in `union_fixture(unpack_into=)`. Fixed [#50](https://github.com/smarie/python-pytest-cases/issues/50) and [#51](https://github.com/smarie/python-pytest-cases/issues/51).
### 1.9.3 - Bugfix
Fixed issues when parametrize argnames contains a list. This fixed [#49](https://github.com/smarie/python-pytest-cases/issues/49)
### 1.9.2 - Bugfix with pytest 3.7
Fixed [#48](https://github.com/smarie/python-pytest-cases/issues/48).
### 1.9.1 - Bugfix with pytest 3.7
Fixed [#48](https://github.com/smarie/python-pytest-cases/issues/48).
### 1.9.0 - New `--with-reorder` commandline option
New commandline option '--with-reorder' to change the reordering strategy currently in application. Fixes [#45](https://github.com/smarie/python-pytest-cases/issues/45).
The `--with-reorder` "skip" mode was not working correctly in presence of marks, fixed it. Fixed [#46](https://github.com/smarie/python-pytest-cases/issues/46).
### 1.8.1 - BugFixes
Ids should not be used when setting a NOT_USED parametrization. Fixes [#43](https://github.com/smarie/python-pytest-cases/issues/43)
Fixed issue with ordering and setup/teardown for higher-level scope fixtures (session and module scopes) when using union fixtures. Fixes [#44](https://github.com/smarie/python-pytest-cases/issues/44)
### 1.8.0 - Better ids for fixture unions
New:
- `fixture_union` now accept a non-`None` value for `ids`. It also has a new `idstyle` argument allowing users to change the style of ids used. Finally `pytest_parametrize_plus` relies on this `ids` argument to set a more readable list of ids for the created union. Fixes [#41](https://github.com/smarie/python-pytest-cases/issues/41).
Misc:
- Added non-regression test for fixture order. It passes already for all recent pytest versions (after 3.3). Fixes [#42](https://github.com/smarie/python-pytest-cases/issues/42)
### 1.7.0 - New `@pytest_parametrize_plus` allowing fixture references to be used in parameter values
New decorator `@pytest_parametrize_plus` able to handle the case where a `fixture_ref()` is present in the parameter values list. This decorator can be applied both on test functions and fixtures (if they are decorated with `@pytest_fixture_plus`). Fixes [#40](https://github.com/smarie/python-pytest-cases/issues/40)
Major refactoring of the "union fixtures" mechanism.
- The `NOT_USED` status is now correctly propagated between dependent fixtures. This should fix a few cases where user fixtures were setup/teardown while not used in the current test node.
- Empty fixture unions are not permitted anymore.
- The way unions are handled in test parametrization was redesigned. The new design is based on a two-steps approach: first build the fixture closure for each node as a tree (and not a list as in `pytest`), and then apply parametrization intelligently based on this tree structure. This fixes several unintuitive behaviours that were happening with unions.
Note: interestingly this also fixes [pytest#5054](https://github.com/pytest-dev/pytest/issues/5054).
### 1.6.3 - Minor exception enhancement
Improved the error message when the name template is wrong in `@cases_generator`. Fixes [#39](https://github.com/smarie/python-pytest-cases/issues/39).
### 1.6.2 - bug fixes
`fixture_union`:
* Changed the repr of `NOT_USED` to `pytest_cases.NOT_USED`.
* `@pytest_fixture_plus` now correctly handles the `NOT_USED` when fixtures in the union do not contain any parameter. Fixes [#38](https://github.com/smarie/python-pytest-cases/issues/38).
`param_fixtures`:
* `param_fixtures` now delegates to `param_fixture` when a single parameter name is provided. This is more consistent. Fixed [#36](https://github.com/smarie/python-pytest-cases/issues/36).
* `param_fixture[s]` now support all arguments from `fixture` (`scope` and `autouse` in particular).
### 1.6.1 - `@pytest_fixture_plus` improvement to handle `NOT_USED` cases
Fixed issue where fixtures get called with `NOT_USED` as a parameter when using a `fixture_union`. This issue is actually only fixed in `@pytest_fixture_plus`, if you use `@pytest.fixture` you have to handle it manually. Fixes [#37](https://github.com/smarie/python-pytest-cases/issues/37).
### 1.6.0 - `fixture_union` and `param_fixture[s]` bugfix
New `fixture_union` method to create a fixture that is the union/combination of other fixtures. This is an attempt to solve [this pytest proposal](https://docs.pytest.org/en/latest/proposals/parametrize_with_fixtures.html).
Also, `param_fixture` and `param_fixtures` can now be used without necessarily storing the return value into a variable: they will automatically register the created fixtures in the calling module.
Finally, fixed a bug with `param_fixtures` when called to create a fixture for a single parameter.
### 1.5.1 - `param_fixtures` bugfix
Fixed `param_fixtures` issue: all parameter values were identical to the last parameter of the tuple. Fixes [#32](https://github.com/smarie/python-pytest-cases/issues/32).
### 1.5.0 - new helpers `param_fixture` and `param_fixtures`
Following [Sup3rGeo](https://github.com/Sup3rGeo)'s proposal, introduced two helper methods to create simple "parameter fixtures". Fixes [#31](https://github.com/smarie/python-pytest-cases/issues/31).
### 1.4.2 - parametrized `@pytest_fixture_plus` minor bug fix
`@pytest_fixture_plus` now correctly honors parameter id and marks overridden at single parameter level using `pytest.param`. Fixed [#30](https://github.com/smarie/python-pytest-cases/issues/30).
### 1.4.1 - parametrized `@pytest_fixture_plus` minor bug fix
Fixed `@pytest_fixture_plus` in case it is used with `parametrize` and one parameter is itself customized using `pytest.param`. Fixed [#29](https://github.com/smarie/python-pytest-cases/issues/29).
### 1.4.0 - `@pytest_fixture_plus` major improvement
* Major improvement of `@pytest_fixture_plus`: instead of generating fixtures, it now correctly parametrizes the fixture. Skip/fail Marks are correctly copied too. Fixes [#28](https://github.com/smarie/python-pytest-cases/issues/28).
* `pytest_fixture_plus` does not accept the `params` and `ids` arguments any more, it only relies on parametrization marks.
### 1.3.3 - parametrized `@pytest_fixture_plus` Bugfix
Fixed minor bug with parametrized `@pytest_fixture_plus`: spaces are now correctly removed when multiple parameter names are provided in the same `parametrize` call. Fixes [#27](https://github.com/smarie/python-pytest-cases/issues/27).
### 1.3.2 - parametrized `@pytest_fixture_plus` Bugfix
Fixed bug with `@pytest_fixture_plus` when used in parametrized mode. Fixes [#26](https://github.com/smarie/python-pytest-cases/issues/26). Thanks [Sup3rGeo](https://github.com/Sup3rGeo)!
### 1.3.1 - Minor dependency change
Now using `decopatch` to create the decorators.
### 1.3.0 - More flexible case generators names + Minor dependency change
Cases generators can now support explicit name lists, and name generator callables, in addition to the name template strings. Fixed [#24](https://github.com/smarie/python-pytest-cases/issues/24).
Dependency to `decorator` has been dropped and replaced with `makefun`. Fixed [#25](https://github.com/smarie/python-pytest-cases/issues/25).
### 1.2.2 - fixed bug with marks on cases with pytest 3.3
Marks on cases are now also working with pytest 3.3. Fixed [#23](https://github.com/smarie/python-pytest-cases/issues/23).
Ids for marked tests are now better managed. A new function `get_pytest_parametrize_args` is now used to transform the list of cases obtained by `get_all_cases(module)`, into the list of marked cases and ids required by `@pytest.mark.parametrize`. The doc has been updated to explain this for advanced users wishing to perform this step manually.
### 1.2.1 - fixed id of test cases with marks
Id of test cases with marks was appearing as `ParameterSet`. Fixed it.
### 1.2.0 - @pytest.mark can be used on cases + @pytest_fixture_plus parametrization order bugfix
Pytest marks such as `@pytest.mark.skipif` can now be used on case functions. As a consequence, `get_all_cases` is now the recommended function to use instead of `extract_cases_from_module` to perform manual collection. Indeed `get_all_cases` correctly prepares the resulting parameters list so that pytest sees the marks. Fixed [#21](https://github.com/smarie/python-pytest-cases/issues/21).
Fixed parametrization order when `@pytest_fixture_plus` is used with several `@pytest.mark.parametrize`. Fixed [#22](https://github.com/smarie/python-pytest-cases/issues/22).
### 1.1.1 - Improved generated fixture names for `@pytest_fixture_plus`
When `@pytest_fixture_plus` is used on a function marked as parametrized, some fixtures are generated (one for each parameter). Generated fixture names now follow the pattern `__`.
Fixed [#20](https://github.com/smarie/python-pytest-cases/issues/20).
### 1.1.0 - New `@pytest_fixture_plus`
New decorator `@pytest_fixture_plus` allows to use several `@pytest.mark.parametrize` on a fixture. Therefore one can use multiple `@cases_data` decorators, too. Fixes [#19](https://github.com/smarie/python-pytest-cases/issues/19).
*Note: this is a temporary feature, that will be removed if/when [pytest supports it](https://github.com/pytest-dev/pytest/issues/3960).*
### 1.0.0 - `@cases_fixture` + pytest 2.x support
Pytest 2.x is now supported. Fixes [#14](https://github.com/smarie/python-pytest-cases/issues/14).
**New feature:** `@cases_fixture` ! Now you can put your cases data retrieval in a fixture so that its duration does not enter into the test duration. This is particularly interesting if you use [pytest-harvest](https://smarie.github.io/python-pytest-harvest/) to create benchmarks: you probably do not want the case data retrieval/parsing to be counted in the test duration, especially if you use caching on the case function to accelerate subsequent retrievals. Fixes [#15](https://github.com/smarie/python-pytest-cases/issues/15).
### 0.10.1 - minor encoding issue in setup.py
### 0.10.0 - support for python 2
Python 2 is now supported. Fixed [#3](https://github.com/smarie/python-pytest-cases/issues/3).
- Note: `CaseData`, `Given`, `ExpectedNormal`, `ExpectedError`, and `MultipleStepsCaseData` type hints is not created in python 2 and python<3.5
### 0.9.1 - pytest-steps is now an independent project
* Light refactoring: some internal function names are now private, and there are now two submodules.
* [pytest-steps](https://smarie.github.io/python-pytest-steps/) is now an independent project. Examples in the documentation have been updated
* New documentation page: API reference
### 0.8.0 - Filtering can now be done using a callable.
* `@cases_data`: the `filter` argument now contains a filtering function. WARNING: the previous behaviour is still available but has been renamed `has_tag`. Fixes [#8](https://github.com/smarie/python-pytest-cases/issues/8).
### 0.7.0 - Hardcoded cases selection, and multi-module selection
* `@cases_data` has a new parameters `cases` that can be used to hardcode a case or a list of cases. Its `module` parameter can also now take a list of modules
### 0.6.0 - Case parameters and better test suites
* `get_for` is deprecated: it was too specific to a given case data format.
* `MultipleStepsCaseData` was fixed to also support multiple inputs.
* Case functions can now have parameters (even case generators). This is particularly useful for test suites. Fixes [#9](https://github.com/smarie/python-pytest-cases/issues/9).
### 0.5.0 - support for test suites
* test functions can now be decorated with `@test_steps` to easily define a test suite with several steps. This fixes [#7](https://github.com/smarie/python-pytest-cases/issues/7).
### 0.4.0 - support for data caching with lru_cache
* cases can now be decorated with `@lru_cache`. `@cases_generator` also provides a `lru_cache` parameter to enable caching. Fixes [#6](https://github.com/smarie/python-pytest-cases/issues/6).
### 0.3.0 - case generators
* New decorator `@cases_generator` to define case generators. Fixes [#1](https://github.com/smarie/python-pytest-cases/issues/1).
* Also, removed unused functions `is_expected_error_instance` and `assert_exception_equal`
### 0.2.0 - THIS_MODULE constant + Tagging/Filtering + doc
* New constant `THIS_MODULE` so that cases and test functions can coexist in the same file. This fixes [#5](https://github.com/smarie/python-pytest-cases/issues/5).
* Added `@test_target` and `@case_tags` decorators for case functions, and added `filter` parameter in `@cases_data`. This allows users to :
* tag a case function with any item (and in particular with the reference to the function it relates to),
* and to filter the case functions used by a test function according to a particular tag.
This fixes [#4](https://github.com/smarie/python-pytest-cases/issues/4).
* Improved documentation
### 0.1.0 - First public version
* Initial fork from private repo
python-pytest-cases-3.10.1/docs/examples.md 0000664 0000000 0000000 00000000702 15151413152 0020624 0 ustar 00root root 0000000 0000000 # Examples
Our examples are hosted in a separate repository so that they can be updated independently.
* [data science benchmark](https://smarie.github.io/pytest-patterns/examples/data_science_benchmark/) demonstrates how `pytest` can be used as a benchmarking engine thanks to `pytest-cases` and `pytest-harvest`, to compare the performances of several regression algorithms on several datasets and produce various reports (plots, csv table...).
python-pytest-cases-3.10.1/docs/imgs/ 0000775 0000000 0000000 00000000000 15151413152 0017424 5 ustar 00root root 0000000 0000000 python-pytest-cases-3.10.1/docs/imgs/0_bench_plots_example.png 0000664 0000000 0000000 00000072767 15151413152 0024407 0 ustar 00root root 0000000 0000000 PNG
IHDR Į S° sRGB ®Īé gAMA ±üa pHYs t tŽfx uIDATx^ķŻTåŁ’ńWPQ±F£Q°Qģ-ŲĮ5ö%h4@^F#jĄ®Ń$ĘÄ»ŃÄ(Ųb°bEADc¬ÆĘ(F}ž’ß½ēlĪĻĪĪīÜĆĢ9ūż\×}±3³{ĪģüĪsó’ @'C @§C @§C @§C @§C @§C @§C @§C @§C. ƾś*Ģ5+|ōŃGį’žļ’(¢(¢
]Ź<Ź>Ź@"6’ł’”(¢(źT„T)Bpio(Żb{KEQEQEŖt PØRąŅĘ
A’ ]G²!øĮ 3!Ć @gB! ĪSÉšõ×_/¾ų"|öŁgEĶŅėMÆ; ?B0L[Ā9sĀ3Ā“iÓ(„×^ _`r~ńÅĆ+ƼbĖüūß’ZQåWzéõ¦×^ķYĢ Š6B0L¹
AoČśōÓO{ Ģ+zŻéõ§×! Ą!¦Ģ00ļńśŚ ĆĘÄė jCw^żuėõŌ©S{:fŠ AaÄÉzõź~żė_'·P¼ž 6Į0ąyöąõ µA!Ļ;=łå¬tмž 6Į0`
z§~zXuÕUC·nŻĀ+®ĘÓoŗé¦°ÕV[
Z(¬³Ī:aŹ)ÉWšŽ{ļ
żöŪ/¬°Ā
öųZk®¹ęäŃ&m
`-Æuč”eY&,ŗč¢aė·O=õTņh£Gė®»nøņŹ+ķk[l±šżļ?|üńĒÉgūų/¼pXn¹å¹ē;×ĻÕ¶G}tX~łåķóxąäŃ.»ģ²Š³gĻpūķ·žżū.]ŗ×^{-ymįõ µA!ū;ęcĀK,.æüņšź«Æz(7®9÷ė×/üłĻ/½ōRųŽ÷¾gAō?’ł}ķo¾Ī:ė,->}zųĶo~cįńŃGµĒ„\ÖUĘ6ß|ó°ė®»'x"¼üņĖįČ#K-µTx’ż÷ķsYd°×^{
g}6L4Éī/~ń{\9äū¾÷Ž{Æ}Ī{īi:ūs7Ūl3ūzż?õ{wļŽŻ~¦(wķŚÕ>gņäɶęķæžõ/{mćõ µA!ūŅŖ Bo©4_zé„É=!<’üóvß/¼Ü3·vŚÉlŖ\¾ļ¾ūld÷óĻ?·Ū)J_|ńÅö±B°Fn³#æŃŻxćķcŻÆšzĆ
7ŲmŃč²¾&ż¹
½óĶ7_={¶ŻNm»ķ¶įøć³õĖB£r¼ž 6Į0`_=öõ3vŲ?
Į?žxrO|šŻ7qāD»y³:±öŚk%\2ōčŃ#,°Ąa}ö±Ē„\>óĢ3ĆüóĻo_-ݧjQ^c5ģć¦;¬¼ņŹö±B«~§3gŚķŌśėÆßüsÆæžzūŅ£ßuß}÷µĻQÖtN£żxżØFÆc’\ÓŹ3B0!Ų×3ϱ¾®“Ž}÷]ūtNp¾^ßGōūéwzć7ģvj½õÖkž¹&L°iéeµ³õöŪoŪē¤sŃ1¼ž T#\=+ĻĮ0`_źNh+7¢\Že]ĀĮlN²ėÓ§OÅ!ų{ī±pŖÕ¶Bp:āĘo“Ū¢ķC#½éĻÕ|fżŽÜBpuxżØF,øzVaĮžN:é$;1ī+®°¹³<ņĶ®$9ŅVŠdź½NPÓßJC°¦l±Årļŗė.ūś^Ǽ('m
`ŃĻÕōūļæ?<÷Üsaļ½÷¶ćōū„<šĄŠ»wo[ķB#ßę”čæüå/ö8!ø:¼ž T#\=+ĻĮ0`½Õ¼^
JØ®“ŅJįŌSO(k^Žšo|#pĀ į?üaÅ!X4{ÄGŲŅeśł
Õ
¬éōJB°¾GéiZmŌØQÉgšÅ_O<Ѱ~>O«HhJ«Ćė@5bĮÕ³ņCF%““mveŌÆ? ÕWĻŹ3B0!1’ūßķ"ĪńäOŚH“Bpzrj×jÄ«gå!
ą
6ŲĄNÓüęķ¶Ū®yę
^ Ŗ®g`B0ŠxżØF,øzVaĮ@cāõ ±ąźYyF!×jÄ«gå!4&^ Ŗ®g`B0ŠxżØF,øzVaĮ@cāõ ±ąźYyFnP\p]«{÷ī¶DÕ¤IGātűĆ?ܮքÆéׯ_óek+AÆ? ÕWĻŹ3Bp0a]~vÜøqöę§KćjÖ3g&ŃŅ9sĀFmvŚi§ššĆ3fz(<õŌSÉg“\lzno¹åäVŪ>żōÓ°×^{
E]Ō¾V;Y„e.gĖ-·W_}ur+®½æSŃÜ~ūķa½õÖ³ĖkĆė@5bĮÕ³ņÜÜj¢ŻQ£F%·ZŗšĀĆ*«¬¾ųāäöėh½ jU1dČūvŚiÉ=M¾t(|źwU-“ŠBaĶ5×]tQņheōµķ æ’żļĆ2Ė,}öŁšöŪoÆæž:üó’“pjķ{*ܾśźm»öžNy3|ųp;Ó[·°īŗė&÷¶“žśė«®ŗ*¹GPŲū©gå!øĮhT·K.įęoNīi¢7Ō&·Zśīwæ<šĄpč”o|ćƾüņĖä3ęöłēŪÖ¬Y³ZŻņ\pĮ°ųā>ų ¹7!ųSN±0śŹ+Æć?Ž~w1ØT{ēGŁźöjķ{~ē;ß §zjr«uķż:BƧz9ā#Āļ~÷»0xšąVCšo~óŪé- ±÷SĻŹ3e½Å²OkĮ54{öl{B&OÜÓD”¶O>Éśöķkó>ųąš·æż-\{ķµaÉ%'|rņs=z“żŅ*bŽe]l$żč£NīmÕŅ¢Ćž
)}Żw߯ķhōģŁ3tŅIį?’łO8ꨣģĀ+¬°B?~|ņ!¼žśėö3ō|lŗé¦ö±Ęį°Ē5ŗŗźŖ«³Ī:Ėn§4ś:ß|ó
W_}ÕnǦ!h¤uæżöKn5Üźh¦Ńh;¹ņŹ+Gč÷HēÖ[o~śÓŚĒ©÷Ž{ĻF,ļ»ļ¾0hŠ ęķA„Ūż=²£ÓŖ“Wļ¾ū®żīĻ=÷ŻN½üņĖ6EB=čßæøē{ģė²!ųĶ7ßūķ°hūŻm·Ż¬)õZĮR½×ćĒsLųįhĻKJ櫞o?’łĻĆRK-Õä?śč#ŪIŌ趦xØ„Ó
n»ķ6¹ÕļøņŹ+7?æÕm_)M]R¦OÜ37B0jÄŽO=+ĻĮ
&
ĮS¦LIīi2fĢ»1
D+®øbßsĪ9ĒNkMg VHŅČŗFõ’`
'¬_|ŃĀ®¾~v°`¬÷«_żŹBčo¼a_ąo}ė[įĘo“rČ!ö}:E_«`„
ąµ×^;ģ½÷Žö±žoś¹:ņ„^²ē^Gīæ’~{\ō{¤Ssuڵ
¤Ī?’|;SĮüż÷ß·ĄØą®ŃgŻģś]v}n~ęÆg§BčćµÖZ+lµÕVaźŌ©aāÄ6
ū;i
¶cķČ=óĢ3Ö«8Ą¶łt4WÆ
_ż_xį2“ŲbĶYdŪįŃó¤ĻÓ’ióĶ7»īŗkxā'ģ¹ŅH·Brś»ė®»ģ{]~łåHŅÕįŌ;īh’·rS.vŖōs[CPŲū©gå2Žb٧5ąźČtŻæķ¶Ū&·ÜqĒöÄVz8øÜP,l²
,éHÖķløS@ÓčfJ;!
Bł4~śév[4²ØP|ĘgŲķ·ŽzĖļĒ{Ģnk^·F+³”(>õõ
ś¾żĶ6ŪĢBkÖ>ūģc'J¦ōłiąTųU¼īŗėģ¶čląÓÉépŖ4gægJkD:ėī»ļ¶’cŗ"wŽygÆ×N
ś©ĄŅ¶«9ŠśzYvŁe[«ß+“Ņ\!X’,n+ąfCæhžā/¶õ<NįŠ\Żo~óɦjMG)W1m
`ķd{_ ±÷SĻŹ3BpŅĮaĆ%·črk'ĘwÜqs“óĪ;ÆÅx[:CÖ¤ĀŲóĻ?ß”
¢-K„P¦QUIC°~nÖ{ģ~ō£%·ö?ģ°Ćģcķüh¤8{~MUPĄ^`ĀĀ/l#éóQŻŅD=’:¤ŹNŃNF±E£³Ā Có©`ÉŅķŅßE4=!ūõź£ģØŖJæĀ~śł„½ÜsĻ=ē
ĮmĻ:óĢ3ĆüóĻ?×÷Ö}R!ź©d×mżĢģsŃm
`ķĤæG!@5bļ§gą.¦Ń1½ł9ŅŽÓ¢m²Xßuųg?ū’ó’lXuųøR!¬ngC°ęNƳĪ:öqJĮ©4gæ(p),feb¹|ŠA%·ę¢jėæ’żo;d_āō=u2F5]&;Z*
ĮW\qEr«Ié¬~l`Õ
@ĪjķvŪm<Ҥ£!ųK.kēK_SÓķ-żzMmŠĪ_éČŖJ8
Į„ėe«„!øō9ŃH¼ękǾ·ę0ÆFēcīlŌj:ę«ĪĻ"ØFģżŌ³ņÜ 4æS”C#:Y'¤ōFÆP„9Äo¼±Ō£šÓÖź„:K~śé§-üi$U’_ŃH£v²įRóQ½Bp:õA4Aó·³÷éyZ~łåm.ÆFzKēĻRMŲyē[ńĄŖŠyā'ŚÜŲk®¹&¹·I%!X;jė„9·½Ķ®ÄNPOinöwRxV/÷HÓ!Ī>ūģäVSßō;µ5æW?_ĻGkŌĆtŖLkj1BÆ)õńŽ{ļMī!@5bļ§g`ĪE#éé”nŃ’MĮM#ZAĖZ)y
`MHOęśÉO~b£öédźæų
ķšhT°T[!XARAJėE뤯ōÄøt
ŃļµÕĻŌj„Ļm%!X'²iŚNKCÆ©v(“VpJ#©"”yėZA£¹nøaß)=1N'Ļéń×^{-<ųą6m#K¬#
ģ·Žz«ō¦5×W£Į©Ųs¢-¶ŲĀØĀ·¾¢Ńu
vŃżŚQ`ÕŹŚ&tDFÓQ
Åj¢©.Z±C«²óōõi{(7å ±÷SĻŹ3B0Lg
ĮV¢sżS
”Õ!m-»„tƬQVŅ+pjn·NŌ*„ ō¹QŖ,ķY"-õÉ'Ų\ŲŅyĶRIÖ4ÕV[ĶĀc¶WŖ]¾M4MGAT=ŠļW:,
ÓźżŅK/Ż|DC#Üé6©QtMłQšÕNʱĒk#ŽŁ{Näć?¶iqWō\kmķt%Ńļ¤a§”rķ(t~żK+;"¢t>xkĮ Ŗ{?õ¬<#Ćt4£uiÖč_[t¹k
ÉüćÉ=µ§ Ø©!O>łdrż4b=Ń®4¬@}Ā '$÷äÓ*õ.×jÄ«gå!쯬e»tŲ\oŠ<äyA˰Ķ93ģæ’ž6ņY²Pz[µŖ52«QeŲ§QTźjŪĢ#-WÉU’xżØF,øzVaĮž* ĮZóW£±:łQ'^ĶŖßK£Ø
y”k
vMUŠ2rŗGéŹEÄė@5bĮÕ³ņCÆ? ÕWĻŹ3B0!hL¼ž T#\=+ĻĮ0` 1ńśPXpõ¬<#ĆĘÄė@5bĮÕ³ņCÆ? ÕWĻŹ3B0!hL¼ž T#\=+ĻĮ0` 1ńśPXpõ¬<#ĆMĻméeĖłōÓOĆ^{ķeėńźk?üšĆ.ߌrĖ-ĆÕW_ÜkļļT4æżķoĆ®»īÜjÆ? ÕWĻŹ3B0LCščÅę]uĄ!Cģ’uŚi§%÷4QųŅży š©ßUµŠB
5×\3\tŃEÉ£Ń×¶'pžž÷æĖ,³LxöŁgĆŪo澞śk»ĢÆĀqŖµļyūķ·ÕW_Ż.k\N{§