<commit_before>import datetime
import calendar
from json import JSONEncoder, dumps

from flask import Response

from inbox.server.models.tables.base import (
    Message, SharedFolder, User, Account, Part,
    Contact, Thread, Namespace, Block)


# Flask's jsonify() doesn't handle datetimes or
# json arrays as primary objects
class APIEncoder(JSONEncoder):

    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return calendar.timegm(obj.utctimetuple())

        elif isinstance(obj, Namespace):
            return {
                'id':  obj.public_id,
                'object': 'namepace',
                'ns':  obj.public_id,

                # Account specific
                'account':  obj.account.public_id,
                'email_address':  obj.account.email_address,
                'provider':  obj.account.provider,
                # 'status':  'syncing',  # TODO what are values here
                # 'last_sync':  1398790077,  # tuesday 4/29
                # 'scope': ['mail', 'contacts']
            }

        elif isinstance(obj, Message):
            resp = {
                'id':  obj.public_id,
                'object': 'message',
                'ns': obj.namespace.public_id,
                'subject': obj.subject,
                'from': obj.from_addr,
                'to': obj.to_addr,
                'cc': obj.cc_addr,
                'bcc': obj.bcc_addr,
                'date': obj.received_date,
                'thread': obj.thread.public_id,
                'size': obj.size,
                'files': [],  # TODO calculate attachments from blocks
                'body': obj.sanitized_body,
                # 'snippet'     : obj.snippet,
                # 'list_info'   : obj.mailing_list_headers
            }
            if obj.is_draft:
                resp['is_draft'] = obj.is_draft
            return resp

        elif isinstance(obj, Thread):
            return {
                'id':  obj.public_id,
                'object':  'thread',
                'ns':  obj.namespace.public_id,
                'subject':  obj.subject,
                'participants':  obj.participants,
                'recent_date':  obj.recentdate,
                'subject_date': obj.subjectdate,
                'messages':  [m.public_id for m in obj.messages]  # for now
            }

        elif isinstance(obj, Contact):
            return {
                'id': obj.public_id,
                'object': 'contact',
                'ns': obj.namespace.public_id,
                'name': obj.name,
                'email_address': obj.email_address
            }

        elif isinstance(obj, Part):  # ie: Attachments
            return {
                'id': obj.public_id,
                'object': 'file',
                'ns': obj.namespace.public_id,
                'content_type': obj.content_type,
                'size': obj.size,
                'filename': obj.filename or obj.content_id,
                'is_inline': obj.content_disposition is not None
                and obj.content_disposition.lower() == 'inline',
                'message': obj.message.public_id
            }

        elif isinstance(obj, Block):  # ie: Files
            # TODO consider adding more info?
            return {
                'id': obj.public_id,
                'object': 'file',
                'ns': obj.namespace.public_id,
                'content_type': obj.content_type,
                'size': obj.size,
            }

        elif isinstance(obj, User):
            return {
                'id': obj.public_id,
                'object': 'user',
                'name': obj.name,
                'namespaces': [a.namespace.public_id for a in obj.accounts]
                # TOD
            }
            raise NotImplementedError

        elif isinstance(obj, Account):
            # Shouldn't ever need to serialize these...
            raise NotImplementedError

        elif isinstance(obj, SharedFolder):
            raise NotImplementedError

        # elif isinstance(obj, Webhook):
        #     pass

        # elif insstance(obj, CalendarEvent):
        #     pass

        # Let the base class default method raise the TypeError
        return JSONEncoder.default(self, obj)


def cereal(obj, pretty=False):
    if pretty:
        return dumps(obj,
                     sort_keys=True,
                     indent=4,
                     separators=(',', ': '),
                     cls=APIEncoder)
    return dumps(obj, cls=APIEncoder)


def jsonify(obj):
    return Response(cereal(obj, pretty=True),
                    mimetype='application/json')
<commit_msg>Format display name/email pairs in JSON as dicts, not arrays.<commit_after>import datetime
import calendar
from json import JSONEncoder, dumps

from flask import Response

from inbox.server.models.tables.base import (
    Message, SharedFolder, User, Account, Part,
    Contact, Thread, Namespace, Block)


def format_address_list(addresses):
    return [{'name': name, 'email': email} for name, email in addresses]


# Flask's jsonify() doesn't handle datetimes or
# json arrays as primary objects
class APIEncoder(JSONEncoder):

    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return calendar.timegm(obj.utctimetuple())

        elif isinstance(obj, Namespace):
            return {
                'id':  obj.public_id,
                'object': 'namepace',
                'ns':  obj.public_id,

                # Account specific
                'account':  obj.account.public_id,
                'email_address':  obj.account.email_address,
                'provider':  obj.account.provider,
                # 'status':  'syncing',  # TODO what are values here
                # 'last_sync':  1398790077,  # tuesday 4/29
                # 'scope': ['mail', 'contacts']
            }

        elif isinstance(obj, Message):
            resp = {
                'id':  obj.public_id,
                'object': 'message',
                'ns': obj.namespace.public_id,
                'subject': obj.subject,
                'from': format_address_list(obj.from_addr),
                'to': format_address_list(obj.to_addr),
                'cc': format_address_list(obj.cc_addr),
                'bcc': format_address_list(obj.bcc_addr),
                'date': obj.received_date,
                'thread': obj.thread.public_id,
                'size': obj.size,
                'files': [],  # TODO calculate attachments from blocks
                'body': obj.sanitized_body,
                # 'snippet'     : obj.snippet,
                # 'list_info'   : obj.mailing_list_headers
            }
            if obj.is_draft:
                resp['is_draft'] = obj.is_draft
            return resp

        elif isinstance(obj, Thread):
            return {
                'id':  obj.public_id,
                'object':  'thread',
                'ns':  obj.namespace.public_id,
                'subject':  obj.subject,
                'participants':  obj.participants,
                'recent_date':  obj.recentdate,
                'subject_date': obj.subjectdate,
                'messages':  [m.public_id for m in obj.messages]  # for now
            }

        elif isinstance(obj, Contact):
            return {
                'id': obj.public_id,
                'object': 'contact',
                'ns': obj.namespace.public_id,
                'name': obj.name,
                'email_address': obj.email_address
            }

        elif isinstance(obj, Part):  # ie: Attachments
            return {
                'id': obj.public_id,
                'object': 'file',
                'ns': obj.namespace.public_id,
                'content_type': obj.content_type,
                'size': obj.size,
                'filename': obj.filename or obj.content_id,
                'is_inline': obj.content_disposition is not None
                and obj.content_disposition.lower() == 'inline',
                'message': obj.message.public_id
            }

        elif isinstance(obj, Block):  # ie: Files
            # TODO consider adding more info?
            return {
                'id': obj.public_id,
                'object': 'file',
                'ns': obj.namespace.public_id,
                'content_type': obj.content_type,
                'size': obj.size,
            }

        elif isinstance(obj, User):
            return {
                'id': obj.public_id,
                'object': 'user',
                'name': obj.name,
                'namespaces': [a.namespace.public_id for a in obj.accounts]
                # TOD
            }
            raise NotImplementedError

        elif isinstance(obj, Account):
            # Shouldn't ever need to serialize these...
            raise NotImplementedError

        elif isinstance(obj, SharedFolder):
            raise NotImplementedError

        # elif isinstance(obj, Webhook):
        #     pass

        # elif insstance(obj, CalendarEvent):
        #     pass

        # Let the base class default method raise the TypeError
        return JSONEncoder.default(self, obj)


def cereal(obj, pretty=False):
    if pretty:
        return dumps(obj,
                     sort_keys=True,
                     indent=4,
                     separators=(',', ': '),
                     cls=APIEncoder)
    return dumps(obj, cls=APIEncoder)


def jsonify(obj):
    return Response(cereal(obj, pretty=True),
                    mimetype='application/json')

{'fraction_non_alphanumeric': 0.10493245366006912, 'fraction_numerical': 0.0029322442140538277, 'mean_word_length': 1.4677002583979328, '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': '5982467', 'n_tokens_mistral': 2678, 'n_tokens_neox': 2472, 'n_words': 597}