Marco Ricci commited on 2026-08-23 12:44:07
Zeige 3 geänderte Dateien mit 19 Einfügungen und 17 Löschungen.
Even when the `cryptography` library is available, we test the fallback behavior of `derivepassphrase export vault` by inhibiting the loading of `cryptography`. As a result, we no longer need a separate testing environment for the "no cryptography support" case, and can therefore halve the number of configurations in our testing matrix. We also no longer need some associated configuration and helper objects. In hindsight, I cannot believe I never tried to do a web search on how to inhibit loading of a module in Python, and rather assumed that just because pytest does not prominently offer a dedicated top-level function or a dedicated `monkeypatch` method, that this is not supported. But seeing the underlying documentation for `importlib.import_module` and the documentation of how `sys.modules[...] = None` affects the module resolution, it becomes immediately obvious that this can be handled with monkeypatching, and does not need a separate virtualenv.
| ... | ... |
@@ -391,23 +391,18 @@ dependencies = [ |
| 391 | 391 |
'pytest < 8.4 ; python_version < "3.10"', |
| 392 | 392 |
'hypothesis != 6.130.13, != 6.131.*, != 6.132.*, != 6.133.*, != 6.134.*, != 6.135.0, != 6.135.1 ; python_version < "3.10"', |
| 393 | 393 |
] |
| 394 |
+features = ["export", "export-dev-wheels"] |
|
| 394 | 395 |
matrix-name-format = '{variable}_{value}'
|
| 395 | 396 |
|
| 396 | 397 |
[[tool.hatch.envs.hatch-test.matrix]] |
| 397 | 398 |
python = ["3.14", "3.13", "3.12", "3.11", "3.10", "3.9", "pypy3.11", "pypy3.10", "pypy3.9"] |
| 398 |
-cryptography = ["no", "yes"] |
|
| 399 | 399 |
parser-version = ["PEG"] |
| 400 | 400 |
|
| 401 | 401 |
[[tool.hatch.envs.hatch-test.matrix]] |
| 402 | 402 |
python = ["3.9", "pypy3.9"] |
| 403 |
-cryptography = ["no", "yes"] |
|
| 404 | 403 |
parser-version = ["LL1"] |
| 405 | 404 |
|
| 406 | 405 |
[tool.hatch.envs.hatch-test.overrides] |
| 407 |
-matrix.cryptography.features = [ |
|
| 408 |
- { value = "export", if = ["yes"] },
|
|
| 409 |
- { value = "export-dev-wheels", if = ["yes"] },
|
|
| 410 |
-] |
|
| 411 | 406 |
matrix.parser-version.env-vars = [ |
| 412 | 407 |
{ key = "PYTHONOLDPARSER", value = "1", if = ["LL1"] },
|
| 413 | 408 |
] |
| ... | ... |
@@ -56,16 +56,6 @@ if TYPE_CHECKING: |
| 56 | 56 |
# ===== |
| 57 | 57 |
|
| 58 | 58 |
|
| 59 |
-skip_if_cryptography_support = pytest.mark.skipif( |
|
| 60 |
- importlib.util.find_spec("cryptography") is not None,
|
|
| 61 |
- reason='cryptography support available; cannot test "no support" scenario', |
|
| 62 |
-) |
|
| 63 |
-""" |
|
| 64 |
-A cached pytest mark to skip this test if cryptography support is |
|
| 65 |
-available. Usually this means that the test targets |
|
| 66 |
-`derivepassphrase`'s fallback functionality, which is not available |
|
| 67 |
-whenever the primary functionality is. |
|
| 68 |
-""" |
|
| 69 | 59 |
skip_if_no_cryptography_support = pytest.mark.skipif( |
| 70 | 60 |
importlib.util.find_spec("cryptography") is None,
|
| 71 | 61 |
reason='no "cryptography" support', |
| ... | ... |
@@ -11,6 +11,7 @@ import operator |
| 11 | 11 |
import os |
| 12 | 12 |
import pathlib |
| 13 | 13 |
import string |
| 14 |
+import sys |
|
| 14 | 15 |
import types |
| 15 | 16 |
from typing import TYPE_CHECKING, NamedTuple, TypeVar |
| 16 | 17 |
|
| ... | ... |
@@ -473,7 +474,6 @@ class TestGenericVaultCLIErrors: |
| 473 | 474 |
"expected error exit and known error message" |
| 474 | 475 |
) |
| 475 | 476 |
|
| 476 |
- @pytest_machinery.skip_if_cryptography_support |
|
| 477 | 477 |
@pytest_machinery.Parametrize.VAULT_CONFIG_FORMATS_DATA |
| 478 | 478 |
def test_no_cryptography_error_message( |
| 479 | 479 |
self, |
| ... | ... |
@@ -484,6 +484,23 @@ class TestGenericVaultCLIErrors: |
| 484 | 484 |
) -> None: |
| 485 | 485 |
"""Abort export call if no cryptography is available.""" |
| 486 | 486 |
del config_data |
| 487 |
+ with pytest.MonkeyPatch.context() as monkeypatch: |
|
| 488 |
+ monkeypatch.setitem(sys.modules, "cryptography", None) |
|
| 489 |
+ monkeypatch.delitem( |
|
| 490 |
+ sys.modules, |
|
| 491 |
+ "derivepassphrase.exporter.vault_native", |
|
| 492 |
+ raising=False, |
|
| 493 |
+ ) |
|
| 494 |
+ monkeypatch.delitem( |
|
| 495 |
+ sys.modules, |
|
| 496 |
+ "derivepassphrase.exporter.storeroom", |
|
| 497 |
+ raising=False, |
|
| 498 |
+ ) |
|
| 499 |
+ monkeypatch.delitem( # also reset export_data handler registry |
|
| 500 |
+ sys.modules, |
|
| 501 |
+ "derivepassphrase.exporter", |
|
| 502 |
+ raising=False, |
|
| 503 |
+ ) |
|
| 487 | 504 |
result = self._call_cli( |
| 488 | 505 |
["-f", format, "VAULT_PATH"], vault_config=config |
| 489 | 506 |
) |
| 490 | 507 |