# Remove support for entry-points for all supported series

**URL:** https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846
**Category:** Organisation
**Created:** [January 5, 2024, 4:28pm UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846 "2024-01-05T16:28:12Z")
**Posts on this page:** 14
**Page:** 1

<div class="post-metadata">

### Author: ![ced](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/ced/32/1237_2.png) [@ced](https://discuss.tryton.org/u/ced)
#### Post date: [January 5, 2024, 4:28pm UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846/1 "2024-01-05T16:28:14Z")

</div>

I would like to remove the support for module declaration from entry-points and rely only on the path `trytond.modules.<name>`.

Supporting this feature is a real burden and painful due to the complexity of the Python packaging.  
We got issues like [Entrypoint modules are being loaded twice (#12884) · Issues · Tryton / Tryton · GitLab](https://bugs.tryton.org/issue12884) and [Tryton 7.0 does not find module installed via entrypoints (#12900) · Issues · Tryton / Tryton · GitLab](https://bugs.tryton.org/issue12900).

I never used the entry-points to declare modules but only installation in `trytond.modules.*` (which works also in editable mode).

I would like to know how many people are actually using entry-points and why?

---

<div class="post-metadata">

### Author: ![ced](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/ced/32/1237_2.png) [@ced](https://discuss.tryton.org/u/ced)
#### Post date: [January 5, 2024, 7:11pm UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846/2 "2024-01-05T19:11:36Z")

</div>

Indeed entry points are needed for installation in editable mode.  
So we will have to deal with it ☹

---

<div class="post-metadata">

### Author: ![Dan](https://discuss-cdn.tryton.org/letter_avatar_proxy/v4/letter/d/eada6e/32.png) [@Dan](https://discuss.tryton.org/u/Dan)
#### Post date: [February 15, 2024, 4:06pm UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846/3 "2024-02-15T16:06:43Z")

</div>

I am using entrypoints because I don’t package my modules whatsoever. I lay python sources in a src folder which is prepended to a PYTHONPATH, then a

```auto
# src/mypackage-1.2.3.dist-info/entry-points.txt
[trytond.modules]
mytrytondmodule = my.python.module

```

will make my sources available as trytond modules.

This has been the aftermath of many years struggling with the legacy setup.py files from the Tryton ecosystem causing multiple issues to pipenv and poetry resolvers and venv managers.

Eventually, I discovered I didn’t need to package the modules at all, which was the comon practice in my organisation for non-tryton applications, and I was happy everafter (until the issues you linked rose).

I had gone as far as prototyping a Hatch plugin ([GitHub - pypa/hatch: Modern, extensible Python project management](https://github.com/pypa/hatch) plugin) that could replace all those setup.py files, but abandoned that initiative because I never felt Tryton has any interest in keeping up with the Python packaging evolution. I still believe it is doable.

BUT

This post kind of startled me. Like, how can a project that aims for modularity consider removing the only module registration mechanism? I’d expect moves in the quite opposite direction!

E.g. pytest plugins can be made discoverable either via the `pytest11` entrypoint (e.g. [pytest-trytond/setup.cfg at 30afd1f9030ba31d8033c832c18574a3a12c563b · calidae/pytest-trytond · GitHub](https://github.com/calidae/pytest-trytond/blob/30afd1f9030ba31d8033c832c18574a3a12c563b/setup.cfg#L38C1-L38C9)), a `PYTEST_PLUGINS` environment variable or some simple attributes in a `pyproject.toml` file. Requiring all plugins to be package under a `pytest.contrib` module of sorts would be rather weird. Same goes for Tryton IMHO.

---

<div class="post-metadata">

### Author: ![johbo](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/johbo/32/2493_2.png) [@johbo](https://discuss.tryton.org/u/johbo)
#### Post date: [March 5, 2024, 8:02am UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846/4 "2024-03-05T08:02:10Z")

</div>

I am using the entrypoints mechanism to register plugins with trytond. Main reason is that I was not able to have my code inside of `trytond.modules` without trouble. My guess is that this is because it does not support to be a namespace package. So I ended up putting my code into a separate package and registering it via the entrypoint mechanism.

The main issue was with the development setup. In a regular installation I would not have the issue and be able to throw it all into `trytond.modules`.

In general I agree with the pytest example from the post above, it would be weird if tryton or any other project would impose package names upon me.

---

<div class="post-metadata">

### Author: ![johbo](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/johbo/32/2493_2.png) [@johbo](https://discuss.tryton.org/u/johbo)
#### Post date: [March 7, 2024, 8:34am UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846/5 "2024-03-07T08:34:06Z")

</div>

> [@Dan](#):
>
> I had gone as far as prototyping a Hatch plugin ([GitHub - pypa/hatch: Modern, extensible Python project management](https://github.com/pypa/hatch) plugin) that could replace all those setup.py files, but abandoned that initiative because I never felt Tryton has any interest in keeping up with the Python packaging evolution. I still believe it is doable.

Actually the topic did stick with me and I just realized that I have defined my tiny customization module completely different than the typical trytond module is defined and used a `pyproject.toml` instead:

```auto
[project]
name = "bv-tryton-meta-botech"
version = "0.8.0"
authors = [
  { name="Johannes Bornhold", email="joh@bo-tech.de" },
]
description = "Meta package with Tryton adjustments for the use at bo-tech."
readme = "README.md"
requires-python = ">=3.8"
classifiers = [
    "Programming Language :: Python :: 3",
    "License :: OSI Approved :: MIT License",
    "Operating System :: OS Independent",
]

[project.entry-points."trytond.modules"]
meta_botech = "bv.tryton.meta_botech"

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

[tool.hatch.build.targets.wheel]
packages = ["src/bv"]

```

Have to admit that I am not too deep into the recent developments of packaging in Python, still, so far this works out just fine thanks to the entrypoint support.

@ced would you mind sharing a few hints about the complexities / issues around the entrypoint support? Just wondering if there may be other options to reduce the maintenance burden.

---

<div class="post-metadata">

### Author: ![ced](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/ced/32/1237_2.png) [@ced](https://discuss.tryton.org/u/ced)
#### Post date: [March 7, 2024, 8:39am UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846/6 "2024-03-07T08:39:32Z")

</div>

The complexity is that there are 2 ways for trytond to load a module.

---

<div class="post-metadata">

### Author: ![htgoebel](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/htgoebel/32/1256_2.png) [@htgoebel](https://discuss.tryton.org/u/htgoebel)
#### Post date: [March 7, 2024, 10:11pm UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846/7 "2024-03-07T22:11:09Z")

</div>

> [@johbo](#):
>
> My guess is that this is because [trytond.modules] does not support to be a namespace package.

Yes, indeed this is the reason.

Since I was bugged again by not being able to I load a module in certain setups, I spend quite some time to analyze the root cause — which is a combination of different issues:

- Official Tryton modules define themself as Python package `trytond.modules.xxx` and provide an entry-point of type `trytond.module` pointing to this very package. Many third-party modules I’ve seen follow this convention (although the distribution package might have different a name like `mycoop-xxx`). AFAIK this is the case ever since.
- Anyhow, `trytond.modules` is _not_ a namespace-module (since there is an ` __init__.py` and this does not set up a namespace either). Which means: Python will search `trytond.modules.xxx` in the same directory as the file `trytond.modules. __init__.py`. This of course will fail except if the package was linked or copied there.
- In Tryton 6.x, trytond implemented [its own mechanisms to load the entry-point](https://foss.heptapod.net/tryton/tryton/-/blob/branch/6.0/trytond/trytond/modules/ __init__.py#L57-71) — and there even was a comment on why `ep.load()` can not be used. AFAIR this worked acceptable well — except of the drawback that the name of the directory, the module lives in must match the name of the module. (The later inhibits e.g. “src layout”.)
- In Tryton 7, up to trytond 7.0.5, this was changed to [import modules using `importlib.import_module()` with hard-coded module name prefix `trytond.modules.`](https://foss.heptapod.net/tryton/tryton/-/commit/d29ec7a37dca29e7e54a2af4ae6398a2fdf34478). This inhibited using different package names.
- trytond 7.0.6 changed to using [`ep.load()` if an entry-point was found, otherwise using `importlib.import_module(f'{MODULES_GROUP}.{name}')`](https://foss.heptapod.net/tryton/tryton/-/blob/branch/7.0/trytond/trytond/tools/misc.py#L39-44). Bad luck: `ep.load()` (almost) first of all uses `importlib.import_module()` to load the modules — which for official Tryton modules will fail for the reasons explained above.
- Now, as a work-around it was [documented to install editable packages using `--use-pep517`](https://foss.heptapod.net/tryton/tryton/-/merge_requests/957/diffs) - which works: This option will create a file like ` __editable___ trytond_xxx_7_0_0_finder.py`, which in effect makes `trytond.modules` a namespace package 🙂

Conclusion: IMHO for 3rd-party modules the best solution is to use an entry-point and a custom package-namespace.

Anyhow, this yields to another issue: When swapping package `mycoop-party-superextensions` by `yourcorp-party-superextensions`, tests of modules using module `….party.superextensions` would need to ba changed — jsut because the implementation changed.

There are three solutions I see:

1. Make `trytond.modules` a real namespace package — not good since this would require changes to all modules using functions from `trytond.modules`.
2. Introduce another “modules” namespace, e.g. `trytond.modules.3rd_party`, `trytond.3rd_party` — this would require changes to 3rd-party modules.
3. Make `trytond.modules` extend its own ` __path__ ` by collecting the paths of all `trytond.module` entry-points — anyhow I did not find a reasonable way to get these values from `ep.dist`.

---

<div class="post-metadata">

### Author: ![htgoebel](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/htgoebel/32/1256_2.png) [@htgoebel](https://discuss.tryton.org/u/htgoebel)
#### Post date: [March 7, 2024, 10:25pm UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846/8 "2024-03-07T22:25:21Z")

</div>

Since all official modules provide entry-points, too, the code could be stripped down to only use entry-points. (And also use `importlib.resources.files()` for accessing the files.)

---

<div class="post-metadata">

### Author: ![htgoebel](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/htgoebel/32/1256_2.png) [@htgoebel](https://discuss.tryton.org/u/htgoebel)
#### Post date: [March 7, 2024, 10:28pm UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846/9 "2024-03-07T22:28:27Z")

</div>

> [@Dan](#):
>
> I had gone as far as prototyping a Hatch plugin ([GitHub - pypa/hatch: Modern, extensible Python project management](https://github.com/pypa/hatch) plugin) that could replace all those setup.py files, but abandoned that initiative because I never felt Tryton has any interest in keeping up with the Python packaging evolution. I still believe it is doable.

This is interesting, since I thought about such thing, too. Meanwhile I implemented [Tryton Community / setuptools · GitLab](https://foss.heptapod.net/tryton-community/setuptools) (which still relies on setuptools, though).

---

<div class="post-metadata">

### Author: ![Dan](https://discuss-cdn.tryton.org/letter_avatar_proxy/v4/letter/d/eada6e/32.png) [@Dan](https://discuss.tryton.org/u/Dan)
#### Post date: [March 12, 2024, 10:44am UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846/10 "2024-03-12T10:44:50Z")

</div>

> [@htgoebel](#):
>
> This is interesting, since I thought about such thing, too. Meanwhile I implemented [Tryton Community / setuptools · GitLab](https://foss.heptapod.net/tryton-community/setuptools) (which still relies on setuptools, though).

There is nothing wrong with setuptools per se, only with the deprecated implicit `setuptools.build_meta: __legacy__ ` fallback. For a pure PEP-517 resolver/installation frontend trying to circumvent that backend can easily go wrong.

Ultimately `hatch`, even from my 0-knowledge about it, felt much easier and natural to extend than the actual PEP-517 `setuptools.build_meta` backend, and did not feature tons of complexities accumulated throughout the Python history that were anyway unnecessary to package a pure python trytond module: we just need to build metadata mixing tryton.cfg and pyproject.toml and providing some sensible defaults!

> [@htgoebel](#):
>
> There are three solutions I see:
> 
> 1. Make `trytond.modules` a real namespace package — not good since this would require changes to all modules using functions from `trytond.modules`.
> 2. Introduce another “modules” namespace, e.g. `trytond.modules.3rd_party`, `trytond.3rd_party` — this would require changes to 3rd-party modules.
> 3. Make `trytond.modules` extend its own ` __path__ ` by collecting the paths of all `trytond.module` entry-points — anyhow I did not find a reasonable way to get these values from `ep.dist`.

1. While very breaking code-wise, a straightforward `trytond.modules.import_module("mymod")` was an easy replacement for `from trytond.modules import mymod` for me when I needed it.
2. I would understand reluctance against that since we would have to maintain yet an additional module loading system.
3. I have mixed feelings with this idea. Generally I’d be against tampering that, but importlib replacements for distutils entrypoints might have a nicer interface that could make easier that kind of hacking.

> [@htgoebel](#):
>
> Since all official modules provide entry-points, too, the code could be stripped down to only use entry-points. (And also use `importlib.resources.files()` for accessing the files.)

This! @ced why isn’t this the present solution? Which are the pitfalls or blockers? Can we work towards this?

---

<div class="post-metadata">

### Author: ![ced](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/ced/32/1237_2.png) [@ced](https://discuss.tryton.org/u/ced)
#### Post date: [March 12, 2024, 10:48am UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846/11 "2024-03-12T10:48:29Z")

</div>

> [@Dan](#):
>
> why isn’t this the present solution? Which are the pitfalls or blockers? Can we work towards this?

This prevent to work without installation.

But also `importlib.resources.as_file()` may not provide direct access to the file but to a temporary copy which would be a performance killer.

---

<div class="post-metadata">

### Author: ![htgoebel](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/htgoebel/32/1256_2.png) [@htgoebel](https://discuss.tryton.org/u/htgoebel)
#### Post date: [March 15, 2024, 9:44am UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846/12 "2024-03-15T09:44:05Z")

</div>

> [@ced](#):
>
> But also `importlib.resources.as_file()` may not provide direct access to the file but to a temporary copy which would be a performance killer.

`as_file()` indeed uses a temporary copy. Anyhow `files()` (which is what I proposed) returns a `PosixPath` instance. Thus no copy and no performance impact.

---

<div class="post-metadata">

### Author: ![ced](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/ced/32/1237_2.png) [@ced](https://discuss.tryton.org/u/ced)
#### Post date: [March 15, 2024, 10:54am UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846/13 "2024-03-15T10:54:23Z")

</div>

But tools and library are expecting a file not a `Traversable` which a subset of method of `Path`.

---

<div class="post-metadata">

### Author: ![htgoebel](https://discuss-cdn.tryton.org/user_avatar/discuss.tryton.org/htgoebel/32/1256_2.png) [@htgoebel](https://discuss.tryton.org/u/htgoebel)
#### Post date: [March 22, 2024, 12:21pm UTC](https://discuss.tryton.org/t/remove-support-for-entry-points-for-all-supported-series/6846/14 "2024-03-22T12:21:22Z")

</div>

I admit that the documentation of `importlib.resources` is not a master piece of documentation, esp. given the complexity of the import machinery.

When testing this using code like the one below, I always get a full PosixPath for non-zipped packages:

```auto
import importlib.resources
files = importlib.resources.files('trytond.modules.company')
print(repr(files))

```

Thus it would be interesting to know in which setup you experience not getting a PosixPath. (I can imagine that dev-mode might not work if installed using zipped eggs, anyhow this could be worked around easily.)
