TypeError with classes


Since methods are functions in a class I can assume that they have the same behavior as what I tested in test_type_error_w_positional_arguments, test_type_error_w_keyword_arguments and test_type_error_w_args_and_kwargs.

The difference is that how I call a method is affected by if I do it with a class or an instance.


preview

I have these tests by the end of the chapter

  1import src.type_error
  2
  3
  4def test_type_error_w_positional_arguments():
  5    src.type_error.function_00('a')
  6    src.type_error.function_01('a', 'b')
  7    src.type_error.function_02('a', 'b', 'c')
  8    src.type_error.function_03('a', 'b', 'c', 'd')
  9    src.type_error.function_04('a')
 10    src.type_error.function_05('a', 'b')
 11    src.type_error.function_06('a', 'b', 'c')
 12    src.type_error.function_07('a', 'b', 'c', 'd')
 13    src.type_error.function_08('last', 'one')
 14
 15
 16def test_type_error_w_keyword_arguments():
 17    src.type_error.function_00(the_input=0)
 18    src.type_error.function_01(
 19        first='first',
 20        second={'key': 'value'},
 21    )
 22    src.type_error.function_02(
 23        third=(0, 1, 2, 'n'),
 24        second=[0, 1, 2, 'n'],
 25        first={0, 1, 2, 'n'},
 26    )
 27    src.type_error.function_03(
 28        first=None,
 29        second=False,
 30        third=True,
 31        fourth=4,
 32    )
 33    src.type_error.function_04(argument='value')
 34    src.type_error.function_05(
 35        argument_0='value1',
 36        argument_1=(0, 1, 2, 'n'),
 37    )
 38    src.type_error.function_06(
 39        argument_0='value1',
 40        argument_1=(0, 1, 2, 'n'),
 41        argument_2=[0, 1, 2, 'n'],
 42    )
 43    src.type_error.function_07(
 44        argument_0=(0, 1, 2, 'n'),
 45        argument_1=[0, 1, 2, 'n'],
 46        argument_2={0, 1, 2, 'n'},
 47        argument_n={'key': 'value'},
 48    )
 49    src.type_error.function_08(
 50        argument='positional', name='keyword'
 51    )
 52
 53
 54def test_type_error_w_args_and_kwargs():
 55    src.type_error.function_00('argument')
 56    src.type_error.function_01(1, 0)
 57    src.type_error.function_02(
 58        third=True, second=False, first=None
 59    )
 60    src.type_error.function_03(
 61        second=[0, 1, 2, 'n'],
 62        first=(0, 1, 2, 'n'),
 63        third={0, 1, 2, 'n'},
 64        fourth={'key': 'value'}
 65    )
 66    src.type_error.function_04('value')
 67    src.type_error.function_05(
 68        (0, 1, 2, 'n'),
 69        [0, 1, 2, 'n'],
 70    )
 71    src.type_error.function_06(
 72        (0, 1, 2, 'n'),
 73        [0, 1, 2, 'n'],
 74        argument_2={0, 1, 2, 'n'},
 75    )
 76    src.type_error.function_07(
 77        argument_n={'key': 'value'},
 78        argument_2={0, 1, 2, 'n'},
 79        argument_0=(0, 1, 2, 'n'),
 80        argument_1=[0, 1, 2, 'n'],
 81    )
 82    src.type_error.function_08(
 83        'positional', argument='keyword'
 84    )
 85
 86
 87def test_type_error_w_class_methods():
 88    src.type_error.AClass.method_00()
 89    src.type_error.AClass().method_01()
 90    src.type_error.AClass().method_02()
 91    src.type_error.AClass.method_03()
 92    src.type_error.AClass.method_04()
 93    src.type_error.AClass().method_05()
 94    src.type_error.AClass().method_06()
 95    src.type_error.AClass().method_07()
 96    src.type_error.AClass().method_08()
 97    src.type_error.AClass().method_09()
 98
 99
100# Exceptions seen
101# AssertionError
102# NameError
103# TypeError
104# ModuleNotFoundError
105# AttributeError

open the project


test_type_error_w_class_methods

RED: make it fail


I add a test with a call to AClass.method from test_type_error.py

82    src.type_error.function_08(
83        'positional', argument='keyword'
84    )
85
86
87def test_type_error_w_class_methods():
88    src.type_error.AClass.method_00()
89
90
91# Exceptions seen

the terminal is my friend, and shows AttributeError

AttributeError: module 'src.type_error'
                has no attribute 'AClass'

because AClass is not defined in type_error.py.


GREEN: make it pass


  • I open type_error.py

  • I add a class definition for AClass to type_error.py

    40def function_08(name, argument):
    41    return None
    42
    43
    44class AClass(object):
    45
    46    pass
    

    the terminal is my friend, and shows AttributeError

    AttributeError: type object 'AClass' has no attribute 'method_00'
    

    because there is nothing named method_00 in AClass.

  • I add the name to the class definition

    44class AClass(object):
    45
    46    # pass
    47    method_00
    

    the terminal is my friend, and shows NameError

    NameError: name 'method_00' is not defined
    
  • I define method_00 by pointing it to None

    44class AClass(object):
    45
    46    # pass
    47    # method_00
    48    method_00 = None
    

    the terminal is my friend, and shows TypeError

    TypeError: 'NoneType' object is not callable
    

    because method_00 points to None and I cannot call None like a function.

  • I change method_00 to a method

    44class AClass(object):
    45
    46    # pass
    47    # method_00
    48    # method_00 = None
    49    def method_00(): return None
    

    the test passes.


REFACTOR: make it better


  • I remove the commented lines

    44class AClass(object):
    45
    46    def method_00(): return None
    
  • I add a call to src.type_error.AClass().method_01 from test_type_error.py

    87def test_type_error_w_class_methods():
    88    src.type_error.AClass.method_00()
    89    src.type_error.AClass().method_01()
    90
    91
    92# Exceptions seen
    

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AClass' object
                    has no attribute 'method_01'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_01 to AClass in type_error.py

    44class AClass(object):
    45
    46    def method_00(): return None
    47    def method_01(): return None
    

    the terminal is my friend, and shows TypeError

    TypeError: AClass.method_01() takes
               0 positional arguments but 1 was given
    

    because a method of an instance takes the instance of the class (self) it belongs to as the first argument.

  • I add @staticmethod to method_01

    class AClass(object):
    
        def method_00(): return None
    
        @staticmethod
        def method_01(): return None
    

    the test passes because I can use the staticmethod decorator if I do not want to add self to the method definition when it does not use anything in the class.

    Both methods look the same. The difference is in how I call them AClass.method_00() vs AClass().method_01().

  • I add a call to src.type_error.AClass().method_02 from test_type_error.py

    87def test_type_error_w_class_methods():
    88    src.type_error.AClass.method_00()
    89    src.type_error.AClass().method_01()
    90    src.type_error.AClass().method_02()
    91
    92
    93# Exceptions seen
    

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AClass' object
                    has no attribute 'method_02'.
                    Did you mean: 'method_00'?
    
  • I add a definition for method_02 to AClass in type_error.py

    44class AClass(object):
    45
    46    def method_00(): return None
    47
    48    @staticmethod
    49    def method_01(): return None
    50
    51    def method_02(): return self.method_01()
    

    the terminal is my friend, and shows TypeError

    TypeError: AClass.method_02() takes
               0 positional arguments but 1 was given
    

    because a method of an instance takes the instance of the class (self) it belongs to as the first argument.

  • I add @staticmethod to method_02

    48    @staticmethod
    49    def method_01(): return None
    50
    51    @staticmethod
    52    def method_02(): return self.method_01()
    

    the terminal is my friend, and shows NameError

    NameError: name 'self' is not defined
    
  • I add self to the parentheses of method_02

    51    @staticmethod
    52    # def method_02(): return self.method_01()
    53    def method_02(self):
    54        return self.method_01()
    

    the terminal is my friend, and shows TypeError

    TypeError: AClass.method_02() missing
               1 required positional argument: 'self'
    
  • I comment out the staticmethod decorator

    51    # @staticmethod
    52    # def method_02(): return self.method_01()
    53    def method_02(self):
    54        return self.method_01()
    

    the test passes because a method of an instance takes the instance of the class (self) it belongs to as the first argument which allows it to use things that belong to the class.

  • I add a call to src.type_error.AClass.method_03 from test_type_error.py

    87def test_type_error_w_class_methods():
    88    src.type_error.AClass.method_00()
    89    src.type_error.AClass().method_01()
    90    src.type_error.AClass().method_02()
    91    src.type_error.AClass.method_03()
    92
    93
    94# Exceptions seen
    

    the terminal is my friend, and shows AttributeError

    AttributeError: type object 'AClass'
                    has no attribute 'method_03'.
                    Did you mean: 'method_00'?
    
  • I add a definition for method_03 to AClass in type_error.py

    51    # @staticmethod
    52    # def method_02(): return self.method_01()
    53    def method_02(self):
    54        return self.method_01()
    55
    56    def method_03():
    57        return method_02()
    

    the terminal is my friend, and shows NameError

    NameError: name 'method_02' is not defined
    
  • I add AClass. before method_02

    56    def method_03():
    57        # return method_02()
    58        return AClass.method_02()
    

    the terminal is my friend, and shows TypeError

    TypeError: AClass.method_02() missing
               1 required positional argument: 'self'
    

    because

  • I use an instance of the class to call the method

    56    def method_03():
    57        # return method_02()
    58        # return AClass.method_02()
    59        return AClass().method_02()
    

    the test passes. This is a silly example because I used AClass() inside a method of AClass. I could just use self. I would only need this if I was calling a method of a different class.

  • Here is another silly example. I add a call to src.type_error.AClass.method_04 from test_type_error.py

    87def test_type_error_w_class_methods():
    88    src.type_error.AClass.method_00()
    89    src.type_error.AClass().method_01()
    90    src.type_error.AClass().method_02()
    91    src.type_error.AClass.method_03()
    92    src.type_error.AClass.method_04()
    93
    94
    95# Exceptions seen
    

    the terminal is my friend, and shows AttributeError

    AttributeError: type object 'AClass'
                    has no attribute 'method_04'.
                    Did you mean: 'method_00'?
    
  • I add method definition for method_04 to AClass in type_error.py

    56    def method_03():
    57        # return method_02()
    58        # return AClass.method_02()
    59        return AClass().method_02()
    60
    61    def method_04():
    62        return AClass.method_02()
    

    the terminal is my friend, and shows TypeError

    TypeError: AClass.method_02() missing
               1 required positional argument: 'self
    

    because

  • I pass AClass as input in the call to method_02

    61    def method_04():
    62        # return AClass.method_02()
    63        return AClass.method_02(AClass)
    

    the test passes. I called a method of AClass and passed AClass as input. I can use self.

  • I add a call to src.type_error.AClass().method_05 from test_type_error.py

    87def test_type_error_w_class_methods():
    88    src.type_error.AClass.method_00()
    89    src.type_error.AClass().method_01()
    90    src.type_error.AClass().method_02()
    91    src.type_error.AClass.method_03()
    92    src.type_error.AClass.method_04()
    93    src.type_error.AClass().method_05()
    94
    95
    96# Exceptions seen
    

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AClass' object
                    has no attribute 'method_05'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_05 to AClass in type_error.py

    61    def method_04():
    62        # return AClass.method_02()
    63        return AClass.method_02(AClass)
    64
    65    def method_05():
    66        return method_02()
    

    because a method of an instance takes the instance of the class (self) it belongs to as the first argument.

  • I add self to the parentheses of method_05

    65    # def method_05():
    66    def method_05(self):
    67        return method_02()
    

    the terminal is my friend, and shows NameError

    NameError: name 'method_02' is not defined
    
  • I add self. before method_02

    65    # def method_05():
    66    def method_05(self):
    67        # return method_02()
    68        return self.method_02()
    

    the test passes.

  • I add a call to src.type_error.AClass().method_06 from test_type_error.py

    87def test_type_error_w_class_methods():
    88    src.type_error.AClass.method_00()
    89    src.type_error.AClass().method_01()
    90    src.type_error.AClass().method_02()
    91    src.type_error.AClass.method_03()
    92    src.type_error.AClass.method_04()
    93    src.type_error.AClass().method_05()
    94    src.type_error.AClass().method_06()
    95
    96
    97# Exceptions seen
    

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AClass' object
                    has no attribute 'method_06'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_06 to AClass

    65    # def method_05():
    66    def method_05(self):
    67        # return method_02()
    68        return self.method_02()
    69
    70    def method_06():
    71        return self.method_01()
    

    the terminal is my friend, and shows TypeError

    TypeError: AClass.method_06() takes
               0 positional arguments but 1 was given
    

    because a method of an instance takes the instance of the class (self) it belongs to as the first argument.

  • I add self to the parentheses of method_06

    70    # def method_06():
    71    def method_06(self):
    72        return self.method_01()
    

    the test passes.

  • I add a call to src.type_error.AClass().method_07 from test_type_error.py

    87def test_type_error_w_class_methods():
    88    src.type_error.AClass.method_00()
    89    src.type_error.AClass().method_01()
    90    src.type_error.AClass().method_02()
    91    src.type_error.AClass.method_03()
    92    src.type_error.AClass.method_04()
    93    src.type_error.AClass().method_05()
    94    src.type_error.AClass().method_06()
    95    src.type_error.AClass.method_07()
    96
    97
    98# Exceptions seen
    

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AClass' object
                    has no attribute 'method_07'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_07 to AClass in type_error.py

    70    # def method_06():
    71    def method_06(self):
    72        return self.method_01()
    73
    74    def method_07(self):
    75        return self.method_00()
    

    the terminal is my friend, and shows TypeError

    TypeError: AClass.method_07() missing
               1 required positional argument: 'self'
    

    because

  • I use an instance of the class to call the method from test_type_error.py

    87def test_type_error_w_class_methods():
    88    src.type_error.AClass.method_00()
    89    src.type_error.AClass().method_01()
    90    src.type_error.AClass().method_02()
    91    src.type_error.AClass.method_03()
    92    src.type_error.AClass.method_04()
    93    src.type_error.AClass().method_05()
    94    src.type_error.AClass().method_06()
    95    # src.type_error.AClass.method_07()
    96    src.type_error.AClass().method_07()
    97
    98
    99# Exceptions seen
    

    the terminal is my friend, and shows TypeError

    TypeError: AClass.method_00() takes
               0 positional arguments but 1 was given
    

    because

  • I add the staticmethod decorator to method_00 of AClass in type_error.py

    44class AClass(object):
    45
    46    @staticmethod
    47    def method_00(): return None
    

    the test passes. I can use the staticmethod decorator if I do not want to add self to the method definition when it does not use anything in the class.

  • I add a call to src.type_error.AClass.method_08() from test_type_error.py

     87def test_type_error_w_class_methods():
     88    src.type_error.AClass.method_00()
     89    src.type_error.AClass().method_01()
     90    src.type_error.AClass().method_02()
     91    src.type_error.AClass.method_03()
     92    src.type_error.AClass.method_04()
     93    src.type_error.AClass().method_05()
     94    src.type_error.AClass().method_06()
     95    # src.type_error.AClass.method_07()
     96    src.type_error.AClass().method_07()
     97    src.type_error.AClass.method_08()
     98
     99
    100# Exceptions seen
    

    the terminal is my friend, and shows AttributeError

    AttributeError: type object 'AClass'
                    has no attribute 'method_08'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_08 to AClass in type_error.py

    75    def method_07(self):
    76        return self.method_00()
    77
    78    def method_08(self):
    79        return self.method_04()
    

    the terminal is my friend, and shows TypeError

    TypeError: AClass.method_08() missing
               1 required positional argument: 'self'
    

    because I called method_08 like a staticmethod and it is defined as an instance method (It expects self as input).

  • I use an instance of the class to call the method from test_type_error.py

     87def test_type_error_w_class_methods():
     88    src.type_error.AClass.method_00()
     89    src.type_error.AClass().method_01()
     90    src.type_error.AClass().method_02()
     91    src.type_error.AClass.method_03()
     92    src.type_error.AClass.method_04()
     93    src.type_error.AClass().method_05()
     94    src.type_error.AClass().method_06()
     95    # src.type_error.AClass.method_07()
     96    src.type_error.AClass().method_07()
     97    # src.type_error.AClass.method_08()
     98    src.type_error.AClass().method_08()
     99
    100
    101# Exceptions seen
    

    the terminal shows TypeError

    TypeError: AClass.method_04() takes
               0 positional arguments but 1 was given
    

    because

  • I add the staticmethod decorator to method_04 of AClass in type_error.py

    57    def method_03():
    58        # return method_02()
    59        # return AClass.method_02()
    60        return AClass().method_02()
    61
    62    @staticmethod
    63    def method_04():
    64        # return AClass.method_02()
    65        return AClass.method_02(AClass)
    66
    67    # def method_05():
    68    def method_05(self):
    69        # return method_02()
    70        return self.method_02()
    

    the test passes.

  • I add a call to src.type_error.AClass.method_09() from test_type_error.py

     87def test_type_error_w_class_methods():
     88    src.type_error.AClass.method_00()
     89    src.type_error.AClass().method_01()
     90    src.type_error.AClass().method_02()
     91    src.type_error.AClass.method_03()
     92    src.type_error.AClass.method_04()
     93    src.type_error.AClass().method_05()
     94    src.type_error.AClass().method_06()
     95    # src.type_error.AClass.method_07()
     96    src.type_error.AClass().method_07()
     97    # src.type_error.AClass.method_08()
     98    src.type_error.AClass().method_08()
     99    src.type_error.AClass().method_09()
    100
    101
    102# Exceptions seen
    

    the terminal is my friend, and shows AttributeError

    AttributeError: type object 'AClass'
                    has no attribute 'method_09'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_09 to AClass in type_error.py

    79    def method_08(self):
    80        return self.method_04()
    81
    82    def method_09(self):
    83        return self.method_03()
    

    the terminal is my friend, and shows TypeError

    TypeError: AClass.method_03() takes
               0 positional arguments but 1 was given
    

    because

  • I add the @staticmethod to method_03 of AClass in type_error.py

    52    # @staticmethod
    53    # def method_02(): return self.method_01()
    54    def method_02(self):
    55        return self.method_01()
    56
    57    @staticmethod
    58    def method_03():
    59        # return method_02()
    60        # return AClass.method_02()
    61        return AClass().method_02()
    62
    63    @staticmethod
    64    def method_04():
    65        # return AClass.method_02()
    66        return AClass.method_02(AClass)
    

    the test passes.

  • I remove the commented lines from type_error.py

    44class AClass(object):
    45
    46    @staticmethod
    47    def method_00(): return None
    48
    49    @staticmethod
    50    def method_01(): return None
    51
    52    def method_02(self):
    53        return self.method_01()
    54
    55    @staticmethod
    56    def method_03():
    57        return AClass().method_02()
    58
    59    @staticmethod
    60    def method_04():
    61        return AClass.method_02(AClass)
    62
    63    def method_05(self):
    64        return self.method_02()
    65
    66    def method_06(self):
    67        return self.method_01()
    68
    69    def method_07(self):
    70        return self.method_00()
    71
    72    def method_08(self):
    73        return self.method_04()
    74
    75    def method_09(self):
    76        return self.method_03()
    
  • I remove the commented lines from test_type_error.py

     87def test_type_error_w_class_methods():
     88    src.type_error.AClass.method_00()
     89    src.type_error.AClass().method_01()
     90    src.type_error.AClass().method_02()
     91    src.type_error.AClass.method_03()
     92    src.type_error.AClass.method_04()
     93    src.type_error.AClass().method_05()
     94    src.type_error.AClass().method_06()
     95    src.type_error.AClass().method_07()
     96    src.type_error.AClass().method_08()
     97    src.type_error.AClass().method_09()
     98
     99
    100# Exceptions seen
    101# AssertionError
    102# NameError
    103# TypeError
    104# ModuleNotFoundError
    105# AttributeError
    
  • I open a new terminal then make sure I am in the type_error folder

    cd type_error
    
  • I add a git commit message in the other terminal

    git commit --all --message \
    'add test_type_error_w_class_methods'
    

review

The tests show that

All the tests so far show that I get TypeError when I call a function/method in a way that is different from its definition.


code from the chapter

Do you want to see all the CODE I typed in this chapter?


what is next?

so far you know

Would you like to see another way to write tests?


rate pumping python

If this has been a 7 star experience for you, please CLICK HERE to leave a 5 star review of pumping python. It helps other people get into the book too.