示例#1
0
    def coerce_value(self,
                     setting: spec.Setting,
                     *,
                     allow_missing: bool = False):
        if issubclass(setting.type, types.ConfigType):
            try:
                return setting.type.from_pyvalue(self.value,
                                                 allow_missing=allow_missing)
            except (ValueError, TypeError):
                raise errors.ConfigurationError(
                    f'invalid value type for the {setting.name!r} setting')
        elif setting.set_of:
            if self.value is None and allow_missing:
                return None
            elif not typeutils.is_container(self.value):
                raise errors.ConfigurationError(f'invalid value type for the '
                                                f'{setting.name!r} setting')
            else:
                for v in self.value:
                    if not isinstance(v, setting.type):
                        raise errors.ConfigurationError(
                            f'invalid value type for the '
                            f'{setting.name!r} setting')

                return frozenset(self.value)
        else:
            if isinstance(self.value, setting.type):
                return self.value
            elif self.value is None and allow_missing:
                return None
            else:
                raise errors.ConfigurationError(
                    f'invalid value type for the {setting.name!r} setting')
示例#2
0
 def container_visit(self, node):
     result = []
     for elem in node:
         if base.is_ast_node(elem) or typeutils.is_container(elem):
             result.append(self.visit(elem))
         else:
             result.append(elem)
     return result
示例#3
0
    def container_visit(self, node):
        ctxlist = []
        for el in node:
            if isinstance(el, ast.AST) or typeutils.is_container(el):
                ctx = self.visit(el)

                if isinstance(ctx, list):
                    ctxlist.extend(ctx)
                else:
                    ctxlist.append(ctx)
        return ctxlist
示例#4
0
def nodes_equal(n1, n2):
    if type(n1) is not type(n2):
        return False

    for field, _value in base.iter_fields(n1, include_meta=False):
        if not n1._fields[field].hidden:
            n1v = getattr(n1, field)
            n2v = getattr(n2, field)

            if typeutils.is_container(n1v):
                n1v = list(n1v)
                if typeutils.is_container(n2v):
                    n2v = list(n2v)
                else:
                    return False

                if len(n1v) != len(n2v):
                    return False

                for i, item1 in enumerate(n1v):
                    try:
                        item2 = n2v[i]
                    except IndexError:
                        return False

                    if base.is_ast_node(item1):
                        if not nodes_equal(item1, item2):
                            return False
                    else:
                        if item1 != item2:
                            return False

            elif base.is_ast_node(n1v):
                if not nodes_equal(n1v, n2v):
                    return False

            else:
                if n1v != n2v:
                    return False

    return True
示例#5
0
 def combine_field_results(self, results, *, flatten=True):
     if flatten:
         flattened = []
         for res in results:
             if isinstance(res, Field):
                 flattened.append(res)
             elif typeutils.is_container(res):
                 flattened.extend(res)
             else:
                 flattened.append(res)
         return flattened
     else:
         return results
示例#6
0
    def _infer_nullability(self, kwargs: typing.Dict[str, object]) -> bool:
        nullable = False
        for k, v in kwargs.items():
            if typeutils.is_container(v):
                nullable = all(getattr(vv, 'nullable', False) for vv in v)

            elif getattr(v, 'nullable', None):
                nullable = True

            if nullable:
                break

        return nullable
示例#7
0
    def generic_visit(self, node, *, combine_results=None):
        field_results = []

        for field, value in base.iter_fields(node, include_meta=False):
            field_spec = node._fields[field]
            if self.skip_hidden and field_spec.hidden:
                continue

            if typeutils.is_container(value):
                for item in value:
                    if base.is_ast_node(item) or typeutils.is_container(item):
                        res = self.visit(item)
                        if res is not None:
                            field_results.append(res)
            elif base.is_ast_node(value):
                res = self.visit(value)
                if res is not None:
                    field_results.append(res)

        if combine_results is not None:
            return combine_results(field_results)
        else:
            return self.combine_field_results(field_results)
示例#8
0
    def generic_visit(self, node):
        for field, old_value in base.iter_fields(node, include_meta=False):
            old_value = getattr(node, field, None)

            if typeutils.is_container(old_value):
                new_values = old_value.__class__(self.visit(old_value))
                setattr(node, field, old_value.__class__(new_values))

            elif isinstance(old_value, base.AST):
                new_node = self.visit(old_value)
                if new_node is not old_value:
                    setattr(node, field, new_node)

        return node
示例#9
0
def evaluate_config_set(ir: irast.ConfigSet, schema: s_schema.Schema) -> Any:

    value = evaluate_to_python_val(ir.expr, schema)
    if ir.cardinality is qltypes.SchemaCardinality.Many:
        if value is None:
            value = []
        elif not typeutils.is_container(value):
            value = [value]

    return config.Operation(
        opcode=config.OpCode.CONFIG_SET,
        scope=ir.scope,
        setting_name=ir.name,
        value=value,
    )
示例#10
0
def fix_parent_links(node):
    for field, value in iter_fields(node):
        if isinstance(value, dict):
            for n in value.values():
                if is_ast_node(n):
                    n.parent = node
                    fix_parent_links(n)

        elif typeutils.is_container(value):
            for n in value:
                if is_ast_node(n):
                    n.parent = node
                    fix_parent_links(n)

        elif is_ast_node(value):
            value.parent = node
            fix_parent_links(value)

    return node
示例#11
0
    def generic_visit(self, node, *, combine_results=None):
        field_results = []

        for _field, value in base.iter_fields(node, include_meta=False):
            if typeutils.is_container(value):
                for item in value:
                    if base.is_ast_node(item):
                        res = self.visit(item)
                        if res is not None:
                            field_results.append(res)
            elif base.is_ast_node(value):
                res = self.visit(value)
                if res is not None:
                    field_results.append(res)

        if combine_results is not None:
            return combine_results(field_results)
        else:
            return self.combine_field_results(field_results)
示例#12
0
def evaluate_config_set(
        ir: irast.ConfigSet,
        schema: s_schema.Schema) -> Any:

    if ir.scope == qltypes.ConfigScope.GLOBAL:
        raise UnsupportedExpressionError(
            'SET GLOBAL is not supported by static eval'
        )

    value = evaluate_to_python_val(ir.expr, schema)
    if ir.cardinality is qltypes.SchemaCardinality.Many:
        if value is None:
            value = []
        elif not typeutils.is_container(value):
            value = [value]

    return config.Operation(
        opcode=config.OpCode.CONFIG_SET,
        scope=ir.scope,
        setting_name=ir.name,
        value=value,
    )
示例#13
0
def encode_value(val: Any) -> str:
    """Encode value into an appropriate SQL expression."""
    if hasattr(val, 'to_sql_expr'):
        val = val.to_sql_expr()
    elif isinstance(val, tuple):
        val_list = [encode_value(el) for el in val]
        val = f'ROW({", ".join(val_list)})'
    elif isinstance(val, struct.Struct):
        val_list = [encode_value(el) for el in val.as_tuple()]
        val = f'ROW({", ".join(val_list)})'
    elif typeutils.is_container(val):
        val_list = [encode_value(el) for el in val]
        val = f'ARRAY[{", ".join(val_list)}]'
    elif val is None:
        val = 'NULL'
    elif not isinstance(val, numbers.Number):
        val = ql(str(val))
    elif isinstance(val, int):
        val = str(int(val))
    else:
        val = str(val)

    return val
示例#14
0
 def visit(self, node):
     if typeutils.is_container(node):
         return [self.node_visit(n) for n in node]
     else:
         return self.node_visit(node)
示例#15
0
 def visit(self, node):
     if typeutils.is_container(node):
         return self.container_visit(node)
     else:
         return self.node_visit(node)
示例#16
0
 def visit(self, node):
     if typeutils.is_container(node):
         return self.container_visit(node)
     elif base.is_ast_node(node):
         return self.node_visit(node)
示例#17
0
    def from_pyvalue(cls, data, *, allow_missing=False):
        if not isinstance(data, dict):
            raise cls._err(f'expected a dict value, got {type(data)!r}')

        spec = config.get_settings()

        data = dict(data)
        tname = data.pop('_tname', None)
        if tname is not None:
            if '::' in tname:
                tname = s_name.QualName.from_string(tname).name
            cls = spec.get_type_by_name(tname)

        fields = {f.name: f for f in dataclasses.fields(cls)}

        items = {}
        inv_keys = []
        for fieldname, value in data.items():
            field = fields.get(fieldname)
            if field is None:
                if value is None:
                    # This may happen when data is produced by
                    # a polymorphic config query.
                    pass
                else:
                    inv_keys.append(fieldname)

                continue

            f_type = field.type

            if value is None:
                # Config queries return empty pointer values as None.
                continue

            if typing_inspect.is_generic_type(f_type):
                container = typing_inspect.get_origin(f_type)
                if container not in (frozenset, list):
                    raise RuntimeError(f'invalid type annotation on '
                                       f'{cls.__name__}.{fieldname}: '
                                       f'{f_type!r} is not supported')

                eltype = typing_inspect.get_args(f_type, evaluate=True)[0]
                if isinstance(value, eltype):
                    value = container((value, ))
                elif (typeutils.is_container(value)
                      and all(isinstance(v, eltype) for v in value)):
                    value = container(value)
                else:
                    raise cls._err(
                        f'invalid {fieldname!r} field value: expecting '
                        f'{eltype.__name__} or a list thereof, but got '
                        f'{type(value).__name__}')

            elif (issubclass(f_type, CompositeConfigType)
                  and isinstance(value, dict)):

                tname = value.get('_tname', None)
                if tname is not None:
                    if '::' in tname:
                        tname = s_name.QualName.from_string(tname).name
                    actual_f_type = spec.get_type_by_name(tname)
                else:
                    actual_f_type = f_type
                    value['_tname'] = f_type.__name__

                value = actual_f_type.from_pyvalue(value)

            elif not isinstance(value, f_type):
                raise cls._err(
                    f'invalid {fieldname!r} field value: expecting '
                    f'{f_type.__name__}, but got {type(value).__name__}')

            items[fieldname] = value

        if inv_keys:
            inv_keys = ', '.join(repr(r) for r in inv_keys)
            raise cls._err(f'unknown fields: {inv_keys}')

        for fieldname, field in fields.items():
            if fieldname not in items and field.default is dataclasses.MISSING:
                if allow_missing:
                    items[fieldname] = None
                else:
                    raise cls._err(f'missing required field: {fieldname!r}')

        try:
            return cls(**items)
        except (TypeError, ValueError) as ex:
            raise cls._err(str(ex))