Skip to content

Session-level hooks (pytest_html_report_title, etc.) do not fire from conftest.py in a nested test directory #944

@melumuccu

Description

@melumuccu

Hi team,

I've encountered an issue where certain pytest-html hooks behave differently depending on the location of the conftest.py file. Specifically, session-level hooks like pytest_html_report_title and pytest_html_results_table_header do not seem to fire when conftest.py is placed inside a nested directory (e.g., src/tests/), while item-level hooks like pytest_html_results_table_row work as expected.

This behavior seems to be related to pytest's conftest.py discovery mechanism, where session-level hooks might need to be in a top-level conftest.py to be registered correctly. However, this can be confusing, and it would be great if this behavior was either documented or handled more consistently.

To Reproduce

I've created a minimal reproducible repository here: https://github.com/melumuccu/pytest-html-issue

The issue can be observed by comparing two directory structures.

Case 1: Not Working ❌

In this structure, session-level hooks do not fire.

  • Directory Structure:

    .
    ├── pytest.ini
    └── src
        └── tests
            ├── conftest.py  <-- Hooks defined here
            └── test_sample.py
    
  • Observation: The report title is not changed, and the "Duration" header is not removed. However, the pytest_html_results_table_row hook does fire for each test.

  • Log (pytest --trace-config):

$ make test                                    
docker run --rm \
                -v /Users/fujisawakoki/projects/_private/pytest-html-issue:/app \
                pytest-sample-project \
                pytest --trace-config
PLUGIN registered: <_pytest.config.PytestPluginManager object at 0xffff9f9ab8d0>
PLUGIN registered: <_pytest.config.Config object at 0xffff9f910250>
PLUGIN registered: <module '_pytest.mark' from '/usr/local/lib/python3.11/dist-packages/_pytest/mark/__init__.py'>
PLUGIN registered: <module '_pytest.main' from '/usr/local/lib/python3.11/dist-packages/_pytest/main.py'>
PLUGIN registered: <module '_pytest.runner' from '/usr/local/lib/python3.11/dist-packages/_pytest/runner.py'>
PLUGIN registered: <module '_pytest.fixtures' from '/usr/local/lib/python3.11/dist-packages/_pytest/fixtures.py'>
PLUGIN registered: <module '_pytest.helpconfig' from '/usr/local/lib/python3.11/dist-packages/_pytest/helpconfig.py'>
PLUGIN registered: <module '_pytest.python' from '/usr/local/lib/python3.11/dist-packages/_pytest/python.py'>
PLUGIN registered: <module '_pytest.terminal' from '/usr/local/lib/python3.11/dist-packages/_pytest/terminal.py'>
PLUGIN registered: <module '_pytest.debugging' from '/usr/local/lib/python3.11/dist-packages/_pytest/debugging.py'>
PLUGIN registered: <module '_pytest.unittest' from '/usr/local/lib/python3.11/dist-packages/_pytest/unittest.py'>
PLUGIN registered: <module '_pytest.capture' from '/usr/local/lib/python3.11/dist-packages/_pytest/capture.py'>
PLUGIN registered: <module '_pytest.skipping' from '/usr/local/lib/python3.11/dist-packages/_pytest/skipping.py'>
PLUGIN registered: <module '_pytest.legacypath' from '/usr/local/lib/python3.11/dist-packages/_pytest/legacypath.py'>
PLUGIN registered: <module '_pytest.tmpdir' from '/usr/local/lib/python3.11/dist-packages/_pytest/tmpdir.py'>
PLUGIN registered: <module '_pytest.monkeypatch' from '/usr/local/lib/python3.11/dist-packages/_pytest/monkeypatch.py'>
PLUGIN registered: <module '_pytest.recwarn' from '/usr/local/lib/python3.11/dist-packages/_pytest/recwarn.py'>
PLUGIN registered: <module '_pytest.pastebin' from '/usr/local/lib/python3.11/dist-packages/_pytest/pastebin.py'>
PLUGIN registered: <module '_pytest.nose' from '/usr/local/lib/python3.11/dist-packages/_pytest/nose.py'>
PLUGIN registered: <module '_pytest.assertion' from '/usr/local/lib/python3.11/dist-packages/_pytest/assertion/__init__.py'>
PLUGIN registered: <module '_pytest.junitxml' from '/usr/local/lib/python3.11/dist-packages/_pytest/junitxml.py'>
PLUGIN registered: <module '_pytest.doctest' from '/usr/local/lib/python3.11/dist-packages/_pytest/doctest.py'>
PLUGIN registered: <module '_pytest.cacheprovider' from '/usr/local/lib/python3.11/dist-packages/_pytest/cacheprovider.py'>
PLUGIN registered: <module '_pytest.freeze_support' from '/usr/local/lib/python3.11/dist-packages/_pytest/freeze_support.py'>
PLUGIN registered: <module '_pytest.setuponly' from '/usr/local/lib/python3.11/dist-packages/_pytest/setuponly.py'>
PLUGIN registered: <module '_pytest.setupplan' from '/usr/local/lib/python3.11/dist-packages/_pytest/setupplan.py'>
PLUGIN registered: <module '_pytest.stepwise' from '/usr/local/lib/python3.11/dist-packages/_pytest/stepwise.py'>
PLUGIN registered: <module '_pytest.warnings' from '/usr/local/lib/python3.11/dist-packages/_pytest/warnings.py'>
PLUGIN registered: <module '_pytest.logging' from '/usr/local/lib/python3.11/dist-packages/_pytest/logging.py'>
PLUGIN registered: <module '_pytest.reports' from '/usr/local/lib/python3.11/dist-packages/_pytest/reports.py'>
PLUGIN registered: <module '_pytest.python_path' from '/usr/local/lib/python3.11/dist-packages/_pytest/python_path.py'>
PLUGIN registered: <module '_pytest.unraisableexception' from '/usr/local/lib/python3.11/dist-packages/_pytest/unraisableexception.py'>
PLUGIN registered: <module '_pytest.threadexception' from '/usr/local/lib/python3.11/dist-packages/_pytest/threadexception.py'>
PLUGIN registered: <module '_pytest.faulthandler' from '/usr/local/lib/python3.11/dist-packages/_pytest/faulthandler.py'>
PLUGIN registered: <module 'anyio.pytest_plugin' from '/usr/local/lib/python3.11/dist-packages/anyio/pytest_plugin.py'>
PLUGIN registered: <module 'pytest_metadata.plugin' from '/usr/local/lib/python3.11/dist-packages/pytest_metadata/plugin.py'>
PLUGIN registered: <module 'pytest_html.plugin' from '/usr/local/lib/python3.11/dist-packages/pytest_html/plugin.py'>
PLUGIN registered: <module 'pytest_html.fixtures' from '/usr/local/lib/python3.11/dist-packages/pytest_html/fixtures.py'>
PLUGIN registered: <CaptureManager _method='fd' _global_capturing=<MultiCapture out=<FDCapture 1 oldfd=5 _state='suspended' tmpfile=<_io.TextIOWrapper name="<_io.FileIO name=6 mode='rb+' closefd=True>" mode='r+' encoding='utf-8'>> err=<FDCapture 2 oldfd=7 _state='suspended' tmpfile=<_io.TextIOWrapper name="<_io.FileIO name=8 mode='rb+' closefd=True>" mode='r+' encoding='utf-8'>> in_=<FDCapture 0 oldfd=3 _state='started' tmpfile=<_io.TextIOWrapper name='/dev/null' mode='r' encoding='utf-8'>> _state='suspended' _in_suspended=False> _capture_fixture=None>
PLUGIN registered: <Session app exitstatus=<ExitCode.OK: 0> testsfailed=0 testscollected=0>
PLUGIN registered: <_pytest.cacheprovider.LFPlugin object at 0xffff9ec8da90>
PLUGIN registered: <_pytest.cacheprovider.NFPlugin object at 0xffff9ecaec10>
PLUGIN registered: <pytest_html.selfcontained_report.SelfContainedReport object at 0xffff9eeabb50>
PLUGIN registered: <class '_pytest.legacypath.LegacyTmpdirPlugin'>
PLUGIN registered: <_pytest.terminal.TerminalReporter object at 0xffff9ecb6910>
PLUGIN registered: <_pytest.logging.LoggingPlugin object at 0xffff9ef57e50>
PLUGIN registered: <_pytest.fixtures.FixtureManager object at 0xffff9ecca5d0>
============================= test session starts ==============================
platform linux -- Python 3.11.13, pytest-7.4.4, pluggy-1.6.0
using: pytest-7.4.4
setuptools registered plugins:
  anyio-4.10.0 at /usr/local/lib/python3.11/dist-packages/anyio/pytest_plugin.py
  pytest-metadata-3.1.1 at /usr/local/lib/python3.11/dist-packages/pytest_metadata/plugin.py
  pytest-html-4.1.1 at /usr/local/lib/python3.11/dist-packages/pytest_html/plugin.py
  pytest-html-4.1.1 at /usr/local/lib/python3.11/dist-packages/pytest_html/fixtures.py
active plugins:
    281473359460560     : <_pytest.config.PytestPluginManager object at 0xffff9f9ab8d0>
    pytestconfig        : <_pytest.config.Config object at 0xffff9f910250>
    mark                : /usr/local/lib/python3.11/dist-packages/_pytest/mark/__init__.py
    main                : /usr/local/lib/python3.11/dist-packages/_pytest/main.py
    runner              : /usr/local/lib/python3.11/dist-packages/_pytest/runner.py
    fixtures            : /usr/local/lib/python3.11/dist-packages/_pytest/fixtures.py
    helpconfig          : /usr/local/lib/python3.11/dist-packages/_pytest/helpconfig.py
    python              : /usr/local/lib/python3.11/dist-packages/_pytest/python.py
    terminal            : /usr/local/lib/python3.11/dist-packages/_pytest/terminal.py
    debugging           : /usr/local/lib/python3.11/dist-packages/_pytest/debugging.py
    unittest            : /usr/local/lib/python3.11/dist-packages/_pytest/unittest.py
    capture             : /usr/local/lib/python3.11/dist-packages/_pytest/capture.py
    skipping            : /usr/local/lib/python3.11/dist-packages/_pytest/skipping.py
    legacypath          : /usr/local/lib/python3.11/dist-packages/_pytest/legacypath.py
    tmpdir              : /usr/local/lib/python3.11/dist-packages/_pytest/tmpdir.py
    monkeypatch         : /usr/local/lib/python3.11/dist-packages/_pytest/monkeypatch.py
    recwarn             : /usr/local/lib/python3.11/dist-packages/_pytest/recwarn.py
    pastebin            : /usr/local/lib/python3.11/dist-packages/_pytest/pastebin.py
    nose                : /usr/local/lib/python3.11/dist-packages/_pytest/nose.py
    assertion           : /usr/local/lib/python3.11/dist-packages/_pytest/assertion/__init__.py
    junitxml            : /usr/local/lib/python3.11/dist-packages/_pytest/junitxml.py
    doctest             : /usr/local/lib/python3.11/dist-packages/_pytest/doctest.py
    cacheprovider       : /usr/local/lib/python3.11/dist-packages/_pytest/cacheprovider.py
    freeze_support      : /usr/local/lib/python3.11/dist-packages/_pytest/freeze_support.py
    setuponly           : /usr/local/lib/python3.11/dist-packages/_pytest/setuponly.py
    setupplan           : /usr/local/lib/python3.11/dist-packages/_pytest/setupplan.py
    stepwise            : /usr/local/lib/python3.11/dist-packages/_pytest/stepwise.py
    warnings            : /usr/local/lib/python3.11/dist-packages/_pytest/warnings.py
    logging             : /usr/local/lib/python3.11/dist-packages/_pytest/logging.py
    reports             : /usr/local/lib/python3.11/dist-packages/_pytest/reports.py
    python_path         : /usr/local/lib/python3.11/dist-packages/_pytest/python_path.py
    unraisableexception : /usr/local/lib/python3.11/dist-packages/_pytest/unraisableexception.py
    threadexception     : /usr/local/lib/python3.11/dist-packages/_pytest/threadexception.py
    faulthandler        : /usr/local/lib/python3.11/dist-packages/_pytest/faulthandler.py
    anyio               : /usr/local/lib/python3.11/dist-packages/anyio/pytest_plugin.py
    metadata            : /usr/local/lib/python3.11/dist-packages/pytest_metadata/plugin.py
    html                : /usr/local/lib/python3.11/dist-packages/pytest_html/plugin.py
    html_fixtures       : /usr/local/lib/python3.11/dist-packages/pytest_html/fixtures.py
    capturemanager      : <CaptureManager _method='fd' _global_capturing=<MultiCapture out=<FDCapture 1 oldfd=5 _state='suspended' tmpfile=<_io.TextIOWrapper name="<_io.FileIO name=6 mode='rb+' closefd=True>" mode='r+' encoding='utf-8'>> err=<FDCapture 2 oldfd=7 _state='suspended' tmpfile=<_io.TextIOWrapper name="<_io.FileIO name=8 mode='rb+' closefd=True>" mode='r+' encoding='utf-8'>> in_=<FDCapture 0 oldfd=3 _state='started' tmpfile=<_io.TextIOWrapper name='/dev/null' mode='r' encoding='utf-8'>> _state='suspended' _in_suspended=False> _capture_fixture=None>
    session             : <Session app exitstatus=<ExitCode.OK: 0> testsfailed=0 testscollected=0>
    lfplugin            : <_pytest.cacheprovider.LFPlugin object at 0xffff9ec8da90>
    nfplugin            : <_pytest.cacheprovider.NFPlugin object at 0xffff9ecaec10>
    281473347926864     : <pytest_html.selfcontained_report.SelfContainedReport object at 0xffff9eeabb50>
    legacypath-tmpdir   : <class '_pytest.legacypath.LegacyTmpdirPlugin'>
    terminalreporter    : <_pytest.terminal.TerminalReporter object at 0xffff9ecb6910>
    logging-plugin      : <_pytest.logging.LoggingPlugin object at 0xffff9ef57e50>
    funcmanage          : <_pytest.fixtures.FixtureManager object at 0xffff9ecca5d0>
rootdir: /app
configfile: pytest.ini
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
PLUGIN registered: <module 'conftest' from '/app/src/conftest.py'>
collected 3 items

src/tests/test_sample.py .3️⃣ pytest_html_results_table_row
3️⃣ pytest_html_results_table_row
3️⃣ pytest_html_results_table_row
.3️⃣ pytest_html_results_table_row
3️⃣ pytest_html_results_table_row
3️⃣ pytest_html_results_table_row
.3️⃣ pytest_html_results_table_row
3️⃣ pytest_html_results_table_row
3️⃣ pytest_html_results_table_row
                                             [100%]

------------ Generated html report: file:///app/output/report.html -------------
============================== 3 passed in 0.01s ===============================

Case 2: Working Correctly ✅

In this structure, all hooks fire as expected.

  • Directory Structure:

    .
    ├── pytest.ini
    └── tests
        ├── conftest.py  <-- Hooks defined here
        └── test_sample.py
    
  • Observation: The report title is changed, and the "Duration" header and cells are removed correctly.

  • Log (pytest --trace-config):

$ make test                                    
docker run --rm \
                -v /Users/fujisawakoki/projects/_private/pytest-html-issue:/app \
                pytest-sample-project \
                pytest --trace-config
PLUGIN registered: <_pytest.config.PytestPluginManager object at 0xffff9fb7b8d0>
PLUGIN registered: <_pytest.config.Config object at 0xffff9fae0250>
PLUGIN registered: <module '_pytest.mark' from '/usr/local/lib/python3.11/dist-packages/_pytest/mark/__init__.py'>
PLUGIN registered: <module '_pytest.main' from '/usr/local/lib/python3.11/dist-packages/_pytest/main.py'>
PLUGIN registered: <module '_pytest.runner' from '/usr/local/lib/python3.11/dist-packages/_pytest/runner.py'>
PLUGIN registered: <module '_pytest.fixtures' from '/usr/local/lib/python3.11/dist-packages/_pytest/fixtures.py'>
PLUGIN registered: <module '_pytest.helpconfig' from '/usr/local/lib/python3.11/dist-packages/_pytest/helpconfig.py'>
PLUGIN registered: <module '_pytest.python' from '/usr/local/lib/python3.11/dist-packages/_pytest/python.py'>
PLUGIN registered: <module '_pytest.terminal' from '/usr/local/lib/python3.11/dist-packages/_pytest/terminal.py'>
PLUGIN registered: <module '_pytest.debugging' from '/usr/local/lib/python3.11/dist-packages/_pytest/debugging.py'>
PLUGIN registered: <module '_pytest.unittest' from '/usr/local/lib/python3.11/dist-packages/_pytest/unittest.py'>
PLUGIN registered: <module '_pytest.capture' from '/usr/local/lib/python3.11/dist-packages/_pytest/capture.py'>
PLUGIN registered: <module '_pytest.skipping' from '/usr/local/lib/python3.11/dist-packages/_pytest/skipping.py'>
PLUGIN registered: <module '_pytest.legacypath' from '/usr/local/lib/python3.11/dist-packages/_pytest/legacypath.py'>
PLUGIN registered: <module '_pytest.tmpdir' from '/usr/local/lib/python3.11/dist-packages/_pytest/tmpdir.py'>
PLUGIN registered: <module '_pytest.monkeypatch' from '/usr/local/lib/python3.11/dist-packages/_pytest/monkeypatch.py'>
PLUGIN registered: <module '_pytest.recwarn' from '/usr/local/lib/python3.11/dist-packages/_pytest/recwarn.py'>
PLUGIN registered: <module '_pytest.pastebin' from '/usr/local/lib/python3.11/dist-packages/_pytest/pastebin.py'>
PLUGIN registered: <module '_pytest.nose' from '/usr/local/lib/python3.11/dist-packages/_pytest/nose.py'>
PLUGIN registered: <module '_pytest.assertion' from '/usr/local/lib/python3.11/dist-packages/_pytest/assertion/__init__.py'>
PLUGIN registered: <module '_pytest.junitxml' from '/usr/local/lib/python3.11/dist-packages/_pytest/junitxml.py'>
PLUGIN registered: <module '_pytest.doctest' from '/usr/local/lib/python3.11/dist-packages/_pytest/doctest.py'>
PLUGIN registered: <module '_pytest.cacheprovider' from '/usr/local/lib/python3.11/dist-packages/_pytest/cacheprovider.py'>
PLUGIN registered: <module '_pytest.freeze_support' from '/usr/local/lib/python3.11/dist-packages/_pytest/freeze_support.py'>
PLUGIN registered: <module '_pytest.setuponly' from '/usr/local/lib/python3.11/dist-packages/_pytest/setuponly.py'>
PLUGIN registered: <module '_pytest.setupplan' from '/usr/local/lib/python3.11/dist-packages/_pytest/setupplan.py'>
PLUGIN registered: <module '_pytest.stepwise' from '/usr/local/lib/python3.11/dist-packages/_pytest/stepwise.py'>
PLUGIN registered: <module '_pytest.warnings' from '/usr/local/lib/python3.11/dist-packages/_pytest/warnings.py'>
PLUGIN registered: <module '_pytest.logging' from '/usr/local/lib/python3.11/dist-packages/_pytest/logging.py'>
PLUGIN registered: <module '_pytest.reports' from '/usr/local/lib/python3.11/dist-packages/_pytest/reports.py'>
PLUGIN registered: <module '_pytest.python_path' from '/usr/local/lib/python3.11/dist-packages/_pytest/python_path.py'>
PLUGIN registered: <module '_pytest.unraisableexception' from '/usr/local/lib/python3.11/dist-packages/_pytest/unraisableexception.py'>
PLUGIN registered: <module '_pytest.threadexception' from '/usr/local/lib/python3.11/dist-packages/_pytest/threadexception.py'>
PLUGIN registered: <module '_pytest.faulthandler' from '/usr/local/lib/python3.11/dist-packages/_pytest/faulthandler.py'>
PLUGIN registered: <module 'anyio.pytest_plugin' from '/usr/local/lib/python3.11/dist-packages/anyio/pytest_plugin.py'>
PLUGIN registered: <module 'pytest_metadata.plugin' from '/usr/local/lib/python3.11/dist-packages/pytest_metadata/plugin.py'>
PLUGIN registered: <module 'pytest_html.plugin' from '/usr/local/lib/python3.11/dist-packages/pytest_html/plugin.py'>
PLUGIN registered: <module 'pytest_html.fixtures' from '/usr/local/lib/python3.11/dist-packages/pytest_html/fixtures.py'>
PLUGIN registered: <CaptureManager _method='fd' _global_capturing=<MultiCapture out=<FDCapture 1 oldfd=5 _state='suspended' tmpfile=<_io.TextIOWrapper name="<_io.FileIO name=6 mode='rb+' closefd=True>" mode='r+' encoding='utf-8'>> err=<FDCapture 2 oldfd=7 _state='suspended' tmpfile=<_io.TextIOWrapper name="<_io.FileIO name=8 mode='rb+' closefd=True>" mode='r+' encoding='utf-8'>> in_=<FDCapture 0 oldfd=3 _state='started' tmpfile=<_io.TextIOWrapper name='/dev/null' mode='r' encoding='utf-8'>> _state='suspended' _in_suspended=False> _capture_fixture=None>
PLUGIN registered: <module 'conftest' from '/app/tests/conftest.py'>
PLUGIN registered: <Session app exitstatus=<ExitCode.OK: 0> testsfailed=0 testscollected=0>
PLUGIN registered: <_pytest.cacheprovider.LFPlugin object at 0xffffa04b4710>
PLUGIN registered: <_pytest.cacheprovider.NFPlugin object at 0xffff9ee41150>
PLUGIN registered: <pytest_html.selfcontained_report.SelfContainedReport object at 0xffffa064e1d0>
PLUGIN registered: <class '_pytest.legacypath.LegacyTmpdirPlugin'>
PLUGIN registered: <_pytest.terminal.TerminalReporter object at 0xffff9ee47490>
PLUGIN registered: <_pytest.logging.LoggingPlugin object at 0xffff9ee3fcd0>
PLUGIN registered: <_pytest.fixtures.FixtureManager object at 0xffff9ee50110>
1️⃣ pytest_html_report_title
2️⃣ pytest_html_results_table_header
============================= test session starts ==============================
platform linux -- Python 3.11.13, pytest-7.4.4, pluggy-1.6.0
using: pytest-7.4.4
setuptools registered plugins:
  anyio-4.10.0 at /usr/local/lib/python3.11/dist-packages/anyio/pytest_plugin.py
  pytest-metadata-3.1.1 at /usr/local/lib/python3.11/dist-packages/pytest_metadata/plugin.py
  pytest-html-4.1.1 at /usr/local/lib/python3.11/dist-packages/pytest_html/plugin.py
  pytest-html-4.1.1 at /usr/local/lib/python3.11/dist-packages/pytest_html/fixtures.py
active plugins:
    281473361361104     : <_pytest.config.PytestPluginManager object at 0xffff9fb7b8d0>
    pytestconfig        : <_pytest.config.Config object at 0xffff9fae0250>
    mark                : /usr/local/lib/python3.11/dist-packages/_pytest/mark/__init__.py
    main                : /usr/local/lib/python3.11/dist-packages/_pytest/main.py
    runner              : /usr/local/lib/python3.11/dist-packages/_pytest/runner.py
    fixtures            : /usr/local/lib/python3.11/dist-packages/_pytest/fixtures.py
    helpconfig          : /usr/local/lib/python3.11/dist-packages/_pytest/helpconfig.py
    python              : /usr/local/lib/python3.11/dist-packages/_pytest/python.py
    terminal            : /usr/local/lib/python3.11/dist-packages/_pytest/terminal.py
    debugging           : /usr/local/lib/python3.11/dist-packages/_pytest/debugging.py
    unittest            : /usr/local/lib/python3.11/dist-packages/_pytest/unittest.py
    capture             : /usr/local/lib/python3.11/dist-packages/_pytest/capture.py
    skipping            : /usr/local/lib/python3.11/dist-packages/_pytest/skipping.py
    legacypath          : /usr/local/lib/python3.11/dist-packages/_pytest/legacypath.py
    tmpdir              : /usr/local/lib/python3.11/dist-packages/_pytest/tmpdir.py
    monkeypatch         : /usr/local/lib/python3.11/dist-packages/_pytest/monkeypatch.py
    recwarn             : /usr/local/lib/python3.11/dist-packages/_pytest/recwarn.py
    pastebin            : /usr/local/lib/python3.11/dist-packages/_pytest/pastebin.py
    nose                : /usr/local/lib/python3.11/dist-packages/_pytest/nose.py
    assertion           : /usr/local/lib/python3.11/dist-packages/_pytest/assertion/__init__.py
    junitxml            : /usr/local/lib/python3.11/dist-packages/_pytest/junitxml.py
    doctest             : /usr/local/lib/python3.11/dist-packages/_pytest/doctest.py
    cacheprovider       : /usr/local/lib/python3.11/dist-packages/_pytest/cacheprovider.py
    freeze_support      : /usr/local/lib/python3.11/dist-packages/_pytest/freeze_support.py
    setuponly           : /usr/local/lib/python3.11/dist-packages/_pytest/setuponly.py
    setupplan           : /usr/local/lib/python3.11/dist-packages/_pytest/setupplan.py
    stepwise            : /usr/local/lib/python3.11/dist-packages/_pytest/stepwise.py
    warnings            : /usr/local/lib/python3.11/dist-packages/_pytest/warnings.py
    logging             : /usr/local/lib/python3.11/dist-packages/_pytest/logging.py
    reports             : /usr/local/lib/python3.11/dist-packages/_pytest/reports.py
    python_path         : /usr/local/lib/python3.11/dist-packages/_pytest/python_path.py
    unraisableexception : /usr/local/lib/python3.11/dist-packages/_pytest/unraisableexception.py
    threadexception     : /usr/local/lib/python3.11/dist-packages/_pytest/threadexception.py
    faulthandler        : /usr/local/lib/python3.11/dist-packages/_pytest/faulthandler.py
    anyio               : /usr/local/lib/python3.11/dist-packages/anyio/pytest_plugin.py
    metadata            : /usr/local/lib/python3.11/dist-packages/pytest_metadata/plugin.py
    html                : /usr/local/lib/python3.11/dist-packages/pytest_html/plugin.py
    html_fixtures       : /usr/local/lib/python3.11/dist-packages/pytest_html/fixtures.py
    capturemanager      : <CaptureManager _method='fd' _global_capturing=<MultiCapture out=<FDCapture 1 oldfd=5 _state='suspended' tmpfile=<_io.TextIOWrapper name="<_io.FileIO name=6 mode='rb+' closefd=True>" mode='r+' encoding='utf-8'>> err=<FDCapture 2 oldfd=7 _state='suspended' tmpfile=<_io.TextIOWrapper name="<_io.FileIO name=8 mode='rb+' closefd=True>" mode='r+' encoding='utf-8'>> in_=<FDCapture 0 oldfd=3 _state='started' tmpfile=<_io.TextIOWrapper name='/dev/null' mode='r' encoding='utf-8'>> _state='suspended' _in_suspended=False> _capture_fixture=None>
    /app/tests/conftest.py: /app/tests/conftest.py
    session             : <Session app exitstatus=<ExitCode.OK: 0> testsfailed=0 testscollected=0>
    lfplugin            : <_pytest.cacheprovider.LFPlugin object at 0xffffa04b4710>
    nfplugin            : <_pytest.cacheprovider.NFPlugin object at 0xffff9ee41150>
    281473372709328     : <pytest_html.selfcontained_report.SelfContainedReport object at 0xffffa064e1d0>
    legacypath-tmpdir   : <class '_pytest.legacypath.LegacyTmpdirPlugin'>
    terminalreporter    : <_pytest.terminal.TerminalReporter object at 0xffff9ee47490>
    logging-plugin      : <_pytest.logging.LoggingPlugin object at 0xffff9ee3fcd0>
    funcmanage          : <_pytest.fixtures.FixtureManager object at 0xffff9ee50110>
rootdir: /app
configfile: pytest.ini
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 3 items

tests/test_sample.py .3️⃣ pytest_html_results_table_row
3️⃣ pytest_html_results_table_row
3️⃣ pytest_html_results_table_row
.3️⃣ pytest_html_results_table_row
3️⃣ pytest_html_results_table_row
3️⃣ pytest_html_results_table_row
.3️⃣ pytest_html_results_table_row
3️⃣ pytest_html_results_table_row
3️⃣ pytest_html_results_table_row
                                                 [100%]

------------ Generated html report: file:///app/output/report.html -------------
============================== 3 passed in 0.01s ===============================

Expected Behavior

I would expect all hooks defined in a discovered conftest.py to be honored, regardless of its depth in the directory tree, especially if pytest is successfully collecting and running tests from that location.

If this is the intended design of pytest, it might be beneficial for pytest-html to include a note in the documentation about the placement of conftest.py for session-level hooks.

Environment

  • OS: Ubuntu 22.04 (in Docker)
  • Python version: 3.11.4
  • pytest version: 7.4.4
  • pytest-html version: 4.1.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions