python-adminui icon indicating copy to clipboard operation
python-adminui copied to clipboard

How to use multiple source files when constructing the Web app to avoid circular includes

Open jwag59 opened this issue 3 years ago • 5 comments

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?

jwag59 avatar Jun 03 '22 11:06 jwag59

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:

  1. you may pass app to other files in your project as a parameter;
  2. you may use from __main__ import app or other ways to import the app

bigeyex avatar Jun 04 '22 04:06 bigeyex

by the way, I'm considering adding some universal mechanism, to make simple projects simpler.

bigeyex avatar Jun 05 '22 05:06 bigeyex

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.

jwag59 avatar Jun 06 '22 07:06 jwag59

I've been using the new shared app feature and all seems to be working very well ... thank-you.

jwag59 avatar Jun 09 '22 07:06 jwag59

You can close this issue!!

jwag59 avatar Jun 26 '22 08:06 jwag59