A Go-like CLI runner for Python projects — type `pyrun .` instead of `python3 script.py`
Project description
py-modu
A Go-like CLI runner for Python projects.
In Go, you run a project with go run .. In Python, you're stuck typing
python3 the_exact_filename.py every time and remembering that filename
across a dozen little projects gets old fast. py-modu gives Python the
same convenience:
pyrun .
That's it. No filename to remember or type.
Table of contents
- Why py-modu
- Installation
- Usage
- How it works
- Comparison with Go
- FAQ
- Troubleshooting
- Development
- Contributing
- License
Why py-modu
Python doesn't have a single, obvious "run the project" command the way Go,
Rust (cargo run), or Node (npm start) do. py-modu is a small, focused
tool that fills that gap for simple scripts and small projects it doesn't
try to be a build system, a dependency manager, or a task runner. It does
one thing: figure out what you meant by "run this," and run it.
Installation
Recommended: pipx (isolated, global, no system conflicts)
pipx install py-modu
pipx installs CLI tools into their own
isolated environment and puts them on your PATH, so pyrun is available
everywhere without touching your system Python or any project's virtualenv.
Don't have pipx yet? One line gets you both, on any OS:
python3 -m pip install --user pipx && python3 -m pipx ensurepath
On Windows (PowerShell), use py instead of python3:
py -m pip install --user pipx
py -m pipx ensurepath
Restart your terminal afterward so the updated PATH takes effect.
Alternative: pip
pip install py-modu
On some Linux distributions, installing CLI tools system-wide with plain
pip is blocked (PEP 668, "externally-managed-environment"). If you hit
that error, either use pipx above, or install into a virtual environment:
python3 -m venv .venv
source .venv/bin/activate # .venv\Scripts\activate on Windows
pip install py-modu
Verifying the install
pyrun --version
Should print pyrun 0.1.1. If you get a "command not found" error right
after a pipx install, it usually means your shell hasn't picked up the
updated PATH yet open a new terminal window, or run
pipx ensurepath again and restart.
Compatibility: Python 3.8 and newer. Tested in CI on Linux, macOS, and Windows across Python 3.8 through 3.13.
Usage
Run the current project
pyrun .
py-modu looks for an entry point in the current directory, in this order:
main.pyapp.pyrun.py- If none of those exist but there's exactly one
.pyfile in the directory, that file is used.
If there are multiple .py files and none matches the list above,
py-modu refuses to guess and tells you what to do instead, it will
never silently pick the wrong file.
Run a specific file
pyrun path/to/script.py
Bypasses auto-detection entirely and just runs that file.
Pass arguments through to your script
Anything after -- goes straight into your script's sys.argv:
pyrun . -- --input data.csv --verbose
Inside main.py, sys.argv[1:] would be ['--input', 'data.csv', '--verbose'],
exactly as if you'd run python3 main.py --input data.csv --verbose directly.
Check the version or see all options
pyrun --version
pyrun --help
How it works
py-modu is intentionally simple under the hood, no magic, no config
files, no daemon process.
- Discovery: it lists
.pyfiles in the target directory and applies themain.py→app.py→run.py→ single-file rule described above. - Execution: it runs the chosen file as a real subprocess
subprocess.run([sys.executable, target_file, *your_args])not animport. This matters for two reasons:if __name__ == "__main__":in your script behaves exactly as it would if you'd run it directly.- Your script's exit code is passed back through as
pyrun's own exit code, sopyrun .works correctly inside CI pipelines and shell scripts that check$?.
- Interpreter resolution: it uses
sys.executable, i.e. whichever Python interpreter is currently active. Run it inside an activated virtualenv and your project's dependencies are available exactly as if you'd typedpython3 file.pyyourselfpy-modudoesn't create, manage, or need to know about virtual environments at all.
Comparison with Go
| Go | py-modu | |
|---|---|---|
| Run current project | go run . |
pyrun . |
| Run a specific file | go run script.go |
pyrun script.py |
| Entry point convention | package main, func main() |
main.py, app.py, or run.py |
| Pass arguments | go run . -- args |
pyrun . -- args |
| Ambiguous entry point | compile error | explicit message, asks you to disambiguate |
FAQ
Why not just use python3 script.py?
You still can py-modu doesn't replace anything or change how Python
itself runs files. It just removes the need to remember or type the exact
filename, the way go run . does for Go. It's a small quality-of-life
tool for people who bounce between a lot of small scripts and projects.
Does it work with virtual environments?
Yes — activate your venv first, then run pyrun . as normal. It uses
whatever interpreter is currently active.
Does it manage dependencies, like poetry or uv?
No. py-modu only decides which file to run it has no opinion about
package management. Use it alongside pip, poetry, uv, or whatever
you already use.
What if I have both main.py and app.py?
main.py wins the check order is fixed and always favors main.py
first, matching the Go convention this tool is modeled on.
Can I use it in a Makefile or CI pipeline?
Yes. Because pyrun runs your script as a real subprocess and forwards
its exit code, pyrun . behaves like any other command for the purposes
of &&, set -e, or a CI step's pass/fail status.
Troubleshooting
| Problem | Fix |
|---|---|
pyrun: command not found after install |
Open a new terminal, or run pipx ensurepath again |
Error: no Python files found |
You're not in the directory you think you are — check pwd |
Error: found multiple Python files ... and none is named main.py/app.py/run.py |
Rename your entry file to one of those three, or run it explicitly: pyrun yourfile.py |
| Wrong Python version / missing packages when running | Make sure your virtualenv is activated before running pyrun . |
pip install py-modu fails with "externally-managed-environment" |
Use pipx install py-modu instead, or install inside a venv |
Development
git clone https://github.com/maxchichar/py-modu.git
cd py-modu
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest
Project layout:
py-modu/
├── src/py_modu/
│ ├── __init__.py # exposes main() and __version__
│ ├── __main__.py # enables `python -m py_modu`
│ └── core.py # entry-point discovery + execution logic
├── tests/
│ └── test_core.py
├── pyproject.toml
└── README.md
Contributing
Issues and pull requests are welcome. Before opening a PR:
pip install -e ".[dev]"
pytest
Please keep changes focused py-modu is intentionally small in scope.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file py_modu-0.1.1.tar.gz.
File metadata
- Download URL: py_modu-0.1.1.tar.gz
- Upload date:
- Size: 8.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a3bd8b30e2f62ec192263ca37af8799304b1de540bdae0aff0e6a6ce485d392c
|
|
| MD5 |
b1a1d19b2928e13924b8e324b436a8d5
|
|
| BLAKE2b-256 |
93fb8f0d1bd5eedf1444c41c285e4e4a35ec1f1c108c53dd57aa4ed2d14492c1
|
File details
Details for the file py_modu-0.1.1-py3-none-any.whl.
File metadata
- Download URL: py_modu-0.1.1-py3-none-any.whl
- Upload date:
- Size: 7.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
487f63ee54a86d8af7e172ae2ba91060151dc5763305bbce1064e91d4fa085be
|
|
| MD5 |
e80e4a9c2cfe659dfc6215aff05b0231
|
|
| BLAKE2b-256 |
c573ac3edbaf9802166e7ec1d9cb81a7db45efcbfa9ab932e64bf3c8fa50552e
|