Commit 18784113 authored by Lucas Bourneuf's avatar Lucas Bourneuf
Browse files

working POC for export \o/ It's impressive ! See new example.

parent 0ad54e31
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import biseau as bs import biseau as bs
import datetime import datetime
import itertools import itertools
from functools import wraps
from . import Script, __version__ from . import Script, __version__
try: try:
import black import black
...@@ -21,22 +22,9 @@ def get_pipeline_options(scripts:[Script]) -> dict: ...@@ -21,22 +22,9 @@ def get_pipeline_options(scripts:[Script]) -> dict:
return {n: False for _, __, n in option_names_from_options(scripts)} 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]: def _standalone_export_pipeline(scripts:[Script], options:dict={}, default_context:str='',
"""Return a string of Python code, implementing a standalone program reproducing given pipeline. metarg_outfile:str='out.png', metarg_dotfile:str='out.dot',
metarg_dot_prog:str='dot', verbosity:int=0) -> [str]:
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.
"""
gen = _standalone_export_pipeline(scripts, options, default_context, verbosity)
python_code = '\n'.join(gen)
if black:
return black.format_str(python_code, mode=black.FileMode())
return python_code
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. """Yield Python code strings, implementing a standalone program reproducing given pipeline.
options -- {option name: bool} indicating whether or not the option options -- {option name: bool} indicating whether or not the option
...@@ -46,18 +34,19 @@ def _standalone_export_pipeline(scripts:[Script], options:dict={}, default_conte ...@@ -46,18 +34,19 @@ def _standalone_export_pipeline(scripts:[Script], options:dict={}, default_conte
""" """
option_names = {(idx, name): final_name for idx, (_, name, final_name) in enumerate(option_names_from_options(scripts))} option_names = {(idx, name): final_name for idx, (_, name, final_name) in enumerate(option_names_from_options(scripts))}
print('OPTIONS NAMES:', option_names) # print('OPTIONS NAMES:', option_names)
print('RECOGNIZED OPTIONS:', options) # print('RECOGNIZED OPTIONS:', options)
options_used = tuple( options_used = tuple(
((idx, name), final_name) for (idx, name), final_name in option_names.items() ((idx, name), final_name) for (idx, name), final_name in option_names.items()
if options.get(final_name) if options.get(final_name)
) )
print('OPTIONS USED:', options_used) # print('OPTIONS USED:', options_used)
yield '"""Standalone script generated by biseau ' + str(__version__) + ', ' + str(datetime.datetime.now()) + '"""\n' yield '"""Standalone script generated by biseau ' + str(__version__) + ', ' + str(datetime.datetime.now()) + '"""\n'
yield 'import os' yield 'import os'
yield 'import argparse' yield 'import argparse'
yield 'from clitogui import clitogui' yield 'from clitogui import clitogui'
yield 'import clyngor' yield 'import clyngor'
yield 'import biseau'
yield '' yield ''
if options_used: if options_used:
yield '@clitogui.clitogui' yield '@clitogui.clitogui'
...@@ -89,9 +78,9 @@ def _standalone_export_pipeline(scripts:[Script], options:dict={}, default_conte ...@@ -89,9 +78,9 @@ def _standalone_export_pipeline(scripts:[Script], options:dict={}, default_conte
def as_dict(opts): def as_dict(opts):
return {name: vals for name, *vals in opts} return {name: vals for name, *vals in opts}
option = as_dict(scripts[idx].options)[final_name] option = as_dict(scripts[idx].options)[final_name]
func, args = argparse_addarg_args_from_option(final_name, option) func, args = argparse_addarg_args_from_option(final_name, option, explicit_value=scripts[idx].options_values.get(name))
yield f' parser.{func}({", ".join(args)})' yield f' parser.{func}({", ".join(args)})'
print('MAKE ARG:', f' parser.{func}({", ".join(args)})') # print('MAKE ARG:', f' parser.{func}({", ".join(args)})')
yield ' return parser' yield ' return parser'
yield '' yield ''
else: else:
...@@ -119,14 +108,19 @@ def _standalone_export_pipeline(scripts:[Script], options:dict={}, default_conte ...@@ -119,14 +108,19 @@ def _standalone_export_pipeline(scripts:[Script], options:dict={}, default_conte
else: else:
raise ValueError(f"unhandled export of language '{script.language}'") raise ValueError(f"unhandled export of language '{script.language}'")
runon_args = ', '.join(f"{name}={name}" for name, *_ in script.options) runon_args = ', '.join(f"{name}={name}" for name, *_ in script.options)
yield f' return \'\'.join(run_on(context, {runon_args}))' new_context = f"''.join(run_on(context, {runon_args}))"
if not script.erase_context:
new_context = 'context + ' + new_context
yield f' return {new_context}'
yield 'def run_on(context:str, args):' yield 'def run_on(context:str, args):'
for runon, script in runons: for runon, script in runons:
target_idx = scripts.index(script) target_idx = scripts.index(script)
options = ((name, final_name) for (idx, name), final_name in options_used if idx == target_idx) options = ((name, final_name) for (idx, name), final_name in options_used if idx == target_idx)
args = ', '.join(f"{name}=args.{final_name}" for name, final_name in options) args = ', '.join(f"{name}=args.{final_name}" for name, final_name in options)
yield f' context = {runon}(context, {args})' yield f' context = {runon}(context, {args})'
yield ' print(context)'
yield f' biseau.compile_to_single_image(context, outfile={repr(metarg_outfile)}, dotfile={repr(metarg_dotfile)}, dot_prog={repr(metarg_dot_prog)}, verbosity={repr(verbosity)})'
yield ' return context'
yield 'if __name__ == "__main__":' yield 'if __name__ == "__main__":'
yield ' args = cli().parse_args()' yield ' args = cli().parse_args()'
yield ' context = ' + repr(default_context) yield ' context = ' + repr(default_context)
...@@ -165,9 +159,10 @@ def option_names_from_options(scripts:[Script]) -> [(str, str, str)]: ...@@ -165,9 +159,10 @@ def option_names_from_options(scripts:[Script]) -> [(str, str, str)]:
yield script_name, name, final_name yield script_name, name, final_name
def argparse_addarg_args_from_option(name:str, option) -> [str]: def argparse_addarg_args_from_option(name:str, option, *, explicit_value=None) -> [str]:
print('creating argparse arguments:', name, option) # print('creating argparse arguments:', name, option)
argtype, default, description = option argtype, default, description = option
if explicit_value is not None: default = explicit_value # override default
if argtype is open: if argtype is open:
ctype = 'existing_file' ctype = 'existing_file'
elif isinstance(argtype, tuple) and len(argtype) == 2 and argtype[0] is open: elif isinstance(argtype, tuple) and len(argtype) == 2 and argtype[0] is open:
...@@ -181,3 +176,20 @@ def argparse_addarg_args_from_option(name:str, option) -> [str]: ...@@ -181,3 +176,20 @@ def argparse_addarg_args_from_option(name:str, option) -> [str]:
elif isinstance(argtype, str): elif isinstance(argtype, str):
ctype = 'str' ctype = 'str'
return 'add_argument', (f"'{name}'", f'type={ctype}', f'default={repr(default)}', f'help="{description}"') return 'add_argument', (f"'{name}'", f'type={ctype}', f'default={repr(default)}', f'help="{description}"')
@wraps(_standalone_export_pipeline)
def standalone_export_pipeline(*args, **kwargs) -> [str]:
"""Return a string of Python code, 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.
"""
gen = _standalone_export_pipeline(*args, **kwargs)
python_code = '\n'.join(gen)
if black:
return black.format_str(python_code, mode=black.FileMode())
return python_code
"""Example of pipeline export"""
import biseau as bs
def take_scripts():
scripts = 'scripts/context.py', 'scripts/build_concepts.py', 'scripts/galois-lattice.json', 'scripts/show_galois_lattice.py'
for name in scripts:
yield from bs.build_scripts_from_file(name)
# get scripts and their options
scripts = tuple(take_scripts())
options = bs.export.get_pipeline_options(scripts)
# print('OPTIONS:', options)
# for script in scripts:
# print(f"Option of script {script.name} are: {script.options}")
# setting some options to be exposed in the final CLI/GUI
options['fname'] = True
options['type'] = True
scripts[0].options_values['fname'] = 'contexts/human.cxt'
# output to outfile
OUTFILE = 'out-export.py'
with open(OUTFILE, 'w') as fd:
fd.write(bs.standalone_export_pipeline(scripts, options))
print(OUTFILE, 'written')
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