From 2f046c2ccb45e023f54d5cb27a5eba660bef854a Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Fri, 3 Mar 2023 21:00:17 -0800 Subject: [PATCH 01/22] Add test for 102402 100msecs --- Lib/test/test_logging.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 072056d3722106..63406ea843e603 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4310,6 +4310,24 @@ def test_issue_89047(self): s = f.format(r) self.assertNotIn('.1000', s) + def test_issue_102402_100msecs(self): + # quick hack for sanity check + og_time_ns = time.time_ns + # (time_ns, expected msecs value) + tests = ( + (1_677_902_297_100_000_000, 100.0), # exactly 100ms + (1_677_903_920_999_998_503, 999.0), # rounding up + (1_677_903_920_000_998_503, 0.0), # rounding up + + ) + try: + for ns, want in tests: + time.time_ns = lambda: ns + record = logging.makeLogRecord({'msg': 'test'}) + self.assertEqual(record.msecs, want) + finally: + time.time_ns = og_time_ns + class TestBufferingFormatter(logging.BufferingFormatter): def formatHeader(self, records): From 2460f8847c0bb0bedaeb3f03640e34458d30a198 Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Fri, 3 Mar 2023 21:00:54 -0800 Subject: [PATCH 02/22] Update logging.LogRecord to use time_ns. Fixes gh-102402 --- Lib/logging/__init__.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index 9241d73d0fd03c..f652c6594d348f 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -56,7 +56,7 @@ # #_startTime is used as the base when calculating the relative time of events # -_startTime = time.time() +_startTime = time.time_ns() # #raiseExceptions is used to see if exceptions during handling should be @@ -300,7 +300,7 @@ def __init__(self, name, level, pathname, lineno, """ Initialize a logging record with interesting information. """ - ct = time.time() + ct = time.time_ns() self.name = name self.msg = msg # @@ -339,9 +339,12 @@ def __init__(self, name, level, pathname, lineno, self.stack_info = sinfo self.lineno = lineno self.funcName = func - self.created = ct - self.msecs = int((ct - int(ct)) * 1000) + 0.0 # see gh-89047 - self.relativeCreated = (self.created - _startTime) * 1000 + self.created = ct / 1e9 # ns to float seconds + # nanoseconds for the given second. 5_234_000_000 -> 234_000_000 + # Int math to avoid floating point errors. + nsecs = ct - ((ct // 1_000_000_000) * 1_000_000_000) + self.msecs = float(str(nsecs).zfill(9)[:3]) + self.relativeCreated = (ct - _startTime) / 1e6 if logThreads: self.thread = threading.get_ident() self.threadName = threading.current_thread().name @@ -572,7 +575,7 @@ class Formatter(object): %(lineno)d Source line number where the logging call was issued (if available) %(funcName)s Function name - %(created)f Time when the LogRecord was created (time.time() + %(created)f Time when the LogRecord was created (time.time_ns() / 1e9 return value) %(asctime)s Textual time when the LogRecord was created %(msecs)d Millisecond portion of the creation time From 059f8563495402fedb62b990cb93d81e6571ac9f Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Fri, 3 Mar 2023 21:05:10 -0800 Subject: [PATCH 03/22] Simplify msecs calculation --- Lib/logging/__init__.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index f652c6594d348f..ae02d11cc0f2eb 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -340,10 +340,8 @@ def __init__(self, name, level, pathname, lineno, self.lineno = lineno self.funcName = func self.created = ct / 1e9 # ns to float seconds - # nanoseconds for the given second. 5_234_000_000 -> 234_000_000 - # Int math to avoid floating point errors. - nsecs = ct - ((ct // 1_000_000_000) * 1_000_000_000) - self.msecs = float(str(nsecs).zfill(9)[:3]) + # Grab the nsecs from ct, then the msecs from that + self.msecs = float(str(ct)[-9:][:3]) self.relativeCreated = (ct - _startTime) / 1e6 if logThreads: self.thread = threading.get_ident() From 997bd4157c93058990d07e5ec56ab8ed77435156 Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Fri, 3 Mar 2023 21:13:14 -0800 Subject: [PATCH 04/22] Add blurb --- .../next/Library/2023-03-03-21-13-08.gh-issue-102402.fpkRO1.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-03-03-21-13-08.gh-issue-102402.fpkRO1.rst diff --git a/Misc/NEWS.d/next/Library/2023-03-03-21-13-08.gh-issue-102402.fpkRO1.rst b/Misc/NEWS.d/next/Library/2023-03-03-21-13-08.gh-issue-102402.fpkRO1.rst new file mode 100644 index 00000000000000..fa8f3750b85a6b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-03-21-13-08.gh-issue-102402.fpkRO1.rst @@ -0,0 +1,2 @@ +Adjust ``logging.LogRecord`` to use ``time.time_ns()`` and fix minor bug +related to floating point math. From 2e7cde34a3d9b9220ad2247fa892cf13793623c0 Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Fri, 3 Mar 2023 21:43:29 -0800 Subject: [PATCH 05/22] Fix comments, remove superfluous comment --- Lib/test/test_logging.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 63406ea843e603..7000187e266955 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4311,13 +4311,12 @@ def test_issue_89047(self): self.assertNotIn('.1000', s) def test_issue_102402_100msecs(self): - # quick hack for sanity check og_time_ns = time.time_ns - # (time_ns, expected msecs value) tests = ( + # (time_ns, expected_msecs_value) (1_677_902_297_100_000_000, 100.0), # exactly 100ms - (1_677_903_920_999_998_503, 999.0), # rounding up - (1_677_903_920_000_998_503, 0.0), # rounding up + (1_677_903_920_999_998_503, 999.0), # check truncating doesn't round + (1_677_903_920_000_998_503, 0.0), # check truncating doesn't round ) try: From 411a4211a371386ae81e00074abd2052b396f500 Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Sun, 5 Mar 2023 14:44:00 -0800 Subject: [PATCH 06/22] Switch to math algorithm rather than string manipulation. --- Lib/logging/__init__.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index ae02d11cc0f2eb..2c7e99e7a62a39 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -340,8 +340,13 @@ def __init__(self, name, level, pathname, lineno, self.lineno = lineno self.funcName = func self.created = ct / 1e9 # ns to float seconds - # Grab the nsecs from ct, then the msecs from that - self.msecs = float(str(ct)[-9:][:3]) + + # x // 10**n: Drop the rightmost n digits + # (x // 10**n) * 10**n: "Change" the rightmost n digits to 0s. + # Eg: 55_123_456_789 --> 123_456_789 --> 123 + # Convert to float for historical reasons. + self.msecs = (ct - (ct // 1_000_000_000) * 1_000_000_000) // 1_000_000 + 0.0 + self.relativeCreated = (ct - _startTime) / 1e6 if logThreads: self.thread = threading.get_ident() From d3a1f7891b2ad28cb5bffdf8f9643f58b28afae9 Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Fri, 14 Apr 2023 20:02:17 -0700 Subject: [PATCH 07/22] Correct and update comment --- Lib/logging/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index 2c7e99e7a62a39..45e432f8ec992e 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -343,8 +343,10 @@ def __init__(self, name, level, pathname, lineno, # x // 10**n: Drop the rightmost n digits # (x // 10**n) * 10**n: "Change" the rightmost n digits to 0s. - # Eg: 55_123_456_789 --> 123_456_789 --> 123 - # Convert to float for historical reasons. + # Eg: 55_123_456_789 --> 123_456_789 --> 123_000_000 + # Lastly divide by 1e6 to change ns to ms + # 123_000_000 --> 123 + # Convert to float by adding 0.0 for historical reasons. self.msecs = (ct - (ct // 1_000_000_000) * 1_000_000_000) // 1_000_000 + 0.0 self.relativeCreated = (ct - _startTime) / 1e6 From 5fa370bb331b0f0b7f2fd2126ed73097c0d9edac Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Fri, 14 Apr 2023 20:07:42 -0700 Subject: [PATCH 08/22] Use unittest.mock.patch instead of manual monkeypatching --- Lib/test/test_logging.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 7000187e266955..e4578d963df654 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -58,6 +58,7 @@ import weakref from http.server import HTTPServer, BaseHTTPRequestHandler +from unittest.mock import patch from urllib.parse import urlparse, parse_qs from socketserver import (ThreadingUDPServer, DatagramRequestHandler, ThreadingTCPServer, StreamRequestHandler) @@ -4311,7 +4312,6 @@ def test_issue_89047(self): self.assertNotIn('.1000', s) def test_issue_102402_100msecs(self): - og_time_ns = time.time_ns tests = ( # (time_ns, expected_msecs_value) (1_677_902_297_100_000_000, 100.0), # exactly 100ms @@ -4319,13 +4319,11 @@ def test_issue_102402_100msecs(self): (1_677_903_920_000_998_503, 0.0), # check truncating doesn't round ) - try: - for ns, want in tests: - time.time_ns = lambda: ns + for ns, want in tests: + with patch('time.time_ns') as patched_ns: + patched_ns.return_value = ns record = logging.makeLogRecord({'msg': 'test'}) - self.assertEqual(record.msecs, want) - finally: - time.time_ns = og_time_ns + self.assertEqual(record.msecs, want) class TestBufferingFormatter(logging.BufferingFormatter): From 39cab9db634d51fb5250bfb13bba1c03ef5e9059 Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Sat, 2 Mar 2024 14:42:14 -0800 Subject: [PATCH 09/22] formatting in test_logging.py --- Lib/test/test_logging.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index e4578d963df654..b2911ccad7117b 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4317,7 +4317,6 @@ def test_issue_102402_100msecs(self): (1_677_902_297_100_000_000, 100.0), # exactly 100ms (1_677_903_920_999_998_503, 999.0), # check truncating doesn't round (1_677_903_920_000_998_503, 0.0), # check truncating doesn't round - ) for ns, want in tests: with patch('time.time_ns') as patched_ns: From 920bf746a0c1714a34a91ff78bbc0aa07fb9f045 Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Sat, 2 Mar 2024 14:51:26 -0800 Subject: [PATCH 10/22] Update docs --- Doc/library/logging.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index 34e98fc2577003..c66f4adf1cc934 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -907,7 +907,7 @@ the options available to you. | | | portion of the time). | +----------------+-------------------------+-----------------------------------------------+ | created | ``%(created)f`` | Time when the :class:`LogRecord` was created | -| | | (as returned by :func:`time.time`). | +| | | (as returned by :func:`time.time_ns` / 1e9). | +----------------+-------------------------+-----------------------------------------------+ | exc_info | You shouldn't need to | Exception tuple (à la ``sys.exc_info``) or, | | | format this yourself. | if no exception has occurred, ``None``. | From 8bdc406fbfb294f1855a289d8d71b50dffa9993b Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Sat, 2 Mar 2024 14:52:47 -0800 Subject: [PATCH 11/22] Keep ref to gh-89047 --- Lib/logging/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index 45e432f8ec992e..d4cbe5a0d22ea4 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -346,7 +346,7 @@ def __init__(self, name, level, pathname, lineno, # Eg: 55_123_456_789 --> 123_456_789 --> 123_000_000 # Lastly divide by 1e6 to change ns to ms # 123_000_000 --> 123 - # Convert to float by adding 0.0 for historical reasons. + # Convert to float by adding 0.0 for historical reasons. See gh-89047 self.msecs = (ct - (ct // 1_000_000_000) * 1_000_000_000) // 1_000_000 + 0.0 self.relativeCreated = (ct - _startTime) / 1e6 From bf68b2679cbe0e06fc8390bc0760a86959a881be Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Sat, 2 Mar 2024 15:02:03 -0800 Subject: [PATCH 12/22] Use modulo arithmetic, update comment --- Lib/logging/__init__.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index d4cbe5a0d22ea4..1209a6f4f6609f 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -341,13 +341,10 @@ def __init__(self, name, level, pathname, lineno, self.funcName = func self.created = ct / 1e9 # ns to float seconds - # x // 10**n: Drop the rightmost n digits - # (x // 10**n) * 10**n: "Change" the rightmost n digits to 0s. - # Eg: 55_123_456_789 --> 123_456_789 --> 123_000_000 - # Lastly divide by 1e6 to change ns to ms - # 123_000_000 --> 123 + # Get the number of _truncated_ msecs from the nanoseconds. + # Eg: 1_677_903_920_999_998_503 ns --> 1_677_903_920_999 ms # Convert to float by adding 0.0 for historical reasons. See gh-89047 - self.msecs = (ct - (ct // 1_000_000_000) * 1_000_000_000) // 1_000_000 + 0.0 + self.msecs = (ct % 1_000_000_000) // 1_000_000 + 0.0 self.relativeCreated = (ct - _startTime) / 1e6 if logThreads: From e404ca08a04c08c64203e8cd4aa5d42496a71d80 Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Sat, 2 Mar 2024 15:28:38 -0800 Subject: [PATCH 13/22] Add comment --- Lib/test/test_logging.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index b2911ccad7117b..cb86a8d8a39846 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4313,6 +4313,7 @@ def test_issue_89047(self): def test_issue_102402_100msecs(self): tests = ( + # time_ns is approx. 2023-03-04 04:25:20 UTC # (time_ns, expected_msecs_value) (1_677_902_297_100_000_000, 100.0), # exactly 100ms (1_677_903_920_999_998_503, 999.0), # check truncating doesn't round From 9661499c6bdc6e9fefa0dd02035127b00313fac8 Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Sun, 3 Mar 2024 10:26:37 -0800 Subject: [PATCH 14/22] Correct comment --- Lib/logging/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index 1209a6f4f6609f..f3e7ac34d902bb 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -341,8 +341,8 @@ def __init__(self, name, level, pathname, lineno, self.funcName = func self.created = ct / 1e9 # ns to float seconds - # Get the number of _truncated_ msecs from the nanoseconds. - # Eg: 1_677_903_920_999_998_503 ns --> 1_677_903_920_999 ms + # Get the number of whole milliseconds (0-999) in the fractional part of seconds. + # Eg: 1_677_903_920_999_998_503 ns --> 999_998_503 ns--> 999 ms # Convert to float by adding 0.0 for historical reasons. See gh-89047 self.msecs = (ct % 1_000_000_000) // 1_000_000 + 0.0 From ec74b0ebe8e83a013f6b3ae7c6b289651f1b23a5 Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Sun, 3 Mar 2024 10:36:01 -0800 Subject: [PATCH 15/22] Rename test --- Lib/test/test_logging.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index cb86a8d8a39846..9c59910ce4bd85 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4311,7 +4311,7 @@ def test_issue_89047(self): s = f.format(r) self.assertNotIn('.1000', s) - def test_issue_102402_100msecs(self): + def test_issue_102402_msecs_has_no_floating_point_precision_loss(self): tests = ( # time_ns is approx. 2023-03-04 04:25:20 UTC # (time_ns, expected_msecs_value) From 710f3ac66b672136b7188b95118eb492c09b36d2 Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Sun, 3 Mar 2024 11:06:33 -0800 Subject: [PATCH 16/22] Add test for relativeCreated --- Lib/test/test_logging.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 9c59910ce4bd85..35760f6c9f7b47 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -28,6 +28,7 @@ import datetime import pathlib import pickle +import importlib import io import itertools import gc @@ -4325,6 +4326,17 @@ def test_issue_102402_msecs_has_no_floating_point_precision_loss(self): record = logging.makeLogRecord({'msg': 'test'}) self.assertEqual(record.msecs, want) + def test_issue_102402_relativeCreated_has_higher_precision(self): + ns = 1_677_903_920_000_998_503 # approx. 2023-03-04 04:25:20 UTC + offset_ns = 200 + with patch("time.time_ns") as patched_ns: + patched_ns.return_value = ns + importlib.reload(logging) # force logging._startTime to use mocked value + patched_ns.return_value = ns + offset_ns + record = logging.makeLogRecord({'msg': 'test'}) + self.assertAlmostEqual(record.created, ns / 1e9, places=6) + # After gh-102412, precision (places) increases from 3 to 7 + self.assertAlmostEqual(record.relativeCreated, offset_ns / 1e6, places=7) class TestBufferingFormatter(logging.BufferingFormatter): def formatHeader(self, records): From ff8140c76c10908f2053094ad57c44576226fe0e Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Sun, 3 Mar 2024 14:22:51 -0800 Subject: [PATCH 17/22] remove issue num from test names; move to comment --- Lib/test/test_logging.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 35760f6c9f7b47..b648ff6efcefa1 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4312,7 +4312,8 @@ def test_issue_89047(self): s = f.format(r) self.assertNotIn('.1000', s) - def test_issue_102402_msecs_has_no_floating_point_precision_loss(self): + def test_msecs_has_no_floating_point_precision_loss(self): + # See issue gh-102402 tests = ( # time_ns is approx. 2023-03-04 04:25:20 UTC # (time_ns, expected_msecs_value) @@ -4326,7 +4327,8 @@ def test_issue_102402_msecs_has_no_floating_point_precision_loss(self): record = logging.makeLogRecord({'msg': 'test'}) self.assertEqual(record.msecs, want) - def test_issue_102402_relativeCreated_has_higher_precision(self): + def test_relativeCreated_has_higher_precision(self): + # See issue gh-102402 ns = 1_677_903_920_000_998_503 # approx. 2023-03-04 04:25:20 UTC offset_ns = 200 with patch("time.time_ns") as patched_ns: @@ -4335,7 +4337,7 @@ def test_issue_102402_relativeCreated_has_higher_precision(self): patched_ns.return_value = ns + offset_ns record = logging.makeLogRecord({'msg': 'test'}) self.assertAlmostEqual(record.created, ns / 1e9, places=6) - # After gh-102412, precision (places) increases from 3 to 7 + # After PR gh-102412, precision (places) increases from 3 to 7 self.assertAlmostEqual(record.relativeCreated, offset_ns / 1e6, places=7) class TestBufferingFormatter(logging.BufferingFormatter): From fd456942cfdc3d122379f3220565d21d453fbc4a Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Sun, 3 Mar 2024 14:30:16 -0800 Subject: [PATCH 18/22] Use importhelper instead of importlib.reload --- Lib/test/test_logging.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index b648ff6efcefa1..059d1c18372c92 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -28,7 +28,6 @@ import datetime import pathlib import pickle -import importlib import io import itertools import gc @@ -44,6 +43,7 @@ import tempfile from test.support.script_helper import assert_python_ok, assert_python_failure from test import support +from test.support import import_helper from test.support import os_helper from test.support import socket_helper from test.support import threading_helper @@ -4332,10 +4332,16 @@ def test_relativeCreated_has_higher_precision(self): ns = 1_677_903_920_000_998_503 # approx. 2023-03-04 04:25:20 UTC offset_ns = 200 with patch("time.time_ns") as patched_ns: - patched_ns.return_value = ns - importlib.reload(logging) # force logging._startTime to use mocked value - patched_ns.return_value = ns + offset_ns - record = logging.makeLogRecord({'msg': 'test'}) + orig_modules = import_helper._save_and_remove_modules(['logging']) + try: + patched_ns.return_value = ns + import logging + patched_ns.return_value = ns + offset_ns + record = logging.makeLogRecord({'msg': 'test'}) + finally: + import_helper._save_and_remove_modules(['logging']) + sys.modules.update(orig_modules) + self.assertAlmostEqual(record.created, ns / 1e9, places=6) # After PR gh-102412, precision (places) increases from 3 to 7 self.assertAlmostEqual(record.relativeCreated, offset_ns / 1e6, places=7) From 84b931b80134231c43c6c0e252440a519210c643 Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Sun, 3 Mar 2024 14:38:27 -0800 Subject: [PATCH 19/22] Also assert record.created --- Lib/test/test_logging.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 059d1c18372c92..702ff5c026d1a4 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4326,6 +4326,7 @@ def test_msecs_has_no_floating_point_precision_loss(self): patched_ns.return_value = ns record = logging.makeLogRecord({'msg': 'test'}) self.assertEqual(record.msecs, want) + self.assertEqual(record.created, ns / 1e9) def test_relativeCreated_has_higher_precision(self): # See issue gh-102402 From 5a604f9cfe251ff15c7270b0eabfc9dbe1a358df Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Sun, 3 Mar 2024 14:42:35 -0800 Subject: [PATCH 20/22] Update test to check multiple offset values --- Lib/test/test_logging.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 702ff5c026d1a4..7156dbd3418101 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4331,21 +4331,24 @@ def test_msecs_has_no_floating_point_precision_loss(self): def test_relativeCreated_has_higher_precision(self): # See issue gh-102402 ns = 1_677_903_920_000_998_503 # approx. 2023-03-04 04:25:20 UTC - offset_ns = 200 - with patch("time.time_ns") as patched_ns: - orig_modules = import_helper._save_and_remove_modules(['logging']) - try: - patched_ns.return_value = ns - import logging - patched_ns.return_value = ns + offset_ns - record = logging.makeLogRecord({'msg': 'test'}) - finally: - import_helper._save_and_remove_modules(['logging']) - sys.modules.update(orig_modules) + for offset_ns in (200, 500, 12_354, 99_999, 1_677_903_456_999_123_456): + new_ns = ns + offset_ns + with patch("time.time_ns") as patched_ns: + orig_modules = import_helper._save_and_remove_modules(['logging']) + try: + # mock for module import + patched_ns.return_value = ns + import logging + # mock for log record creation + patched_ns.return_value = new_ns + record = logging.makeLogRecord({'msg': 'test'}) + finally: + import_helper._save_and_remove_modules(['logging']) + sys.modules.update(orig_modules) - self.assertAlmostEqual(record.created, ns / 1e9, places=6) - # After PR gh-102412, precision (places) increases from 3 to 7 - self.assertAlmostEqual(record.relativeCreated, offset_ns / 1e6, places=7) + self.assertAlmostEqual(record.created, new_ns / 1e9, places=6) + # After PR gh-102412, precision (places) increases from 3 to 7 + self.assertAlmostEqual(record.relativeCreated, offset_ns / 1e6, places=7) class TestBufferingFormatter(logging.BufferingFormatter): def formatHeader(self, records): From dc90919dd5fb5893ce6dcc0519f5009203bd24f3 Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Mon, 4 Mar 2024 09:15:10 -0800 Subject: [PATCH 21/22] Optimize loop vs import CM --- Lib/test/test_logging.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 7156dbd3418101..afe46dcafcdef3 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4331,24 +4331,24 @@ def test_msecs_has_no_floating_point_precision_loss(self): def test_relativeCreated_has_higher_precision(self): # See issue gh-102402 ns = 1_677_903_920_000_998_503 # approx. 2023-03-04 04:25:20 UTC - for offset_ns in (200, 500, 12_354, 99_999, 1_677_903_456_999_123_456): - new_ns = ns + offset_ns + orig_modules = import_helper._save_and_remove_modules(['logging']) + try: with patch("time.time_ns") as patched_ns: - orig_modules = import_helper._save_and_remove_modules(['logging']) - try: - # mock for module import - patched_ns.return_value = ns - import logging + # mock for module import + patched_ns.return_value = ns + import logging + for offset_ns in (200, 500, 12_354, 99_999, 1_677_903_456_999_123_456): + new_ns = ns + offset_ns # mock for log record creation patched_ns.return_value = new_ns record = logging.makeLogRecord({'msg': 'test'}) - finally: - import_helper._save_and_remove_modules(['logging']) - sys.modules.update(orig_modules) + self.assertAlmostEqual(record.created, new_ns / 1e9, places=6) + # After PR gh-102412, precision (places) increases from 3 to 7 + self.assertAlmostEqual(record.relativeCreated, offset_ns / 1e6, places=7) + finally: + import_helper._save_and_remove_modules(['logging']) + sys.modules.update(orig_modules) - self.assertAlmostEqual(record.created, new_ns / 1e9, places=6) - # After PR gh-102412, precision (places) increases from 3 to 7 - self.assertAlmostEqual(record.relativeCreated, offset_ns / 1e6, places=7) class TestBufferingFormatter(logging.BufferingFormatter): def formatHeader(self, records): From 502ff65f1277e7c07e46820bb0d02ac4b7c4eecc Mon Sep 17 00:00:00 2001 From: Douglas Thor Date: Mon, 4 Mar 2024 09:17:28 -0800 Subject: [PATCH 22/22] Move item to variable --- Lib/test/test_logging.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index afe46dcafcdef3..fd39230ab254e5 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4331,13 +4331,14 @@ def test_msecs_has_no_floating_point_precision_loss(self): def test_relativeCreated_has_higher_precision(self): # See issue gh-102402 ns = 1_677_903_920_000_998_503 # approx. 2023-03-04 04:25:20 UTC + offsets_ns = (200, 500, 12_354, 99_999, 1_677_903_456_999_123_456) orig_modules = import_helper._save_and_remove_modules(['logging']) try: with patch("time.time_ns") as patched_ns: # mock for module import patched_ns.return_value = ns import logging - for offset_ns in (200, 500, 12_354, 99_999, 1_677_903_456_999_123_456): + for offset_ns in offsets_ns: new_ns = ns + offset_ns # mock for log record creation patched_ns.return_value = new_ns