Repository navigation
Conversation
configure_logging returned early whenever the 'pretab' logger had any real handler, so it could not tell PreTab's own stream handler from a host's. The first configuration pinned the level for the rest of the process (a later verbose=2 fit only printed the level-1 summary), and under a host-configured root logger (logging.basicConfig) PreTab still added its own handler, so every line was printed twice. PreTab now marks the handler it attaches. A host handler on the 'pretab' logger still makes the call a no-op; otherwise the level is always applied and PreTab's handler is reused, not duplicated. When a host handler on an ancestor already receives the records, no handler is attached and one attached earlier is removed. get_feature_info() no longer lowers a DEBUG level set earlier. The verbose and get_feature_info docstrings and the fit-time logging section of the outputs and inspection guide describe the new behaviour. Fixes #67
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #67.
Only the first
configure_loggingcall in a process set the verbosity, so after averbose=1fit or a defaultget_feature_info()call, laterverbose=2/verbose=3fits printed only the level-1 summary. Under a host-configured root logger (logging.basicConfig), every PreTab line was printed twice.Root cause
configure_loggingreturned early whenever_has_real_handlerfound a non-NullHandlerhandler on the"pretab"logger. That included theStreamHandleran earlier call had attached, and the early return also skippedset_verbosity(level)._has_real_handlerlooked only at the"pretab"logger itself, not at ancestor handlers that receive its records through propagation, so PreTab added its own handler next to a root handler.Fix
configure_logging(pretab/core/logging.py) marks the handler it attaches with a_pretab_own_handlerattribute._has_real_handlernow counts only host handlers (_is_host_handler: neither aNullHandlernor PreTab's own)."pretab"logger still makes the call a no-op. Otherwise the level is applied on every call, and PreTab's own handler is reused instead of a second one being added._ancestor_has_real_handlerwalks up the parent loggers whilepropagateis true. When a host handler there receives the records,configure_loggingattaches no handler and removes one it attached earlier.Preprocessor.get_feature_info(verbose=True)callsconfigure_logging(2)when DEBUG is already enabled, elseconfigure_logging(1). Now that later calls change the level, rendering the table would otherwise lower a more verbose level.Behaviour changes
verboselevel, so a laterverbose=2/verbose=3fit logs the per-feature table and internal decisions after an earlier, less verbose configuration. Repeatedconfigure_logging(level)calls update the"pretab"logger level.logging.basicConfig, PreTab attaches no stream handler and removes one it attached earlier. Messages appear once, through the host's handler and format (INFO:pretab.preprocessor:...). The"pretab"logger level is still set.configure_logging(handler=...)counts as PreTab's own: later calls reuse it, and it is removed once a host handler on an ancestor receives the records.get_feature_info()no longer lowers a DEBUG level set earlier (for example byset_verbosity(2)) to INFO.Documentation
configure_loggingdocstring: the call is a no-op only for a host handler on the"pretab"logger; repeated calls update the level and reuse PreTab's handler; with a host handler on an ancestor, no handler is attached and one attached earlier is removed.Preprocessordocstring,verboseparameter: a host handler on the"pretab"logger or on an ancestor (a root handler fromlogging.basicConfig) takes over, and each fit applies its own level.Preprocessor.get_feature_infodocstring,verboseparameter: a handler is attached only when no host handler receives the records, and a more verbose level is kept.docs/core_concepts/outputs_and_inspection.md("Fit-time logging"): new paragraph on per-fit levels and host handlers.Tests
test_configure_logging_raises_the_level_on_later_calls: a second call sets DEBUG and leaves exactly one PreTab handler. Fails onmain, passes here.test_fit_verbose_2_after_verbose_1_logs_the_feature_table: averbose=2fit after averbose=1fit writes the per-feature table to stderr. Fails onmain, passes here.test_configure_logging_defers_to_a_root_handler: with a rootStreamHandler, averbose=1fit logs "fit complete" exactly once through it, nothing on stderr, and attaches no PreTab handler. Fails onmain, passes here.test_configure_logging_hands_over_to_a_host_configured_later: PreTab's handler is removed once a root handler appears. Fails onmain, passes here.test_get_feature_info_does_not_lower_a_debug_level:get_feature_info()afterconfigure_logging(2)keeps DEBUG. Guard test: passes on both by design (mainnever changes the first level); it fails with theconfigure_loggingchange alone, without theget_feature_infochange._root_handlershelper runs a test body with a given set of root handlers, because pytest's capture handlers on the root logger would otherwise count as a host handler. The existingtest_configure_logging_attaches_stream_handler_when_nonenow runs inside it.Reproduction
Output of the script from #67 on this branch:
Each problem runs in a fresh process, as in the issue.
Checks
just test: 1443 passed, 59 skipped, 7 xfailed; coverage 93.69% (gate 90%).scripts/quickstart.pypasses.just docs: strict build succeeds.just check: all pre-commit and pre-push hooks pass (ruff format, ruff lint, prettier, file hygiene, pyright with 0 errors).Merge notes
main.This change was previously part of #75, which is closed in favour of one pull request per issue.