pax_global_header00006660000000000000000000000064144427131440014516gustar00rootroot0000000000000052 comment=f56d3935ff8ca99f087f8fd8c38f028f4375b2c7 pytest-env-0.8.2/000077500000000000000000000000001444271314400136435ustar00rootroot00000000000000pytest-env-0.8.2/.github/000077500000000000000000000000001444271314400152035ustar00rootroot00000000000000pytest-env-0.8.2/.github/CODEOWNERS000066400000000000000000000000171444271314400165740ustar00rootroot00000000000000* @gaborbernat pytest-env-0.8.2/.github/FUNDING.yml000066400000000000000000000000341444271314400170150ustar00rootroot00000000000000tidelift: "pypi/pytest-env" pytest-env-0.8.2/.github/SECURITY.md000066400000000000000000000005551444271314400170010ustar00rootroot00000000000000# Security Policy ## Supported Versions | Version | Supported | | ------- | ------------------ | | 0.8.0 + | :white_check_mark: | | < 0.8.0 | :x: | ## Reporting a Vulnerability To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. pytest-env-0.8.2/.github/dependabot.yml000066400000000000000000000001651444271314400200350ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "daily" pytest-env-0.8.2/.github/workflows/000077500000000000000000000000001444271314400172405ustar00rootroot00000000000000pytest-env-0.8.2/.github/workflows/check.yml000066400000000000000000000041301444271314400210360ustar00rootroot00000000000000name: check on: push: tags-ignore: ["**"] pull_request: schedule: - cron: "0 8 * * *" concurrency: group: check-${{ github.ref }} cancel-in-progress: true jobs: test: name: test ${{ matrix.py }} - ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: py: - "3.12.0-beta.2" - "3.11" - "3.10" - "3.9" - "3.8" - "3.7" os: - ubuntu-latest steps: - name: Setup python for tox uses: actions/setup-python@v4 with: python-version: "3.11" - name: Install tox run: python -m pip install tox - uses: actions/checkout@v3 with: fetch-depth: 0 - name: Setup python for test ${{ matrix.py }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.py }} - name: Pick environment to run run: | import codecs; import os; import sys env = "TOXENV=py{}{}\n".format(*sys.version_info[0:2]) print("Picked:\n{}for{}".format(env, sys.version)) with codecs.open(os.environ["GITHUB_ENV"], "a", "utf-8") as file_handler: file_handler.write(env) shell: python - name: Setup test suite run: tox -vv --notest - name: Run test suite run: tox --skip-pkg-install env: CI_RUN: "yes" check: name: ${{ matrix.tox_env }} - ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: - ubuntu-latest tox_env: - dev - type - readme steps: - uses: actions/checkout@v3 with: fetch-depth: 0 - name: Setup Python "3.11" uses: actions/setup-python@v4 with: python-version: "3.11" - name: Install tox run: python -m pip install tox - name: Setup test suite run: tox -vv --notest -e ${{ matrix.tox_env }} - name: Run test suite run: tox --skip-pkg-install -e ${{ matrix.tox_env }} pytest-env-0.8.2/.github/workflows/release.yml000066400000000000000000000012061444271314400214020ustar00rootroot00000000000000name: Release to PyPI on: push: tags: ["*"] jobs: release: runs-on: ubuntu-latest environment: name: release url: https://pypi.org/p/pytest-env permissions: id-token: write steps: - name: Setup python to build package uses: actions/setup-python@v4 with: python-version: "3.11" - name: Install build run: python -m pip install build - uses: actions/checkout@v3 with: fetch-depth: 0 - name: Build package run: pyproject-build -s -w . -o dist - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@v1.8.6 pytest-env-0.8.2/.gitignore000066400000000000000000000000701444271314400156300ustar00rootroot00000000000000*.pyc *.egg-info dist/ .tox/ /src/pytest_env/version.py pytest-env-0.8.2/.pre-commit-config.yaml000066400000000000000000000016571444271314400201350ustar00rootroot00000000000000repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit rev: "v0.0.272" hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] - repo: https://github.com/psf/black rev: 23.3.0 hooks: - id: black - repo: https://github.com/tox-dev/tox-ini-fmt rev: "1.3.0" hooks: - id: tox-ini-fmt args: ["-p", "fix"] - repo: https://github.com/tox-dev/pyproject-fmt rev: "0.11.2" hooks: - id: pyproject-fmt additional_dependencies: ["tox>=4.6"] - repo: https://github.com/pre-commit/mirrors-prettier rev: "v3.0.0-alpha.9-for-vscode" hooks: - id: prettier args: ["--print-width=120", "--prose-wrap=always"] - repo: meta hooks: - id: check-hooks-apply - id: check-useless-excludes pytest-env-0.8.2/LICENSE000066400000000000000000000020771444271314400146560ustar00rootroot00000000000000MIT License Copyright (c) 2010-202x The pytest-env developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pytest-env-0.8.2/README.md000066400000000000000000000035561444271314400151330ustar00rootroot00000000000000# pytest-env [![PyPI](https://img.shields.io/pypi/v/pytest-env?style=flat-square)](https://pypi.org/project/pytest-env/) [![Supported Python versions](https://img.shields.io/pypi/pyversions/pytest-env.svg)](https://pypi.org/project/pytest-env/) [![check](https://github.com/pytest-dev/pytest-env/actions/workflows/check.yml/badge.svg)](https://github.com/pytest-dev/pytest-env/actions/workflows/check.yml) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Downloads](https://pepy.tech/badge/pytest-env/month)](https://pepy.tech/project/pytest-env/month) This is a `pytest` plugin that enables you to set environment variables in a `pytest.ini` or `pyproject.toml` file. ## Installation Install with pip: ```shell pip install pytest-env ``` ## Usage In your pytest.ini file add a key value pair with `env` as the key and the environment variables as a line separated list of `KEY=VALUE` entries. The defined variables will be added to the environment before any tests are run: ```ini [pytest] env = HOME=~/tmp RUN_ENV=test ``` Or with `pyproject.toml`: ```toml [tool.pytest.ini_options] env = [ "HOME=~/tmp", "RUN_ENV=test", ] ``` ### Only set if not already set You can use `D:` (default) as prefix if you don't want to override existing environment variables: ```ini [pytest] env = D:HOME=~/tmp D:RUN_ENV=test ``` ### Transformation You can use existing environment variables using a python-like format, these environment variables will be expended before setting the environment variable: ```ini [pytest] env = RUN_PATH=/run/path/{USER} ``` You can apply the `R:` prefix to keep the raw value and skip this transformation step (can combine with the `D:` flag, order is not important): ```ini [pytest] env = R:RUN_PATH=/run/path/{USER} R:D:RUN_PATH_IF_NOT_SET=/run/path/{USER} ``` pytest-env-0.8.2/pyproject.toml000066400000000000000000000057641444271314400165730ustar00rootroot00000000000000[build-system] build-backend = "hatchling.build" requires = [ "hatch-vcs>=0.3", "hatchling>=1.17.1", ] [project] name = "pytest-env" description = "py.test plugin that allows you to add environment variables." readme = "README.md" keywords = [ "env", "pytest", ] license.file = "LICENSE" maintainers = [{ name = "Bernát Gábor", email = "gaborjbernat@gmail.com" }] requires-python = ">=3.7" classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development :: Libraries :: Python Modules", ] dynamic = [ "version", ] dependencies = [ "pytest>=7.3.1", ] optional-dependencies.test = [ "coverage>=7.2.7", "pytest-mock>=3.10", ] urls.Homepage = "https://github.com/pytest-dev/pytest-env" urls.Source = "https://github.com/pytest-dev/pytest-env" urls.Tracker = "https://github.com/pytest-dev/pytest-env/issues" [project.entry-points.pytest11] env = "pytest_env.plugin" [tool.hatch] build.hooks.vcs.version-file = "src/pytest_env/version.py" version.source = "vcs" [tool.black] line-length = 120 [tool.isort] profile = "black" known_first_party = ["pytest_env"] [tool.coverage] run.source = ["pytest_env", "tests"] run.dynamic_context = "test_function" run.branch = true run.parallel = true report.fail_under = 92 report.show_missing = true html.show_contexts = true html.skip_covered = false paths.source = [ "src", ".tox*/*/lib/python*/site-packages", ".tox*/pypy*/site-packages", ".tox*\\*\\Lib\\site-packages", "*/src", "*\\src", ] [tool.mypy] python_version = "3.10" show_error_codes = true strict = true [tool.ruff] select = ["ALL"] line-length = 120 target-version = "py37" isort = {known-first-party = ["pytest_env"], required-imports = ["from __future__ import annotations"]} ignore = [ "ANN101", # no typoe annotation for self "ANN401", # allow Any as type annotation "D203", # `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible "D212", # `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible "S104", # Possible binding to all interface ] [tool.ruff.per-file-ignores] "tests/**/*.py" = [ "S101", # asserts allowed in tests... "FBT", # don"t care about booleans as positional arguments in tests "INP001", # no implicit namespace "D", # don"t care about documentation in tests "S603", # `subprocess` call: check for execution of untrusted input "PLR2004", # Magic value used in comparison, consider replacing with a constant variable ] pytest-env-0.8.2/src/000077500000000000000000000000001444271314400144325ustar00rootroot00000000000000pytest-env-0.8.2/src/pytest_env/000077500000000000000000000000001444271314400166325ustar00rootroot00000000000000pytest-env-0.8.2/src/pytest_env/__init__.py000066400000000000000000000002061444271314400207410ustar00rootroot00000000000000"""Pytest set environments.""" from __future__ import annotations from .version import __version__ __all__ = [ "__version__", ] pytest-env-0.8.2/src/pytest_env/plugin.py000066400000000000000000000027441444271314400205110ustar00rootroot00000000000000"""Adopt environment section in pytest configuration files.""" from __future__ import annotations import os import pytest def pytest_addoption(parser: pytest.Parser) -> None: """Add section to configuration files.""" help_msg = "a line separated list of environment variables of the form (FLAG:)NAME=VALUE" parser.addini("env", type="linelist", help=help_msg, default=[]) @pytest.hookimpl(tryfirst=True) # type: ignore[misc] def pytest_load_initial_conftests( args: list[str], # noqa: ARG001 early_config: pytest.Config, parser: pytest.Parser, # noqa: ARG001 ) -> None: """Load environment variables from configuration files.""" for line in early_config.getini("env"): # INI lines e.g. D:R:NAME=VAL has two flags (R and D), NAME key, and VAL value parts = line.partition("=") ini_key_parts = parts[0].split(":") flags = {k.strip().upper() for k in ini_key_parts[:-1]} # R: is a way to designate whether to use raw value -> perform no transformation of the value transform = "R" not in flags # D: is a way to mark the value to be set only if it does not exist yet skip_if_set = "D" in flags key = ini_key_parts[-1].strip() value = parts[2].strip() if skip_if_set and key in os.environ: continue # transformation -> replace environment variables, e.g. TEST_DIR={USER}/repo_test_dir. os.environ[key] = value.format(**os.environ) if transform else value pytest-env-0.8.2/src/pytest_env/py.typed000066400000000000000000000000001444271314400203170ustar00rootroot00000000000000pytest-env-0.8.2/tests/000077500000000000000000000000001444271314400150055ustar00rootroot00000000000000pytest-env-0.8.2/tests/conftest.py000066400000000000000000000001021444271314400171750ustar00rootroot00000000000000from __future__ import annotations pytest_plugins = ["pytester"] pytest-env-0.8.2/tests/template.py000066400000000000000000000003111444271314400171650ustar00rootroot00000000000000from __future__ import annotations import ast import os def test_env() -> None: for key, value in ast.literal_eval(os.environ["_TEST_ENV"]).items(): assert os.environ[key] == value, key pytest-env-0.8.2/tests/test_env.py000066400000000000000000000066741444271314400172230ustar00rootroot00000000000000from __future__ import annotations import os import re from pathlib import Path from unittest import mock import pytest @pytest.mark.parametrize( ("env", "ini", "expected_env"), [ pytest.param( {}, "[pytest]\nenv = MAGIC=alpha", {"MAGIC": "alpha"}, id="new key - add to env", ), pytest.param( {}, "[pytest]\nenv = MAGIC=alpha\n SORCERY=beta", {"MAGIC": "alpha", "SORCERY": "beta"}, id="two new keys - add to env", ), pytest.param( # This test also tests for non-interference of env variables between this test and tests above {}, "[pytest]\nenv = d:MAGIC=beta", {"MAGIC": "beta"}, id="D flag - add to env", ), pytest.param( {"MAGIC": "alpha"}, "[pytest]\nenv = MAGIC=beta", {"MAGIC": "beta"}, id="key exists in env - overwrite", ), pytest.param( {"MAGIC": "alpha"}, "[pytest]\nenv = D:MAGIC=beta", {"MAGIC": "alpha"}, id="D exists - original val kept", ), pytest.param( {"PLANET": "world"}, "[pytest]\nenv = MAGIC=hello_{PLANET}", {"MAGIC": "hello_world"}, id="curly exist - interpolate var", ), pytest.param( {"PLANET": "world"}, "[pytest]\nenv = R:MAGIC=hello_{PLANET}", {"MAGIC": "hello_{PLANET}"}, id="R exists - not interpolate var", ), pytest.param( {"MAGIC": "a"}, "[pytest]\nenv = R:MAGIC={MAGIC}b\n D:MAGIC={MAGIC}c\n MAGIC={MAGIC}d", {"MAGIC": "{MAGIC}bd"}, id="incremental interpolation", ), pytest.param( {"PLANET": "world"}, "[pytest]\nenv = D:R:RESULT=hello_{PLANET}", {"RESULT": "hello_{PLANET}"}, id="two flags", ), pytest.param( {"PLANET": "world"}, "[pytest]\nenv = R:D:RESULT=hello_{PLANET}", {"RESULT": "hello_{PLANET}"}, id="two flags - reversed", ), pytest.param( {"PLANET": "world"}, "[pytest]\nenv = d:r:RESULT=hello_{PLANET}", {"RESULT": "hello_{PLANET}"}, id="lowercase flags", ), pytest.param( {"PLANET": "world"}, "[pytest]\nenv = D : R : RESULT = hello_{PLANET}", {"RESULT": "hello_{PLANET}"}, id="whitespace is ignored", ), pytest.param( {"MAGIC": "zero"}, "", {"MAGIC": "zero"}, id="empty ini works", ), ], ) def test_env( testdir: pytest.Testdir, env: dict[str, str], ini: str, expected_env: dict[str, str], request: pytest.FixtureRequest, ) -> None: tmp_dir = Path(str(testdir.tmpdir)) test_name = re.sub(r"\W|^(?=\d)", "_", request.node.callspec.id).lower() Path(str(tmp_dir / f"test_{test_name}.py")).symlink_to(Path(__file__).parent / "template.py") (tmp_dir / "pytest.ini").write_text(ini, encoding="utf-8") # monkeypatch persists env variables across parametrized tests, therefore using mock.patch.dict with mock.patch.dict(os.environ, {**env, "_TEST_ENV": repr(expected_env)}, clear=True): result = testdir.runpytest() result.assert_outcomes(passed=1) pytest-env-0.8.2/tests/test_version.py000066400000000000000000000002061444271314400201010ustar00rootroot00000000000000from __future__ import annotations def test_version() -> None: import pytest_env assert pytest_env.__version__ is not None pytest-env-0.8.2/tox.ini000066400000000000000000000030311444271314400151530ustar00rootroot00000000000000[tox] requires = tox>=4.2 env_list = fix py312 py311 py310 py39 py38 py37 type readme skip_missing_interpreters = true [testenv] description = run the tests with pytest package = wheel wheel_build_env = .pkg extras = test set_env = COVERAGE_FILE = {env:COVERAGE_FILE:{toxworkdir}{/}.coverage.{envname}} commands = coverage erase coverage run -m pytest {tty:--color=yes} \ --junitxml {toxworkdir}{/}junit.{envname}.xml \ {posargs:tests} coverage combine coverage report coverage html -d {envtmpdir}{/}htmlcov [testenv:fix] description = run static analysis and style check using flake8 skip_install = true deps = pre-commit>=3.2. pass_env = HOMEPATH PROGRAMDATA commands = pre-commit run --all-files --show-diff-on-failure [testenv:type] description = run type check on code base deps = mypy==1.3 set_env = {tty:MYPY_FORCE_COLOR = 1} commands = mypy --strict src mypy --strict tests [testenv:readme] description = check that the long description is valid skip_install = true deps = build[virtualenv]>=0.10 twine>=4.0.2 change_dir = {toxinidir} commands = python -m build -o {envtmpdir} . twine check {envtmpdir}/* [testenv:dev] description = generate a DEV environment package = editable extras = test commands = python -m pip list --format=columns python -c 'import sys; print(sys.executable)' [flake8] max-complexity = 22 max-line-length = 120 noqa-require-code = true dictionaries = en_US,python,technical,django