Skip to content
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

%glue magic command #578

Open
aritmos opened this issue Dec 15, 2023 · 0 comments
Open

%glue magic command #578

aritmos opened this issue Dec 15, 2023 · 0 comments
Labels
enhancement New feature or request

Comments

@aritmos
Copy link

aritmos commented Dec 15, 2023

Context

Within my Jupyter Book project I found myself at a bad trade-off in functionality between using myst's eval directive, for super simple markdown variable inlining and some of Jupyter Book's advanced functionalities, namely "Components and UI elements".

Within Jupyter Lab, the eval works but not components such as grids, for these the book needs to be compiled. But if one uses myst evaluation then the notebook execution mode has to be set to "inline", which reruns all of the notebooks. Running all of the notebooks (especially those with expensive calculations) in order to see the visual elements in the book was very frustrating. Thankfully I saw that myst also had the glue directive, which did not require the inline execution!

Upon switching to using glue i realised that the public API was somewhat cumbersome, I didn't like the pattern of glue("my_var", some_long_chained_pandas_expression). In many cases I also wanted to reuse these variables later in the notebook within code cells, which led many cases of this pseudo-duplication:

my_var = some_long_chained_pandas_expression
glue("my_var", my_var)

In every case I was content with using the variable's own identifier (the name I had given the variable) as the key for my "gluing". Essentially immitating the eval directive. I found the glue("my_var", my_var) quite cumbersome and redundant and worked towards automating it by wrapping the function. Eventually I realised instead one could define a magic command that gets rid of the extra line altogether. I think this functionality might a generally desired functionality.

Proposal

Add a %glue (line) magic command that automatically "glues a variable assignment".
Additionally some sort of cell magic command could be proposed that might bind all variable assignments within the cell.

Essentially it replaces the glue("var", var) pattern with %glue var = ...

I wrote this barebones implementation for my own project but I am by no means a python expert. I assume a more performant/robust/safe implementation could be achieved.

from IPython.core.magic import register_line_magic
import ast

@register_line_magic
def glue(line: str) -> None:
    # execute the line
    exec(line, get_ipython().user_ns)

    # glue the assigned variables
    line_ast = ast.parse(line, mode="exec")
    target = line_ast.body[0].targets[0]

    
    if isinstance(target, ast.Name):
        # single variable assignment
        var_name = target.id
        var_value = get_ipython().user_ns[var_name]
        glue_(var_name, var_value, False)

    elif isinstance(target, ast.Tuple) or isinstance(target, ast.List):
        # destructured variable assignment for tuples and lists
        var_names = [element.id for element in target.elts]
        var_values = [get_ipython().user_ns[var_name] for var_name in var_names]

        for var_name, var_value in zip(var_names, var_values):
            glue_(var_name, var_value, False)

get_ipython().register_magic_function(glue, magic_kind='line')

In my case, dealing with dataframes representing database queries I also had many cases of pattern destructuring in my assignments when dealing with a single row. So I also made the command able to handle these cases such as %glue (x, y) = coords.

The implementation handles the single variable assignments as well as tuples and lists. I assume allowed python grammar could break the AST implementation. Shadowing the original glue function could also reasonably be avoided, the magic method could always be given a complementary name.

I used some older discourse to find how to define custom cell magics, there might also very well be cleaner implementations possible with the latest ipython versions. I'd be happy to look into it while cleaning up this implementation and submit a PR.

Tasks and updates

No response

@aritmos aritmos added the enhancement New feature or request label Dec 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant