From e9c0abcdc4e6afff7a5cb191803bcd650e10268e Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sun, 21 Dec 2025 21:39:47 +0100 Subject: [PATCH] feat: first version --- LICENSE | 165 ++++++++++++++++++ README.fr.md | 22 +++ README.md | 22 +++ locale/fr/LC_MESSAGES/rougail_output_table.po | 62 +++++++ locale/rougail_output_table.pot | 53 ++++++ src/rougail/output_table/__init__.py | 139 +++++++++++++++ src/rougail/output_table/__version__.py | 1 + src/rougail/output_table/config.py | 78 +++++++++ src/rougail/output_table/i18n.py | 26 +++ .../fr/LC_MESSAGES/rougail_output_table.mo | Bin 0 -> 1392 bytes 10 files changed, 568 insertions(+) create mode 100644 LICENSE create mode 100644 README.fr.md create mode 100644 README.md create mode 100644 locale/fr/LC_MESSAGES/rougail_output_table.po create mode 100644 locale/rougail_output_table.pot create mode 100644 src/rougail/output_table/__init__.py create mode 100644 src/rougail/output_table/__version__.py create mode 100644 src/rougail/output_table/config.py create mode 100644 src/rougail/output_table/i18n.py create mode 100644 src/rougail/output_table/locale/fr/LC_MESSAGES/rougail_output_table.mo diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/README.fr.md b/README.fr.md new file mode 100644 index 0000000..948dd45 --- /dev/null +++ b/README.fr.md @@ -0,0 +1,22 @@ +--- +gitea: none +include_toc: true +--- +[🇬🇧 (EN)](README.md) - [🇫🇷 (FR)](README.fr.md) + +## Affiche les données dans un tableau + +> [!NOTE] +> +> **Chemin** : table\ +> *`désactivé`*\ +> **Désactivé** : si table n'est pas mis dans "[Sélection pour sortie](#step.output)" + +| Variable | Description | Valeur par défaut | Type | Validateur | +|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------| +| **table.first_column**
**Ligne de commande** : --table.first_column
**Variable d'environnement** : TABLE.FIRST_COLUMN | Contenu de la première colonne. | La première colonne est description si "[Noms des étiquettes](#table.columns)" n'a qu'une valeur, sinon c'est namespace | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | Le nom de l'étiquette ne doit pas avoir le même nom que la première colonne.
**Choix** :
• description
• namespace | +| **table.columns**
**Ligne de commande** : --table.columns
**Variable d'environnement** : TABLE.COLUMNS | Noms des étiquettes.
Chaque étiquette créée une colonne. Le contenu des colonnes viennent des variables avec les étiquettes définis. | | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` `obligatoire` | `unique` | +| **table.output_format**
**Ligne de commande** : --table.output_format
**Variable d'environnement** : TABLE.OUTPUT_FORMAT | Noms des étiquettes. | console | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | **Choix** :
• console
• github
• asciidoc
• html
• rst | +| **table.header**
**Ligne de commande** :
• --table.header
• --table.no-header
**Variable d'environnement** : TABLE.HEADER | Ajouter l'entête dans le tableau. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | | + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..c527e64 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +--- +gitea: none +include_toc: true +--- +[🇬🇧 (EN)](README.md) - [🇫🇷 (FR)](README.fr.md) + +## Displays the data in a table + +> [!NOTE] +> +> **Path**: table\ +> *`disabled`*\ +> **Disabled**: if table is not set in "[Select for output](#step.output)" + +| Variable | Description | Default value | Type | Validator | +|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------| +| **table.first_column**
**Command line**: --table.first_column
**Environment variable**: TABLE.FIRST_COLUMN | Content of the first column. | First column is description if "[Tag names](#table.columns)" has only one value, otherwise it's namespace | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | Tag name must not have the same name has first column.
**Choices**:
• description
• namespace | +| **table.columns**
**Command line**: --table.columns
**Environment variable**: TABLE.COLUMNS | Tag names.
Each tag creates a column. The content of the columns comes from the variables with the defined tags. | | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` `mandatory` | `unique` | +| **table.output_format**
**Command line**: --table.output_format
**Environment variable**: TABLE.OUTPUT_FORMAT | Tag names. | console | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | **Choices**:
• console
• github
• asciidoc
• html
• rst | +| **table.header**
**Command line**:
• --table.header
• --table.no-header
**Environment variable**: TABLE.HEADER | Add header in table. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | | + + diff --git a/locale/fr/LC_MESSAGES/rougail_output_table.po b/locale/fr/LC_MESSAGES/rougail_output_table.po new file mode 100644 index 0000000..e463025 --- /dev/null +++ b/locale/fr/LC_MESSAGES/rougail_output_table.po @@ -0,0 +1,62 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2025-12-21 21:18+0100\n" +"PO-Revision-Date: 2025-12-21 21:26+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" +"X-Generator: Poedit 3.8\n" + +#: src/rougail/output_table/__init__.py:55 +msgid "the \"step.output\" is not set to \"{0}\"" +msgstr "\"step.output\" n'est pas mis à \"{0}\"" + +#: src/rougail/output_table/config.py:28 +msgid "Displays the data in a table" +msgstr "Affiche les données dans un tableau" + +#: src/rougail/output_table/config.py:33 +msgid "if table is not set in \"step.output\"" +msgstr "si table n'est pas mis dans \"step.output\"" + +#: src/rougail/output_table/config.py:36 +msgid "Content of the first column" +msgstr "Contenu de la première colonne" + +#: src/rougail/output_table/config.py:47 +msgid "" +"First column is description if \"_.columns\" has only one value, otherwise " +"it's namespace" +msgstr "" +"La première colonne est description si \"_.columns\" n'a qu'une valeur, " +"sinon c'est namespace" + +#: src/rougail/output_table/config.py:52 +msgid "Tag name must not have the same name has first column" +msgstr "" +"Le nom de l'étiquette ne doit pas avoir le même nom que la première colonne" + +#: src/rougail/output_table/config.py:55 src/rougail/output_table/config.py:60 +msgid "Tag names" +msgstr "Noms des étiquettes" + +#: src/rougail/output_table/config.py:56 +msgid "" +"Each tag creates a column. The content of the columns comes from the " +"variables with the defined tags." +msgstr "" +"Chaque étiquette créée une colonne. Le contenu des colonnes viennent des " +"variables avec les étiquettes définis" + +#: src/rougail/output_table/config.py:69 +msgid "Add header in table" +msgstr "Ajouter l'entête dans le tableau" diff --git a/locale/rougail_output_table.pot b/locale/rougail_output_table.pot new file mode 100644 index 0000000..8ef9b1d --- /dev/null +++ b/locale/rougail_output_table.pot @@ -0,0 +1,53 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-21 21:30+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" + + +#: src/rougail/output_table/__init__.py:55 +msgid "the \"step.output\" is not set to \"{0}\"" +msgstr "" + +#: src/rougail/output_table/config.py:28 +msgid "Displays the data in a table" +msgstr "" + +#: src/rougail/output_table/config.py:33 +msgid "if table is not set in \"step.output\"" +msgstr "" + +#: src/rougail/output_table/config.py:36 +msgid "Content of the first column" +msgstr "" + +#: src/rougail/output_table/config.py:47 +msgid "First column is description if \"_.columns\" has only one value, otherwise it's namespace" +msgstr "" + +#: src/rougail/output_table/config.py:52 +msgid "Tag name must not have the same name has first column" +msgstr "" + +#: src/rougail/output_table/config.py:55 src/rougail/output_table/config.py:60 +msgid "Tag names" +msgstr "" + +#: src/rougail/output_table/config.py:56 +msgid "Each tag creates a column. The content of the columns comes from the variables with the defined tags." +msgstr "" + +#: src/rougail/output_table/config.py:69 +msgid "Add header in table" +msgstr "" + diff --git a/src/rougail/output_table/__init__.py b/src/rougail/output_table/__init__.py new file mode 100644 index 0000000..bdf4b14 --- /dev/null +++ b/src/rougail/output_table/__init__.py @@ -0,0 +1,139 @@ +""" +Silique (https://www.silique.fr) +Copyright (C) 2022-2025 + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . +""" + +from typing import Optional + +from tabulate import tabulate + +from tiramisu import groups +from tiramisu.error import PropertiesOptionError, ConfigError +from rougail.error import ExtensionError + +from .i18n import _ +from .__version__ import __version__ + + +TABULATE = {"console": "plain", + "html": "unsafehtml", + } + + +class RougailOutputTable: + output_name = "table" + + def __init__( + self, + config: "Config", + *, + rougailconfig: "RougailConfig" = None, + user_data_errors: Optional[list] = None, + user_data_warnings: Optional[list] = None, + **kwargs, + ) -> None: + if rougailconfig is None: + from rougail import RougailConfig + + rougailconfig = RougailConfig + rougailconfig["step.output"] = self.output_name + if rougailconfig["step.output"] != self.output_name: + raise ExtensionError( + _('the "step.output" is not set to "{0}"').format(self.output_name) + ) + self.rougailconfig = rougailconfig + self.config = config + try: + groups.namespace + self.support_namespace = True + except AttributeError: + self.support_namespace = False + if user_data_errors: + self.errors = user_data_errors.copy() + else: + self.errors = [] + if user_data_warnings: + self.warnings = user_data_warnings.copy() + else: + self.warnings = [] + self.datas = {} + + def run(self) -> None: + self.config.property.read_only() + self.output_format = self.rougailconfig["table.output_format"] + if self.output_format in TABULATE: + self.output_format = TABULATE[self.output_format] + self.columns = self.rougailconfig["table.columns"].copy() + self.first_column = self.rougailconfig["table.first_column"] + if self.first_column == 'namespace': + self.columns.insert(0, 'namespace') + else: + self.columns.insert(0, 'description') + for option in self.config: + if self.support_namespace and self.first_column == 'namespace' and option.group_type() is groups.namespace: + namespace = option.description() + else: + namespace = "" + self.walk(option, namespace) + if self.rougailconfig["table.header"]: + headers = tuple([col.capitalize() for col in self.columns]) + else: + headers = () + if self.datas: + datas = [] + for data in self.datas.values(): + datas.append(["\n".join(data.get(col, [])) for col in self.columns]) + msg = ( + tabulate( + datas, + headers=headers, + tablefmt=self.output_format, + ) + + "\n" + ) + else: + msg = "" + return True, msg + + def print(self) -> str: + ret, datas = self.run() + print(datas) + return ret + + def walk(self, config, namespace): + for option in config: + if option.isoptiondescription(): + self.walk(option, namespace) + tags = option.information.get('tags', []) + if not tags: + continue + for col in self.columns: + if col in tags: + value = option.value.get() + if isinstance(value, list): + self.datas.setdefault(namespace, {}).setdefault(col, []).extend([str(val) for val in value]) + else: + self.datas.setdefault(namespace, {}).setdefault(col, []).append(str(value)) + if self.first_column == 'namespace': + self.datas[namespace]["namespace"] = [namespace] + else: + self.datas[namespace]["description"] = [option.description()] + + +RougailOutput = RougailOutputTable + + +__all__ = ("RougailOutputTable",) diff --git a/src/rougail/output_table/__version__.py b/src/rougail/output_table/__version__.py new file mode 100644 index 0000000..6c8e6b9 --- /dev/null +++ b/src/rougail/output_table/__version__.py @@ -0,0 +1 @@ +__version__ = "0.0.0" diff --git a/src/rougail/output_table/config.py b/src/rougail/output_table/config.py new file mode 100644 index 0000000..863b8b0 --- /dev/null +++ b/src/rougail/output_table/config.py @@ -0,0 +1,78 @@ +""" +Silique (https://www.silique.fr) +Copyright (C) 2025 + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . +""" + +from .i18n import _ + + +def get_rougail_config( + *, + backward_compatibility=True, # pylint: disable=unused-argument +) -> dict: + rougail_options = f""" +table: + description: {_('Displays the data in a table')} + disabled: + jinja: |- + {{{{ step.output is propertyerror or step.output != 'table' }}}} + return_type: boolean + description: {_('if table is not set in "step.output"')} + + first_column: + description: {_("Content of the first column")} + choices: + - description + - namespace + default: + jinja: |- + {{% if _.columns | length == 1 %}} + description + {{% else %}} + namespace + {{% endif %}} + description: {_('First column is description if "_.columns" has only one value, otherwise it\'s namespace')} + validators: + - jinja: |- + {{{{ _.first_column in _.columns }}}} + return_type: boolean + description: {_("Tag name must not have the same name has first column")} + + columns: + description: {_('Tag names')} + help: {_('Each tag creates a column. The content of the columns comes from the variables with the defined tags.')} + multi: true + + output_format: + description: {_('Tag names')} + choices: + - console + - github + - asciidoc + - html + - rst + default: console + + header: true # {_("Add header in table")} +""" + return { + "name": "table", + "process": "output", + "options": rougail_options, + "level": 60, + } + +__all__ = ("get_rougail_config",) diff --git a/src/rougail/output_table/i18n.py b/src/rougail/output_table/i18n.py new file mode 100644 index 0000000..f6b7d4a --- /dev/null +++ b/src/rougail/output_table/i18n.py @@ -0,0 +1,26 @@ +"""Internationalisation utilities +Silique (https://www.silique.fr) +Copyright (C) 2025 + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . +""" + +from gettext import translation +from pathlib import Path + +t = translation( + "rougail_output_table", str(Path(__file__).parent / "locale"), fallback=True +) + +_ = t.gettext diff --git a/src/rougail/output_table/locale/fr/LC_MESSAGES/rougail_output_table.mo b/src/rougail/output_table/locale/fr/LC_MESSAGES/rougail_output_table.mo new file mode 100644 index 0000000000000000000000000000000000000000..481d7cca6976c25bbbe83ef236708122748345bc GIT binary patch literal 1392 zcmZvb%Z?LA6o!j11Y(g5$u5y{#sXPU=#K4Z(8ye*2{RKR1~Q7wWf3VUx{vJ|wX1rn zsy(qHmWU@{&jJaCX9z1Vc#Awi7Rf%5@}C}qZHbnSKUdYc)#<>t<{ursGl{MJFn`Udy_d;xBN|AL=@-H(*I2wnp(fg1b|d=eUj^_B}~r)cXT$w z-yvn5b>x79ldzQfNR+MSJvj>49>aCu-MCIV(cVZKfsRZ>It1oCFqU&k9a6Qs)DM|} z(~x;nM&m4*0X2U~=b4){(t(^Urubo+=%V7wjr{s*JqM(WgzdOfOBdcT^9Za$t$Uby6c59b$f5-m&R$0d00pSPyAWaMYOc@*96|K6@p3jB;KZ8Q6UH||9 literal 0 HcmV?d00001