Merge pull request #1791 from Kodiologist/assertmsg
Run statements in the second argument of `assert`
This commit is contained in:
commit
3a4e31c209
4
NEWS.rst
4
NEWS.rst
@ -9,6 +9,10 @@ Removals
|
|||||||
* Support for attribute lists in `defclass` has been removed. Use `setv`
|
* Support for attribute lists in `defclass` has been removed. Use `setv`
|
||||||
and `defn` instead.
|
and `defn` instead.
|
||||||
|
|
||||||
|
Bug Fixes
|
||||||
|
------------------------------
|
||||||
|
* Statements in the second argument of `assert` are now executed.
|
||||||
|
|
||||||
0.17.0
|
0.17.0
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
|
@ -324,6 +324,18 @@ def is_unpack(kind, x):
|
|||||||
and x[0] == "unpack-" + kind)
|
and x[0] == "unpack-" + kind)
|
||||||
|
|
||||||
|
|
||||||
|
def make_hy_model(outer, x, rest):
|
||||||
|
return outer(
|
||||||
|
[HySymbol(a) if type(a) is str else
|
||||||
|
a[0] if type(a) is list else a
|
||||||
|
for a in x] +
|
||||||
|
(rest or []))
|
||||||
|
def mkexpr(*items, **kwargs):
|
||||||
|
return make_hy_model(HyExpression, items, kwargs.get('rest'))
|
||||||
|
def mklist(*items, **kwargs):
|
||||||
|
return make_hy_model(HyList, items, kwargs.get('rest'))
|
||||||
|
|
||||||
|
|
||||||
class HyASTCompiler(object):
|
class HyASTCompiler(object):
|
||||||
"""A Hy-to-Python AST compiler"""
|
"""A Hy-to-Python AST compiler"""
|
||||||
|
|
||||||
@ -390,21 +402,11 @@ class HyASTCompiler(object):
|
|||||||
ret = Result()
|
ret = Result()
|
||||||
for module, names in self.imports.items():
|
for module, names in self.imports.items():
|
||||||
if None in names:
|
if None in names:
|
||||||
e = HyExpression([
|
ret += self.compile(mkexpr('import', module).replace(expr))
|
||||||
HySymbol("import"),
|
|
||||||
HySymbol(module),
|
|
||||||
]).replace(expr)
|
|
||||||
ret += self.compile(e)
|
|
||||||
names = sorted(name for name in names if name)
|
names = sorted(name for name in names if name)
|
||||||
if names:
|
if names:
|
||||||
e = HyExpression([
|
ret += self.compile(mkexpr('import',
|
||||||
HySymbol("import"),
|
mklist(module, mklist(*names))))
|
||||||
HyList([
|
|
||||||
HySymbol(module),
|
|
||||||
HyList([HySymbol(name) for name in names])
|
|
||||||
])
|
|
||||||
]).replace(expr)
|
|
||||||
ret += self.compile(e)
|
|
||||||
self.imports = defaultdict(set)
|
self.imports = defaultdict(set)
|
||||||
return ret.stmts
|
return ret.stmts
|
||||||
|
|
||||||
@ -818,11 +820,22 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
@special("assert", [FORM, maybe(FORM)])
|
@special("assert", [FORM, maybe(FORM)])
|
||||||
def compile_assert_expression(self, expr, root, test, msg):
|
def compile_assert_expression(self, expr, root, test, msg):
|
||||||
|
if msg is None or type(msg) is HySymbol:
|
||||||
ret = self.compile(test)
|
ret = self.compile(test)
|
||||||
e = ret.force_expr
|
return ret + asty.Assert(
|
||||||
if msg is not None:
|
expr,
|
||||||
msg = self.compile(msg).force_expr
|
test=ret.force_expr,
|
||||||
return ret + asty.Assert(expr, test=e, msg=msg)
|
msg=(None if msg is None else self.compile(msg).force_expr))
|
||||||
|
|
||||||
|
# The `msg` part may involve statements, which we only
|
||||||
|
# want to be executed if the assertion fails. Rewrite the
|
||||||
|
# form to set `msg` to a variable.
|
||||||
|
msg_var = self.get_anon_var()
|
||||||
|
return self.compile(mkexpr(
|
||||||
|
'if*', mkexpr('and', '__debug__', mkexpr('not', [test])),
|
||||||
|
mkexpr('do',
|
||||||
|
mkexpr('setv', msg_var, [msg]),
|
||||||
|
mkexpr('assert', 'False', msg_var))).replace(expr))
|
||||||
|
|
||||||
@special(["global", "nonlocal"], [oneplus(SYM)])
|
@special(["global", "nonlocal"], [oneplus(SYM)])
|
||||||
def compile_global_or_nonlocal(self, expr, root, syms):
|
def compile_global_or_nonlocal(self, expr, root, syms):
|
||||||
@ -1364,19 +1377,17 @@ class HyASTCompiler(object):
|
|||||||
# We need to ensure the statements for the condition are
|
# We need to ensure the statements for the condition are
|
||||||
# executed on every iteration. Rewrite the loop to use a
|
# executed on every iteration. Rewrite the loop to use a
|
||||||
# single anonymous variable as the condition.
|
# single anonymous variable as the condition.
|
||||||
def e(*x): return HyExpression(x)
|
cond_var = self.get_anon_var()
|
||||||
s = HySymbol
|
return self.compile(mkexpr(
|
||||||
cond_var = s(self.get_anon_var())
|
'do',
|
||||||
return self.compile(e(
|
mkexpr('setv', cond_var, 'True'),
|
||||||
s('do'),
|
mkexpr('while', cond_var,
|
||||||
e(s('setv'), cond_var, 1),
|
|
||||||
e(s('while'), cond_var,
|
|
||||||
# Cast the condition to a bool in case it's mutable and
|
# Cast the condition to a bool in case it's mutable and
|
||||||
# changes its truth value, but use (not (not ...)) instead of
|
# changes its truth value, but use (not (not ...)) instead of
|
||||||
# `bool` in case `bool` has been redefined.
|
# `bool` in case `bool` has been redefined.
|
||||||
e(s('setv'), cond_var, e(s('not'), e(s('not'), cond))),
|
mkexpr('setv', cond_var, mkexpr('not', mkexpr('not', [cond]))),
|
||||||
e(s('if*'), cond_var, e(s('do'), *body)),
|
mkexpr('if*', cond_var, mkexpr('do', rest=body)),
|
||||||
*([e(s('else'), *else_expr)] if else_expr is not None else []))).replace(expr)) # noqa
|
*([mkexpr('else', rest=else_expr)] if else_expr is not None else []))).replace(expr)) # noqa
|
||||||
|
|
||||||
orel = Result()
|
orel = Result()
|
||||||
if else_expr is not None:
|
if else_expr is not None:
|
||||||
|
@ -1653,16 +1653,15 @@ macros()
|
|||||||
(= (identify-keywords 1 "bloo" :foo)
|
(= (identify-keywords 1 "bloo" :foo)
|
||||||
["other" "other" "keyword"])))
|
["other" "other" "keyword"])))
|
||||||
|
|
||||||
#@(pytest.mark.xfail
|
|
||||||
(defn test-assert-multistatements []
|
(defn test-assert-multistatements []
|
||||||
; https://github.com/hylang/hy/issues/1390
|
; https://github.com/hylang/hy/issues/1390
|
||||||
(setv s (set))
|
(setv l [])
|
||||||
(defn f [x]
|
(defn f [x]
|
||||||
(.add s x)
|
(.append l x)
|
||||||
False)
|
False)
|
||||||
(with [(pytest.raises AssertionError)]
|
(with [(pytest.raises AssertionError)]
|
||||||
(assert (do (f 1) (f 2)) (do (f 3) (f 4))))
|
(assert (do (f 1) (f 2)) (do (f 3) (f 4))))
|
||||||
(assert (= s #{1 2 3 4}))))
|
(assert (= l [1 2 3 4])))
|
||||||
|
|
||||||
(defn test-underscore_variables []
|
(defn test-underscore_variables []
|
||||||
; https://github.com/hylang/hy/issues/1340
|
; https://github.com/hylang/hy/issues/1340
|
||||||
|
Loading…
Reference in New Issue
Block a user