-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conda Generic Plugin Hooks #45
base: main
Are you sure you want to change the base?
Conda Generic Plugin Hooks #45
Conversation
would it be better to reuse existing terminology (e.g., |
@kenodegard , I'm not exactly sure what that means. Can you please clarify a little? |
@travishathaway as in use |
Co-authored-by: Bianca Henderson <[email protected]>
@kenodegard , I think I'm going to just go with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving some general naming and conceptual items as feedback since the way this is written at the moment doesn't fully use pluggy's abilties.
Generally speaking it would be useful to pass the actually used command to the pre/post command action, and be a little more detailed about the exception handler implementation since it's a lot different than the pre and post command hooks.
new-cep.md
Outdated
- All registered `on_exception` hooks will be called inside the | ||
[`conda.exceptions.ExceptionHandler`][conda-on-exception-location] class. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the conda.exceptions.ExceptionHandler
should be instead the default exception handler registered (using the tryfirst=True
hookimpl parameter)
Co-authored-by: Jannis Leidel <[email protected]>
Co-authored-by: Jannis Leidel <[email protected]>
@jezdez, thanks for the review. When I created the The "exception_handler" hook would then function just like the "solver" hook. You would only be allowed to configure a single exception handler. I'm thinking this would be easier from a plugin author's perspective. All they would have to do is the following: from conda.exceptions import ExceptionHandler
# Example for implementing pretty printing exceptions with "rich"
from rich.console import Console
console = Console()
PLUGN_NAME = "rich"
class RichExceptionHandler(ExceptionHandler):
"""
Custom exception handler that uses rich to print exceptions.
"""
def handle_exception(self, exc_val, exc_tb):
console.print_exception(show_locals=True)
@hookimpl
def conda_exception_handlers(exception):
"""
Returns our CondaExceptionHandler class which attaches our ``print_exception(``.
"""
yield CondaExceptionHandler(
name=f"{PLUGIN_NAME}_exception_handler",
exception_handler=RichExceptionHandler
) We could change the function signature of the What do you think? Is relying on inheritance here a Good Idea™️? |
…haway/ceps into cep-conda-generic-plugin-hooks
new-cep.md
Outdated
) | ||
``` | ||
|
||
### `exception_handler` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we review, if current implementation of exception classes should be extended to support custom exception handlers? For example - let's say in the code we have (just found the first one)
if args.all and prefix == context.default_prefix:
msg = "cannot remove current environment. deactivate and run conda remove again"
raise CondaEnvironmentError(msg)
If I want to write a custom exception handler for his exception, I'm missing context - which environment and reason, why it couldn't be removed (or is conda Context the right thing to use?)
If quick question - yes, it worth to review and extend exception handling mechanism - I believe it's another CEP?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aovasylenko, please see @jaimergp's comment below. I think he did a reasonable job of summarizing what you were talking about.
The scenario you are talking about would require a very extensive refactor to existing code, and I do not think it is realistic anytime soon. In the meantime, it's way easier to just rely on the context object like you said.
@travishathaway Okay, thinking about this a little more, I think we'll have to handle a situation in which multiple plugins implement exception handlers and exist in the runtime environment at the same time. E.g. imagine if conda-libmamba-solver shipped an exception handler that would enable it to print out additional details of solver errors (e.g. conda/conda-libmamba-solver#102) and the user in addition would like to install a handler that generally renders exceptions with rich (like your example above). The "solver" hook works in that way: there can be multiple solvers installed, and the default setting and the config system determine which to use. In case of exceptions handlers, we probably shouldn't require users to enable them before using them, though. Or is that an indicator to require a My question is whether we want to enable multiple exception handlers to coexist and create a kind of exception handling pipeline instead of enabling exactly one exception handler?
The API could require exception handlers to return if they've handled all exceptions, e.g.
@jaimergp You've looked at conda/conda-libmamba-solver#102 a bunch and I think @wolfv has thought about that as well, what's your take on this topic? |
new-cep.md
Outdated
""" | ||
yield CondaExceptionHandler( | ||
name=f"{PLUGIN_NAME}_exception_handler", | ||
handler=CustomExceptionHandler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will it support run_for
as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left that out because I didn't think that this plugin should have that fine grain control. It would also complicate the implementation too.
|
||
- `name`: unique name which identifies this plugin hook | ||
- `action`: a callable which contains the code to be run | ||
- `run_for`: a Python `set` of strings representing the commands this will be run on (e.g. `install` and `create`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it optional or mandatory parameter?
(also asked similar question if exception handler hook should have it as well)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. I think making this argument optional with the default behavior of it running for every command makes the most sense.
A bunch of exceptions in We could argue that exceptions should be more library friendly, and not so focused on the message but... I actually think it could be seen as a symptom of a bigger problem: exceptions in Some examples of exceptions-as-flow-control (anti?)pattern:
So maybe that little mess is something to discuss before or while designing a custom exception handler mechanism? I do agree that having multiple exceptions handlers coexisting seems less limiting than a chain of subclasses. Didn't Python add support for Exception groups or something like that? Is that useful in this case? |
Co-authored-by: Bianca Henderson <[email protected]>
@jezdez @aovasylenko @jaimergp I have thought about this some and have decided to take @jaimergp's advice to not include a custom exception handler yet. To use a metaphor, I think we need to clean up the house a bit before inviting guests in 😅. I think that a refactor of the current exception handling mechanism should be done before we revisit this. Once that has been done, we can restart this conversation with a separate CEP. In the meantime, I will remove exception handling from this CEP and just stick with the Once I've removed the exception handling pieces from this CEP, I will move it out of "draft" status. Hopefully, the vote will follow soon afterwards 👍. |
Example of how our plugin developers could use these hooks: |
Hi, some questions about the hooks. As I post in the description in PR conda/conda#10567: A core usage is to define environment variables when activating/deactivating a conda environment. E.g.: export CMAKE_PREFIX_PATH="${CONDA_PREFIX}" NOTE: In conda/conda#10567, I propose to create a post-create hook to add I wonder can the hooks affect the current shell environment like # post-activate hook
export CONDA_CMAKE_PREFIX_PATH_BACKUP="${CMAKE_PREFIX_PATH}"
export CONDA_LD_LIBRARY_PATH_BACKUP="${LD_LIBRARY_PATH}"
export CMAKE_PREFIX_PATH="${CONDA_PREFIX}"
export LD_LIBRARY_PATH="${CONDA_PREFIX}/lib:${LD_LIBRARY_PATH}" # pre-deactivate hook
export CMAKE_PREFIX_PATH="${CONDA_CMAKE_PREFIX_PATH_BACKUP}"
export LD_LIBRARY_PATH="${CONDA_LD_LIBRARY_PATH_BACKUP}"
unset CONDA_CMAKE_PREFIX_PATH_BACKUP
unset CONDA_LD_LIBRARY_PATH_BACKUP |
We may also need to document the execution order when multiple hooks are run for the same event:
for example, lexicographic order, like This is the IPython startup directory
.py and .ipy files in this directory will be run *prior* to any code or files specified
via the exec_lines or exec_files configurables whenever you load this profile.
Files will be run in lexicographical order, so you can control the execution order of files
with a prefix, e.g.::
00-first.py
50-middle.py
99-last.ipy We need to document the order of
|
Thanks for your feedback. To answer your question, no this not possible. I researched this myself once and came to the conclusion that simply is not possible because of how shells work (sub-process cannot modify the parent process' environment variable values). This is why we use so much shell specific code in conda and why it's necessary for us to modify a user's shell configuration file (e.g. |
@XuehaiPan - I think such a plugin would need to add the relevant instructions in |
This is a CEP for implementing a set of generic plugin hooks for conda. Included so far are the following hooks:
☝️ This list is not final, and we welcome a healthy discussion to debate exactly what belongs here.