def testId__getitem__(self): """Id.__getitem__""" # Why the aa? At one point a subtle bug was present that wasn't being # caught with single character path elements. a = Id('aa/b/c/d') def T(x): self.assert_(x) T(isinstance(a[0], Id)) T(isinstance(a[0:3], Id)) T(a[0] == Id('aa')) T(a[1] == Id('b')) T(a[2] == Id('c')) T(a[3] == Id('d')) T(a[-1] == Id('d')) self.assertRaises(IndexError, a.__getitem__, 4) T(a[0:2] == Id('aa/b')) T(a[2:0] == Id('.')) T(a[2:0:-1] == Id('c/b')) # useless? who knows T(a[-2:] == Id('c/d'))
def _init(self): self.square = bool(self.square) def gen_pad_shape(dia, id, layer=None): if self.square: r = dia / 2 return Polygon(ext=(V(-r, -r), V(r, -r), V(r, r), V(-r, r)), id=id, layer=layer) else: return Circle(dia=dia, id=id, layer=layer) self.add(Hole(dia=self.dia, id=Id())) self.add( gen_pad_shape(self.dia + (self.thickness * 2), id=Id('pad'), layer='top.pad')) self.add(gen_pad_shape(self.mask, id=Id('mask'), layer='top.mask')) self.add( gen_pad_shape(self.mask + (self.clearance * 2), id=Id('clearance'), layer='top.clearance')) self.connects.add(Id('pad'))
def testElement_notify(self): """Element.notify()""" def T(got,expected = True): self.assert_(expected == got,'got: %s expected: %s' % (got,expected)) a = Element(id=Id('a')) class cb: def __init__(self): self.count = 0 def __call__(self): self.count += 1 self.assertRaises(ValueError, lambda:a.topology_notify(Id('a'),lambda:None)) self.assertRaises(ValueError, lambda:a.topology_notify(Id('z/y'),lambda:None)) self.assertRaises(TypeError, lambda:a.topology_notify(Id('.'),None)) # Test callback adding and deletion cb1 = cb() a.topology_notify(Id('a/b'),cb1) T(unwrap(a).__dict_callbacks__['b'],set((weakref.ref(cb1),))) cb2 = cb() a.topology_notify(Id('a/b'),cb2) T(unwrap(a).__dict_callbacks__['b'], set((weakref.ref(cb1), weakref.ref(cb2)))) del cb1 T(unwrap(a).__dict_callbacks__['b'],set((weakref.ref(cb2),))) del cb2 T(not unwrap(a).__dict_callbacks__.has_key('b') or unwrap(a).__dict_callbacks__['b'] == set()) # Test that callbacks are actually called # Called for adding an object cb1 = cb() a.topology_notify(Id('a/b'),cb1) cb2 = cb() a.topology_notify(Id('a/b'),cb2) b = Element(id=Id('b')) cbp = cb() b.topology_notify(Id('.'),cbp) a.add(b) T(cb1.count,1) T(cb2.count,1) T(cbp.count,1) T(not unwrap(a).__dict_callbacks__.has_key('b')) T(not unwrap(b).__dict_callbacks__.has_key('parent')) # Test for removing an object, just a check that there is no .remove # for now. T(not hasattr(a,'remove'))
def testId__iter__(self): p = [] for i in Id('aa/b/cc/dd'): self.assert_(isinstance(i, Id)) p.append(i) self.assert_(p == [Id('aa'), Id('b'), Id('cc'), Id('dd')])
def testIdInitWithId(self): """Id(Id('foo'))""" a = Id('foo') b = Id(a) self.assert_(hash(a) == hash(b))
def testIdHashable(self): """hash(Id())""" a = Id('foo') b = Id('bar') c = Id('foo') self.assert_(hash(a) == hash(c)) self.assert_(hash(a) != hash(b))
def _init(self): self.add(self.from_ab(self.thickness, id=Id('pad'), layer='top.pad')) self.add( self.from_ab(self.thickness + (self.clearance * 2), id=Id('clearance'), layer='top.clearance')) self.add(self.from_ab(self.mask, id=Id('mask'), layer='top.mask')) self.connects.add(Id('pad'))
def testId_len(self): """len(Id)""" def T(x): self.assert_(x) T(len(Id('_1/_2/_3')) == 3) T(len(Id('_1/_2')) == 2) T(len(Id('_1')) == 1) T(len(Id('.')) == 0) T(len(Id()) == 0)
def testElementRef_apply_remove_context(self): """ElementRef._(apply|remove)_context""" def T(got, expected=True): self.assert_(expected == got, 'got: %s expected: %s' % (got, expected)) global bypass class skit(Element): def f(self, d): global bypass r = bypass bypass = d return ElementRef(self, r) a = Element(id=Id('a')) a.add(Element(id=Id('b'))) a.b.add(Element(id=Id('c'))) s = skit(id=Id('s')) a.b.c.add(s) bypass = Id('.') r = a.b.c.s.f(None) T(r().id, Id('a/b/c/s')) bypass = Id('../../..') r = a.b.c.s.f(r) T(bypass().id, Id('.')) T(r().id, Id('a'))
def testIdAddSide_effects(self): """Id() + Id() has no side effects""" a = Id('foo') b = Id('bar') c = a + b self.assert_(str(a) == 'foo') self.assert_(str(b) == 'bar') self.assert_(str(c) == 'foo/bar')
def testIdEqNeq(self): """Id() ==, != operators""" self.assert_(Id() == Id()) self.assert_(not Id() != Id()) self.assert_(Id('asdf') != Id()) self.assert_(Id('asdf') == Id() + Id('asdf'))
def testId_build_context(self): """Id._build_context()""" def T(got, expected=True): self.assert_(expected == got, 'got: %s expected: %s' % (got, expected)) T(Id('spam')._build_context(Id('eggs'), False), Id('eggs/spam')) T( Id('spam')._build_context(Id('ham/eggs'), False), Id('ham/eggs/spam')) T(Id('spam')._build_context(Id('ham/eggs'), True), Id('ham'))
def T(elem,id_set): ids = set() for e in elem: if isinstance(e,Element): ids.add(e.id) id_set = set([Id(i) for i in id_set]) self.assert_(ids == id_set,'got: %s expected: %s' % (ids,id_set))
def testElementRemoveNotImplemented(self): """Element.remove() not yet implemented""" # This is a real test, if this fails, we need to make sure that # Connects handles the case where a Element parent is removed. a = Element(id=Id('a')) self.assert_(not hasattr(a,'remove'))
def testConnectsReprEvalRepr(self): """repr(eval(repr(Connects))) round trip""" def T(got,expected = True): self.assert_(expected == got,'got: %s expected: %s' % (got,expected)) a = Element(id=Id('a')) a.add(Element(id=Id('b'))) a.b.add(Element(id=Id('c'))) a.connects.add(Id('.')) a.connects.add(a.b) a.connects.add(a.b.c) a2 = Element(id='a') a2.connects = eval(repr(a.connects)) a2.connects.base = a2 T(repr(a2.connects),repr(a.connects))
def __init__(self, id=Id()): """Create a sheet. id - Id name """ Component.__init__(self, id=id)
def testId_from_Id_subclass(self): """Id(some id subclass) returns an Id""" class foo(Id): pass f = foo('foo') self.assert_(isinstance(f, foo)) f = Id(f) self.assert_(not isinstance(f, foo))
def _init(self): top_leds = [] bottom_leds = [] def dt(a, b): t = self.add(Trace(thickness=20 * MIL)) t.set_endpoints(a, b) for x in xrange(self.cols): prev = None for y in xrange(self.rows): l = Led(id=Id('LED%s_%s' % (str(x), str(y)))) translate( l, V((x * self.spacing) - ((self.cols - 1) * self.spacing / 2), (y * self.spacing) - ((self.rows - 0) * self.spacing / 2))) l = self.add(l) if prev is None: top_leds.append(l) else: dt(prev.footprint._2, l.footprint._1) prev = l bottom_leds.append(prev) # Create offset points for the common anodes and cathodes. top_points = [] for t in top_leds: p = Point() translate(p, centerof(t.footprint._1) + V(0, -self.spacing / 2)) p = self.add(p) dt(t.footprint._1, p) top_points.append(p) bottom_points = [] for t in bottom_leds: p = Point() translate(p, centerof(t.footprint._2) + V(0, self.spacing / 2)) p = self.add(p) dt(t.footprint._2, p) bottom_points.append(p) # Link common anodes and cathodes p = None for i in top_points: if p is not None: dt(p, i) p = i p = None for i in bottom_points: if p is not None: dt(p, i) p = i
def testSymbol(self): """Symbol class""" def T(got, expected=True): self.assert_( got == expected, '\ngot: %s\nexpected: %s' % (repr(got), repr(expected))) class foo(Symbol): def _init(self): a = Pin(id='a') b = Pin(id='b') c = Pin(id='c') self.create_linked_pins((a, b, c, 'd')) f = foo(id=Id('f')) T(f.a.connects.to(Id('f/footprint/_1'))) T(f.b.connects.to(Id('f/footprint/_2'))) T(f.c.connects.to(Id('f/footprint/_3'))) T(f.d.connects.to(Id('f/footprint/_4')))
def testBaseTrace(self): """Basic tests of BaseTrace""" def T(got, expected=True): self.assert_(expected == got, 'got: %s expected: %s' % (got, expected)) a = Element(id=Id('a')) b = Element(id=Id('b')) a.add(b) b.add(Pin(dia=1, thickness=1, clearance=1, mask=1, id=Id('foo'))) b.add( Pad(a=(0, 0), b=(1, 1), thickness=0.5, clearance=0.2, mask=0.6, id=Id('bar'))) class basetrace(BaseTrace): valid_endpoint_types = (Pin, Pad) a.add(basetrace(id='t')) a.t.set_endpoints(a.b.foo, a.b.bar) T(a.t.a().id, Id('a/b/foo')) T(a.t.b().id, Id('a/b/bar')) T(a.b.foo in a.t.connects) T(a.b.bar in a.t.connects) T(a.b.foo.connects.to(a.t)) T(a.b.bar.connects.to(a.t))
def testElementCommonParent(self): """Element._common_parent and related functions""" def T(got,expected = True): self.assert_(expected == got,'got: %s expected: %s' % (got,expected)) a = Element(id=Id('a')) b = Element(id=Id('b')) T(a.have_common_parent(a)) T(b.have_common_parent(b)) T(not a.have_common_parent(b)) T(not b.have_common_parent(a)) a.add(b) T(a.have_common_parent(b)) T(b.have_common_parent(a)) a.add(Element(id=Id('z'))) a.b.add(Element(id=Id('c'))) T(a.z.have_common_parent(a.b.c)) T(not Element().have_common_parent(a.b.c))
def testId_subclassing(self): """Subclasses of Id work""" class foo(Id): def __new__(cls, s): return Id.__new__(cls, 'foo' + s) f = foo('lish') self.assert_(isinstance(f, Id)) self.assert_(isinstance(f, foo)) self.assert_(f == Id('foolish')) self.assert_(str(f) == 'foolish') class foo(Id): def __new__(cls, s, bar): self = Id.__new__(cls, s) self.bar = bar return self f = foo(Id('bar'), 'bar') self.assert_(isinstance(f, Id)) self.assert_(isinstance(f, foo)) self.assert_(f == Id('bar')) self.assert_(str(f) == 'bar') self.assert_(f.bar == 'bar')
def testConnectsExplicit(self): """Explicit connections""" def T(got,expected = True): self.assert_(expected == got,'got: %s expected: %s' % (got,expected)) def R(ex,fn): self.assertRaises(ex,fn) a = Element(id=Id('a')) T(set(a.connects),set()) b = Element(id=Id('b')) R(ValueError,lambda: a.connects.add(b)) a.add(b) a.add(Element(id=Id('c'))) a.connects.add(a.b) T(a.b in a.connects) T(Id('a/b') in a.connects) T(not (Id('c') in a.connects)) T(not (a.c in a.connects)) R(ValueError,lambda: Element() in a.connects)
def iterlayout(self, layer_mask): if self.layer in layer_mask: if not self.a or not self.b: raise NotImplementedError # FIXME: try: yield self.copper except AttributeError: self.add( Line(a=centerof(self.a()), b=centerof(self.b()), thickness=self.thickness, layer=self.layer, id=Id('copper'))) yield self.copper
def testElementIdAttr(self): """Auto-magical attribute lookup from sub-element Id's""" a = Element(id=Id('a')) translate(a,V(1,1)) foo = Element(id=Id('foo')) translate(foo,V(2,1)) bar = Element(id=Id('bar')) translate(bar,V(1,2)) a.add(foo) a.add(bar) self.assert_(a.foo.id == Id('a/foo')) self.assert_(repr(centerof(a.foo)) == repr(V(3,2))) self.assert_(a.bar.id == Id('a/bar')) self.assert_(repr(centerof(a.bar)) == repr(V(2,3))) self.assertRaises(AttributeError,lambda: a.foobar) foo.foo = 'foo' self.assert_(a.foo.foo is foo.foo) a.foo.bar = 'bar' self.assert_(a.foo.bar is foo.bar)
def testId_apply_context(self): def T(got, expected=True): self.assert_(expected == got, 'got: %s expected: %s' % (got, expected)) class e(object): def __init__(self, id): self.id = Id(id) self._id_real = Id(id) T(Id()._apply_context(e('ham')), Id('ham')) T(Id('eggs')._apply_context(e('ham')), Id('ham/eggs')) T(Id('..')._apply_context(e('ham')), Id())
def testElement__getitem__(self): """Element[] lookups""" def T(elem,key,expected_id): got = elem[key] expected_id = Id(expected_id) self.assert_(got.id == expected_id,'got: %s expected: %s' % (got.id,expected_id)) def R(elem,key,partial_stack): # partial_stack is not currently used, but err = None self.assertRaises(KeyError,lambda:elem[key]) a = Element(id='a') T(a,'','a') R(a,'foo',[]) R(a,Id('foo'),[]) R(a,'..',[a]) R(a,'../b',[a]) R(a,'../..',[a]) b = a.add(Element(id='b')) T(a,'b','a/b') with b as b2: R(a,'b/b',[a,b2]) R(b2,'../c',[b2,a]) c = a.add(Element(id='c')) T(a,'c','a/c') d = a.b.add(Element(id='d')) T(a,'b','a/b') T(a,'b/d','a/b/d') T(b,'..',a['.'].id) T(b,'../b',b.id) T(b,'../b/d',d.id) e = Element(id='e') e2 = a.add(e) a['e'].foo = 'foo' self.assert_(e2.foo is e.foo) self.assert_(a.e.foo is e.foo) self.assert_(a['e'].foo is e.foo)
def test_Source_notify_unwraps(self): """Source.notify unwraps callables before storing them""" def T(got, expected=True): self.assert_(expected == got, 'got: %s expected: %s' % (got, expected)) a = Element(id=Id('a')) called = False class f: def __init__(self): self.called = False def __call__(self): self.called = True f = f() a.notify('foo', f) a.foo = 10 T(f.called)
def __new__(cls,*args): """Create a new ElementRef ref - Referenced Element, or Id base - Context providing Element """ ref = None base = None if len(args) == 1: ref = args[0] elif len(args) == 2: base = args[0] ref = args[1] else: raise TypeError("%s.__new__() takes either 1 or 2 arguments, %d given", cls.__name__, len(args)) try: ref = ref.id except AttributeError: if not isinstance(ref,Id): raise TypeError("Expected Element, ElementRef or Id, not %s" % type(id)) # Id.__new__(Id('foo')) short-circuits to directly return Id('foo'), # have to kludge around that. self = Id.__new__(cls,ref) self.base = base if self.base is not None: self.base.connects.add(self) return self
def __new__(cls, *args): """Create a new ElementRef ref - Referenced Element, or Id base - Context providing Element """ ref = None base = None if len(args) == 1: ref = args[0] elif len(args) == 2: base = args[0] ref = args[1] else: raise TypeError( "%s.__new__() takes either 1 or 2 arguments, %d given", cls.__name__, len(args)) try: ref = ref.id except AttributeError: if not isinstance(ref, Id): raise TypeError("Expected Element, ElementRef or Id, not %s" % type(id)) # Id.__new__(Id('foo')) short-circuits to directly return Id('foo'), # have to kludge around that. self = Id.__new__(cls, ref) self.base = base if self.base is not None: self.base.connects.add(self) return self
def test_apply_remove_context(self): """V._(apply|remove)_context""" def T(got,expected = True): self.assert_(expected == got,'got: %s expected: %s' % (got,expected)) a = Element(id=Id('a')) b = Element(id=Id('b')) a.add(b) c = Element(id=Id('c')) a.b.add(c) a.v = V(1,1) c.v = V(1,1) translate(a.b,V(0,1)) translate(a.b.c,V(1,0)) T((a.b.c.v == V(2,2)).all()) # The added d element here is important. It's transform is null, so any # optimizations that skip applying null transforms will hopefully # trigger bugs here. # # Secondly, if we used c, it still has a transform applied to any # results from it. For instance with a.b.c as uc, uc.v == V(2,1) right # now. Confusing! d = Element(id=Id('d')) a.b.c.add(d) with a.b.c.d as ud: # The original vertex is at 1,1 The two translations moved by # center point by 0,1 then 1,0 totaling 1,1 so the result cancels # out to 0,0 T((ud[Id('../../')].v == V(0,0)).all()) rotate(a,pi / 2) T(repr(a.b.c.v),repr(V(2,-2))) with a.b.c.d as ud: # Even with the rotation, the translates still cancel out, why? # Because the whole stack above a was rotated, which isn't "seen" # from the perspective of the stack above a. T((ud[Id('../../')].v == V(0,0)).all())
def __new__(cls,s,bar): self = Id.__new__(cls,s) self.bar = bar return self
def __new__(cls,s): return Id.__new__(cls,'foo' + s)