def unset(self, of: t.Union[_T_Enum, t.Type[_T]]) -> None: preconditions.check_instance_of(of, (type, enum.Enum)) if isinstance(of, enum.Enum): self._enums.get(type(of), set()).discard(of) else: assert isinstance(of, type) self._objects.pop(of, None)
def apply( self, plugin_name: t.Optional[str] = None, from_project: t.Union[None, str, 'Project'] = None, merge: bool = True, ) -> Namespace: """ Loads a plugin and applies it to the project. Plugins are loaded via #Context.plugin_loader and applied to the project immediately after. The default implementation for loading plugins uses Python package entrypoints as configured in the #Context. Returns the extension namespace created for the plugin. The extension is also merged into the #Project.ext namespace unless the *merge* parameter is set to #False. """ if plugin_name is not None: if from_project is not None: raise TypeError( 'plugin_name and from_project should not be specified at the same time' ) check_instance_of(plugin_name, str, 'plugin_name') plugin = self.context.plugin_loader.load_plugin(plugin_name) plugin.apply(self) elif from_project is not None: from_project = self.subproject(from_project) if isinstance( from_project, str) else from_project check_instance_of(from_project, (str, Project), 'from_project') if not from_project._on_apply: raise ValueError(f'{from_project} has no on_apply handler') from_project._on_apply(self) from_project.exports.merge_into(self.extensions) else: raise TypeError('need plugin_name or from_project')
def do_last(self, action: t.Union['Action', Closure]) -> None: from craftr.core.actions import Action, LambdaAction check_instance_of(action, (Action, Closure), 'action') if isinstance(action, Closure): closure = action action = LambdaAction( lambda context: closure(self, context).apply(self)) self.do_last_actions.append(action)
def get(self, of): preconditions.check_instance_of(of, (type, enum.Enum)) if isinstance(of, enum.Enum): return of if of in self._enums.get(type(of), set()) else None result = self._objects.get(of) if result is None and self._parent is not None: result = self._parent.get(of) return result
def get_converters(self, type_: BaseType, direction: Direction) -> t.Iterable[Converter]: preconditions.check_instance_of(type_, BaseType) # type: ignore if isinstance(type_, ConcreteType ) and type_.type in self.__converters_by_type[direction]: yield self.__converters_by_type[direction][type_.type] elif type(type_) in self.__converters_by_type[direction]: yield self.__converters_by_type[direction][type(type_)] for module in reversed(self.__converter_providers): yield from module.get_converters(type_, direction)
def dataclass_to_schema( dataclass_type: t.Type, type_hint_adapter: t.Optional[TypeHintAdapter] = None) -> Schema: """ Converts the given *dataclass_type* to a #Schema. The dataclass fields are converted to #BaseType#s via the given *type_hint_adapter*. If no adapter is specified, the #DefaultTypeHintAdapter will be used (note that this adapter does _not_ expand #ConcreteType#s of dataclasses to #ObjectType#s). """ preconditions.check_instance_of(dataclass_type, type) preconditions.check_argument(is_dataclass(dataclass_type), 'expected @dataclass type') if type_hint_adapter is None: type_hint_adapter = DefaultTypeHintAdapter() fields: t.Dict[str, Field] = {} annotations = get_type_hints(dataclass_type) resolver = ModuleForwardReferenceResolver( sys.modules[dataclass_type.__module__]) for field in _get_fields(dataclass_type): if not field.init: # If we cannot initialize the field in the constructor, we should also # exclude it from the definition of the type for de-/serializing. continue # NOTE (NiklasRosenstein): We do not use #field.type because if it contains a #t.ForwardRef, # it will not be resolved and we can't convert that to our type representation. field_type_hint = type_hint_adapter.adapt_type_hint( annotations[field.name], None, resolver) field_annotations = list( field.metadata.get(ANNOTATIONS_METADATA_KEY, [])) # Handle field(metadata={'alias': ...}). The value can be a string or list of strings. if not any(isinstance(x, A.alias) for x in field_annotations): if 'alias' in field.metadata: aliases = field.metadata['alias'] if isinstance(aliases, str): aliases = [aliases] field_annotations.append(A.alias(*aliases)) field_default_factory = field.default_factory # type: ignore fields[field.name] = Field( field.name, field_type_hint, field_annotations, NotSet.Value if field.default == _MISSING else field.default, NotSet.Value if field_default_factory == _MISSING else field_default_factory) return Schema( dataclass_type.__name__, fields, list(A.get_type_annotations(dataclass_type).values()), dataclass_type, )
def depends_on(self, *tasks: t.Union[str, 'Task']) -> None: """ Specify that the task dependends on the specified other tasks. Strings are resolved from the tasks own project. """ for index, item in enumerate(tasks): check_instance_of(item, (str, Task), lambda: 'task ' + str(index)) if isinstance(item, str): self.dependencies += self.project.tasks.resolve(item) elif isinstance(item, Task): self.dependencies.append(item)
def __init__( self, func: t.Callable[[t.Optional[U], t.Optional[V]], T], left: Provider[U], right: Provider[V], ) -> None: check_instance_of(left, Provider) # type: ignore # python/mypy#5374 check_instance_of(right, Provider) # type: ignore # python/mypy#5374 self._func = func self._left = left self._right = right
def depends_on(self, *tasks: t.Union[str, Task]) -> None: """ Specify that the task dependends on the specified other tasks. Strings are resolved from the tasks own project. """ if self.finalized: raise RuntimeError(f'Task is finalized, cannot add dependency') for index, item in enumerate(tasks): check_instance_of(item, (str, Task), lambda: 'task ' + str(index)) if isinstance(item, str): self.dependencies += self.project.tasks.resolve(item) elif isinstance(item, Task): self.dependencies.append(item)
def convert(self, direction: Direction, value: t.Any, type_hint: t.Union[BaseType, t.Type[T]], filename: t.Optional[str] = None, position: t.Optional[Position] = None, key: t.Union[str, int, None] = None, annotations: t.Optional[t.List[t.Any]] = None, settings: t.Optional[t.List[t.Any]] = None, ) -> T: preconditions.check_instance_of(direction, Direction) type_ = self.adapt_type_hint(type_hint) field = Field('$', type_, annotations or []) loc = Location(None, type_, key, filename, position) ctx = Context(None, self, self, self, Settings(*(settings or []), parent=self.settings), direction, value, loc, field) return ctx.convert()
def convert(self, ctx: Context) -> t.Any: preconditions.check_instance_of(ctx.type, ConcreteType) preconditions.check_argument( t.cast(ConcreteType, ctx.type).type is decimal.Decimal, 'must be Decimal') context = Optional(ctx.get_annotation(A.precision))\ .map(lambda b: b.to_context()).or_else(None) fieldinfo = ctx.get_annotation(A.fieldinfo) or A.fieldinfo() if ctx.direction == Direction.deserialize: if (not fieldinfo.strict and isinstance(ctx.value, (int, float))) or isinstance( ctx.value, str): return decimal.Decimal(ctx.value, context) raise ctx.type_error(expected='str') else: if not isinstance(ctx.value, decimal.Decimal): raise ctx.type_error(expected=decimal.Decimal) return str(ctx.value)
def create_instance(self, type: t.Type[T], fqn: str, config_key: str = '<notset>') -> T: """ Creates an instance of the specified type from a fully qualified name. If the class implements the #LoadableFromSettings protocol, the method will be called to create an instance. """ class_ = load_class(fqn) try: if issubclass(class_, LoadableFromSettings): instance = class_.from_settings(self) else: instance = class_() except Exception: raise ClassInstantiationError( f'Error while instantiating instance of `{class_.__module__}.{class_.__qualname__}` ' f'from configuration key `{config_key}`') check_instance_of(instance, type) return instance
def convert(self, ctx: Context) -> t.Any: preconditions.check_instance_of(ctx.type, ConcreteType) type_ = t.cast(ConcreteType, ctx.type).type datefmt = ctx.get_annotation(A.datefmt) or ( self.DEFAULT_DATE_FMT if type_ == datetime.date else self.DEFAULT_TIME_FMT if type_ == datetime.time else self.DEFAULT_DATETIME_FMT if type_ == datetime.datetime else None) assert datefmt is not None if ctx.direction == Direction.deserialize: if isinstance(ctx.value, type_): return ctx.value elif isinstance(ctx.value, str): dt = datefmt.parse( type_, ctx.value ) # TODO(NiklasRosenstein): Rethrow as ConversionError assert isinstance(dt, type_) return dt raise ctx.type_error(expected=f'str|{type_.__name__}') else: if not isinstance(ctx.value, type_): raise ctx.type_error(expected=type_) return datefmt.format(ctx.value)
def subtype(extends: t.Type, name: str = None) -> t.Callable[[T_Type], T_Type]: """ Decorator for subtypes of the #@union-decorated type *extends*. The *extends* class must use #union.Subtypes.Dynamic. If a *name* is specified, the class will also be decorated with the #typeinfo annotation. The decorated class _must_ be a subclass of the *extends* class, otherwise a #TypeError is raised. Example: ```py @dataclass @union.subtype(Person) class Student(Person): courses: t.Set[str] ``` """ preconditions.check_instance_of(extends, type) inst = preconditions.check_not_none( get_annotation(extends, union, None), lambda: f'{extends.__name__} is not annotated with @union') subtypes = preconditions.check_instance_of( inst.subtypes, DynamicSubtypes, lambda: f'{extends.__name__} is not using union.Subtypes.Dynamic') def decorator(subtype: T_Type) -> T_Type: preconditions.check_subclass_of(subtype, extends) if name is not None: subtype = typeinfo(name)(subtype) subtypes.add_type(typeinfo.get_name(subtype), subtype) return subtype return decorator
def convert(self, ctx: Context) -> t.Any: source_type = type(ctx.value) target_type = preconditions.check_instance_of(ctx.location.type, ConcreteType).type fieldinfo = ctx.get_annotation(A.fieldinfo) or A.fieldinfo() strict = ctx.direction == Direction.serialize or fieldinfo.strict func = (self._strict_adapters if strict else self._nonstrict_adapters)\ .get((source_type, target_type)) if func is None: raise ctx.error( f'unable to {ctx.direction.name} {source_type.__name__} -> {target_type.__name__}' ) try: return func(ctx.value) except ValueError as exc: raise ctx.error(str(exc))
def add_converter_for_type(self, type_: t.Type, converter: Converter, direction: Direction = None) -> None: preconditions.check_instance_of(type_, type) preconditions.check_instance_of(converter, Converter) # type: ignore if direction is not None: preconditions.check_instance_of(direction, Direction) self.__converters_by_type[direction][type_] = converter else: self.__converters_by_type[Direction.deserialize][type_] = converter self.__converters_by_type[Direction.serialize][type_] = converter
def add_converter_provider(self, provider: ConverterProvider) -> None: preconditions.check_instance_of(provider, ConverterProvider) # type: ignore self.__converter_providers.append(provider)
def __init__(self, func: t.Callable[[t.Optional[U]], t.Optional[T]], inner: Provider[U]) -> None: check_instance_of(inner, Provider) # type: ignore # python/mypy#5374 self._func = func self._inner = inner