Commit cbfbf536 authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz
Browse files

python: make sure spot.automata() terminates the command

Fixes #341.

* python/spot/ (automata): Rewrite and simplify using
the subprocess context manager.
* tests/python/ New file.
* tests/ Add it.
* NEWS: Mention the issue.
parent 6afc2d45
Pipeline #1229 passed with stages
in 111 minutes and 15 seconds
......@@ -59,6 +59,9 @@ New in spot (not yet released)
- "autfilt -B --sat-minimize" was incorrectly producing
transition-based automata.
- Using spot.automata("cmd...|") to read just a few automata out of
an infinite stream would not properly terminate the command.
New in spot 2.5.2 (2018-03-25)
Bugs fixed:
......@@ -34,6 +34,7 @@ import subprocess
import os
import signal
import tempfile
from contextlib import suppress as _supress
# The parrameters used by default when show() is called on an automaton.
_show_default = None
......@@ -441,30 +442,33 @@ def automata(*sources, timeout=None, ignore_abort=True,
p = automaton_stream_parser(filename, o)
a = True
while a:
# This returns None when we reach the end of the file.
a = p.parse(_bdd_dict).aut
if a:
yield a
# Using proc as a context manager ensures that proc.stdout will be
# closed on exit, and the process will be properly waited for.
# This is important when running tools that produce an infinite
# stream of automata and that must be killed once the generator
# returned by spot.automata() is destroyed. Otherwise, _supress()
# is just a dummy context manager that does nothing (Python 3.7
# introduces nullcontext() for this purpose, but at the time of
# writing we support Python 3.4).
mgr = proc if proc else _supress()
with mgr:
while a:
# This returns None when we reach the end of the file.
a = p.parse(_bdd_dict).aut
if a:
yield a
# Make sure we destroy the parser (p) and the subprocess
# (prop) in the correct order...
# (prop) in the correct order.
del p
if proc is not None:
if not a:
# We reached the end of the stream. Wait for the
# process to finish, so that we get its exit code.
ret = proc.wait()
# if a != None, we probably got there through an
# exception, and the subprocess might still be
# running. Check if an exit status is available
# just in case.
ret = proc.poll()
ret = proc.returncode
del proc
if ret:
# Do not complain about the exit code if we are already raising
# an exception.
if ret and sys.exc_info()[0] is None:
raise subprocess.CalledProcessError(ret, filename[:-1])
# deleting o explicitely now prevents Python 3.5 from
# deleting o explicitly now prevents Python 3.5 from
# reporting the following error: "<built-in function
# delete_automaton_parser_options> returned a result with
# an error set". It's not clear to me if the bug is in Python
......@@ -351,10 +351,10 @@ TESTS_ipython = \
# do not consider part of the documentation: those have to start
# with a _.
TESTS_python = \
python/ \
python/_altscc.ipynb \
python/_autparserr.ipynb \
python/_aux.ipynb \
python/_word.ipynb \
python/ \
python/ \
python/ \
......@@ -362,6 +362,7 @@ TESTS_python = \
python/ \
python/ \
python/ \
python/_word.ipynb \
python/ \
python/ \
python/ \
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2017 Laboratoire de Recherche et Développement de l'Epita
# (LRDE).
# This file is part of Spot, a model checking library.
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <>.
import spot
from subprocess import _active
def two_intersecting_automata():
"""return two random automata with a non-empty intersection"""
g = spot.automata('randaut -A4 -Q5 -n-1 2 |')
for a, b in zip(g, g):
if a.intersects(b):
return a, b
for i in range(5):
n = len(_active)
print(n, "active processes")
assert(n == 0);
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment