Skip to content

Commit

Permalink
Python API: fix bindings when assertions are disabled
Browse files Browse the repository at this point in the history
Python's -O command-line option disableds the execution of "assert"
statements. In order for the generated Python bindings to work in such a
mode, we need to keep assertion logic only in "assert" statements. This
commit fixes statements that currently don't respect this principle.

Fixes GitHub issue AdaCore#485
TN: U326-020
  • Loading branch information
pmderodat committed Mar 26, 2021
1 parent 80d6e2c commit 3d609f8
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 6 deletions.
8 changes: 5 additions & 3 deletions langkit/templates/python_api/module_py.mako
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,8 @@ class AnalysisUnit(object):
result = []
diag = Diagnostic._c_type()
for i in range(count):
assert _unit_diagnostic(self._c_value, i, ctypes.byref(diag))
success = _unit_diagnostic(self._c_value, i, ctypes.byref(diag))
assert success
result.append(diag._wrap())
return result

Expand Down Expand Up @@ -977,8 +978,9 @@ class Token(ctypes.Structure):
cls._check_token(last)
first._check_same_unit(last)
result = _text()
assert _token_range_text(ctypes.byref(first), ctypes.byref(last),
ctypes.byref(result))
success = _token_range_text(ctypes.byref(first), ctypes.byref(last),
ctypes.byref(result))
assert success
return result._wrap() or u''

@property
Expand Down
13 changes: 10 additions & 3 deletions testsuite/python_support/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ def build_and_run(grammar=None, py_script=None, ada_main=None, lexer=None,
version: str = "undefined",
build_date: str = "undefined",
full_error_traces: bool = True,
additional_make_args: List[str] = []):
additional_make_args: List[str] = [],
python_args: Optional[List[str]] = None):
"""
Compile and emit code for `ctx` and build the generated library. Then,
execute the provided scripts/programs, if any.
Expand Down Expand Up @@ -248,6 +249,9 @@ def build_and_run(grammar=None, py_script=None, ada_main=None, lexer=None,
:param additional_make_args: Additional command-line arguments to pass to
"manage.py make".
:param python_args: Arguments to pass to the Python interpreter when
running a Python script.
"""
assert not types_from_lkt or lkt_file is not None

Expand Down Expand Up @@ -362,8 +366,11 @@ def run(*argv, **kwargs):
# library, we have to use the special Python interpreter the testsuite
# provides us. See the corresponding code in
# testuite_support/python_driver.py.
python_interpreter = os.environ['PYTHON_INTERPRETER']
run(python_interpreter, py_script)
args = [os.environ['PYTHON_INTERPRETER']]
if python_args:
args.extend(python_args)
args.append(py_script)
run(*args)

if ada_main is not None:
if isinstance(ada_main, str):
Expand Down
12 changes: 12 additions & 0 deletions testsuite/tests/python_api/asserts/expected_concrete_syntax.lkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import lexer_example
@with_lexer(foo_lexer)
grammar foo_grammar {
@main_rule main_rule <- list+(Example("example"))

}

@abstract class FooNode : Node {
}

class Example : FooNode {
}
21 changes: 21 additions & 0 deletions testsuite/tests/python_api/asserts/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import sys

import libfoolang


print('main.py: Running...')

ctx = libfoolang.AnalysisContext()
u = ctx.get_from_buffer('foo.txt', b'{example example')

print("Diagnostics:")
for d in u.diagnostics:
print(d)
print("")

print("Token range:")
text_range = libfoolang.Token.text_range(u.first_token, u.last_token)
print(libfoolang._py2to3.text_repr(text_range))
print("")

print('main.py: Done.')
8 changes: 8 additions & 0 deletions testsuite/tests/python_api/asserts/test.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
main.py: Running...
u.root.p_count(None) = <TypeError: list instance expected, got NoneType instead>
u.root.p_count(42) = <TypeError: list instance expected, got int instead>
u.root.p_count(u.root.p_all_items) = 3
u.root.p_example_items = [<Example foo.txt:1:1-1:8>, <Example foo.txt:1:14-1:21>]
u.root.p_count(u.root.p_example_items) = 2
main.py: Done.
Done
26 changes: 26 additions & 0 deletions testsuite/tests/python_api/asserts/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""
Regression test: check that getting the list of diagnostics and the range of
text between two tokens works when Python assertions are disabled. This used
not to work because "operational" code was in assert statements in the Python
bindings.
"""

from langkit.dsl import ASTNode

from utils import build_and_run


class FooNode(ASTNode):
pass


class Example(FooNode):
token_node = True


build_and_run(
lkt_file='expected_concrete_syntax.lkt',
py_script='main.py',
python_args=["-O"],
)
print('Done')
1 change: 1 addition & 0 deletions testsuite/tests/python_api/asserts/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
driver: python

0 comments on commit 3d609f8

Please sign in to comment.