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!!
