def init_members(self, roles_json, entity_id):
        for role_id, role_definition in roles_json.items():
            check_type(role_definition, list,
                       [self.plural, entity_id, role_id])
            for index, person_id in enumerate(role_definition):
                check_type(person_id, basestring_type,
                           [self.plural, entity_id, role_id,
                            str(index)])
                if person_id not in self.simulation.persons.ids:
                    raise SituationParsingError([
                        self.plural, entity_id, role_id
                    ], "Unexpected value: {0}. {0} has been declared in {1} {2}, but has not been declared in {3}."
                                                .format(
                                                    person_id, entity_id,
                                                    role_id, self.simulation.
                                                    persons.plural))
                if person_id not in self.persons_to_allocate:
                    raise SituationParsingError(
                        [self.plural, entity_id, role_id],
                        "{} has been declared more than once in {}".format(
                            person_id, self.plural))
                self.persons_to_allocate.discard(person_id)

        entity_index = self.ids.index(entity_id)
        for person_role, person_legacy_role, person_id in iter_over_entity_members(
                self, roles_json):
            person_index = self.simulation.persons.ids.index(person_id)
            self.members_entity_id[person_index] = entity_index
            self.members_role[person_index] = person_role
            self.members_legacy_role[person_index] = person_legacy_role
    def finalize_variables_init(self):
        for variable_name, holder in self._holders.items():
            periods = holder.buffer.keys()
            # We need to handle small periods first for set_input to work
            sorted_periods = sorted(periods, key=key_period_size)
            for period in sorted_periods:
                array = holder.buffer[period]
                try:
                    holder.set_input(period, array)
                except PeriodMismatchError as e:
                    # This errors happens when we try to set a variable value for a period that doesn't match its definition period
                    # It is only raised when we consume the buffer. We thus don't know which exact key caused the error.
                    # We do a basic research to find the culprit path
                    culprit_path = next(
                        dpath.search(self.entities_json,
                                     "*/{}/{}".format(e.variable_name,
                                                      str(e.period)),
                                     yielded=True), None)
                    if culprit_path:
                        path = [self.plural] + culprit_path[0].split('/')
                    else:
                        path = [
                            self.plural
                        ]  # Fallback: if we can't find the culprit, just set the error at the entities level

                    raise SituationParsingError(path, e.message)
    def init_variable_values(self, entity_object, entity_id):
        entity_index = self.ids.index(entity_id)
        for variable_name, variable_values in entity_object.items():
            path_in_json = [self.plural, entity_id, variable_name]
            try:
                self.check_variable_defined_for_entity(variable_name)
            except ValueError as e:  # The variable is defined for another entity
                raise SituationParsingError(path_in_json, e.args[0])
            except VariableNotFound as e:  # The variable doesn't exist
                raise SituationParsingError(path_in_json, e.message, code=404)

            if not isinstance(variable_values, dict):
                raise SituationParsingError(
                    path_in_json,
                    "Invalid type: must be of type object. Input variables must be set for specific periods. For instance: {'salary': {'2017-01': 2000, '2017-02': 2500}}, or {'birth_date': {'ETERNITY': '1980-01-01'}}."
                )

            holder = self.get_holder(variable_name)
            for period_str, value in variable_values.items():
                path_in_json.append(period_str)
                try:
                    period = make_period(period_str)
                except ValueError as e:
                    raise SituationParsingError(path_in_json, e.args[0])
                if value is not None:
                    array = holder.buffer.get(period)
                    if array is None:
                        array = holder.default_array()
                    if holder.variable.value_type == Enum and isinstance(
                            value, basestring_type):
                        try:
                            value = holder.variable.possible_values[
                                value].index
                        except KeyError:
                            possible_values = [
                                item.name
                                for item in holder.variable.possible_values
                            ]
                            raise SituationParsingError(
                                path_in_json,
                                "'{}' is not a valid value for '{}'. Possible values are ['{}']."
                                .format(value, variable_name,
                                        "', '".join(possible_values)))
                    try:
                        array[entity_index] = value
                    except (ValueError, TypeError):
                        if holder.variable.value_type == date:
                            error_message = "Invalid date: '{}'.".format(value)
                        else:
                            error_message = "Invalid value: must be of type {}, received '{}'.".format(
                                holder.variable.json_type, value)
                        raise SituationParsingError(path_in_json,
                                                    error_message)

                    holder.buffer[period] = array
    def init_from_json(self, entities_json):
        self.members_entity_id = np.empty(self.simulation.persons.count,
                                          dtype=np.int32)
        self.members_role = np.empty(self.simulation.persons.count,
                                     dtype=object)
        self.members_legacy_role = np.empty(self.simulation.persons.count,
                                            dtype=np.int32)
        self._members_position = None

        self.persons_to_allocate = set(self.simulation.persons.ids)

        Entity.init_from_json(self, entities_json)

        if self.persons_to_allocate:
            unallocated_person = self.persons_to_allocate.pop()
            raise SituationParsingError([
                self.plural
            ], '{0} has been declared in {1}, but is not a member of any {2}. All {1} must be allocated to a {2}.'
                                        .format(unallocated_person,
                                                self.simulation.persons.plural,
                                                self.key))