ImportError: no module named foo; AttributeError: 'module' object has no attribute 'bar'

I’ve gone through https://anvil.works/docs/structuring-your-app/how-to-import-things and searched the forums but still just can’t work out how to effectively import ‘global’ objects from my top level HomePage. Here’s my app structure, rather thrown together without much planning

So in HomePage I have a variable green = '#5eb348' and in DeliveryRow for example I can successfully import this with from .. import green. (As someone said elsewhere, auto-complete is your friend with imports.)

My problem is with UserProfile however. It’s a module form but I’ve also tried switching it to a package form (I confess I’m vague on the differences and whether it even matters), and I’ve tried every combination I can think of as well as scouring the auto-complete suggestions… but just can’t get the reference right. For example:

import green
image
from . import green or from .. import green
image
from HomePage import green or from .HomePage import green
image

And curiously, even though auto-complete suggests from . import HomePage,


I still get an error:
image

I’m pulling my hair out here! Very grateful if someone can spot what I’m doing wrong, thanks very much…

This is likely to be a circular import

You are possibly doing something like:

Form A:

from ..FormB import foo

Form B:

from ..FormA import bar

or likewise

Form A:

from .. import FormB

Form B:

from .. import FormA

One option

you can move import statements into methods or classes to prevent them being circular

Form A:

from ..FormB import foo

Form B:

def some_method():
  from ..FormA import bar

# no longer a circular import :-)

or likewise

Form A:

from .. import FormB

Form B:

def some_method():
  from .. import FormA

# no longer a circular import :-)

Another option

(depending on the attribute you are importing - courtesy of @stefano.menci suggestion below)
You could abstract certain attributes into their own module

Globals (module)

foo = # some python object
bar = # some other python object

Form A:

from Globals import foo

Form B:

from Globals import bar
4 Likes

Try creating a module (not a form), call it for example globals.py, and create green and all the other globals in that module. Then every form will import globals or just from globals import green.

This will help you avoiding circular imports and make everything clearer.

3 Likes

Thanks @stucork - yes you’re right… My HomePage was importing UserSetup (so it could add it as a component when the UserSetp menu button is pressed). That obviously prevented me from re-importing from the HomePage.

I really like the simplicity of of @stefano.menci’s solution so will go for that!

PS I’ll scour the Docs and Forum again tomorrow but would be curious to know if there’s a recommended design pattern for the common layout where you have menu items/buttons on a top toolbar and want to dynamically load each page as a component below…