Refactoring the logging module #5367
Conversation
Need to add a fmt_string parameter if want to replicate earlier behavior
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #5367 +/- ##
===========================================
- Coverage 93.84% 93.84% -0.01%
===========================================
Files 182 182
Lines 22497 22495 -2
Branches 3200 3202 +2
===========================================
- Hits 21113 21111 -2
Misses 922 922
Partials 462 462 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Can I ask for some feedback here? I feel this code here is fairly straightforward and readable, and it preserves existing behavior of the old code as well. I'm a bit confused on where to write the tests. There are two |
|
I also need to write docs as well |
| create( | ||
| "MDAnalysis", | ||
| stream=stream, | ||
| level="DEBUG", | ||
| fmt="%(asctime)s %(name)-12s %(levelname)-8s %(message)s", | ||
| ) | ||
| create( | ||
| "MDAnalysis", | ||
| stream=sys.stdout, | ||
| level="INFO", | ||
| fmt="%(name)-12s: %(levelname)-8s %(message)s", | ||
| ) |
There was a problem hiding this comment.
All of this is intend to replicate old behavior from the original.
| @@ -112,7 +120,9 @@ def stop_logging(): | |||
| clear_handlers(logger) # this _should_ do the job... | |||
|
|
|||
|
|
|||
There was a problem hiding this comment.
In general, I guess this PR make create() a more general type of function which add handlers to a master logger, so should it get renamed?
There was a problem hiding this comment.
Probably yes to renaming, but you'd need to
- deprecate the old function
- schedule for removal in 3.0.0
because we're following semantic versioning https://semver.org and we cannot remove documented functionality in a public function until we make a new major release.
Similarly, we cannot just rename kwargs in a public function like create(). You have to keep the old one around and deprecated them.
There was a problem hiding this comment.
Probably should raise an issue of it as well
orbeckst
left a comment
There was a problem hiding this comment.
Overall this looks good and does not generate a lot more code. I'd be supportive of the change.
You'll need to deprecate kwargs if you change them. ALternatively, leave them and say in the docs that "logfile" can be any file-like or stream-like object.
I see that's WIP so you know that you'll also eventually need docs, tests, and CHANGELOG.
|
|
||
|
|
||
| def start_logging(logfile="MDAnalysis.log", version=version.__version__): | ||
| def start_logging(stream="MDAnalysis.log", version=version.__version__): |
There was a problem hiding this comment.
Under semantic versioning, you need to maintain backwards compatibility. So something like
def start_logging(stream="MDAnalysis.log", logfile=None, version=version.__version__):
if logfile is not None:
warnings.warn(DeprecationWarning, "logfile kwarg will be removed in MDAnalysis 3.0.0, use stream instead"
# we probably have a dedicated function for the deprecation warning...
stream = logfile
...|
|
||
| def create(logger_name="MDAnalysis", logfile="MDAnalysis.log"): | ||
| def create( | ||
| logger_name="MDAnalysis", stream="MDAnalysis.log", level="DEBUG", fmt=None |
There was a problem hiding this comment.
as above, you need to deprecate kwargs if you really want to rename them
|
|
|
Random thing I noticed there are so many unused imports in this module. I think my ide counted at least five modules that weren't be being used but was imported still. |
| class RedirectedStderr(object): | ||
| """Temporarily replaces sys.stderr with *stream*. | ||
|
|
||
| Deals with cached stderr, see | ||
| http://stackoverflow.com/questions/6796492/temporarily-redirect-stdout-stderr | ||
| """ | ||
|
|
||
| def __init__(self, stream=None): | ||
| self._stderr = sys.stderr | ||
| self.stream = stream or sys.stdout | ||
|
|
||
| def __enter__(self): | ||
| self.old_stderr = sys.stderr | ||
| self.old_stderr.flush() | ||
| sys.stderr = self.stream | ||
|
|
||
| def __exit__(self, exc_type, exc_value, traceback): | ||
| self._stderr.flush() | ||
| sys.stderr = self.old_stderr | ||
|
|
||
|
|
||
| @pytest.fixture() | ||
| def buffer(): | ||
| return StringIO() | ||
|
|
||
|
|
||
| def _assert_in(output, string): | ||
| assert ( | ||
| string in output | ||
| ), "Output '{0}' does not match required format '{1}'.".format( | ||
| output.replace("\r", "\\r"), string.replace("\r", "\\r") | ||
| ) |
There was a problem hiding this comment.
If you were to grep -F -r for these functions or classes, they don't exist anywhere else in the testsuite. So they should be removed!
| class NullHandler(logging.Handler): | ||
| """Silent Handler. | ||
|
|
||
| Useful as a default:: | ||
|
|
||
| h = NullHandler() | ||
| logging.getLogger("MDAnalysis").addHandler(h) | ||
| del h | ||
|
|
||
| see the advice on logging and libraries in | ||
| http://docs.python.org/library/logging.html?#configuring-logging-for-a-library | ||
| """ | ||
|
|
||
| def emit(self, record): | ||
| pass | ||
|
|
||
|
|
| def test_start_stop_logging(): | ||
| try: | ||
| MDAnalysis.log.start_logging() | ||
| logger = logging.getLogger("MDAnalysis") | ||
| logger.info("Using the MDAnalysis logger works") | ||
| except Exception as err: | ||
| raise AssertionError("Problem with logger: {0}".format(err)) | ||
| finally: | ||
| MDAnalysis.log.stop_logging() |
There was a problem hiding this comment.
This test doesn't really test functionality or properties of the mda.start/stop_logging() functions. It just tests if the command succeeds. Need a rewrite
| for h in list(logger.handlers): | ||
| logger.removeHandler(h) |
There was a problem hiding this comment.
There's a really subtle bug with the original version. logger.removeHandler(h) mutates the original logger.handlers so it "skips" handlers in the list. Putting in a list creates a copy, so the entire elements get deleted
See test_stop_logging under TestConvenienceFunctions. The original version without list would have failed that test.
Initial draft that address #5357 and #5368. It should be a quick relatively painless change to implement.
Changes made in this Pull Request:
LLM / AI generated code disclosure
LLMs or other AI-powered tools (beyond simple IDE use cases) were used in this contribution: yes / no
PR Checklist
package/CHANGELOGfile updated?package/AUTHORS? (If it is not, add it!)Developers Certificate of Origin
I certify that I can submit this code contribution as described in the Developer Certificate of Origin, under the MDAnalysis LICENSE.
📚 Documentation preview 📚: https://mdanalysis--5367.org.readthedocs.build/en/5367/