<commit_before># -*- coding: utf-8 -*-

from typing import Iterable

import numpy as np

from openfisca_core.entities import Role
from openfisca_core.indexed_enums import EnumArray
from openfisca_core.holders import Holder


ADD = 'add'
DIVIDE = 'divide'


def projectable(function):
    """
    Decorator to indicate that when called on a projector, the outcome of the function must be projected.
    For instance person.household.sum(...) must be projected on person, while it would not make sense for person.household.get_holder.
    """
    function.projectable = True
    return function


class Population(object):
    def __init__(self, entity):
        self.simulation = None
        self.entity = entity
        self._holders = {}
        self.count = 0
        self.ids = []

    def clone(self, simulation):
        result = Population(self.entity)
        result.simulation = simulation
        result._holders = {variable: holder.clone(result) for (variable, holder) in self._holders.items()}
        result.count = self.count
        result.ids = self.ids
        return result

    def empty_array(self):
        return np.zeros(self.count)

    def filled_array(self, value, dtype = None):
        return np.full(self.count, value, dtype)

    def __getattr__(self, attribute):
        projector = get_projector_from_shortcut(self, attribute)
        if not projector:
            raise AttributeError("You tried to use the '{}' of '{}' but that is not a known attribute.".format(attribute, self.entity.key))
        return projector

    def get_index(self, id):
        return self.ids.index(id)

    # Calculations

    def check_array_compatible_with_entity(self, array):
        if not self.count == array.size:
            raise ValueError("Input {} is not a valid value for the entity {} (size = {} != {} = count)".format(
                array, self.key, array.size, self.count))

    def __call__(self, variable_name, period, options = None, **parameters):
        """
            Calculate the variable ``variable_name`` for the entity and the period ``period``, using the variable formula if it exists.

            Example:

            >>> person('salary', '2017-04')
            >>> array([300.])

            :returns: A numpy array containing the result of the calculation
        """
        self.entity.check_variable_defined_for_entity(variable_name)

        if options is None:
            options = []

        if ADD in options and DIVIDE in options:
            raise ValueError('Options ADD and DIVIDE are incompatible (trying to compute variable {})'.format(variable_name).encode('utf-8'))
        elif ADD in options:
            return self.simulation.calculate_add(variable_name, period, **parameters)
        elif DIVIDE in options:
            return self.simulation.calculate_divide(variable_name, period, **parameters)
        else:
            return self.simulation.calculate(variable_name, period, **parameters)

    # Helpers

    def get_holder(self, variable_name):
        self.entity.check_variable_defined_for_entity(variable_name)
        holder = self._holders.get(variable_name)
        if holder:
            return holder
        variable = self.entity.get_variable(variable_name)
        self._holders[variable_name] = holder = Holder(variable, self)<commit_msg>Reinstate check for missing period argument<commit_after># -*- coding: utf-8 -*-

import traceback

from typing import Iterable

import numpy as np

from openfisca_core.entities import Role
from openfisca_core.indexed_enums import EnumArray
from openfisca_core.holders import Holder


ADD = 'add'
DIVIDE = 'divide'


def projectable(function):
    """
    Decorator to indicate that when called on a projector, the outcome of the function must be projected.
    For instance person.household.sum(...) must be projected on person, while it would not make sense for person.household.get_holder.
    """
    function.projectable = True
    return function


class Population(object):
    def __init__(self, entity):
        self.simulation = None
        self.entity = entity
        self._holders = {}
        self.count = 0
        self.ids = []

    def clone(self, simulation):
        result = Population(self.entity)
        result.simulation = simulation
        result._holders = {variable: holder.clone(result) for (variable, holder) in self._holders.items()}
        result.count = self.count
        result.ids = self.ids
        return result

    def empty_array(self):
        return np.zeros(self.count)

    def filled_array(self, value, dtype = None):
        return np.full(self.count, value, dtype)

    def __getattr__(self, attribute):
        projector = get_projector_from_shortcut(self, attribute)
        if not projector:
            raise AttributeError("You tried to use the '{}' of '{}' but that is not a known attribute.".format(attribute, self.entity.key))
        return projector

    def get_index(self, id):
        return self.ids.index(id)

    # Calculations

    def check_array_compatible_with_entity(self, array):
        if not self.count == array.size:
            raise ValueError("Input {} is not a valid value for the entity {} (size = {} != {} = count)".format(
                array, self.key, array.size, self.count))

    def check_period_validity(self, variable_name, period):
        if period is None:
            stack = traceback.extract_stack()
            filename, line_number, function_name, line_of_code = stack[-3]
            raise ValueError('''
You requested computation of variable "{}", but you did not specify on which period in "{}:{}":
    {}
When you request the computation of a variable within a formula, you must always specify the period as the second parameter. The convention is to call this parameter "period". For example:
    computed_salary = person('salary', period).
See more information at <https://openfisca.org/doc/coding-the-legislation/35_periods.html#periods-in-variable-definition>.
'''.format(variable_name, filename, line_number, line_of_code).encode('utf-8'))

    def __call__(self, variable_name, period = None, options = None, **parameters):
        """
            Calculate the variable ``variable_name`` for the entity and the period ``period``, using the variable formula if it exists.

            Example:

            >>> person('salary', '2017-04')
            >>> array([300.])

            :returns: A numpy array containing the result of the calculation
        """
        self.entity.check_variable_defined_for_entity(variable_name)
        self.check_period_validity(variable_name, period)

        if options is None:
            options = []

        if ADD in options and DIVIDE in options:
            raise ValueError('Options ADD and DIVIDE are incompatible (trying to compute variable {})'.format(variable_name).encode('utf-8'))
        elif ADD in options:
            return self.simulation.calculate_add(variable_name, period, **parameters)
        elif DIVIDE in options:
            return self.simulation.calculate_divide(variable_name, period, **parameters)
        else:
            return self.simulation.calculate(variable_name, period, **parameters)

    # Helpers

    def get_holder(self, variable_name):
        self.entity.check_variable_defined_for_entity(variable_name)
        holder = self._holders.get(variable_name)
        if holder:
            return holder
        variable = self.entity.get_variable(variable_name)
        self._holders[variable_name] = holder = Holder(variable, self)
{'fraction_non_alphanumeric': 0.09576158940397352, 'fraction_numerical': 0.003708609271523179, 'mean_word_length': 2.829107505070994, 'pattern_counts': {'":': 1, '<': 4, '<?xml version=': 0, '>': 16, 'https://': 1, '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': '1183043', 'n_tokens_mistral': 2078, 'n_tokens_neox': 2007, 'n_words': 625}