coherent-oss / coherent.build

A zero-config Python project build backend
5 stars 0 forks source link

Add support for entry points #10

Closed jaraco closed 3 weeks ago

jaraco commented 3 weeks ago

Projects need some way to declare entry points. I can think of at least a couple of ways to solve this need.

Consider a project called ns.lib with modules fixtures and cli and a couple of entry points defined in it:

[pytest11]
pytest-plugin = ns.lib.fixtures

[console_scripts]
abc = ns.lib.cli:main

Simply supply the metadata file

At first, I was thinking of simply asking users to add a (meta)/entry_points.txt file and having that file just be copied to the metadata during the build.

This approach benefits from simplicity of implementation. The file would simply be copied from the source (meta) folder to the package's metadata. No new syntax is needed. The main downside is this introduces an additional file that's static metadata in the repo. Another downside is the user has to hard-code names in the package (ns, lib, fixtures, cli) and keep those names in sync.

Special attribute definition

Entry points could also be declared through inline variables in the code. Users would add something like the following to the modules:

# fixtures.py
__entry_points__ = {"pytest11.pytest-plugin": ""}
# or
__entry_points__ = {"pytest11.pytest-plugin"}
# cli.py
__entry_points__ = {"console_scripts.abc": "main"}

Each key represents the group and name of the entry point. The value represents the optional object.attr portion of the definition. The builder would create the entry_points.txt file by discovering these attributes in the modules at build time. These attributes would be read statically.

Markers

Similar to the special attributes, entry points could be declared using markers, similar to pytest markers, where a module or object or an object's attr could be "marked" as an entry point, and the builder would examine the runtime state of the package to discover entry points. Something like:

# fixtures.py

markers = coherent.build.entry_point(group="pytest11", name="pytest-plugin")
# cli.py

@coherent.build.console_script(name="abc")
def main(...):
    ...

A big advantage to this approach is it provides a rich way to describe the entry point. Another advantage is it links callables directly to their name ("main" is specified just once).

Two big disadvantages:

jaraco commented 3 weeks ago

I think I'm going to start by implementing option 1 (Simply supply the metadata file), because that's the most straightforward and least controversial. I may add support for option 2 or something similar later.