## Abstract
We are excited to introduce a new enhancement to Conda that brings more flexibility and customization to its behavior. With the 23.7.0 release, we have added generic plugin hooks, including `pre_command` and `post_command`. These hooks empower plugin authors to execute their code both before and after specific conda commands, opening up a world of possibilities for enhancing authentication handling, creativity, and extensibility within the conda ecosystem.
## Specification
The following three new plugin hooks have been introduced:
- `pre_command`: Runs before the invoked conda command is executed.
- `post_command`: Runs after the invoked conda command is executed.
To create these hooks, plugin authors define `conda.plugins.hookimpl` decorated functions named either `conda_pre_command` or `conda_post_command`. These functions return either a `CondaPreCommand` or `CondaPostCommand` class, respectively. Each hook receives the following properties:
- `name`: A unique identifier for the plugin hook.
- `action`: A callable containing the code to be executed.
- `run_for`: A Python `set` of strings representing the commands the hook will run on (e.g., `install` and `create`).
### Example: Custom Plugin Hooks
```python
from conda.plugins import hookimpl, CondaPreCommand, CondaPostCommand
PLUGIN_NAME = "custom_plugin"
def custom_plugin_pre_command_action(command):
"""
Defines our custom pre-command action,
which simply prints a message.
"""
print(f"Pre-command action before {command}")
@hookimpl
def conda_pre_commands():
"""
Yields our CondaPreCommand instance, which
attaches our ``custom_plugin_pre_command_action``
to the "install" and "create" commands.
"""
yield CondaPreCommand(
name=f"{PLUGIN_NAME}_pre_command",
action=custom_plugin_pre_command_action,
run_for={"install", "create"}
)
def custom_plugin_post_command_action(command):
"""
Defines our custom post-command action,
which simply prints a message.
"""
print(f"Post-command action after {command}")
@hookimpl
def conda_post_commands():
"""
Yields our CondaPostCommand instance, which
attaches our ``custom_plugin_post_command_action``
to the "install" and "create" commands.
"""
yield CondaPostCommand(
name=f"{PLUGIN_NAME}_post_command",
action=custom_plugin_post_command_action,
run_for={"install", "create"}
)
```
## Motivation
The addition of these plugin hooks addresses various use cases and needs within the conda community. Key motivations include:
1. **Better Authentication Handling:** With the `pre_command` hook, plugin authors can interrupt the normal start-up of conda commands to enhance authentication handling. This allows for user authentication, retrieving credentials from an OS keyring, and secure usage throughout the command and subsequent runs.
2. **Empowering the Community:** By introducing these generic hooks, we empower the conda community to creatively extend and customize conda's functionality. The possibilities are vast, and we eagerly anticipate the community's innovative use of these hooks.
## Rationale
The introduction of generic plugin hooks ensures the flexibility and scalability of conda's plugin ecosystem. Starting with a focused set of hooks allows aspiring conda plugin authors to adapt to the new enhancement with ease. As the plugin ecosystem evolves and matures, additional hooks may be introduced through future CEPs (Conda Enhancement Proposals).
## FAQ
We understand you may have questions about these new hooks, so here are some frequently asked questions:
- **Will I have access to global variables such as `conda.base.context.context` in my plugin hook?**
- Yes, all plugin hooks listed in this CEP will have access to global variables after the context object has been initialized.
- **Where exactly will the `pre_command` hooks be called?**
- All registered `pre_command` hooks will be called before the `conda.cli.main:main_subshell` function's `do_call` call.
- **Where exactly will the `post_command` hooks be called?**
- All registered `post_command` hooks will be called after the `conda.cli.main:main_subshell` function's `do_call` call.
- **Will these hooks be available for `conda activate` and `conda deactivate` commands?**
- Initially, no. We are actively considering their availability for these commands in response to community demand. Currently, implementing these hooks for these commands presents unique challenges related to their shell handling.
- **Will I be able to combine the use of these hooks with others in a single plugin?**
- Absolutely! We encourage combining these generic hooks with existing ones to create a rich set of possibilities for extending conda's functionality.
- **What is the execution order of the registered plugin hooks?**
- _To Be Determined_
## Conclusion
With the introduction of generic plugin hooks, we hope to empower the conda community to build a more diverse and extensible ecosystem. Plugin authors can now seamlessly integrate their custom logic before and after conda commands, opening doors to innovation and creative solutions.