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')
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
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
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
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
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
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)
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
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, )
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
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)
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, )
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
def visit(self, node): if typeutils.is_container(node): return [self.node_visit(n) for n in node] else: return self.node_visit(node)
def visit(self, node): if typeutils.is_container(node): return self.container_visit(node) else: return self.node_visit(node)
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)
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))