Sometimes you have these simple Python projects that are essentially just a single file. On the road to package your project "properly", you'll find a lot of documentation and tools pushing you towards a complex project layout with multiple folders (e.g. a generally recommended src layout) and additional (empty) __init__.py files sprinkled all around.

When that feels too much as overkill, consider keeping your project layout simple with your single python file just at the project root.

Single module packaging with classic setup.py and setuptools

With a classic setuptools-based setup.py, you can achieve this with the py_modules option. For example, assuming your single Python file is called snorfle.py

from setuptools import setup

setup(
    name="snorfle",
    ...,
    py_modules=["snorfle"],
    ...,
)

When building this project (e.g. python -m build), you get a wheel that will install snorfle.py directly as a module under site-packages as desired.

Note that, if you decide to switch to a more complex project layout after all, you have to switch over to other setuptools options and functionality like packages, find_packages(), etc.

Single module packaging with Hatch/Hatchling

When I was playing around on some simple projects to switch over to more modern packaging workflows, using pyproject.toml and Hatch/Hatchling, I was a bit lost when looking for a py_modules equivalent. However, after some more digging, it turned out that Hatch/Hatchling makes it actually easier and more uniform compared to use-case specific options of old-school setup().

All you need is the generic include build option to list your single file:

[project]
name = "snorfle"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build]
include = ["snorfle.py"]

When your project grows more complex over time, you just have to adapt the include option appropriately (and possibly add some more file selection related options).