CannotChainAttributeAccesses
Observed

CannotChainAttributeAccesses
Incorrect

Attribute accesses cannot be chained together

Correct

Attribute accesses can be chained together

Correction
Here is what's right.

class C:
    def work(self):
        pass

def m():
    return C()

The following two code snippets both invoke a function m() and then invoke the method work() on the object returned by m():

o = m()
o.work()
m().work()

Here we see the corresponding expressions trees (first example on the left, second one on the right):

The expression m() evaluates to an object of type C, and it is perfectly legal to invoke a method on that object.

It’s equally valid to access any attribute on such an object:

m().attr = 19

This writes 19 to the attr attribute of the object returned by m().

Origin
Where could this misconception come from?

Students may believe that there cannot be a non-atomic expression on the left side of the dot. They may have encountered attribute accesses and method invocations in only a limited number of forms, such as:

variable.attr = 19
self.attr = 19

variable.method()
self.method()

Symptoms
How do you know your students might have this misconception?

Students only use atomic expressions on the left side of the dot in attribute accesses and method invocations. If necessary, they break down more complex expressions into multiple statements, each with a single atomic expression on the left side of the dot.

They may always write code like:

o2 = o1.attr
o2.m()

even when o2 is not needed elsewhere, instead of chaining the attribute access and method invocation together:

o1.attr.m()