1

I'm using poetry to manage my python project, here's the project:

my_project/
├── pyproject.toml
├── module.py
└── scripts/
    └── main.py

And I want to know how to import function from module.py into my_scripts/main.py correctly.

My pyproject.toml:

[tool.poetry]
name = "my_project"
version = "0.1.0"
description = ""
authors = []

[tool.poetry.dependencies]
python = "^3.11"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

I have tried this:

# In my_scripts/main.py

from module import my_function

And run these commands:

poetry install
poetry shell
python my_scripts/main.py

then got this error:

ModuleNotFoundError: No module named 'module'

I also have put a __init__.py under my_project/ but didn't work out.

Matt Peng
  • 848
  • 6
  • 12

2 Answers2

0

What made it work for me is to create a folder in your root with the same name of the package in the pyproject.toml file. If you don't do this, poetry will not find your project and will not install it in editable mode.

You also need to let Python know that a folder is a package or sub-package by placing an __init__.py file in it.

my_project/
├─ pyproject.toml
├─ my_project/
   ├─ __init__.py
   ├─ module.py
   ├─ scripts/
      ├─ __init__.py
      ├─ main.py

When you initialize the folder you should see that the project is installed.

...> poetry install
Installing dependencies from lock file

Installing the current project: my_project (0.1.0)

Last thing, you need to change the import in main.py.

# main.py

from my_project.module import my_function

print("my_function imported")

You can now activate the virtual environment (if it's not already active) and run your script.

...> poetry shell
Spawning shell within: C:\...\my_project\.venv
...
...> python my_project\scripts\main.py
my_function imported

PS

As @sinoroc pointed out in the comments, it is possible (and preferable according to him) to run the module with python -m my_project.scripts.main.

I am new to the topic, but according to this SO answer:

__package__ is set to the immediate parent package in <modulename> [when running python via command line with the -m option]

This means that relative imports like the following magically work.

# main.py

from ..module import my_function

# ..module tells python to look in the parent directory for module.py

print("my_function imported")
...> python -m my_project.scripts.main
my_function imported
...> python my_project\scripts\main.py
Traceback (most recent call last):
...
ImportError: attempted relative import with no known parent package

edd313
  • 1,109
  • 7
  • 20
  • 1
    Yes, seems like that could be one way to fix this. But you have to use `python -m myproject.scripts.main`. – sinoroc Jan 12 '23 at 11:04
  • Thanks @sinoroc, that's interesting. Could you elaborate on the difference? Feel free to edit the answer directly. – edd313 Jan 12 '23 at 11:06
  • 1
    I do not know the details, it is a matter of `sys.path` I think. What I have read many times is that if the thing that Python should run is part of a package (there is a `__init__.py`), then it should preferrably be run with `python -m` and dotted notation. -- See the [references on this page](https://sinoroc.gitlab.io/kb/python/python_imports.html) but I admit it is not straightforward, I should try to find a better reference. -- Maybe there are better explanations here: https://stackoverflow.com/q/7610001 – sinoroc Jan 12 '23 at 11:39
  • @edd313 @sinoroc Thank you guys for solutions. I found a simple way that I don't need to create a subdirectory or any `__init__.py` file. Just submitted my answer and I wanna know if there is any drawback of my solution. – Matt Peng Jan 12 '23 at 17:07
0

I managed to make it work by adding this line to the pyproject.toml under the [tool.poetry] section:

[tool.poetry]
# ...other fields
packages = [{ include = "**/*" }]

No __init__.py is needed. Just run:

poetry install
poetry shell
python scripts/main.py
Matt Peng
  • 848
  • 6
  • 12
  • 1
    Hi @Matt Peng, I am not sure about the drawbacks. My only comment is that this solution is not very common. Check out the default folder structure that you get with the [`poetry new`](https://python-poetry.org/docs/cli#new) command, for example. Or have a look on GitHub at the repositories of the packages that you use. They probably have no modules in the root folder, rather all the code is in `src/` or similar. – edd313 Jan 12 '23 at 17:26