def assert_equal_sets(collection1, collection2): """Assert that both collections have the same number and set of elements. """ # Checking length of both collections first, so we catch duplicates that # appear in one collection and not the other. assert_length(collection2, len(collection1)) assert_equal(set(collection1), set(collection2))
def get_reconstructor_with_imports(obj): """ >>> reconstructor, imports = ImmutableObject.get_reconstructor_with_imports(re.compile('abcd')) >>> reconstructor "re.compile('abcd')" >>> imports == set(['re']) True >>> reconstructor, imports = ImmutableObject.get_reconstructor_with_imports(re.compile('abcd', re.I | re.M)) >>> reconstructor "re.compile('abcd', re.IGNORECASE | re.MULTILINE)" >>> imports == set(['re']) True """ if isinstance(obj, (int, long, float, str, unicode, types.NoneType)): # Bultin types has very convienient representation. return repr(obj), set() elif isinstance(obj, RePatternType): flags = regexp_flags_as_string(obj.flags) if flags: return ('re.compile(%r, %s)' % (obj.pattern, flags), set(['re'])) else: return ('re.compile(%r)' % obj.pattern, set(['re'])) elif isinstance(obj, types.FunctionType): function = obj.func_name module = obj.__module__ return (function, set([(module, function)])) else: raise TypeError("Unknown type of an ImmutableObject: %r." % obj)
def union(*sets): """Return a union of all the given sets. """ if len(sets) == 0: return set() # Since 2.6 set.union accepts multiple input iterables. if sys.version_info >= (2, 6): return set.union(*sets) else: return reduce(operator.or_, sets, set())
def explicit_calls(event): events_so_far = set() def ec(event): if isinstance(event, list): return flatten(map(ec, event)) # Avoid infinite recursion. if event in events_so_far: return [] else: events_so_far.add(event) if isinstance(event, Call): return [event] + ec(event.subcalls) + ec(event.input.values()) elif isinstance(event, Callable): return ec(event.calls) elif isinstance(event, EqualAssertionLine) and isinstance(event.actual, (Call, MethodCallContext)): return ec(event.actual) elif isinstance(event, GeneratorAssertionLine): return ec(event.generator_call) elif isinstance(event, RaisesAssertionLine): return ec(event.call) elif isinstance(event, MethodCallContext): return ec(event.call) return [] return ec(event)
def explicit_calls(event): events_so_far = set() def ec(event): if isinstance(event, list): return flatten(map(ec, event)) # Avoid infinite recursion. if event in events_so_far: return [] else: events_so_far.add(event) if isinstance(event, Call): return [event] + ec(event.subcalls) + ec(event.input.values()) elif isinstance(event, Callable): return ec(event.calls) elif isinstance(event, EqualAssertionLine) and isinstance( event.actual, (Call, MethodCallContext)): return ec(event.actual) elif isinstance(event, GeneratorAssertionLine): return ec(event.generator_call) elif isinstance(event, RaisesAssertionLine): return ec(event.call) elif isinstance(event, MethodCallContext): return ec(event.call) return [] return ec(event)
def __new__(cls, string, uncomplete=False, imports=None): if imports is None: imports = set() code_string = str.__new__(cls, string) code_string.uncomplete = uncomplete code_string.imports = imports return code_string
def python_modules_below(path): VCS_PATHS = set([".bzr", "CVS", "_darcs", ".git", ".hg", ".svn"]) def is_python_module(path): return path.endswith(".py") def not_vcs_file(path): return not set(path.split(os.path.sep)).intersection(VCS_PATHS) return filter(not_vcs_file, filter(is_python_module, rlistdir(path)))
def enumerate_events(objs): """Return a list of all events needed for testing by the objects passed. Avoids infinite recursion by keeping a list of events already traversed. """ events_so_far = set() def get_those_and_contained_events(objs): """Return a list containing given objects and all objects contained within them. """ return objs + get_contained_events(objs) def get_contained_events(obj): """Return a list of Events this object requires during testing. This function will descend recursively if objects contained within given object are composite themselves. """ if isinstance(obj, list): return flatten(map(get_contained_events, obj)) # Lists are unhashable anyway, so we don't remember them. if obj in events_so_far: return [] else: events_so_far.add(obj) if isinstance(obj, ImmutableObject): # ImmutableObjects are self-sufficient. return [] elif isinstance(obj, UnknownObject): return [] elif isinstance(obj, SequenceObject): return get_those_and_contained_events(obj.contained_objects) elif isinstance(obj, MapObject): return get_those_and_contained_events(flatten(obj.mapping)) elif isinstance(obj, LibraryObject): return get_those_and_contained_events(obj.arguments) elif isinstance(obj, BuiltinException): return get_those_and_contained_events(obj.args) elif isinstance(obj, UserObject): return get_contained_events(obj.get_init_and_external_calls()) elif isinstance(obj, (FunctionCall, MethodCall, GeneratorObjectInvocation)): ret = get_those_and_contained_events(obj.input.values() + list(obj.side_effects)) if obj.caller: ret += side_effects_before_and_affected_objects(obj) return ret elif isinstance(obj, GeneratorObject): if obj.is_activated(): return get_those_and_contained_events(obj.args.values()) + get_contained_events(obj.calls) else: return [] elif isinstance(obj, SideEffect): return [obj] + get_those_and_contained_events(list(obj.affected_objects)) elif isinstance(obj, CallToC): return side_effects_before_and_affected_objects(obj) else: raise TypeError("Wrong argument to get_contained_events: %s." % repr(obj)) return get_those_and_contained_events(objs)
def __init__(self, obj, serialize): # Serialize the parts first and only after that call super, so that # the parts get a lower timestamp than the whole object. self.mapping = [(serialize(k), serialize(v)) for k, v in obj.items()] CompositeObject.__init__(self, obj) self.constructor_format = "{%s}" self.imports = set()
def __init__(self, obj, serialize): # Serialize the parts first and only after that call super, so that # the parts get a lower timestamp than the whole object. self.contained_objects = map(serialize, obj) CompositeObject.__init__(self, obj) # Arrays constructor needs to include a typecode. if isinstance(obj, array.array): self.constructor_format = "array.array('%s', [%%s])" % obj.typecode self.imports = set(["array"]) # Special case for tuples with a single element. elif isinstance(obj, tuple) and len(obj) == 1: self.constructor_format = "(%s,)" self.imports = set() else: self.constructor_format = self.type_formats_with_imports[type(obj)][0] self.imports = self.type_formats_with_imports[type(obj)][1]
def __init__(self, obj, serialize): # Serialize the parts first and only after that call super, so that # the parts get a lower timestamp than the whole object. self.mapping = [(serialize(k), serialize(v)) for k,v in obj.items()] CompositeObject.__init__(self, obj) self.constructor_format = "{%s}" self.imports = set()
def __init__(self, obj, serialize): CompositeObject.__init__(self, obj) self.args = map(serialize, obj.args) self.constructor_format = "%s(%%s)" % class_name(obj) self.imports = set() if class_of(obj) in BUILTIN_ENVIRONMENT_ERROR_TYPES and obj.filename is not None: self.args.append(serialize(obj.filename))
def __init__(self, obj, serialize): # Serialize the parts first and only after that call super, so that # the parts get a lower timestamp than the whole object. self.contained_objects = map(serialize, obj) CompositeObject.__init__(self, obj) # Arrays constructor needs to include a typecode. if isinstance(obj, array.array): self.constructor_format = "array.array('%s', [%%s])" % obj.typecode self.imports = set(["array"]) # Special case for tuples with a single element. elif isinstance(obj, tuple) and len(obj) == 1: self.constructor_format = "(%s,)" self.imports = set() else: self.constructor_format = self.type_formats_with_imports[type( obj)][0] self.imports = self.type_formats_with_imports[type(obj)][1]
def __init__(self, obj, serialize): CompositeObject.__init__(self, obj) self.args = map(serialize, obj.args) self.constructor_format = "%s(%%s)" % class_name(obj) self.imports = set() if class_of( obj ) in BUILTIN_ENVIRONMENT_ERROR_TYPES and obj.filename is not None: self.args.append(serialize(obj.filename))
class LibraryObject(SerializedObject): type_formats_with_imports = { ('xml.dom.minidom', 'Element'): ("Element(%s)", ["tagName", "namespaceURI", "prefix"], set([("xml.dom.minidom", "Element")])), ('datetime', 'datetime'): ("datetime.datetime(%s)", [ "year", "month", "day", "hour", "minute", "second", "microsecond", "tzinfo" ], set(["datetime"])), } def __init__(self, obj, serialize): con, argnames, imp = self.type_formats_with_imports[id_of_class_of( obj)] self.constructor_format = con self.arguments = map(serialize, [getattr(obj, a, None) for a in argnames]) self.imports = imp # Arguments were serialized first, before a call to super, so that they # get a lower timestamp than the whole object. SerializedObject.__init__(self, obj)
def add_test_events_for_side_effects(events, side_effects): globals_already_setup = set() step = 0 first_timestamp = events[0].timestamp last_timestamp = events[-1].timestamp for side_effect in side_effects: if isinstance(side_effect, GlobalRead) and \ not isinstance(side_effect.value, UnknownObject) and \ side_effect.get_full_name() not in globals_already_setup: tmp_name = "old_%s_%s" % (side_effect.module.replace( ".", "_"), side_effect.name) ref = ModuleVariableReference(side_effect.module, side_effect.name, first_timestamp - 4.2 - step) # SETUP: old_module_variable = module.variable events.insert(0, Assign(tmp_name, ref, first_timestamp - 3.2 - step)) # SETUP: module.variable = value events.insert( 1, Assign(side_effect.get_full_name(), side_effect.value, first_timestamp - 2.2 - step)) # TEARDOWN: module.variable = old_module_variable # TODO: Crazy hack, teardowns should always be at the end, I'll fix # that someday. events.append( Assign(side_effect.get_full_name(), tmp_name, last_timestamp + 300.2 + step)) globals_already_setup.add((side_effect.get_full_name())) elif isinstance(side_effect, GlobalRebind): events.append( EqualAssertionLine( side_effect.value, ModuleVariableReference(side_effect.module, side_effect.name, last_timestamp + 1.1 + step), last_timestamp + 2.1 + step)) elif isinstance(side_effect, AttributeRebind): events.append( EqualAssertionLine( side_effect.value, ObjectAttributeReference(side_effect.obj, side_effect.name, last_timestamp + 1.3 + step), last_timestamp + 2.3 + step)) step += 5
def add_test_events_for_side_effects(events, side_effects): globals_already_setup = set() step = 0 first_timestamp = events[0].timestamp last_timestamp = events[-1].timestamp for side_effect in side_effects: if ( isinstance(side_effect, GlobalRead) and not isinstance(side_effect.value, UnknownObject) and side_effect.get_full_name() not in globals_already_setup ): tmp_name = "old_%s_%s" % (side_effect.module.replace(".", "_"), side_effect.name) ref = ModuleVariableReference(side_effect.module, side_effect.name, first_timestamp - 4.2 - step) # SETUP: old_module_variable = module.variable events.insert(0, Assign(tmp_name, ref, first_timestamp - 3.2 - step)) # SETUP: module.variable = value events.insert(1, Assign(side_effect.get_full_name(), side_effect.value, first_timestamp - 2.2 - step)) # TEARDOWN: module.variable = old_module_variable # TODO: Crazy hack, teardowns should always be at the end, I'll fix # that someday. events.append(Assign(side_effect.get_full_name(), tmp_name, last_timestamp + 300.2 + step)) globals_already_setup.add((side_effect.get_full_name())) elif isinstance(side_effect, GlobalRebind): events.append( EqualAssertionLine( side_effect.value, ModuleVariableReference(side_effect.module, side_effect.name, last_timestamp + 1.1 + step), last_timestamp + 2.1 + step, ) ) elif isinstance(side_effect, AttributeRebind): events.append( EqualAssertionLine( side_effect.value, ObjectAttributeReference(side_effect.obj, side_effect.name, last_timestamp + 1.3 + step), last_timestamp + 2.3 + step, ) ) step += 5
class SequenceObject(CompositeObject): """A builtin object that contains an ordered sequence of other objects inside it. Tuples and other immutable builtin types are still serialized into a SequenceObject, because they may contain a mutable element inside them. """ type_formats_with_imports = { list: ("[%s]", set()), frozenset: ("frozenset([%s])", set()), set: ("set([%s])", set()), sets.ImmutableSet: ("ImmutableSet([%s])", set([("sets", "ImmutableSet")])), sets.Set: ("Set([%s])", set([("sets", "Set")])), tuple: ("(%s)", set()), } def __init__(self, obj, serialize): # Serialize the parts first and only after that call super, so that # the parts get a lower timestamp than the whole object. self.contained_objects = map(serialize, obj) CompositeObject.__init__(self, obj) # Arrays constructor needs to include a typecode. if isinstance(obj, array.array): self.constructor_format = "array.array('%s', [%%s])" % obj.typecode self.imports = set(["array"]) # Special case for tuples with a single element. elif isinstance(obj, tuple) and len(obj) == 1: self.constructor_format = "(%s,)" self.imports = set() else: self.constructor_format = self.type_formats_with_imports[type( obj)][0] self.imports = self.type_formats_with_imports[type(obj)][1]
def putinto(cs, template, imports=set()): """Put the CodeString into a template, adding additional imports. """ return CodeString(template % cs, cs.uncomplete, union(cs.imports, imports))
import array import exceptions import re import types from pythoscope.compat import frozenset, set, sets from pythoscope.event import Event from pythoscope.util import RePatternType, class_name, class_of, \ module_name, regexp_flags_as_string, string2id, underscore # Filter out private attributes, like __doc__, __name__ and __package__. BUILTIN_EXCEPTION_TYPES = set([v for k,v in exceptions.__dict__.items() if not k.startswith('_')]) # Exceptions with special semantics for the `args` attribute. # See <http://docs.python.org/library/exceptions.html#exceptions.EnvironmentError> # for details. BUILTIN_ENVIRONMENT_ERROR_TYPES = [EnvironmentError, OSError, IOError] # Include VMSError or WindowsError if they exist. try: BUILTIN_ENVIRONMENT_ERROR_TYPES.append(WindowsError) except NameError: try: BUILTIN_ENVIRONMENT_ERROR_TYPES.append(VMSError) except NameError: pass # :: object -> string def get_human_readable_id(obj): # Get human readable id based on object's value, if obj is True:
def addimport(cs, imp): return putinto(cs, "%s", set([imp]))
def get_traced_method_names(self): traced_method_names = set() for user_object in self.user_objects: for call in user_object.calls: traced_method_names.add(call.definition.name) return traced_method_names
def not_vcs_file(path): return not set(path.split(os.path.sep)).intersection(VCS_PATHS)
import array import exceptions import re import types from pythoscope.compat import frozenset, set, sets from pythoscope.event import Event from pythoscope.util import RePatternType, class_name, class_of, \ module_name, regexp_flags_as_string, string2id, underscore # Filter out private attributes, like __doc__, __name__ and __package__. BUILTIN_EXCEPTION_TYPES = set( [v for k, v in exceptions.__dict__.items() if not k.startswith('_')]) # Exceptions with special semantics for the `args` attribute. # See <http://docs.python.org/library/exceptions.html#exceptions.EnvironmentError> # for details. BUILTIN_ENVIRONMENT_ERROR_TYPES = [EnvironmentError, OSError, IOError] # Include VMSError or WindowsError if they exist. try: BUILTIN_ENVIRONMENT_ERROR_TYPES.append(WindowsError) except NameError: try: BUILTIN_ENVIRONMENT_ERROR_TYPES.append(VMSError) except NameError: pass # :: object -> string def get_human_readable_id(obj):
def enumerate_events(objs): """Return a list of all events needed for testing by the objects passed. Avoids infinite recursion by keeping a list of events already traversed. """ events_so_far = set() def get_those_and_contained_events(objs): """Return a list containing given objects and all objects contained within them. """ return objs + get_contained_events(objs) def get_contained_events(obj): """Return a list of Events this object requires during testing. This function will descend recursively if objects contained within given object are composite themselves. """ if isinstance(obj, list): return flatten(map(get_contained_events, obj)) # Lists are unhashable anyway, so we don't remember them. if obj in events_so_far: return [] else: events_so_far.add(obj) if isinstance(obj, ImmutableObject): # ImmutableObjects are self-sufficient. return [] elif isinstance(obj, UnknownObject): return [] elif isinstance(obj, SequenceObject): return get_those_and_contained_events(obj.contained_objects) elif isinstance(obj, MapObject): return get_those_and_contained_events(flatten(obj.mapping)) elif isinstance(obj, LibraryObject): return get_those_and_contained_events(obj.arguments) elif isinstance(obj, BuiltinException): return get_those_and_contained_events(obj.args) elif isinstance(obj, UserObject): return get_contained_events(obj.get_init_and_external_calls()) elif isinstance(obj, (FunctionCall, MethodCall, GeneratorObjectInvocation)): ret = get_those_and_contained_events(obj.input.values() + list(obj.side_effects)) if obj.caller: ret += side_effects_before_and_affected_objects(obj) return ret elif isinstance(obj, GeneratorObject): if obj.is_activated(): return get_those_and_contained_events(obj.args.values()) +\ get_contained_events(obj.calls) else: return [] elif isinstance(obj, SideEffect): return [obj] + get_those_and_contained_events( list(obj.affected_objects)) elif isinstance(obj, CallToC): return side_effects_before_and_affected_objects(obj) else: raise TypeError("Wrong argument to get_contained_events: %s." % repr(obj)) return get_those_and_contained_events(objs)
def expand_into_timeline(*events): """Return a sorted list of all events related to given events in any way. """ return sorted_by_timestamp(set(enumerate_events(list(events))))
def get_unique_calls(self): return set(self.calls)