I'm trying to create a basic blogging application in Python using Web.Py. I have started without a direcotry structure, but soon I needed one. So I created this structure:
Blog/
├── Application/
│ ├── App.py
│ └── __init__.py
|
├── Engine/
│ ├── Connection/
│ │ ├── __init__.py
│ │ └── MySQLConnection.py
│ ├── Errors.py
│ └── __init__.py
├── __init__.py
├── Models/
│ ├── BlogPostModel.py
│ └── __init__.py
├── start.py
└── Views/
├── Home.py
└── __init__.py
start.py imports Application.App, which contains Web.Py stuff and imports Blog.Models.BlogPostModel, which imports Blog.Engine.Connection.MySQLConnection.
Application.App also imports Engine.Errors and Views.Home. All these imports happen inside contructors, and all code inside all files are in classes. When I run python start.py, which contains these three lines of code:
from Application import App
app = App.AppInstance()
app.run()
The following stack trace is printed:
Blog $ python start.py
Traceback (most recent call last):
File "start.py", line 2, in <module>
Blog = App.AppInstance()
File "/home/goktug/code/Blog/Application/App.py", line 4, in __init__
from Blog.Views import Home
ImportError: No module named Blog.Views
But according to what I understand from some research, this should run, at least until it reaches something after App.py. Can anyone tell where I made the mistake? (I can provide more code on request, but for now I'm stopping here, as this one is getting messier and messier).
App.py contains the statement
from Blog.Views import Home
So Blog needs to be among the list of directories Python searches for modules (sys.path). That can be arranged in various ways.
Since you are starting the app with python start.py, the directory
containing start.py is automatically added to the search path. So
you could change
from Blog.Views import Home
to
from Views import Home
Another option would be to move start.py up one level, out of the
Blog directory. Then when you call python start.py, the
directory containing start.py will also be the directory
containing Blog. So Python would find Blog when executing from
Blog.Views ...
Finally, you could add the Blog directory to your PYTHONPATH environment
variable.
You can only import the module Blog if its parent directory (not Blog itself) is on python's path.
If you run your program from the Blog directory like you do, you can only imort Views directly, like you do with Application.App:
from Views import Home
instead of
from Blog.Views import Home
in your Application/App.py.
Related
CONTEXT. Python 3.9.1, Flask 2.0.1 and Windows 10
WHAT I WANT TO DO. Call a module located inside a custom package.
TROUBLE. No matter what I do, the console insists on telling me: ModuleNotFoundError: No module named 'my_package'
WHAT AM I DOING.
I am following the official Flask tutorial https://flask.palletsprojects.com/en/2.0.x/tutorial/index.html. Therefore, the structure of the project is basically this (with slight changes from the tutorial):
/flask-tutorial
├── flaskr/
│ ├── __init__.py
│ ├── db.py
│ ├── schema.sql
│ ├── templates/
│ ├── static/
│ └── my_package/
│ ├── __init__.py (this file is empty)
│ ├── auth.py
│ ├── backend.py
│ ├── blog.py
│ └── user.py
├── venv/
├── .env
├── .flaskenv
├── setup.py
└── MANIFEST.in
Inside the file /flask-tutorial/flaskr/init.py I try to call the modules that contain my blueprints:
from my_package import backend
from my_package import auth
from my_package import user
from my_package import blog
backend.bp.register_blueprint(auth.bp)
backend.bp.register_blueprint(user.bp)
backend.bp.register_blueprint(blog.bp)
app.register_blueprint(backend.bp)
When I running the application (with the flask run command), the console tells me ModuleNotFoundError: No module named 'my_package', indicating that the problem is in the line where it is from my_package import backend.
HOW I TRIED TO SOLVE THE PROBLEM (unsuccessfully).
First. I have created an empty file called init.py inside 'my_package'
Second. Inside the file /flask-tutorial/flaskr/init.py, before the problematic FROM, I have put:
import os.path
import sys
parent = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, parent)
On the internet there are several posts with this same problem. Many of them mention that the solution is to put a init.py file inside the package (I already did this and it does not work for me). Also, unfortunately the structure of the projects in question is different from mine.
Any ideas how to fix this?
Change your code to
from .my_package import backend
from .my_package import auth
from .my_package import user
from .my_package import blog
backend.bp.register_blueprint(auth.bp)
backend.bp.register_blueprint(user.bp)
backend.bp.register_blueprint(blog.bp)
app.register_blueprint(backend.bp)
Just add a single dot . before the package name to import the package in the same parent package. In your case, __init__.py and my_package have a common flaskr as their parent package.
I'm using pyright for type checking and I'm also using pytest for testing inside Visual Studio Code. The folder structure for my tests is to have a 'test' subfolder in the package root . For example
|
MyPackage
|-- __init__.py
|-- MyModule.py
|--test
|-- __init__.py
|--MyModule_test.py
I'm organizing things like this as there will be many packages and I want to keep things organized.
Inside pytest I have
import pytest
import MyPackage.MyModule
...
Pytest is able to discover the tests and run them OK because it has some special ability to adjust its sys.path (or something).
However, pyright will just complain that it cannot import the module,
Import 'MyPackage.MyModule' could not be resolvedpyright (reportMissingImports). This makes sense, but is there some way to deal with this, either in pyright or in the Visual Studio Code settings to stop this from complaining?
You can add the library path to the path variable.
import sys
sys.path.insert(1, str('..'))
import MyModule
To enable Pylance to use your library properly (for auto-complete ...), use the following steps:
Pylance, by default, includes the root path of your workspace. If you want to include other subdirectories as import resolution paths, you can add them using the python.analysis.extraPaths setting for the workspace.
In VS Code press +<,> to open Settings.
Type in python.analysis.extraPaths
Select "Add Item"
Type in the path to your library `..'
Ok, a relative import as illustrated here was able to solve this. So in my case I should have
# MyModule_test.py
import pytest
from .. import MyModule
You should create a pyrightconfig.json file or pyproject.toml file at the root of your project. For example, if it's a Django project, you should have one of those files where manage.py is placed. Then, set include parameter and add the subdirectories (or app folders in Django terms).
You can consult this sample config file. See this issue ticket.
For example, if this were my project structure:
├── manage.py
├── movie
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── moviereviews
│ ├── asgi.py
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── pyproject.toml
my pyproject.toml would be:
[tool.pyright]
include = ["movie", "moviereviews"]
If you are working within a Python virtual environment, set venvPath and venv. Consult the documentation for an exhaustive list of options.
I have created a small script for comparing how similar two images are. This is contained in a file called compare_image.py, which contains just one function, compare. This file is in the app directory. I am trying to import it from the models.py file using the line import compare_image, but attempting this results in the error message ModuleNotFoundError: No module named 'compare_image'.
The simplified directory structure looks like this:
myproject
└── myapp
├── __init__.py
├── admin.py
├── apps.py
├── compare_image.py
├── forms.py
├── models.py
├── tests.py
├── urls.py
└── views.py
myapp is the only app in the project. Apart from this, the webapp functions fine.
I have tried deleting and retouching the __init__.py file to no avail. I can import compare_image fine from a python shell in the myapp directory. The only imports in compare_image.py are to PIL or standard libraries, so I don't think circular imports are the culprit.
One solution would be to just put the code in models.py, but I don't want to clutter this file.
I thought since this error seems so basic there might be some standard mechanism for user-written scripts in Django, but I can't find any mention of this online.
I would be happy to provide more details about the project if it will make things clearer. Thanks in advance for any help (this error is driving me crazy!)
I think you're doing an absolute import where you need a relative one. Can you try:
from .compare_image import compare
from a python file in the same folder as compare_image.py?
So, here's my (okay.. messy) dir:
.
├── app
│ ├── __init__.py
│ ├── analyze_text.py
│ ├── images.py
│ ├── main.py
│ ├── messages.py
│ ├── process_text.py
│ ├── requirements.txt
│ ├── response.py
│ └── tests
│ ├── __init__.py
│ ├── analyze_text_test.py
│ ├── test_process_text.py
│ └── unit_tests.py
└── setup.py # no idea what's going on with this
All I want to do is, simply use
from analyze_text import AnalyzeText
in the analyze_text_test.py file without seeing
"You're an idiot and you don't know what you're doing" in the terminal.. a.k.a:
ImportError: No module named (whatever)
I found this solution:
https://stackoverflow.com/a/11158224/2738183
import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir)
import mymodule
Which works, but it's Janky.
Why?
Because..
I'm using it in a Janky way. I don't wanna have to re-paste this code to every single one of my unittests in the tests folder (which are in different files.)
(So what if i just paste it once in init.py? You get an error that's what. But I did randomly try that just to see what happened)
So what is the most elegant way to approach this problem? ( without repasting code (or just sticking it in a function and calling it multiple times) )
Edit:
The comments so far haven't solved anything, so I'll try to make this a bit more clear. I found a solution that works. So in each file in the tests directory I have to re-paste that solution (or call the same function as many times as there are files.) That's exactly what I'm trying to avoid. I'd like a solution that can apply to every file in the test directory so that I can use imports from the parent directory like normal, instead of appending the parent path inside every single one of those files.
Never mind. I found an elegant solution on stack overflow that I like.
Which amounted to placing
import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir)
inside a file within the tests directory named env.py
and simply adding
import env
before importing as usual
see: https://stackoverflow.com/a/23386287/2738183
When I build or debug a particular file in my Python project (which imports a user defined package) I get an import error. How can I solve this problem?
test.py
def sum(a,b):
return a+b
test2.py
from test import sum
sum(3,4)
The above code will give an import error cannot import test.
Directory tree
├── graphs
│ ├── Dijkstra's\ Algorithm.py
│ ├── Floyd\ Warshall\ DP.py
│ ├── Kruskal's\ algorithm.py
│ ├── Prim's\ Algoritm.py
│ ├── __init__.py
│ └── graph.py
├── heap
│ ├── __init__.py
│ ├── heap.py
│ └── priority_queue.py
Trying to import in graphs;
from heap.heap import Heap
About the heap file, make sure that you are running on the project root folder.
If these test.py files are running on the same folder, try to add a __init__.py empty file on this folder.
The __init__.py files are required to make Python treat the directories as containing packages; this is done to prevent directories with a common name, such as string, from unintentionally hiding valid modules that occur later (deeper) on the module search path. In the simplest case, __init__.py can just be an empty file, but it can also execute initialisation code for the package or set the __all__ variable, described later.