pythonimportmodule

import modules from external directories


I am working on a python app in which I have the following structure:

project/
├── src/
│   ├── main.py
│   ├── pdfs/
│   │   ├── create_pdf1.py
│   │   ├── create_pdf2.py
│   │   ├── create_pdf3.py
│   │   ├── create_pdf4.py
│   │   ├── create_pdf5.py
│   │   └── merge_pdfs.py
│   ├── entities/
│   │   ├── entitie1.py
│   ├── utils/
│   │   └── helpers.py
├── aux/
│   ├── pdf_aux1.pdf
│   └── pdf_aux2.pdf
├── out/
    ├── result1.pdf
    └── result2.pdf

I am now working on the create_pdf1.py module and trying to import a class from the entitie1.py module but I keep getting the following error when I run the code:

Traceback (most recent call last):
  File "c:\Users\ricar\project\src\pdfs\create_pdf1.py", line 3, in <module>
    from entities.entitie1 import Legajo, Persona, Domicilio, Empresa
ModuleNotFoundError: No module named 'entities'

I tried using from ..entities.entitie1 import Legajo, Persona, Domicilio, Empresa but I get this error ImportError: attempted relative import with no known parent package

One thing I have to say us that up until yesterday I didn't have the code distributed like this. All the modules where in the src folder and I could import them without any trouble. It was when I re-organized everything that I run the code and this errors started appearing.


Solution

  • You need to organize the project with __init__py (empty file) in each directory level. This way, the Python module import will work without any issues. Ref: https://www.geeksforgeeks.org/what-is-__init__-py-file-in-python/

    pdf-generator
    ├── pdf-generator
    │   ├── __init__.py
    │   ├── aux
    │   │   ├── __init__.py
    │   │   ├── pdf_aux1.pdf
    │   │   └── pdf_aux2.pdf
    │   ├── entitles
    │   │   ├── __init__.py
    │   │   └── entitie1.py
    │   ├── main.py
    │   ├── out
    │   │   ├── __init__.py
    │   │   ├── result1.pdf
    │   │   └── result2.pdf
    │   ├── pdfs
    │   │   ├── __init__.py
    │   │   ├── create_pdf1.py
    │   │   ├── create_pdf2.py
    │   │   ├── create_pdf3.py
    │   │   ├── create_pdf4.py
    │   │   ├── create_pdf5.py
    │   │   └── merge_pdfs.py
    │   └── utils
    │       ├── __init__.py
    │       └── helpers.py
    └── tests
        ├── resources
        └── test_create_pdf.py
    

    Note: If you use PyCharm as an IDE, use the New --> Python Package. This will create a directory with __init__.py in it.

    Pycharm option

    Then in create_pdf1.py import the entitle1 as below,

    from pdf_generator.entitles.entitle1 import Legajo, Persona, Domicilio, Empresa
    

    EDIT: Updated answer for VSCode

    To make it work in VSCode, you need to create a pyproject.toml file in the project root directory as a build descriptor. For the latest python3 versions, the recommended way is to use pyproject.toml instead of setup.py.

    eg:

    pdf_generator
    ├── pdf_generator
    │   ├── __init__.py
    │   ├── entitles
    │   │   ├── __init__.py
    │   │   └── entitle1.py
    │   ├── main.py
    │   └── pdfs
    │       ├── __init__.py
    │       └── create_pdf1.py
    ├── pyproject.toml
    └── tests
        └── __init__.py
    

    Sample pyproject.toml template. You can edit the commented fields and placeholder fields to match your needs.

    [build-system]
    requires = ["setuptools >= 61.0", "wheel"]
    build-backend = "setuptools.build_meta"
    
    
    [project]
    name = "pdf_generator"
    version = "1.0.0"
    
    description = "<Description of pdf generator tool>"
    #readme = "README.md"
    requires-python = ">=3.8"
    #license = {file = "LICENSE"}
    authors = [
      {name = "<Your name>", email = "name@email.com"},
    ]
    
    classifiers = [
      "Programming Language :: Python :: 3.8",
      "Programming Language :: Python :: 3.9",
      "Programming Language :: Python :: 3.10",
      "License  :: OSI Approved :: Apache Software License",
      "Operating system  ::  OS Independent"
    ]
    
    
    dependencies = [
          "flake8",
          # Add your poject specific dependencies
    ]
    

    Then install your project using the below command (You can choose the Terminal option from VSCode and execute it there). This will install the project globally or your virtual environment if you set one.

    pip install . --upgrade

    Once installed, then you should be able to run the code from VSCode, too.