-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathnb.py
More file actions
72 lines (56 loc) · 2.22 KB
/
nb.py
File metadata and controls
72 lines (56 loc) · 2.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# -*- coding: utf-8 -*-
"""Ultralight math notebook.
Auto-print top-level expressions, auto-assign last result as _.
"""
__all__ = ["nb"]
# This is the kind of thing thinking with macros does to your program. ;)
from ast import Expr
from mcpyrate.quotes import macros, q, u, a, h # noqa: F401
from mcpyrate import parametricmacro
from .testingtools import istestmacro
@parametricmacro
def nb(tree, *, args, syntax, **kw):
"""[syntax, block] Ultralight math notebook.
Auto-print top-level expressions, auto-assign last result as _.
A custom print function can be supplied as an argument.
Example::
with nb:
2 + 3
42 * _
from sympy import *
with nb[pprint]:
x, y = symbols("x, y")
x * y
3 * _
"""
if syntax != "block":
raise SyntaxError("nb is a block macro only") # pragma: no cover
if syntax == "block" and kw['optional_vars'] is not None:
raise SyntaxError("nb does not take an as-part") # pragma: no cover
# Expand outside in. This macro is so simple and orthogonal the
# ordering doesn't matter. This is cleaner.
return _nb(body=tree, args=args)
def _nb(body, args):
p = args[0] if args else q[h[print]] # custom print function hook
with q as newbody:
_ = None
theprint = lambda value: h[_print_and_passthrough](a[p], value)
for stmt in body:
# We ignore statements (because no return value), and, test[] and related
# expressions from our test framework. Those have no meaningful return value
# either, and play a role similar to the `assert` statement.
if type(stmt) is not Expr or istestmacro(stmt.value):
newbody.append(stmt)
continue
with q as newstmts:
_ = a[stmt.value]
if _ is not None:
theprint(_)
newbody.extend(newstmts)
return newbody
# Work together with `autoreturn`. If the implicit print appears in tail position,
# the passthrough will return the value that was printed, so that when `autoreturn`
# transforms the code into `return theprint(_)`, it still works fine.
def _print_and_passthrough(printer, value):
printer(value)
return value