From e6bf38042e6151fad84dde8871fac3fcf13b2f77 Mon Sep 17 00:00:00 2001 From: Tushar Sadhwani Date: Thu, 31 Oct 2024 23:21:49 +0530 Subject: [PATCH] feat: `--beartype-skip-packages` (#9) --- pyproject.toml | 16 ++++++++-------- src/pytest_beartype/__init__.py | 31 ++++++++++++++++++++++++++----- tests/pytest_beartype_test.py | 20 +++++++++++++++----- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 245d6a9..817699c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,12 @@ [build-system] -requires = [ "setuptools >=61", "wheel" ] +requires = ["setuptools >=61", "wheel"] build-backend = "setuptools.build_meta" [project] name = "pytest-beartype" -version = "0.1.1" +version = "0.2.0" description = "Pytest plugin to run your tests with beartype checking enabled." -authors = [ { name = "Tushar Sadhwani", email = "tushar.sadhwani000@gmail.com" } ] +authors = [{ name = "Tushar Sadhwani", email = "tushar.sadhwani000@gmail.com" }] readme = "README.md" requires-python = ">=3.8" urls.Source = "https://github.com/tusharsadhwani/pytest-beartype" @@ -25,16 +25,16 @@ classifiers = [ "Programming Language :: Python :: Implementation :: CPython", "Typing :: Typed", ] -dependencies = [ "beartype", "pytest" ] -optional-dependencies.dev = [ "black", "mypy", "pytest-cov", "tox" ] +dependencies = ["beartype>=0.19.0", "pytest"] +optional-dependencies.dev = ["black", "mypy", "pytest-cov", "tox"] entry-points.pytest11.pytest_beartype = "pytest_beartype" [tool.setuptools] -package-data = { "*" = [ "py.typed" ] } -packages.find.where = [ "./src" ] +package-data = { "*" = ["py.typed"] } +packages.find.where = ["./src"] [tool.pytest.ini_options] -addopts = [ "--cov", "--cov-report=term-missing" ] +addopts = ["--cov", "--cov-report=term-missing"] [tool.mypy] strict = true diff --git a/src/pytest_beartype/__init__.py b/src/pytest_beartype/__init__.py index c5a3467..fb4c21f 100644 --- a/src/pytest_beartype/__init__.py +++ b/src/pytest_beartype/__init__.py @@ -11,10 +11,16 @@ def pytest_addoption(parser: "pytest.Parser") -> None: "comma-delimited list of the fully-qualified names of " "all packages and modules to type-check with beartype" ) + skip_help_msg = ( + "comma-delimited list of the fully-qualified names of " + "all packages and modules to SKIP type-checking with beartype" + ) group = parser.getgroup("beartype") group.addoption("--beartype-packages", action="store", help=help_msg) parser.addini("beartype_packages", type="args", help=help_msg) + group.addoption("--beartype-skip-packages", action="store", help=skip_help_msg) + parser.addini("beartype_skip_packages", type="args", help=skip_help_msg) def pytest_configure(config: "pytest.Config") -> None: @@ -23,22 +29,35 @@ def pytest_configure(config: "pytest.Config") -> None: # "beartype_packages" section in the user-defined "pytest.ini" file, or the # "--beartype-packages" options, defined above by the pytest_addoption() hook. package_names = config.getini("beartype_packages") - package_names_arg_str = config.getoption("beartype_packages", "") if package_names_arg_str: package_names += package_names_arg_str.split(",") + packages_to_skip = config.getini("beartype_skip_packages") + packages_to_skip_arg_str = config.getoption("beartype_skip_packages", "") + if packages_to_skip_arg_str: + packages_to_skip += packages_to_skip_arg_str.split(",") + + # If `--beartype-packages` is specified (and isn't just `*`), + # and `--beartype-skip-packages` is also specified, then bail out with an error. + if package_names and "*" not in package_names and packages_to_skip: + pytest.exit( + "'beartype_packages' and 'beartype_skip_packages' cannot be used together." + ) + # If the user passed this option... if package_names: # Defer hook-specific imports. To improve "pytest" startup performance, # avoid performing *ANY* imports unless the user actually passed the # "--beartype-packages" option declared by this plugin. - from beartype.roar import BeartypeWarning - from beartype.claw import beartype_all, beartype_packages - from beartype._util.text.utiltextjoin import join_delimited import sys from warnings import warn + from beartype import BeartypeConf + from beartype._util.text.utiltextjoin import join_delimited + from beartype.claw import beartype_all, beartype_packages + from beartype.roar import BeartypeWarning + class BeartypePytestWarning(BeartypeWarning): """ Beartype :mod:`pytest` warning. @@ -110,6 +129,8 @@ class BeartypePytestWarning(BeartypeWarning): # Install an import hook type-checking these packages and modules. if "*" in package_names: - beartype_all() + beartype_all( + conf=BeartypeConf(claw_skip_package_names=tuple(packages_to_skip)) + ) else: beartype_packages(package_names) diff --git a/tests/pytest_beartype_test.py b/tests/pytest_beartype_test.py index 963466c..724e08f 100644 --- a/tests/pytest_beartype_test.py +++ b/tests/pytest_beartype_test.py @@ -1,6 +1,6 @@ from unittest import mock -import pytest +import pytest import pytest_beartype @@ -12,8 +12,18 @@ def test_pytest_addoption() -> None: with mock.patch.object(pytest.OptionGroup, "addoption") as mock_addoption: pytest_beartype.pytest_addoption(pytest.Parser()) - mock_addoption.assert_called_once_with( - "--beartype-packages", - action="store", - help=mock.ANY, + assert mock_addoption.call_count == 2 + mock_addoption.assert_has_calls( + [ + mock.call( + "--beartype-packages", + action="store", + help=mock.ANY, + ), + mock.call( + "--beartype-skip-packages", + action="store", + help=mock.ANY, + ), + ] )