Best Python code snippet using autotest_python
namedtuple_with_abc.py
Source:namedtuple_with_abc.py
...4"""5namedtuple_with_abc.py:6* named tuple mix-in + ABC (abstract base class) recipe,7* works under Python 2.6, 2.7 as well as 3.x.8Import this module to patch collections.namedtuple() factory function9-- enriching it with the 'abc' attribute (an abstract base class + mix-in10for named tuples) and decorating it with a wrapper that registers each11newly created named tuple as a subclass of namedtuple.abc.12How to import:13 import collections, namedtuple_with_abc14or:15 import namedtuple_with_abc16 from collections import namedtuple17 # ^ in this variant you must import namedtuple function18 # *after* importing namedtuple_with_abc module19or simply:20 from namedtuple_with_abc import namedtuple21Simple usage example:22 class Credentials(namedtuple.abc):23 _fields = 'username password'24 def __str__(self):25 return ('{0.__class__.__name__}'26 '(username={0.username}, password=...)'.format(self))27 print(Credentials("alice", "Alice's password"))28For more advanced examples -- see below the "if __name__ == '__main__':".29"""30import collections31from abc import ABCMeta, abstractproperty32from functools import wraps33from sys import version_info34__all__ = ('namedtuple',)35_namedtuple = collections.namedtuple36class _NamedTupleABCMeta(ABCMeta):37 '''The metaclass for the abstract base class + mix-in for named tuples.'''38 def __new__(mcls, name, bases, namespace):39 fields = namespace.get('_fields')40 for base in bases:41 if fields is not None:42 break43 fields = getattr(base, '_fields', None)44 if not isinstance(fields, abstractproperty):45 basetuple = _namedtuple(name, fields)46 bases = (basetuple,) + bases47 namespace.pop('_fields', None)48 namespace.setdefault('__doc__', basetuple.__doc__)49 namespace.setdefault('__slots__', ())50 return ABCMeta.__new__(mcls, name, bases, namespace)51exec(52 # Python 2.x metaclass declaration syntax53 """class _NamedTupleABC(object):54 '''The abstract base class + mix-in for named tuples.'''55 __metaclass__ = _NamedTupleABCMeta56 _fields = abstractproperty()""" if version_info[0] < 3 else57 # Python 3.x metaclass declaration syntax58 """class _NamedTupleABC(metaclass=_NamedTupleABCMeta):59 '''The abstract base class + mix-in for named tuples.'''60 _fields = abstractproperty()"""61)62_namedtuple.abc = _NamedTupleABC63#_NamedTupleABC.register(type(version_info)) # (and similar, in the future...)64@wraps(_namedtuple)65def namedtuple(*args, **kwargs):66 '''Named tuple factory with namedtuple.abc subclass registration.'''67 cls = _namedtuple(*args, **kwargs)68 _NamedTupleABC.register(cls)69 return cls70collections.namedtuple = namedtuple71if __name__ == '__main__':72 '''Examples and explanations'''73 # Simple usage74 class MyRecord(namedtuple.abc):75 _fields = 'x y z' # such form will be transformed into ('x', 'y', 'z')76 def _my_custom_method(self):77 return list(self._asdict().items())78 # (the '_fields' attribute belongs to the named tuple public API anyway)79 rec = MyRecord(1, 2, 3)80 print(rec)81 print(rec._my_custom_method())82 print(rec._replace(y=222))83 print(rec._replace(y=222)._my_custom_method())84 # Custom abstract classes...85 class MyAbstractRecord(namedtuple.abc):86 def _my_custom_method(self):87 return list(self._asdict().items())88 try:89 MyAbstractRecord() # (abstract classes cannot be instantiated)90 except TypeError as exc:91 print(exc)92 class AnotherAbstractRecord(MyAbstractRecord):93 def __str__(self):94 return '<<<{0}>>>'.format(super(AnotherAbstractRecord,95 self).__str__())96 # ...and their non-abstract subclasses97 class MyRecord2(MyAbstractRecord):98 _fields = 'a, b'99 class MyRecord3(AnotherAbstractRecord):100 _fields = 'p', 'q', 'r'101 rec2 = MyRecord2('foo', 'bar')102 print(rec2)103 print(rec2._my_custom_method())104 print(rec2._replace(b=222))105 print(rec2._replace(b=222)._my_custom_method())106 rec3 = MyRecord3('foo', 'bar', 'baz')107 print(rec3)108 print(rec3._my_custom_method())109 print(rec3._replace(q=222))110 print(rec3._replace(q=222)._my_custom_method())111 # You can also subclass non-abstract ones...112 class MyRecord33(MyRecord3):113 def __str__(self):114 return '< {0!r}, ..., {0!r} >'.format(self.p, self.r)115 rec33 = MyRecord33('foo', 'bar', 'baz')116 print(rec33)117 print(rec33._my_custom_method())118 print(rec33._replace(q=222))119 print(rec33._replace(q=222)._my_custom_method())120 # ...and even override the magic '_fields' attribute again121 class MyRecord345(MyRecord3):122 _fields = 'e f g h i j k'123 rec345 = MyRecord345(1, 2, 3, 4, 3, 2, 1)124 print(rec345)125 print(rec345._my_custom_method())126 print(rec345._replace(f=222))127 print(rec345._replace(f=222)._my_custom_method())128 # Mixing-in some other classes is also possible:129 class MyMixIn(object):130 def method(self):131 return "MyMixIn.method() called"132 def _my_custom_method(self):133 return "MyMixIn._my_custom_method() called"134 def count(self, item):135 return "MyMixIn.count({0}) called".format(item)136 def _asdict(self): # (cannot override a namedtuple method, see below)137 return "MyMixIn._asdict() called"138 class MyRecord4(MyRecord33, MyMixIn): # mix-in on the right139 _fields = 'j k l x'140 class MyRecord5(MyMixIn, MyRecord33): # mix-in on the left141 _fields = 'j k l x y'142 rec4 = MyRecord4(1, 2, 3, 2)143 print(rec4)144 print(rec4.method())145 print(rec4._my_custom_method()) # MyRecord33's146 print(rec4.count(2)) # tuple's147 print(rec4._replace(k=222))148 print(rec4._replace(k=222).method())149 print(rec4._replace(k=222)._my_custom_method()) # MyRecord33's150 print(rec4._replace(k=222).count(8)) # tuple's151 rec5 = MyRecord5(1, 2, 3, 2, 1)152 print(rec5)153 print(rec5.method())154 print(rec5._my_custom_method()) # MyMixIn's155 print(rec5.count(2)) # MyMixIn's156 print(rec5._replace(k=222))157 print(rec5._replace(k=222).method())158 print(rec5._replace(k=222)._my_custom_method()) # MyMixIn's159 print(rec5._replace(k=222).count(2)) # MyMixIn's160 # None that behavior: the standard namedtuple methods cannot be161 # overriden by a foreign mix-in -- even if the mix-in is declared162 # as the leftmost base class (but, obviously, you can override them163 # in the defined class or its subclasses):164 print(rec4._asdict()) # (returns a dict, not "MyMixIn._asdict() called")165 print(rec5._asdict()) # (returns a dict, not "MyMixIn._asdict() called")166 class MyRecord6(MyRecord33):167 _fields = 'j k l x y z'168 def _asdict(self):169 return "MyRecord6._asdict() called"170 rec6 = MyRecord6(1, 2, 3, 1, 2, 3)171 print(rec6._asdict()) # (this returns "MyRecord6._asdict() called")172 # All that record classes are real subclasses of namedtuple.abc:173 assert issubclass(MyRecord, namedtuple.abc)174 assert issubclass(MyAbstractRecord, namedtuple.abc)175 assert issubclass(AnotherAbstractRecord, namedtuple.abc)176 assert issubclass(MyRecord2, namedtuple.abc)177 assert issubclass(MyRecord3, namedtuple.abc)178 assert issubclass(MyRecord33, namedtuple.abc)179 assert issubclass(MyRecord345, namedtuple.abc)180 assert issubclass(MyRecord4, namedtuple.abc)181 assert issubclass(MyRecord5, namedtuple.abc)182 assert issubclass(MyRecord6, namedtuple.abc)183 # ...but abstract ones are not subclasses of tuple184 # (and this is what you probably want):185 assert not issubclass(MyAbstractRecord, tuple)186 assert not issubclass(AnotherAbstractRecord, tuple)187 assert issubclass(MyRecord, tuple)188 assert issubclass(MyRecord2, tuple)189 assert issubclass(MyRecord3, tuple)190 assert issubclass(MyRecord33, tuple)191 assert issubclass(MyRecord345, tuple)192 assert issubclass(MyRecord4, tuple)193 assert issubclass(MyRecord5, tuple)194 assert issubclass(MyRecord6, tuple)195 # Named tuple classes created with namedtuple() factory function196 # (in the "traditional" way) are registered as "virtual" subclasses197 # of namedtuple.abc:198 MyTuple = namedtuple('MyTuple', 'a b c')199 mt = MyTuple(1, 2, 3)200 assert issubclass(MyTuple, namedtuple.abc)...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!