Skip to content

Improved logging#252

Merged
rozyczko merged 8 commits into
developfrom
improved_logging
Jun 17, 2026
Merged

Improved logging#252
rozyczko merged 8 commits into
developfrom
improved_logging

Conversation

@rozyczko

Copy link
Copy Markdown
Member

Switched from direct warnings.warn and print statements to Python's standard logging module throughout the codebase.

  • Replaced all uses of warnings.warn and print for runtime and deprecation warnings with appropriate calls to the logging module, using named loggers under the easyscience hierarchy for better control and filtering.

  • Added a new user guide page, controlling-log-output.md, detailing how to suppress, filter, or redirect EasyScience log messages.

  • No global reconfiguration, no default stream handlers, and all loggers inherit configuration, giving users and downstream libraries full control over log output.

@rozyczko rozyczko added [scope] enhancement Adds/improves features (major.MINOR.patch) [priority] medium Normal/default priority [area] base classes Changes to or creation of new base classes labels May 21, 2026
@codecov

codecov Bot commented May 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.87395% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.92%. Comparing base (d4a4c23) to head (1fb8443).
⚠️ Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
src/easyscience/global_object/hugger/property.py 10.00% 9 Missing ⚠️
src/easyscience/fitting/available_minimizers.py 25.00% 3 Missing ⚠️
src/easyscience/legacy/xml.py 0.00% 2 Missing ⚠️
src/easyscience/global_object/undo_redo.py 75.00% 1 Missing ⚠️
src/easyscience/utils/decorators.py 0.00% 1 Missing ⚠️
src/easyscience/variable/parameter.py 0.00% 1 Missing ⚠️
...yscience/variable/parameter_dependency_resolver.py 75.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop     #252      +/-   ##
===========================================
+ Coverage    82.55%   82.92%   +0.37%     
===========================================
  Files           62       62              
  Lines         4946     5084     +138     
===========================================
+ Hits          4083     4216     +133     
- Misses         863      868       +5     
Flag Coverage Δ
integration 43.94% <42.01%> (+0.45%) ⬆️
unittests 82.41% <84.03%> (+1.13%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/easyscience/base_classes/collection_base.py 100.00% <100.00%> (ø)
src/easyscience/base_classes/easy_list.py 96.20% <100.00%> (ø)
src/easyscience/base_classes/obj_base.py 100.00% <100.00%> (ø)
...syscience/fitting/calculators/interface_factory.py 97.27% <100.00%> (+0.02%) ⬆️
src/easyscience/fitting/fitter.py 97.29% <100.00%> (+0.39%) ⬆️
.../easyscience/fitting/minimizers/minimizer_bumps.py 95.95% <100.00%> (-3.52%) ⬇️
...rc/easyscience/fitting/minimizers/minimizer_dfo.py 96.51% <100.00%> (ø)
.../easyscience/fitting/minimizers/minimizer_lmfit.py 97.22% <100.00%> (ø)
src/easyscience/global_object/logger.py 100.00% <100.00%> (+30.00%) ⬆️
src/easyscience/legacy/collection_base.py 97.65% <100.00%> (ø)
... and 8 more

... and 1 file with indirect coverage changes

@rozyczko rozyczko marked this pull request as ready for review May 25, 2026 19:20

@damskii9992 damskii9992 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should have an ADR on the logger to explain why we implemented it, and instructions on how to use it, both when writing to it, and when ignoring it (I guess the last one can simply refer to the .md file you wrote).

Comment on lines +143 to +146
@pytest.fixture(autouse=True)
def _quiet_easyscience():
with global_object.log.at_level(logging.ERROR):
yield

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work? You're only muting the log in the context, so how would this actually mute the log in a test? Wouldn't

global_object.log.set_level('ERROR')

Be better?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

autouse fixture yields inside with at_level(logging.ERROR), so the test body runs within the context and is muted. Your set_level('ERROR') also works and is marginally simpler, but the code is correct

Comment thread docs/docs/user-guide/controlling-log-output.md Outdated
Comment on lines +189 to +191
- **No default stream handlers** — EasyScience does not attach handlers
that write to `stdout` or `stderr`. It only creates log records.
Applications and test frameworks decide where those records go.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this bad? What about users that use easyscience as a standalone fitting package? Do they not see any messages without configuring it? They should . . .

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python's logging.lastResort handler emits WARNINGs and above to stderr when no handlers are
configured, so standalone easyscience users do see warnings/errors out of the box.
Only INFO/DEBUG are hidden without change of setup.

Comment thread src/easyscience/global_object/logger.py Outdated
Comment thread src/easyscience/global_object/logger.py Outdated
upper = stripped.upper()
if upper in _LEVEL_NAME_MAP:
return _LEVEL_NAME_MAP[upper]
return default

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should probably raise in the end. If you try to set a logging level, but make a spelling mistake, we shouldn't silently return the default.
Also, why the hell is the default a separate parameter? Why not just the default of raw? Which probably also should have a better parameter name (level?)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this method probably shouldn't have any defaults . . .

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

silently falling back to a default on a bad value is the right behaviour. You don't want import to crash on a typo'd env var. This is for env var parsing.
FOr public API (set_level/at_level) tthis should raise. I think we need to split the concerns here
Strict parse for the API
lenient parse (default) for env var

Comment thread src/easyscience/fitting/calculators/interface_factory.py
Comment thread src/easyscience/fitting/minimizers/minimizer_bumps.py
Comment thread src/easyscience/fitting/available_minimizers.py
logging.getLogger('easyscience.deprecated').warning(
'Call to deprecated function %s.',
func.__name__,
stacklevel=3,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stacklevel? Is that a feature in the logging module? You haven't used this elsewhere.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stacklevel is a supported kwarg on logging methods and here it correctly points the warning at the caller of the deprecated function.
Not having it elsewhere is a fair point. I'll add it to other deprecation log locations for consistency

Comment thread pyproject.toml Outdated
'COM812', # https://docs.astral.sh/ruff/rules/missing-trailing-comma/
# The following is replaced by 'D'/[tool.ruff.lint.pydocstyle] and [tool.pydoclint]
'DOC', # https://docs.astral.sh/ruff/rules/#pydoclint-doc
# The following is replaced by 'D'/[tool.ruff.lint.pydocstyle] and [tool.pydoclint] 'DOC', # https://docs.astral.sh/ruff/rules/#pydoclint-doc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You also accidentally reverted this to comment out the DOC rule :)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cause pixi run check is messing it up!!!
I need to change it once and for all

@rozyczko

Copy link
Copy Markdown
Member Author

I think we should have an ADR on the logger to explain why we implemented it, and instructions on how to use it, both when writing to it, and when ignoring it (I guess the last one can simply refer to the .md file you wrote).

#277

@rozyczko rozyczko requested a review from damskii9992 June 16, 2026 13:23
@damskii9992 damskii9992 added [area] global_object Anything related to the global_object and removed [area] base classes Changes to or creation of new base classes labels Jun 17, 2026

@damskii9992 damskii9992 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM now with a single addition ;)

Comment thread src/easyscience/global_object/logger.py Outdated
"""Convert a level number or name into a numeric level, raising on an unknown name."""
if isinstance(level, int):
return level
stripped = level.strip()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if level was something else than an int or str?
Since you're using the method in the level setter, you need to check the input type.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. this is called directly from the setter, so isn't guaranteed the right type.

@damskii9992

Copy link
Copy Markdown
Contributor

And don't forget to finalize the ADR suggestion into a real ADR:
#277
And maybe link to the discussions in this PR?

@damskii9992 damskii9992 linked an issue Jun 17, 2026 that may be closed by this pull request
@rozyczko rozyczko merged commit 6efc17e into develop Jun 17, 2026
33 of 34 checks passed
@rozyczko rozyczko deleted the improved_logging branch June 17, 2026 12:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[area] global_object Anything related to the global_object [priority] medium Normal/default priority [scope] enhancement Adds/improves features (major.MINOR.patch)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make logging in core user controlled

2 participants