pythonimportmoduleorganizationtyper

How to resolve mutual dependencies between a main script and submodules needing access to a global variable from the script?


I'm building a Typer app with lots of commands. I want to categorize the commands into subfiles but am unsure how to resolve the dependencies.

|
├── melvil
│   ├── add.json
│   ├── book
│   │   ├── book.py
│   │   └── __init__.py      
│   ├── booklist
│   │   ├── booklist.py
│   │   └── __init__.py 
│   ├── helper
│   │   ├── helper.py
│   │   └──__init__.py  
│   ├── search
│   │   ├── __init__.py
│   │   └── search.py
│   │
│   │
│   ├── __init__.py
│   ├── main.py
│   ├── setup.py
│   └── test_input.txt

main.py is the parent. It looks like this:

import typer
from datetime import date

app = typer.Typer()

# Import submodules
from booklist.booklist import *
from book.book import *
from search.search import *
from helper.helper import *

# App is only invoked when we run main.py directly, but not when we import it.
if __name__ == "__main__":
    app()

So, we make a new Typer app and import everything from the submodules. Simple enough.

Each of the submodules contains Typer commands, like booklist:

# This file focuses on commands that affect the entire booklist.

import inquirer
import os
import json
import csv

@app.command()
def delete():
    """
    ...Irrelevant code here...
    """

Here's the problem: in order to define a Typer command with the @app.command() decorator, each submodule first needs to import app from the parent main.py. However, main.py gets run in the import statement for any of the submodules, and so a circular import arises when main.py imports whatever submodule it's in.

How should one structure this project so that all submodules have access to app and main.py can also access all the submodules?


Solution

  • You could just have app be initialized in its own separate module. Let the sub-modules import it from there and have your main module import those sub-modules.

    Something like this: app.py

    import typer
    
    app = typer.Typer()
    

    booklist.py

    from YOURTOPLEVELPACKAGE.app import app
    
    @app.command()
    def your_function():
        ...
    

    main.py

    # All of those include `app`
    from booklist.booklist import *
    from book.book import *
    from search.search import *
    from helper.helper import *
    
    if __name__ == "__main__":
          app()