summaryrefslogtreecommitdiff
path: root/Doc/includes
diff options
context:
space:
mode:
Diffstat (limited to 'Doc/includes')
-rw-r--r--Doc/includes/email-alternative-new-api.py56
-rw-r--r--[-rwxr-xr-x]Doc/includes/email-alternative.py76
-rw-r--r--Doc/includes/email-dir.py55
-rw-r--r--Doc/includes/email-headers.py22
-rw-r--r--Doc/includes/email-mime.py29
-rw-r--r--Doc/includes/email-read-alternative.py (renamed from Doc/includes/email-read-alternative-new-api.py)0
-rw-r--r--Doc/includes/email-simple.py8
-rw-r--r--Doc/includes/email-unpack.py8
-rw-r--r--Doc/includes/run-func.c4
-rw-r--r--Doc/includes/test.py2
-rw-r--r--Doc/includes/tzinfo-examples.py130
11 files changed, 166 insertions, 224 deletions
diff --git a/Doc/includes/email-alternative-new-api.py b/Doc/includes/email-alternative-new-api.py
deleted file mode 100644
index 321f727c31..0000000000
--- a/Doc/includes/email-alternative-new-api.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env python3
-
-import smtplib
-
-from email.message import EmailMessage
-from email.headerregistry import Address
-from email.utils import make_msgid
-
-# Create the base text message.
-msg = EmailMessage()
-msg['Subject'] = "Ayons asperges pour le déjeuner"
-msg['From'] = Address("Pepé Le Pew", "pepe", "example.com")
-msg['To'] = (Address("Penelope Pussycat", "penelope", "example.com"),
- Address("Fabrette Pussycat", "fabrette", "example.com"))
-msg.set_content("""\
-Salut!
-
-Cela ressemble à un excellent recipie[1] déjeuner.
-
-[1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718
-
---Pepé
-""")
-
-# Add the html version. This converts the message into a multipart/alternative
-# container, with the original text message as the first part and the new html
-# message as the second part.
-asparagus_cid = make_msgid()
-msg.add_alternative("""\
-<html>
- <head></head>
- <body>
- <p>Salut!<\p>
- <p>Cela ressemble à un excellent
- <a href="http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718>
- recipie
- </a> déjeuner.
- </p>
- <img src="cid:{asparagus_cid}" \>
- </body>
-</html>
-""".format(asparagus_cid=asparagus_cid[1:-1]), subtype='html')
-# note that we needed to peel the <> off the msgid for use in the html.
-
-# Now add the related image to the html part.
-with open("roasted-asparagus.jpg", 'rb') as img:
- msg.get_payload()[1].add_related(img.read(), 'image', 'jpeg',
- cid=asparagus_cid)
-
-# Make a local copy of what we are going to send.
-with open('outgoing.msg', 'wb') as f:
- f.write(bytes(msg))
-
-# Send the message via local SMTP server.
-with smtplib.SMTP('localhost') as s:
- s.send_message(msg)
diff --git a/Doc/includes/email-alternative.py b/Doc/includes/email-alternative.py
index 85070f36ae..2e142b1e3b 100755..100644
--- a/Doc/includes/email-alternative.py
+++ b/Doc/includes/email-alternative.py
@@ -2,47 +2,55 @@
import smtplib
-from email.mime.multipart import MIMEMultipart
-from email.mime.text import MIMEText
-
-# me == my email address
-# you == recipient's email address
-me = "my@email.com"
-you = "your@email.com"
-
-# Create message container - the correct MIME type is multipart/alternative.
-msg = MIMEMultipart('alternative')
-msg['Subject'] = "Link"
-msg['From'] = me
-msg['To'] = you
-
-# Create the body of the message (a plain-text and an HTML version).
-text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttps://www.python.org"
-html = """\
+from email.message import EmailMessage
+from email.headerregistry import Address
+from email.utils import make_msgid
+
+# Create the base text message.
+msg = EmailMessage()
+msg['Subject'] = "Ayons asperges pour le déjeuner"
+msg['From'] = Address("Pepé Le Pew", "pepe", "example.com")
+msg['To'] = (Address("Penelope Pussycat", "penelope", "example.com"),
+ Address("Fabrette Pussycat", "fabrette", "example.com"))
+msg.set_content("""\
+Salut!
+
+Cela ressemble à un excellent recipie[1] déjeuner.
+
+[1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718
+
+--Pepé
+""")
+
+# Add the html version. This converts the message into a multipart/alternative
+# container, with the original text message as the first part and the new html
+# message as the second part.
+asparagus_cid = make_msgid()
+msg.add_alternative("""\
<html>
<head></head>
<body>
- <p>Hi!<br>
- How are you?<br>
- Here is the <a href="https://www.python.org">link</a> you wanted.
+ <p>Salut!</p>
+ <p>Cela ressemble à un excellent
+ <a href="http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718>
+ recipie
+ </a> déjeuner.
</p>
+ <img src="cid:{asparagus_cid}" />
</body>
</html>
-"""
+""".format(asparagus_cid=asparagus_cid[1:-1]), subtype='html')
+# note that we needed to peel the <> off the msgid for use in the html.
-# Record the MIME types of both parts - text/plain and text/html.
-part1 = MIMEText(text, 'plain')
-part2 = MIMEText(html, 'html')
+# Now add the related image to the html part.
+with open("roasted-asparagus.jpg", 'rb') as img:
+ msg.get_payload()[1].add_related(img.read(), 'image', 'jpeg',
+ cid=asparagus_cid)
-# Attach parts into message container.
-# According to RFC 2046, the last part of a multipart message, in this case
-# the HTML message, is best and preferred.
-msg.attach(part1)
-msg.attach(part2)
+# Make a local copy of what we are going to send.
+with open('outgoing.msg', 'wb') as f:
+ f.write(bytes(msg))
# Send the message via local SMTP server.
-s = smtplib.SMTP('localhost')
-# sendmail function takes 3 arguments: sender's address, recipient's address
-# and message to send - here it is sent as one string.
-s.sendmail(me, you, msg.as_string())
-s.quit()
+with smtplib.SMTP('localhost') as s:
+ s.send_message(msg)
diff --git a/Doc/includes/email-dir.py b/Doc/includes/email-dir.py
index 3c7c770dda..0dcfbfb402 100644
--- a/Doc/includes/email-dir.py
+++ b/Doc/includes/email-dir.py
@@ -3,22 +3,14 @@
"""Send the contents of a directory as a MIME message."""
import os
-import sys
import smtplib
# For guessing MIME type based on file name extension
import mimetypes
from argparse import ArgumentParser
-from email import encoders
-from email.message import Message
-from email.mime.audio import MIMEAudio
-from email.mime.base import MIMEBase
-from email.mime.image import MIMEImage
-from email.mime.multipart import MIMEMultipart
-from email.mime.text import MIMEText
-
-COMMASPACE = ', '
+from email.message import EmailMessage
+from email.policy import SMTP
def main():
@@ -47,12 +39,12 @@ must be running an SMTP server.
directory = args.directory
if not directory:
directory = '.'
- # Create the enclosing (outer) message
- outer = MIMEMultipart()
- outer['Subject'] = 'Contents of directory %s' % os.path.abspath(directory)
- outer['To'] = COMMASPACE.join(args.recipients)
- outer['From'] = args.sender
- outer.preamble = 'You will not see this in a MIME-aware mail reader.\n'
+ # Create the message
+ msg = EmailMessage()
+ msg['Subject'] = 'Contents of directory %s' % os.path.abspath(directory)
+ msg['To'] = ', '.join(args.recipients)
+ msg['From'] = args.sender
+ msg.preamble = 'You will not see this in a MIME-aware mail reader.\n'
for filename in os.listdir(directory):
path = os.path.join(directory, filename)
@@ -67,33 +59,18 @@ must be running an SMTP server.
# use a generic bag-of-bits type.
ctype = 'application/octet-stream'
maintype, subtype = ctype.split('/', 1)
- if maintype == 'text':
- with open(path) as fp:
- # Note: we should handle calculating the charset
- msg = MIMEText(fp.read(), _subtype=subtype)
- elif maintype == 'image':
- with open(path, 'rb') as fp:
- msg = MIMEImage(fp.read(), _subtype=subtype)
- elif maintype == 'audio':
- with open(path, 'rb') as fp:
- msg = MIMEAudio(fp.read(), _subtype=subtype)
- else:
- with open(path, 'rb') as fp:
- msg = MIMEBase(maintype, subtype)
- msg.set_payload(fp.read())
- # Encode the payload using Base64
- encoders.encode_base64(msg)
- # Set the filename parameter
- msg.add_header('Content-Disposition', 'attachment', filename=filename)
- outer.attach(msg)
+ with open(path, 'rb') as fp:
+ msg.add_attachment(fp.read(),
+ maintype=maintype,
+ subtype=subtype,
+ filename=filename)
# Now send or store the message
- composed = outer.as_string()
if args.output:
- with open(args.output, 'w') as fp:
- fp.write(composed)
+ with open(args.output, 'wb') as fp:
+ fp.write(msg.as_bytes(policy=SMTP))
else:
with smtplib.SMTP('localhost') as s:
- s.sendmail(args.sender, args.recipients, composed)
+ s.send_message(msg)
if __name__ == '__main__':
diff --git a/Doc/includes/email-headers.py b/Doc/includes/email-headers.py
index 89c8f3af32..2c421451a8 100644
--- a/Doc/includes/email-headers.py
+++ b/Doc/includes/email-headers.py
@@ -1,18 +1,24 @@
# Import the email modules we'll need
-from email.parser import Parser
+from email.parser import BytesParser, Parser
+from email.policy import default
# If the e-mail headers are in a file, uncomment these two lines:
-# with open(messagefile) as fp:
-# headers = Parser().parse(fp)
+# with open(messagefile, 'rb') as fp:
+# headers = BytesParser(policy=default).parse(fp)
-# Or for parsing headers in a string, use:
-headers = Parser().parsestr('From: <user@example.com>\n'
+# Or for parsing headers in a string (this is an uncommon operation), use:
+headers = Parser(policy=default).parsestr(
+ 'From: Foo Bar <user@example.com>\n'
'To: <someone_else@example.com>\n'
'Subject: Test message\n'
'\n'
'Body would go here\n')
# Now the header items can be accessed as a dictionary:
-print('To: %s' % headers['to'])
-print('From: %s' % headers['from'])
-print('Subject: %s' % headers['subject'])
+print('To: {}'.format(headers['to']))
+print('From: {}'.format(headers['from']))
+print('Subject: {}'.format(headers['subject']))
+
+# You can also access the parts of the addresses:
+print('Recipient username: {}'.format(headers['to'].addresses[0].username))
+print('Sender name: {}'.format(headers['from'].addresses[0].display_name))
diff --git a/Doc/includes/email-mime.py b/Doc/includes/email-mime.py
index 61d08302a2..c610242f11 100644
--- a/Doc/includes/email-mime.py
+++ b/Doc/includes/email-mime.py
@@ -1,30 +1,29 @@
# Import smtplib for the actual sending function
import smtplib
-# Here are the email package modules we'll need
-from email.mime.image import MIMEImage
-from email.mime.multipart import MIMEMultipart
+# And imghdr to find the types of our images
+import imghdr
-COMMASPACE = ', '
+# Here are the email package modules we'll need
+from email.message import EmailMessage
-# Create the container (outer) email message.
-msg = MIMEMultipart()
+# Create the container email message.
+msg = EmailMessage()
msg['Subject'] = 'Our family reunion'
# me == the sender's email address
# family = the list of all recipients' email addresses
msg['From'] = me
-msg['To'] = COMMASPACE.join(family)
+msg['To'] = ', '.join(family)
msg.preamble = 'Our family reunion'
-# Assume we know that the image files are all in PNG format
+# Open the files in binary mode. Use imghdr to figure out the
+# MIME subtype for each specific image.
for file in pngfiles:
- # Open the files in binary mode. Let the MIMEImage class automatically
- # guess the specific image type.
with open(file, 'rb') as fp:
- img = MIMEImage(fp.read())
- msg.attach(img)
+ img_data = fp.read()
+ msg.add_attachment(img_data, maintype='image',
+ subtype=imghdr.what(None, img_data))
# Send the email via our own SMTP server.
-s = smtplib.SMTP('localhost')
-s.send_message(msg)
-s.quit()
+with smtplib.SMTP('localhost') as s:
+ s.send_message(msg)
diff --git a/Doc/includes/email-read-alternative-new-api.py b/Doc/includes/email-read-alternative.py
index 3f5ab24c0f..3f5ab24c0f 100644
--- a/Doc/includes/email-read-alternative-new-api.py
+++ b/Doc/includes/email-read-alternative.py
diff --git a/Doc/includes/email-simple.py b/Doc/includes/email-simple.py
index b9b8b410a6..f69ef40ff0 100644
--- a/Doc/includes/email-simple.py
+++ b/Doc/includes/email-simple.py
@@ -2,13 +2,13 @@
import smtplib
# Import the email modules we'll need
-from email.mime.text import MIMEText
+from email.message import EmailMessage
-# Open a plain text file for reading. For this example, assume that
-# the text file contains only ASCII characters.
+# Open the plain text file whose name is in textfile for reading.
with open(textfile) as fp:
# Create a text/plain message
- msg = MIMEText(fp.read())
+ msg = EmailMessage()
+ msg.set_content(fp.read())
# me == the sender's email address
# you == the recipient's email address
diff --git a/Doc/includes/email-unpack.py b/Doc/includes/email-unpack.py
index 574a0b6d72..e0a7f01f58 100644
--- a/Doc/includes/email-unpack.py
+++ b/Doc/includes/email-unpack.py
@@ -3,11 +3,11 @@
"""Unpack a MIME message into a directory of files."""
import os
-import sys
import email
-import errno
import mimetypes
+from email.policy import default
+
from argparse import ArgumentParser
@@ -22,8 +22,8 @@ Unpack a MIME message into a directory of files.
parser.add_argument('msgfile')
args = parser.parse_args()
- with open(args.msgfile) as fp:
- msg = email.message_from_file(fp)
+ with open(args.msgfile, 'rb') as fp:
+ msg = email.message_from_binary_file(fp, policy=default)
try:
os.mkdir(args.directory)
diff --git a/Doc/includes/run-func.c b/Doc/includes/run-func.c
index 986d670319..ead7bdd232 100644
--- a/Doc/includes/run-func.c
+++ b/Doc/includes/run-func.c
@@ -63,6 +63,8 @@ main(int argc, char *argv[])
fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
return 1;
}
- Py_Finalize();
+ if (Py_FinalizeEx() < 0) {
+ return 120;
+ }
return 0;
}
diff --git a/Doc/includes/test.py b/Doc/includes/test.py
index 7ebf46afd1..9e9d4a6712 100644
--- a/Doc/includes/test.py
+++ b/Doc/includes/test.py
@@ -204,7 +204,7 @@ Test cyclic gc(?)
import os
import sys
from distutils.util import get_platform
-PLAT_SPEC = "%s-%s" % (get_platform(), sys.version[0:3])
+PLAT_SPEC = "%s-%d.%d" % (get_platform(), *sys.version_info[:2])
src = os.path.join("build", "lib.%s" % PLAT_SPEC)
sys.path.append(src)
diff --git a/Doc/includes/tzinfo-examples.py b/Doc/includes/tzinfo-examples.py
index 3a8cf47eaf..ae5a509266 100644
--- a/Doc/includes/tzinfo-examples.py
+++ b/Doc/includes/tzinfo-examples.py
@@ -1,46 +1,13 @@
-from datetime import tzinfo, timedelta, datetime
+from datetime import tzinfo, timedelta, datetime, timezone
ZERO = timedelta(0)
HOUR = timedelta(hours=1)
-
-# A UTC class.
-
-class UTC(tzinfo):
- """UTC"""
-
- def utcoffset(self, dt):
- return ZERO
-
- def tzname(self, dt):
- return "UTC"
-
- def dst(self, dt):
- return ZERO
-
-utc = UTC()
-
-# A class building tzinfo objects for fixed-offset time zones.
-# Note that FixedOffset(0, "UTC") is a different way to build a
-# UTC tzinfo object.
-
-class FixedOffset(tzinfo):
- """Fixed offset in minutes east from UTC."""
-
- def __init__(self, offset, name):
- self.__offset = timedelta(minutes=offset)
- self.__name = name
-
- def utcoffset(self, dt):
- return self.__offset
-
- def tzname(self, dt):
- return self.__name
-
- def dst(self, dt):
- return ZERO
+SECOND = timedelta(seconds=1)
# A class capturing the platform's idea of local time.
-
+# (May result in wrong values on historical times in
+# timezones where UTC offset and/or the DST rules had
+# changed in the past.)
import time as _time
STDOFFSET = timedelta(seconds = -_time.timezone)
@@ -53,6 +20,16 @@ DSTDIFF = DSTOFFSET - STDOFFSET
class LocalTimezone(tzinfo):
+ def fromutc(self, dt):
+ assert dt.tzinfo is self
+ stamp = (dt - datetime(1970, 1, 1, tzinfo=self)) // SECOND
+ args = _time.localtime(stamp)[:6]
+ dst_diff = DSTDIFF // SECOND
+ # Detect fold
+ fold = (args == _time.localtime(stamp - dst_diff))
+ return datetime(*args, microsecond=dt.microsecond,
+ tzinfo=self, fold=fold)
+
def utcoffset(self, dt):
if self._isdst(dt):
return DSTOFFSET
@@ -99,20 +76,37 @@ def first_sunday_on_or_after(dt):
# In the US, since 2007, DST starts at 2am (standard time) on the second
# Sunday in March, which is the first Sunday on or after Mar 8.
DSTSTART_2007 = datetime(1, 3, 8, 2)
-# and ends at 2am (DST time; 1am standard time) on the first Sunday of Nov.
-DSTEND_2007 = datetime(1, 11, 1, 1)
+# and ends at 2am (DST time) on the first Sunday of Nov.
+DSTEND_2007 = datetime(1, 11, 1, 2)
# From 1987 to 2006, DST used to start at 2am (standard time) on the first
-# Sunday in April and to end at 2am (DST time; 1am standard time) on the last
+# Sunday in April and to end at 2am (DST time) on the last
# Sunday of October, which is the first Sunday on or after Oct 25.
DSTSTART_1987_2006 = datetime(1, 4, 1, 2)
-DSTEND_1987_2006 = datetime(1, 10, 25, 1)
+DSTEND_1987_2006 = datetime(1, 10, 25, 2)
# From 1967 to 1986, DST used to start at 2am (standard time) on the last
-# Sunday in April (the one on or after April 24) and to end at 2am (DST time;
-# 1am standard time) on the last Sunday of October, which is the first Sunday
+# Sunday in April (the one on or after April 24) and to end at 2am (DST time)
+# on the last Sunday of October, which is the first Sunday
# on or after Oct 25.
DSTSTART_1967_1986 = datetime(1, 4, 24, 2)
DSTEND_1967_1986 = DSTEND_1987_2006
+def us_dst_range(year):
+ # Find start and end times for US DST. For years before 1967, return
+ # start = end for no DST.
+ if 2006 < year:
+ dststart, dstend = DSTSTART_2007, DSTEND_2007
+ elif 1986 < year < 2007:
+ dststart, dstend = DSTSTART_1987_2006, DSTEND_1987_2006
+ elif 1966 < year < 1987:
+ dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986
+ else:
+ return (datetime(year, 1, 1), ) * 2
+
+ start = first_sunday_on_or_after(dststart.replace(year=year))
+ end = first_sunday_on_or_after(dstend.replace(year=year))
+ return start, end
+
+
class USTimeZone(tzinfo):
def __init__(self, hours, reprname, stdname, dstname):
@@ -141,27 +135,39 @@ class USTimeZone(tzinfo):
# implementation) passes a datetime with dt.tzinfo is self.
return ZERO
assert dt.tzinfo is self
-
- # Find start and end times for US DST. For years before 1967, return
- # ZERO for no DST.
- if 2006 < dt.year:
- dststart, dstend = DSTSTART_2007, DSTEND_2007
- elif 1986 < dt.year < 2007:
- dststart, dstend = DSTSTART_1987_2006, DSTEND_1987_2006
- elif 1966 < dt.year < 1987:
- dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986
- else:
- return ZERO
-
- start = first_sunday_on_or_after(dststart.replace(year=dt.year))
- end = first_sunday_on_or_after(dstend.replace(year=dt.year))
-
+ start, end = us_dst_range(dt.year)
# Can't compare naive to aware objects, so strip the timezone from
# dt first.
- if start <= dt.replace(tzinfo=None) < end:
+ dt = dt.replace(tzinfo=None)
+ if start + HOUR <= dt < end - HOUR:
+ # DST is in effect.
return HOUR
- else:
- return ZERO
+ if end - HOUR <= dt < end:
+ # Fold (an ambiguous hour): use dt.fold to disambiguate.
+ return ZERO if dt.fold else HOUR
+ if start <= dt < start + HOUR:
+ # Gap (a non-existent hour): reverse the fold rule.
+ return HOUR if dt.fold else ZERO
+ # DST is off.
+ return ZERO
+
+ def fromutc(self, dt):
+ assert dt.tzinfo is self
+ start, end = us_dst_range(dt.year)
+ start = start.replace(tzinfo=self)
+ end = end.replace(tzinfo=self)
+ std_time = dt + self.stdoffset
+ dst_time = std_time + HOUR
+ if end <= dst_time < end + HOUR:
+ # Repeated hour
+ return std_time.replace(fold=1)
+ if std_time < start or dst_time >= end:
+ # Standard time
+ return std_time
+ if start <= std_time < end - HOUR:
+ # Daylight saving time
+ return dst_time
+
Eastern = USTimeZone(-5, "Eastern", "EST", "EDT")
Central = USTimeZone(-6, "Central", "CST", "CDT")