Skip to main content

A pytest plugin for test case-level dynamic dependency management

Project description

pytest-casewise-package-install

English | ??


English

A pytest plugin for test case-level dynamic dependency management. Solves dependency conflicts between multiple test cases by automatically installing required package versions before test execution and cleaning up the environment afterward, ensuring isolation and consistency.

Features

  • ?? Test Case-Level Package Management: Specify different package versions for each test case
  • ?? Dependency Isolation: Avoid conflicts between tests requiring different package versions
  • ?? Automatic Installation: Packages are installed automatically before test execution
  • ?? Automatic Cleanup: Environment is restored after each test
  • ?? Smart Caching: Package installations are cached and reused across tests
  • ?? Multiple Usage Patterns: Decorator or marker-based syntax

Installation

pip install pytest-casewise-package-install

Quick Start

Using Decorator

from pytest_casewise_package_install import with_packages

@with_packages({"requests": "2.31.0"})
def test_with_requests():
    import requests
    assert requests.__version__ == "2.31.0"

Using Pytest Marker

import pytest

@pytest.mark.with_packages(packages={"requests": "2.28.0"})
def test_with_marker():
    import requests
    assert requests.__version__ == "2.28.0"

Multiple Packages

from pytest_casewise_package_install import with_packages

@with_packages({
    "numpy": "1.26.4",
    "pandas": "2.0.0"
})
def test_multiple_packages():
    import numpy
    import pandas
    assert numpy.__version__ == "1.26.4"
    assert pandas.__version__ == "2.0.0"

Parametrize with Different Versions (NEW!)

Test the same code with different package versions - perfect for model testing:

import pytest
from pytest_casewise_package_install import param_with_packages

@pytest.mark.parametrize("model_name,packages", [
    param_with_packages(
        "bert-base-uncased",
        packages={"transformers": "4.30.0"},
        id="bert-v4.30"
    ),
    param_with_packages(
        "gpt2",
        packages={"transformers": "4.35.0"},
        id="gpt2-v4.35"
    ),
])
def test_model(model_name, packages):
    import transformers
    print(f"Testing {model_name} with transformers {transformers.__version__}")
    # your test code

Using Fixtures for Dynamic Management

from pytest_casewise_package_install import package_env

def test_with_fixture(package_env):
    with package_env.use_packages({"numpy": "1.24.0"}):
        import numpy
        assert numpy.__version__ == "1.24.0"
    # environment automatically restored

Configuration

You can configure the plugin behavior in pytest.ini or setup.cfg:

[pytest]
# custom cache directory (optional)
casewise_cache_dir = ~/.my_custom_cache

# automatically cleanup environment after each test (default: true)
casewise_auto_cleanup = true

# package installation timeout in seconds (default: 300)
casewise_install_timeout = 300

# verbose output (default: false)
casewise_verbose = true

Or use environment variables:

export CASEWISE_CACHE_DIR=~/.my_custom_cache
export CASEWISE_AUTO_CLEANUP=true
export CASEWISE_INSTALL_TIMEOUT=300
export CASEWISE_VERBOSE=true

How It Works

  1. Test Discovery: The plugin hooks into pytest's test collection phase
  2. Package Detection: Detects package requirements from decorators or markers
  3. Environment Setup: Before test execution:
    • Creates isolated installation directory for required packages
    • Installs packages using pip install --target
    • Modifies PYTHONPATH and sys.path to use the isolated packages
  4. Test Execution: Test runs with the specified package versions
  5. Cleanup: After test execution:
    • Restores original PYTHONPATH and sys.path
    • Keeps installed packages cached for future tests

Advanced Usage

Test Class with Different Versions

from pytest_casewise_package_install import with_packages

class TestPackageVersions:
    @with_packages({"click": "8.1.3"})
    def test_click_8_1_3(self):
        import click
        assert click.__version__ == "8.1.3"
    
    @with_packages({"click": "8.0.0"})
    def test_click_8_0_0(self):
        import click
        assert click.__version__ == "8.0.0"

Reusing Package Sets

The plugin automatically caches package installations. If two tests require the same package set, the second test will reuse the first test's installation:

from pytest_casewise_package_install import with_packages

@with_packages({"requests": "2.31.0"})
def test_one():
    import requests
    assert requests.__version__ == "2.31.0"

@with_packages({"requests": "2.31.0"})
def test_two():
    # reuses the installation from test_one
    import requests
    assert requests.__version__ == "2.31.0"

Use Cases

This plugin is particularly useful when:

  • Testing compatibility with multiple versions of a dependency
  • Running tests that require conflicting package versions
  • Testing migration paths between package versions
  • Ensuring test isolation in CI/CD pipelines
  • Testing against different versions of transitive dependencies

Limitations

  • Package installation happens during test setup, which may increase test duration
  • Large packages can consume significant disk space in the cache directory
  • Some packages with complex native dependencies may not work correctly with --target installation
  • Import-time side effects in packages may not be fully isolated

Development

Setup Development Environment

git clone https://github.com/yourusername/pytest-casewise-package-install
cd pytest-casewise-package-install
pip install -e .

Run Tests

pytest tests/

Run Examples

cd examples
pytest -v

License

MIT License


??

????????????????? pytest ?????????????????????????????????????????????????????????

????

  • ?? ????????: ???????????????
  • ?? ????: ??????????????????
  • ?? ????: ???????????
  • ?? ????: ?????????
  • ?? ????: ?????????????
  • ?? ??????: ???????????

??

pip install pytest-casewise-package-install

????

?????

from pytest_casewise_package_install import with_packages

@with_packages({"requests": "2.31.0"})
def test_with_requests():
    import requests
    assert requests.__version__ == "2.31.0"

?? Pytest Marker

import pytest

@pytest.mark.with_packages(packages={"requests": "2.28.0"})
def test_with_marker():
    import requests
    assert requests.__version__ == "2.28.0"

???

from pytest_casewise_package_install import with_packages

@with_packages({
    "numpy": "1.26.4",
    "pandas": "2.0.0"
})
def test_multiple_packages():
    import numpy
    import pandas
    assert numpy.__version__ == "1.26.4"
    assert pandas.__version__ == "2.0.0"

??

??? pytest.ini ? setup.cfg ????????

[pytest]
# ???????????
casewise_cache_dir = ~/.my_custom_cache

# ??????????????: true?
casewise_auto_cleanup = true

# ????????????: 300?
casewise_install_timeout = 300

# ???????: false?
casewise_verbose = true

????????

export CASEWISE_CACHE_DIR=~/.my_custom_cache
export CASEWISE_AUTO_CLEANUP=true
export CASEWISE_INSTALL_TIMEOUT=300
export CASEWISE_VERBOSE=true

????

  1. ????: ???? pytest ???????
  2. ???: ?????????????
  3. ????: ???????
    • ??????????????
    • ?? pip install --target ???
    • ?? PYTHONPATH ? sys.path ???????
  4. ????: ????????????
  5. ??: ??????
    • ????? PYTHONPATH ? sys.path
    • ??????????????????

????

??????????

from pytest_casewise_package_install import with_packages

class TestPackageVersions:
    @with_packages({"click": "8.1.3"})
    def test_click_8_1_3(self):
        import click
        assert click.__version__ == "8.1.3"
    
    @with_packages({"click": "8.0.0"})
    def test_click_8_0_0(self):
        import click
        assert click.__version__ == "8.0.0"

?????

???????????????????????????????????????????

from pytest_casewise_package_install import with_packages

@with_packages({"requests": "2.31.0"})
def test_one():
    import requests
    assert requests.__version__ == "2.31.0"

@with_packages({"requests": "2.31.0"})
def test_two():
    # ???? test_one ???
    import requests
    assert requests.__version__ == "2.31.0"

????

??????????????

  • ??????????????
  • ????????????
  • ????????????
  • ? CI/CD ?????????
  • ???????????

??

  • ????????????????????????
  • ????????????????????
  • ???????????????????? --target ??
  • ?????????????????

??

??????

git clone https://github.com/yourusername/pytest-casewise-package-install
cd pytest-casewise-package-install
pip install -e .

????

pytest tests/

????

cd examples
pytest -v

???

MIT License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytest_casewise_package_install-0.2.0.tar.gz (40.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pytest_casewise_package_install-0.2.0-py3-none-any.whl (17.9 kB view details)

Uploaded Python 3

File details

Details for the file pytest_casewise_package_install-0.2.0.tar.gz.

File metadata

File hashes

Hashes for pytest_casewise_package_install-0.2.0.tar.gz
Algorithm Hash digest
SHA256 d56eb5768707004fcf9bfdfafddcf050c87af5290633c16796740cb559bdf12f
MD5 dc26f91d2d6202e0b2b19bb9a949acdb
BLAKE2b-256 0a37a3c05547c99e1831b42158d6a3b77a5615171bf410a74c2cdf1576d2d9c5

See more details on using hashes here.

File details

Details for the file pytest_casewise_package_install-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pytest_casewise_package_install-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 253492f5ad9067d5183ba44ecbca0f453ad77334221329ce05640abcd028afaf
MD5 31b010e88e8e3d446a23a688375ed7e9
BLAKE2b-256 b9d3678ec5e2b57e8e008cbfe88618ce9d18ccbfdd69b1f2ba974654b0ca151b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page