Python import from parent package - python

I'm having some trouble with imports in Python.
Here is a simple example of what's going wrong.
I have a directory structure like this:
app
|---__init__.py
|---sub_app
|---__init__.py
The code:
app/__init__.py
shared_data = {
'data': 123
}
from sub_app import more_shared_data
print more_shared_data
app/sub_app/__init__.py
more_shared_data = {
'data': '12345'
}
from app import shared_data
print shared_data
However I get the error:
ImportError: No module named app
How do I import the shared_data dict, into app/sub_app/__init__.py?

You can use relative imports for this . Example -
In your app/sub_app/__init__.py -
more_shared_data = {
'data': '12345'
}
from .. import shared_data
print shared_data
This should work for the simple example you have provided , but it does lead to circular import , app is importing sub_app and sub_app is importing app .
For more complex usecases, you can end up with errors (If you import sub_app) before defining specific elements, and then in sub_app/__init__.py you try to import app and use those elements that are only defined after the import statement for sub_app . A very simple example where it would cause issue -
app/__init__.py -
from .sub_app import more_shared_data
print(more_shared_data)
shared_data = {
'data': 123
}
app/sub_app/__init__.py -
more_shared_data = {
'data': '12345'
}
from .. import shared_data
print(shared_data)
Now, if you try to import app , you will get the error -
>>> import app
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<some file>\__init__.py", line 1, in <module>
from .shared import more_shared_data
File "<some file>\sub_app\__init__.py", line 4, in <module>
from .. import shared_data
ImportError: cannot import name 'shared_data'
You should re-think if shared_data does belong to app/__init__.py , or it can be moved to sub_app/__init__.py and then imported from there in app .

You have a few problems here, one of which is hidden.
It looks like you are trying to invoke your program like:
python app/__init__.py
python app/sub_app/__init__.py
This causes problems in that the directory of the main file is considered to be the root directory of the program. That is, why sub_app cannot see app.
You can instead invoke your programs like such
python -m app.sub_app
This way python assumed the current directory is the root directory and looks for the module app.sub_app under this directory. This causes another problem though. To be able to run a package you need to provide a __main__.py in the package (as well as __init__.py). If the modules do not import each other, then order of invocation will be app/__init__.py, app/sub_app/__init__.py, and then app/sub_app/__main__.py
app
|---__init__.py
|---sub_app
|---__init__.py
|---__main__.py
app/sub_app/__main__.py can do stuff like:
from app import shared_data
from . import more_shared_data
# or
from app.sub_app import more_shared_data
Finally, the hidden problem is that you have circular imports. That is, app depends on sub_app and sub_app depends on app. That both app and sub_app need the other to be loaded, before they can load -- this is of course impossible. You should refactor your code to avoid circular imports.

Related

Trying to reuse code across multiple Flask servers, stuck on importing with errors "ModuleNotFoundError" or "ImportError"

My goal is to import code into three separate Flask servers. It's not going well. I am on python 3.10.4. I have read perhaps 10 different posts that say things like "put a __init__.py file in your folders" which I have done.
For context I'm not exactly new to Python but I've never learned the importing/module system properly.
I have three Flask servers that run scraping operations on different (but similar) websites. I need them to be separate for various reasons. Anyway, all three need to run the same procedure of getting an IP for a proxy from my proxy provider. For this I have some code:
# we don't need the details here so I snip it to save space
def get_proxy_ip(choice):
r = requests.get(download_list, headers={"Authorization": "Token " + token})
selected_proxy_ip = r.json()["results"][choice]["proxy_address"]
selected_proxy_port = r.json()["results"][choice]["port"]
print(selected_proxy_ip)
return selected_proxy_ip, selected_proxy_port
I want to use this function across all 3 of my Flask servers. Here are some various ways I've tried to import the code into one of the Flask servers:
scrapers/rentCanada/app.py
import requests
from flask import Flask, request, make_response
print("cats")
app = Flask(__name__)
print(__name__, __package__)
# from ..shared.ipgetter import get_proxy_ip
# from ..shared.checker import check_public_ip
# from scrapers.shared.ipgetter import get_proxy_ip
# from scrapers.shared.checker import check_public_ip
import shared.ipgetter as ipgetter
import shared.checker as checker
None of them work.
import shared.ipgetter as ipgetter yields:
cats
__main__ None
Traceback (most recent call last):
File "/home/rlm/Code/canadaAps/scrapers/rentCanada/app.py", line 10, in <module>
import shared.ipgetter as ipgetter
ModuleNotFoundError: No module named 'shared'
ModuleNotFoundError: No module named 'scrapers' yields: ModuleNotFoundError: No module named 'scrapers'
from ..shared.ipgetter import get_proxy_ip yields: ImportError: attempted relative import with no known parent package
At this point you need to see my folder structure.
/scrapers
..__init__.py
..setup.py
../rentCanada
.....__init__.py
.....app.py
../rentFaster
.....__init__.py
.....app.py
../rentSeeker
.....__init__.py
.....app.py
../shared
.....__init__.py
.....ipgetter.py
.....checker.py
I need to be able to use any of the app.py files as entry points.
I also tried setup.py with this:
from setuptools import setup, find_packages
setup(
name = 'tools',
packages = find_packages(),
)
followed by python setup.py install but that didn't make a "tools" import available in app.py like I wanted.
As a final note I suspect someone will tell me to use a blueprint. To me those look like a tool I'd use if I was adding a route. I'm not sure they're right for a simple function, but maybe I'm wrong.
My solution for now is to run Flask with python rentCanada/app.py from the /scrapers folder and use this code
import sys
from pathlib import Path
sys.path.append(str(Path(__file__).parent.parent)) # necessary so util folder is available
import requests
from flask import Flask, request, make_response
print("cats")
app = Flask(__name__)
print(__name__, __package__)
from util.ipgetter import get_proxy_ip
from util.checker import check_public_ip
So the program appends the app.py file folder's parent folder to the path. That makes the util folder (which used to be shared but had a naming conflict) available within the app.py file.

Attempting to import methods into cucumber test results in "No module named 'blueprints' " error - Cucumber Test, Python, Behave

I know this question is a duplicate but I seriously need some help on it. I have searched everywhere for a solution and none of the ones I found helped solved the issue. I would REALLY appreciate some input.
I am working on a project with the following tree structure:
Project
- Source
- Web
- test
- features
testing.features
- steps
testing.py
- app
- __init__.py
- blueprints
communication_bp.py
I am working on a cucumber test code using the behave module and the folder I am working on is the test folder, which include features and steps.
What I am trying to do is to import some methods found in communication_bp.py from the app folder into the cucumber test file "testing.py" in python.
So Line 3 is what I am trying to achieve.
testing.py:
from behave_restful import *
import requests
from blueprints.communication_bp import client_comm
but I keep getting this error.
File "../steps/testing.py", line 3, in <module>
from blueprints.communication_bp import client_comm
ModuleNotFoundError: No module named 'blueprints'
Based on what I have read, the app folder is supposed to have __init__.py, which it does.
I will include what both this file and communication_bp.py file here as well.
init.py
from flask import Flask
from flask_cors import CORS
from flask_jwt_extended import JWTManager
from flask_socketio import SocketIO
# Create the Flask application
rest = Flask(__name__)
...
...
from app.blueprints.communication_bp import communication_bp
...
...
rest.register_blueprint(communication_bp, url_prefix = Config.API_PREFIX)
...
...
communication_bp.py
import sys
import json
from flask import Blueprint, request
...
...
So what exactly does this program wants? What am I missing here?

Django views error in importing custom python files

I am trying to import main1.py file in views.py of my django app.
But unable to import it.
Moreover location of my main file and sub-dependent file also lies at the view.py folder location.
I have tried with following options
1 import main
with this error is : No module found with name main
2 from .app_name import main
using this error is : import * only allowed at module level
folder structure is
The name of the file is main1.py, but you are trying to import main.py.
Try:
from app_name import main1 # Absolute import.
from . import main1 # Explicit relative import.
import main1 # Implicit relative import. Won't work in Python3.

import on Python doesn't work as expected

Although the variable should be imported, I get "name X is not defined" exception.
main.py
from config import *
from utils import *
say_hello()
utils.py
from config import *
def say_hello():
print(config_var)
config.py
from utils import *
config_var = "Hello"
Trying to run "main.py":
Traceback (most recent call last):
File "main.py", line 3, in
say_hello()
File "C:\Users\utils.py", line 3, in say_hello
print(config_var)
NameError: name 'config_var' is not defined
What happened here? Why some_var is not accessible from utils.py?
You are importing config in util and util in config which will causing this error(create cross loop). remove from utils import * from config.py and then try this.
And in main.py you don't need to import the from config import * unless you are using variables from config directly in your main()
you should also import config.config_var, since this variable belongs to that specific module
You are creating to many import statements perhaps try the following below, but also you need to define a parameter in utils.py if you are passing a parameter through there.
In utils.py we require a parameter to be passed since you want to print out the appropriate value, In config.py you are defining a value. Then in main.py as discussed before using the wildcard operator "*" isn't entirely good in this situation then in order to call the respective functions you need to address them through their file name
In utils.py :
def say_hello(config_var):
print(config_var)
In config.py
config_var = "Hello"
Then in main.py
import config as cn
import utils as ut
ut.say_hello(cn.config_var)
Check out this thread for how to write python modules as well How to write a Python module/package?

"ImportError: cannot import name mail" in Flask

I have built is a simple web app with Flask and Python, which I intend to upload to Heroku.
When starting my app locally, with the following script:
#!venv/bin/python
from app import app
app.run(debug = True)
I get this error message:
Traceback (most recent call last):
File "./run.py", line 2, in <module>
from app import app, mail
File "/home/ricardo/personalSite/app/__init__.py", line 3, in <module>
from app import index
File "/home/ricardo/personalSite/app/index.py", line 6, in <module>
from emails import send_email
File "/home/ricardo/personalSite/app/emails.py", line 2, in <module>
from app import app, mail
ImportError: cannot import name mail
So, it cannot import mail.
Inside the app directory I have this __init__.py, here is were I create the Mail object that is ginving me trouble to import:
from flask import Flask
app = Flask(__name__)
from app import index
from flask.ext.mail import Mail
mail = Mail(app)
And this is the file emails.py where I call the send_mail function:
from flask.ext.mail import Message
from app import app, mail
from flask import render_template
from config import ADMINS
from decorators import async
So, according to the error message, the error is in this file, in the from app import app, mail.
What is the problem? Why can't it import mail?
Update:
This is my directory listing:
persSite\
venv\
<virtual environment files>
app\
static\
templates\
__init__.py
index.py
emails.py
decorators.oy
tmp\
run.py
You have a circular dependency. You have to realize what Python is doing when it imports a file.
Whenever Python imports a file, Python looks to see if the file has already started being imported before. Thus, if module A imports module B which imports module A, then Python will do the following:
Start running module A.
When module A tries to import module B, temporarily stop running module A, and start running module B.
When module B then tries to import module A, then Python will NOT continue running module A to completion; instead, module B will only be able to import from module A the attributes that were already defined there before module B started running.
Here is app/__init__.py, which is the first file to be imported.
from flask import Flask
app = Flask(__name__)
from app import index # <-- See note below.
from flask.ext.mail import Mail
mail = Mail(app)
When this file is imported, it is just Python running the script. Any global attribute created becomes part of the attributes of the module. So, by the time you hit the third line, the attributes 'Flask' and 'app' have been defined. However, when you hit the third line, Python begins trying to import index from app. So, it starts running the app/index.py file.
This, of course, looks like the following:
from flask.ext.mail import Message
from app import app, mail # <-- Error here
from flask import render_template
from config import ADMINS
from decorators import async
Remember, when this Python file is being imported, you have thus far only defined Flask and app in the app module. Therefore, trying to import mail will not work.
So, you need to rearrange your code so that if app.index relies on an attribute in app, that app defines that attribute before attempting to import app.index.
This is probably the problem:
from app import app, mail
In the file 'app/emails.py' the import is from the current module, not a nested app module. Try:
from . import app, mail
If it doesn't work, you should update your question with a more detailed directory listing.

Categories

Resources