<commit_before># -*- coding: utf-8 -*-
"""Provides AttributeStore class."""
__docformat__ = "restructuredtext en"

__copyright__ = """
Copyright (C) 2008-2013 Hendrikx-ITC B.V.

Distributed under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option) any later
version.  The full license is in the file COPYING, distributed as part of
this software.
"""
from functools import partial

import psycopg2

from minerva.util import head, expand_args, k, no_op
from minerva.db.query import Table
from minerva.directory import EntityType, DataSource
from minerva.db.error import NoSuchColumnError, DataTypeMismatch, \
    translate_postgresql_exception, translate_postgresql_exceptions, \
    UniqueViolation
from minerva.db.dbtransaction import DbTransaction, DbAction, insert_before
from minerva.storage.attribute.attribute import Attribute
from minerva.storage.valuedescriptor import ValueDescriptor
from minerva.storage import datatype

MAX_RETRIES = 10

DATATYPE_MISMATCH_ERRORS = {
    psycopg2.errorcodes.DATATYPE_MISMATCH,
    psycopg2.errorcodes.NUMERIC_VALUE_OUT_OF_RANGE,
    psycopg2.errorcodes.INVALID_TEXT_REPRESENTATION
}


class NoSuchAttributeError(Exception):
    """Exception type indicating an unknown attribute."""
    pass


class AttributeStoreDescriptor():
    def __init__(self, data_source, entity_type, attribute_descriptors):
        self.data_source = data_source
        self.entity_type = entity_type
        self.attribute_descriptors = attribute_descriptors


class AttributeStore():

    """
    Provides the main interface to the attribute storage facilities.

    Use `store` for writing to the attribute store and `retrieve` for reading
    from the attribute store.

    """

    def __init__(self, id, data_source, entity_type, attributes=tuple()):
        self.id = id
        self.data_source = data_source
        self.entity_type = entity_type

        self.attributes = attributes

        for attr in attributes:
            attr.attribute_store = self

        self.table = Table("attribute", self.table_name())
        self.history_table = Table("attribute_history", self.table_name())
        self.staging_table = Table("attribute_staging", self.table_name())
        self.curr_table = Table("attribute", self.table_name())

    def table_name(self):
        """Return the table name for this attribute store."""
        return "{0}_{1}".format(self.data_source.name, self.entity_type.name)

    def update_attributes(self, attribute_descriptors):
        """Add to, or update current attributes."""
        def f(cursor):
            self.check_attributes_exist(attribute_descriptors)(cursor)
            self.check_attribute_types(attribute_descriptors)(cursor)

        return f

    @staticmethod
    def get_attributes(attribute_store_id):
        """Load associated attributes from database and return them."""
        def f(cursor):
            query = (
                "SELECT id, name, data_type, attribute_store_id, description "
                "FROM attribute_directory.attribute "
                "WHERE attribute_store_id = %s"
            )
            args = attribute_store_id,

            cursor.execute(query, args)

            def row_to_attribute(row):
                """Create Attribute, link to this attribute store and return it."""
                attribute_id, name, data_type, attribute_store_id, description = row

                return Attribute(
                    attribute_id, name, datatype.type_map[data_type],
                    attribute_store_id, description
                )

            return [row_to_attribute(row) for row in cursor.fetchall()]

        return f

    @classmethod
    def from_attributes(cls, data_source, entity_type, attribute_descriptors):
        """
        Return AttributeStore with specified attributes.

        If an attribute store with specified data source and entity type exists,
        it is loaded, or a new one is created if it doesn't.

        """
        def f(cursor):
            query = (
                "SELECT * "
                "FROM attribute_directory.to_attribute_store("
                "%s, %s, %s::attribute_directory.attribute_descr[]"
                ")"
            )<commit_msg>Remove incorrect comment<commit_after># -*- coding: utf-8 -*-
"""Provides AttributeStore class."""
__docformat__ = "restructuredtext en"

__copyright__ = """
Copyright (C) 2008-2013 Hendrikx-ITC B.V.

Distributed under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option) any later
version.  The full license is in the file COPYING, distributed as part of
this software.
"""
from functools import partial

import psycopg2

from minerva.util import head, expand_args, k, no_op
from minerva.db.query import Table
from minerva.directory import EntityType, DataSource
from minerva.db.error import NoSuchColumnError, DataTypeMismatch, \
    translate_postgresql_exception, translate_postgresql_exceptions, \
    UniqueViolation
from minerva.db.dbtransaction import DbTransaction, DbAction, insert_before
from minerva.storage.attribute.attribute import Attribute
from minerva.storage.valuedescriptor import ValueDescriptor
from minerva.storage import datatype

MAX_RETRIES = 10

DATATYPE_MISMATCH_ERRORS = {
    psycopg2.errorcodes.DATATYPE_MISMATCH,
    psycopg2.errorcodes.NUMERIC_VALUE_OUT_OF_RANGE,
    psycopg2.errorcodes.INVALID_TEXT_REPRESENTATION
}


class NoSuchAttributeError(Exception):
    """Exception type indicating an unknown attribute."""
    pass


class AttributeStoreDescriptor():
    def __init__(self, data_source, entity_type, attribute_descriptors):
        self.data_source = data_source
        self.entity_type = entity_type
        self.attribute_descriptors = attribute_descriptors


class AttributeStore():

    """
    Provides the main interface to the attribute storage facilities.

    Use `store` for writing to the attribute store and `retrieve` for reading
    from the attribute store.

    """

    def __init__(self, id, data_source, entity_type, attributes=tuple()):
        self.id = id
        self.data_source = data_source
        self.entity_type = entity_type

        self.attributes = attributes

        for attr in attributes:
            attr.attribute_store = self

        self.table = Table("attribute", self.table_name())
        self.history_table = Table("attribute_history", self.table_name())
        self.staging_table = Table("attribute_staging", self.table_name())
        self.curr_table = Table("attribute", self.table_name())

    def table_name(self):
        """Return the table name for this attribute store."""
        return "{0}_{1}".format(self.data_source.name, self.entity_type.name)

    def update_attributes(self, attribute_descriptors):
        """Add to, or update current attributes."""
        def f(cursor):
            self.check_attributes_exist(attribute_descriptors)(cursor)
            self.check_attribute_types(attribute_descriptors)(cursor)

        return f

    @staticmethod
    def get_attributes(attribute_store_id):
        """Load associated attributes from database and return them."""
        def f(cursor):
            query = (
                "SELECT id, name, data_type, attribute_store_id, description "
                "FROM attribute_directory.attribute "
                "WHERE attribute_store_id = %s"
            )
            args = attribute_store_id,

            cursor.execute(query, args)

            def row_to_attribute(row):
                attribute_id, name, data_type, attribute_store_id, description = row

                return Attribute(
                    attribute_id, name, datatype.type_map[data_type],
                    attribute_store_id, description
                )

            return [row_to_attribute(row) for row in cursor.fetchall()]

        return f

    @classmethod
    def from_attributes(cls, data_source, entity_type, attribute_descriptors):
        """
        Return AttributeStore with specified attributes.

        If an attribute store with specified data source and entity type exists,
        it is loaded, or a new one is created if it doesn't.

        """
        def f(cursor):
            query = (
                "SELECT * "
                "FROM attribute_directory.to_attribute_store("
                "%s, %s, %s::attribute_directory.attribute_descr[]"
                ")"
            )
{'fraction_non_alphanumeric': 0.07980284004224857, 'fraction_numerical': 0.004224856237530807, 'mean_word_length': 2.891324200913242, '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': '1683815', 'n_tokens_mistral': 2335, 'n_tokens_neox': 2246, 'n_words': 642}