Repository: AdaCore/e3-core (language: python)

Issue:
Pytest may not run with coverage
When trying to run a single test with the latest `pytest` driver, it ends up with:

```
INTERNALERROR>   File ".../lib/python3.11/site-packages/_pytest/config/__init__.py", line 1709, in getoption
INTERNALERROR>     raise ValueError(f"no option named {name!r}") from e
INTERNALERROR> ValueError: no option named 'cov_source'
```


Discussion / hints:

Fix patch:
diff --git a/pyproject.toml b/pyproject.toml
index 63805203..04f96ee9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -20,6 +20,9 @@ classifiers = [
   "Topic :: Software Development :: Build Tools"
 ]
 
+# Even if they are used by the pytest driver, the pytest and coverage
+# dependencies are not installed by default. This is on purpose to avoid
+# importing test/coverage packages in a release install.
 dependencies = [
   "colorama",
   "pyyaml",
@@ -49,6 +52,7 @@ config = [
   "typeguard<3.0.0"
 ]
 test = [
+  "coverage",
   "mock",
   "requests-mock",
   "pytest",


Test patch:
diff --git a/src/e3/pytest.py b/src/e3/pytest.py
index 574b1fe2..d878a38e 100644
--- a/src/e3/pytest.py
+++ b/src/e3/pytest.py
@@ -12,19 +12,26 @@
 
 import e3.log
 
-from coverage.sqldata import CoverageData
-from coverage.files import PathAliases
-from coverage import Coverage
-
-
-import pytest
+try:
+    import pytest
+    from coverage.sqldata import CoverageData
+    from coverage.files import PathAliases
+    from coverage import Coverage
+except ImportError as ie:  # defensive code
+    # Those packages may be missing. In order to avoid importing tests or
+    # coverage packages in release mode, they are deliberately not part of
+    # the dependencies. Let the user know that the packages should be installed
+    # if he wants to use e3 pytest driver.
+    raise ImportError(
+        "Missing test and coverage packages. Please install pytest and coverage "
+        "packages"
+    ) from ie
 
 import typing
 
 if typing.TYPE_CHECKING:
     from typing import Callable
 
-
 test_errors = False
 
 # Detect that we're in CI mode, most providers set the $CI environment variable
@@ -73,7 +80,7 @@ def env_protect(request: pytest.FixtureRequest) -> None:
 
     The fixture is enabled for all tests and does the following:
 
-    * store/restore env between each tests
+    * store/restore env between tests
     * create a temporary directory and do a cd to it before each
       test. The directory is automatically removed when test ends
     """
@@ -98,9 +105,13 @@ def restore_env() -> None:
 
 
 def pytest_configure(config: pytest.Config) -> None:
-    if config.getoption("e3") and config.getoption("cov_source"):
+    if (
+        config.getoption("e3")
+        and hasattr(config.option, "cov_source")
+        and config.getoption("cov_source")
+    ):
         # When e3 plugin is activated, the report generated by pytest-cov
-        # should be deactivated to avoid duplicating the output. Also
+        # should be deactivated to avoid duplicating the output. Also,
         # some options set by e3 change the coverage, pytest-cov report is not
         # accurate in that case.
         cov = config.pluginmanager.getplugin("_cov")
@@ -122,9 +133,13 @@ def pytest_sessionfinish(session: pytest.Session, exitstatus: int) -> None:
         # test code.
         session.exitstatus = 3
 
-    if session.config.getoption("cov_source"):
+    if hasattr(session.config.option, "cov_source") and session.config.getoption(
+        "cov_source"
+    ):
         cov_file = str(session.config.rootpath / ".coverage")
-        if session.config.getoption("e3_cov_rewrite"):
+        if hasattr(
+            session.config.option, "e3_cov_rewrite"
+        ) and session.config.getoption("e3_cov_rewrite"):
             origin_dir, new_dir = session.config.getoption("e3_cov_rewrite")
             fix_coverage_paths(origin_dir=origin_dir, new_dir=new_dir, cov_db=cov_file)
 
@@ -181,7 +196,7 @@ def fix_coverage_paths(origin_dir: str, new_dir: str, cov_db: str) -> None:
         .tox/py311-cov-xdist/lib/python3.11/site-packages/e3
     :param new_dir: path to the dir that should be visible instead of origin_dir
         e.g. src/
-    :param cov_db: path to the .coverage data base
+    :param cov_db: path to the .coverage database
     """
     paths = PathAliases()
     paths.add(origin_dir, new_dir)