<commit_before>#!/usr/bin/env python

import smtplib
import os.path
import logging
from multiprocessing import Pool
from collections import deque

"""
Tool for sending email from python. It was created to notify
(hence, notipy :) me when a job was completed (along with any relevant results)
Compatible with both python2 and python3
"""

#Instructions:
#Create file <<< sendDetails1.txt >> containing the following contents 
#
#email:<EMAIL>
#password:<<PASSWORD>>
#server:smtp.gmail.com
#port:587
#
#To run:
#import notipy
#notipy.sendMail("<EMAIL>", "This is a message")


# Constants
numMessageCharInLogEntry = 40
defaultSubject = "Notipy Automail"
logFileName = "notipy.log"

class MissingValueException(Exception):
    pass

class MissingConfigFileException(Exception):
    pass

def _readSendDetails():
    required_keywords = ["email", "password", "server", "port"]
    send_details = {}

    # Check for sendDetails1.txt. This is included in the .gitignore
    # file containing so it is NOT tracked by Git.
    if os.path.isfile("sendDetails1.txt"):
        fin = open("sendDetails1.txt")
    else:
        raise MissingConfigFileException()

    for line in fin:
        lineSplit = line.rstrip().split(":")
        send_details[lineSplit[0]] = lineSplit[1]

    # Check for required terms
    for i in required_keywords:
        if i in send_details.keys():
            if not send_details[i]:
                raise MissingValueException(i)
        else:
            raise MissingValueException(i)
    return send_details

def _formatAndSendMail(toAddress, message, subject=defaultSubject):
    statusStr= ""
    logCode = logging.INFO
    if isinstance(toAddress, str):   #smtolib expects the toAddress to be a string
        toAddress = [x.strip() for x in toAddress.split(",")]

    try:
        send_details = _readSendDetails()
    except MissingValueException as e:
        statusStr = "The sendDetails.txt/sendDetails1.txt file must contain a key and value for key: " + str(e) + " ."
        logCode = logging.ERROR
    except MissingConfigFileException as e:
        statusStr = "You must provide a sendDetails1.txt file. See GitHub Readme for file format details."
        logCode = logging.ERROR
    else:
        SERVER = send_details["server"]
        PORT = send_details["port"]
        FROM = send_details["email"]
        PWD = send_details["password"]

        fullMessage = """From: %s\r\nTo: %s\r\nSubject: %s\r\n\

        %s
        """ % (FROM, ", ".join(toAddress), subject, message )

        server = smtplib.SMTP(SERVER, PORT)
        server.starttls()
        server.login(FROM, PWD)
        server.sendmail(FROM, toAddress, fullMessage)
        server.quit()

        statusStr = "Successfully sent mail to " + str(toAddress) + " with message: " + message[:min(numMessageCharInLogEntry,len(message))] + "..."
    
    return (statusStr, logCode)

def _logSend(result):
    message, logLevel = result
    if logLevel == logging.INFO:
        logging.info(message)
    elif logLevel == logging.ERROR:
        logging.error(message)

def sendMail(toAddress, message, subject = ""):
    if (subject != ""):
        status = _formatAndSendMail(toAddress, message, subject)
    else:
        status = _formatAndSendMail(toAddress, message)
    _logSend(status)

def sendMailAsync(toAddress, message, subject = ""):
    args = [toAddress, message]
    if (subject != ""):
        args.append(subject)
    pool = Pool()
    pool.apply_async(_formatAndSendMail, args, callback=_logSend)

def queryLogs(numEntry, logFile=None):
    if not logFile:
        logFile = logFileName
    with open(logFile) as fin:
        for i in deque(fin, maxlen=numEntry):
            print(i)

# Run when notipy is imported
logging.basicConfig(filename=logFileName, level=logging.DEBUG, format='%(asctime)-15s %(levelname)-8s %(message)s')<commit_msg>Now handling and logging SMTPExceptions.<commit_after>#!/usr/bin/env python

import smtplib
import os.path
import logging
from multiprocessing import Pool
from collections import deque

"""
Tool for sending email from python. It was created to notify
(hence, notipy :) me when a job was completed (along with any relevant results)
Compatible with both python2 and python3
"""

#Instructions:
#Create file <<< sendDetails1.txt >> containing the following contents 
#
#email:<EMAIL>
#password:<<PASSWORD>>
#server:smtp.gmail.com
#port:587
#
#To run:
#import notipy
#notipy.sendMail("<EMAIL>", "This is a message")


# Constants
numMessageCharInLogEntry = 40
defaultSubject = "Notipy Automail"
logFileName = "notipy.log"

class MissingValueException(Exception):
    pass

class MissingConfigFileException(Exception):
    pass

def _readSendDetails():
    required_keywords = ["email", "password", "server", "port"]
    send_details = {}

    # Check for sendDetails1.txt. This is included in the .gitignore
    # file containing so it is NOT tracked by Git.
    if os.path.isfile("sendDetails1.txt"):
        fin = open("sendDetails1.txt")
    else:
        raise MissingConfigFileException()

    for line in fin:
        lineSplit = line.rstrip().split(":")
        send_details[lineSplit[0]] = lineSplit[1]

    # Check for required terms
    for i in required_keywords:
        if i in send_details.keys():
            if not send_details[i]:
                raise MissingValueException(i)
        else:
            raise MissingValueException(i)
    return send_details

def _formatAndSendMail(toAddress, message, subject=defaultSubject):
    statusStr= ""
    logCode = logging.INFO
    if isinstance(toAddress, str):   #smtolib expects the toAddress to be a string
        toAddress = [x.strip() for x in toAddress.split(",")]

    try:
        send_details = _readSendDetails()
    except MissingValueException as e:
        statusStr = "The sendDetails.txt/sendDetails1.txt file must contain a key and value for key: " + str(e) + " ."
        logCode = logging.ERROR
    except MissingConfigFileException as e:
        statusStr = "You must provide a sendDetails1.txt file. See GitHub Readme for file format details."
        logCode = logging.ERROR
    else:
        SERVER = send_details["server"]
        PORT = send_details["port"]
        FROM = send_details["email"]
        PWD = send_details["password"]

        fullMessage = """From: %s\r\nTo: %s\r\nSubject: %s\r\n\

        %s
        """ % (FROM, ", ".join(toAddress), subject, message )

        try:
            server = smtplib.SMTP(SERVER, PORT)
            server.starttls()
            server.login(FROM, PWD)
            server.sendmail(FROM, toAddress, fullMessage)
            server.quit()
        except smtplib.SMTPException as e:
            statusStr = "SMTPException caught: " + str(e)
            logCode = logging.ERROR
        else:
            statusStr = "Successfully sent mail to " + str(toAddress) + " with message: " + message[:min(numMessageCharInLogEntry,len(message))] + "..."

    return (statusStr, logCode)

def _logSend(result):
    message, logLevel = result
    if logLevel == logging.INFO:
        logging.info(message)
    elif logLevel == logging.ERROR:
        logging.error(message)

def sendMail(toAddress, message, subject = ""):
    if (subject != ""):
        status = _formatAndSendMail(toAddress, message, subject)
    else:
        status = _formatAndSendMail(toAddress, message)
    _logSend(status)

def sendMailAsync(toAddress, message, subject = ""):
    args = [toAddress, message]
    if (subject != ""):
        args.append(subject)
    pool = Pool()
    pool.apply_async(_formatAndSendMail, args, callback=_logSend)

def queryLog(numEntry, logFile=None):
    if not logFile:
        logFile = logFileName
    with open(logFile) as fin:
        for i in deque(fin, maxlen=numEntry):
            print(i)

# Run when notipy is imported
logging.basicConfig(filename=logFileName, level=logging.DEBUG, format='%(asctime)-15s %(levelname)-8s %(message)s')
{'fraction_non_alphanumeric': 0.11017269633177865, 'fraction_numerical': 0.004538005798562965, 'mean_word_length': 3.1301405517959395, 'pattern_counts': {'":': 2, '<': 17, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1481078', 'n_tokens_mistral': 2405, 'n_tokens_neox': 2347, 'n_words': 659}