def _parse_children()

in functions/source/KeyGen/asn1crypto/core.py [0:0]


    def _parse_children(self, recurse=False):
        """
        Parses the contents and generates Asn1Value objects based on the
        definitions from _fields.

        :param recurse:
            If child objects that are Sequence or SequenceOf objects should
            be recursively parsed

        :raises:
            ValueError - when an error occurs parsing child objects
        """

        cls = self.__class__
        if self._contents is None:
            if self._fields:
                self.children = [VOID] * len(self._fields)
                for index, (_, _, params) in enumerate(self._fields):
                    if 'default' in params:
                        if cls._precomputed_specs[index]:
                            field_name, field_spec, value_spec, field_params, _ = cls._precomputed_specs[index]
                        else:
                            field_name, field_spec, value_spec, field_params, _ = self._determine_spec(index)
                        self.children[index] = self._make_value(field_name, field_spec, value_spec, field_params, None)
            return

        try:
            self.children = []
            contents_length = len(self._contents)
            child_pointer = 0
            field = 0
            field_len = len(self._fields)
            parts = None
            again = child_pointer < contents_length
            while again:
                if parts is None:
                    parts, child_pointer = _parse(self._contents, contents_length, pointer=child_pointer)
                again = child_pointer < contents_length

                if field < field_len:
                    _, field_spec, value_spec, field_params, spec_override = (
                        cls._precomputed_specs[field] or self._determine_spec(field))

                    # If the next value is optional or default, allow it to be absent
                    if field_params and ('optional' in field_params or 'default' in field_params):
                        if self._field_ids[field] != (parts[0], parts[2]) and field_spec != Any:

                            # See if the value is a valid choice before assuming
                            # that we have a missing optional or default value
                            choice_match = False
                            if issubclass(field_spec, Choice):
                                try:
                                    tester = field_spec(**field_params)
                                    tester.validate(parts[0], parts[2], parts[4])
                                    choice_match = True
                                except (ValueError):
                                    pass

                            if not choice_match:
                                if 'optional' in field_params:
                                    self.children.append(VOID)
                                else:
                                    self.children.append(field_spec(**field_params))
                                field += 1
                                again = True
                                continue

                    if field_spec is None or (spec_override and issubclass(field_spec, Any)):
                        field_spec = value_spec
                        spec_override = None

                    if spec_override:
                        child = parts + (field_spec, field_params, value_spec)
                    else:
                        child = parts + (field_spec, field_params)

                # Handle situations where an optional or defaulted field definition is incorrect
                elif field_len > 0 and field + 1 <= field_len:
                    missed_fields = []
                    prev_field = field - 1
                    while prev_field >= 0:
                        prev_field_info = self._fields[prev_field]
                        if len(prev_field_info) < 3:
                            break
                        if 'optional' in prev_field_info[2] or 'default' in prev_field_info[2]:
                            missed_fields.append(prev_field_info[0])
                        prev_field -= 1
                    plural = 's' if len(missed_fields) > 1 else ''
                    missed_field_names = ', '.join(missed_fields)
                    raise ValueError(unwrap(
                        '''
                        Data for field %s (%s class, %s method, tag %s) does
                        not match the field definition%s of %s
                        ''',
                        field + 1,
                        CLASS_NUM_TO_NAME_MAP.get(parts[0]),
                        METHOD_NUM_TO_NAME_MAP.get(parts[1]),
                        parts[2],
                        plural,
                        missed_field_names
                    ))

                else:
                    child = parts

                if recurse:
                    child = _build(*child)
                    if isinstance(child, (Sequence, SequenceOf)):
                        child._parse_children(recurse=True)

                self.children.append(child)
                field += 1
                parts = None

            index = len(self.children)
            while index < field_len:
                name, field_spec, field_params = self._fields[index]
                if 'default' in field_params:
                    self.children.append(field_spec(**field_params))
                elif 'optional' in field_params:
                    self.children.append(VOID)
                else:
                    raise ValueError(unwrap(
                        '''
                        Field "%s" is missing from structure
                        ''',
                        name
                    ))
                index += 1

        except (ValueError, TypeError) as e:
            args = e.args[1:]
            e.args = (e.args[0] + '\n    while parsing %s' % type_name(self),) + args
            raise e