Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions nava/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import os
import shlex
from functools import wraps
import importlib.util
from .thread import NavaThread
from .params import OVERVIEW, Engine
from .params import SOUND_FILE_PLAY_ERROR, SOUND_FILE_EXIST_ERROR, ENGINE_TYPE_ERROR
from .params import SOUND_FILE_PATH_TYPE_ERROR, SOUND_ID_EXIST_ERROR, LOOP_ASYNC_ERROR
from .params import PythonEnvironment, SHELL_TYPE_ZMQ, SHELL_TYPE_TERMINAL, VSCODE_ENV_VARS
from .errors import NavaBaseError
from . import params

Expand Down Expand Up @@ -129,6 +131,21 @@ def __play_winsound_flags(sound_path, flags):
winsound.PlaySound(sound_path, flags)


def __play_google_colab(sound_path):
"""
Play sound in Google Colab Notebook.

:param sound_path: sound path
:type sound_path: str
:param loop: sound loop flag
:type loop: bool
:return: None
"""
from IPython.display import Audio, display
audio = Audio(sound_path, autoplay=True)
display(audio)


@quote
def __play_alsa(sound_path, async_mode=False, loop=False):
"""
Expand Down Expand Up @@ -265,6 +282,11 @@ def __play_auto(sound_path, async_mode=False, loop=False):
:type loop: bool
:return: None or sound id
"""
env = detect_environment()
if env == PythonEnvironment.COLAB:
return __play_google_colab(sound_path)
# we will add other notebook environment handlers in the future

sys_platform = sys.platform
if sys_platform == "win32":
return __play_winsound(sound_path, async_mode, loop)
Expand Down Expand Up @@ -325,3 +347,44 @@ def play_cli(sound_path, loop=False):
print("Error: {0}".format(e))
finally:
stop_all()


def detect_environment():
"""
Detect the current Python execution environment.

Supported environments:
- Google Colab
- Local Jupyter Notebook/Lab
- VS Code Notebook
- IPython Terminal
- Plain Python script

:return: PythonEnvironment Enum value indicating the environment.
"""
ip = None
try:
from IPython import get_ipython
ip = get_ipython()
except ImportError:
return PythonEnvironment.PLAIN_PYTHON
if ip is None:
return PythonEnvironment.PLAIN_PYTHON

shell_name = ip.__class__.__name__.lower()

# Explicit Google Colab check (most reliable)
if importlib.util.find_spec("google.colab") is not None:
return PythonEnvironment.COLAB

# VS Code check via known env vars
if any(var in os.environ for var in VSCODE_ENV_VARS):
return PythonEnvironment.VSCODE

if shell_name == SHELL_TYPE_ZMQ:
return PythonEnvironment.LOCAL_JUPYTER

if shell_name == SHELL_TYPE_TERMINAL:
return PythonEnvironment.IPYTHON_TERMINAL

return PythonEnvironment.UNKNOWN
23 changes: 23 additions & 0 deletions nava/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,29 @@ class Engine(Enum):
AFPLAY = "afplay"


class PythonEnvironment(Enum):
"""Python environment class."""

COLAB = "Google Colab"
LOCAL_JUPYTER = "Local Jupyter Notebook or JupyterLab"
VSCODE = "VS Code Notebook"
IPYTHON_TERMINAL = "IPython Terminal"
PLAIN_PYTHON = "Plain Python (.py script)"
UNKNOWN = "Unknown Environment"


# Environment variables typically set by VS Code
VSCODE_ENV_VARS = [
"VSCODE_PID", # this is often set when running in VS Code
"VSCODE_CWD", # this is often set when running in VS Code
"VSCODE_IPC_HOOK_CLI",
"TERM_PROGRAM", # often set to "vscode"
]

# Shell type identifiers
SHELL_TYPE_ZMQ = "zmqinteractiveshell" # Jupyter Notebook/Lab
SHELL_TYPE_TERMINAL = "terminalinteractiveshell" # IPython Terminal

SOUND_FILE_PLAY_ERROR = "Sound can not play due to some issues."
SOUND_FILE_EXIST_ERROR = "Given sound file doesn't exist."
SOUND_FILE_PATH_TYPE_ERROR = "Sound file's path should be a string."
Expand Down
Loading