Skip to content

Commit

Permalink
Install import hook earlier during pytest initialization (#143)
Browse files Browse the repository at this point in the history
The pytest plugin does not work at all in this very common scenario:

- Application/library uses a conftest.py file with pytest configuration
- This conftest.py imports application/library modules.

Even worse, no matter what is passed as the ‘--typeguard-packages=’
command line argument, no warnings or errors will be reported at all.
Typeguard will be fully silent. this this makes it seem the code is
fully correct, while in reality the code is not checked by typeguard
*at all*. Oops. 💥 🙈 😱

The problem is that the pytest plugin used the ‘pytest_sessionstart()’
hook, which triggers only after conftest.py files (or other pytest
configuration files) have been loaded already. This is too late to
install the import hook: the targeted modules may have been imported
already at this point!

This pull request fixes this problem in the following way:

- Use ‘pytest_configure()’ instead of ‘pytest_sessionstart()’, since
  the former triggers before any conftest files are loaded.

- Make it impossible to silently skip checks for packages specified on
  the command line that cannot actually be checked. In those situations,
  raise an error with all the details. Example for
  ‘--typeguard-packages=sys’:

  INTERNALERROR> RuntimeError: typeguard cannot check these packages that are already imported: sys

See also:

- https://docs.pytest.org/en/stable/reference.html#pytest.hookspec.pytest_configure
- https://docs.pytest.org/en/stable/reference.html#pytest.hookspec.pytest_sessionstart
  • Loading branch information
wbolster committed Aug 14, 2020
1 parent 461cfd5 commit 9673ad1
Showing 1 changed file with 20 additions and 5 deletions.
25 changes: 20 additions & 5 deletions typeguard/pytest_plugin.py
@@ -1,3 +1,5 @@
import sys

from typeguard.importhook import install_import_hook


Expand All @@ -8,8 +10,21 @@ def pytest_addoption(parser):
'type checking')


def pytest_sessionstart(session):
packages = session.config.getoption('typeguard_packages')
if packages:
package_list = [pkg.strip() for pkg in packages.split(',')]
install_import_hook(packages=package_list)
def pytest_configure(config):
value = config.getoption("typeguard_packages")
if not value:
return

packages = [pkg.strip() for pkg in value.split(",")]

already_imported_packages = sorted(
package for package in packages if package in sys.modules
)
if already_imported_packages:
message = (
"typeguard cannot check these packages because they "
"are already imported: {}"
)
raise RuntimeError(message.format(", ".join(already_imported_packages)))

install_import_hook(packages=packages)

0 comments on commit 9673ad1

Please sign in to comment.