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

PYIODE: handling newline displays in interactive mode #639

Open
yvdabb opened this issue Aug 14, 2024 · 0 comments
Open

PYIODE: handling newline displays in interactive mode #639

yvdabb opened this issue Aug 14, 2024 · 0 comments
Assignees

Comments

@yvdabb
Copy link
Collaborator

yvdabb commented Aug 14, 2024

Problem:

The presence of \n in equation objects is common due to how the text is formatted in the original IODE GUI and associated source files (e.g., for multiline display purposes). When this representation is brought into Python interactive mode, the \n characters can (slightly) disrupt readability.

°°°°°°°°

First attempt:

Ideally, when working in an interactive console, we want the expression io.equations["ACAF"].lec to no longer display a hard-coded \n in the output, similar to how an ordinary print() statement would handle the situation. Unfortunately, we see:

(ACAF/VAF[-1]) := acaf1+acaf2*GOSF[-1]+\nacaf4*(TIME=1995)

A possible solution introduces a custom string class FormattedLecString that overrides the __repr__ method to return the string just as if it were an ordinary print statement.

class FormattedLecString(str):
    def __repr__(self):
        return str(self)
@property
def lec(self) -> str:
    # ...
    return FormattedLecString(formatted_lec_definition) 

This approach has the potential downside that the return objects are no longer of the standard string type, which might cause issues when assigning or using them in situations where str is expected.

°°°°°°°°
Second attempt:

Another approach is to modify the behavior of the interactive console itself. First, we need to determine whether we are in interactive mode, which can be done using this method. There are ways to customize the standard Python REPL but unfortunately they do not have an effect within the usual IPython environment. Extra adjustments are therefore needed to get things working in PyCharm or VSCode interactive mode.

import sys
from IPython import get_ipython

# Execute *only* next two lines in interactive mode (e.g., PyCharm console, VSCode Jupyter/Interactive, etc.)
var = "abc\ndef"
var

# Next, continue and execute the code below in interactive mode and observe the new behavior.
def setup_custom_display_interactive_mode():
   if hasattr(sys, 'ps1'):
       print("interactive mode")

       # Interactive Mode Type 1: custom display hook for standard Python REPL
       def my_displayhook(value):
           if value is not None:
               print(value if isinstance(value, str) else repr(value))

       # Assign custom hook to sys.displayhook
       sys.displayhook = my_displayhook

       # Interactive Mode Type 2: check if running IPython and set up custom display function
       ip = get_ipython()
       if ip is not None:
           def custom_display_string(value, p, cycle):  # keep 'cycle' argument
               p.text(value if isinstance(value, str) else repr(value))
           
           ip.display_formatter.formatters['text/plain'].for_type(str, custom_display_string)
   else:
       print("non-interactive mode")

setup_custom_display_interactive_mode()
var

The output and behaviour is as follows:

In [3]: var
Out[3]: 'abc\ndef'
...
In [5] var
Out[5]: 
abc
def

If there are better implementations or solutions, please let me know (@alixdamman, @gdementen). It might also be worth discussing whether implementing this feature is sensible in the first place (taking into account user-experience, maintenance cost, performance, etc.).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant