Skip to content

Commit 087bb6f

Browse files
committed
Move the test macro detection code to unpythonic.syntax.testutil
It doesn't really belong with the `nb` notebook macro. Now it's where it belongs, and `nb` imports it.
1 parent ba17f1f commit 087bb6f

File tree

2 files changed

+39
-23
lines changed

2 files changed

+39
-23
lines changed

unpythonic/syntax/nb.py

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66

77
# This is the kind of thing thinking with macros does to your program. ;)
88

9-
from ast import Expr, Subscript, Name, Call
9+
from ast import Expr
1010

1111
from macropy.core.quotes import macros, q, ast_literal # noqa: F401
1212

13-
from .util import isx
13+
from .testutil import istestmacro
1414

1515
def nb(body, args):
1616
p = args[0] if args else q[print] # custom print function hook
@@ -20,6 +20,10 @@ def nb(body, args):
2020
theprint = ast_literal[p]
2121
newbody.extend(init)
2222
for stmt in body:
23+
# We ignore statements (because no return value), and,
24+
# test[] and related expressions from our test framework.
25+
# Those don't return a value either, and play a role
26+
# similar to the `assert` statement.
2327
if type(stmt) is not Expr or istestmacro(stmt.value):
2428
newbody.append(stmt)
2529
continue
@@ -29,22 +33,3 @@ def nb(body, args):
2933
theprint(_)
3034
newbody.extend(newstmts)
3135
return newbody
32-
33-
# Integration with the test framework - ignore test[] et al. expressions.
34-
#
35-
# See unpythonic.syntax.test.testutil and unpythonic.test.fixtures.
36-
# TODO: move istestmacro to testutil?
37-
_test_macro_names = ["test", "test_signals", "test_raises", "error", "fail"]
38-
_test_function_names = ["unpythonic_assert",
39-
"unpythonic_assert_signals",
40-
"unpythonic_assert_raises"]
41-
def istestmacro(tree):
42-
def isunexpandedtestmacro(tree):
43-
return (type(tree) is Subscript and
44-
type(tree.value) is Name and
45-
tree.value.id in _test_macro_names)
46-
def isexpandedtestmacro(tree):
47-
return (type(tree) is Call and
48-
any(isx(tree.func, fname, accept_attr=False)
49-
for fname in _test_function_names))
50-
return isunexpandedtestmacro(tree) or isexpandedtestmacro(tree)

unpythonic/syntax/testutil.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,51 @@
11
# -*- coding: utf-8 -*-
2-
"""Utilities for writing tests."""
2+
"""Utilities for writing tests.
3+
4+
See also `unpythonic.test.fixtures` for the high-level machinery.
5+
"""
36

47
from macropy.core.quotes import macros, q, u, ast_literal, name
58
from macropy.core.hquotes import macros, hq # noqa: F811, F401
69
from macropy.core import unparse
710

8-
from ast import Tuple, Str, copy_location
11+
from ast import Tuple, Str, Subscript, Name, Call, copy_location
912

1013
from ..dynassign import dyn # for MacroPy's gen_sym
1114
from ..misc import callsite_filename
1215
from ..conditions import cerror, handlers, restarts, invoke
1316
from ..collections import box, unbox
1417
from ..symbol import sym
1518

19+
from .util import isx
20+
1621
from ..test import fixtures
1722

23+
# -----------------------------------------------------------------------------
24+
# Helper for other macros to detect uses of the ones we define here.
25+
26+
# Note the unexpanded `error[]` macro is distinguishable from a call to
27+
# the function `unpythonic.conditions.error`, because a macro invocation
28+
# is an `ast.Subscript`, whereas a function call is an `ast.Call`.
29+
_test_macro_names = ["test", "test_signals", "test_raises", "error", "fail"]
30+
_test_function_names = ["unpythonic_assert",
31+
"unpythonic_assert_signals",
32+
"unpythonic_assert_raises"]
33+
def istestmacro(tree):
34+
"""Return whether `tree` is an invocation of a testing macro.
35+
36+
Expanded or unexpanded doesn't matter; this is currently provided
37+
so that other macros can detect and skip subtrees that invoke a test.
38+
"""
39+
def isunexpandedtestmacro(tree):
40+
return (type(tree) is Subscript and
41+
type(tree.value) is Name and
42+
tree.value.id in _test_macro_names)
43+
def isexpandedtestmacro(tree):
44+
return (type(tree) is Call and
45+
any(isx(tree.func, fname, accept_attr=False)
46+
for fname in _test_function_names))
47+
return isunexpandedtestmacro(tree) or isexpandedtestmacro(tree)
48+
1849
# -----------------------------------------------------------------------------
1950
# Regular code, no macros yet.
2051

0 commit comments

Comments
 (0)