Python typing.ForwardRef() Examples

The following are 30 code examples of typing.ForwardRef(). You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may also want to check out all available functions/classes of the module typing , or try the search function .
Example #1
Source File: typing.py    From pydantic with MIT License 6 votes vote down vote up
def resolve_annotations(raw_annotations: Dict[str, Type[Any]], module_name: Optional[str]) -> Dict[str, Type[Any]]:
    """
    Partially taken from typing.get_type_hints.

    Resolve string or ForwardRef annotations into type objects if possible.
    """
    if module_name:
        base_globals: Optional[Dict[str, Any]] = sys.modules[module_name].__dict__
    else:
        base_globals = None
    annotations = {}
    for name, value in raw_annotations.items():
        if isinstance(value, str):
            if sys.version_info >= (3, 7):
                value = ForwardRef(value, is_argument=False)
            else:
                value = ForwardRef(value)
        try:
            value = _eval_type(value, base_globals, None)
        except NameError:
            # this is ok, it can be fixed with update_forward_refs
            pass
        annotations[name] = value
    return annotations 
Example #2
Source File: typed_json_dataclass.py    From typed-json-dataclass with MIT License 6 votes vote down vote up
def _validate_list_types(self, actual_value, expected_type):
        """
        Recursively checks nested lists like List[List[str]] and checks that
        all elements in the list are uniform
        """
        # typing.List[type] will have __args__
        if isinstance(actual_value, list) and \
           hasattr(expected_type, '__args__'):
            nested_type = expected_type.__args__[0]
            if isinstance(nested_type, typing.ForwardRef):
                # Strip out ForwardRef(' and ') as a hack for getting the
                # expected class
                type_for_forward_ref = str(nested_type)[12:-2]
                return all(
                    type_for_forward_ref == v.__class__.__name__
                    for v in actual_value
                )

            return all(
                self._validate_list_types(v, nested_type) for v in actual_value
            )
        else:
            return isinstance(actual_value, expected_type) 
Example #3
Source File: draw_tnodes.py    From pyta with GNU General Public License v3.0 6 votes vote down vote up
def _type_str(type):
    if isinstance(type, TypeVar) or isinstance(type, _GenericAlias) or \
            type.__class__.__name__ == '_Any' or \
            isinstance(type, ForwardRef) or type is None:
        return str(type).replace('typing.', '')
    elif getattr(type, '__origin__', None) is Union:
        trimmed_args = []
        for arg in type.__args__:
            if not isinstance(arg, _GenericAlias):
                trimmed_args.append(_type_str(arg))
            else:
                break
        if len(trimmed_args) == 0:
            trimmed_args.append(_type_str(type.__args__[0]))
        if len(trimmed_args) != len(type.__args__):
            trimmed_args.append('...')
        return 'Union[%s]' % ', '.join(trimmed_args)
    else:
        return type.__name__ 
Example #4
Source File: base.py    From pyta with GNU General Public License v3.0 6 votes vote down vote up
def literal_substitute(t: type, type_map: Dict[str, type]) -> type:
    """Make substitutions in t according to type_map, returning resulting type."""
    if isinstance(t, TypeVar) and t.__name__ in type_map:
        return type_map[t.__name__]
    elif isinstance(t, TypeVar):
        return TypeVar(t.__name__)
    elif isinstance(t, ForwardRef):
        return ForwardRef(literal_substitute(t.__forward_arg__, type_map))
    elif isinstance(t, TuplePlus):
        subbed_args = [literal_substitute(t1, type_map) for t1 in t.__constraints__]
        return TuplePlus('tup+', *subbed_args)
    elif is_callable(t):
        args = list(literal_substitute(t1, type_map) for t1 in t.__args__[:-1])
        res = literal_substitute(t.__args__[-1], type_map)
        new_t = Callable[args, res]
        if hasattr(t, '__polymorphic_tvars__'):
            new_t.__polymorphic_tvars__ = t.__polymorphic_tvars__.copy()
        return new_t
    elif isinstance(t, _GenericAlias) and t.__args__ is not None:
        return t.copy_with(tuple(literal_substitute(t1, type_map) for t1 in t.__args__))
    else:
        return t 
Example #5
Source File: type_store.py    From pyta with GNU General Public License v3.0 6 votes vote down vote up
def lookup_method(self, operator, *args, node):
        """Helper method to lookup a method type given the operator and types of arguments.

        TODO: modify this implementation to use mro.
        """
        if args:
            # First try to do a direct lookup.
            if isinstance(args[0], ForwardRef) and operator in self.classes[args[0].__forward_arg__]:
                for func_type, _ in self.classes[args[0].__forward_arg__][operator]:
                    if len(args) != len(func_type.__args__) - 1:
                        continue
                    if self.type_constraints.can_unify(Callable[list(args), Any],
                                                       Callable[list(func_type.__args__[:-1]), Any]):
                        return func_type

            # If that doesn't work, fall back on a brute force search.
            func_types_list = self.methods[operator]
            for func_type, _ in func_types_list:
                if len(args) != len(func_type.__args__) - 1:
                    continue
                if self.type_constraints.can_unify(Callable[list(args), Any],
                                                   Callable[list(func_type.__args__[:-1]), Any]):
                    return func_type
            return TypeFailFunction(tuple(func_types_list), None, node) 
Example #6
Source File: typing.py    From pydantic with MIT License 5 votes vote down vote up
def update_field_forward_refs(field: 'ModelField', globalns: Any, localns: Any) -> None:
    """
    Try to update ForwardRefs on fields based on this ModelField, globalns and localns.
    """
    if field.type_.__class__ == ForwardRef:
        field.type_ = evaluate_forwardref(field.type_, globalns, localns or None)
        field.prepare()
    if field.sub_fields:
        for sub_f in field.sub_fields:
            update_field_forward_refs(sub_f, globalns=globalns, localns=localns) 
Example #7
Source File: test_unify.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def test_same_forward_ref():
    fr1 = ForwardRef('a')
    fr2 = ForwardRef('a')
    unify_helper(fr1, fr2, fr1)
    unify_helper(fr1, fr2, fr2) 
Example #8
Source File: typing.py    From pydantic with MIT License 5 votes vote down vote up
def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
        return type_._evaluate(globalns, localns) 
Example #9
Source File: typing.py    From pydantic with MIT License 5 votes vote down vote up
def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
        return type_._eval_type(globalns, localns) 
Example #10
Source File: _compat.py    From punq with MIT License 5 votes vote down vote up
def ensure_forward_ref(self, service, factory, instance, **kwargs):
    if isinstance(service, str):
        self.register(ForwardRef(service), factory, instance, **kwargs) 
Example #11
Source File: recast.py    From cloudformation-cli-python-plugin with Apache License 2.0 5 votes vote down vote up
def get_forward_ref_type() -> Any:
    # ignoring mypy on the import as it catches (_)ForwardRef as invalid, use for
    # introspection is valid:
    # https://docs.python.org/3/library/typing.html#typing.ForwardRef
    if "ForwardRef" in dir(typing):
        return typing.ForwardRef  # type: ignore
    return typing._ForwardRef  # type: ignore 
Example #12
Source File: base.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def _eval_node(node_name: str, _globals: Dict[str, type], _locals: Dict[str, type]):
    """Return a type represented by node_name."""
    try:
        eval_type = eval(node_name, _globals, _locals)
    except:
        eval_type = ForwardRef(node_name)

    if eval_type in (list, dict, tuple, set):
        # Annotation set as class type (ie. list) instead of typing generic (ie. List[Any])
        return eval(f"typing.{node_name.capitalize()}", _globals, _locals)
    else:
        return eval_type 
Example #13
Source File: base.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def _node_to_type(node: NodeNG, locals: Dict[str, type] = None) -> type:
    """Return a type represented by the input node."""
    locals = locals or _TYPESHED_TVARS
    if node is None:
        return Any
    elif isinstance(node, str):
        return _eval_node(node, globals(), locals)
    elif isinstance(node, astroid.Name):
        return _eval_node(node.name, globals(), locals)
    elif isinstance(node, astroid.Attribute):
        return _eval_node(node.attrname, globals(), locals)
    elif isinstance(node, astroid.Subscript):
        v = _node_to_type(node.value)
        s = _node_to_type(node.slice)
        if isinstance(v, ForwardRef):
            return literal_substitute(v, {v.__forward_arg__: s})
        else:
            return v[s]
    elif isinstance(node, astroid.Index):
        return _node_to_type(node.value)
    elif isinstance(node, astroid.Tuple):
        return tuple(_node_to_type(t) for t in node.elts if not isinstance(t, astroid.Ellipsis))
    elif isinstance(node, astroid.List):
        return [_node_to_type(t) for t in node.elts if not isinstance(t, astroid.Ellipsis)]
    elif isinstance(node, astroid.Const) and node.value is None:
        return None
    elif isinstance(node, astroid.Const) and isinstance(node.value, str):
        return _node_to_type(node.value)
    elif isinstance(node, astroid.Const) and node.value is Ellipsis:
        return Ellipsis
    else:
        return node 
Example #14
Source File: base.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def _ann_node_to_type(node: astroid.Name) -> TypeResult:
    """Return a type represented by the input node, substituting Any for missing arguments in generic types
    """
    try:
        ann_node_type = _node_to_type(node)
    except SyntaxError:
        # Attempted to create ForwardRef with invalid string
        return TypeFailAnnotationInvalid(node)

    ann_type = _generic_to_annotation(ann_node_type, node)
    return ann_type 
Example #15
Source File: utils.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def _get_name(t: type) -> str:
    """If t is associated with a class, return the name of the class; otherwise, return a string repr. of t"""
    if isinstance(t, ForwardRef):
        return t.__forward_arg__
    elif isinstance(t, type):
        return t.__name__
    elif isinstance(t, _GenericAlias):
        return '{} of {}'.format(_get_name(t.__origin__),
                                 ', '.join(_get_name(arg) for arg in t.__args__))
    else:
        return str(t) 
Example #16
Source File: type_inference_visitor.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def get_attribute_class(self, t: type) -> Tuple[str, type, bool]:
        """Check for and return name and type of class represented by type t."""
        is_inst_expr = True

        # TypeVar; e.g., 'TypeVar('_T1')' corresponding to a function argument
        if isinstance(t, TypeVar):
            return t.__name__, t, None

        # Class type: e.g., 'Type[ForwardRef('A')]'
        if getattr(t, '__origin__', None) is type:
            class_type = t.__args__[0]
            is_inst_expr = False
        # Instance of class or builtin type; e.g., 'ForwardRef('A')' or 'int'
        else:
            class_type = t

        if isinstance(class_type, ForwardRef):
            class_name = class_type.__forward_arg__
        elif isinstance(class_type, _GenericAlias):
            class_name = class_type._name
        else:
            class_name = getattr(t, '__name__', None)

        # TODO: the condition below is too general
        if class_name is not None and class_name not in self.type_store.classes:
            class_name = class_name.lower()

        return class_name, class_type, is_inst_expr 
Example #17
Source File: type_inference_visitor.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def _set_module_environment(self, node: astroid.Module) -> None:
        """Method to set environment of a Module node."""
        node.type_environment = Environment()
        for name in node.globals:
            if not any(isinstance(elt, (astroid.ImportFrom, astroid.Import)) for elt in node.globals[name]):
                new_tvar = self.type_constraints.fresh_tvar(node.globals[name][0])
                if any(isinstance(elt, astroid.ClassDef) for elt in node.globals[name]):
                    self.type_constraints.unify(new_tvar, Type[ForwardRef(name)], node)
                node.type_environment.globals[name] = new_tvar
        self._populate_local_env(node) 
Example #18
Source File: test_initializer.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def test_class_without_init():
    program = """
    class Foo:
        def fee(self):
            return 1

    foo = Foo()
    """
    ast_mod, ti = cs._parse_text(program)
    for call_node in ast_mod.nodes_of_class(astroid.Call):
        assert isinstance(call_node.inf_type.getValue(), ForwardRef)
        assert call_node.inf_type.getValue() == ForwardRef('Foo') 
Example #19
Source File: test_initializer.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def test_class_with_init():
    program = """
    class Foo:
    
        def __init__(self):
            self.a = 5
    
    foo = Foo()
    """
    ast_mod, ti = cs._parse_text(program)
    for call_node in ast_mod.nodes_of_class(astroid.Call):
        assert isinstance(call_node.inf_type.getValue(), ForwardRef)
        assert call_node.inf_type.getValue() == ForwardRef('Foo') 
Example #20
Source File: test_function_def_inference.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def test_functiondef_classmethod():
    program = \
        '''
        class A:

            @classmethod
            def method(cls, x):
                return x + 1
        '''
    module, inferer = cs._parse_text(program)
    for func_def in module.nodes_of_class(astroid.FunctionDef):
        assert lookup_type(inferer, func_def, func_def.argnames()[0]) == Type[ForwardRef('A')] 
Example #21
Source File: test_function_def_inference.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def test_functiondef_method():
    program = \
        '''
        class A:

            def method(self, x):
                return x + 1
        '''
    module, inferer = cs._parse_text(program)
    for func_def in module.nodes_of_class(astroid.FunctionDef):
        assert lookup_type(inferer, func_def, func_def.argnames()[0]) == ForwardRef('A') 
Example #22
Source File: test_tnode_structure.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def test_userdefn_inheritance_simple(draw=False):
    src = """
    class A:
        pass

    class B:
        pass

    class C(A, B):
        pass

    a = A()
    b = B()
    c = C()
    """
    ast_mod, ti = cs._parse_text(src, reset=True)
    tc = ti.type_constraints
    a, b, c = [ti.lookup_typevar(node, node.name) for node
               in ast_mod.nodes_of_class(astroid.AssignName)]

    assert isinstance(tc.unify(a, b), TypeFail)
    assert tc.unify(c, a).getValue() == ForwardRef('C')
    assert isinstance(tc.unify(a, c), TypeFail)  # note that order matters!
    assert tc.unify(c, b).getValue() == ForwardRef('C')
    assert isinstance(tc.unify(b, c), TypeFail)

    actual_set = tc_to_disjoint(tc)
    expected_set = [
        {'~_TV0', Type[ForwardRef('A')]},
        {'~_TV1', Type[ForwardRef('B')]},
        {'~_TV2', Type[ForwardRef('C')]},
        {'~_TV3', ForwardRef('A')},
        {'~_TV4', ForwardRef('B')},
        {'~_TV5', ForwardRef('C')}
    ]

    # _TNodes should be unchanged after unification
    compare_list_sets(actual_set, expected_set)

    if draw:
        gen_graph_from_nodes(tc._nodes) 
Example #23
Source File: test_tnode_structure.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def test_forward_ref(draw=False):
    tc.reset()
    t0 = tc.fresh_tvar()
    assert isinstance(tc.unify(ForwardRef('A'), ForwardRef('B')), TypeFail)
    assert tc.unify(ForwardRef('A'), ForwardRef('A')).getValue() == ForwardRef('A')
    assert tc.unify(t0, ForwardRef('A')).getValue() == ForwardRef('A')
    actual_set = tc_to_disjoint(tc)
    expected_set = [{'~_TV0', ForwardRef('A')}, {ForwardRef('B')}]
    compare_list_sets(actual_set, expected_set)
    if draw:
        gen_graph_from_nodes(tc._nodes) 
Example #24
Source File: test_unify.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def test_one_forward_ref():
    fr = ForwardRef('a')
    unify_helper(fr, str, TypeFail("Attempted to unify forwardref  with non-ref"))


# Unify Tuples 
Example #25
Source File: test_unify.py    From pyta with GNU General Public License v3.0 5 votes vote down vote up
def test_diff_forward_ref():
    skip('The existing error msg does not apply to this situation')
    fr1 = ForwardRef('a')
    fr2 = ForwardRef('b')
    unify_helper(fr1, fr2, TypeFail("Attempted to unify forwardref  with non-ref")) 
Example #26
Source File: type_inference_visitor.py    From pyta with GNU General Public License v3.0 4 votes vote down vote up
def visit_functiondef(self, node: astroid.FunctionDef) -> None:
        node.inf_type = NoType()

        # Get the inferred type of the function arguments
        inferred_args = [self.lookup_inf_type(node, arg) for arg in node.argnames()]

        if isinstance(node.parent, astroid.ClassDef) and inferred_args:
            # first argument is special in these cases
            if node.type == 'method':
                self.type_constraints.unify(inferred_args[0], ForwardRef(node.parent.name), node)
            elif node.type == 'classmethod':
                self.type_constraints.unify(inferred_args[0], Type[ForwardRef(node.parent.name)], node)

        # Get inferred return type
        if any(node.nodes_of_class(astroid.Return)):
            return_node = list(node.nodes_of_class(astroid.Return))[-1]
            if isinstance(return_node.inf_type, TypeFail):
                inferred_return = return_node.inf_type
            else:
                inferred_return = self.lookup_inf_type(node, 'return')
        elif node.name == '__init__' and inferred_args:
            inferred_return = inferred_args[0]
        else:
            inferred_return = TypeInfo(type(None))

        # Update the environment storing the function's type.
        polymorphic_tvars = set()
        for arg in inferred_args + [inferred_return]:
            arg >> (
                lambda a: polymorphic_tvars.add(a.__name__) if isinstance(a, TypeVar) else None)

        # Create function signature
        func_type = create_Callable_TypeResult(failable_collect(inferred_args), inferred_return, polymorphic_tvars)

        # Check for optional arguments, create a Union of function signatures if necessary
        num_defaults = len(node.args.defaults)
        if num_defaults > 0 and not isinstance(func_type, TypeFail):
            for i in range(num_defaults):
                opt_args = inferred_args[:-1-i]
                opt_func_type = create_Callable_TypeResult(failable_collect(opt_args), inferred_return, polymorphic_tvars)
                func_type = func_type >> (
                    lambda f: opt_func_type >> (
                        lambda opt_f: TypeInfo(Union[f, opt_f])))

        # Final type signature unify
        func_name = self.lookup_inf_type(node.parent, node.name)
        result = self.type_constraints.unify(func_name, func_type, node)
        if isinstance(result, TypeFail):
            node.inf_type = result 
Example #27
Source File: type_inference_visitor.py    From pyta with GNU General Public License v3.0 4 votes vote down vote up
def get_call_signature(self, c: type, node: NodeNG) -> TypeResult:
        """Check for and return initializer function signature when using class name as Callable.
        Return Callable unmodified otherwise.

        :param c: Class, ForwardRef to a class, or Callable
        :param node: astroid.Call node where function call is occurring
        """
        # Any is interpreted as a function that can take any arguments.
        if c is Any:
            return TypeInfo(Callable[..., Any])
        # Callable type; e.g., 'Callable[[int], int]'
        elif is_callable(c):
            return TypeInfo(c)
        # Union of Callables
        elif getattr(c, '__origin__', None) is Union and all(is_callable(elt) for elt in c.__args__):
            return TypeInfo(c)
        # Class types; e.g., 'Type[ForwardRef('A')]'
        elif getattr(c, '__origin__', None) is type:
            class_type = c.__args__[0]
            if isinstance(class_type, ForwardRef):
                class_name = c.__args__[0].__forward_arg__
            else:
                class_name = class_type.__name__

            if '__init__' in self.type_store.classes[class_name]:
                matching_init_funcs = []
                for func_type, _ in self.type_store.classes[class_name]['__init__']:
                    new_func_type = Callable[list(func_type.__args__[1:-1]), func_type.__args__[0]]
                    matching_init_funcs.append(new_func_type)
                init_func = Union[tuple(matching_init_funcs)]
            else:
                # Classes declared without initializer
                init_func = Callable[[], class_type]
            return TypeInfo(init_func)
        # Class instances; e.g., 'ForwardRef('A')'
        elif isinstance(c, ForwardRef):
            class_type = c
            class_name = c.__forward_arg__

            if '__call__' in self.type_store.classes[class_name]:
                call_args = list(self.type_store.classes[class_name]['__call__'][0][0].__args__)
                call_func = Callable[call_args[1:-1], call_args[-1]]
                return TypeInfo(call_func)
            else:
                class_tnode = self.type_constraints.get_tnode(class_type)
                return TypeFailLookup(class_tnode, node, node.parent)
        else:
            return TypeFailFunction((c,), None, node) 
Example #28
Source File: node.py    From Pyno with MIT License 4 votes vote down vote up
def new_code(self, code):
        self.cleanup()
        # New code, search for in/outputs

        self.code = code
        self.problem = False

        self.call_func = None
        self.cleanup_func = None
        try:
            self.env = {'S': self.local_scope, 'G': self.window.global_scope}
            exec(code, self.env)

            self.call_func = self.env['call']
            if not isinstance(self.call_func, types.FunctionType):
                raise Exception('Call value is not callable!')

            if 'cleanup' in self.env:
                self.cleanup_func = self.env['cleanup']
        except Exception as ex:
            self.problem = True
            self.er_label.text = "Reader error: " + str(ex)
        else:
            self.label.text = self.name = self.call_func.__name__

            signature = inspect.signature(self.call_func)
            inputs = tuple(map(lambda x: x.name, signature.parameters.values()))

            if (tuple in signature.return_annotation.mro()):
                out = []
                i = 0
                for arg in list(signature.return_annotation.__args__):
                    is_string = isinstance(arg, typing.ForwardRef) and isinstance(arg.__forward_arg__, str)
                    out.append(arg.__forward_arg__ if is_string else 'result ' + str(i))
                    i += 1
                outputs = tuple(out)
            else:
                outputs = ('result',)

            self.resize_to_name(self.name)
            self.insert_inouts({'inputs': inputs,
                                'outputs': outputs}) 
Example #29
Source File: recast.py    From cloudformation-cli-python-plugin with Apache License 2.0 4 votes vote down vote up
def _field_to_type(field: Any, key: str, classes: Dict[str, Any]) -> Any:  # noqa: C901
    if field in [int, float, str, bool, typing.Any]:
        return field
    # If it's a ForwardRef we need to find base type
    if isinstance(field, get_forward_ref_type()):
        # Assuming codegen added an _ as a prefix, removing it and then getting the
        # class from model classes
        return classes[field.__forward_arg__[1:]]
    # Assuming this is a generic object created by typing.Union
    try:
        possible_types = field.__args__
        if not possible_types:
            raise InvalidRequest(f"Cannot process type {field} for field {key}")
    except AttributeError:
        raise InvalidRequest(f"Cannot process type {field} for field {key}")
    # Assuming that the union is generated from typing.Optional, so only
    # contains one type and None
    # pylint: disable=unidiomatic-typecheck
    fields = [t for t in possible_types if type(None) != t]
    if len(fields) != 1:
        raise InvalidRequest(f"Cannot process type {field} for field {key}")
    field = fields[0]
    # If it's a primitive we're done
    if field in [int, float, str, bool, typing.Any]:
        return field
    # If it's a ForwardRef we need to find base type
    if isinstance(field, get_forward_ref_type()):
        # Assuming codegen added an _ as a prefix, removing it and then getting the
        # class from model classes
        return classes[field.__forward_arg__[1:]]
    # reduce Sequence/AbstractSet to inner type
    if str(field).startswith("typing.Sequence") or str(field).startswith(
        "typing.AbstractSet"
    ):
        return _field_to_type(field.__args__[0], key, classes)
    if str(field).startswith("typing.MutableMapping"):
        return _field_to_type(field.__args__[1], key, classes)
    # If it's a type we don't know how to handle, we bail
    raise InvalidRequest(f"Cannot process type {field} for field {key}")


# pylint: disable=protected-access,no-member 
Example #30
Source File: type_util.py    From pytypes with Apache License 2.0 4 votes vote down vote up
def resolve_fw_decl(in_type, module_name=None, globs=None, level=0,
        search_stack_depth=2):
    '''Resolves forward references in ``in_type``, see
    https://www.python.org/dev/peps/pep-0484/#forward-references.


    Note:

    ``globs`` should be a dictionary containing values for the names
    that must be resolved in ``in_type``. If ``globs`` is not provided, it
    will be created by ``__globals__`` from the module named ``module_name``,
    plus ``__locals__`` from the last ``search_stack_depth`` stack frames (Default: 2),
    beginning at the calling function. This is to resolve cases where ``in_type`` and/or
    types it fw-references are defined inside a function.

    To prevent walking the stack, set ``search_stack_depth=0``.
    Ideally provide a proper ``globs`` for best efficiency.
    See ``util.get_function_perspective_globals`` for obtaining a ``globs`` that can be
    cached. ``util.get_function_perspective_globals`` works like described above.
    '''
    # Also see discussion at https://github.com/Stewori/pytypes/pull/43
    if in_type in _fw_resolve_cache:
        return _fw_resolve_cache[in_type], True
    if globs is None:
        #if not module_name is None:
        globs = util.get_function_perspective_globals(module_name, level+1,
                level+1+search_stack_depth)
    if isinstance(in_type, _basestring):
        # For the case that a pure forward ref is given as string
        out_type = eval(in_type, globs)
        _fw_resolve_cache[in_type] = out_type
        return out_type, True
    elif isinstance(in_type, ForwardRef):
        # Todo: Mabe somehow get globs from in_type.__forward_code__
        if not in_type.__forward_evaluated__:
            in_type.__forward_value__ = eval(in_type.__forward_arg__, globs)
            in_type.__forward_evaluated__ = True
            return in_type, True
    elif is_Tuple(in_type):
        return in_type, any([resolve_fw_decl(in_tp, None, globs)[1] \
                for in_tp in get_Tuple_params(in_type)])
    elif is_Union(in_type):
        return in_type, any([resolve_fw_decl(in_tp, None, globs)[1] \
                for in_tp in get_Union_params(in_type)])
    elif is_Callable(in_type):
        args, res = get_Callable_args_res(in_type)
        ret = any([resolve_fw_decl(in_tp, None, globs)[1] \
                for in_tp in args])
        ret = resolve_fw_decl(res, None, globs)[1] or ret
        return in_type, ret
    elif hasattr(in_type, '__args__') and in_type.__args__ is not None:
        return in_type, any([resolve_fw_decl(in_tp, None, globs)[1] \
                for in_tp in in_type.__args__])
    return in_type, False