I have a series of Python Click CLI scripts each built with identical / similar code patterns. An important schema for dynamic management of different types of files has a serious flaw. I've changed this dispatcher model. My version loads Python files into a subdirectory (
plugins) which are loaded at the highest level with
import plugins * (see example below).
The scripts are all loaded in the same Python virtual environment.
+ bin | - + project1 | | -setup.py | | -script1_main.py | | - + plugins | | | - [some files named `handle_*`] | ... | | - + project2 | | -setup.py | | -script2_main.py | | - + plugins | | | - [some files named `handle_[something else]` | | ...
The problem as currently implemented occurs when a new project is installed (
pip install -e.), a previously installed plugins folder has already been loaded.
Below, I have a minimal example showing that the pattern works and that I can quickly test in a Jupyter notebook. You can also recreate the problem. If you make the described changes and run both versions from the command prompt, you will get the following results:
(cptvenv)> TestClickPlugin2 cpt2_1. IMPORT DISPATCHER FUNC HANDLEPLUGINS cpt2_2. PLUGINS OF APPEAL 3. THIS IS NOT RELOADED cpt2_4. MAIN CURRENT cpt2_5. THE IMPORTATION SEEMS OK. cpt2_6. PLUGIN MANIPULATOR IN PROGRESS OF SHIPPING Yay!
I can create a new virtual environment, but it's really a non-starter; I need these scripts to coexist. I could rename the repertoire
plugins in line with the name of the project
cpt_plugins. And here is another method using
importlib, Import an arbitrary python source file. (Python 3.3+).
Can the current example be modified somehow to allow me to reuse this same plug-in model?
If you use Anaconda, I think you could create it very easily. Create a project directory. Save your Jupyter notebook here. In the Jupyter notebook, paste the code below and add cell breaks before every %% writefile, as shown. Install with pip from the command line. Copy the Jupyter notebook into a new directory. Increment CLI file and command names in
setup.py and run the new script to see the results pasted above.
! mkdir plugins # Cellular break %% writefile ./setup.py since the configuration of the import of setuptools install( name = "ClickPluginTest2", version = "0.1", py_modules =['main'], install_requires =[ 'click' ], entry_points = & # 39; & # 39; [console_scripts] TestClickPlugin2 = cpt2_main: Main & # 39; & # 39; & # 39 ;, ) %% writefile ./cpt2_main.py import click print ("cpt2_1. IMPORT DISPATCHER FUNC HANDLEPLUGINS") from cpt2_dispatcher import HandlePlugins since cpt2_print import PrintMe @ click.command () def Main (): print ("cpt2_4, RUNNING MAIN") Print me () try: HandlePlugins () with the exception of e: print ("(% s) n" "Errors when calling HandlePlugins." % (e,)) %% writefile ./cpt2_print.py def PrintMe (): print ("cpt2_5. IMPORTATION SEEMS OK.") %% writefile ./cpt2_dispatcher.py bone import import system print ("cpt2_2 .CALLING PLUGINS") import plugins * def HandlePlugins (): print ("cpt2_6, EXECUTION OF PLUGIN TRANSFER IN THE DISPATCHER") handler_module = & # 39; handle_csv & # 39; getattr (sys.modules[__name__], handler_module) .run () return %% writefile ./plugins/__init__.py bone import global import print ("cpt2_3 THIS IS NOT RELOADED") modules = glob.glob (os.path.join (os.path.dirname (__ file__), descriptor _ *. py & # 39;)) __all__ = [os.path.basename(f)[:-3] for f in modules if os.path.isfile (f) and not f.endswith ('__ __ __ __ py ...)]%% writefile ./plugins/handle_csv.py def run (): print ("Yay!") %% writefile ./__init__.py # empty file