How to structure a APP not a package or a "project"

Hi, I’m writing a data processing app in python and I don’t know how to structure the APP to RUN it.

Every guid just tells you how to structure your project to upload it to pypi but I don’t need to upload it I need to run my project. I use the usual example:

helloworld/
main.py <------ I tried adding this here and importing helloworld but it doesn’t work?

├── helloworld/
│ ├── init.py
│ ├── helloworld.py
│ └── helpers.py

├── .gitignore
├── LICENSE
├── README.md
├── requirements.txt
└── pyproject.toml

Real python shows this but this is the setup to upload my package to pypi, how do I use the code I wrote in helloworld package in a top level script? None of the imports work outside of the package. How do I actually run my app??

Can you show the contents of main.py? The apps I build are like this and they do work - if I start them from the directory where main.py is.

The import works if you start inside the root directory and run the main.py file like python main.py, and use an absolute import in that code. This way, the helloworld package folder (the one with __init__.py, helloworld.py and helpers.py in it) is put onto sys.path automatically at startup.

If you want to run the main.py from somewhere else on your computer, then Python needs to know both where to find main.py, and where the main.py’s import should look. The reason people talk about making packages and uploading them (aside from “sharing open-source code is good”) is because a package can be installed, which takes care of these issues.

If you only want to use the code locally, you don’t have to build a package to install it. You can use an editable install with Pip. Make sure that python means a Python where you don’t mind installing the code (if you’re using a Python that came with your operating system, you may run into problems); navigate to the project folder, and use pip install -e .. As long as your pyproject.toml is properly configured, Pip will set up files in your Python’s site-packages folder, that tell Python about your current folder’s contents and structure.

(If Pip doesn’t recognize the command, or tells you that a setup.py is required for editable installs, update Pip first.)

By default, this will use Setuptools to configure the package (i.e.: figure out which files in your project folder are supposed to be part of the installation, and what modules and packages they represent), and Setuptools will make some default assumptions that are wrong - we need to tell it that the main.py file should also be installed as a module, as well as installing the helloworld package. A minimal example looks like:

[project]
name = "helloworld"
version = "0.1.0"

[tool.setuptools]
py-modules = [ "main" ]
packages = [ "helloworld" ]

After this, we can use python -m main to run the main.py script as a module. This tells Python to search for main.py (in the paths that it knows to search), instead of using a directly specified path.

Keep in mind that if you want to “install” more “applications” in the same Python, they’ll be competing for names. If all of them are supposed to have a main.py “driver”, that isn’t going to work - python -m main can only refer to one of them.

Another way to solve the problem (which avoids that namespace issue) is to put the driver code in a __main__.py file inside the helloworld package folder. (When you do this, you should use relative import instead; but the absolute import in this example will still work for now.) This makes the helloworld package runnable as if it were an ordinary module: python -m helloworld.

Finally, instead of installing the code, you can do a more manual configuration of Python so that it knows where to look for the helloworld package - i.e., do something that puts the containing project folder onto sys.path. This can mean setting the PYTHONPATH environment variable, or (seriously, only as a last resort) manually hacking the sys.path list from within the main.py script.

1 Like