Source

mementos / test / test.py

from mementos import *
import sys, pytest

def with_metaclass(meta, base=object):
    """Create a base class with a metaclass."""
    return meta("NewBase", (base,), {})

def test_one():    
    class Thing(with_metaclass(MementoMetaclass, object)):
                
        def __init__(self, name):
            self.name = name
        

    t1 = Thing("one")
    t2 = Thing("one")
    assert t1 is t2
    
    o1 = Thing("lovely")
    o2 = Thing(name="lovely")
    assert o1 is not o2   # because the call signature is different
    
    class OtherThing(with_metaclass(MementoMetaclass, object)):
        
        def __init__(self, name):
            self.name = name
            self.color = None
            self.weight = None
            
        def set(self, color=None, weight=None):
            self.color = color or self.color
            self.weight = weight or self.weight
            return self
    
    ot1 = OtherThing("one").set(color='blue')
    ot2 = OtherThing("one").set(weight='light')
    assert ot1 is ot2
    assert ot1.color == ot2.color == 'blue'
    assert ot1.weight == ot2.weight == 'light'
    
def test_inline_with_metaclass():
    
    # Make sure you can do the metaclass specification directly.
    
    class Thing23(MementoMetaclass("NewBase", (object,), {})):
                
        def __init__(self, name):
            self.name = name
        

    t1 = Thing23("one")
    t2 = Thing23("one")
    assert t1 is t2
    
    o1 = Thing23("lovely")
    o2 = Thing23(name="lovely")
    assert o1 is not o2   # because the call signature is different
    
def test_id_metaclass():
    
    # Test the metaclass that uses the id of the first arg
    # but really as much a test of memento_factory, since IdMementoMetaclass not
    # part of base module
       
    IdMementoMetaclass = memento_factory("IdMementoMetaclass",
                                         lambda cls, args, kwargs: (cls, id(args[0])) )

    class IdTrack(with_metaclass(IdMementoMetaclass, object)):
        def __init__(self, name, *args):
            self.name = name
            self.args = args
            
    id1 = IdTrack("joe")
    id2 = IdTrack("joe")
    assert id1 is id2
    
    id3 = IdTrack("joe", 1, 4)
    assert id3 is id2
    
    id4 = IdTrack("Joe", 1, 4)
    id5 = IdTrack("Joe")
    assert id4 is id5
    assert id4 is not id3
    assert id5 is not id3
    
def test_id_metaclass_primitive():
    
    # Test the metaclass that uses the id of the first arg
    # but really as much a test of memento_factory, since IdMementoMetaclass not
    # part of base module
       
    IdMementoPrimitive = memento_factory("IdMementoMetaclass",
                                         lambda cls, args, kwargs: id(args[0]) )

    class IdTrackPrim(with_metaclass(IdMementoPrimitive, object)):
        def __init__(self, name, *args):
            self.name = name
            self.args = args
            
    id1 = IdTrackPrim("joe")
    id2 = IdTrackPrim("joe")
    assert id1 is id2
    
    id3 = IdTrackPrim("joe", 1, 4)
    assert id3 is id2
    
    id4 = IdTrackPrim("Joe", 1, 4)
    id5 = IdTrackPrim("Joe")
    assert id4 is id5
    assert id4 is not id3
    assert id5 is not id3
    
def test_metaclass_factory():
    
    mymeta = memento_factory("mymeta", lambda cls, args, kwargs: (cls, kwargs['b']))
    
    class BTrack(with_metaclass(mymeta, object)):
        def __init__(self, name, **kwargs):
            assert 'b' in kwargs
            self.name = name
            self.b = kwargs['b']
            
    b1 = BTrack('andy', b=1)
    b2 = BTrack('dave', b=1)
    assert b1 is b2
    assert b1.name == 'andy'  # because b1 got there first, defined object such that b=1
    
    b3 = BTrack('andy', b=2)
    assert b3 is not b1
    assert b3 is not b2
    assert b3.name == 'andy'
    
@pytest.mark.skipif("sys.version_info < (2,7)")
def test_perfect_signatures():
    # use inspect.getcallargs to make signatures that dont vary
    
    from inspect import getcallargs
    import hashlib
    
    def call_fingerprint(cls, args, kwargs):
        """
        Given a complex __init__ call with varied positional, keyward, variable,
        and variable keyword arguments, canonicalize the argument values and
        return a suitable hash key. NB this is suitable for cases where it is
        primarily the use of default values and keyword specification of args
        that might otherwise be given positionally that causes key signatures to
        vary, and in which the primary args (ie, not * or ** values) are simple
        scalars.
        
        In cases where objects or dicts may be passed, or * and ** values are
        used, a deep recursive flattening and sorting of values and key/value
        pairs must be done. This 1% of the 1% use case is beyond the scope here.
        """
        callargs = getcallargs(cls.__init__, None, *args, **kwargs)
        callitems = list(callargs.items())
        callitems.sort()
        h = hashlib.md5()
        h.update(repr(callitems).encode('utf-8'))
        return h.hexdigest()
        
    Perfect = memento_factory("Perfect", call_fingerprint)
    
    class PerfectCall(with_metaclass(Perfect, object)):
        def __init__(self, name, a=1, b=2, c=3, *args, **kwargs):
            self.vector = (name, a, b, c)
    
    p1 = PerfectCall('amy')
    p2 = PerfectCall('amy', b=2)
    p3 = PerfectCall('amy', c=3)
    p4 = PerfectCall('amy', c=3, a=1)
    p5 = PerfectCall(c=3, a=1, b=2, name='amy')
    assert p1 is p2
    assert p2 is p3
    assert p3 is p4
    assert p4 is p5
    
    p6 = PerfectCall('amy', b=33)
    assert p1 is not p6
    
    p7 = PerfectCall(**{'name': 'amy', 'b': 33})
    assert p6 is p7
    
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.