Detailed description
pytest captures logging.info() calls differently depending on whether you run the full monorepo test suite or a single package. The same logging bug can be visible in one context and completely invisible in the other.
# Full monorepo — logging.info() formatting errors surface → tests FAIL
uv run pytest
# Single package — logging.info() formatting errors are silently swallowed → tests PASS
uv run pytest components/my-package/
Root cause
No log_level is set in [tool.pytest.ini_options]. The root logger therefore starts at Python's default level (WARNING). When logger.info() is called:
- effective level =
WARNING → isEnabledFor(INFO) returns False → call is a no-op, no record is created, no formatting is attempted → bug invisible
- effective level =
INFO → record is created, reaches pytest's handler, formatting is attempted → bug visible
When running the full monorepo, a fixture in another component sets the root logger to INFO. This state leaks into the rest of the test session. The my-package tests then run with INFO active and a malformed logger.info("message", value) call (missing %s placeholder) raises:
TypeError: not all arguments converted during string formatting
When running only my-package, no component ever sets the root logger to INFO, so it stays at WARNING and the bug is invisible.
Minimal example
# src/mymodule.py
import logging
logger = logging.getLogger(__name__)
def buggy():
logger.info("value is", 42) # ← missing %s placeholder
# tests/test_mymodule.py
from mymodule import buggy
def test_buggy():
buggy() # PASS if root logger is WARNING, FAIL if INFO
Running pytest tests/ alone → passes.
Running alongside a test suite that configures INFO logging → fails.
Fix
Add log_level = "INFO" to [tool.pytest.ini_options] in pyproject.toml so pytest always sets the root logger to INFO at session startup, making behavior deterministic regardless of test scope or execution order:
[tool.pytest.ini_options]
log_level = "INFO"
pytest and OS versions
- pytest
8.4.2
- OS: Windows 10 (
win32 10.0.26100)
pip list
Full output
Package Version Editable project location
------------------------------ ----------- -----------------------------------------------------------------------
altair 5.5.0
annotated-types 0.7.0
anyio 4.12.1
networkx 3.3
numpy 1.26.4
packaging 25.0
pandas 2.2.3
pluggy 1.6.0
polyfactory 3.2.0
pydantic 2.12.5
pydantic-core 2.41.5
pyhamcrest 2.1.0
pytest 8.4.2
pytest-custom-exit-code 0.3.0
pytest-mock 3.15.1
pytest-timeout 2.4.0
python-dotenv 1.2.1
ruff 0.5.7
scikit-learn 1.3.2
scikit-learn-extra 0.3.0
scipy 1.14.1
my-package 0.1.0 components/my-package
umap-learn 0.5.7
pip listfrom the virtual environment you are usingDetailed description
pytest captures
logging.info()calls differently depending on whether you run the full monorepo test suite or a single package. The same logging bug can be visible in one context and completely invisible in the other.Root cause
No
log_levelis set in[tool.pytest.ini_options]. The root logger therefore starts at Python's default level (WARNING). Whenlogger.info()is called:WARNING→isEnabledFor(INFO)returnsFalse→ call is a no-op, no record is created, no formatting is attempted → bug invisibleINFO→ record is created, reaches pytest's handler, formatting is attempted → bug visibleWhen running the full monorepo, a fixture in another component sets the root logger to
INFO. This state leaks into the rest of the test session. Themy-packagetests then run withINFOactive and a malformedlogger.info("message", value)call (missing%splaceholder) raises:When running only
my-package, no component ever sets the root logger toINFO, so it stays atWARNINGand the bug is invisible.Minimal example
Running
pytest tests/alone → passes.Running alongside a test suite that configures
INFOlogging → fails.Fix
Add
log_level = "INFO"to[tool.pytest.ini_options]inpyproject.tomlso pytest always sets the root logger toINFOat session startup, making behavior deterministic regardless of test scope or execution order:pytest and OS versions
8.4.2win32 10.0.26100)pip listFull output