def test_instance(self): Point = structclass('Point', 'x y') p = Point(11, 22) self.assertEqual(p, Point(x=11, y=22)) self.assertEqual(p, Point(11, y=22)) self.assertEqual(p, Point(y=22, x=11)) self.assertEqual(p, Point(*(11, 22))) self.assertEqual(p, Point(**dict(x=11, y=22))) self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument self.assertEqual(repr(p), 'Point(x=11, y=22)') #self.assertNotIn('__weakref__', dir(p)) self.assertEqual(p, Point._make([11, 22])) # test _make classmethod self.assertEqual(p.__fields__, ('x', 'y')) # test __fields__ attribute self.assertEqual(tuple(p._replace(x=1)), (1, 22)) # test _replace method self.assertEqual(p._asdict(), dict(x=1, y=22)) # test _asdict method #self.assertEqual(vars(p), p._asdict()) # verify that vars() works p.x = -1 self.assertEqual(p.x, -1) # verify that field string can have commas Point = structclass('Point', 'x, y') p = Point(x=11, y=22) self.assertEqual(repr(p), 'Point(x=11, y=22)') # verify that fieldspec can be a non-string sequence Point = structclass('Point', ('x', 'y')) p = Point(x=11, y=22) self.assertEqual(repr(p), 'Point(x=11, y=22)')
def test_instance(self): Point = structclass('Point', 'x y') p = Point(11, 22) self.assertEqual(p, Point(x=11, y=22)) self.assertEqual(p, Point(11, y=22)) self.assertEqual(p, Point(y=22, x=11)) self.assertEqual(p, Point(*(11, 22))) self.assertEqual(p, Point(**dict(x=11, y=22))) self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument self.assertEqual(repr(p), 'Point(x=11, y=22)') #self.assertNotIn('__weakref__', dir(p)) #print(p) self.assertEqual(p, Point._make([11, 22])) # test _make classmethod self.assertEqual(p.__attrs__, ('x', 'y')) # test __attrs__ attribute self.assertEqual(tuple(p._replace(x=1)), (1, 22)) # test _replace method self.assertEqual(p._asdict(), dict(x=1, y=22)) # test _asdict method #self.assertEqual(vars(p), p._asdict()) # verify that vars() works p.x = -1 self.assertEqual(p.x, -1) # verify that field string can have commas Point = structclass('Point', 'x, y') p = Point(x=11, y=22) self.assertEqual(repr(p), 'Point(x=11, y=22)') # verify that fieldspec can be a non-string sequence Point = structclass('Point', ('x', 'y')) p = Point(x=11, y=22) self.assertEqual(repr(p), 'Point(x=11, y=22)')
def test_join_structclasses(self): C1 = structclass('C1', 'a b') C2 = structclass('C2', 'c d') C = join_classes('C', [C1, C2]) CC = structclass('C', 'a b c d') c = C(1,2,3,4) cc = CC(1,2,3,4) self.assertEqual(c, cc)
def test_join_structclasses(self): C1 = structclass('C1', 'a b') C2 = structclass('C2', 'c d') C = join_classes('C', [C1, C2]) CC = structclass('CC', 'a b c d') cc = CC(1, 2, 3, 4) c = C(1, 2, 3, 4) self.assertNotEqual(c, cc)
def test_hash(self): A = structclass('A', 'x y', readonly=True) a = A(1, 2) self.assertEqual(hash(a), hash(tuple(a))) B = structclass('B', 'x y', hashable=True) b = B(1, 2) hash_b = hash(b) self.assertEqual(hash_b, hash(tuple(b))) b.x = -1 self.assertNotEqual(hash(b), hash_b)
def _make_structclass(name, types, readonly=False, use_dict=False, gc=False, use_weakref=False, hashable=False): msg = "StructClass('Name', [(f0, t0), (f1, t1), ...]); each t must be a type" types = [(n, _type_check(t, msg)) for n, t in types] module = None try: module = _sys._getframe(2).f_globals.get('__name__', '__main__') except (AttributeError, ValueError): pass # print('mod:', module) struct_cls = structclass(name, [n for n, _ in types], readonly=readonly, use_dict=use_dict, gc=gc, use_weakref=use_weakref, hashable=hashable, module=module) struct_cls.__annotations__ = dict(types) # try: # struct_cls.__module__ = _sys._getframe(2).f_globals.get('__name__', '__main__') # except (AttributeError, ValueError): # pass return struct_cls
def record(self): if not self.r: if isinstance(self.raw, StructClass): return self.raw else: d = self.dict() self.r = structclass('T', d)(**d) return self.r
def test_refleak_on_assignemnt(self): Test = structclass("Test", "x") a = {} c = sys.getrefcount(a) b = Test(a) self.assertEqual(sys.getrefcount(a), c + 1) b.x = None self.assertEqual(sys.getrefcount(a), c)
def test_dict(self): A = structclass('A', 'a b c', use_dict=True) a = A(a=1, b=2, c=3, d=100, e=200) self.assertEqual(a.a, 1) self.assertEqual(a.b, 2) self.assertEqual(a.c, 3) self.assertEqual(a.__dict__, {'d': 100, 'e': 200}) self.assertEqual(len(a), 3)
def test_dict(self): A = structclass('A', 'a b c', usedict=True) a=A(a=1, b=2, c=3, d=100, e=200) self.assertEqual(a.a, 1) self.assertEqual(a.b, 2) self.assertEqual(a.c, 3) self.assertEqual(a.__dict__, {'d':100, 'e':200}) self.assertEqual(len(a), 3)
def test_factory(self): Point = structclass('Point', 'x y') self.assertEqual(Point.__name__, 'Point') self.assertEqual(Point.__doc__, 'Point(x, y)') #self.assertEqual(Point.__slots__, ('x','y')) self.assertEqual(Point.__module__, __name__) self.assertEqual(Point.__attrs__, ('x', 'y')) self.assertRaises(ValueError, structclass, 'abc%', 'efg ghi') # type has non-alpha char self.assertRaises(ValueError, structclass, 'class', 'efg ghi') # type has keyword self.assertRaises(ValueError, structclass, '9abc', 'efg ghi') # type starts with digit self.assertRaises(ValueError, structclass, 'abc', 'efg g%hi') # field with non-alpha char self.assertRaises(ValueError, structclass, 'abc', 'abc class') # field has keyword self.assertRaises(ValueError, structclass, 'abc', '8efg 9ghi') # field starts with digit self.assertRaises(ValueError, structclass, 'abc', '_efg ghi') # field with leading underscore self.assertRaises(ValueError, structclass, 'abc', 'efg efg ghi') # duplicate field structclass('Point0', 'x1 y2') # Verify that numbers are allowed in names structclass('_', 'a b c') # Test leading underscores in a typename nt = structclass('nt', 'the quick brown fox') # check unicode input self.assertNotIn("u'", repr(nt.__attrs__)) nt = structclass('nt', ('the', 'quick')) # check unicode input self.assertNotIn("u'", repr(nt.__attrs__)) self.assertRaises(TypeError, Point._make, [11]) # catch too few args self.assertRaises(TypeError, Point._make, [11, 22, 33]) # catch too many args
def test_tupleness(self): Point = structclass('Point', 'x y') p = Point(11, 22) self.assertEqual(tuple(p), (11, 22)) # coercable to a real tuple self.assertEqual(list(p), [11, 22]) # coercable to a list self.assertEqual(max(p), 22) # iterable self.assertEqual(max(*p), 22) # star-able x, y = p self.assertEqual(tuple(p), (x, y)) # unpacks like a tuple self.assertEqual(p.x, x) self.assertEqual(p.y, y) self.assertRaises(AttributeError, eval, 'p.z', locals()) Point2 = structclass('Point', 'x y', sequence=False) p2 = Point2(11, 22) with self.assertRaises(TypeError): p2[3]
def test_repr(self): with support.captured_stdout() as template: A = structclass('A', 'x') a = A(1) self.assertEqual(repr(a), 'A(x=1)') # repr should show the name of the subclass class B(A): pass b = B(1) self.assertEqual(repr(b), 'B(x=1)')
def test_tupleness(self): Point = structclass('Point', 'x y') p = Point(11, 22) self.assertEqual(tuple(p), (11, 22)) # coercable to a real tuple self.assertEqual(list(p), [11, 22]) # coercable to a list self.assertEqual(max(p), 22) # iterable self.assertEqual(max(*p), 22) # star-able x, y = p self.assertEqual(tuple(p), (x, y)) # unpacks like a tuple self.assertEqual(p.x, x) self.assertEqual(p.y, y) self.assertRaises(AttributeError, eval, 'p.z', locals()) Point2 = structclass('Point', 'x y', assequence=False) p2 = Point2(11, 22) with self.assertRaises(TypeError): p2[3]
def test_defaults(self): Point = structclass('Point', 'x y', defaults=(10, 20)) # 2 defaults self.assertEqual(tuple(Point(1, 2)), (1, 2)) self.assertEqual(tuple(Point(1)), (1, 20)) self.assertEqual(tuple(Point()), (10, 20)) Point = structclass('Point', 'x y', defaults=(20, )) # 1 default self.assertEqual(tuple(Point(1, 2)), (1, 2)) self.assertEqual(tuple(Point(1)), (1, 20)) Point = structclass('Point', 'x y', defaults=()) # 0 defaults self.assertEqual(tuple(Point(1, 2)), (1, 2)) with self.assertRaises(TypeError): Point(1) with self.assertRaises(TypeError): # catch too few args Point() with self.assertRaises(TypeError): # catch too many args Point(1, 2, 3) with self.assertRaises(TypeError): # too many defaults Point = structclass('Point', 'x y', defaults=(10, 20, 30)) with self.assertRaises(TypeError): # non-iterable defaults Point = structclass('Point', 'x y', defaults=10) with self.assertRaises(TypeError): # another non-iterable default Point = structclass('Point', 'x y', defaults=False) Point = structclass('Point', 'x y', defaults=None) # default is None self.assertIsNone(Point.__new__.__defaults__, None) self.assertEqual(tuple(Point(10, 20)), (10, 20)) with self.assertRaises(TypeError): # catch too few args Point(10) Point = structclass('Point', 'x y', defaults=[10, 20]) # allow non-tuple iterable self.assertEqual(Point.__new__.__defaults__, (10, 20)) self.assertRaises(TypeError, Point(1, 2), (1, 2)) self.assertEqual(Point(1, 2), Point(1, 2)) self.assertNotEqual(Point(1, 2), Point(10, 20)) self.assertEqual(Point(1), Point(1, 20)) self.assertEqual(Point(), Point(10, 20)) Point = structclass('Point', 'x y', defaults=iter([10, 20])) # allow plain iterator self.assertEqual(Point.__new__.__defaults__, (10, 20)) self.assertEqual(tuple(Point(1, 2)), (1, 2)) self.assertEqual(tuple(Point(1)), (1, 20)) self.assertEqual(tuple(Point()), (10, 20))
def test_name_conflicts(self): # Some names like "self", "cls", "tuple", "itemgetter", and "property" # failed when used as field names. Test to make sure these now work. T = structclass('T', 'itemgetter property self cls tuple') t = T(1, 2, 3, 4, 5) self.assertEqual(tuple(t), (1, 2, 3, 4, 5)) newt = t._replace(itemgetter=10, property=20, self=30, cls=40, tuple=50) self.assertEqual(tuple(newt), (10, 20, 30, 40, 50)) # Broader test of all interesting names in a template with support.captured_stdout() as template: T = structclass('T', 'x') words = set(re.findall('[A-Za-z]+', template.getvalue())) words -= set(keyword.kwlist) words = list(words) if 'None' in words: words.remove('None') T = structclass('T', words) # test __new__ values = tuple(range(len(words))) t = T(*values) self.assertEqual(tuple(t), values) t = T(**dict(zip(T.__attrs__, values))) self.assertEqual(tuple(t), values) # test _make t = T._make(values) self.assertEqual(tuple(t), values) # exercise __repr__ repr(t) # test _asdict self.assertEqual(t._asdict(), dict(zip(T.__attrs__, values))) # test _replace t = T._make(values) newvalues = tuple(v * 10 for v in values) newt = t._replace(**dict(zip(T.__attrs__, newvalues))) self.assertEqual(tuple(newt), newvalues) # test __attrs__ self.assertEqual(T.__attrs__, tuple(words))
def test_repr(self): A = structclass('A', 'x') a = A(1) self.assertEqual(repr(a), 'A(x=1)') # repr should show the name of the subclass class B(A): pass b = B(1) self.assertEqual(repr(b), 'B(x=1)')
def test_odd_sizes(self): Zero = structclass('Zero', '') self.assertEqual(tuple(Zero()), ()) self.assertEqual(tuple(Zero._make([])), ()) self.assertEqual(repr(Zero()), 'Zero()') self.assertEqual(Zero()._asdict(), {}) self.assertEqual(Zero().__fields__, ()) Dot = structclass('Dot', 'd') self.assertEqual(tuple(Dot(1)), (1, )) self.assertEqual(tuple(Dot._make([1])), (1, )) self.assertEqual(Dot(1).d, 1) self.assertEqual(repr(Dot(1)), 'Dot(d=1)') self.assertEqual(Dot(1)._asdict(), {'d': 1}) self.assertEqual(tuple(Dot(1)._replace(d=999)), (999, )) self.assertEqual(Dot(1).__fields__, ('d', )) # n = 5000 n = 254 # SyntaxError: more than 255 arguments: import string, random names = list( set(''.join( [random.choice(string.ascii_letters) for j in range(10)]) for i in range(n))) n = len(names) Big = structclass('Big', names) b = Big(*range(n)) self.assertEqual(tuple(b), tuple(range(n))) self.assertEqual(tuple(Big._make(range(n))), tuple(range(n))) for pos, name in enumerate(names): self.assertEqual(getattr(b, name), pos) repr(b) # make sure repr() doesn't blow-up d = b._asdict() d_expected = dict(zip(names, range(n))) self.assertEqual(d, d_expected) b2 = b._replace(**dict([(names[1], 999), (names[-5], 42)])) b2_expected = list(range(n)) b2_expected[1] = 999 b2_expected[-5] = 42 self.assertEqual(tuple(b2), tuple(b2_expected)) self.assertEqual(b.__fields__, tuple(names))
def test_name_conflicts(self): # Some names like "self", "cls", "tuple", "itemgetter", and "property" # failed when used as field names. Test to make sure these now work. T = structclass('T', 'itemgetter property self cls tuple') t = T(1, 2, 3, 4, 5) self.assertEqual(tuple(t), (1, 2, 3, 4, 5)) newt = t._replace(itemgetter=10, property=20, self=30, cls=40, tuple=50) self.assertEqual(tuple(newt), (10, 20, 30, 40, 50))
def test_defaults(self): Point = structclass('Point', 'x y', defaults=(10, 20)) # 2 defaults self.assertEqual(tuple(Point(1, 2)), (1, 2)) self.assertEqual(tuple(Point(1)), (1, 20)) self.assertEqual(tuple(Point()), (10, 20)) Point = structclass('Point', 'x y', defaults=(20,)) # 1 default self.assertEqual(tuple(Point(1, 2)), (1, 2)) self.assertEqual(tuple(Point(1)), (1, 20)) Point = structclass('Point', 'x y', defaults=()) # 0 defaults self.assertEqual(tuple(Point(1, 2)), (1, 2)) with self.assertRaises(TypeError): Point(1) with self.assertRaises(TypeError): # catch too few args Point() with self.assertRaises(TypeError): # catch too many args Point(1, 2, 3) with self.assertRaises(TypeError): # too many defaults Point = structclass('Point', 'x y', defaults=(10, 20, 30)) with self.assertRaises(TypeError): # non-iterable defaults Point = structclass('Point', 'x y', defaults=10) with self.assertRaises(TypeError): # another non-iterable default Point = structclass('Point', 'x y', defaults=False) Point = structclass('Point', 'x y', defaults=None) # default is None self.assertIsNone(Point.__new__.__defaults__, None) self.assertEqual(tuple(Point(10, 20)), (10, 20)) with self.assertRaises(TypeError): # catch too few args Point(10) Point = structclass('Point', 'x y', defaults=[10, 20]) # allow non-tuple iterable self.assertEqual(Point.__new__.__defaults__, (10, 20)) self.assertRaises(TypeError, Point(1, 2), (1, 2)) self.assertEqual(Point(1, 2), Point(1, 2)) self.assertNotEqual(Point(1, 2), Point(10, 20)) self.assertEqual(Point(1), Point(1, 20)) self.assertEqual(Point(), Point(10, 20)) Point = structclass('Point', 'x y', defaults=iter([10, 20])) # allow plain iterator self.assertEqual(Point.__new__.__defaults__, (10, 20)) self.assertEqual(tuple(Point(1, 2)), (1, 2)) self.assertEqual(tuple(Point(1)), (1, 20)) self.assertEqual(tuple(Point()), (10, 20))
def _make_structclass(name, types, readonly=False, usedict=False, gc=False, weakref=False, hashable=False): msg = "StructClass('Name', [(f0, t0), (f1, t1), ...]); each t must be a type" types = [(n, _type_check(t, msg)) for n, t in types] struct_cls = structclass(name, [n for n, _ in types], readonly=readonly, usedict=usedict, gc=gc, weakref=weakref, hashable=hashable) struct_cls.__annotations__ = dict(types) try: struct_cls.__module__ = _sys._getframe(2).f_globals.get('__name__', '__main__') except (AttributeError, ValueError): pass return struct_cls
def test_odd_sizes(self): Zero = structclass('Zero', '') self.assertEqual(tuple(Zero()), ()) self.assertEqual(tuple(Zero._make([])), ()) self.assertEqual(repr(Zero()), 'Zero()') self.assertEqual(Zero()._asdict(), {}) self.assertEqual(Zero().__attrs__, ()) Dot = structclass('Dot', 'd') self.assertEqual(tuple(Dot(1)), (1,)) self.assertEqual(tuple(Dot._make([1])), (1,)) self.assertEqual(Dot(1).d, 1) self.assertEqual(repr(Dot(1)), 'Dot(d=1)') self.assertEqual(Dot(1)._asdict(), {'d':1}) self.assertEqual(tuple(Dot(1)._replace(d=999)), (999,)) self.assertEqual(Dot(1).__attrs__, ('d',)) # n = 5000 n = 254 # SyntaxError: more than 255 arguments: import string, random names = list(set(''.join([random.choice(string.ascii_letters) for j in range(10)]) for i in range(n))) n = len(names) Big = structclass('Big', names) b = Big(*range(n)) self.assertEqual(tuple(b), tuple(range(n))) self.assertEqual(tuple(Big._make(range(n))), tuple(range(n))) for pos, name in enumerate(names): self.assertEqual(getattr(b, name), pos) repr(b) # make sure repr() doesn't blow-up d = b._asdict() d_expected = dict(zip(names, range(n))) self.assertEqual(d, d_expected) b2 = b._replace(**dict([(names[1], 999),(names[-5], 42)])) b2_expected = list(range(n)) b2_expected[1] = 999 b2_expected[-5] = 42 self.assertEqual(tuple(b2), tuple(b2_expected)) self.assertEqual(b.__attrs__, tuple(names))
def test_name_conflicts(self): # Some names like "self", "cls", "tuple", "itemgetter", and "property" # failed when used as field names. Test to make sure these now work. T = structclass('T', 'itemgetter property self cls tuple') t = T(1, 2, 3, 4, 5) self.assertEqual(tuple(t), (1,2,3,4,5)) newt = t._replace(itemgetter=10, property=20, self=30, cls=40, tuple=50) self.assertEqual(tuple(newt), (10,20,30,40,50)) # Broader test of all interesting names in a template with support.captured_stdout() as template: T = structclass('T', 'x') words = set(re.findall('[A-Za-z]+', template.getvalue())) words -= set(keyword.kwlist) words = list(words) if 'None' in words: words.remove('None') T = structclass('T', words) # test __new__ values = tuple(range(len(words))) t = T(*values) self.assertEqual(tuple(t), values) t = T(**dict(zip(T.__attrs__, values))) self.assertEqual(tuple(t), values) # test _make t = T._make(values) self.assertEqual(tuple(t), values) # exercise __repr__ repr(t) # test _asdict self.assertEqual(t._asdict(), dict(zip(T.__attrs__, values))) # test _replace t = T._make(values) newvalues = tuple(v*10 for v in values) newt = t._replace(**dict(zip(T.__attrs__, newvalues))) self.assertEqual(tuple(newt), newvalues) # test __attrs__ self.assertEqual(T.__attrs__, tuple(words))
def __call__(self, *args, **kwargs): raise NotImplemented # NOTE! this was origiannl a @dataclass(unsafe_hash=True, order=True) # class TokenGazetteerMatch, with __slots__=("start", "end", "match", "entrydata", "matcherdata") # and type declarations start: int, end: int, match: list, entrydata: object, matcherdata: object # HOWEVER, dataclasses require Python 3.7 and have their own issues. # Named tuples cannot be used because what we need has to be mutable. # So for now we use the structclass approach from package recordclass which is very compact and rather fast. # !! structclass by default does NOT support cyclic garbage collection which should be ok for us TokenGazetteerMatch = structclass( "TokenGazetteerMatch", ("start", "end", "match", "data", "listidx") ) class TokenGazetteerNode(object): """ Represent an entry in the hash map of entry first tokens. If is_match is True, that token is already a match and data contains the entry data. The continuations attribute contains None or a list of multi token matches that start with the first token and the entry data if we have a match (all tokens match). """ __slots__ = ("is_match", "data", "nodes", "listidx") def __init__(self, is_match=None, data=None, nodes=None, listidx=None): """
def test_join_structclasses_intersection(self): C1 = structclass('C1', 'a b') C2 = structclass('C2', 'b c') with self.assertRaises(AttributeError): C = join_classes('C', [C1, C2])
def test_factory_doc_attr(self): Point = structclass('Point', 'x y') self.assertEqual(Point.__doc__, 'Point(x, y)')
"""Unit tests for structclass.py.""" import unittest from recordclass import structclass, join_classes from collections import OrderedDict import pickle, copy import keyword import re import sys # try: # from test import support # except: # from test import test_support as support TestNT = structclass('TestNT', 'x y z') # type used for pickle tests TestNT2 = structclass('TestNT2', 'x y z', use_dict=True) # type used for pickle tests class structclassTest(unittest.TestCase): def test_factory(self): Point = structclass('Point', 'x y') self.assertEqual(Point.__name__, 'Point') self.assertEqual(Point.__doc__, 'Point(x, y)') #self.assertEqual(Point.__slots__, ('x','y')) self.assertEqual(Point.__module__, __name__) self.assertEqual(Point.__fields__, ('x', 'y')) self.assertRaises(ValueError, structclass, 'abc%', 'efg ghi') # type has non-alpha char self.assertRaises(ValueError, structclass, 'class',
from recordclass import recordclass, structclass, new_datatype from collections import namedtuple import perf #from sys import getsizeof as sizeof STest = namedtuple("TEST", "a b c d e f g h i j k") sa = STest(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10,k=11) RTest = recordclass("RTEST", "a b c d e f g h i j k") ra = RTest(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10,k=11) RTest2 = structclass("RTEST", "a b c d e f g h i j k") ra2 = RTest2(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10,k=11) RTest3 = structclass("RTEST", "a b c d e f g h i j k", gc=True) ra3 = RTest3(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10,k=11) NDTest = new_datatype("NDTest", "a b c d e f g h i j k") nd = NDTest(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10,k=11) class Test(object): __slots__ = ["a","b","c","d","e","f","g","h","i","j","k"] def __init__(self, a, b, c, d, e, f, g, h, i, j, k): self.a = a; self.b = b; self.c = c self.d = d; self.e = e; self.f = f self.g = g; self.h = h; self.i = i self.j = j; self.k = k
import unittest, doctest, operator from recordclass import structclass, join_classes from collections import OrderedDict import pickle, copy import keyword import re import sys try: from test import support except: from test import test_support as support TestNT = structclass('TestNT', 'x y z') # type used for pickle tests TestNT2 = structclass('TestNT2', 'x y z', usedict=True) # type used for pickle tests class structclassTest(unittest.TestCase): def test_factory(self): Point = structclass('Point', 'x y') self.assertEqual(Point.__name__, 'Point') self.assertEqual(Point.__doc__, 'Point(x, y)') #self.assertEqual(Point.__slots__, ('x','y')) self.assertEqual(Point.__module__, __name__) self.assertEqual(Point.__attrs__, ('x', 'y')) self.assertRaises(ValueError, structclass, 'abc%', 'efg ghi') # type has non-alpha char self.assertRaises(ValueError, structclass, 'class', 'efg ghi') # type has keyword self.assertRaises(ValueError, structclass, '9abc', 'efg ghi') # type starts with digit