From 0aca55330adfac2eec6e6586677ec7d7aac72510 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Mon, 25 Sep 2023 10:40:24 +0100 Subject: [PATCH 1/8] WIP --- Lib/email/_msgid.py | 29 +++++++++++++++++++++++++++++ Lib/email/utils.py | 39 ++++++++++----------------------------- 2 files changed, 39 insertions(+), 29 deletions(-) create mode 100644 Lib/email/_msgid.py diff --git a/Lib/email/_msgid.py b/Lib/email/_msgid.py new file mode 100644 index 00000000000000..b99cdcf6dfdead --- /dev/null +++ b/Lib/email/_msgid.py @@ -0,0 +1,29 @@ +# This function used to be part of email.utils, +# but has been separated out to speedup the import of that module + +import os +import random +import socket +import time + +def make_msgid(idstring=None, domain=None): + """Returns a string suitable for RFC 2822 compliant Message-ID, e.g: + + <142480216486.20800.16526388040877946887@nightshade.la.mastaler.com> + + Optional idstring if given is a string used to strengthen the + uniqueness of the message id. Optional domain if given provides the + portion of the message id after the '@'. It defaults to the locally + defined hostname. + """ + timeval = int(time.time()*100) + pid = os.getpid() + randint = random.getrandbits(64) + if idstring is None: + idstring = '' + else: + idstring = '.' + idstring + if domain is None: + domain = socket.getfqdn() + msgid = '<%d.%d.%d%s@%s>' % (timeval, pid, randint, idstring, domain) + return msgid diff --git a/Lib/email/utils.py b/Lib/email/utils.py index 81da5394ea1695..72d5d38760e0f9 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -22,11 +22,8 @@ 'unquote', ] -import os import re import time -import random -import socket import datetime import urllib.parse @@ -36,9 +33,6 @@ from email._parseaddr import parsedate, parsedate_tz, _parsedate_tz -# Intrapackage imports -from email.charset import Charset - COMMASPACE = ', ' EMPTYSTRING = '' UEMPTYSTRING = '' @@ -94,6 +88,8 @@ def formataddr(pair, charset='utf-8'): name.encode('ascii') except UnicodeEncodeError: if isinstance(charset, str): + # lazy import to improve module import time + from email.charset import Charset charset = Charset(charset) encoded_name = charset.header_encode(name) return "%s <%s>" % (encoded_name, address) @@ -171,29 +167,6 @@ def format_datetime(dt, usegmt=False): return _format_timetuple_and_zone(now, zone) -def make_msgid(idstring=None, domain=None): - """Returns a string suitable for RFC 2822 compliant Message-ID, e.g: - - <142480216486.20800.16526388040877946887@nightshade.la.mastaler.com> - - Optional idstring if given is a string used to strengthen the - uniqueness of the message id. Optional domain if given provides the - portion of the message id after the '@'. It defaults to the locally - defined hostname. - """ - timeval = int(time.time()*100) - pid = os.getpid() - randint = random.getrandbits(64) - if idstring is None: - idstring = '' - else: - idstring = '.' + idstring - if domain is None: - domain = socket.getfqdn() - msgid = '<%d.%d.%d%s@%s>' % (timeval, pid, randint, idstring, domain) - return msgid - - def parsedate_to_datetime(data): parsed_date_tz = _parsedate_tz(data) if parsed_date_tz is None: @@ -351,3 +324,11 @@ def localtime(dt=None, isdst=None): if dt is None: dt = datetime.datetime.now() return dt.astimezone() + + +def __getattr__(attr): + # lazy import, to speedup module import time + if attr == "make_msgid": + from ._msgid import make_msgid + return make_msgid + raise AttributeError(f"module {__name__!r} has no attribute {attr!r}") From f3c815da7bb7efbc73ebc5c969b2331362296cf2 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Mon, 25 Sep 2023 10:49:55 +0100 Subject: [PATCH 2/8] news --- .../Library/2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst diff --git a/Misc/NEWS.d/next/Library/2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst b/Misc/NEWS.d/next/Library/2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst new file mode 100644 index 00000000000000..e095d7721de695 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst @@ -0,0 +1,4 @@ +Reduce the import time of :mod:`email.utils` by around 46%. This results in +the import time of :mod:`email.message` falling by around 28%, which in turn +reduces the import time of :mod:`importlib.metadata` by around 5%. Patch by +ALex Waygood. From 992274f8d1aed901d45d750fc6216a08ac8bbdd8 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 25 Sep 2023 11:53:03 +0100 Subject: [PATCH 3/8] I can spell my own name Co-authored-by: Nikita Sobolev --- .../next/Library/2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst b/Misc/NEWS.d/next/Library/2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst index e095d7721de695..397e756a3eefdb 100644 --- a/Misc/NEWS.d/next/Library/2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst +++ b/Misc/NEWS.d/next/Library/2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst @@ -1,4 +1,4 @@ Reduce the import time of :mod:`email.utils` by around 46%. This results in the import time of :mod:`email.message` falling by around 28%, which in turn reduces the import time of :mod:`importlib.metadata` by around 5%. Patch by -ALex Waygood. +Alex Waygood. From 493aa332405bc7841fe2aa4ce4dec1079122b2a4 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 25 Sep 2023 12:02:03 +0100 Subject: [PATCH 4/8] Apply suggestions from code review Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Lib/email/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/email/utils.py b/Lib/email/utils.py index 72d5d38760e0f9..cb294e783dcaea 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -327,8 +327,8 @@ def localtime(dt=None, isdst=None): def __getattr__(attr): - # lazy import, to speedup module import time + # lazy import, to speed up module import time if attr == "make_msgid": - from ._msgid import make_msgid + from email._msgid import make_msgid return make_msgid raise AttributeError(f"module {__name__!r} has no attribute {attr!r}") From 03233f19d8b5a21df4e96dae4b480bd4526cc02a Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Tue, 3 Oct 2023 15:52:41 +0100 Subject: [PATCH 5/8] Abandon the separate submodule idea --- Lib/email/_msgid.py | 29 ----------------------------- Lib/email/utils.py | 36 ++++++++++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 37 deletions(-) delete mode 100644 Lib/email/_msgid.py diff --git a/Lib/email/_msgid.py b/Lib/email/_msgid.py deleted file mode 100644 index b99cdcf6dfdead..00000000000000 --- a/Lib/email/_msgid.py +++ /dev/null @@ -1,29 +0,0 @@ -# This function used to be part of email.utils, -# but has been separated out to speedup the import of that module - -import os -import random -import socket -import time - -def make_msgid(idstring=None, domain=None): - """Returns a string suitable for RFC 2822 compliant Message-ID, e.g: - - <142480216486.20800.16526388040877946887@nightshade.la.mastaler.com> - - Optional idstring if given is a string used to strengthen the - uniqueness of the message id. Optional domain if given provides the - portion of the message id after the '@'. It defaults to the locally - defined hostname. - """ - timeval = int(time.time()*100) - pid = os.getpid() - randint = random.getrandbits(64) - if idstring is None: - idstring = '' - else: - idstring = '.' + idstring - if domain is None: - domain = socket.getfqdn() - msgid = '<%d.%d.%d%s@%s>' % (timeval, pid, randint, idstring, domain) - return msgid diff --git a/Lib/email/utils.py b/Lib/email/utils.py index 72d5d38760e0f9..6551c151d4973b 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -167,6 +167,34 @@ def format_datetime(dt, usegmt=False): return _format_timetuple_and_zone(now, zone) +def make_msgid(idstring=None, domain=None): + """Returns a string suitable for RFC 2822 compliant Message-ID, e.g: + + <142480216486.20800.16526388040877946887@nightshade.la.mastaler.com> + + Optional idstring if given is a string used to strengthen the + uniqueness of the message id. Optional domain if given provides the + portion of the message id after the '@'. It defaults to the locally + defined hostname. + """ + # Lazy imports to speedup module import time + # (no other functions in email.utils need these modules) + import os + import random + import socket + timeval = int(time.time()*100) + pid = os.getpid() + randint = random.getrandbits(64) + if idstring is None: + idstring = '' + else: + idstring = '.' + idstring + if domain is None: + domain = socket.getfqdn() + msgid = '<%d.%d.%d%s@%s>' % (timeval, pid, randint, idstring, domain) + return msgid + + def parsedate_to_datetime(data): parsed_date_tz = _parsedate_tz(data) if parsed_date_tz is None: @@ -324,11 +352,3 @@ def localtime(dt=None, isdst=None): if dt is None: dt = datetime.datetime.now() return dt.astimezone() - - -def __getattr__(attr): - # lazy import, to speedup module import time - if attr == "make_msgid": - from ._msgid import make_msgid - return make_msgid - raise AttributeError(f"module {__name__!r} has no attribute {attr!r}") From f11bc987866fd9321d6ccba093505d0534b527d4 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Tue, 3 Oct 2023 16:06:36 +0100 Subject: [PATCH 6/8] stats are slightly less impressive now because importing random is cheaper now --- .../2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst b/Misc/NEWS.d/next/Library/2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst index e095d7721de695..b61f0bdd019ee1 100644 --- a/Misc/NEWS.d/next/Library/2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst +++ b/Misc/NEWS.d/next/Library/2023-09-25-10-47-22.gh-issue-109653.TUHrId.rst @@ -1,4 +1,4 @@ -Reduce the import time of :mod:`email.utils` by around 46%. This results in -the import time of :mod:`email.message` falling by around 28%, which in turn -reduces the import time of :mod:`importlib.metadata` by around 5%. Patch by -ALex Waygood. +Reduce the import time of :mod:`email.utils` by around 43%. This results in +the import time of :mod:`email.message` falling by around 18%, which in turn +reduces the import time of :mod:`importlib.metadata` by around 6%. Patch by +Alex Waygood. From b387dcd42d09ee114ef7b996d15678c2a48c8b86 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 3 Oct 2023 16:53:39 +0100 Subject: [PATCH 7/8] Update Lib/email/utils.py Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Lib/email/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/email/utils.py b/Lib/email/utils.py index 6551c151d4973b..96b5903f6fdf90 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -182,6 +182,7 @@ def make_msgid(idstring=None, domain=None): import os import random import socket + timeval = int(time.time()*100) pid = os.getpid() randint = random.getrandbits(64) From e2010284d0b1db6b3fd44d4be77e92adde27c599 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Wed, 4 Oct 2023 22:08:30 +0100 Subject: [PATCH 8/8] eagerly import os, it is free --- Lib/email/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/email/utils.py b/Lib/email/utils.py index 96b5903f6fdf90..a49a8fa986ce0c 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -22,6 +22,7 @@ 'unquote', ] +import os import re import time import datetime @@ -179,7 +180,6 @@ def make_msgid(idstring=None, domain=None): """ # Lazy imports to speedup module import time # (no other functions in email.utils need these modules) - import os import random import socket