diff --git a/doc/source/testing_and_debugging.rst b/doc/source/testing_and_debugging.rst index 1f7f1adc4..f804a30a1 100644 --- a/doc/source/testing_and_debugging.rst +++ b/doc/source/testing_and_debugging.rst @@ -79,12 +79,14 @@ supported sub-commands. This utility will allow to print a representation of the DragonFlow model in -different formats. Currently supported formats are: text, PlantUML and +different formats. Currently supported formats are: text, PlantUML, rst and JsonSchema (OpenApiSchema 3.0). The output may be sent to the stdout or to a file. * PlantUML output can be visualized using the PlantUML Server [#]_ +* rst output can be visualized using Online reStructuredText editor [#]_ Use the *df-model --help* command to get a detailed usage instructions. .. [#] https://gist.github.com/omeranson/5c731955edcf0517bfb0ce0ce511cc9b .. [#] http://www.plantuml.com/plantuml/uml/ +.. [#] http://rst.ninjs.org/?theme=nature diff --git a/dragonflow/cli/df_model.py b/dragonflow/cli/df_model.py index 2ce6590a4..742bd8776 100644 --- a/dragonflow/cli/df_model.py +++ b/dragonflow/cli/df_model.py @@ -20,6 +20,7 @@ import sys from jsonmodels import fields from oslo_serialization import jsonutils +import prettytable from dragonflow.db import field_types from dragonflow.db import model_framework @@ -391,6 +392,80 @@ class OASPrinter(ModelsPrinter): pass +class RstPrinter(ModelsPrinter): + """ModelPrinter that prints to reStructuredText format. + + This printer prints output that can be reused and included in rst files + for documentation purposes. + """ + def __init__(self, fh): + super(RstPrinter, self).__init__(fh) + self._model_fields_table = prettytable.PrettyTable( + ['Field', 'Type', 'Restrictions', 'Required', 'Embedded', 'List']) + # The empty column was added as a patch, as rst does not accept + # single column tables + self._model_indexes_table = prettytable.PrettyTable(['Index', '']) + self._model_events_table = prettytable.PrettyTable(['Event', '']) + self._set_rst_tables_style() + self._model_printed = False + + def _set_rst_tables_style(self): + for table in (self._model_fields_table, + self._model_indexes_table, + self._model_events_table): + table.horizontal_char = '=' + table.vertical_char = ' ' + table.junction_char = ' ' + table.header_style = 'cap' + table.align = 'l' + + def model_start(self, model_name): + # Print separator, anchor and title + if self._model_printed: + self._print('\n----\n') + _title = '{}'.format(model_name) + _surround_line = '-' * len(_title) + self._print(_surround_line) + self._print(_title) + self._print(_surround_line) + + def model_end(self, model_name): + self._model_printed = True + + def fields_end(self): + self._print(self._model_fields_table) + self._model_fields_table.clear_rows() + + def handle_field(self, field_name, field_type, is_required, is_embedded, + is_single, restrictions): + restriction_str = '{}'.format(restrictions) if restrictions else '' + if field_type in BASIC_TYPES: + type_str = field_type + else: + type_str = '`{}`_'.format(field_type, field_type) + self._model_fields_table.add_row([field_name, type_str, + restriction_str, is_required, + is_embedded, not is_single]) + + def indexes_end(self): + self._print('\n|\n') + self._print(self._model_indexes_table) + self._model_indexes_table.clear_rows() + + def handle_index(self, index_name): + self._model_indexes_table.add_row([index_name, '']) + + def events_end(self): + self._print('') + self._print('|') + self._print('') + self._print(self._model_events_table) + self._model_events_table.clear_rows() + + def handle_event(self, event_name): + self._model_events_table.add_row([event_name, '']) + + class DfModelsParser(object): """Parser for the Dragonflow models schema @@ -540,12 +615,16 @@ def smart_open(filename=None): def main(): parser = argparse.ArgumentParser(description='Print Dragonflow schema') group = parser.add_mutually_exclusive_group() - group.add_argument('--plaintext', help='Plaintext output (default)', + group.add_argument('--plaintext', + help='Plaintext output (default)', action='store_true') group.add_argument('--uml', help='PlantUML format output', action='store_true') group.add_argument('--json', help='OpenApiSchema JSON format output', action='store_true') + group.add_argument('--rst', + help='reStructuredText output', + action='store_true') parser.add_argument('-o', '--outfile', help='Output to file (instead of stdout)') args = parser.parse_args() @@ -554,6 +633,8 @@ def main(): printer = UMLPrinter(fh) elif args.json: printer = OASPrinter(fh) + elif args.rst: + printer = RstPrinter(fh) else: printer = PlaintextPrinter(fh) parser = DfModelsParser(printer) diff --git a/test-requirements.txt b/test-requirements.txt index d13aac770..8bbe68913 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -19,3 +19,4 @@ testtools>=2.2.0 # MIT redis>=2.10.0 # MIT hiredis>=0.2.0 # BSD reno>=2.5.0 # Apache-2.0 +PrettyTable>=0.7.1,<0.8 # BSD