AttributeError with objects


test_attribute_error_w_variables and test_attribute_error_w_functions show that variables and functions in a module are attributes of the module.

Is an object in a module also an attribute of the module?

preview

I have these tests by the end of the chapter


open the project

  • I open a terminal

  • I change directory to the attribute_error folder in the pumping_python folder

    terminal
    cd attribute_error
    
  • I open test_attribute_error.py from the tests folder

  • I use pytest-watcher to run the tests automatically

    terminal
    uv run pytest-watcher . --now --patterns "**/*.py"
    

    the terminal is my friend, and shows

    tests/test_attribute_error.py ..                  [100%]
    
    ================== 2 passed in D.EFs ===================
    

test_attribute_error_w_object_attributes

RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a test for object attributes to tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.attribute_error'
                    has no attribute 'AnObject'
    

GREEN: make it pass


  • I open __init__.py from the attribute_error folder in the src folder

  • I add a function to src/attribute_error/__init__.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'function' object
                    has no attribute 'attribute_00'
    
  • I add a variable for attribute_00 to the function

    the terminal still shows the same Exception because I cannot get to a variable inside a function from outside the function. The variable is only used inside the function when it runs.

  • I change AnObject from a function to an object

    the terminal is my friend, and shows SyntaxError

    E    return function_09()
    E    ^^^^^^^^^^^^^^^^^^^^
    E  SyntaxError: 'return' outside function
    

    because I cannot use a return statement outside a function.

  • I add SyntaxError to the list of Exceptions seen, in tests/test_attribute_error.py

  • I comment out the return statement from AnObject in src/attribute_error/__init__.py

    • the test passes because attribute_00 is now an attribute/property of the AnObject object

    • AnObject is an attribute of the attribute_error module in the src folder

    • I can use attribute_00 from outside the file with src.attribute_error.AnObject.attribute_00 or src.attribute_error.AnObject().attribute_00

      src.attribute_error.AnObject.attribute_00
      src.attribute_error.AnObject().attribute_00
      └── src/
          └── attribute_error/
              └── __init__.py
                  └── class AnObject(object):
                      └── attribute_00 = function_09()
      

REFACTOR: make it better


  • I remove the commented lines

  • I add a line for src.attribute_error.AnObject().attribute_01 to tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'attribute_01'.
                    Did you mean: 'attribute_00'?
    
  • I add attribute_01 to the object definition in src/attribute_error/__init__.py

    • the test passes because in this case it does not matter if I use the object (AnObject) or an instance of the class (AnObject()).

    • attribute_01 is now an attribute of AnObject in src/attribute_error/__init__.py, and I can use it from outside the file with src.attribute_error.AnObject.attribute_01 or src.attribute_error.AnObject().attribute_01

      src.attribute_error.AnObject.attribute_01
      src.attribute_error.AnObject().attribute_01
      └── src/
          └── attribute_error/
              └── __init__.py
                  └── class AnObject(object):
                      └── attribute_01 = attribute_00
      
  • I add a line for src.attribute_error.AnObject.attribute_02 to tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: type object 'AnObject'
                    has no attribute 'attribute_02'.
                    Did you mean: 'attribute_00'?
    
  • I add attribute_02 to the object definition in src/attribute_error/__init__.py

    the test passes because attribute_02 is now an attribute of AnObject in src/attribute_error/__init__.py, and I can use it from outside the file with src.attribute_error.AnObject.attribute_02 or src.attribute_error.AnObject().attribute_02

    src.attribute_error.AnObject.attribute_02
    src.attribute_error.AnObject().attribute_02
    └── src/
        └── attribute_error/
            └── __init__.py
                └── class AnObject(object):
                    └── attribute_02 = attribute_01
    
  • I add a line for src.attribute_error.AnObject().attribute_03 to tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'attribute_03'.
                    Did you mean: 'attribute_00'?
    
  • I add attribute_03 to the object definition in src/attribute_error/__init__.py

    the test passes because attribute_03 is now an attribute of AnObject in src/attribute_error/__init__.py, and I can use it from outside the file with src.attribute_error.AnObject.attribute_03 or src.attribute_error.AnObject().attribute_03

    src.attribute_error.AnObject.attribute_03
    src.attribute_error.AnObject().attribute_03
    └── src/
        └── attribute_error/
            └── __init__.py
                └── class AnObject(object):
                    └── attribute_03 = attribute_02
    
  • I add a line for src.attribute_error.AnObject.attribute_04 to tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: type object 'AnObject'
                    has no attribute 'attribute_04'.
                    Did you mean: 'attribute_00'?
    
  • I add attribute_04 to the object definition in src/attribute_error/__init__.py

    the test passes because attribute_04 is now an attribute of AnObject in src/attribute_error/__init__.py, and I can use it from outside the file with src.attribute_error.AnObject.attribute_04 or src.attribute_error.AnObject().attribute_04

    src.attribute_error.AnObject.attribute_04
    src.attribute_error.AnObject().attribute_04
    └── src/
        └── attribute_error/
            └── __init__.py
                └── class AnObject(object):
                    └── attribute_04 = attribute_03
    
  • I add a line for src.attribute_error.AnObject().attribute_05 to tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'attribute_05'.
                    Did you mean: 'attribute_00'?
    
  • I add attribute_05 to the object definition in src/attribute_error/__init__.py

    the test passes because attribute_05 is now an attribute of AnObject in src/attribute_error/__init__.py, and I can use it from outside the file with src.attribute_error.AnObject.attribute_05 or src.attribute_error.AnObject().attribute_05

    src.attribute_error.AnObject.attribute_05
    src.attribute_error.AnObject().attribute_05
    └── src/
        └── attribute_error/
            └── __init__.py
                └── class AnObject(object):
                    └── attribute_05 = attribute_04
    
  • I add a line for src.attribute_error.AnObject().attribute_06 to tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'attribute_06'.
                    Did you mean: 'attribute_00'?
    
  • I add attribute_06 to the object definition in src/attribute_error/__init__.py

    the test passes because attribute_06 is now an attribute of AnObject in src/attribute_error/__init__.py, and I can use it from outside the file with src.attribute_error.AnObject.attribute_06 or src.attribute_error.AnObject().attribute_06

    src.attribute_error.AnObject.attribute_06
    src.attribute_error.AnObject().attribute_06
    └── src/
        └── attribute_error/
            └── __init__.py
                └── class AnObject(object):
                    └── attribute_06 = attribute_05
    
  • I add a line for src.attribute_error.AnObject.attribute_07 to tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: type object 'AnObject'
                    has no attribute 'attribute_07'.
                    Did you mean: 'attribute_00'?
    
  • I add attribute_07 to the object definition in src/attribute_error/__init__.py

    the test passes because attribute_07 is now an attribute of AnObject in src/attribute_error/__init__.py, and I can use it from outside the file with src.attribute_error.AnObject.attribute_07 or src.attribute_error.AnObject().attribute_07

    src.attribute_error.AnObject.attribute_07
    src.attribute_error.AnObject().attribute_07
    └── src/
        └── attribute_error/
            └── __init__.py
                └── class AnObject(object):
                    └── attribute_07 = attribute_06
    
  • I add a line for src.attribute_error.AnObject.attribute_08 to tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: type object 'AnObject'
                    has no attribute 'attribute_08'.
                    Did you mean: 'attribute_00'?
    
  • I add attribute_08 to the object definition in src/attribute_error/__init__.py

    the test passes because attribute_08 is now an attribute of AnObject in src/attribute_error/__init__.py, and I can use it from outside the file with src.attribute_error.AnObject.attribute_08 or src.attribute_error.AnObject().attribute_08

    src.attribute_error.AnObject.attribute_08
    src.attribute_error.AnObject().attribute_08
    └── src/
        └── attribute_error/
            └── __init__.py
                └── class AnObject(object):
                    └── attribute_08 = attribute_07
    
  • I add a line for src.attribute_error.AnObject().attribute_09 to tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'attribute_09'.
                    Did you mean: 'attribute_00'?
    
  • I add attribute_09 to the object definition in src/attribute_error/__init__.py

    the test passes because attribute_09 is now an attribute of AnObject in src/attribute_error/__init__.py, and I can use it from outside the file with src.attribute_error.AnObject.attribute_09 or src.attribute_error.AnObject().attribute_09

    src.attribute_error.AnObject.attribute_09
    src.attribute_error.AnObject().attribute_09
    └── src/
        └── attribute_error/
            └── __init__.py
                └── class AnObject(object):
                    └── attribute_09 = attribute_08
    
  • I add a git commit message in the other terminal

    terminal
    git commit -am \
    'add test_attribute_error_w_object_attributes'
    
  • A variable in an object is an attribute of the class

  • An object in a module is an attribute of the module

  • A function in a module is an attribute of the module

  • A variable in a module is an attribute of the module


test_attribute_error_w_object_methods

The tests show that variables, functions and objects in a module are attributes of the module, and variables in an object are attributes of the class.

Methods of a class are also attributes of the class.


RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a test for methods to tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

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

GREEN: make it pass


  • I add the name to AnObject and point it to attribute_09, in src/attribute_error/__init__.py

    the terminal is my friend, and shows TypeError

    TypeError: 'NoneType' object is not callable
    

    because method_00 is attribute_09, attribute_09 is None, and I cannot call None like a function.

  • I use the def keyword to change it from a variable (attribute) to a method

    the terminal is my friend, and shows NameError

    NameError: name 'attribute_09' is not defined
    

    because there is nothing inside method_00 named attribute_09 and it cannot get to attribute_09 of AnObject, yet.

  • I add self. before the name to reference the object attribute

    the terminal is my friend, and shows NameError

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

    the terminal is my friend, and shows TypeError

    TypeError: AnObject.method_00() missing
               1 required positional argument: 'self'
    

    because I called the method with the object not an instance of the class.

  • I use an instance of the class to call the method in tests/test_attribute_error.py

    src.attribute_error.AnObject().method_00
    └── src/
        └── attribute_error/
            └── __init__.py
                └── class AnObject(object):
                    └── def method_00(self):
                        └── return self.attribute_09
    

REFACTOR: make it better


  • I remove the commented lines from src/attribute_error/__init__.py

  • I remove the commented line from tests/test_attribute_error.py

  • You know the “drill”, I add a call to src.attribute_error.AnObject().method_01

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'method_01'.
                    Did you mean: 'method_00'?
    
  • I add the method to the definition of AnObject in src/attribute_error/__init__.py

    the test passes because method_01 is now an attribute of AnObject in src/attribute_error/__init__.py, and I can call it from outside the file with src.attribute_error.AnObject().method_01()

    src.attribute_error.AnObject().method_01
    └── src/
        └── attribute_error/
            └── __init__.py
                └── class AnObject(object):
                    └── def method_01(self):
                        └── return self.method_00()
    
  • I add a call to src.attribute_error.AnObject().method_02 from tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'method_02'.
                    Did you mean: 'method_00'?
    
  • I add the method to the definition of AnObject in src/attribute_error/__init__.py

    the test passes because method_02 is now an attribute of AnObject in src/attribute_error/__init__.py, and I can call it from outside the file with src.attribute_error.AnObject().method_02()

    src.attribute_error.AnObject().method_02
    └── src/
        └── attribute_error/
            └── __init__.py
                └── class AnObject(object):
                    └── def method_02(self):
                        └── return self.method_01()
    
  • I add a call to src.attribute_error.AnObject().method_03 from tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'method_03'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_03 to the definition of AnObject in src/attribute_error/__init__.py

    the test passes because method_03 is now an attribute of AnObject in src/attribute_error/__init__.py, and I can call it from outside the file with src.attribute_error.AnObject().method_03()

    src.attribute_error.AnObject().method_03
    └── src/
        └── attribute_error/
            └── __init__.py
                └── class AnObject(object):
                    └── def method_03(self):
                        └── return self.method_02()
    
  • I add a call to src.attribute_error.AnObject().method_04 from tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'method_04'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_04 to the definition of AnObject in src/attribute_error/__init__.py

    the test passes because method_04 is now an attribute of AnObject in src/attribute_error/__init__.py, and I can call it from outside the file with src.attribute_error.AnObject().method_04()

    src.attribute_error.AnObject().method_04
    └── src/
        └── attribute_error/
            └── __init__.py
                └── class AnObject(object):
                    └── def method_04(self): return self.method_03()
    
  • I add a call to src.attribute_error.AnObject().method_05 from tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'method_05'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_05 to the definition of AnObject in src/attribute_error/__init__.py

    the test passes.

  • I add a call to src.attribute_error.AnObject().method_06 from tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'method_06'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_06 to the definition of AnObject in src/attribute_error/__init__.py

    the test passes.

  • I add a call to src.attribute_error.AnObject().method_07 from tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'method_07'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_07 to the definition of AnObject in src/attribute_error/__init__.py

    the test passes.

  • I add a call to src.attribute_error.AnObject().method_08 from tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'method_08'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_08 to the definition of AnObject in src/attribute_error/__init__.py

    the test passes.

  • I add a call to src.attribute_error.AnObject().method_09 from tests/test_attribute_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'method_09'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_09 to the definition of AnObject in src/attribute_error/__init__.py

    the test passes because method_09 is now an attribute of AnObject in src/attribute_error/__init__.py, and I can call it from outside the file with src.attribute_error.AnObject().method_09()

    src.attribute_error.AnObject().method_09
    └── src/
        └── attribute_error/
            └── __init__.py
                └── class AnObject(object):
                    └── def method_09(self):
                        └── return self.method_08()
    
  • I add a git commit message in the other terminal

    terminal
    git commit -am \
    'add test_attribute_error_w_object_methods'
    

A function in an object is an attribute of the class and is called a method


close the project

  • I close src/attribute_error/__init__.py and tests/test_attribute_error.py

  • I click in the terminal where the tests are running

  • I use q on the keyboard to leave the tests. The terminal goes back to the command line.

  • I change directory to the parent of attribute_error

    terminal
    cd ..
    

    the terminal shows

    .../pumping_python
    

    I am back in the pumping_python directory.


review

All the tests I have run for AttributeError show that

I still have the problem that the tests all show the correct way to use attributes I made in src/attribute_error/__init__.py. If someone reads the file or runs it, there is no way for them to know how the code relates to AttributeError unless they go through the process with me, there has to be a better way.


code from the chapter

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


what is next?

Would you like to test TypeError with objects?


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.