Alternative implementations of python / setuptools I / O points (extensions) in other languages ​​/ applications

Although this question has a python backend, the question is not related to python itself, but rather about extension mechanisms and registration / search order for plugins.

In python, the concept of entrypoints was introduced by setuptools and is tied to the metadata of installed python distributions (called packages on other packaging systems).

In my opinion, one of the functions provided by the inputs is to allow the application to determine where others can insert things, so any application that wants to use an entry point can get a list of registered classes / functions there. Take an example:

  • Foo defines the entrypoint "entrypoint1" and searches for plugins registered under this name.
  • The bar registers the called ( Bar.callable ) at the entrypoint1 entry point.
  • Any python script can then list Bar.callable as one of the registered calls for "entrypoint1".

Using setuptools, applications register entry points during installation, and the information is stored in metadata associated with a package called .egginfo (which usually contains information about the distribution name, its dependencies, and some other packaging metadata).

I have the feeling that package metadata is not a good place to store such information, because I don’t understand why this information is tied to the package.

I am interested to learn about such entrypoints / extensions / plugins functions in other languages, and especially if the concept is tied to metadata and packaging or not. And the question is ...

Do you have any examples that I should pay attention to? Could you explain why the design was chosen in this way?

Can you see different ways to solve this problem? Do you know how this problem has already been solved in different tools? What are the disadvantages and advantages of the current python implementation over others?




What i have found so far

I have found in different projects, a way to create and distribute "plugins" that are especially concerned with "how we make plugins."

For example, libpeas (the gobject plugin structure) defines a set of ways to extend the default behavior by specifying plugins. Although this is interesting, I'm just interested in the "registration and discovery" (and, ultimately, downloading) parts of it.

Here are some of my findings:

Libpeas defines its own metadata file (* .plugin), which stores information about the type of called (different languages ​​may have different plugins). The main information here is the name of the module to load.

Maven has a project document containing information on how material is managed there. Maven manages plugins with their dependencies and metadata, so it seems like an interesting place to look for how they implemented things .

As stated in their documentation, maven plugins use annotations ( @goal ) for classes, which are then used to find all plugins registered with a specific @goal . Although this approach is possible in static languages, it is not in interpreted languages, since we only know which all possible classes / calls at one given point in time can change.

Mercurial uses a central configuration file ( ~/.hgrc ) containing the mapping of the plugin name to the path that it can find.




A few more thoughts

Although this is not the answer to this question, it is also interesting how setuptools entry points are implemented and how they are compared in terms of performance using mercurial ones.

When you request a specific entry point using setuptools, all metadata is read at runtime and the list is created in this way . This means this reading may take some time if you have many python distributions in your way. Mercurial, on the other hand, hardcodes this information into a single file, which means that you must specify the full path to your callee, and then registered calls are not “detected”, but “read” directly from the configuration file. This allows you to get a finer configuration on what should be available and what should not be and it seems faster.

On the other hand, since the python path can be changed at runtime, this means that called calls provided in this way must be checked on the path to know whether they should be returned or not in all situations.




Why entry points are currently tied to packaging

It's also interesting to understand why entry points are tied to packaging in setuptools. The main reason is that it seems useful that python distributions can register part of themselves as an extension of the entry point during installation: then the installation also allows you to register entry points: there is no need for an additional registration step.

Although this works pretty well in most cases (when python distributions are actually installed), this does not happen when they are not installed or simply not packaged. In other words, from what I understand, you cannot register an entry point at runtime without a .egg-info file.

+48
python plugins packaging
Aug 13 '11 at 15:58
source share
3 answers

as one of the possible ideas, you can take a look at the OSGi concept, which is used to manage the Eclipse plugin system. This may be unnecessary for your particular case, but certainly a source of inspiration.

+1
Oct 20 '13 at 20:48
source share

As you started talking about the implementation / processing of the programming language, it may be worth noting that recently gcc got the capabilities of the plugin .

0
Aug 19 '11 at 13:52
source share

In python, there is "PYTHONPATH", which is an environment variable that determines where the "import" will look at code snippets from.

if you have

  PYTHONPATH=/home/user/tests 

all the tearing in

  /home/user/tests 

have their own

  __init__.py 

which lists the modules that can be found there.

For example, in

  /home/user/tests/__init__.py 

you have

  __all__ = ["computeSomething", "computeSomthingElse"] 

referring to existing files:

  /home/user/tests/computeSomething.py /home/user/tests/computeSomethingElse.py 

then in python you can immediately

  import computeSomethingElse 

or

  from computeSomethingElse import myObjectFromSomethingElse. 

Hope this helps.

0
Aug 23 2018-11-11T00:
source share



All Articles