def __join_ssa_branches_types_of_members_for_object(obj, previous_context, branch1, branch2): """ Implementation of the SSA joining algorithm for two SSA branches, handling types of members :param previous_context: :param branch1: dict(obj, dict(name, type)) :param branch2: :return: """ type_dict = dict() # NOTE: Explanations in comments are done with an if/else control structure. Other structures are the same. # Proceed with the first branch (if) # For any variable stored in the first branch (note that we only deal with variables that change its type in the # active branch, not all the possible variables accessible within the SSA context. This is also a major speedup # over our previous version. for var_name in branch1: if var_name in branch2: # Variable defined in if and else body: Joins both types type_dict[var_name] = UnionType.add(branch1[var_name], branch2[var_name]) else: # Variable defined in if and in the previous context: Joins the previous type and the if one previous_type = previous_context.get_type_of_member( Localization.get_current(), obj, var_name) if not isinstance(previous_type, StypyTypeError): type_dict[var_name] = UnionType.add(previous_type, branch1[var_name]) else: # Variable defined in if body, but did not exist in the previous context: Joins the if type with an # undefined type, as the if could not be executed type_dict[var_name] = UnionType.add(branch1[var_name], UndefinedType) StypyTypeError.remove_error_msg(previous_type) # Now proceed with the second branch (else). If no else is present and empty dict is passed, and therefore no # processing is done. for var_name in branch2: if var_name in branch1: continue # Already processed (above) else: # Variable defined only in the else body and in the previous context: Treat equally to the if branch # counterpart previous_type = previous_context.get_type_of_member( Localization.get_current(), obj, var_name) if not isinstance(previous_type, StypyTypeError): type_dict[var_name] = UnionType.add(previous_type, branch2[var_name]) else: # Variable defined in else body, but did not existed in the previous context: Same treatment as their # if branch counterpart type_dict[var_name] = UnionType.add(branch2[var_name], UndefinedType) StypyTypeError.remove_error_msg(previous_type) # type_store_previous does not need to be iterated because it is included in the if and else stores return type_dict
def unique(localization, proxy_obj, arguments): dvar = call_utilities.parse_varargs_and_kwargs(localization, arguments, ['return_index', 'return_inverse', 'return_counts'], { 'return_index': bool, 'return_inverse': bool, 'return_counts': bool, }, 'unique') if isinstance(dvar, StypyTypeError): return dvar if Number == type(arguments[0]): ret_arr = call_utilities.create_numpy_array(arguments[0]) else: ret_arr = call_utilities.create_numpy_array(get_contained_elements_type(localization, arguments[0])) if len(dvar.keys()) == 0: return ret_arr tup = wrap_type(tuple()) union = UnionType.add(ret_arr, call_utilities.create_numpy_array(numpy.int32())) if len(dvar.keys()) == 1: set_contained_elements_type(localization, tup, union) if len(dvar.keys()) == 2: union = UnionType.add(union, call_utilities.create_numpy_array(numpy.int32())) set_contained_elements_type(localization, tup, union) if len(dvar.keys()) == 3: union = UnionType.add(union, call_utilities.create_numpy_array(numpy.int32())) union = UnionType.add(union, call_utilities.create_numpy_array(numpy.int32())) set_contained_elements_type(localization, tup, union) return tup
def groups(localization, proxy_obj, arguments): t = UnionType.add(undefined_type.UndefinedType, str()) t = UnionType.add(t, 0) t = UnionType.add(t, types.NoneType) tup = call_utilities.wrap_contained_type(tuple()) tup.set_contained_type(t) return tup
def turn_to_type(obj): """ As in our type analysis process we may have to deal with code whose sources are not available, calls to this code must be performed so we can obtain return values that can be used in our program analysis. This code is responsible of turning the values obtained from these calls to its types so stypy is able to use its return types to analyze the program. :param obj: :return: """ # Already wrapped: it is already a type if type(obj) is StandardWrapper: return obj if type(obj) in types_without_value: obj = type(obj)() wrapped_obj = wrap_contained_type(obj) # Special handling for dicts and similar if type_containers.can_store_keypairs(wrapped_obj): collected_items = dict() keys = obj.keys() for key in keys: values_for_key = type_containers.get_contained_elements_type_for_key(obj, key) key_type = turn_to_type(key) value_types = turn_to_type(values_for_key) try: existing_values = collected_items[key_type] except: existing_values = None collected_items[key_type] = UnionType.add(value_types, existing_values) for key in keys: del obj[key] for key, value in collected_items.items(): type_containers.set_contained_elements_type_for_key(wrapped_obj, key, value) return wrapped_obj # Special handling for containers if type_containers.can_store_elements(wrapped_obj): union_contained = None for elem in obj: elem = turn_to_type(elem) if elem is type: union_contained = UnionType.add(union_contained, elem) else: try: union_contained = UnionType.add(union_contained, known_python_types.get_sample_instance_for_type( type(elem).__name__)) except Exception as exc: union_contained = UnionType.add(union_contained, elem) wrapped_obj.set_contained_type(union_contained) return wrapped_obj return obj
def test_merge_union_types(self): int_var = int def fun(): pass class Foo: def method(self): pass def method_2(self): pass class_var = Foo method_var = Foo.method instance_var = Foo() import math module_var = math union1 = UnionType.create_from_type_list([int_var, fun, class_var]) union2 = UnionType.create_from_type_list( [method_var, instance_var, module_var]) compare_types(union1, [int_var, fun, class_var]) compare_types(union2, [method_var, instance_var, module_var]) fused_union = UnionType.add(union1, union2) compare_types( fused_union, [int_var, fun, class_var, method_var, instance_var, module_var]) clone = UnionType.create_from_type_list( [int_var, fun, class_var, method_var, instance_var, module_var]) compare_types(fused_union, clone) method2_var = Foo.method_2 UnionType.add(clone, types) UnionType.add(clone, method2_var) compare_types( fused_union, [int_var, fun, class_var, method_var, instance_var, module_var]) compare_types(clone, [ int_var, fun, class_var, method_var, instance_var, module_var, method2_var, types ]) clone2 = UnionType.create_from_type_list([ int_var, fun, class_var, method_var, instance_var, module_var, method2_var, types ]) self.assertFalse(fused_union == clone) compare_types(clone2, clone)
def block(localization, proxy_obj, arguments): union = None for arg in arguments: if call_utilities.is_iterable(arg): union = UnionType.add( union, get_contained_elements_type(localization, arg)) else: union = UnionType.add(union, arg) return call_utilities.create_numpy_array(union)
def test_create_union_type_with_vars(self): union = UnionType.add(int, str) compare_types(union, [int, str]) union2 = UnionType(union, list) compare_types(union, [int, str]) compare_types(union2, [int, str, list]) self.assertFalse(union == union2) clone = UnionType.add(int, str) self.assertTrue(union == clone)
def test_create_union_type_with_classes(self): class Foo: pass union = UnionType.add(Foo, AssertionError) compare_types(union, [Foo, AssertionError]) union2 = UnionType(union, object) compare_types(union2, [Foo, AssertionError, object]) clone = UnionType.add(Foo, AssertionError) self.assertFalse(union == union2) self.assertTrue(union == clone)
def test_create_union_type_with_funcs(self): def foo(): pass union = UnionType.add(foo, range) compare_types(union, [foo, range]) union2 = UnionType(union, getattr) compare_types(union, [foo, range]) compare_types(union2, [foo, range, getattr]) self.assertFalse(union == union2) clone = UnionType.add(foo, range) self.assertTrue(union == clone)
def test_create_union_type_with_modules(self): import math import sys import types union = UnionType.add(math, sys) compare_types(union, [math, sys]) clone = UnionType.add(math, sys) compare_types(union, clone.types) union2 = UnionType.add(clone, types) compare_types(union2, [math, sys, types]) self.assertFalse(union == union2)
def assign_ssa_finally_branch_types_of_members_for_object( obj, branch_rest, branch_finally): """ Assign all the types contained on the dictionary branch2 to the dictionary branch1, overwriting them if the same name exist in both branches. This is needed for the implementation of the finally branch, that do not follow the same behaviour as the other branches when implementing the SSA algorithm. :param obj: :param branch_rest: :param branch_finally: :return: """ for name in branch_finally: if isinstance(branch_finally[name], UnionType): types = branch_finally[name].get_types() types_without_undefined = filter(lambda t: t is not UndefinedType, types) if len(types_without_undefined) < len( types): # There were undefined types union_without_undefined = UnionType.create_from_type_list( types_without_undefined) branch_rest[name] = UnionType.add(branch_rest[name], union_without_undefined) continue # if obj not in branch_rest: # branch_rest[obj] = dict() branch_rest[name] = branch_finally[name] return branch_rest
def __setitem__(localization, proxy_obj, arguments): r = TypeWrapper.get_wrapper_of(proxy_obj.__self__) existing = r.get_contained_type() if existing is types.NoneType or type(existing) is types.NoneType: r.set_contained_type(arguments[1]) else: r.set_contained_type(UnionType.add(arguments[1], existing))
def create_union_type(types_): ret = None for elem in types_: ret = UnionType.add(ret, elem) return ret
def fit(localization, proxy_obj, arguments): dvar = call_utilities.parse_varargs_and_kwargs( localization, arguments, ['domain', 'rcond', 'full', 'w', 'window'], { 'domain': IterableDataStructure, 'rcond': RealNumber, 'full': bool, 'w': IterableDataStructure, 'window': IterableDataStructure, }, 'fit', 3) if isinstance(dvar, StypyTypeError): return dvar ret = call_utilities.create_numpy_array_n_dimensions( call_utilities.get_inner_type(localization, arguments[0]), call_utilities.get_dimensions(localization, arguments[0])) ret = numpy.polynomial.Chebyshev(ret.get_wrapped_type()) if 'full' in dvar.keys(): tup = wrap_contained_type(tuple()) ld = wrap_contained_type(list()) ld.set_contained_type( call_utilities.get_inner_type(localization, arguments[0])) un = UnionType.add(ret, ld) tup.set_contained_type(un) return tup return ret
def __getitem__(localization, proxy_obj, arguments): r = TypeWrapper.get_wrapper_of(proxy_obj.__self__) index_selector = arguments[0] if isinstance(index_selector, tuple): index_selector = index_selector[0] dims = call_utilities.get_dimensions(localization, r) if dims > 1: if call_utilities.is_iterable(arguments[0]): if call_utilities.is_iterable(arguments[0].get_contained_type()): return call_utilities.create_numpy_array_n_dimensions( call_utilities.cast_to_numpy_type(call_utilities.get_inner_type(localization, r)), dims - 1) contained = call_utilities.cast_to_numpy_type(call_utilities.get_inner_type(localization, r)) for i in range(dims - 1): contained = UnionType.add(contained, call_utilities.create_numpy_array_n_dimensions(r.get_contained_type(), i + 1)) else: contained = r.get_contained_type() if isinstance(index_selector, TypeWrapper): if isinstance(index_selector.wrapped_type, slice) or ( call_utilities.is_iterable(index_selector) and not isinstance(index_selector.wrapped_type, tuple)): l = call_utilities.create_numpy_array(contained) return l return contained # proxy_obj.__self__.dtype.type()
def heappush(localization, proxy_obj, arguments): ex_type = get_contained_elements_type(localization, arguments[0]) if ex_type is UndefinedType: u = arguments[1] else: u = UnionType.add(ex_type, arguments[1]) set_contained_elements_type(localization, arguments[0], u) return types.NoneType
def add_key_and_value_type(container, key, type_): try: existing = container[key] except KeyError: existing = None to_add = UnionType.add(existing, type_) container[key] = to_add
def test_simple_union_invoke(self): union = UnionType.add(int(), str()) islower = self.type_store.get_type_of_member(self.loc, union, "islower") res = invoke(self.loc, islower) self.assertTrue(len(TypeWarning.get_warning_msgs()) == 1) compare_types(res, False)
def test_create_union_type_with_mixed_types(self): int_var = int def fun(): pass class Foo: def method(self): pass def method_2(self): pass class_var = Foo method_var = Foo.method instance_var = Foo() import math module_var = math union = UnionType.create_from_type_list( [int_var, fun, class_var, method_var, instance_var, module_var]) compare_types( union, [int_var, fun, class_var, method_var, instance_var, module_var]) clone = UnionType.create_from_type_list( [int_var, fun, class_var, method_var, instance_var, module_var]) compare_types(union, clone) method2_var = Foo.method_2 UnionType.add(clone, types) UnionType.add(clone, method2_var) compare_types( union, [int_var, fun, class_var, method_var, instance_var, module_var]) compare_types(clone, [ int_var, fun, class_var, method_var, instance_var, module_var, method2_var, types ])
def einsum(localization, proxy_obj, arguments): if isinstance(arguments[-1], dict): if Str == type(arguments[0]): arg_num = 2 else: arg_num = 1 dvar = call_utilities.parse_varargs_and_kwargs(localization, arguments, ['out', 'dtype', 'order', 'casting', 'optimize'], { 'out': IterableDataStructure, 'dtype': type, 'order': Str, 'casting': Str, 'optimize': [bool, Str] }, 'einsum', arg_num) if isinstance(dvar, StypyTypeError): return dvar val_temp = call_utilities.check_possible_values(dvar, 'order', ['C', 'F', 'A', 'K']) if isinstance(val_temp, StypyTypeError): return val_temp val_temp = call_utilities.check_possible_values(dvar, 'casting', ['no', 'equiv', 'safe', 'same_kind', 'unsafe']) if isinstance(val_temp, StypyTypeError): return val_temp val_temp = call_utilities.check_possible_values(dvar, 'optimize', ['greedy', 'optimal', False, True]) if isinstance(val_temp, StypyTypeError): return val_temp arguments = arguments[:-1] else: dvar = dict() typ = None if Str == type(arguments[0]): arg_list = arguments[1:] if Number == type(arguments[1]) and 'out' in dvar: return dvar['out'] else: arg_list = arguments for arg in arg_list: if call_utilities.is_iterable(arg): typ_temp = call_utilities.cast_to_numpy_type(call_utilities.get_inner_type(localization, arg)) typ = call_utilities.cast_to_greater_numpy_type(typ, typ_temp) union = UnionType.add(typ, call_utilities.create_numpy_array(DynamicType)) if 'out' in dvar: set_contained_elements_type(localization, dvar['out'], DynamicType) return call_utilities.create_numpy_array(DynamicType) return union
def test_create_union_type_with_instances(self): class Foo: pass foo_inst = Foo() assert_inst = AssertionError() object_inst = object() union = UnionType.add(foo_inst, assert_inst) compare_types(union, [foo_inst, assert_inst]) union2 = UnionType(union, object_inst) compare_types(union2, [foo_inst, assert_inst, object_inst]) clone = UnionType.add(foo_inst, assert_inst) self.assertFalse(union == union2) self.assertTrue(union == clone) clone2 = UnionType.add(foo_inst, AssertionError()) self.assertFalse(union == clone2)
def dstack(localization, proxy_obj, arguments): elem_list = wrap_contained_type(list()) for arg in arguments: if call_utilities.is_iterable(arg): cont = get_contained_elements_type(localization, arg) if call_utilities.is_iterable(cont): union2 = UnionType.add(elem_list.get_contained_type(), cont.get_contained_type()) elem_list.set_contained_type(union2) else: union2 = UnionType.add(elem_list.get_contained_type(), cont) elem_list.set_contained_type(union2) else: return StypyTypeError( localization, "A non-iterable parameter {0} was passed to the dstack function" .format(str(arg))) return call_utilities.create_numpy_array(elem_list)
def concatenate(localization, proxy_obj, arguments): union = None for arg in arguments: if call_utilities.is_iterable(arg): union = UnionType.add( union, get_contained_elements_type(localization, arg)) else: return StypyTypeError( localization, "A non-iterable parameter {0} was passed to the concatenate function" .format(str(arg))) return call_utilities.create_numpy_array(union)
def hstack(localization, proxy_obj, arguments): union = None for arg in arguments: if call_utilities.is_iterable(arg): union = UnionType.add( union, call_utilities.get_inner_type(localization, arg)) else: return StypyTypeError( localization, "A non-iterable parameter {0} was passed to the hstack function" .format(str(arg))) return call_utilities.create_numpy_array(union)
def iadd(localization, proxy_obj, arguments): if call_utilities.is_iterable( arguments[0]) and call_utilities.is_iterable(arguments[1]): if isinstance( arguments[0].get_wrapped_type(), list) and isinstance( arguments[1].get_wrapped_type(), tuple): t1 = get_contained_elements_type(localization, arguments[0]) t2 = get_contained_elements_type(localization, arguments[1]) tEnd = UnionType.add(t1, t2) set_contained_elements_type(localization, arguments[0], tEnd) return arguments[0] return None
def add(localization, proxy_obj, arguments): if call_utilities.is_iterable( arguments[0]) and call_utilities.is_iterable(arguments[1]): if isinstance(arguments[0].get_wrapped_type(), tuple) and isinstance( arguments[1].get_wrapped_type(), tuple): t1 = call_utilities.get_contained_elements_type( localization, arguments[0]) t2 = call_utilities.get_contained_elements_type( localization, arguments[1]) if isinstance(t1, UnionType): t1 = t1.duplicate() tEnd = UnionType.add(t1, t2) wrap = call_utilities.wrap_contained_type((tEnd, )) wrap.set_contained_type(tEnd) return wrap return None # Type rule results
def stack(localization, proxy_obj, arguments): dvar = call_utilities.parse_varargs_and_kwargs(localization, arguments, ['axis'], { 'axis': Integer, }, 'stack') if isinstance(dvar, StypyTypeError): return dvar union = None for arg in arguments: if call_utilities.is_iterable(arg): union = UnionType.add( union, get_contained_elements_type(localization, arg)) else: return StypyTypeError( localization, "A non-iterable parameter {0} was passed to the stack function" .format(str(arg))) return call_utilities.create_numpy_array(union)
def linspace(localization, proxy_obj, arguments): dvar = call_utilities.parse_varargs_and_kwargs( localization, arguments, ['num', 'endpoint' 'retstep' 'dtype'], { 'num': Integer, 'endpoint': bool, 'retstep': bool, 'dtype': type, }, 'linspace', 2) if isinstance(dvar, StypyTypeError): return dvar temp_ret = call_utilities.create_numpy_array(numpy.float64()) if 'retstep' in dvar.keys(): union = UnionType.add(temp_ret, numpy.float64()) out_tuple = wrap_contained_type((union, )) out_tuple.set_contained_type(union) return out_tuple return temp_ret
def func(*args, **kwargs): frame = inspect.currentframe() while True: if frame.f_code is f.func_code: # Constructors don't return values if f.__name__ == "__init__": return None try: call = frame.f_globals[frame.f_code.co_name] # Check call arguments of the recursive call to detect recursive call argument errors prior to # return a RecursionType. arguments = process_argument_values( args[0], call.stypy_type_of_self, call.stypy_type_store, call.stypy_function_name, call.stypy_param_names_list, call.stypy_varargs_param_name, call.stypy_kwargs_param_name, call.stypy_call_defaults, args[1:], kwargs) if is_error_type(arguments): return arguments except: pass try: # Return the most up-to-date calculated return type in a recursive call. Pair it with a # RecursionType() to indicate it may be composed by more types. context = call.stypy_type_store.get_current_active_context( ) if default_function_ret_var_name in context: return UnionType.add( context.get_type_of(call.stypy_localization, default_function_ret_var_name), RecursionType()) return RecursionType() except: return RecursionType() frame = frame.f_back if frame is None: break return f(*args, **kwargs)
def test_union_invoke_return_types(self): class Foo: def method(self, localization): return True def method_2(self, localization): return str() class Foo2: def method(self, localization): return False def method_2(self, localization): return int() # Access a member that can be provided only by some of the types in the union union = UnionType.add(Foo(), Foo2()) method = self.type_store.get_type_of_member(self.loc, union, "method_2") res = invoke(self.loc, method) self.assertTrue(len(TypeWarning.get_warning_msgs()) == 0) compare_types(res, [str(), int()])