-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.py
143 lines (116 loc) · 4.08 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
"""
Entrypoint script to schedule notebook
and send email.
Author: @hunterowens
"""
import datetime
import os
import sys
import time
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
import boto3
import civis
import pandas as pd
import papermill as pm
sys.path.append(os.getcwd())
# check dir
if not os.path.exists('outputs'):
os.makedirs('outputs')
output_path = f'./outputs/{str(datetime.datetime.now().date())}-coronavirus-stats.ipynb'
# Try executing the notebook. If it fails due to data being incomplete,
# try again in an hour, for a maximum of ten hours.
MAX_TRIES = 3
RETRY = 60 * 60
for i in range(MAX_TRIES):
try:
pm.execute_notebook(
'/app/notebooks/county-city-indicators.ipynb',
output_path,
cwd='/app/notebooks'
)
break
except pm.PapermillExecutionError as e:
if "Data incomplete" in e.evalue:
print(f"Data incomplete, trying again in {RETRY} seconds")
time.sleep(RETRY)
else:
raise e
else:
raise RuntimeError(f"Unable to get fresh data after {MAX_TRIES} tries.")
# shell out, run NB Convert
output_format = 'PDFviaHTML'
cmd = f"jupyter nbconvert --to {output_format} --no-input --no-prompt {output_path}"
output_file = f'./outputs/{str(datetime.datetime.now().date())}-coronavirus-stats.pdf'
os.system(cmd)
# Replace [email protected] with your "From" address.
# This address must be verified with Amazon SES.
SENDER = "[email protected]"
# Replace [email protected] with a "To" address. If your account
# is still in the sandbox, this address must be verified.
RECIPIENT = "[email protected]"
# If necessary, replace us-west-2 with the AWS Region you're using for Amazon SES.
AWS_REGION = "us-west-2"
# The subject line for the email.
SUBJECT = f"Coronavirus Stats for {str(datetime.datetime.now().date())}"
# The full path to the file that will be attached to the email.
ATTACHMENT = output_file
# The email body for recipients with non-HTML email clients.
BODY_TEXT = "Hello,\r\nPlease see the attached file for a status update on coronavirus-related indicators."
# The HTML body of the email.
BODY_HTML = """\
<html>
<head></head>
<body>
<p>Please see the attached file for a status update on coronavirus-related indicators.</p>
</body>
</html>
"""
# The character encoding for the email.
CHARSET = "utf-8"
# Create a new SES resource and specify a region.
client = boto3.client('ses',region_name=AWS_REGION)
# Create a multipart/mixed parent container.
msg = MIMEMultipart('mixed')
# Add subject, from and to lines.
msg['Subject'] = SUBJECT
msg['From'] = SENDER
msg['To'] = RECIPIENT
# Create a multipart/alternative child container.
msg_body = MIMEMultipart('alternative')
# Encode the text and HTML content and set the character encoding. This step is
# necessary if you're sending a message with characters outside the ASCII range.
textpart = MIMEText(BODY_TEXT.encode(CHARSET), 'plain', CHARSET)
htmlpart = MIMEText(BODY_HTML.encode(CHARSET), 'html', CHARSET)
# Add the text and HTML parts to the child container.
msg_body.attach(textpart)
msg_body.attach(htmlpart)
# Define the attachment part and encode it using MIMEApplication.
att = MIMEApplication(open(ATTACHMENT, 'rb').read())
# Add a header to tell the email client to treat this part as an attachment,
# and to give the attachment a name.
att.add_header('Content-Disposition','attachment',filename=os.path.basename(ATTACHMENT))
# Attach the multipart/alternative child container to the multipart/mixed
# parent container.
msg.attach(msg_body)
# Add the attachment to the parent container.
msg.attach(att)
#print(msg)
try:
#Provide the contents of the email.
response = client.send_raw_email(
Source=SENDER,
Destinations=[
RECIPIENT
],
RawMessage={
'Data':msg.as_string(),
}
)
# Display an error if something goes wrong.
except ClientError as e:
print(e.response['Error']['Message'])
else:
print("Email sent! Message ID:"),
print(response['MessageId'])