from fastcore.test import *
from basedpl import Array, bpl
from IPython.utils.capture import capture_output
import numpy as npNotebook magics
BPL adds %bpl and %%bpl magics to IPython. Both evaluate in basedpl.bpl, the same workspace as Python calls through bpl.
The line magic returns a native array or function. The cell magic displays what the BPL prompt would show, including implicit expression results. Registering the magics gives the workspace the prompt’s display settings: matrices, nested arrays and strings show in boxes, and functions as trees. Python values’ rich display in the notebook shows the same way, because it reads the same workspace.
Rendering output
AplOut preserves BPL spacing. Its HTML representation escapes the output before putting it in a <pre> element.
out = AplOut('1 < 2')
assert '<' in out._repr_html_()
out1 < 2
The magics
Each execution emits a small CDN script load. The browser keeps one toolbar, including when a dialog is reopened on the same kernel.
The line magic shows explicit output as BPL produces it, and returns its expression’s native value. A trailing ; suppresses all cell display without skipping execution. Output produced before an error is displayed before the error is raised.
Tab completes user and system names in BPL input. Completion reads the workspace without evaluating anything.
The cell magic displays each expression. Assignments remain silent.
%%bpl
m←2 3⍴⍳6
m×10┌→───────┐ ↓ 0 10 20│ │30 40 50│ └~───────┘
The line magic returns a native basedpl.Array. Use .np or .py for conversion. BPL parses comments itself. A ⍝ inside a quoted string doesn’t start a comment.
z = %bpl m ⍝ a matrix
test_is(type(z), Array)
np.testing.assert_array_equal(z.np, [[0, 1, 2], [3, 4, 5]])
test_eq(magic.bpl('"a⍝b" ⍝ comment').py, 'a⍝b')
z┌→────┐
↓0 1 2│
│3 4 5│
└~────┘
Python values bound through bpl are visible to the magics. Python integers stay exact.
bpl(x=np.arange(1, 4))
value = %bpl +/x
test_eq(value.py, 6)
test_is(type(value.py), int)
value6ₓ₈
BPL’s display commands also work in a cell.
%%bpl
]Display [[1 2] "ab"]┌→───────────┐ │ ┌→──┐ ┌→─┐ │ │ │1 2│ │ab│ │ │ └~──┘ └──┘ │ └∊───────────┘
A suppressed cell still updates the workspace.
%%bpl
quiet←7;SVG elements and custom MIME renderers display in cell magics and as Python values.
%%bpl
circle←•element "circle"
•svg ["cx":50 "cy":50 "r":30 "fill":"orange"] circle ""Names and help
Use ]help name for help and ]help name -source for source, in either magic. Leading definition comments supply help. Inspecting a function doesn’t call it.
%%bpl
double←{⍝ Double the argument
⎕←"called" ⋄ ⍵×2}with capture_output() as cap: magic.bpl(']help double')
assert 'Double the argument' in cap.outputs[-1].data['text/markdown']
with capture_output() as cap: magic.bpl('', ']help double -source')
assert '⎕←"called"' in cap.outputs[-1].data['text/markdown']
test_eq(len(cap.outputs), 2)Completion follows the magic’s workspace, including names defined after registration. Quoted text and comments stay literal.
from IPython.core.completer import provisionalcompletershell = get_ipython()
for text, expected in [('%bpl dou', 'double'), ('v = %bpl dou', 'double'), ('%%bpl\n1+•sr', '•src'), ("%%bpl\n''' dou", 'double')]:
with provisionalcompleter(): matches = list(shell.Completer.completions(text, len(text)))
assert expected in [m.text for m in matches]
for text in ['%%bpl\n"dou', '%%bpl\n⍝ dou', 'ordinary_python']:
with provisionalcompleter(): matches = list(shell.Completer.completions(text, len(text)))
assert not any(m.type == 'BPL name' for m in matches)Errors and workspace state
Errors retain source locations and leave completed assignments in the workspace. Incomplete input raises a syntax error and leaves the workspace unchanged.
with capture_output() as cap: test_fail(lambda: magic.bpl('', '⎕←42 ⋄ 1÷"a"'), contains='DOMAIN ERROR')
assert '42' in cap.outputs[-1].data['text/html']
test_fail(lambda: magic.bpl('', '{⍵+1'), contains='SYNTAX ERROR')
test_eq(magic.bpl('quiet').py, 9)Set bpl.timeout to a per-evaluation deadline in seconds. Ctrl-C interrupts the evaluation. Output captured before cancellation is displayed. The workspace keeps its names after cancellation. Native-library calls and individual BigInt operations can delay cancellation.
Installation
%load_ext basedpl.notebooks registers the magics in the current kernel. bpl-install-magic adds the extension to the default IPython profile. Registration does not start a BPL worker.
Symbol input
The magics load BPL’s browser input method for typing glyphs. Using BPL notebooks explains the input method.