stuff, fmt

This commit is contained in:
lda
2026-08-30 04:30:06 +07:00 Verified
parent 282dc5b4e8
commit b4e5058000
7 changed files with 81 additions and 94 deletions
+7 -6
View File
@@ -1,6 +1,6 @@
"""Small, side-effect-free API for the in-process IPython runner."""
from .app import App, generate_good_names
from .app import App
from .events import (
error_from_execution_result,
event_from_execution_result,
@@ -22,22 +22,23 @@ from .shell import (
run_cell_and_collect,
setup_shell,
)
from .utils import generate_good_names
__all__ = [
"App",
"CallError",
"CallEvent",
"CallEventKind",
"CallError",
"CallOptions",
"CallResponse",
"CallResult",
"error_from_execution_result",
"event_from_execution_result",
"Shell",
"event_from_history_output",
"generate_good_names",
"ShellInfo",
"ShellStatus",
"error_from_execution_result",
"event_from_execution_result",
"event_from_history_output",
"generate_good_names",
"isolate_output_history",
"run_cell_and_collect",
"setup_shell",
+1 -11
View File
@@ -4,22 +4,12 @@ import json
from dataclasses import asdict
from uuid import uuid4
from wonderwords import RandomWord
from ipython_demo.utils import generate_good_names
from .models import CallOptions, CallResponse, ShellInfo
from .shell import Shell
_WORD_GENERATOR = RandomWord()
def generate_good_names() -> str:
"""Generate a readable, collision-resistant shell name."""
adjective = _WORD_GENERATOR.word(include_parts_of_speech=["adjectives"])
noun = _WORD_GENERATOR.word(include_parts_of_speech=["nouns"])
return f"{adjective}-{noun}-{uuid4().hex[:4]}"
class App:
"""Coordinate named shells and expose frontend-shaped call responses."""
-1
View File
@@ -1,7 +1,6 @@
from dataclasses import dataclass
from typing import Literal
CallEventKind = Literal[
"stdout",
"stderr",
+13 -1
View File
@@ -1,8 +1,10 @@
import inspect
from uuid import uuid4
from wonderwords import RandomWord
def line():
this = inspect.currentframe()
if not this: # i want ?. operator SOOOOOOOO
return None
@@ -10,3 +12,13 @@ def line():
if not frame:
return None
return frame.f_lineno
_WORD_GENERATOR = RandomWord()
def generate_good_names() -> str:
"""Generate a readable, collision-resistant shell name."""
adjective = _WORD_GENERATOR.word(include_categories=["adjectives"])
noun = _WORD_GENERATOR.word(include_categories=["nouns"])
return f"{adjective}-{noun}-{uuid4().hex[:4]}"
+6 -22
View File
@@ -1,47 +1,31 @@
import contextlib
import importlib
import io
import json
import re
import subprocess
import sys
import unittest
from unittest.mock import Mock, patch
from ipython_demo import utils
from ipython_demo.app import App
from ipython_demo.models import CallOptions, CallResponse
class AppTests(unittest.TestCase):
def test_generate_good_names_uses_readable_random_words(self):
app_module = importlib.import_module("ipython_demo.app")
generator = Mock()
assert isinstance(generator.word, Mock)
generator.word.side_effect = ["luminous", "otter"]
with patch.object(
app_module,
utils,
"_WORD_GENERATOR",
generator,
create=True,
):
name = app_module.generate_good_names()
name = utils.generate_good_names()
self.assertRegex(name, re.compile(r"^[a-z]+-[a-z]+-[0-9a-f]{4}$"))
generator.word.assert_any_call(include_parts_of_speech=["adjectives"])
generator.word.assert_any_call(include_parts_of_speech=["nouns"])
def test_main_emits_one_json_payload(self):
completed = subprocess.run(
[sys.executable, "-c", "from ipython_demo.app import main; main()"],
capture_output=True,
text=True,
check=True,
)
payload = json.loads(completed.stdout)
self.assertEqual(len(payload), 2)
self.assertEqual(payload[0]["events"][0]["kind"], "stdout")
self.assertTrue(payload[1]["options"]["collapsed"])
generator.word.assert_any_call(include_categories=["adjectives"])
generator.word.assert_any_call(include_categories=["nouns"])
def test_run_code_returns_frontend_facing_call_response(self):
app = App()
+35
View File
@@ -0,0 +1,35 @@
import unittest
from collections.abc import Callable
from typing import Any
from IPython.core.interactiveshell import InteractiveShell
from ipython_demo.shell import Shell
class TestMyIdeas(unittest.TestCase):
def test_MY_two_instances(self):
InteractiveShell1 = Shell("InteractiveShell1").init_shell()
InteractiveShell2 = Shell("InteractiveShell2").init_shell()
def ok[T](
resolve: Callable[[InteractiveShell], Any],
method: Callable[[T, T], Any],
) -> None:
t1 = resolve(InteractiveShell1)
t2 = resolve(InteractiveShell2)
method(t1, t2)
ok(
lambda shell: getattr(shell.history_manager, "outputs", None),
self.assertIsNot,
)
ok(lambda shell: shell.display_formatter, self.assertIsNot)
ok(lambda shell: shell.display_pub, self.assertIsNot)
ok(lambda shell: shell.displayhook, self.assertIsNot)
ok(lambda shell: shell.history_manager, self.assertIsNot)
ok(lambda shell: shell.user_ns, self.assertIsNot)
if __name__ == "__main__":
unittest.main()
+12 -46
View File
@@ -1,61 +1,21 @@
import contextlib
import importlib.util
import io
import os
import subprocess
import sys
import types
import unittest
from pathlib import Path
from unittest.mock import patch
from IPython.core.interactiveshell import InteractiveShell
from IPython.core.history import HistoryOutput
from IPython.core.interactiveshell import InteractiveShell
from IPython.utils import capture
import ipython_demo.events as events_module
import ipython_demo.models as models_module
import ipython_demo.shell as shell_module
PACKAGE_ROOT = Path(__file__).parents[1] / "src" / "ipython_demo"
package = types.ModuleType("ipython_demo")
package.__path__ = [str(PACKAGE_ROOT)]
sys.modules["ipython_demo"] = package
def load_package_module(name: str):
path = PACKAGE_ROOT / f"{name}.py"
spec = importlib.util.spec_from_file_location(f"ipython_demo.{name}", path)
assert spec is not None and spec.loader is not None
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
return module
models_module = load_package_module("models")
events_module = load_package_module("events")
shell_module = load_package_module("shell")
class ShellTests(unittest.TestCase):
def test_init_shell_has_no_seed_escape_hatch(self):
import inspect
self.assertNotIn(
"seed", inspect.signature(shell_module.Shell.init_shell).parameters
)
def test_package_import_has_no_experiment_side_effects(self):
env = os.environ.copy()
env["PYTHONPATH"] = str(PACKAGE_ROOT.parent)
completed = subprocess.run(
[sys.executable, "-c", "import ipython_demo; print('imported')"],
capture_output=True,
text=True,
env=env,
check=True,
)
self.assertEqual(completed.stdout, "imported\n")
def test_event_from_history_output_preserves_streams_and_mime(self):
stdout = events_module.event_from_history_output(
HistoryOutput("out_stream", {"stream": ["hello", "\n"]}),
@@ -105,9 +65,13 @@ class ShellTests(unittest.TestCase):
)
self.assertIsInstance(execution.error, models_module.CallError)
assert execution.error
self.assertEqual(execution.error.ename, "ValueError")
self.assertEqual(execution.error.evalue, "boom")
self.assertTrue(events, "no events")
self.assertEqual(events[-1].kind, "error")
self.assertTrue(events[-1].data, "no data in last event")
assert events[-1].data
self.assertEqual(events[-1].data["ename"], "ValueError")
self.assertEqual(events[-1].data["evalue"], "boom")
@@ -168,12 +132,14 @@ class ShellTests(unittest.TestCase):
"Shell.run_cell must use the shell-local output records"
)
with patch.object(
with (
patch.object(
capture,
"capture_output",
fail_capture_output,
),
contextlib.redirect_stdout(io.StringIO()),
):
with contextlib.redirect_stdout(io.StringIO()):
result, events = wrapper.run_cell(
"print('hello'); 42",
call_id="call-1",