Package: cincodex
cincodexCincodex is a simple, flexible, and unopinionated plugin system for Python projects. Cincodex is designed for both applications and libraries that wish to be extensible at runtime. Plugins can be any Python object including a class, a function, or an instance of an object. The following is a very basic example showing that the application creates a Codex, which is the plugin system, then discovers all available plugins within the./pluginsdirectory, and the./plugins/foo/bar.pysource file registers a function with the codex.# app.pyfromcincodeximportCodex,register_codexcodex=Codex('my_app')register_codex(codex)# discover all pluginscodex.discover_plugins('./plugins')# after this, the `foo.bar` plugin is available and we can call it.plugin=codex.get('foo.bar')plugin()# 'Hello world!'# ./plugins/foo/bar.pyfromappimportcodex@codex.register@codex.metadata(id='foo.bar')deffoo_bar_plugin():print('Hello world!')Cincodex has been tested on Linux and Windows systems but should support other operating systems as well. Cincodex supports Python 3.10 and newer.InstallationpipinstallcincodexFeaturesCincodex is designed to work with multiple Python packages within a single project. For example, an application can have its own plugin system a multiple dependencies can have their own plugin system and they will not interfere with each other.Cincodex automatically discovers and registers all available plugins within one or more root directories.The method of finding and loading plugins and registering their metadata are all extensible within cincodex. Easily customize the plugin metadata and change how plugins are loaded.Theimportstatement and machinery continues to work properly for discovered plugins, supporting both relative and absolute imports within plugins.A plugin is anything: a class, a function, or an object instance. Cincodex works seamlessly with all plugin types.A more complete exampleThe following is a cincodex plugin system where:A plugin base class that all plugin must implement. Each plugin says "hello" in a different language.A custom plugin metadata classLoading plugin from multiple directorieshello.pyThis module defines the plugin metadata, plugin base class, and codex.## hello.py#fromcincodeximportCodex,PluginMetadata,register_codex# First we create a custom plugin metadata class, inheriting from cincodex `PluginMetadata`classHelloPluginMetadata(PluginMetadata):def__init__(self,id:str,*,lang:str):super().__init__(id)self.lang=lang# Our plugin system will be class based. So, next we create a base class that all plugins must# inherit from and implement the `say_hello` method.classHelloPlugin:# __plugin_metadata__ is always set by cincodex with the call to `Codex.register`. We include# the field here so that the IDE / type checking knows that __plugin_metadata__ is a class# attribute.__plugin_metadata__:HelloPluginMetadatadefsay_hello(self)->None:raiseNotImplementedError()# Create and register the codexcodex:Codex[type[HelloPlugin],HelloPluginMetadata]=Codex('hello',HelloPluginMetadata)register_codex(codex)builtin_plugins/english.pyDefines a plugin that says "hello" in English.## ./builtin_plugins/english.py#fromhelloimportHelloPlugin,codex@codex.register@codex.metadata('lang.english',lang='en-us')classEnglishHello(HelloPlugin):defsay_hello(self):name=input('What is your name? > ')print('Hello,',name)./contrib_plugins/german.pyDefines a plugin that says "hello" in German.## ./contrib_plugins/german.py#fromhelloimportHelloPluginfromcincodeximportget_codex# We registered the codex so we don't technically need to import itcodex=get_codex('hello')@codex.register@codex.metadata('lang.german',lang='de')classGermanLang(HelloPlugin):defsay_hello(self):name=input('Wie heissen sie? > ')print('Guten tag,',name)app.pyApplication script that discovers both builtin and contributed plugins and runs each sequentially.## app.py#if__name__=='__main__':fromhelloimportHelloPluginMetadata,codex# Discover builtin and contributed pluginscodex.discover_plugins('./builtin_plugins')codex.discover_plugins('./contrib_plugins')# iterate over all available pluginsforplugin_clsincodex:# `plugin_cls` is a type[HelloPlugin]# get the plugin metadatametadata=HelloPluginMetadata.get(plugin_cls)# our codex registers plugin *classes*, so we need to first instantiate an instance of this# pluginplugin=plugin_cls()print(f'Running plugin:{metadata.id}(lang:{metadata.lang})')plugin.say_hello()print()In this example, runningpython app.pywill output the following:$ python app.py

Running plugin: lang.english (lang: en-us)
What is your name? > Adam
Hello, Adam

Running plugin: lang.german (lang: de)
Wie heissen sie? > Wolfgang
Guten tag, WolfgangThis example is available in theexample_appdirectory.API DocumentationCincodex API documentation is generated by Sphinx and hosted onRead the Docs. The API documentation includes more detailed and complex examples and information on how to extend cincodex.LicenseCincodex is licensed under the MIT permissive license.