Reputation: 2028
I would like to distribute a python package using poetry and make it executable as a cli, just like black
, pipenv
, poetry
, flake8
and friends.
Example usage would be:
python -m my-package [args]
So far I have been succesful in building a wheel and installing it on a docker image using the following configuration:
pyproject.toml
[tool.poetry]
name = "my-package
version = "0.1.0"
description = "A cli tool"
authors = []
packages = [
{ include = "src/main.py" },
]
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
Build commands:
poetry build -f wheel
poetry export -o dist/requirements.txt
Docker image:
FROM python:3.8-slim as base
COPY dist/requirements.txt /requirements.txt
RUN pip install --no-cache-dir --upgrade -r /requirements.txt
ARG APP_VERSION
COPY dist/my-package-$APP_VERSION-py3-none-any.whl .
RUN pip install --no-cache-dir --no-deps my-package-$APP_VERSION-py3-none-any.whl
Built using the following command:
docker build -t my-package:latest --build-arg APP_VERSION=$(poetry version -s) .
And run using the following command:
docker run -it my-package:latest /usr/local/bin/python -m my-package
Which results in:
/usr/local/bin/python: No module named my-package
While locally I can execute it by doing:
cd src
python main.py [args]
How can I install/package a wheel to make it executable as a cli?
Additional logs:
╰─ docker build -t my-package:latest --build-arg APP_VERSION=0.1.0 .
[+] Building 1.9s (10/10) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 353B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/python:3.8-slim 0.9s
=> [1/5] FROM docker.io/library/python:3.8-slim@sha256:0f6d6953c6612786ed05aaf1de7151dbbb0cea6bc83687040d5f15377be7ef64 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 6.12kB 0.0s
=> CACHED [2/5] COPY dist/requirements.txt /requirements.txt 0.0s
=> CACHED [3/5] RUN pip install --no-cache-dir --upgrade -r /requirements.txt 0.0s
=> CACHED [4/5] COPY dist/my-package-0.1.0-py3-none-any.whl . 0.0s
=> [5/5] RUN pip install --user --no-cache-dir --no-deps my-package-0.1.0-py3-none-any.whl 0.9s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:4f41ba75b6bbacd33d64a06eed921c1ca8aeca55e9340536b9208fcb694826dd 0.0s
=> => naming to my-package:latest 0.0s
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
'package' took 2.9720 sec
╰─ docker run -it my-package:latest /bin/bash
root@f61d2505e762:/# python -m my-package
/usr/local/bin/python: No module named my-package
root@f61d2505e762:/# python -m my-package
/usr/local/bin/python: No module named my-package
root@f61d2505e762:/# pip freeze > req.txt
root@f61d2505e762:/# cat req.txt
certifi==2021.10.8
charset-normalizer==2.0.9
idna==3.3
my-package @ file:///my-package-0.1.0-py3-none-any.whl
psycopg2-binary==2.9.2
requests==2.26.0
urllib3==1.26.7
Upvotes: 8
Views: 11234
Reputation: 15202
Running a python application via python -m app
uses a different mechanism compared to having a command app
.
Let's assume the following project structure:
demo-cli
├── demo_cli
│ ├── __init__.py
│ ├── __main__.py
│ └── cli.py
├── poetry.lock
└── pyproject.toml
pyproject.toml
:
[tool.poetry]
name = "demo-cli"
version = "0.1.0"
description = ""
authors = ["finswimmer <[email protected]>"]
packages = [{include = "demo_cli"}]
[tool.poetry.dependencies]
python = "^3.10"
[tool.poetry.scripts]
demo-cli = "demo_cli.cli:say_hello"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
cli.py
:
def say_hello():
print("Hello")
__main__.py
:
from demo_cli import cli
cli.say_hello()
This part in the pyproject.toml
give us a command demo-cli
by defining the method which should be executed:
[tool.poetry.scripts]
demo-cli = "demo_cli.cli:say_hello"
The content of the __main__.py
is triggered on a python -m demo_cli
. So we need to add the method call there. More detailed information can be found here.
Upvotes: 6