How to define a script in the venv/bin dir with pyproject.toml (in hatch or any other wrapper)

1k Views Asked by At

Im unsure about the new doc on packaging with hatch and wonder if someone worked out how to define a script in a pip installable package. So in short I need to be able to direct python -m build to make a package with open_foo_bar.py as in the example, install into the (virtual env)/bin dir.

my package looks like this (after a python -m build step that generated dist dir)

pypi_package/
├── bin
│   └── open_foo_bar.py
├── dist
│   ├── foo-0.1.0-py3-none-any.whl
│   └── foo-0.1.0.tar.gz
├── pyproject.toml
├── README.md
└── test_pkg
    ├── foolib.py
    └── __init__.py

Im trying to get bin/open_foo_bar.py installed into the $(virtual env)/bin instead it installs it into the site-packages/bin

./lib/python3.10/site-packages/bin/open_foo_bar.py

myproject.toml is

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


[project]
name = "FOO"
version = "0.1.0"
authors = [
  { name="Mr Foo", email="[email protected]" },
]
description = "a Foo bar without drinks"
readme = "README.md"
requires-python = ">=3.8"
classifiers = [
    "Programming Language :: Python :: 3",
    "License :: OSI Approved :: MIT License",
    "Operating System :: OS Independent",
]

dependencies = [
  'requests'
]

[project.urls]
"Homepage" = "http://footopia.s/howto_foo"

This used to be easy by defining the scripts section in setup.py

setuptools.setup(
   ...
   scripts ['bin/script1'],
   ... 
)
1

There are 1 best solutions below

2
aqua On BEST ANSWER

In theory the Python spec defines how entrypoints and scripts are supposed to be handled.

Hatch has chosen to do it a bit differently, and I'm not sure if this is even considered best-practice. This approach combines Forced Inclusion with Metadata Entrypoints/CLI.

Here's how you might achieve your desired outcome:

  1. Add a main or run function to your script open_foo_bar.py
  2. Force hatch to make your script appear as part of the package once it is installed. You would add the lines:
[tool.hatch.build.targets.sdist.force-include]
"bin/open_foo_bar.py" = "test_pkg/open_foo_bar.py"

[tool.hatch.build.targets.wheel.force-include]
"bin/open_foo_bar.py" = "test_pkg/open_foo_bar.py"
  1. Create an entrypoint using the scripts section:
[project.scripts]
open_foo_bar = "test_pkg.open_foo_bar:main"

When you install the package, open_foo_bar should be in your virtualenv bin/ directory, and it will call your main function within open_foo_bar.py, which will have been moved to reside within your package in site-packages.

It's a hacky solution, but there doesn't appear to be a 1:1 feature for supporting arbitrary scripts. Hatch actually does mention the usage of an Entrypoints section, but it's catered towards plugin management.