python-adminui
python-adminui copied to clipboard
How to use multiple source files when constructing the Web app to avoid circular includes
I have been constructing my app quite happily using multiple source files, one per view. The directory layout is:
[root@fxhead adminui]# tree -L 2
.
├── app.py
├── config.py
├── data
│ ├── __pycache__
│ └── table_data.py
├── db_calls.py
├── pages
│ ├── about.py
│ ├── bmcs.py
│ ├── cluster_stats.py
│ ├── dashboard.py
│ ├── firmware.py
│ ├── nodegroups.py
│ ├── nodes.py
│ ├── __pycache__
│ ├── racks.py
│ ├── repos.py
│ └── submit_job.py
├── requirements.txt
├── static
│ ├── favicon.ico
│ ├── logo.png
└── upload
In this case my app.py includes the definitions for each page/view such as:
.
from pages.firmware import fwlist_layout
.
@app.page('/bmcs/fws', 'Firmware')
def fws_view_page():
return fwlist_layout()
.
.
.
And then the fwlist_layout function is located in the pages/firmware.py source file.
Everything works fine unless I need to access the actual 'app' object (the AdminApp object) in one of the source files in the pages directory.
For example after using an Upload component, the upload itself works fine, I cannot access the app.uploaded_file_location function. If I use this without any includes I get a Python error that the app object has no attribute 'upload_file_location'.
print(app.uploaded_file_location(file))
AttributeError: module 'adminui.app' has no attribute 'uploaded_file_location'
Then when checking the app object in PyCharm for one of the source files in my pages/ directory, it does indeed look like the object available is not an initialized instance. At least uploaded_file_location and many other object attributes are not seen/available.
But whenever I use an import from the app.py into these files I get a circular includes. So when I try the following includes in the pages/firmware.py file:
from adminui import *
from app import app <--- this one added to try to get access to the 'app' object
I get the following error when I try to run the app:
[root@fxhead adminui]# ./app.py
Traceback (most recent call last):
File "./app.py", line 22, in <module>
from pages.firmware import fwlist_layout
File "/opt/adminui/pages/firmware.py", line 2, in <module>
from app import app
File "/opt/adminui/app.py", line 22, in <module>
from pages.firmware import fwlist_layout
ImportError: cannot import name 'fwlist_layout' from partially initialized module 'pages.firmware' (most likely due to a circular import) (/opt/adminui/pages/firmware.py)
[root@fxhead adminui]#
My skill level is not high enough to understand what is really going on here. My guess is that AdminApp is not meant to work with multiple source files as I've never had this issue with other projects I've worked on. (e.g. apps built with Flask).
Can you give me any clues how I can manage the imports so I can access the 'app' object in other source files without a circular import error?
Seemingly your fwlist_layout module did some initialization work when importing(this is quite uncommon in Python packages though). Try not to import it in the app.py directly. Aside from blueprints (which is a feature in Flask and not implemented in adminui), basically it's not quite different from Flask:
- you may pass app to other files in your project as a parameter;
- you may use
from __main__ import appor other ways to import the app
by the way, I'm considering adding some universal mechanism, to make simple projects simpler.
I don't do any special initialization in fwlist_layout. I simply call an SQL function to get some records from a DB and then create the layout and return it.
And BTW I cannot get from __main__ import app to work. The 'main' is not found. Therefore the only way so far I can get this to work is to pass 'app' as a parameter to the call to fwlist_layout and then assign it to a global variable in this function so I can use it in other functions in the same source module.
I've been using the new shared app feature and all seems to be working very well ... thank-you.
You can close this issue!!