I want to make my program pluggable. I'd like to use the setuptools way of doing so, using eggs.
I've been able to make a plugin to provide an alternate class for some functionality, and I can use it.
I would like to select the class to use at runtime; either the one in my core module or in any of the plugins. I'd like to use the pkg_resources way of querying for these classes:
for entrypoint in pkg_resources.iter_entry_points("myapp.myclasses"):
How can I create an EntryPoint object for my class in core, and register it, so that iter_entry_points will return it the same way as for my .egg plugin class ?
pkg_resources.iter_entry_points
lists any entry points by the given name in any egg, including your own package. Thus, if your entry_points
entry in setup.py
lists the following, and you've run setup.py develop
to generate the metadata, your own entry point will be included:
[myapp.myclasses]
classentry1 = myapp.mymodule:myclassname1
classentry2 = myapp.mymodule:myclassname2
The Babel project does exactly this; in it's setup.py
it lists entry points for both babel.checkers
and babel.extractors
, and these are looked up by babel.messages.checkers:_find_checkers
and babel.messages.extract:extract
, respectively.
If you do not want to have a setup.py
file (which is easy enough to create and/or generate from a template), then you are facing having to alter the internal state of pkg_resources.working_set
instead:
working_set.entries
is a list of eggs. You'll have to add the path of your project's top-level directory to this.working_set.entry_keys
is a mapping from paths in entries
to a list of package names. Add your project as `working_set.entry_keys[path] = ['package.name']working_set.by_key
is a mapping from package name to a pkg_resources.Distribution
instances. You'll need to create a Distribution
instance and store it under your package name: working_set.by_key['package.name'] = yourdistribution
.For your purposes the Distribution
instance can be fairly sparse, but I'd include at least the project name. You'll need to have a entry-point map on it though:
yourdistribution = Distribution(project_name='package.name')
yourdistribution._ep_map = {'myapp.myclasses', {
'classentry1': entrypointinstance_for_classentry1,
'classentry2': entrypointinstance_for_classentry2,
}}
The internal structure _ep_map
is normally parsed on demand from the egg-info metadata.
Please note that this is relying entirely on undocumented internal data structures that can change between versions. In other words, you are on your own here. I'd generate a setup.py
file instead, and run python setup.py develop
to generate the egg metadata instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With