<commit_before>import schedule
import logging
import re
import datetime
import io
import time
import traceback
import importlib
import pkgutil
import inspect
from datetime import date
from enum import Enum
from weasyprint import HTML
from jinja2 import Environment, FileSystemLoader
from reporter.emailing import send_markdown_email
from reporter.connections import DatabaseConnection
from reporter.emailing import email_error


class Schedule(Enum):
    def daily(func):
        schedule.every().day.at("08:00").do(func)

    def weekly(func):
        schedule.every().monday.at("08:00").do(func)

    def monthly(func):
        schedule.every(4).weeks.do(func)

    def never(func):
        pass


class Report:
    def __init__(self, introduction=None, recipients=None,
                 name=None, send_email=True, schedule=None):

        self._name = name or type(self).__name__

        # Unpick CamelCase
        self._name = re.sub('([a-z])([A-Z])', r'\1 \2', self._name)

        self._recipients = recipients or ('DEFAULT_RECIPIENT')
        self._introduction = introduction or ''
        self._send_email = send_email
        self._schedule = schedule or Schedule.weekly

    def schedule(self):

        self._schedule(self.run)
        logging.info("{} scheduled".format(self._name))

    def run(self):
        try:
            report, rows, attachments = self.get_report()

            logging.info("{} ran with {} rows".format(self._name, rows))

            if (rows == 0):
                return

            if self._send_email:
                send_markdown_email(
                    self._name,
                    self._recipients,
                    report,
                    attachments)
        except KeyboardInterrupt as e:
            raise e
        except Exception:
            logging.error(traceback.format_exc())
            email_error(self._name, traceback.format_exc())

    def get_introduction(self):
        result = "**{} ({:%d-%b-%Y})**\r\n\r\n".format(
            self._name,
            date.today())
        result += "_{}_:\r\n\r\n".format(self._introduction)
        return result

    def get_report(self):
        return None, 0, None

    def get_details(self):
        return '"{}", "{}", "{}"'.format(
            self._name,
            self._schedule.__name__,
            "; ".join(self._recipients),
        )


class SqlReport(Report):
    def __init__(self, sql, conn=None, parameters=None, **kwargs):

        super().__init__(**kwargs)
        self._sql = sql
        self._conn = conn or DatabaseConnection.reporting
        self._parameters = parameters or ()

    def get_report(self):
        attachments = None

        with self._conn() as conn:

            conn.execute(self._sql, self._parameters)

            if conn.rowcount == 0:
                return None, 0, attachments

            report, rows = self.get_report_lines(conn)<commit_msg>Add actual recipients<commit_after>import schedule
import logging
import re
import datetime
import io
import time
import traceback
import importlib
import pkgutil
import inspect
from datetime import date
from enum import Enum
from weasyprint import HTML
from jinja2 import Environment, FileSystemLoader
from reporter.emailing import send_markdown_email
from reporter.connections import DatabaseConnection
from reporter.emailing import email_error, get_recipients


class Schedule(Enum):
    def daily(func):
        schedule.every().day.at("08:00").do(func)

    def weekly(func):
        schedule.every().monday.at("08:00").do(func)

    def monthly(func):
        schedule.every(4).weeks.do(func)

    def never(func):
        pass


class Report:
    def __init__(self, introduction=None, recipients=None,
                 name=None, send_email=True, schedule=None):

        self._name = name or type(self).__name__

        # Unpick CamelCase
        self._name = re.sub('([a-z])([A-Z])', r'\1 \2', self._name)

        self._recipients = recipients or ('DEFAULT_RECIPIENT')
        self._introduction = introduction or ''
        self._send_email = send_email
        self._schedule = schedule or Schedule.weekly

    def schedule(self):

        self._schedule(self.run)
        logging.info("{} scheduled".format(self._name))

    def run(self):
        try:
            report, rows, attachments = self.get_report()

            logging.info("{} ran with {} rows".format(self._name, rows))

            if (rows == 0):
                return

            if self._send_email:
                send_markdown_email(
                    self._name,
                    self._recipients,
                    report,
                    attachments)
        except KeyboardInterrupt as e:
            raise e
        except Exception:
            logging.error(traceback.format_exc())
            email_error(self._name, traceback.format_exc())

    def get_introduction(self):
        result = "**{} ({:%d-%b-%Y})**\r\n\r\n".format(
            self._name,
            date.today())
        result += "_{}_:\r\n\r\n".format(self._introduction)
        return result

    def get_report(self):
        return None, 0, None

    def get_details(self):
        return '"{}", "{}", "{}", "{}"'.format(
            self._name,
            self._schedule.__name__,
            "; ".join(self._recipients),
            "; ".join(get_recipients(self._recipients)),
        )


class SqlReport(Report):
    def __init__(self, sql, conn=None, parameters=None, **kwargs):

        super().__init__(**kwargs)
        self._sql = sql
        self._conn = conn or DatabaseConnection.reporting
        self._parameters = parameters or ()

    def get_report(self):
        attachments = None

        with self._conn() as conn:

            conn.execute(self._sql, self._parameters)

            if conn.rowcount == 0:
                return None, 0, attachments

            report, rows = self.get_report_lines(conn)
{'fraction_non_alphanumeric': 0.11371688881390248, 'fraction_numerical': 0.0053990214273662894, 'mean_word_length': 2.185384202041913, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '2047178', 'n_tokens_mistral': 1715, 'n_tokens_neox': 1593, 'n_words': 395}