Python can't import module from package - python

I have a flask restful project with the following layout (file names changed for convenience)
myproject/
__init__.py
app.py
common/
__init__.py
util.py
foo/
__init__.py
main.py
utilities.py
foo/ is just a folder containing code for one of the API endpoints, I'm planning to add others in the future, for this reason I have common/util.py file which contains reusable functions that I will use with other API endpoints.
foo/main.py
from flask_restful import Resource, request
from utilities import Analysis
class Foo(Resource):
def get(self):
pass
in foo/utilities.py I have classes with methods that get some data, I import those classes to foo/main.py to return JSON response
classes in foo/utilities.py also uses some functions from common/util.py but when I try to import something from common/util.py to foo/utilities.py I get import common.util
ModuleNotFoundError: No module named 'common'
What could be causing this? I tried importing various ways:
from common.util import my_func
from .common.util import my_func
from myproject.common.util import my_func
but none worked.
This is myproject/app.py in case it matters:
from flask import Flask
from flask_restful import Api
from foo.main import Foo
app = Flask(__name__)
api = Api(app)
api.add_resource(Foo, '/Foo')
if __name__ == "__main__":
app.run()
I'm doing all of this in activated virtualenv if it matters

from common.util import my_func
In Python 3 this is an absolute import, that is, the directory with common/ subdirectory must be in sys.path. In your situation it's certainly a wrong approach.
from .common.util import my_func
This import expects common to be a subdirectory of foo which is also not the case.
from myproject.common.util import my_func
This is finally the best approach but for it to work the parent directory of myproject/ subdirectory must be in sys.path. Either you install the entire myproject or add the parent directory to $PYTHONPATH environment variable or add the directory to sys.path in foo/main.py. Something like:
PYTHONPATH=/home/to/parentdir /home/to/parentdir/myproject/foo/main.py
or
import sys
sys.path.insert(0, '/home/to/parentdir')
/home/to/parentdir is the directory where myproject/ is.
After installing myproject or adding its parent directory to sys.path you can also use relative import. You need to remember that common is a sibling package comparing to foo so the import must be not from .common but from ..common:
from ..common.util import my_func

Related

Python - access module from package that is not imported through __init__.py?

I'm using one package that with __init__.py import only one variable from module, but whole module itself is not exposed. Is there a way to access that module?
Lets look in this case:
Whole package:
test_package/
├── __init__.py
└── test_me.py
Now contents:
__init__.py:
from .test_me import test_me
test_me.py:
STATIC = 'static'
class Test:
pass
test_me = Test()
Now if I import package test_package. I can only access variable test_me, which is an instance of Test class. Though I can't access STATIC variable, because module itself was not exposed.
Is there a way to access test_me module in this case and not only one of its variables?
P.S. If I use sys to append path directly to that package's module, it throws error that such module does not exist when I try to import it.
If you add the package directory to your path, Python can import any file in that directory as if it were a module by itself.
import sys
sys.path.extend(test_package.__path__)
import test_me
print(test_me.STATIC)
You need to import them through __init__.py, so change its contents to:
from .test_me import test_me, STATIC
Now the following will work:
import test_package
print(test_package.STATIC)

Cannot import app modules implementing Flask CLI

For some reason when I try to execute my custom command:
flask create_user
I get an error whenever I try import anything from my src folder:
File "/app/backend/flask_app/command.py", line 17, in seed_db
import src.models
ModuleNotFoundError: No module named 'src'
/
__init__.py
command.py
run.py
src/
__init__.py
models/
__init__.py
user_model.py
command.py
import click
from flask import Flask
from flask.cli import with_appcontext
app = Flask(__name__)
#app.cli.command()
#with_appcontext
def create_user():
import src.models as models
print("hello")
app.cli.add_command(seed_db)
I found the solution.
I had to delete the root dir __init__.py file.
I found this answer from the famous Miguel Grinberg:
https://github.com/miguelgrinberg/flasky/issues/310#issuecomment-340641813
These files (__init__.py) make python believe the main directory of the package is one directory above, so that is the directory that is added to the Python path. Usually you want your top-level directory to not be a Python package, so that the current directory goes to the path.
__
It is a matter of python way of import modules, not about Flask command.
Since command.py file is at the same level of the models folder you can just write:
import models.user_models as users
After that you can acces the user_models module from users reference:
import models.user_models as users
users.some_function_name()

Import method from __init__.py

Having some issues with importing modules in python. This is my folder structure
my_app/
app.py
__init__.py (I want to import a function from this file)
folder1/
__init.py
method1.py
folder2/
__init__.py
method.py
In my root __init__.py I have this function
def want_to_be_run_elsewhere():
pass
In my app.py, I want to import this function and run it when I start my application, but I'm unsure how to do it.
from my_app import want_to_be_run_elsewhere
This throws a no module named my_app
From what I can tell, I have all the necessary __init__.py files, so maybe it could be sys.path related?
I've read some similar threads on here but I haven't been able to solve this.
Usually you would do the import like
from . import want_to_be_run_elsewhere
This doesn't work here, because you are calling app.py. If you import my_app.app, it is part of the module. If you call it it is not. Importing from the module it is in using . will then not work.
You could either move app.py outside of my_app, removing it from the module and making imports work again.
Or you can use
from __init__ import want_to_be_run_elsewhere
in app.py
I believe
from my_app import want_to_be_run_elsewhere
will only work if you have actually pip install -e my_app/. Then it should work too.

Importing a module into a custom command

Suppose I have the following Django project:
/ # Project dir
/myapp # App dir
/myapp/views.py # views file
/myapp/mymodule.py # a Python module
/myapp/management/commands/mycommand.py # command file
In the views file, I can import mymodule.py by simply writing import mymodule in views.py. However, if I do the same in mycommand.py, I get the error: ImportError: no module named mymodule. I know that to import a model, I can write from myapp.models import mymodel, but mymodule is not a model, it is a separate Python module. So, how do I import this moduel into my command file?
Thats because of where mymodule is in relation to all of your other files.
If you type
from myapp import mymodule
In mycommand.py as long as you have set up your __init__.py files correctly in myapp and are using a setup.py file you should be fine. The modules documentation has more information on this
The fact that you are unable to do this means your myapp folder is not in the python's sys.path. The reason it worked in views.py is because mymodule.py is in the current directory of views.py
Assuming your Project dir (/) is in the python's sys.path:
Add a file __init__.py in myapp directory. This file can be blank.
Then you can do import myapp.mymodule or from myapp import mymodule
The same logic applies for n levels deep. If you have myapp/myappdir1/myappdir2/myfile.py you can do import myapp.myappdir1.myappdir2.myfile assuming each of these have __init__.py file in them.
Check https://docs.python.org/2/tutorial/modules.html#the-module-search-path for python's module search path

import python class into another folder in a package

I'm trying to import a python class from another folder of my python package but I this error "No module named models".
It's a Flask project.
-app
|-run.py
|-myapp
|- libs
|- updateto
|- __init__.py (empty)
|- connection.py
|- removeto
|- __init__.py (empty)
|- static
|- templates
|- __init__.py (NOT empty)
|- routes.py
|- models.py
My init.py:
from flask import Flask
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///maindb.db'
from models import db
db.init_app(app)
import myapp.routes
In my models.py I've a class named: application
And in connection.py I want import my class "application".
I've try with "from models import application" but I've this error "no modules named models".
I think it's possible to reach this goal with the modification of the init.py in the "updateto" folder but I'm no sure because I don't clearly understand the functioning of the init.py file...
Thanks
EDIT:
Which is weird, it's if under connection.py I add "import myapp" and "print(help(myapp))", I've this output:
Help on package myapp:
NAME
myapp
FILE
c:\app\myapp\__init__.py
PACKAGE CONTENTS
libs (package)
models
routes
DATA
app = <Flask 'myapp'>
But if I try "from myapp import models" I've this error "ImportError: cannot import name models"
EDIT2:
If I try to add in connection.py "from myapp import app", it works but not if I try to import models... I'm very surprised. I've try to add in myapp/init.py:
__all__ = ["models", "routes]
But same error...
EDIT3:
hummmm I've move all my modules under the libs folder into myapp and when I try to put in connection.py "from model import application" I've always the same error "ImportError: cannot import name application"
Other test in connection.py:
import models
print(models)
Output:
<module 'myapp.models' from 'C:\app\myapp\models.pyc'>
I can import my module named models but I can't import the class under models.py
EDIT4:
Ok, I think I found the problem. It's my ini.py in myapp, because if I comment this file content, the connection.py can now import my class application in models. I run the file run.py which uses routes.py and it's him that calls operation.py
With some tests, I've find the lines who create my error:
from models import db
db.init_app(app)
import myapp.routes
But why????
I don't know about Flask specifically, but in Python you should generally include a __init__.py in every folder and subfolder for them to be recognised as modules and/or packages.
In the diagram you provide, there is no __init__.py in the app folder. Try putting one and re-post if that resolves your problem.
If it doesn't work, try:
import os
print(os.getcwd())
If the current working directory isn't the app directory, you'll have to work around this. One way would be:
import sys
sys.path.append('/path/to/app')
import myapp.models
You can always see what directories are in your search path for modules by checking sys.path.
Update: Sorry I just realized that maybe you' re trying to run connections.py as a script. That would change you working directory to that of connections.py. Try importing connections.py from your main script with import models inside connections.py and see if you get an error.
Update (in reply to Edit 4): (I don't have enough reputation points to comment yet, so I reply here)
from models import db
db.init_app(app)
import myapp.routes
The problem in this piece of code is the import myapp.routes. Change that to import routes and it should work. As a rule of thumb, your main script's directory is your root directory. You can import any module located in your root directory from inside any other module (even modules inside a sub-folder!) with a simple import module.

Categories