def __init__(self, solver, statistics: callable = (lambda: {})): assert clyngor.have_clingo_module() super().__init__(()) self._solver = solver self._statistics = lambda s=solver: json.dumps( s.statistics, sort_keys=True, indent=4, separators=(',', ': ')) assert callable(self._statistics)
def __init__(self, solver, statistics: callable = (lambda: {})): assert clyngor.have_clingo_module() super().__init__(self.__compute_answers(), with_optimization=True, command='[clingo module call]') self._solver = solver self._statistics = lambda s=solver: s.statistics assert callable(self._statistics)
def test_syntax_error(): assert not clyngor.have_clingo_module() with pytest.raises(clyngor.ASPSyntaxError) as excinfo: tuple(clyngor.solve((), inline='invalid', force_tempfile=True)) assert excinfo.value.filename.startswith('/tmp/tmp') assert excinfo.value.lineno == 2 assert excinfo.value.offset == 1 assert excinfo.value.payload['char_end'] == 2 assert excinfo.value.msg.startswith('unexpected EOF in file /tmp/tmp') assert excinfo.value.msg.endswith(' at line 2 and column 1-2')
def test_undefined_warning(): assert not clyngor.have_clingo_module() with pytest.raises(clyngor.ASPWarning) as excinfo: tuple(clyngor.solve((), inline='b:- c.', error_on_warning=True, force_tempfile=True)) assert excinfo.value.atom == 'c' assert len(excinfo.value.args) == 1 start = "atom 'c' does not occur in any rule head in file /tmp/tmp" assert excinfo.value.args[0].startswith(start) assert excinfo.value.args[0].endswith(" at line 1 and column 5-6") # NB: the following should NOT raise any error (default value) tuple(clyngor.solve((), inline='b:- c.', error_on_warning=False)) tuple(clyngor.solve((), inline='b:- c.'))
def solve(files: iter = (), options: iter = [], inline: str = None, decoders: iter = (), subproc_shell: bool = False, print_command: bool = False, nb_model: int = 0, time_limit: int = 0, constants: dict = {}, clean_path: bool = True, stats: bool = True, clingo_bin_path: str = None, error_on_warning: bool = False, force_tempfile: bool = False, delete_tempfile: bool = True, use_clingo_module: bool = True, grounding_observers: iter = (), propagators: iter = (), solver_conf: object = None, running_sequence: callable = _default_running_sequence, programs: iter = (['base', ()], ), return_raw_output: bool = False) -> iter: """Run the solver on given files, with given options, and return an Answers instance yielding answer sets. files -- iterable of files feeding the solver options -- string or iterable of options for clingo inline -- ASP source code to feed the solver with decoders -- iterable of decoders to apply on ASP (see clyngor.decoder) subproc_shell -- use shell=True in subprocess call (NB: you should not) print_command -- print full command to stdout before running it clean_path -- clean the path of given files before using them stats -- will ask clingo for all stats, instead of just the minimal ones clingo_bin_path -- the path to the clingo binary error_on_warning -- raise an ASPWarning when encountering a clingo warning use_clingo_module -- will use the clingo module (if available) force_tempfile -- use tempfile, even if only inline code is given delete_tempfile -- delete used tempfiles return_raw_output -- don't parse anything, just return iterators over stdout and stderr, without using clingo module The following options needs the propagator support and/or python clingo module: grounding_observers -- iterable of observers to add to the grounding process propagators -- iterable of propagators to add to the solving process solver_conf -- clingo.Configuration instance, given to the running_sequence running_sequence -- If given, must be a callable taking programs, files and Configuration, returning both clingo.Control and clingo.SolveHandle instances. programs -- programs to feed the running sequence with. Shortcut to clingo's options: nb_model -- number of model to output (0 for all (default), None to disable) time_limit -- zero or number of seconds to wait before interrupting solving constants -- mapping name -> value of constants for the grounding """ files = [files] if isinstance(files, str) else files files = tuple(map(cleaned_path, files) if clean_path else files) stdin_feed = None # data to send to stdin use_clingo_module = use_clingo_module and clyngor.have_clingo_module( ) and not return_raw_output if use_clingo_module: # the clingo API do not handle stdin feeding force_tempfile = True if inline and not files and not force_tempfile: # avoid tempfile if possible stdin_feed, inline = inline, None elif inline: with tempfile.NamedTemporaryFile(mode='w', delete=False) as fd: fd.write(inline) tempfile_to_del = fd.name files = tuple(files) + (tempfile_to_del, ) assert files, fd.name run_command = command(files, options, inline, nb_model, time_limit, constants, stats, clingo_bin_path=clingo_bin_path) if print_command: print(run_command) if not files and not inline and not stdin_feed: # in this case, clingo will wait for stdin input, which will never come # so better not call clingo at all, because answer is obvious: one empty model. return Answers((), command=' '.join(run_command)) if use_clingo_module: if time_limit != 0 or constants: raise ValueError("Options 'time_limit' and 'constants' are not " "handled when used with python clingo module.") if solver_conf: raise NotImplementedError( "Solver configuration handling is currently" "not implemented") options = list( shlex.split(options) if isinstance(options, str) else options) ctl = clyngor.clingo_module.Control(options) main = running_sequence(programs=programs, files=files, nb_model=nb_model, propagators=propagators, observers=grounding_observers, generator=True) return main(ctl) else: clingo = subprocess.Popen( run_command, stdin=subprocess.PIPE if stdin_feed else None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=bool(subproc_shell), ) if stdin_feed: clingo.stdin.write(stdin_feed.encode()) clingo.stdin.close() stdout = (line.decode() for line in clingo.stdout) stderr = (line.decode() for line in clingo.stderr) if return_raw_output: return ''.join(stdout), ''.join(stderr) statistics = {} # remove the tempfile after the work. on_end = lambda: (clingo.stderr.close(), clingo.stdout.close()) if inline and tempfile_to_del and delete_tempfile: on_end = lambda: (os.remove(tempfile_to_del), clingo.stderr.close( ), clingo.stdout.close()) return Answers(_gen_answers(stdout, stderr, statistics, error_on_warning), command=' '.join(run_command), on_end=on_end, decoders=decoders, statistics=statistics, with_optimization=True)
def onlyif_no_clingo_module(func): return pytest.mark.skipif( clyngor.have_clingo_module(), reason="Require official clingo module to NOT be available")(func)