EMMAA’s Subscription Service (emmaa.subscription)

Notifications functions (emmaa.subscription.notifications)

class emmaa.subscription.notifications.EmailHtmlBody(template_path)[source]

Bases: object

Parent class for email body.

class emmaa.subscription.notifications.ModelDeltaEmailHtmlBody(template_path='email_unsub/model_email_body.html')[source]

Bases: EmailHtmlBody

Email body for model updates.

render(msg_dicts, unsub_link)[source]

Provided pregenerated msg_dicts render HTML to put in email body.

Parameters
  • msg_dicts (list[dict]) – A list of dictionaries containing parts of messages to be added to email. Each dictionary has the following keys: ‘url’, ‘start’, ‘delta_part’, ‘middle’, ‘message’.

  • unsub_link (str) – A link to unsubscribe page.

Returns

An html string rendered from the associated jinja2 template

Return type

html

class emmaa.subscription.notifications.QueryEmailHtmlBody(domain='emmaa.indra.bio', template_path='email_unsub/email_body.html')[source]

Bases: EmailHtmlBody

Email body for query notifications.

render(static_query_deltas, open_query_deltas, dynamic_query_deltas, unsub_link)[source]

Provided the delta json objects, render HTML to put in email body.

Parameters
  • static_query_deltas (json) – A list of lists that names which queries have updates. Expected structure: [(english_query, detailed_query_link, model, model_type)]

  • dynamic_query_deltas (list[) – A list of lists that names which queries have updates. Expected structure: [(english_query, model, model_type)]

  • unsub_link (str) – A link to unsubscribe page.

Returns

An html string rendered from the associated jinja2 template

Return type

html

emmaa.subscription.notifications.get_all_stats(model_name, test_corpora, date)[source]

Get all stats for a model and its test corpora.

Parameters
  • model_name (str) – A name of the model to get the updates for.

  • test_corpora (list[str]) – A list of test corpora names to get the test updates for.

  • date (str) – A date for which the updates should be generated. The format should be “YYYY-MM-DD”.

Returns

  • model_stats (dict) – A dictionary containing the stats for the given model.

  • test_stats_by_corpus (dict) – A dictionary of test statistics keyed by test corpus name.

emmaa.subscription.notifications.get_all_update_messages(deltas, is_tweet=False)[source]

Get all messages for model deltas that can be further used in tweets and email notifications.

Parameters
  • deltas (dict) – A dictionary containing deltas for a model and its test results returned by get_model_deltas function.

  • is_tweet (bool) – Whether messages are generated for Twitter (used to determine the formatting of model types).

Returns

msg_dicts – A list of individual message dictionaries that can be used for tweets or email notifications.

Return type

list[dict]

emmaa.subscription.notifications.get_model_deltas(model_name, date, model_stats, test_stats_by_corpus)[source]

Get deltas from model and test stats for further use in tweets and email notifications.

Parameters
  • model_name (str) – A name of the model to get the updates for.

  • date (str) – A date for which the updates should be generated. The format should be “YYYY-MM-DD”.

  • model_stats (dict) – A dictionary containing the stats for the given model.

  • test_stats_by_corpus (dict) – A dictionary of test statistics keyed by test corpus name.

Returns

deltas – A dictionary containing the deltas for the given model and test corpora.

Return type

dict

emmaa.subscription.notifications.get_user_query_delta(db, user_email, domain='emmaa.indra.bio')[source]

Produce a report for all query results per user in a given format

Parameters
  • db (emmaa.db.EmmaaDatabaseManager) – An instance of a database manager to use.

  • user_email (str) – The email of the user for which to get the report for

  • domain (str) – The domain name for the unsubscibe link in the html report. Default: “emmaa.indra.bio”.

Returns

A tuple with (str report, html report)

Return type

tuple(str, html_str)

emmaa.subscription.notifications.make_html_report_per_user(static_results_delta, open_results_delta, dynamic_results_delta, email, domain='emmaa.indra.bio')[source]

Produce a report for all query results per user in an html file.

Parameters
  • static_results_delta (list) – A list of tuples of query deltas for static queries. Each tuple has a format (english_query, link, model, mc_type)

  • open_results_delta (list) – A list of tuples of query deltas for open queries. Each tuple has a format (english_query, link, model, mc_type)

  • dynamic_results_delta (list) – A list of tuples of query deltas for dynamic queries. Each tuple has a format (english_query, link, model, mc_type)

  • email (str) – The email of the user to get the results for.

  • domain (str) – The domain name for the unsubscibe link in the report. Default: “emmaa.indra.bio”.

Returns

A string containing an html document

Return type

str

emmaa.subscription.notifications.make_model_html_email(msg_dicts, email, domain='emmaa.indra.bio')[source]

Render html file for model notification email.

emmaa.subscription.notifications.make_reports_from_results(new_results, domain='emmaa.indra.bio')[source]

Make a report given latest results and queries the results are for.

Parameters

new_results (list[tuple]) – Latest results as a list of tuples where each tuple has the format (model_name, query, mc_type, result_json, date, delta).

Returns

reports – A list of reports on changes for each of the queries.

Return type

list

emmaa.subscription.notifications.make_str_report_per_user(static_results_delta, open_results_delta, dynamic_results_delta)[source]

Produce a report for all query results per user as a string.

Parameters
  • static_results_delta (list) – A list of tuples of query deltas for static queries. Each tuple has a format (english_query, link, model, mc_type)

  • open_results_delta (list) – A list of tuples of query deltas for open queries. Each tuple has a format (english_query, link, model, mc_type)

  • dynamic_results_delta (list) – A list of tuples of query deltas for dynamic queries. Each tuple has a format (english_query, link, model, mc_type) (no link in dynamic_results_delta tuples).

Returns

msg – A message about query deltas.

Return type

str

emmaa.subscription.notifications.model_update_notify(model_name, test_corpora, date, db, bucket='emmaa')[source]

This function finds delta for a given model and sends updates via Twitter posts and email notifications.

Parameters
  • model_name (str) – A name of EMMAA model.

  • test_corpora (list[str]) – A list of test corpora names to get test stats.

  • date (str) – A date for which to get stats for.

  • db (emmaa.db.EmmaaDatabaseManager) – An instance of a database manager to use.

  • bucket (str) – A name of S3 bucket where corresponding stats files are stored.

emmaa.subscription.notifications.tweet_deltas(deltas, twitter_cred, verbose=False)[source]

Tweet the model updates.

Parameters
  • deltas (dict) – A dictionary containing deltas for a model and its test results returned by get_model_deltas function.

  • twitter_cred (dict) – A dictionary containing consumer_token, consumer_secret, access_token, and access_secret for a model Twitter account.

  • verbose (bool) – If True, the return from tweepy.Client.create_tweet will be printed

emmaa.subscription.notifications.update_path_counts(model_name, date, test_stats_by_corpus)[source]

Combine path counts from all test corpora and update in the database.

Email Service (emmaa.subscription.email_service)

emmaa.subscription.email_service.close_to_quota_max(used_quota=0.95, region='us-east-1')[source]

Check if the send quota is close to be exceeded

If the total quota for the 24h cycle is Q, the currently used quota is q and ‘used_quota’ is r, return True if q/Q > r, otherwise return False.

Parameters
  • used_quota (float) – A float between 0 and 1.0. This number specifies the fraction of send quota currently used. Default: 0.95

  • region (str) – A valid AWS region. The region to check the quota in. Default: us-east-1.

Returns

True if the quota is close to be exceeded with respect to the provided ratio ‘used’.

Return type

bool

emmaa.subscription.email_service.get_send_statistics(region='us-east-1')[source]

Return the sending statistics, like bounce and complaint rates

See https://boto3.amazonaws.com/v1/documentation/api/latest/ reference/services/ses.html#SES.Client.get_send_statistics for more info

Parameters

region (Optional[str]) – Specify AWS region

Returns

Response syntax:
{
‘SendDataPoints’: [
{

‘Timestamp’: datetime(2015, 1, 1), ‘DeliveryAttempts’: 123, ‘Bounces’: 123, ‘Complaints’: 123, ‘Rejects’: 123

},

]

}

Return type

dict

emmaa.subscription.email_service.send_email(sender, recipients, subject, body_text, body_html, source_arn=None, return_email=None, return_arn=None, region='us-east-1')[source]

Wrapper function for the send_email method of the boto3 SES client

IMPORTANT: sending is limited to 14 emails per second.

See more at: https://boto3.amazonaws.com/v1/documentation/api/latest/reference + /services/ses.html#SES.Client.send_email https://docs.aws.amazon.com/ses/latest/APIReference/API_SendEmail.html and python example at https://docs.aws.amazon.com/ses/latest/DeveloperGuide/ + sending-authorization-delegate-sender-tasks-email.html

Parameters
  • sender (str) – A valid email address to use in the Source field

  • recipients (iterable[str] or str) – A valid email address or a list of valid email addresses. This will fill out the Recipients field.

  • subject (str) – The email subject

  • body_text (str) – The text body of the email

  • body_html (str) – The html body of the email. Must be a valid html body (starting with <html>, ending with </html>).

  • source_arn (str) – The source ARN of the sender. Should be of the format “arn:aws:ses:us-east-1:123456789012:identity/user@example.com” or “arn:aws:ses:us-east-1:123456789012:identity/example.com”. Used only for sending authorization. It is the ARN of the identity that is associated with the sending authorization policy that permits the sender to send using the email address specified as the sender. Example: the owner of the domain “example.com” can send an email from any address using @example.com, as long as the associated source_arn is “arn:aws:ses:us-east-1:123456789012:identity/example.com”

  • return_email (str) – The email to which complaints and bounces are sent. Can be the same as the sender.

  • return_arn (str) – The return path ARN for the sender. This is the ARN associated with the return email. Can be the same as the source_arn if return email is the same as the sender.

  • region (str) – AWS region to use for the SES client. Default: us-east-1

Returns

The API response object in the form of a dict is returned. The structure is:

>>> response = {                'MessageId': 'EXAMPLE78603177f-7a5433e7-8edb-42ae-af10' +                             '-f0181f34d6ee-000000',                'ResponseMetadata': {                    '...': '...',                },            }

Return type

dict

Email Utilities (emmaa.subscription.email_util)

emmaa.subscription.email_util.generate_signature(email, expire_str, digestmod=<built-in function openssl_sha256>)[source]

Return an HMAC signature based on email and expire_str

From documentation of HMAC in python: key is a bytes or bytearray object giving the secret key. If msg is present, the method call update(msg) is made. digestmod is the digest name, digest constructor or module for the HMAC object to use. It supports any name suitable to hashlib.new().

Parameters
  • email (str) – A valid email address. Should not be URL encoded.

  • expire_str (str) – A timestamp string in seconds

  • digestmod (str|digest constructor|module) – digest name, digest constructor or module for the HMAC object to use. Default: hashlib.sha256

Returns

A hexadecimal string representing the signature

Return type

str

Generate an unsubscribe link for the provided email address

Given an email address, generate an unsubscribe link using that email address. Optionally provide the number of days into the future the link should be valid until and the domain name. The domain name is expeceted to be of the format “some.domain.com”. The appropriate path and prefixes will be added together with the query string. Example:

>>> generate_unsubscribe_link('user@email.com', domain='some.domain.com')
>>> 'https://some.domain.com/query/unsubscribe?email=user%40email.com' +
    '&expiration=1234567890&signature=1234567890abcdef'
Parameters
  • email (str) – An email address.

  • days (int) – The number of days into the future the link should be valid until. Default: 7.

  • domain (str) – A domain name to prefix the query string with. Expected format is: “some.domain.com”. Default: ‘emmaa.indra.bio’

Returns

An unsubscribe link for the provided email and (optionally) domain

Return type

str

emmaa.subscription.email_util.generate_unsubscribe_qs(email, days=7)[source]

Generate an unsubscribe query string for a url

Parameters
  • email (str) – A valid email address

  • days (int) – The number of days the query string should be valid. Default: 7.

Returns

A query string of the format ‘email=<urlenc email>&expiration=<timestamp>&signature=<sha256 hex>’

Return type

str

emmaa.subscription.email_util.get_email_subscriptions(email)[source]

Verifies which email subsciptions exist for the provided email

Parameters

email (str) – The email to the check subscriptions for

Return type

list(tuple(str, str, query_hash))

emmaa.subscription.email_util.register_email_unsubscribe(email, queries, models)[source]

Executes an email unsubscribe request

emmaa.subscription.email_util.verify_email_signature(signature, email, expiration, digestmod=<built-in function openssl_sha256>)[source]

Verify HMAC signature