Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34k
gh-102402: Fix floating point math issue by using time.time_ns() in logging.LogRecord#102412
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
dougthor42 commented Mar 4, 2023 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
ghost commented Mar 4, 2023 • edited by ghost
Loading Uh oh!
There was an error while loading. Please reload this page.
edited by ghost
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Lib/test/test_logging.py Outdated
| finally: | ||
| time.time_ns=og_time_ns |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: Is there a more preferred way to accomplish this other than monkeypatching time.time_ns?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use unittest.mock.patch as in this example:
importtimefromunittest.mockimportpatchfortin (123, 456, 789): withpatch('time.time_ns') aspatched_ns: patched_ns.return_value=tvalue=time.time_ns() print(f'patched: {value}') print(f'OG: {time.time_ns()}')which should, when run, print something like this:
patched: 123 OG: 1681278183002693921 patched: 456 OG: 1681278183003199141 patched: 789 OG: 1681278183003610801 There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, my assumption was that we probably didn't want to add imports (I don't know why I assumed that...).
Updated to patch with mock instead of manual patching.
dougthor42 commented Mar 5, 2023
I was able to come up with a math approach that is pretty easy to understand. It's also faster. String manipulation:Math:This version is a little faster: |
Uh oh!
There was an error while loading. Please reload this page.
arhadthedev commented Apr 2, 2023
vsajip left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR - minor changes requested.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Lib/test/test_logging.py Outdated
| finally: | ||
| time.time_ns=og_time_ns |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use unittest.mock.patch as in this example:
importtimefromunittest.mockimportpatchfortin (123, 456, 789): withpatch('time.time_ns') aspatched_ns: patched_ns.return_value=tvalue=time.time_ns() print(f'patched: {value}') print(f'OG: {time.time_ns()}')which should, when run, print something like this:
patched: 123 OG: 1681278183002693921 patched: 456 OG: 1681278183003199141 patched: 789 OG: 1681278183003610801 bedevere-bot commented Apr 12, 2023
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
dougthor42 left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have made the requested changes; please review again
Uh oh!
There was an error while loading. Please reload this page.
Lib/test/test_logging.py Outdated
| finally: | ||
| time.time_ns=og_time_ns |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, my assumption was that we probably didn't want to add imports (I don't know why I assumed that...).
Updated to patch with mock instead of manual patching.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
dougthor42 left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @serhiy-storchaka! I've addressed most items but would like more information on the request for additional testing.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
serhiy-storchaka left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. I left only one minor suggestion, which can be ignored if you have other reasons.
Thank you for your contribution, @dougthor42. For a first time contributor, this PR has surprisingly high quality, you did not even make common errors. And I did not expect such good responsibility after months of inactivity. I will be glad to see your other PRs.
Lib/test/test_logging.py Outdated
| withpatch("time.time_ns") aspatched_ns: | ||
| orig_modules=import_helper._save_and_remove_modules(['logging']) | ||
| try: | ||
| # mock for module import | ||
| patched_ns.return_value=ns | ||
| importlogging |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that it can be out of the loop. You only need the following code in the loop:
new_ns=ns+offset_nspatched_ns.return_value=new_nsrecord=logging.makeLogRecord({'msg': 'test'}) self.assertAlmostEqual(record.created, new_ns/1e9, places=6) self.assertAlmostEqual(record.relativeCreated, offset_ns/1e6, places=7)It is just an optimization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. It may be "just an optimization" but I wouldn't consider it a premature optimization. Updated.
Uh oh!
There was an error while loading. Please reload this page.
dougthor42 left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a first time contributor, this PR has surprisingly high quality, you did not even make common errors. And I did not expect such good responsibility after months of inactivity. I will be glad to see your other PRs.
Thanks! I do hope to find more PRs that I can help with (and have the time to help with...)
Lib/test/test_logging.py Outdated
| withpatch("time.time_ns") aspatched_ns: | ||
| orig_modules=import_helper._save_and_remove_modules(['logging']) | ||
| try: | ||
| # mock for module import | ||
| patched_ns.return_value=ns | ||
| importlogging |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. It may be "just an optimization" but I wouldn't consider it a premature optimization. Updated.
vsajip commented Apr 15, 2024
Closing and reopening, as there seems to have been a spurious error. |
vsajip commented Apr 16, 2024
Thank you @dougthor42 for your patience - sorry it dropped off my radar for so long. |
…()` in `logging.LogRecord` (pythonGH-102412)
vstinner commented Apr 17, 2024
This change introduced reference leaks: |
vstinner commented Apr 17, 2024
I suggest to not reimport the logging module in the test: deftest_relativeCreated_has_higher_precision(self): # See issue gh-102402ns=1_677_903_920_000_998_503# approx. 2023-03-04 04:25:20 UTCoffsets_ns= (200, 500, 12_354, 99_999, 1_677_903_456_999_123_456) with (patch("time.time_ns") astime_ns_mock, support.swap_attr(logging, '_startTime', ns)): foroffset_nsinoffsets_ns: # mock for log record creationnew_ns=ns+offset_nstime_ns_mock.return_value=new_nsrecord=logging.makeLogRecord({'msg': 'test'}) self.assertAlmostEqual(record.created, new_ns/1e9, places=6) # After PR gh-102412, precision (places) increases from 3 to 7self.assertAlmostEqual(record.relativeCreated, offset_ns/1e6, places=7) |
vstinner commented Apr 17, 2024 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
I'm happy that my PEP 564 – Add new time functions with nanosecond resolution is used to fix very concrete time rounding issues ;-) |
serhiy-storchaka commented Apr 17, 2024
Could you please open a new issue for the leak? I tried to find the cause, and still have not found it. It is a puzzle. |
vstinner commented Apr 17, 2024
I proposed a fix: #117985 |
dougthor42 commented Apr 17, 2024
Oh no! Sorry that my change caused more work for people 😞. TIL about |
vstinner commented Apr 18, 2024
Buildbots were broken for 1 day. I merged my fix since no better fix was proposed: 8f25cc9 |
gh-102402: Fix floating point math issue by using
time.time_ns()inlogging.LogRecord.logging.LogRecordto usetime.time_ns()instead oftime.time().LogRecord.msecsto be robust against floating point / binary representation arithmetic errorsNotes / Open Questions:
LogRecord.msecsis a float so I kept it that way. Why is it a float even though it always has.0?LogRecord.createdas a float in seconds.logging.__init__so I didn't add any for the new code. Would you like me to add some annotations?I opted to use string manipulation to grab themsecs. I have an integer math-based approach, but it's, IMO, more verbose and harder to read/understand. LMK if you want me to switch back to that (there are still some minor fixes to apply to it).msecs-related bug.Fixes#102402.