Complexity
Complexity

Reputation: 5820

How to import package in module

I'm new to Python, and I try to structure my Python application.
Given the following directory structure:

πŸ“¦app  
 ┣ πŸ“‚lexer  
 ┃ ┣ πŸ“‚token  
 ┃ ┃ ┣ πŸ“œtoken.py  
 ┃ ┃ ┣ πŸ“œtype.py  
 ┃ ┃ β”— πŸ“œ__init__.py  
 ┃ β”— πŸ“œ__init__.py  
 ┣ πŸ“‚test  
 ┃ ┣ πŸ“‚lexer  
 ┃ ┃ ┣ πŸ“‚token   
 ┃ ┃ ┃ ┣ πŸ“œtest_token.py  
 ┃ ┃ ┃ β”— πŸ“œ__init__.py  
 ┃ ┃ β”— πŸ“œ__init__.py   
 ┃ ┣ πŸ“œtest_app.py  
 ┃ β”— πŸ“œ__init__.py   
 β”— πŸ“œapp.py  

Right now, the application is executed using the following command:

pyhton -m app

When I try to execute the application using

python -m .\app.py

The following error is raised:

Relative module names not supported.

Unit tests are being executed using:

python -m unittest

This works fine and without issues. Now, I'm trying to use the import the token / type.py file in the app.py file.

The contents of this file are:

from enum import Enum, unique

@unique
class Type(Enum):
    UNKNOWN = 1
    EOF     = 2

The following import statement is added in the app.py file:

from app.lexer.token.type import Type

Running the application right now yields the following error:

Traceback (most recent call last):
  File "C:\Python38\lib\runpy.py", line 193, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Python38\lib\runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "C:\DEV\DEMO.ONE\app\app.py", line 17, in <module>
    from app.lexer.token.type import Type
  File "C:\DEV\DEMO.ONE\app\app.py", line 17, in <module>
   from app.lexer.token.type import Type
ModuleNotFoundError: No module named 'app.lexer'; 'app' is not a package

Any ideas on how this can be fixed?

Upvotes: 1

Views: 276

Answers (4)

Petr Blahos
Petr Blahos

Reputation: 2433

app is not a package. A "directory" becomes a package by adding __init__.py in. Try adding app/__init__.py.

On a side note, type is a built-in class in python. It is a bad idea to name your module type.py. Rename it now or you will regret later.

Upvotes: 1

Petr Blahos
Petr Blahos

Reputation: 2433

Actually, python does not know about your app package. When you run python -m app it accedentally works because you have (I presume) started it in the app directory. Therefore python tries to look it up in current directory as well. But then you try to import app.something, and that does not work. Try importing just lexer.token.type. If that works, we know we are on the right track.

Then try

touch __init__.py
cd ..
python -m app.app

Now, to tell python about the package, you will have to make a setup.py file and then install it by doing

pip install -e .

That will put a link into python's library's site-packages directory and python will know about it. Once you have done it, you will be able to run python -m app.app from anywhere.

You might want to read about distutils: https://docs.python.org/3/distutils/setupscript.html

or python packaging: https://packaging.python.org/tutorials/packaging-projects/

Upvotes: 0

rhytonix
rhytonix

Reputation: 998

app/ itself isn't a package -since it doesn't include a __init__ file-. app/ is root of the application, while the package's path starts with lexer. So, change

from app.lexer.token.type import Type

to

from lexer.token.type import Type

Upvotes: 1

lingxiao
lingxiao

Reputation: 1224

i think you need to set environment variable PYTHONPATH before you execute the script from your project root folder.

in command line at your project root folder, do:

export PYTHONPATH=$(pwd)

or put the above in a .env file at project root folder and do

source .env

before executing your script

Upvotes: 0

Related Questions