def constructor_as_string(object, assigned_names={}):
    """For a given object (either a SerializedObject or a list of them) return
    a string representing a code that will construct it.

    >>> from test.helper import make_fresh_serialize
    >>> serialize = make_fresh_serialize()
    >>> m = Module(None, 'myclasses')

    It handles built-in types
        >>> constructor_as_string(serialize(123))
        '123'
        >>> constructor_as_string(serialize('string'))
        "'string'"
        >>> constructor_as_string([serialize(1), serialize('two')])
        "[1, 'two']"

    as well as instances of user-defined classes
        >>> obj = UserObject(None, Class('SomeClass', module=m))
        >>> constructor_as_string(obj)
        'SomeClass()'

    interpreting their arguments correctly
        >>> obj.add_call(MethodCall(Method('__init__', ['self', 'arg']), {'arg': serialize('whatever')}, serialize(None)))
        >>> constructor_as_string(obj)
        "SomeClass('whatever')"

    even if they're user objects themselves:
        >>> otherobj = UserObject(None, Class('SomeOtherClass', module=m))
        >>> otherobj.add_call(MethodCall(Method('__init__', ['self', 'object']), {'object': obj}, serialize(None)))
        >>> constructor_as_string(otherobj)
        "SomeOtherClass(SomeClass('whatever'))"

    or they are already named:
        >>> s = serialize("string")
        >>> anotherobj = UserObject(None, Class('AnotherClass', module=m))
        >>> anotherobj.add_call(MethodCall(Method('__init__', ['self', 's']), {'s': s}, serialize(None)))
        >>> constructor_as_string(anotherobj, {s: 's'})
        'AnotherClass(s)'

    Handles composite objects:
        >>> constructor_as_string(serialize([1, "a", None]))
        "[1, 'a', None]"

    even when they contain instances of user-defined classes:
        >>> constructor_as_string(SequenceObject([obj], lambda x:x))
        "[SomeClass('whatever')]"

    or other composite objects:
        >>> constructor_as_string(serialize((23, [4, [5]], {'a': 'b'})))
        "(23, [4, [5]], {'a': 'b'})"

    or already named objects:
        >>> seq = serialize(["a", None])
        >>> astring = seq.contained_objects[0]
        >>> constructor_as_string(seq, {astring: 'astring'})
        '[astring, None]'

    Empty tuples are recreated properly:
        >>> constructor_as_string(serialize((((42,),),)))
        '(((42,),),)'

    Recreated objects keep their import information:
        >>> cs = constructor_as_string(UserObject(None, Class('MyClass', module=m)))
        >>> cs
        'MyClass()'
        >>> cs.imports
        set([('myclasses', 'MyClass')])

    Library objects like xml.dom.minidom.Element are recreated properly as well:
        >>> from xml.dom.minidom import Element
        >>> constructor_as_string(serialize(Element("tag", "uri", "prefix")))
        "Element('tag', 'uri', 'prefix')"
    """
    if isinstance(object, list):
        return list_of(map(constructor_as_string, object))
    elif assigned_names.has_key(object):
        return CodeString(assigned_names[object])
    elif isinstance(object, UserObject):
        # Look for __init__ call and base the constructor on that.
        init_call = object.get_init_call()
        if init_call:
            cs = call_as_string_for(object.klass.name, init_call.input,
                init_call.definition, assigned_names)
        else:
            cs = call_as_string(object.klass.name, {})
        return addimport(cs, import_for(object.klass))
    elif isinstance(object, ImmutableObject):
        return CodeString(object.reconstructor, imports=object.imports)
    elif isinstance(object, (CompositeObject, LibraryObject)):
        arguments = join(', ', get_contained_objects_info(object, assigned_names))
        return putinto(arguments, object.constructor_format, object.imports)
    elif isinstance(object, GeneratorObject):
        if object.is_activated():
            cs = call_as_string_for(object.definition.name, object.args,
                object.definition)
            return addimport(cs, import_for(object.definition))
        else:
            return todo_value('generator')
    elif isinstance(object, UnknownObject):
        return todo_value(object.partial_reconstructor)
    else:
        raise TypeError("constructor_as_string expected SerializedObject at input, not %s" % object) def call_as_string_for(object_name, args, definition, assigned_names={}):
    """Generate code for calling an object with given arguments.

    >>> from test.helper import make_fresh_serialize
    >>> serialize = make_fresh_serialize()

    Puts varargs at the end of arguments list.
        >>> call_as_string_for('build_url',
        ...     {'proto': serialize('http'), 'params': serialize(('user', 'session', 'new'))},
        ...     Function('build_url', ['proto', '*params']))
        "build_url('http', 'user', 'session', 'new')"

    Works for lone varargs too.
        >>> call_as_string_for('concat', {'args': serialize(([1,2,3], [4,5], [6]))},
        ...     Function('concat', ['*args']))
        'concat([1, 2, 3], [4, 5], [6])'

    Uses assigned name for varargs as well.
        >>> args = serialize((1, 2, 3))
        >>> call_as_string_for('add', {'args': args}, Function('add', ['*args']), {args: 'atuple'})
        'add(*atuple)'

    Inlines extra keyword arguments in the call...
        >>> call_as_string_for('dict', {'kwargs': serialize({'one': 1, 'two': 2})},
        ...     Function('dict', ['**kwargs']))
        'dict(one=1, two=2)'

    ...even when they are combined with varargs.
        >>> call_as_string_for('wrap', {'a': serialize((1, 2, 3)), 'k': serialize({'x': 4, 'y': 5})},
        ...     Function('wrap', ['*a', '**k']))
        'wrap(1, 2, 3, x=4, y=5)'

    Uses assigned name for kwarg if present.
        >>> kwargs = serialize({'id': 42, 'model': 'user'})
        >>> call_as_string_for('filter_params', {'kwargs': kwargs},
        ...    Function('filter_params', ['**kwargs']), {kwargs: 'params'})
        'filter_params(**params)'

    Generates valid code when vararg has been named and kwarg wasn't.
        >>> args = serialize((1, 2, 3))
        >>> call_as_string_for('wrap', {'args': args, 'kwargs': serialize({'a': 6, 'b': 7})},
        ...     Function('wrap', ['*args', '**kwargs']), {args: 'atuple'})
        'wrap(a=6, b=7, *atuple)'

    When varargs are present all preceding arguments are positioned, not named.
        >>> call_as_string_for('sum', {'x': serialize(1), 'rest': serialize((2, 3))},
        ...     Function('sum', ['x', '*rest']))
        'sum(1, 2, 3)'

    When argument type requires import, the import is present in the imports list.
        >>> m = Module(None, 'myclasses')
        >>> cs = call_as_string_for('display',
        ...     {'obj': UserObject(None, Class('MyWindow', module=m))},
        ...     Function('display', ['obj']))
        >>> cs
        'display(MyWindow())'
        >>> cs.imports
        set([('myclasses', 'MyWindow')])
    """
    positional_args = []
    keyword_args = []
    vararg = None
    kwarg = None

    def getvalue(argname):
        return args[argname.lstrip("*")]

    skipped_an_arg = False
    for argname in arguments_of(definition):
        try:
            value = getvalue(argname)
            if argname.startswith("**"):
                if value in assigned_names.keys():
                    kwarg = CodeString("**%s" % assigned_names[value])
                else:
                    for karg, kvalue in map_as_kwargs(value):
                        valuecs = constructor_as_string(kvalue, assigned_names)
                        keyword_args.append(combine(karg, valuecs, "%s=%s"))
            elif argname.startswith("*"):
                if value in assigned_names.keys():
                    vararg = CodeString("*%s" % assigned_names[value])
                else:
                    code_strings = get_contained_objects_info(value, assigned_names)
                    positional_args.extend(code_strings)
            else:
                constructor = constructor_as_string(value, assigned_names)
                if skipped_an_arg:
                    keyword_args.append(combine(argname, constructor, "%s=%s"))
                else:
                    positional_args.append(constructor)
        except KeyError:
            skipped_an_arg = True

    arguments = join(', ', filter(None, (positional_args + keyword_args + [vararg] + [kwarg])))
    return combine(object_name, arguments, "%s(%s)") def type_as_string(obj):
    """Return a most common representation of the wrapped object type.

    >>> type_as_string([SequenceObject((), None), MapObject({}, None)])
    '[tuple, dict]'
    >>> cs = type_as_string(UnknownObject(lambda: None))
    >>> cs
    'types.FunctionType'
    >>> cs.imports
    set(['types'])
    """
    if isinstance(obj, list):
        return list_of(map(type_as_string, obj)) # TODO join preserving code strings attributes
    type2import = {'time': ('datetime', 'time'),
                   'datetime': ('datetime', 'datetime'),
                   'date': ('datetime', 'date')}
    cs = CodeString(obj.type_name)
    if cs.startswith('types.'):
        return addimport(cs, 'types')
    elif str(cs) in type2import.keys():
        # TODO it should be done in the serializer
        return addimport(cs, type2import[str(cs)])
    return cs def todo_value(value):
    """Wrap given value in a <TODO: value> block.
    """
    return CodeString("<TODO: %s>" % value, uncomplete=True) class MethodCallContext(object):
    def __init__(self, call, user_object):
        self.call = call
        self.user_object = user_object

    def __getattr__(self, name):
        if name in ['input', 'definition', 'calls', 'args', 'output', 'timestamp']:
            return getattr(self.call, name)

    def __repr__(self):
        return "MethodCallContext(obj=%r, call=%r)" % (self.user_object, self.call) class SerializedObject(Event):
    """An object captured during execution.

    This is an abstract class, see subclasses for descriptions of different
    types of serialized objects.

    :IVariables:
      timestamp : float
        Number marking creation time of this SerializedObject. This number
        cannot be converted to a meaningful time description. It should only
        be used to arrange objects' creation on a timeline.
      human_readable_id : str
        A human-readable description of an object, suitable to be used as
        an identifier.
      module_name : str
        Location of the module this object's class was defined in. Should be
        usable in import statements.
      type_import : tuple(str, str) or None
        An import needed for the type to be available in the testing
        environment. None if no import is needed.
      type_name : str
        A canonical representation of the type this object is an instance of.
    """
    def __init__(self, obj):
        super(SerializedObject, self).__init__()
        self.human_readable_id = get_human_readable_id(obj)
        self.module_name = module_name(obj)
        self.type_name = get_type_name(obj)

    def _get_type_import(self):
        if self.module_name not in ['__builtin__', 'exceptions']:
            return (self.module_name, self.type_name)
    type_import = property(_get_type_import) def is_serialized_string(obj):
    return isinstance(obj, ImmutableObject) and obj.type_name == 'str' class BuiltinMethodWithPositionArgsSideEffect(SideEffect):
    definition = None # set in a subclass

    def __init__(self, obj, *args):
        super(BuiltinMethodWithPositionArgsSideEffect, self).__init__([obj], list(args))
        self.obj = obj
        self.args = args

    def args_mapping(self):
        return dict(zip(self.definition.args, self.args)) class AttributeRebind(SideEffect):
    def __init__(self, obj, name, value):
        super(AttributeRebind, self).__init__([obj], [value])
        self.obj = obj
        self.name = name
        self.value = value
    def __repr__(self):
        return "%s(id=%r, %r, %s, %r)" % (self.__class__.__name__, id(self), self.obj, self.name, self.value) class GeneratorObject(Callable, SerializedObject):
    """Representation of a generator object - a callable with an input and many
    outputs (here called "yields").
    """
    calls_type = GeneratorObjectInvocation

    def __init__(self, obj, generator=None, args=None, callable=None):
        Callable.__init__(self)
        SerializedObject.__init__(self, obj)
        if generator is not None and args is not None and callable is not None:
            self.activate(generator, args, callable)

    def activate(self, generator, args, callable):
        assert_argument_type(generator, (Function, Method))
        assert_argument_type(callable, (Function, UserObject))
        if self.is_activated():
            raise ValueError("This generator has already been activated.")
        if not generator.is_generator:
            raise TypeError("Tried to activate GeneratorObject with %r as a generator definition." % generator)
        self.definition = generator
        self.args = args
        # Finally register this GeneratorObject with its callable context
        # (which will be a Function or an UserObject). This has to be
        # done only once for each GeneratorObject.
        callable.add_call(self)

    def is_activated(self):
        return hasattr(self, 'args')

    def raised_exception(self):
        return any([c.raised_exception() for c in self.calls])

    def _get_exception(self):
        for invocation in self.calls:
            if invocation.raised_exception():
                return invocation.exception
    exception = property(_get_exception)

    def __repr__(self):
        if self.is_activated():
            return "GeneratorObject(generator=%r, args=%r)" % \
                (self.definition.name, self.args)
        else:
            return "GeneratorObject()" class Call(Event):
    """Stores information about a single function or method call.

    Includes reference to the caller, all call arguments, references to
    other calls made inside this one, references to side effects that occured
    during this call and finally an output value.

    __eq__ and __hash__ definitions provided for Function.get_unique_calls()
    and UserObject.get_external_calls().
    """
    def __init__(self, definition, args, output=None, exception=None):
        if [value for value in args.values() if not isinstance(value, SerializedObject)]:
            raise ValueError("Values of all arguments should be instances of SerializedObject class.")
        if output and exception:
            raise ValueError("Call should have a single point of return.")
        if not isinstance(definition, Definition):
            raise ValueError("Call definition object should be an instance of Definition.")

        super(Call, self).__init__()

        self.definition = definition
        self.input = args
        self.output = output
        self.exception = exception

        self.caller = None
        self.subcalls = []
        self.side_effects = []

    def add_subcall(self, call):
        if call.caller is not None:
            raise TypeError("This %s of %s already has a caller." % \
                                (class_name(call), call.definition.name))
        call.caller = self
        self.subcalls.append(call)

    def raised_exception(self):
        return self.exception is not None

    def set_output(self, output):
        self.output = output

    def set_exception(self, exception):
        self.exception = exception

    def clear_exception(self):
        self.exception = None

    def add_side_effect(self, side_effect):
        self.side_effects.append(side_effect)

    def __eq__(self, other):
        if type(self) != type(other):
            return False
        return self.definition == other.definition and \
               self.input == other.input and \
               self.output == other.output and \
               self.exception == other.exception and \
               self.side_effects == other.side_effects

    def __hash__(self):
        return hash((self.definition.name,
                     tuple(self.input.iteritems()),
                     self.output,
                     self.exception,
                     tuple(self.side_effects)))

    def __repr__(self):
        return "%s(definition=%s, input=%r, output=%r, exception=%r, side_effects=[..(%d)..])" % \
            (class_name(self), self.definition.name, self.input, self.output,
             self.exception, len(self.side_effects)) class Method(Definition):
    def __init__(self, name, args=None, code=None, is_generator=False, klass=None):
        Definition.__init__(self, name, args=args, code=code, is_generator=is_generator)
        self.klass = klass

    def get_call_args(self):
        """Return names of arguments explicitly passed during call to this
        method.

        In other words, it removes "self" from the list of arguments, as "self"
        is passed implicitly.
        """
        if self.args and self.args[0].startswith('*'):
            return self.args
        return self.args[1:]

    def is_creational(self):
        return self.name in CREATIONAL_METHODS

    def is_private(self):
        """Private methods (by convention) start with a single or double
        underscore.

        Note: Special methods are *not* considered private.
        """
        return self.name.startswith('_') and not self.is_special()

    def is_special(self):
        """Special methods, as defined in
        <http://docs.python.org/reference/datamodel.html#specialnames>
        have names starting and ending with a double underscore.
        """
        return self.name.startswith('__') and self.name.endswith('__')

    def __repr__(self):
        return "Method(name=%s, args=%r)" % (self.name, self.args) def assert_argument_type(obj, expected_type):
    if not isinstance(obj, expected_type):
        raise TypeError("%s() should be called with a %s argument, not %s" %
            (callers_name(), type_names(expected_type), obj))
from pythoscope.generator.lines import *
from pythoscope.generator.code_string import addimport, CodeString, combine,\
    putinto
from pythoscope.generator.constructor import constructor_as_string,\
    call_as_string_for, type_as_string, todo_value
from pythoscope.generator.method_call_context import MethodCallContext
from pythoscope.generator.objects_namer import Assign
from pythoscope.serializer import SerializedObject, is_serialized_string
from pythoscope.side_effect import BuiltinMethodWithPositionArgsSideEffect,\
    AttributeRebind
from pythoscope.store import GeneratorObject, Call, Method
from pythoscope.util import assert_argument_type



class Template(object):
    # :: (CodeString, CodeString) -> CodeString
    def equal_assertion(self, expected, actual):
        raise NotImplementedError("Method equal_assertion() not defined.")
    # :: (CodeString, CodeString) -> CodeString
    def raises_assertion(self, exception, call):
        raise NotImplementedError("Method raises_assertion() not defined.")
    # :: () -> CodeString
    def skip_test(self):
        raise NotImplementedError("Method skip_test() not defined.")

class UnittestTemplate(Template):
    def equal_assertion(self, expected, actual):
        return combine(expected, actual, "self.assertEqual(%s, %s)")
    def raises_assertion(self, exception, call):
        return combine(exception, call, "self.assertRaises(%s, %s)")
    def skip_test(self):
        return CodeString("assert False  # TODO: implement your test here")

class NoseTemplate(Template):
    def equal_assertion(self, expected, actual):
        return addimport(combine(expected, actual, "assert_equal(%s, %s)"),
                         ('nose.tools', 'assert_equal'))
    def raises_assertion(self, exception, call):
        return addimport(combine(exception, call, "assert_raises(%s, %s)"),
                         ('nose.tools', 'assert_raises'))
    def skip_test(self):
        return addimport(CodeString("raise SkipTest # TODO: implement your test here"),
                         ('nose', 'SkipTest'))

# :: CodeString -> CodeString
def add_newline(code_string):
    return combine(code_string, "\n")

# :: CodeString -> CodeString
def map_types(string):
    return putinto(string, "map(type, %s)")

# :: CodeString -> CodeString
def type_of(string):
    return putinto(string, "type(%s)")

# :: CodeString -> CodeString
def in_lambda(string):
    return putinto(string, "lambda: %s")

# :: Definition -> (str, str)
def import_for(definition):
    if isinstance(definition, Method):
        return import_for(definition.klass)
    return (definition.module.locator, definition.name)

# :: (CodeString, CodeString, Template) -> CodeString
def equal_assertion_on_values_or_types(expected, actual, template):
    if expected.uncomplete:
        pass
    else:
        return template.equal_assertion(expected, actual)

def call_name(call, assigned_names):
    if isinstance(call, MethodCallContext):
        if call.call.definition.is_creational():
            return call.call.definition.klass.name
        return "%s.%s" % (assigned_names[call.user_object], call.call.definition.name)
    return call.definition.name

def call_in_test(call, already_assigned_names):
    if isinstance(call, GeneratorObject) or (isinstance(call, MethodCallContext) and isinstance(call.call, GeneratorObject)):
        callstring = call_as_string_for(call_name(call, already_assigned_names), call.args,
                                        call.definition, already_assigned_names)
        callstring = combine(callstring, str(len(call.calls)), template="list(islice(%s, %s))")
        callstring = addimport(callstring, ("itertools", "islice"))
    else:

        callstring = call_as_string_for(call_name(call, already_assigned_names), call.input,