Skip to content

Commit

Permalink
[Hotfix] Echo forced to false on terminal detection. (#1067)
Browse files Browse the repository at this point in the history
Model class now detects if executing within a terminal (as opposed to a
notebook). Echo will be forced to false for terminal usage, until
interactivity overhaul is merged. Environment class has been ported from
overhaul PR.
  • Loading branch information
nopdive authored Oct 30, 2024
1 parent c8c6a11 commit b4b0047
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 1 deletion.
11 changes: 10 additions & 1 deletion guidance/models/_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

import numpy as np

from ..visual import Environment

try:
from IPython.display import clear_output, display, HTML

Expand Down Expand Up @@ -226,7 +228,14 @@ def __init__(self, engine, echo=True, **kwargs):

self.engine = engine
self.chat_template = engine.get_chat_template() # TODO [HN]: Should this be a method or attr?
self.echo = echo

# HOTFIX(nopdive): Temporary until visualization overhaul is merged.
environment = Environment()
if environment.is_terminal():
self.echo = False
else:
self.echo = echo

self.token_count = 0 # tracks how many tokens our byte state represents
self.max_display_rate = 0.2 # this controls how frequently we are allowed to redraw the display (in seconds)
self.opened_blocks = {} # what context blocks have been opened but not closed
Expand Down
6 changes: 6 additions & 0 deletions guidance/visual/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""UI and other visual UX considerations.
Users should have few reasons to be accessing this module.
"""

from ._environment import Environment
136 changes: 136 additions & 0 deletions guidance/visual/_environment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
""" Rendering environment detection.
Detection logic is inspired from both plotly and interpretml environment detection.
- https://github.com/plotly/plotly.py
- https://github.com/interpretml/interpret
"""
# TODO(nopdive): Major cloud providers implemented and manually verified.

import os
from pydantic import BaseModel


class EnvFlags(BaseModel):
"""Environment flags - such as if we're in a notebook or cloud."""

is_notebook: bool = False
is_cloud: bool = False


class Environment:
""" Capabilities based environment detection."""

def __init__(self):
""" Initializes.
This will immediately check for which environments are detected.
"""
self._flags = EnvFlags()
self._checks = {
"vscode": _detect_vscode,
"ipython-zmq": _detect_ipython_zmq,
"ipython": _detect_ipython,
}
envs = []
for name, update_flags in self._checks.items():
if update_flags(self._flags): # in-place operation on flags
envs.append(name)
self._detected_envs = envs


@property
def detected_envs(self) -> list[str]:
""" Detected environments (i.e. vscode, ipython-zmq).
Returns:
Detected environment names.
"""
return self._detected_envs


def is_notebook(self) -> bool:
""" Determines if the python process is in a notebook.
Returns:
True if in notebook.
"""
return self._flags.is_notebook

def is_cloud(self) -> bool:
""" Determines if the python process is in a cloud provider.
Returns:
True if in notebook.
"""
return self._flags.is_cloud

def is_terminal(self) -> bool:
""" Determines if the python process not in a notebook (we assume terminal).
Returns:
True if in terminal.
"""
return not self._flags.is_notebook


def _detect_vscode(flags: EnvFlags) -> bool:
"""Detects if called in a vscode process.
Args:
flags: Inplace flags to be set.
Returns:
True if in vscode environment.
"""
# NOTE: We don't flag is_notebook since this will be picked up by ipython-zmq here.
found = "VSCODE_PID" in os.environ
return found


def _detect_ipython(flags: EnvFlags) -> bool:
"""Detects if called in an IPython environment.
Mostly derived from stackoverflow below:
https://stackoverflow.com/questions/15411967/how-can-i-check-if-code-is-executed-in-the-ipython-notebook
Args:
flags: Inplace flags to be set.
Returns:
True if in IPython environment.
"""
found = False
try:
from IPython import get_ipython
found = get_ipython() is not None
except NameError: # pragma: no cover
pass
return found


def _detect_ipython_zmq(flags: EnvFlags) -> bool:
"""Detects if in an IPython environment using ZMQ (i.e. notebook/qtconsole/lab).
Mostly derived from stackoverflow below:
https://stackoverflow.com/questions/15411967/how-can-i-check-if-code-is-executed-in-the-ipython-notebook/24937408
Args:
flags: Inplace flags to be set.
Returns:
True if called in IPython notebook or qtconsole.
"""
try:
from IPython import get_ipython

shell = get_ipython().__class__.__name__
if shell == "ZMQInteractiveShell":
found = True # Jupyter notebook or qtconsole
elif shell == "TerminalInteractiveShell":
found = False # Terminal running IPython
else:
found = False # Other type (?)
except NameError: # pragma: no cover
found = False # Probably standard Python interpreter

flags.is_notebook |= found
return found

0 comments on commit b4b0047

Please sign in to comment.