Commit 14031a1d authored by Lucas Bourneuf's avatar Lucas Bourneuf

first steps to implement a full export

parent 8a970d99
......@@ -18,6 +18,11 @@ Now, you may want to read about:
- [scripting](doc/user-doc.mkd#scripting), that allow you to implement new behavior for biseau.
### Export as standalone script
Currently under development.
## Installation
See [user documentation](doc/user-doc.mkd#installation) for details,
......
......@@ -3,3 +3,4 @@ __version__ = '0.0.7.dev0'
from .script import Script
from .core import run, single_image_from_filenames, multiple_images_from_filenames, gif_from_filenames, compile_to_single_image, compile_to_images, compile_context_to_dots, compile_context_to_dot
from .module_loader import build_scripts_from_file, build_scripts_from_dir
from .export import standalone_export_pipeline
"""Routines for the export of scripts to various form
"""
import itertools
from . import Script, __version__
def get_pipeline_options(scripts:[Script]) -> dict:
"""Return the mapping option->False to be used by standalone_export_pipeline.
One may want to set some options to True, to get them in pipeline standalone export.
"""
return {n: False for _, __, n in option_names_from_options(scripts)}
def standalone_export_pipeline(scripts:[Script], options:dict={}, default_context:str='', verbosity:int=0) -> [str]:
"""Yield Python code strings, implementing a standalone program reproducing given pipeline.
options -- {option name: bool} indicating whether or not the option
must be exposed as program option.
default_context -- the default initial context.
verbosity -- verbosity of the standalone program itself.
"""
option_names = {(idx, name): final_name for idx, (_, name, final_name) in enumerate(option_names_from_options(scripts), 1)}
options_used = tuple(
(idx, final_name) for idx, final_name in option_names.items()
if options[final_name]
)
yield '"Standalone script generated by biseau ' + str(__version__) + '"\n'
yield 'import argparse'
yield 'import clitogui'
yield 'import clyngor'
yield ''
if options:
yield '@clitogui'
yield 'def cli():'
yield ' parser = argparse.ArgumentParser()'
for (idx, name), final_name in options_used:
option = scripts[idx-1].options
option = scripts[idx].options[name]
print(option)
yield f' parser.addArgument({final_name})'
yield ' ...'
yield ' return parser'
yield ''
yield 'def run_on(context:str, ' + ', '.join(name for _, name in options_used) + '):'
for script in scripts:
if script.language == 'python':
yield ' models = clyngor.solve(inline=context).by_predicate'
elif script.language == 'asp':
yield ' context += """\n' + script.source_code + '\n"""'
else:
raise ValueError(f"unhandled export of language '{script.language}'")
yield 'if __name__ == "__main__":'
yield ' args = cli()'
yield ' for dot in run_on(**args):'
yield ' print(dot)'
def option_names_from_options(scripts:[Script]) -> [(str, str, str)]:
"""Yield (script name, option name, unambiguous option name)
so that unambiguous option name is deterministic and unique
accross all options of given scripts.
"""
used_names = set() # set of all available options
conflicting_names = set() # names that will need the script name
script_names = tuple(script.name for script in scripts)
script_name_doublons = {n: itertools.count(1) for n in script_names if script_names.count(n) > 1}
# define names of scripts (append their index when multiple scripts of same name)
script_names = tuple(
(script.name + ' ' + str(next(script_name_doublons[script.name])))
if script.name in script_name_doublons else script.name
for script in scripts
)
assert len(script_names) == len(scripts)
# detect the name conflicts among scripts options
for script in scripts:
for name, type, default, description in script.options:
if name in used_names:
conflicting_names.add(name)
used_names.add(name)
# for each script, ensure the use of proper option name
for script_name, script in zip(script_names, scripts):
for name, type, default, description in script.options:
final_name = name
if name in conflicting_names:
final_name = f'{script_name}: {name}'
yield script_name, name, final_name
from biseau import standalone_export_pipeline
from biseau.module_loader import build_scripts_from_asp_code
ASP_LINK = 'link(a,b).'
def test_standalone_export_pipeline():
scripts = tuple((
*build_scripts_from_asp_code(ASP_LINK),
*build_scripts_from_asp_code('link(X,1..3) :- link(X,_).'),
))
expected_lines = []
# assert tuple(standalone_export_pipeline(scripts)) == expected_lines
Markdown is supported
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