cleanup ltsmin bindings

* python/spot/aux.py (rm_f): new function.
* python/spot/ltsmin.i: Replace the %require magic by a simple function.
Rewrite the %%dve magic.
* tests/python/otfcrash.py: Simplify using spot.ltsmin.require()
* tests/python/ltsmin.ipynb: Likewise, also add more text for the
documentation.
* NEWS: Adjust.
This commit is contained in:
Alexandre Duret-Lutz 2016-02-16 19:08:28 +01:00
parent 9b5a763538
commit 9692d734a9
5 changed files with 559 additions and 611 deletions

8
NEWS
View file

@ -104,11 +104,9 @@ New in spot 1.99.7a (not yet released)
Python: Python:
* The ltsmin interface has been binded in Python. See * The ltsmin interface has been binded in Python. It also
https://spot.lrde.epita.fr/ipynb/ltsmin.html for a short example. comes with a %%dve cell magic to edit DiVinE models in the notebook.
See https://spot.lrde.epita.fr/ipynb/ltsmin.html for a short example.
* The ltsmin interface support two extra 'magic commands' when ipython
is used: %dve and %%require.
* spot.setup() sets de maximum number of states to display in * spot.setup() sets de maximum number of states to display in
automata to 50 by default, as more states is likely to be automata to 50 by default, as more states is likely to be

View file

@ -24,7 +24,8 @@ Auxiliary functions for Spot's Python bindings
from functools import lru_cache from functools import lru_cache
import subprocess import subprocess
import sys import sys
import os
import errno
def extend(*classes): def extend(*classes):
""" """
@ -68,3 +69,14 @@ def ostream_to_svg(ostr):
Encode an ostringstream as utf-8 and send it to dot for cocnversion to SVG. Encode an ostringstream as utf-8 and send it to dot for cocnversion to SVG.
""" """
return str_to_svg(ostr.str().encode('utf-8')) return str_to_svg(ostr.str().encode('utf-8'))
def rm_f(filename):
"""
Remove filename if it exists.
"""
try:
os.remove(filename)
except OSError as e:
if e.errno != errno.ENOENT:
raise

View file

@ -67,6 +67,9 @@ namespace std {
%pythoncode %{ %pythoncode %{
import spot import spot
import spot.aux
import sys
import subprocess
def load(filename): def load(filename):
return model.load(filename) return model.load(filename)
@ -107,69 +110,19 @@ class model:
res += '\n'; res += '\n';
return res return res
# Load IPython specific support if we can. def require(tool):
try: """
# Load only if we are running IPython. Exit with status code 77 if the required tool is not installed.
__IPYTHON__
from IPython.core.magic import (Magics, magics_class, line_cell_magic) This function is mostly useful in Spot test suite, where 77 is a
from IPython.core.magic_arguments \ code used to indicate that some test should be skipped.
import (argument, magic_arguments, parse_argstring) """
import os if tool != "divine":
import tempfile raise ValueError("unsupported argument for require(): " + tool)
import sys
import shutil import shutil
try:
import ipywidgets as widgets
except ImportError:
pass
# This class provides support for %%dve model description
@magics_class
class EditDVE(Magics):
@line_cell_magic
def dve(self, line, cell=None):
try:
# DiViNe prefers when files are in the current directory
# so write cell into local file
t = tempfile.NamedTemporaryFile(dir=os.getcwd())
filename = t.name + '.dve'
f = open(filename,"w")
f.write(cell)
f.close()
# Then compile and unlink temporary files
import subprocess
out=""
self.shell.user_ns[line] = None
out = subprocess.check_call(['divine', 'compile',
'--ltsmin', filename])
os.unlink(filename)
os.unlink(filename + '.cpp')
self.shell.user_ns[line] = load(filename + '2C')
os.unlink(filename + '2C')
except Exception as error:
try:
os.unlink(filename)
os.unlink(filename + '.cpp')
finally:
if out != "":
raise RuntimeError(out) from error
raise error
@line_cell_magic
def require(self, line, cell=None):
if line != "divine":
print ("Unknown" + line, file=sys.stderr)
sys.exit(77)
if cell != None:
print ("No support for Cell magic command")
sys.exit(77)
if shutil.which("divine") == None: if shutil.which("divine") == None:
print ("divine not available", file=sys.stderr) print ("divine not available", file=sys.stderr)
sys.exit(77) sys.exit(77)
import subprocess
out = subprocess.check_output(['divine', 'compile', out = subprocess.check_output(['divine', 'compile',
'--help'], stderr=subprocess.STDOUT) '--help'], stderr=subprocess.STDOUT)
if b'LTSmin' not in out: if b'LTSmin' not in out:
@ -177,6 +130,46 @@ try:
file=sys.stderr) file=sys.stderr)
sys.exit(77) sys.exit(77)
# Load IPython specific support if we can.
try:
# Load only if we are running IPython.
__IPYTHON__
from IPython.core.magic import Magics, magics_class, cell_magic
import os
import tempfile
@magics_class
class EditDVE(Magics):
@cell_magic
def dve(self, line, cell):
if not line:
raise ValueError("missing variable name for %%dve")
# DiViNe prefers when files are in the current directory
# so write cell into local file
with tempfile.NamedTemporaryFile(dir='.', suffix='.dve') as t:
t.write(cell.encode('utf-8'))
t.flush()
try:
p = subprocess.Popen(['divine', 'compile',
'--ltsmin', t.name],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True)
out = p.communicate()
if out[0]:
print(out[0], file=sys.stderr)
ret = p.wait()
if ret:
raise subprocess.CalledProcessError(ret, 'divine')
self.shell.user_ns[line] = load(t.name + '2C')
finally:
spot.aux.rm_f(t.name + '.cpp')
spot.aux.rm_f(t.name + '2C')
ip = get_ipython() ip = get_ipython()
ip.register_magics(EditDVE) ip.register_magics(EditDVE)

File diff suppressed because it is too large Load diff

View file

@ -4,14 +4,7 @@ import tempfile
import shutil import shutil
import sys import sys
# this test requires divine with --ltsmin support spot.ltsmin.require('divine')
if shutil.which("divine") == None:
sys.exit(77)
import subprocess
out = subprocess.check_output(['divine', 'compile',
'--help'], stderr=subprocess.STDOUT)
if b'LTSmin' not in out:
sys.exit(77)
# the test case actually starts here # the test case actually starts here
with tempfile.NamedTemporaryFile(dir='.', suffix='.dve') as fp: with tempfile.NamedTemporaryFile(dir='.', suffix='.dve') as fp: