def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None: """ Evaluates the ForwardRef to actual Field based on global and local namespaces :param globalns: global namespace :type globalns: Any :param localns: local namespace :type localns: Any :return: None :rtype: None """ if self.to.__class__ == ForwardRef: self.to = evaluate_forwardref( self.to, # type: ignore globalns, localns or None, ) (self.__type__, self.column_type,) = populate_m2m_params_based_on_to_model( to=self.to, nullable=self.nullable, ) if self.through.__class__ == ForwardRef: self.through = evaluate_forwardref( self.through, # type: ignore globalns, localns or None, ) forbid_through_relations(self.through)
def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any: annotation = param.annotation if isinstance(annotation, str): annotation = ForwardRef(annotation) annotation = evaluate_forwardref(annotation, globalns, globalns) return annotation
def evaluate_forward_ref(cls, globalns: Any, localns: Any) -> None: """ Evaluates the ForwardRef to actual Field based on global and local namespaces :param globalns: global namespace :type globalns: Any :param localns: local namespace :type localns: Any :return: None :rtype: None """ if cls.to.__class__ == ForwardRef: cls.to = evaluate_forwardref( cls.to, # type: ignore globalns, localns or None, ) ( cls.__type__, cls.constraints, cls.column_type, ) = populate_fk_params_based_on_to_model( to=cls.to, nullable=cls.nullable, ondelete=cls.ondelete, onupdate=cls.onupdate, )
def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any: annotation = param.annotation if isinstance(annotation, str): # Temporary ignore type # Ref: https://github.com/samuelcolvin/pydantic/issues/1738 annotation = ForwardRef(annotation) # type: ignore annotation = evaluate_forwardref(annotation, globalns, globalns) return annotation
def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any: annotation = param.annotation if isinstance(annotation, str): try: annotation = ForwardRef(annotation) # type: ignore annotation = evaluate_forwardref(annotation, globalns, globalns) except (TypeError, NameError): annotation = param.annotation return annotation
def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any: annotation = param.annotation if isinstance(annotation, str): annotation = ForwardRef(annotation) try: annotation = evaluate_forwardref(annotation, globalns, globalns) except Exception as e: logger.opt(colors=True, exception=e).warning( f'Unknown ForwardRef["{param.annotation}"] for parameter {param.name}' ) return inspect.Parameter.empty return annotation
def _make_input_class(f, json_encoders=None): defaults = {} annotations = {} json_encoders_arg = json_encoders if json_encoders else {} class Config: # Override the lenience of the base TaskInput class and only allow expected arguments extra = 'forbid' json_encoders = { **json_encoders_arg, **smttask_json_encoders, **base.TaskInput.Config.json_encoders } for nm, param in inspect.signature(f).parameters.items(): if param.annotation is inspect._empty: raise TypeError( "Constructing a Task requires that all function arguments " f"be annotated. Offender: argument '{nm}' of '{f.__qualname__}'." ) annotation = param.annotation if isinstance(annotation, str): # HACK to resolve forward refs globalns = sys.modules[f.__module__].__dict__.copy() annotation = evaluate_forwardref(ForwardRef(annotation), globalns=globalns, localns=None) annotations[nm] = Union[base.Task, annotation] if param.default is not inspect._empty: defaults[nm] = param.default Inputs = ModelMetaclass(f"{f.__qualname__}.Inputs", (base.TaskInput, ), { **defaults, 'Config': Config, '__annotations__': annotations }) # Set correct module; workaround for https://bugs.python.org/issue28869 Inputs.__module__ = f.__module__ # update_forward_refs required for 3.9+ style annotations # DEVNOTE: When one inspects Inputs.__fields__, some types may still contain 'ForwardRef' # I don't know why that is, but checking Inputs.__fields__[field name].__args__[ForwardRef index].__forward_evaluated__ should still be True # and [...].__forward_value__ should be the expected type Inputs.update_forward_refs() return Inputs
def get_typed_annotation( dependency_param: inspect.Parameter, global_namespace: Dict[str, Any], ) -> Any: """Solve forward reference annotation for instance of `inspect.Parameter`. Arguments: dependency_param: instance of `inspect.Parameter` for which possible forward annotation will be evaluated. global_namespace: dictionary of entities that can be used for evaluating forward references. Returns: Parameter annotation. """ annotation = dependency_param.annotation if isinstance(annotation, str): annotation = ForwardRef(annotation) annotation = evaluate_forwardref(annotation, global_namespace, global_namespace) return annotation
def make_forwardref(annotation: str, globalns: Dict[str, Any]): annotation = ForwardRef(annotation) annotation = evaluate_forwardref(annotation, globalns, globalns) return annotation
def find_graphene_type( type_: T.Type, field: ModelField, registry: Registry, parent_type: T.Type = None, model: T.Type[BaseModel] = None, ) -> BaseType: # noqa: C901 """ Map a native Python type to a Graphene-supported Field type, where possible, throwing an error if we don't know what to map it to. """ if type_ == uuid.UUID: return UUID elif type_ in (str, bytes): return String elif type_ == datetime.datetime: return DateTime elif type_ == datetime.date: return Date elif type_ == datetime.time: return Time elif type_ == bool: return Boolean elif type_ == float: return Float elif type_ == decimal.Decimal: return GrapheneDecimal if DECIMAL_SUPPORTED else Float elif type_ == int: return Int elif type_ in (tuple, list, set): # TODO: do Sets really belong here? return List elif registry and registry.get_type_for_model(type_): return registry.get_type_for_model(type_) elif registry and (isinstance(type_, BaseModel) or (inspect.isclass(type_) and issubclass(type_, BaseModel))): # If it's a Pydantic model that hasn't yet been wrapped with a ObjectType, # we can put a placeholder in and request that `resolve_placeholders()` # be called to update it. registry.add_placeholder_for_model(type_) return registry.get_type_for_model(type_) # NOTE: this has to come before any `issubclass()` checks, because annotated # generic types aren't valid arguments to `issubclass` elif hasattr(type_, "__origin__"): return convert_generic_python_type(type_, field, registry, parent_type=parent_type, model=model) elif isinstance(type_, T.ForwardRef): # A special case! We have to do a little hackery to try and resolve # the type that this points to, by trying to reference a "sibling" type # to where this was defined so we can get access to that namespace... sibling = model or parent_type if not sibling: raise ConversionError( "Don't know how to convert the Pydantic field " f"{field!r} ({field.type_}), could not resolve " "the forward reference. Did you call `resolve_placeholders()`? " "See the README for more on forward references.") module_ns = sys.modules[sibling.__module__].__dict__ resolved = evaluate_forwardref(type_, module_ns, None) # TODO: make this behavior optional. maybe this is a place for the TypeOptions to play a role? if registry: registry.add_placeholder_for_model(resolved) return find_graphene_type(resolved, field, registry, parent_type=parent_type, model=model) elif issubclass(type_, enum.Enum): return Enum.from_enum(type_) elif issubclass(type_, str): return String else: raise ConversionError( f"Don't know how to convert the Pydantic field {field!r} ({field.type_})" )
def make_forwardref(annotation: str, globalns: DictStrAny) -> Any: forward_ref = ForwardRef(annotation) return evaluate_forwardref(forward_ref, globalns, globalns)