From a5fbbf4a082e540ee911c691d5d0e5a327fe2b83 Mon Sep 17 00:00:00 2001 From: Kieran W <41634689+FredHappyface@users.noreply.github.com> Date: Sat, 31 Dec 2022 16:49:26 +0000 Subject: [PATCH] release: 2022.3 --- CHANGELOG.md | 13 ++ DATA_STRUCTURES.md | 141 ------------------ cli2gui/__init__.py | 2 +- cli2gui/application/application.py | 63 ++------ cli2gui/application/pysimplegui2args.py | 7 +- cli2gui/application/widgets.py | 91 ++++++++--- cli2gui/decorators.py | 25 ++-- cli2gui/tojson/argparse2json.py | 49 +++--- cli2gui/tojson/click2json.py | 45 +++--- cli2gui/tojson/docopt2json.py | 75 ++++++---- cli2gui/tojson/getopt2json.py | 27 ++-- cli2gui/tojson/optparse2json.py | 31 ++-- cli2gui/{c2gtypes.py => types.py} | 17 ++- documentation/reference/README.md | 2 +- .../cli2gui/application/application.md | 38 +++-- .../cli2gui/application/pysimplegui2args.md | 2 +- .../reference/cli2gui/application/widgets.md | 100 ++++++++----- documentation/reference/cli2gui/decorators.md | 21 +-- documentation/reference/cli2gui/index.md | 4 +- .../reference/cli2gui/tojson/argparse2json.md | 51 +++---- .../reference/cli2gui/tojson/click2json.md | 32 ++-- .../reference/cli2gui/tojson/docopt2json.md | 36 ++--- .../reference/cli2gui/tojson/getopt2json.md | 21 ++- .../reference/cli2gui/tojson/optparse2json.md | 14 +- .../cli2gui/{c2gtypes.md => types.md} | 38 +++-- pyproject.toml | 2 +- tests/click/test_boolean.py | 26 ++++ tests/click/test_choice.py | 22 +++ tests/click/test_feat_switches.py | 24 +++ tests/docopt/test_11.py | 45 ++++++ tests/docopt/test_advanced.py | 5 - tests/optparse/test_11.py | 45 ++++++ tests/optparse/test_advanced.py | 1 - 33 files changed, 615 insertions(+), 500 deletions(-) delete mode 100644 DATA_STRUCTURES.md rename cli2gui/{c2gtypes.py => types.py} (92%) rename documentation/reference/cli2gui/{c2gtypes.md => types.md} (65%) create mode 100644 tests/click/test_boolean.py create mode 100644 tests/click/test_choice.py create mode 100644 tests/click/test_feat_switches.py create mode 100644 tests/docopt/test_11.py delete mode 100644 tests/docopt/test_advanced.py create mode 100644 tests/optparse/test_11.py delete mode 100644 tests/optparse/test_advanced.py diff --git a/CHANGELOG.md b/CHANGELOG.md index f1e47b6..8086dd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,19 @@ All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](../../commits/master). +## 2022.3 - 2022/12/31 + +- Feature, support defaults https://github.com/FHPythonUtils/Cli2Gui/issues/11 +- Use full module namespace in-place of relative imports +- Use `Enum` for widget types. eg. `types.ItemType.Bool` +- Update internal types +- Add more supported types for other parsers. e.g `click` + - Argparse supports: Bool, Int, Choice, File, Text + - Click supports: Bool, Int, Choice, Text + - DocOpt supports: Bool, Text + - GetOpt supports: Bool, Text + - Optparse supports: Bool, Int, Choice, Text + ## 2022.2.1 - 2022/12/30 - Fix https://github.com/FHPythonUtils/Cli2Gui/issues/13 diff --git a/DATA_STRUCTURES.md b/DATA_STRUCTURES.md deleted file mode 100644 index 89fca4c..0000000 --- a/DATA_STRUCTURES.md +++ /dev/null @@ -1,141 +0,0 @@ -# Data Structures - -The easiest way to understand the data structures would be to clone the repo -and add print statements. - -For instance, in the case of *parser*2json. To understand the structure of the -JSON object add a print to application/application.py and run an example. See -below for an example for `buildSpec["widgets"]`: - -```python -def createLayout(buildSpec, widgets): - """Create the pysimple gui layout from the build spec - [...] - - Returns: - list: list of widgets (layout list) - """ - # Add print ⬇️ - print(buildSpec["widgets"]) - - sections = [] - for widget in buildSpec["widgets"]: - [...] -``` - -Following the above and running `python3.8 test/argparse/advanced.py --cli2gui` -will print - -```python -[{'name': 'positional arguments', 'arg_items': [{'type': 'TextBox', -'display_name': 'positional', 'help': 'positional arg', 'commands': [], -'choices': [], 'dest': 'positional', '_other': {}}, {'type': 'File', -'display_name': 'positional-file', 'help': 'positional arg for a file', -'commands': [], 'choices': [], 'dest': 'positional-file', '_other': {}}], -'groups': []}, {'name': 'optional arguments', 'arg_items': [{'type': 'TextBox', -'display_name': 'optional', 'help': 'optional arg', 'commands': ['--optional'], -'choices': [], 'dest': 'optional', '_other': {}}, {'type': 'Bool', -'display_name': 'store_true', 'help': 'optional arg store true', 'commands': -['--store-true'], 'choices': [], 'dest': 'store_true', '_other': {}}, {'type': -'Bool', 'display_name': 'store_false', 'help': 'optional arg store false', -'commands': ['--store-false'], 'choices': [], 'dest': 'store_false', '_other': -{}}, {'type': 'TextBox', 'display_name': 'store', 'help': 'optional arg store', -'commands': ['--store'], 'choices': [], 'dest': 'store', '_other': {}}, -{'type': 'Counter', 'display_name': 'count', 'help': 'optional arg count', -'commands': ['--count'], 'choices': [], 'dest': 'count', '_other': {}}, {'type': -'Dropdown', 'display_name': 'choices', 'help': 'optional arg store with choices', -'commands': ['--choices'], 'choices': ['choice1', 'choice2'], 'dest': 'choices', -'_other': {}}], 'groups': []}, {'name': 'choose one of the following', -'arg_items': [{'type': 'Group', 'commands': [['--mxg-true'], ['--mxg-false'], -['--mxg'], ['--mxg-count'], ['--mxg-choices']], 'radio': [{'type': 'Bool', -'display_name': 'mxg_true', 'help': 'mutually exclusive arg store true', -'commands': ['--mxg-true'], 'choices': [], 'dest': 'mxg_true', '_other': {}}, -{'type': 'Bool', 'display_name': 'mxg_false', 'help': -'mutually exclusive arg store false', 'commands': ['--mxg-false'], 'choices': [], -'dest': 'mxg_false', '_other': {}}, {'type': 'TextBox', 'display_name': 'mxg', -'help': 'mutually exclusive arg store', 'commands': ['--mxg'], 'choices': [], -'dest': 'mxg', '_other': {}}, {'type': 'Counter', 'display_name': 'mxg_count', -'help': 'mutually exclusive arg count', 'commands': ['--mxg-count'], 'choices': -[], 'dest': 'mxg_count', '_other': {}}, {'type': 'Dropdown', 'display_name': -'mxg_choices', 'help': 'mutually exclusive arg store with choices', 'commands': -['--mxg-choices'], 'choices': ['choice1', 'choice2'], 'dest': 'mxg_choices', -'_other': {}}]}], 'groups': []}] -``` - -The rest of the document includes documentation on several data structures. Note -that this may be more outdated than using the aforementioned method (as this -will have to be updated as features are added and code is streamlined) - -## buildSpec - -Contains the initial data set by the end user - -```python -class BuildSpec(typing.TypedDict): - """Representation for the BuildSpec.""" - run_function: Callable[..., Any] - parser: str - gui: str - theme: Union[str, list[str]] - darkTheme: Union[str, list[str]] - sizes: Union[dict[str, Any]] - image: str - program_name: str - program_description: str - max_args_shown: int - menu: Union[dict[str, Any]] -``` - -## fullBuildSpec - -Contains all the data needed to build the GUI such as the theme, name, -description and so on. - -```python -class FullBuildSpec(typing.TypedDict): - """Representation for the FullBuildSpec (BuildSpec + ParserRep).""" - run_function: Callable[..., Any] - parser: str - gui: str - theme: Union[str, list[str]] - darkTheme: Union[str, list[str]] - sizes: Union[dict[str, Any]] - image: str - program_name: str - program_description: str - max_args_shown: int - menu: Union[dict[str, Any]] - parser_description: str - widgets: list[Widgets] -``` - -## parserRep - -Each *parser*2json.py provides a JSON object that is used to build the GUI. - -```python -class ParserRep(typing.TypedDict): - """Representation for a parser.""" - parser_description: str - widgets: list[Group] -``` - -```python -class Group(typing.TypedDict): - """ representation for an argument group.""" - name: str - arg_items: list[Item] - groups: list[Group, list[Any]] -``` - -```python -class Item(typing.TypedDict): - """ representation for an arg_item.""" - type: str - display_name: str - help: str - commands: list[Any] - choices: list[Any, list[str]] - dest: str - _other: dict[Any, Any] -``` diff --git a/cli2gui/__init__.py b/cli2gui/__init__.py index 9ae7bd1..39abfaf 100755 --- a/cli2gui/__init__.py +++ b/cli2gui/__init__.py @@ -2,4 +2,4 @@ """ from __future__ import annotations -from .decorators import * +from cli2gui.decorators import * diff --git a/cli2gui/application/application.py b/cli2gui/application/application.py index 212819e..ea89a36 100755 --- a/cli2gui/application/application.py +++ b/cli2gui/application/application.py @@ -3,7 +3,7 @@ # pylint: disable=import-outside-toplevel from __future__ import annotations -import json +import logging import sys from pathlib import Path from typing import Any @@ -15,9 +15,9 @@ import yaml from PySimpleGUI import Element, Window -from .. import c2gtypes -from .pysimplegui2args import argFormat -from .widgets import Widgets +from cli2gui import types +from cli2gui.application.pysimplegui2args import argFormat +from cli2gui.application.widgets import Widgets def themeFromFile(themeFile: str) -> list[str]: @@ -163,14 +163,14 @@ def setupWidgets(gui: str, sizes: dict[str, Any], pySimpleGui: Any) -> Widgets: def addItemsAndGroups( - section: c2gtypes.Group, + section: types.Group, argConstruct: list[list[Element]], widgets: Widgets, ): """Add arg_items and groups to the argConstruct list. Args: - section (c2gtypes.Group): contents/ section containing name, arg_items + section (types.Group): contents/ section containing name, arg_items and groups argConstruct (list[list[Element]]): list of widgets to add to the program window @@ -185,49 +185,16 @@ def addItemsAndGroups( if item["type"] == "RadioGroup": rGroup = item["_other"]["radio"] for rElement in rGroup: - argConstruct.append( - widgets.helpFlagWidget( - rElement["display_name"], - rElement["commands"], - rElement["help"], - rElement["dest"], - ) - ) - elif item["type"] == "Bool": - argConstruct.append( - widgets.helpFlagWidget( - item["display_name"], item["commands"], item["help"], item["dest"] - ) - ) - elif item["type"] == "File": - argConstruct.append( - widgets.helpFileWidget( - item["display_name"], item["commands"], item["help"], item["dest"] - ) - ) - elif item["type"] == "Dropdown": - argConstruct.append( - widgets.helpDropdownWidget( - item["display_name"], - item["commands"], - item["help"], - item["dest"], - item["choices"], - ) - ) + argConstruct.append(widgets.helpFlagWidget(rElement)) else: - argConstruct.append( - widgets.helpTextWidget( - item["display_name"], item["commands"], item["help"], item["dest"] - ) - ) + argConstruct.append(widgets.addWidgetFromItem(item)) for group in section["groups"]: argConstruct = addItemsAndGroups(group, argConstruct, widgets) return argConstruct def generatePopup( - buildSpec: c2gtypes.FullBuildSpec, + buildSpec: types.FullBuildSpec, values: dict[Any, Any] | list[Any], widgets: Widgets, pySimpleGui: Any, @@ -235,7 +202,7 @@ def generatePopup( """Create the popup window. Args: - buildSpec (c2gtypes.FullBuildSpec): [description] + buildSpec (types.FullBuildSpec): [description] values (Union[dict[Any, Any]): Returned when a button is clicked. Such as the menu widgets (Widgets): class to build widgets @@ -296,7 +263,7 @@ def generatePopup( def createLayout( - buildSpec: c2gtypes.FullBuildSpec, + buildSpec: types.FullBuildSpec, widgets: Widgets, pySimpleGui: Any, menu: str | list[str], @@ -304,7 +271,7 @@ def createLayout( """Create the pysimplegui layout from the build spec. Args: - buildSpec (c2gtypes.FullBuildSpec): build spec containing widget + buildSpec (types.FullBuildSpec): build spec containing widget widgets (Widgets): class to build widgets pySimpleGui (Any): version of PySimpleGui to use menu (list[str]]): menu data @@ -358,11 +325,11 @@ def createLayout( return layout -def run(buildSpec: c2gtypes.FullBuildSpec): +def run(buildSpec: types.FullBuildSpec): """Main entry point for the application. Args: - buildSpec (c2gtypes.FullBuildSpec): args that customise the application such as the theme + buildSpec (types.FullBuildSpec): args that customise the application such as the theme or the function to run """ import PySimpleGUI as psg # pylint: disable=reimported @@ -410,4 +377,4 @@ def run(buildSpec: c2gtypes.FullBuildSpec): return args buildSpec["run_function"](args) except Exception as exception: # pylint: disable=broad-except - print(repr(exception)) + logging.exception(exception) diff --git a/cli2gui/application/pysimplegui2args.py b/cli2gui/application/pysimplegui2args.py index c1cc70c..2c02893 100644 --- a/cli2gui/application/pysimplegui2args.py +++ b/cli2gui/application/pysimplegui2args.py @@ -5,7 +5,7 @@ import argparse from typing import Any -from ..c2gtypes import ParserType +from cli2gui.types import ParserType def argparseFormat(values: dict[str, Any]) -> argparse.Namespace: @@ -52,8 +52,9 @@ def clickFormat(values: dict[str, Any]) -> list[Any]: """Format args for click.""" args = [] for key in values: - if not callable(key) and len(values[key]) > 0: - args.extend([key, values[key]]) + val = str(values[key]) + if not callable(key) and len(val) > 0: + args.extend([key, val]) return args diff --git a/cli2gui/application/widgets.py b/cli2gui/application/widgets.py index bbd4439..1d48c5f 100644 --- a/cli2gui/application/widgets.py +++ b/cli2gui/application/widgets.py @@ -1,5 +1,4 @@ -"""Widgets class holding methods to create widgets in addition to a sizes... - +"""Widgets class holding methods to create widgets in addition to a sizes. attribute that can be overridden to provide the end user with customisation over the size of the gui. """ @@ -11,10 +10,11 @@ from PIL import Image, ImageTk from PySimpleGUI import Element +from cli2gui import types -class Widgets: - """Widgets class holding methods to create widgets in addition to a sizes... +class Widgets: + """Widgets class holding methods to create widgets in addition to a sizes. attribute that can be overridden to provide the end user with customisation over the size of the gui. """ @@ -62,19 +62,31 @@ def stringSentencecase(self, string: str) -> str: """Individual widgets """ - def inputText(self, key: str) -> Element: + def inputText(self, key: str, default=None) -> Element: """Return an input text field.""" return self.pySimpleGui.InputText( + default, size=self.sizes["input_size"], pad=self.sizes["padding"], key=key, font=("sans", self.sizes["text_size"]), ) - def check(self, key: str) -> Element: + def spin(self, key: str, default=None) -> Element: + """Return an input text field.""" + return self.pySimpleGui.Spin( + list(range(-50, 51)), + initial_value=default or 0, + size=self.sizes["input_size"], + pad=self.sizes["padding"], + key=key, + font=("sans", self.sizes["text_size"]), + ) + + def check(self, key: str, default=None) -> Element: """Return a checkbox.""" return self.pySimpleGui.Check( - "", size=self.sizes["input_size"], pad=self.sizes["padding"], key=key + "", size=self.sizes["input_size"], pad=self.sizes["padding"], key=key, default=default ) def button(self, text: str) -> Element: @@ -107,12 +119,13 @@ def dropdown(self, key: str, argItems: list[str]) -> Element: key=key, ) - def fileBrowser(self, key: str) -> list[Element]: + def fileBrowser(self, key: str, default=None) -> list[Element]: """Return a fileBrowser button and field.""" height = self.sizes["input_size"][1] width = self.sizes["input_size"][0] return [ self.pySimpleGui.InputText( + default, size=(width - int(width / 3), height), pad=(0, self.sizes["padding"][1]), key=key, @@ -165,42 +178,72 @@ def title(self, text: str, image: str = "") -> list[Element]: """ def helpFlagWidget( - self, displayName: str, commands: list[str], helpText: str, dest: str + self, + item: types.Item, ) -> list[Element]: """Return a set of widgets that make up an arg with true/ false.""" return [ - self.helpArgNameAndHelp(commands, helpText, displayName), - self.pySimpleGui.Column([[self.check(dest)]], pad=(0, 0)), + self.helpArgNameAndHelp(item["commands"], item["help"], item["display_name"]), + self.pySimpleGui.Column( + [[self.check(item["dest"], default=item["default"])]], pad=(0, 0) + ), ] def helpTextWidget( - self, displayName: str, commands: list[str], helpText: str, dest: str + self, + item: types.Item, ) -> list[Element]: """Return a set of widgets that make up an arg with text.""" return [ - self.helpArgNameAndHelp(commands, helpText, displayName), - self.pySimpleGui.Column([[self.inputText(dest)]], pad=(0, 0)), + self.helpArgNameAndHelp(item["commands"], item["help"], item["display_name"]), + self.pySimpleGui.Column( + [[self.inputText(item["dest"], default=item["default"])]], pad=(0, 0) + ), + ] + + def helpCounterWidget( + self, + item: types.Item, + ) -> list[Element]: + """Return a set of widgets that make up an arg with text.""" + return [ + self.helpArgNameAndHelp(item["commands"], item["help"], item["display_name"]), + self.pySimpleGui.Column( + [[self.spin(item["dest"], default=item["default"])]], pad=(0, 0) + ), ] def helpFileWidget( - self, displayName: str, commands: list[str], helpText: str, dest: str + self, + item: types.Item, ) -> list[Element]: """Return a set of widgets that make up an arg with a file.""" return [ - self.helpArgNameAndHelp(commands, helpText, displayName), - self.pySimpleGui.Column([self.fileBrowser(dest)], pad=(0, 0)), + self.helpArgNameAndHelp(item["commands"], item["help"], item["display_name"]), + self.pySimpleGui.Column([self.fileBrowser(item["dest"], item["default"])], pad=(0, 0)), ] def helpDropdownWidget( self, - displayName: str, - commands: list[str], - helpText: str, - dest: str, - choices: list[str], + item: types.Item, ) -> list[Element]: """Return a set of widgets that make up an arg with a choice.""" return [ - self.helpArgNameAndHelp(commands, helpText, displayName), - self.pySimpleGui.Column([[self.dropdown(dest, choices)]], pad=(0, 0)), + self.helpArgNameAndHelp(item["commands"], item["help"], item["display_name"]), + self.pySimpleGui.Column( + [[self.dropdown(item["dest"], item["_other"]["choices"])]], pad=(0, 0) + ), ] + + def addWidgetFromItem(self, item: types.Item) -> list[Element]: + """Add a widget from an item (types.Item)""" + functionMap = { + types.ItemType.Bool: self.helpFlagWidget, + types.ItemType.File: self.helpFileWidget, + types.ItemType.Choice: self.helpDropdownWidget, + types.ItemType.Int: self.helpCounterWidget, + types.ItemType.Text: self.helpTextWidget, + } + return functionMap[item["type"]]( + item, + ) diff --git a/cli2gui/decorators.py b/cli2gui/decorators.py index ff04f93..93d2136 100755 --- a/cli2gui/decorators.py +++ b/cli2gui/decorators.py @@ -13,9 +13,15 @@ from shlex import quote from typing import Any -from .application import application -from .c2gtypes import BuildSpec, FullBuildSpec, GUIType, ParserType -from .tojson import argparse2json, click2json, docopt2json, getopt2json, optparse2json +from cli2gui.application import application +from cli2gui.tojson import ( + argparse2json, + click2json, + docopt2json, + getopt2json, + optparse2json, +) +from cli2gui.types import BuildSpec, FullBuildSpec, GUIType, ParserType DO_COMMAND = "--cli2gui" DO_NOT_COMMAND = "--disable-cli2gui" @@ -37,11 +43,11 @@ def createFromParser( arguments. eg. getopt.getopt kwargsParser (Union[dict[Any, Any]]): A parser that acts on named params sourcePath (str): Program source path - buildSpec (c2gtypes.BuildSpec): Build spec + buildSpec (types.BuildSpec): Build spec **kwargs (dict[Any, Any]): kwargs Returns: - c2gtypes.FullBuildSpec: buildSpec to be used by the application + types.FullBuildSpec: buildSpec to be used by the application Raises: RuntimeError: Throw error if incorrect parser selected @@ -106,8 +112,7 @@ def Click2Gui( # pylint: disable=invalid-name menu: str | dict[str, Any] = "", **kwargs: dict[str, Any], ) -> Any: - """Decorator to use in the function that contains the argument parser... - + """Decorator to use in the function that contains the argument parser. Serialises data to JSON and launches the Cli2Gui application. Args: @@ -174,8 +179,7 @@ def Cli2Gui( # pylint: disable=invalid-name max_args_shown: int = 5, menu: str | dict[str, Any] = "", ) -> Any: - """Decorator to use in the function that contains the argument parser... - + """Decorator to use in the function that contains the argument parser. Serialises data to JSON and launches the Cli2Gui application. Args: @@ -259,8 +263,7 @@ def runCli2Gui(self, *args: Any, **kwargs: Any) -> Any: return application.run(buildSpec) def inner(*args: tuple[Any, Any], **kwargs: dict[Any, Any]) -> Any: - """Replace the inner functions with run_cli2gui. eg. When... - + """Replace the inner functions with run_cli2gui. eg. When. ArgumentParser.parse_args is called, do run_cli2gui. Returns: diff --git a/cli2gui/tojson/argparse2json.py b/cli2gui/tojson/argparse2json.py index cbc16a1..e989b04 100755 --- a/cli2gui/tojson/argparse2json.py +++ b/cli2gui/tojson/argparse2json.py @@ -1,5 +1,4 @@ -"""Generate a dict describing argparse arguments... - +"""Generate a dict describing argparse arguments. pylint and pylance both want me to not access protected methods - I know better ;) """ # pylint: disable=protected-access @@ -20,7 +19,7 @@ from sys import argv from typing import Any, Generator, TypedDict -from .. import c2gtypes +from cli2gui import types class ArgparseGroup(TypedDict): @@ -65,8 +64,7 @@ def containsActions(actionA: list[argparse.Action], actionB: list[argparse.Actio def reapplyMutexGroups( mutexGroups: list[argparse._MutuallyExclusiveGroup], actionGroups: list[Any] ): - """_argparse stores mutually exclusive groups independently... - + """_argparse stores mutually exclusive groups independently. of all other groups. So, they must be manually re-combined with the groups/subgroups to which they were originally declared in order to have them appear in the correct location in the UI. @@ -106,54 +104,55 @@ def extractRawGroups(actionGroup: argparse._ArgumentGroup) -> ArgparseGroup: } -def actionToJson(action: argparse.Action, widget: str) -> c2gtypes.Item: +def actionToJson(action: argparse.Action, widget: types.ItemType) -> types.Item: """Generate json for an action and set the widget - used by the application.""" + choices = [str(choice) for choice in action.choices] if action.choices else [] return { "type": widget, "display_name": str(action.metavar or action.dest), "help": str(action.help), "commands": list(action.option_strings), - "choices": [str(choice) for choice in action.choices] if action.choices else [], "dest": action.dest, - "_other": {}, + "default": action.default, + "_other": {"choices": choices, "nargs": action.nargs}, } -def buildRadioGroup(mutexGroup: _MutuallyExclusiveGroup): +def buildRadioGroup(mutexGroup: _MutuallyExclusiveGroup) -> types.Item: """Create a radio group for a mutex group of arguments.""" commands = [action.option_strings for action in mutexGroup._group_actions] return { - "type": "RadioGroup", + "type": types.ItemType.RadioGroup, "commands": commands, - "_other": {"radio": list(catergorizeItems(mutexGroup._group_actions))}, - } + "_other": {"radio": list(categorizeItems(mutexGroup._group_actions))}, + } # type: ignore -def catergorizeItems( +def categorizeItems( actions: list[argparse.Action], -) -> Generator[c2gtypes.Item, None, None]: +) -> Generator[types.Item, None, None]: """Catergorise each action and generate json.""" for action in actions: if isinstance(action, _MutuallyExclusiveGroup): yield buildRadioGroup(action) elif isinstance(action, (_StoreTrueAction, _StoreFalseAction)): - yield actionToJson(action, "Bool") + yield actionToJson(action, types.ItemType.Bool) elif isinstance(action, _CountAction): - yield actionToJson(action, "Counter") + yield actionToJson(action, types.ItemType.Int) elif action.choices: - yield actionToJson(action, "Dropdown") + yield actionToJson(action, types.ItemType.Choice) elif isinstance(action.type, argparse.FileType): - yield actionToJson(action, "File") + yield actionToJson(action, types.ItemType.File) else: - yield actionToJson(action, "TextBox") + yield actionToJson(action, types.ItemType.Text) -def categorizeGroups(groups: list[ArgparseGroup]) -> list[c2gtypes.Group]: +def categorizeGroups(groups: list[ArgparseGroup]) -> list[types.Group]: """Categorize the parser groups and arg_items.""" return [ { "name": group["name"], - "arg_items": list(catergorizeItems(group["arg_items"])), + "arg_items": list(categorizeItems(group["arg_items"])), "groups": categorizeGroups(group["groups"]), } for group in groups @@ -165,7 +164,7 @@ def stripEmpty(groups: list[ArgparseGroup]): return [group for group in groups if group["arg_items"]] -def process(parser: argparse.ArgumentParser) -> list[c2gtypes.Group]: +def process(parser: argparse.ArgumentParser) -> list[types.Group]: """Reapply the mutex groups and then categorize them and the arg_items under the parser.""" mutexGroups = parser._mutually_exclusive_groups rawActionGroups = [ @@ -175,17 +174,17 @@ def process(parser: argparse.ArgumentParser) -> list[c2gtypes.Group]: return categorizeGroups(stripEmpty(correctedActionGroups)) -def convert(parser: argparse.ArgumentParser) -> c2gtypes.ParserRep: +def convert(parser: argparse.ArgumentParser) -> types.ParserRep: """Convert argparse to a dict. Args: parser (argparse.ArgumentParser): argparse parser Returns: - c2gtypes.ParserRep: dictionary representing parser object + types.ParserRep: dictionary representing parser object """ widgets = [] for _, subparser in iterParsers(parser): widgets.extend(process(subparser)) - return {"parser_description": parser.description, "widgets": widgets} + return {"parser_description": str(parser.description), "widgets": widgets} diff --git a/cli2gui/tojson/click2json.py b/cli2gui/tojson/click2json.py index 1ef858c..d7046a5 100644 --- a/cli2gui/tojson/click2json.py +++ b/cli2gui/tojson/click2json.py @@ -4,23 +4,21 @@ from typing import Any, Generator -from .. import c2gtypes +from cli2gui import types -def extract(parser: Any) -> list[c2gtypes.Group]: +def extract(parser: Any) -> list[types.Group]: """Get the actions as json for the parser.""" try: argumentList = [ { "name": "Positional Arguments", - "arg_items": list( - categorizeCommand([parser.commands[key] for key in parser.commands]) - ), + "arg_items": list(categorize([parser.commands[key] for key in parser.commands])), "groups": [], } ] except AttributeError: - argumentList: list[c2gtypes.Group] = [] + argumentList: list[types.Group] = [] argumentList.append( { "name": "Optional Arguments", @@ -31,43 +29,48 @@ def extract(parser: Any) -> list[c2gtypes.Group]: return argumentList -def actionToJson(action: Any, widget: str) -> c2gtypes.Item: +def actionToJson(action: Any, widget: types.ItemType, other: dict | None = None) -> types.Item: """Generate json for an action and set the widget - used by the application.""" nargs = "" try: - action.params[0].nargs if len(action.params) > 0 else "" or "" + nargs = action.params[0].nargs if len(action.params) > 0 else "" or "" except AttributeError: pass + + commands = action.opts + action.secondary_opts return { "type": widget, "display_name": action.name, "help": action.help, - "commands": ("--" if len(action.name) > 1 else "-") + action.name, - "choices": [], - "dest": action.callback or ("--" if len(action.name) > 1 else "-") + action.name, - "_other": {"nargs": nargs}, + "commands": commands, + "dest": action.callback or commands[0], + "default": action.default, + "_other": {**{"nargs": nargs}, **(other or {})}, } -def categorize(actions: list[Any]) -> Generator[c2gtypes.Item, None, None]: +def categorize(actions: list[Any]) -> Generator[types.Item, None, None]: """Catergorise each action and generate json.""" - for action in actions: - yield actionToJson(action, "TextBox") + import click - -def categorizeCommand(actions: list[Any]) -> Generator[c2gtypes.Item, None, None]: - """Catergorise each action and generate json.""" for action in actions: - yield actionToJson(action, "Bool") + if isinstance(action.type, click.Choice): + yield actionToJson(action, types.ItemType.Choice, {"choices": action.type.choices}) + elif isinstance(action.type, click.types.IntParamType): + yield actionToJson(action, types.ItemType.Int) + elif isinstance(action.type, click.types.BoolParamType): + yield actionToJson(action, types.ItemType.Bool) + else: + yield actionToJson(action, types.ItemType.Text) -def convert(parser: Any) -> c2gtypes.ParserRep: +def convert(parser: Any) -> types.ParserRep: """Convert click to a dict. Args: parser (click.core.Command): click parser Returns: - c2gtypes.ParserRep: dictionary representing parser object + types.ParserRep: dictionary representing parser object """ return {"parser_description": "", "widgets": extract(parser)} diff --git a/cli2gui/tojson/docopt2json.py b/cli2gui/tojson/docopt2json.py index 8d3f5f0..9f4079d 100644 --- a/cli2gui/tojson/docopt2json.py +++ b/cli2gui/tojson/docopt2json.py @@ -5,52 +5,61 @@ import re from typing import Any, Iterator -from .. import c2gtypes +from cli2gui import types -def actionToJson(action: tuple[str, str, str, Any, str], widget: str, isPos: bool) -> c2gtypes.Item: +def actionToJson( + action: tuple[str, str, int, Any, str], widget: types.ItemType, isPos: bool +) -> types.Item: """Generate json for an action and set the widget - used by the application.""" - if isPos: - name = action[0] - else: - name = action[1].replace("--", "") if action[1] is not None else action[0].replace("-", "") - - if isPos or action[1] is None: - commands = [action[0]] - elif action[0] is None: - commands = [action[1]] - else: - commands = [action[0], action[1]] + if isPos or len(action) < 5: + return { + "type": widget, + "display_name": action[0], + "help": action[1], + "commands": [action[0]], + "dest": action[0], + "default": None, + "_other": {"nargs": ""}, + } + + default = action[3] if action[3] != "" else None return { "type": widget, - "display_name": name, - "help": action[-1], - "commands": commands, - "choices": [], - "dest": action[1] if not isPos and action[1] is not None else action[0], - "_other": {"nargs": action[2] if not isPos else ""}, + "display_name": (action[1] or action[0]).replace("-", " ").strip(), + "help": action[4], + "commands": [x for x in action[0:2] if x != ""], + "dest": action[1] or action[0], + "default": default, + "_other": {"nargs": action[2]}, } def categorize( - actions: list[tuple[str, str, str, Any, str]], isPos: bool = False -) -> Iterator[c2gtypes.Item]: - """Catergorise each action and generate json.""" + actions: list[tuple[str, str, int, Any, str]], isPos: bool = False +) -> Iterator[types.Item]: + """Catergorise each action and generate json. + + Each action is in the form (short, long, argcount, value, help_message) + + """ for action in actions: # ('-h', '--help', 0, False, 'show this help message and exit') - if not isPos and action[3] in (True, False): - yield actionToJson(action, "Bool", isPos) + if action[0] == "-h" and action[1] == "--help": + pass + elif not isPos and action[2] == 0: + yield actionToJson(action, types.ItemType.Bool, isPos) else: - yield actionToJson(action, "TextBox", isPos) + yield actionToJson(action, types.ItemType.Text, isPos) -def extract(parser: Any) -> list[c2gtypes.Group]: +def extract(parser: Any) -> list[types.Group]: """Get the actions as json for the parser.""" return [ { "name": "Positional Arguments", - "arg_items": list(categorize(parsePos(parser), True)), + "arg_items": list(categorize(parsePos(parser), True)), # type: ignore "groups": [], }, { @@ -70,7 +79,7 @@ def parseSection(name: str, source: Any) -> list[str]: return [s.strip() for s in pattern.findall(source)] -def parse(optionDescription: str) -> tuple[str, str, str, Any, str]: +def parse(optionDescription: str) -> tuple[str, str, int, Any, str]: """Parse an option help text, adapted from docopt.""" short, long, argcount, value = "", "", 0, False options, _, description = optionDescription.strip().partition(" ") @@ -85,10 +94,10 @@ def parse(optionDescription: str) -> tuple[str, str, str, Any, str]: if argcount > 0: matched = re.findall(r"\[default: (.*)\]", description, flags=re.I) value = matched[0] if matched else "" - return (short, long, str(argcount), value, description.strip()) + return (short, long, argcount, value, description.strip()) -def parseOpt(doc: Any) -> list[tuple[str, str, str, Any, str]]: +def parseOpt(doc: Any) -> list[tuple[str, str, int, Any, str]]: """Parse an option help text, adapted from docopt.""" defaults = [] for section in parseSection("options:", doc): @@ -100,7 +109,7 @@ def parseOpt(doc: Any) -> list[tuple[str, str, str, Any, str]]: return defaults -def parsePos(doc: Any) -> list[tuple[str, str, str, Any, str]]: +def parsePos(doc: Any) -> list[tuple[str, str]]: """Parse positional arguments from docstring.""" defaults = [] for section in parseSection("arguments:", doc): @@ -111,13 +120,13 @@ def parsePos(doc: Any) -> list[tuple[str, str, str, Any, str]]: return defaults -def convert(parser: Any) -> c2gtypes.ParserRep: +def convert(parser: Any) -> types.ParserRep: """Convert getopt to a dict. Args: parser (Any): docopt parser Returns: - c2gtypes.ParserRep: dictionary representing parser object + types.ParserRep: dictionary representing parser object """ return {"parser_description": "", "widgets": extract(parser)} diff --git a/cli2gui/tojson/getopt2json.py b/cli2gui/tojson/getopt2json.py index f2bd813..9646bbf 100755 --- a/cli2gui/tojson/getopt2json.py +++ b/cli2gui/tojson/getopt2json.py @@ -5,12 +5,11 @@ from collections.abc import Callable from typing import Generator -from .. import c2gtypes +from cli2gui import types -def actionToJson(action: str, widget: str, short: bool = True) -> c2gtypes.Item: - """Convert an arg to json, behave in the same way as argparse hence the large... - +def actionToJson(action: str, widget: types.ItemType, short: bool = True) -> types.Item: + """Convert an arg to json, behave in the same way as argparse hence the large amount of duplication. """ return { @@ -18,8 +17,8 @@ def actionToJson(action: str, widget: str, short: bool = True) -> c2gtypes.Item: "display_name": action, "help": "", "commands": [("-" if short else "--") + action], - "choices": [], "dest": ("-" if short else "--") + action, + "default": None, "_other": {}, } @@ -29,9 +28,9 @@ def catLong(actions: list[str]): for action in actions: # True/ false if "=" in action: - yield actionToJson(action[:-1], "TextBox", short=False) + yield actionToJson(action[:-1], types.ItemType.Text, short=False) else: - yield actionToJson(action, "Bool", short=False) + yield actionToJson(action, types.ItemType.Bool, short=False) def catShort(actions: list[str]): @@ -41,21 +40,21 @@ def catShort(actions: list[str]): try: # True/ false if ":" in actions[index + 1]: - yield actionToJson(actions[index], "TextBox") + yield actionToJson(actions[index], types.ItemType.Text) index += 2 else: - yield actionToJson(actions[index], "Bool") + yield actionToJson(actions[index], types.ItemType.Bool) index += 1 except IndexError: - yield actionToJson(actions[index], "Bool") + yield actionToJson(actions[index], types.ItemType.Bool) break def process( group: list[str], groupName: str, - categorize: Callable[[list[str]], Generator[c2gtypes.Item, None, None]], -) -> list[c2gtypes.Group]: + categorize: Callable[[list[str]], Generator[types.Item, None, None]], +) -> list[types.Group]: """Generate a group (or section).""" return [ { @@ -66,14 +65,14 @@ def process( ] -def convert(parser: tuple[list[str], list[str]]) -> c2gtypes.ParserRep: +def convert(parser: tuple[list[str], list[str]]) -> types.ParserRep: """Convert getopt to a dict. Args: parser (tuple[list[str], list[str]]): getopt parser Returns: - c2gtypes.ParserRep: dictionary representing parser object + types.ParserRep: dictionary representing parser object """ return { "parser_description": "", diff --git a/cli2gui/tojson/optparse2json.py b/cli2gui/tojson/optparse2json.py index a543df8..47ba665 100755 --- a/cli2gui/tojson/optparse2json.py +++ b/cli2gui/tojson/optparse2json.py @@ -8,10 +8,10 @@ import optparse -from .. import c2gtypes +from cli2gui import types -def extractOptions(optionGroup: optparse.OptionGroup) -> c2gtypes.Group: +def extractOptions(optionGroup: optparse.OptionGroup) -> types.Group: """Get the actions as json for each item under a group.""" return { "name": optionGroup.title, # type: ignore # title is confirmed to exist @@ -25,7 +25,7 @@ def extractOptions(optionGroup: optparse.OptionGroup) -> c2gtypes.Group: } -def extractGroups(parser: optparse.OptionParser) -> c2gtypes.Group: +def extractGroups(parser: optparse.OptionParser) -> types.Group: """Get the actions as json for each item and group under the parser.""" argItems = list( categorize([action for action in parser.option_list if action.action not in "help"]) @@ -37,16 +37,21 @@ def extractGroups(parser: optparse.OptionParser) -> c2gtypes.Group: } -def actionToJson(action: optparse.Option, widget: str) -> c2gtypes.Item: +def actionToJson(action: optparse.Option, widget: types.ItemType) -> types.Item: """Generate json for an action and set the widget - used by the application.""" + choices = action.choices or [] # type: ignore # choices is confirmed to exist\ + default = action.default if action.default != ("NO", "DEFAULT") else None return { "type": widget, "display_name": str(action.metavar or action.dest), "help": str(action.help), "commands": action._long_opts + action._short_opts, - "choices": action.choices if action.choices else [], # type: ignore "dest": action.dest or "", - "_other": {"nargs": str(action.nargs or "")}, + "default": default, + "_other": { + "nargs": str(action.nargs or ""), + "choices": choices, + }, } @@ -55,23 +60,23 @@ def categorize(actions: list[optparse.Option]): for action in actions: # _actions which are either, store_bool, etc.. if action.action in ("store_true", "store_false"): - yield actionToJson(action, "Bool") + yield actionToJson(action, types.ItemType.Bool) # _actions which are of type _CountAction elif action.choices: # type: ignore # choices is confirmed to exist - yield actionToJson(action, "Dropdown") - elif action.action in "count": - yield actionToJson(action, "Counter") + yield actionToJson(action, types.ItemType.Choice) + elif action.action in ("count",): + yield actionToJson(action, types.ItemType.Int) else: - yield actionToJson(action, "TextBox") + yield actionToJson(action, types.ItemType.Text) -def convert(parser: optparse.OptionParser) -> c2gtypes.ParserRep: +def convert(parser: optparse.OptionParser) -> types.ParserRep: """Convert argparse to a dict. Args: parser (optparse.OptionParser): optparse parser Returns: - c2gtypes.ParserRep: dictionary representing parser object + types.ParserRep: dictionary representing parser object """ return {"parser_description": "", "widgets": [extractGroups(parser)]} diff --git a/cli2gui/c2gtypes.py b/cli2gui/types.py similarity index 92% rename from cli2gui/c2gtypes.py rename to cli2gui/types.py index 2c8849d..e8fd010 100644 --- a/cli2gui/c2gtypes.py +++ b/cli2gui/types.py @@ -32,15 +32,26 @@ class BuildSpec(TypedDict): class Item(TypedDict): """Representation for an arg_item.""" - type: str + type: ItemType display_name: str - help: str commands: list[str] - choices: list[str] + help: str dest: str + default: Any _other: dict[str, Any] +class ItemType(Enum): + """Enum of ItemTypes:""" + + RadioGroup = "RadioGroup" + Bool = "Bool" + File = "File" + Choice = "Choice" + Int = "Int" + Text = "Text" + + @dataclass class Group(TypedDict): """Representation for an argument group.""" diff --git a/documentation/reference/README.md b/documentation/reference/README.md index dc4f3e8..d4c7c1b 100644 --- a/documentation/reference/README.md +++ b/documentation/reference/README.md @@ -9,7 +9,6 @@ A full list of `Cli2gui` project modules. - [Application](cli2gui/application/application.md#application) - [Pysimplegui2args](cli2gui/application/pysimplegui2args.md#pysimplegui2args) - [Widgets](cli2gui/application/widgets.md#widgets) - - [C2gtypes](cli2gui/c2gtypes.md#c2gtypes) - [Decorators](cli2gui/decorators.md#decorators) - [Tojson](cli2gui/tojson/index.md#tojson) - [Argparse2json](cli2gui/tojson/argparse2json.md#argparse2json) @@ -17,3 +16,4 @@ A full list of `Cli2gui` project modules. - [Docopt2json](cli2gui/tojson/docopt2json.md#docopt2json) - [Getopt2json](cli2gui/tojson/getopt2json.md#getopt2json) - [Optparse2json](cli2gui/tojson/optparse2json.md#optparse2json) + - [Types](cli2gui/types.md#types) diff --git a/documentation/reference/cli2gui/application/application.md b/documentation/reference/cli2gui/application/application.md index b1cbe1a..f7579f8 100644 --- a/documentation/reference/cli2gui/application/application.md +++ b/documentation/reference/cli2gui/application/application.md @@ -24,7 +24,7 @@ Add arg_items and groups to the argConstruct list. #### Arguments -- `section` *c2gtypes.Group* - contents/ section containing name, arg_items +- `section` *types.Group* - contents/ section containing name, arg_items and groups - `argConstruct` *list[list[Element]]* - list of widgets to add to the program window @@ -39,22 +39,26 @@ argConstruct ```python def addItemsAndGroups( - section: c2gtypes.Group, argConstruct: list[list[Element]], widgets: Widgets + section: types.Group, argConstruct: list[list[Element]], widgets: Widgets ): ... ``` +#### See also + +- [Widgets](./widgets.md#widgets) + ## createLayout -[Show source in application.py:298](../../../../cli2gui/application/application.py#L298) +[Show source in application.py:265](../../../../cli2gui/application/application.py#L265) Create the pysimplegui layout from the build spec. #### Arguments -- `buildSpec` *c2gtypes.FullBuildSpec* - build spec containing widget +- `buildSpec` *types.FullBuildSpec* - build spec containing widget - `widgets` *Widgets* - class to build widgets - `pySimpleGui` *Any* - version of PySimpleGui to use - `menu` *list[str]]* - menu data @@ -67,7 +71,7 @@ Create the pysimplegui layout from the build spec. ```python def createLayout( - buildSpec: c2gtypes.FullBuildSpec, + buildSpec: types.FullBuildSpec, widgets: Widgets, pySimpleGui: Any, menu: str | list[str], @@ -75,17 +79,21 @@ def createLayout( ... ``` +#### See also + +- [Widgets](./widgets.md#widgets) + ## generatePopup -[Show source in application.py:229](../../../../cli2gui/application/application.py#L229) +[Show source in application.py:196](../../../../cli2gui/application/application.py#L196) Create the popup window. #### Arguments -- `buildSpec` *c2gtypes.FullBuildSpec* - [description] +- `buildSpec` *types.FullBuildSpec* - [description] values (Union[dict[Any, Any]): Returned when a button is clicked. Such as the menu - `widgets` *Widgets* - class to build widgets @@ -99,7 +107,7 @@ as the menu ```python def generatePopup( - buildSpec: c2gtypes.FullBuildSpec, + buildSpec: types.FullBuildSpec, values: dict[Any, Any] | list[Any], widgets: Widgets, pySimpleGui: Any, @@ -107,23 +115,27 @@ def generatePopup( ... ``` +#### See also + +- [Widgets](./widgets.md#widgets) + ## run -[Show source in application.py:361](../../../../cli2gui/application/application.py#L361) +[Show source in application.py:328](../../../../cli2gui/application/application.py#L328) Main entry point for the application. #### Arguments -- `buildSpec` *c2gtypes.FullBuildSpec* - args that customise the application such as the theme +- `buildSpec` *types.FullBuildSpec* - args that customise the application such as the theme or the function to run #### Signature ```python -def run(buildSpec: c2gtypes.FullBuildSpec): +def run(buildSpec: types.FullBuildSpec): ... ``` @@ -175,6 +187,10 @@ def setupWidgets(gui: str, sizes: dict[str, Any], pySimpleGui: Any) -> Widgets: ... ``` +#### See also + +- [Widgets](./widgets.md#widgets) + ## themeFromFile diff --git a/documentation/reference/cli2gui/application/pysimplegui2args.md b/documentation/reference/cli2gui/application/pysimplegui2args.md index ec8c8bc..695aabd 100644 --- a/documentation/reference/cli2gui/application/pysimplegui2args.md +++ b/documentation/reference/cli2gui/application/pysimplegui2args.md @@ -17,7 +17,7 @@ Pysimplegui2args ## argFormat -[Show source in pysimplegui2args.py:60](../../../../cli2gui/application/pysimplegui2args.py#L60) +[Show source in pysimplegui2args.py:61](../../../../cli2gui/application/pysimplegui2args.py#L61) Format the args for the desired parser. diff --git a/documentation/reference/cli2gui/application/widgets.md b/documentation/reference/cli2gui/application/widgets.md index 434a8b6..bfa8c92 100644 --- a/documentation/reference/cli2gui/application/widgets.md +++ b/documentation/reference/cli2gui/application/widgets.md @@ -9,6 +9,7 @@ Widgets - [Widgets](#widgets) - [Widgets](#widgets-1) + - [Widgets().addWidgetFromItem](#widgets()addwidgetfromitem) - [Widgets().button](#widgets()button) - [Widgets().check](#widgets()check) - [Widgets().dropdown](#widgets()dropdown) @@ -17,22 +18,23 @@ Widgets - [Widgets().helpArgHelp](#widgets()helparghelp) - [Widgets().helpArgName](#widgets()helpargname) - [Widgets().helpArgNameAndHelp](#widgets()helpargnameandhelp) + - [Widgets().helpCounterWidget](#widgets()helpcounterwidget) - [Widgets().helpDropdownWidget](#widgets()helpdropdownwidget) - [Widgets().helpFileWidget](#widgets()helpfilewidget) - [Widgets().helpFlagWidget](#widgets()helpflagwidget) - [Widgets().helpTextWidget](#widgets()helptextwidget) - [Widgets().inputText](#widgets()inputtext) - [Widgets().label](#widgets()label) + - [Widgets().spin](#widgets()spin) - [Widgets().stringSentencecase](#widgets()stringsentencecase) - [Widgets().stringTitlecase](#widgets()stringtitlecase) - [Widgets().title](#widgets()title) ## Widgets -[Show source in widgets.py:15](../../../../cli2gui/application/widgets.py#L15) - -Widgets class holding methods to create widgets in addition to a sizes... +[Show source in widgets.py:16](../../../../cli2gui/application/widgets.py#L16) +Widgets class holding methods to create widgets in addition to a sizes. attribute that can be overridden to provide the end user with customisation over the size of the gui. @@ -44,9 +46,22 @@ class Widgets: ... ``` +### Widgets().addWidgetFromItem + +[Show source in widgets.py:238](../../../../cli2gui/application/widgets.py#L238) + +Add a widget from an item (types.Item) + +#### Signature + +```python +def addWidgetFromItem(self, item: types.Item) -> list[Element]: + ... +``` + ### Widgets().button -[Show source in widgets.py:80](../../../../cli2gui/application/widgets.py#L80) +[Show source in widgets.py:92](../../../../cli2gui/application/widgets.py#L92) Return a button. @@ -59,20 +74,20 @@ def button(self, text: str) -> Element: ### Widgets().check -[Show source in widgets.py:74](../../../../cli2gui/application/widgets.py#L74) +[Show source in widgets.py:86](../../../../cli2gui/application/widgets.py#L86) Return a checkbox. #### Signature ```python -def check(self, key: str) -> Element: +def check(self, key: str, default=None) -> Element: ... ``` ### Widgets().dropdown -[Show source in widgets.py:101](../../../../cli2gui/application/widgets.py#L101) +[Show source in widgets.py:113](../../../../cli2gui/application/widgets.py#L113) Return a dropdown. @@ -85,14 +100,14 @@ def dropdown(self, key: str, argItems: list[str]) -> Element: ### Widgets().fileBrowser -[Show source in widgets.py:110](../../../../cli2gui/application/widgets.py#L110) +[Show source in widgets.py:122](../../../../cli2gui/application/widgets.py#L122) Return a fileBrowser button and field. #### Signature ```python -def fileBrowser(self, key: str) -> list[Element]: +def fileBrowser(self, key: str, default=None) -> list[Element]: ... ``` @@ -111,7 +126,7 @@ def getImgData(self, imagePath: str, first: bool = False) -> bytes: ### Widgets().helpArgHelp -[Show source in widgets.py:135](../../../../cli2gui/application/widgets.py#L135) +[Show source in widgets.py:148](../../../../cli2gui/application/widgets.py#L148) Return a label for the arg help text. @@ -124,7 +139,7 @@ def helpArgHelp(self, helpText: str) -> Element: ### Widgets().helpArgName -[Show source in widgets.py:131](../../../../cli2gui/application/widgets.py#L131) +[Show source in widgets.py:144](../../../../cli2gui/application/widgets.py#L144) Return a label for the arg name. @@ -137,7 +152,7 @@ def helpArgName(self, displayName: str, commands: list[str]) -> Element: ### Widgets().helpArgNameAndHelp -[Show source in widgets.py:139](../../../../cli2gui/application/widgets.py#L139) +[Show source in widgets.py:152](../../../../cli2gui/application/widgets.py#L152) Return a column containing the argument name and help text. @@ -150,68 +165,68 @@ def helpArgNameAndHelp( ... ``` +### Widgets().helpCounterWidget + +[Show source in widgets.py:204](../../../../cli2gui/application/widgets.py#L204) + +Return a set of widgets that make up an arg with text. + +#### Signature + +```python +def helpCounterWidget(self, item: types.Item) -> list[Element]: + ... +``` + ### Widgets().helpDropdownWidget -[Show source in widgets.py:194](../../../../cli2gui/application/widgets.py#L194) +[Show source in widgets.py:226](../../../../cli2gui/application/widgets.py#L226) Return a set of widgets that make up an arg with a choice. #### Signature ```python -def helpDropdownWidget( - self, - displayName: str, - commands: list[str], - helpText: str, - dest: str, - choices: list[str], -) -> list[Element]: +def helpDropdownWidget(self, item: types.Item) -> list[Element]: ... ``` ### Widgets().helpFileWidget -[Show source in widgets.py:185](../../../../cli2gui/application/widgets.py#L185) +[Show source in widgets.py:216](../../../../cli2gui/application/widgets.py#L216) Return a set of widgets that make up an arg with a file. #### Signature ```python -def helpFileWidget( - self, displayName: str, commands: list[str], helpText: str, dest: str -) -> list[Element]: +def helpFileWidget(self, item: types.Item) -> list[Element]: ... ``` ### Widgets().helpFlagWidget -[Show source in widgets.py:167](../../../../cli2gui/application/widgets.py#L167) +[Show source in widgets.py:180](../../../../cli2gui/application/widgets.py#L180) Return a set of widgets that make up an arg with true/ false. #### Signature ```python -def helpFlagWidget( - self, displayName: str, commands: list[str], helpText: str, dest: str -) -> list[Element]: +def helpFlagWidget(self, item: types.Item) -> list[Element]: ... ``` ### Widgets().helpTextWidget -[Show source in widgets.py:176](../../../../cli2gui/application/widgets.py#L176) +[Show source in widgets.py:192](../../../../cli2gui/application/widgets.py#L192) Return a set of widgets that make up an arg with text. #### Signature ```python -def helpTextWidget( - self, displayName: str, commands: list[str], helpText: str, dest: str -) -> list[Element]: +def helpTextWidget(self, item: types.Item) -> list[Element]: ... ``` @@ -224,13 +239,13 @@ Return an input text field. #### Signature ```python -def inputText(self, key: str) -> Element: +def inputText(self, key: str, default=None) -> Element: ... ``` ### Widgets().label -[Show source in widgets.py:89](../../../../cli2gui/application/widgets.py#L89) +[Show source in widgets.py:101](../../../../cli2gui/application/widgets.py#L101) Return a label. @@ -241,6 +256,19 @@ def label(self, text: str, font: int = 11) -> Element: ... ``` +### Widgets().spin + +[Show source in widgets.py:75](../../../../cli2gui/application/widgets.py#L75) + +Return an input text field. + +#### Signature + +```python +def spin(self, key: str, default=None) -> Element: + ... +``` + ### Widgets().stringSentencecase [Show source in widgets.py:55](../../../../cli2gui/application/widgets.py#L55) @@ -269,7 +297,7 @@ def stringTitlecase(self, string: str, splitStr: str = "ALL"): ### Widgets().title -[Show source in widgets.py:146](../../../../cli2gui/application/widgets.py#L146) +[Show source in widgets.py:159](../../../../cli2gui/application/widgets.py#L159) Return a set of widgets that make up the application header. diff --git a/documentation/reference/cli2gui/decorators.md b/documentation/reference/cli2gui/decorators.md index c4d8f1a..5b74ec3 100644 --- a/documentation/reference/cli2gui/decorators.md +++ b/documentation/reference/cli2gui/decorators.md @@ -13,10 +13,9 @@ Decorators ## Cli2Gui -[Show source in decorators.py:163](../../../cli2gui/decorators.py#L163) - -Decorator to use in the function that contains the argument parser... +[Show source in decorators.py:168](../../../cli2gui/decorators.py#L168) +Decorator to use in the function that contains the argument parser. Serialises data to JSON and launches the Cli2Gui application. #### Arguments @@ -78,10 +77,9 @@ def Cli2Gui( ## Click2Gui -[Show source in decorators.py:96](../../../cli2gui/decorators.py#L96) - -Decorator to use in the function that contains the argument parser... +[Show source in decorators.py:102](../../../cli2gui/decorators.py#L102) +Decorator to use in the function that contains the argument parser. Serialises data to JSON and launches the Cli2Gui application. #### Arguments @@ -137,7 +135,7 @@ def Click2Gui( ## createFromParser -[Show source in decorators.py:24](../../../cli2gui/decorators.py#L24) +[Show source in decorators.py:30](../../../cli2gui/decorators.py#L30) Generate a buildSpec from a parser. @@ -148,12 +146,12 @@ argsParser (Union[tuple[Any, Any]]): A parser that acts on function arguments. eg. getopt.getopt kwargsParser (Union[dict[Any, Any]]): A parser that acts on named params - `sourcePath` *str* - Program source path -- `buildSpec` *c2gtypes.BuildSpec* - Build spec +- `buildSpec` *types.BuildSpec* - Build spec **kwargs (dict[Any, Any]): kwargs #### Returns -- `c2gtypes.FullBuildSpec` - buildSpec to be used by the application +- `types.FullBuildSpec` - buildSpec to be used by the application #### Raises @@ -173,4 +171,9 @@ def createFromParser( ... ``` +#### See also + +- [BuildSpec](./types.md#buildspec) +- [FullBuildSpec](./types.md#fullbuildspec) + diff --git a/documentation/reference/cli2gui/index.md b/documentation/reference/cli2gui/index.md index 49290c0..ed60fcd 100644 --- a/documentation/reference/cli2gui/index.md +++ b/documentation/reference/cli2gui/index.md @@ -11,6 +11,6 @@ Cli2gui ## Modules - [Application](application/index.md) -- [C2gtypes](./c2gtypes.md) - [Decorators](./decorators.md) -- [Tojson](tojson/index.md) \ No newline at end of file +- [Tojson](tojson/index.md) +- [Types](./types.md) \ No newline at end of file diff --git a/documentation/reference/cli2gui/tojson/argparse2json.md b/documentation/reference/cli2gui/tojson/argparse2json.md index 57b8689..bd96c6d 100644 --- a/documentation/reference/cli2gui/tojson/argparse2json.md +++ b/documentation/reference/cli2gui/tojson/argparse2json.md @@ -12,7 +12,7 @@ Argparse2json - [actionToJson](#actiontojson) - [buildRadioGroup](#buildradiogroup) - [categorizeGroups](#categorizegroups) - - [catergorizeItems](#catergorizeitems) + - [categorizeItems](#categorizeitems) - [chooseName](#choosename) - [containsActions](#containsactions) - [convert](#convert) @@ -25,7 +25,7 @@ Argparse2json ## ArgparseGroup -[Show source in argparse2json.py:26](../../../../cli2gui/tojson/argparse2json.py#L26) +[Show source in argparse2json.py:25](../../../../cli2gui/tojson/argparse2json.py#L25) Class to represent an ArgparseGroup @@ -40,14 +40,14 @@ class ArgparseGroup(TypedDict): ## actionToJson -[Show source in argparse2json.py:109](../../../../cli2gui/tojson/argparse2json.py#L109) +[Show source in argparse2json.py:107](../../../../cli2gui/tojson/argparse2json.py#L107) Generate json for an action and set the widget - used by the application. #### Signature ```python -def actionToJson(action: argparse.Action, widget: str) -> c2gtypes.Item: +def actionToJson(action: argparse.Action, widget: types.ItemType) -> types.Item: ... ``` @@ -55,14 +55,14 @@ def actionToJson(action: argparse.Action, widget: str) -> c2gtypes.Item: ## buildRadioGroup -[Show source in argparse2json.py:122](../../../../cli2gui/tojson/argparse2json.py#L122) +[Show source in argparse2json.py:121](../../../../cli2gui/tojson/argparse2json.py#L121) Create a radio group for a mutex group of arguments. #### Signature ```python -def buildRadioGroup(mutexGroup: _MutuallyExclusiveGroup): +def buildRadioGroup(mutexGroup: _MutuallyExclusiveGroup) -> types.Item: ... ``` @@ -70,14 +70,14 @@ def buildRadioGroup(mutexGroup: _MutuallyExclusiveGroup): ## categorizeGroups -[Show source in argparse2json.py:151](../../../../cli2gui/tojson/argparse2json.py#L151) +[Show source in argparse2json.py:150](../../../../cli2gui/tojson/argparse2json.py#L150) Categorize the parser groups and arg_items. #### Signature ```python -def categorizeGroups(groups: list[ArgparseGroup]) -> list[c2gtypes.Group]: +def categorizeGroups(groups: list[ArgparseGroup]) -> list[types.Group]: ... ``` @@ -87,18 +87,16 @@ def categorizeGroups(groups: list[ArgparseGroup]) -> list[c2gtypes.Group]: -## catergorizeItems +## categorizeItems -[Show source in argparse2json.py:132](../../../../cli2gui/tojson/argparse2json.py#L132) +[Show source in argparse2json.py:131](../../../../cli2gui/tojson/argparse2json.py#L131) Catergorise each action and generate json. #### Signature ```python -def catergorizeItems( - actions: list[argparse.Action], -) -> Generator[c2gtypes.Item, None, None]: +def categorizeItems(actions: list[argparse.Action]) -> Generator[types.Item, None, None]: ... ``` @@ -106,7 +104,7 @@ def catergorizeItems( ## chooseName -[Show source in argparse2json.py:55](../../../../cli2gui/tojson/argparse2json.py#L55) +[Show source in argparse2json.py:54](../../../../cli2gui/tojson/argparse2json.py#L54) Get the program name. @@ -121,7 +119,7 @@ def chooseName(name: str, subparser: argparse.ArgumentParser) -> str: ## containsActions -[Show source in argparse2json.py:60](../../../../cli2gui/tojson/argparse2json.py#L60) +[Show source in argparse2json.py:59](../../../../cli2gui/tojson/argparse2json.py#L59) Check if any actions(a) are present in actions(b). @@ -136,7 +134,7 @@ def containsActions(actionA: list[argparse.Action], actionB: list[argparse.Actio ## convert -[Show source in argparse2json.py:178](../../../../cli2gui/tojson/argparse2json.py#L178) +[Show source in argparse2json.py:177](../../../../cli2gui/tojson/argparse2json.py#L177) Convert argparse to a dict. @@ -146,12 +144,12 @@ Convert argparse to a dict. #### Returns -- `c2gtypes.ParserRep` - dictionary representing parser object +- `types.ParserRep` - dictionary representing parser object #### Signature ```python -def convert(parser: argparse.ArgumentParser) -> c2gtypes.ParserRep: +def convert(parser: argparse.ArgumentParser) -> types.ParserRep: ... ``` @@ -159,7 +157,7 @@ def convert(parser: argparse.ArgumentParser) -> c2gtypes.ParserRep: ## extractRawGroups -[Show source in argparse2json.py:97](../../../../cli2gui/tojson/argparse2json.py#L97) +[Show source in argparse2json.py:95](../../../../cli2gui/tojson/argparse2json.py#L95) Recursively extract argument groups and associated actions from ParserGroup objects. @@ -178,7 +176,7 @@ def extractRawGroups(actionGroup: argparse._ArgumentGroup) -> ArgparseGroup: ## isDefaultProgname -[Show source in argparse2json.py:50](../../../../cli2gui/tojson/argparse2json.py#L50) +[Show source in argparse2json.py:49](../../../../cli2gui/tojson/argparse2json.py#L49) Identify if the passed name is the default program name. @@ -193,7 +191,7 @@ def isDefaultProgname(name: str, subparser: argparse.ArgumentParser) -> bool: ## iterParsers -[Show source in argparse2json.py:34](../../../../cli2gui/tojson/argparse2json.py#L34) +[Show source in argparse2json.py:33](../../../../cli2gui/tojson/argparse2json.py#L33) Iterate over name, parser pairs. @@ -210,14 +208,14 @@ def iterParsers( ## process -[Show source in argparse2json.py:168](../../../../cli2gui/tojson/argparse2json.py#L168) +[Show source in argparse2json.py:167](../../../../cli2gui/tojson/argparse2json.py#L167) Reapply the mutex groups and then categorize them and the arg_items under the parser. #### Signature ```python -def process(parser: argparse.ArgumentParser) -> list[c2gtypes.Group]: +def process(parser: argparse.ArgumentParser) -> list[types.Group]: ... ``` @@ -225,10 +223,9 @@ def process(parser: argparse.ArgumentParser) -> list[c2gtypes.Group]: ## reapplyMutexGroups -[Show source in argparse2json.py:65](../../../../cli2gui/tojson/argparse2json.py#L65) - -_argparse stores mutually exclusive groups independently... +[Show source in argparse2json.py:64](../../../../cli2gui/tojson/argparse2json.py#L64) +_argparse stores mutually exclusive groups independently. of all other groups. So, they must be manually re-combined with the groups/subgroups to which they were originally declared in order to have them appear in the correct location in the UI. @@ -250,7 +247,7 @@ def reapplyMutexGroups( ## stripEmpty -[Show source in argparse2json.py:163](../../../../cli2gui/tojson/argparse2json.py#L163) +[Show source in argparse2json.py:162](../../../../cli2gui/tojson/argparse2json.py#L162) Remove groups where group['arg_items'] is false. diff --git a/documentation/reference/cli2gui/tojson/click2json.md b/documentation/reference/cli2gui/tojson/click2json.md index ab043bc..a30e704 100644 --- a/documentation/reference/cli2gui/tojson/click2json.md +++ b/documentation/reference/cli2gui/tojson/click2json.md @@ -10,20 +10,21 @@ Click2json - [Click2json](#click2json) - [actionToJson](#actiontojson) - [categorize](#categorize) - - [categorizeCommand](#categorizecommand) - [convert](#convert) - [extract](#extract) ## actionToJson -[Show source in click2json.py:34](../../../../cli2gui/tojson/click2json.py#L34) +[Show source in click2json.py:32](../../../../cli2gui/tojson/click2json.py#L32) Generate json for an action and set the widget - used by the application. #### Signature ```python -def actionToJson(action: Any, widget: str) -> c2gtypes.Item: +def actionToJson( + action: Any, widget: types.ItemType, other: dict | None = None +) -> types.Item: ... ``` @@ -38,22 +39,7 @@ Catergorise each action and generate json. #### Signature ```python -def categorize(actions: list[Any]) -> Generator[c2gtypes.Item, None, None]: - ... -``` - - - -## categorizeCommand - -[Show source in click2json.py:58](../../../../cli2gui/tojson/click2json.py#L58) - -Catergorise each action and generate json. - -#### Signature - -```python -def categorizeCommand(actions: list[Any]) -> Generator[c2gtypes.Item, None, None]: +def categorize(actions: list[Any]) -> Generator[types.Item, None, None]: ... ``` @@ -61,7 +47,7 @@ def categorizeCommand(actions: list[Any]) -> Generator[c2gtypes.Item, None, None ## convert -[Show source in click2json.py:64](../../../../cli2gui/tojson/click2json.py#L64) +[Show source in click2json.py:67](../../../../cli2gui/tojson/click2json.py#L67) Convert click to a dict. @@ -71,12 +57,12 @@ Convert click to a dict. #### Returns -- `c2gtypes.ParserRep` - dictionary representing parser object +- `types.ParserRep` - dictionary representing parser object #### Signature ```python -def convert(parser: Any) -> c2gtypes.ParserRep: +def convert(parser: Any) -> types.ParserRep: ... ``` @@ -91,7 +77,7 @@ Get the actions as json for the parser. #### Signature ```python -def extract(parser: Any) -> list[c2gtypes.Group]: +def extract(parser: Any) -> list[types.Group]: ... ``` diff --git a/documentation/reference/cli2gui/tojson/docopt2json.md b/documentation/reference/cli2gui/tojson/docopt2json.md index 92ee102..0a580e3 100644 --- a/documentation/reference/cli2gui/tojson/docopt2json.md +++ b/documentation/reference/cli2gui/tojson/docopt2json.md @@ -27,8 +27,8 @@ Generate json for an action and set the widget - used by the application. ```python def actionToJson( - action: tuple[str, str, str, Any, str], widget: str, isPos: bool -) -> c2gtypes.Item: + action: tuple[str, str, int, Any, str], widget: types.ItemType, isPos: bool +) -> types.Item: ... ``` @@ -36,16 +36,18 @@ def actionToJson( ## categorize -[Show source in docopt2json.py:36](../../../../cli2gui/tojson/docopt2json.py#L36) +[Show source in docopt2json.py:39](../../../../cli2gui/tojson/docopt2json.py#L39) Catergorise each action and generate json. +Each action is in the form (short, long, argcount, value, help_message) + #### Signature ```python def categorize( - actions: list[tuple[str, str, str, Any, str]], isPos: bool = False -) -> Iterator[c2gtypes.Item]: + actions: list[tuple[str, str, int, Any, str]], isPos: bool = False +) -> Iterator[types.Item]: ... ``` @@ -53,7 +55,7 @@ def categorize( ## convert -[Show source in docopt2json.py:114](../../../../cli2gui/tojson/docopt2json.py#L114) +[Show source in docopt2json.py:123](../../../../cli2gui/tojson/docopt2json.py#L123) Convert getopt to a dict. @@ -63,12 +65,12 @@ Convert getopt to a dict. #### Returns -- `c2gtypes.ParserRep` - dictionary representing parser object +- `types.ParserRep` - dictionary representing parser object #### Signature ```python -def convert(parser: Any) -> c2gtypes.ParserRep: +def convert(parser: Any) -> types.ParserRep: ... ``` @@ -76,14 +78,14 @@ def convert(parser: Any) -> c2gtypes.ParserRep: ## extract -[Show source in docopt2json.py:48](../../../../cli2gui/tojson/docopt2json.py#L48) +[Show source in docopt2json.py:57](../../../../cli2gui/tojson/docopt2json.py#L57) Get the actions as json for the parser. #### Signature ```python -def extract(parser: Any) -> list[c2gtypes.Group]: +def extract(parser: Any) -> list[types.Group]: ... ``` @@ -91,14 +93,14 @@ def extract(parser: Any) -> list[c2gtypes.Group]: ## parse -[Show source in docopt2json.py:73](../../../../cli2gui/tojson/docopt2json.py#L73) +[Show source in docopt2json.py:82](../../../../cli2gui/tojson/docopt2json.py#L82) Parse an option help text, adapted from docopt. #### Signature ```python -def parse(optionDescription: str) -> tuple[str, str, str, Any, str]: +def parse(optionDescription: str) -> tuple[str, str, int, Any, str]: ... ``` @@ -106,14 +108,14 @@ def parse(optionDescription: str) -> tuple[str, str, str, Any, str]: ## parseOpt -[Show source in docopt2json.py:91](../../../../cli2gui/tojson/docopt2json.py#L91) +[Show source in docopt2json.py:100](../../../../cli2gui/tojson/docopt2json.py#L100) Parse an option help text, adapted from docopt. #### Signature ```python -def parseOpt(doc: Any) -> list[tuple[str, str, str, Any, str]]: +def parseOpt(doc: Any) -> list[tuple[str, str, int, Any, str]]: ... ``` @@ -121,14 +123,14 @@ def parseOpt(doc: Any) -> list[tuple[str, str, str, Any, str]]: ## parsePos -[Show source in docopt2json.py:103](../../../../cli2gui/tojson/docopt2json.py#L103) +[Show source in docopt2json.py:112](../../../../cli2gui/tojson/docopt2json.py#L112) Parse positional arguments from docstring. #### Signature ```python -def parsePos(doc: Any) -> list[tuple[str, str, str, Any, str]]: +def parsePos(doc: Any) -> list[tuple[str, str]]: ... ``` @@ -136,7 +138,7 @@ def parsePos(doc: Any) -> list[tuple[str, str, str, Any, str]]: ## parseSection -[Show source in docopt2json.py:64](../../../../cli2gui/tojson/docopt2json.py#L64) +[Show source in docopt2json.py:73](../../../../cli2gui/tojson/docopt2json.py#L73) Taken from docopt. diff --git a/documentation/reference/cli2gui/tojson/getopt2json.md b/documentation/reference/cli2gui/tojson/getopt2json.md index 5cb26be..e9b9c24 100644 --- a/documentation/reference/cli2gui/tojson/getopt2json.md +++ b/documentation/reference/cli2gui/tojson/getopt2json.md @@ -18,14 +18,13 @@ Getopt2json [Show source in getopt2json.py:11](../../../../cli2gui/tojson/getopt2json.py#L11) -Convert an arg to json, behave in the same way as argparse hence the large... - +Convert an arg to json, behave in the same way as argparse hence the large amount of duplication. #### Signature ```python -def actionToJson(action: str, widget: str, short: bool = True) -> c2gtypes.Item: +def actionToJson(action: str, widget: types.ItemType, short: bool = True) -> types.Item: ... ``` @@ -33,7 +32,7 @@ def actionToJson(action: str, widget: str, short: bool = True) -> c2gtypes.Item: ## catLong -[Show source in getopt2json.py:27](../../../../cli2gui/tojson/getopt2json.py#L27) +[Show source in getopt2json.py:26](../../../../cli2gui/tojson/getopt2json.py#L26) Categorize long args. @@ -48,7 +47,7 @@ def catLong(actions: list[str]): ## catShort -[Show source in getopt2json.py:37](../../../../cli2gui/tojson/getopt2json.py#L37) +[Show source in getopt2json.py:36](../../../../cli2gui/tojson/getopt2json.py#L36) Categorize short args. @@ -63,7 +62,7 @@ def catShort(actions: list[str]): ## convert -[Show source in getopt2json.py:69](../../../../cli2gui/tojson/getopt2json.py#L69) +[Show source in getopt2json.py:68](../../../../cli2gui/tojson/getopt2json.py#L68) Convert getopt to a dict. @@ -73,12 +72,12 @@ parser (tuple[list[str], list[str]]): getopt parser #### Returns -- `c2gtypes.ParserRep` - dictionary representing parser object +- `types.ParserRep` - dictionary representing parser object #### Signature ```python -def convert(parser: tuple[list[str], list[str]]) -> c2gtypes.ParserRep: +def convert(parser: tuple[list[str], list[str]]) -> types.ParserRep: ... ``` @@ -86,7 +85,7 @@ def convert(parser: tuple[list[str], list[str]]) -> c2gtypes.ParserRep: ## process -[Show source in getopt2json.py:54](../../../../cli2gui/tojson/getopt2json.py#L54) +[Show source in getopt2json.py:53](../../../../cli2gui/tojson/getopt2json.py#L53) Generate a group (or section). @@ -96,8 +95,8 @@ Generate a group (or section). def process( group: list[str], groupName: str, - categorize: Callable[[list[str]], Generator[c2gtypes.Item, None, None]], -) -> list[c2gtypes.Group]: + categorize: Callable[[list[str]], Generator[types.Item, None, None]], +) -> list[types.Group]: ... ``` diff --git a/documentation/reference/cli2gui/tojson/optparse2json.md b/documentation/reference/cli2gui/tojson/optparse2json.md index 51d7740..77b0749 100644 --- a/documentation/reference/cli2gui/tojson/optparse2json.md +++ b/documentation/reference/cli2gui/tojson/optparse2json.md @@ -23,7 +23,7 @@ Generate json for an action and set the widget - used by the application. #### Signature ```python -def actionToJson(action: optparse.Option, widget: str) -> c2gtypes.Item: +def actionToJson(action: optparse.Option, widget: types.ItemType) -> types.Item: ... ``` @@ -31,7 +31,7 @@ def actionToJson(action: optparse.Option, widget: str) -> c2gtypes.Item: ## categorize -[Show source in optparse2json.py:53](../../../../cli2gui/tojson/optparse2json.py#L53) +[Show source in optparse2json.py:58](../../../../cli2gui/tojson/optparse2json.py#L58) Catergorise each action and generate json. @@ -46,7 +46,7 @@ def categorize(actions: list[optparse.Option]): ## convert -[Show source in optparse2json.py:68](../../../../cli2gui/tojson/optparse2json.py#L68) +[Show source in optparse2json.py:73](../../../../cli2gui/tojson/optparse2json.py#L73) Convert argparse to a dict. @@ -56,12 +56,12 @@ Convert argparse to a dict. #### Returns -- `c2gtypes.ParserRep` - dictionary representing parser object +- `types.ParserRep` - dictionary representing parser object #### Signature ```python -def convert(parser: optparse.OptionParser) -> c2gtypes.ParserRep: +def convert(parser: optparse.OptionParser) -> types.ParserRep: ... ``` @@ -76,7 +76,7 @@ Get the actions as json for each item and group under the parser. #### Signature ```python -def extractGroups(parser: optparse.OptionParser) -> c2gtypes.Group: +def extractGroups(parser: optparse.OptionParser) -> types.Group: ... ``` @@ -91,7 +91,7 @@ Get the actions as json for each item under a group. #### Signature ```python -def extractOptions(optionGroup: optparse.OptionGroup) -> c2gtypes.Group: +def extractOptions(optionGroup: optparse.OptionGroup) -> types.Group: ... ``` diff --git a/documentation/reference/cli2gui/c2gtypes.md b/documentation/reference/cli2gui/types.md similarity index 65% rename from documentation/reference/cli2gui/c2gtypes.md rename to documentation/reference/cli2gui/types.md index 94bbfe0..adf15be 100644 --- a/documentation/reference/cli2gui/c2gtypes.md +++ b/documentation/reference/cli2gui/types.md @@ -1,23 +1,24 @@ -# C2gtypes +# Types [Cli2gui Index](../README.md#cli2gui-index) / [Cli2gui](./index.md#cli2gui) / -C2gtypes +Types -> Auto-generated documentation for [cli2gui.c2gtypes](../../../cli2gui/c2gtypes.py) module. +> Auto-generated documentation for [cli2gui.types](../../../cli2gui/types.py) module. -- [C2gtypes](#c2gtypes) +- [Types](#types) - [BuildSpec](#buildspec) - [FullBuildSpec](#fullbuildspec) - [GUIType](#guitype) - [Group](#group) - [Item](#item) + - [ItemType](#itemtype) - [ParserRep](#parserrep) - [ParserType](#parsertype) ## BuildSpec -[Show source in c2gtypes.py:15](../../../cli2gui/c2gtypes.py#L15) +[Show source in types.py:15](../../../cli2gui/types.py#L15) Representation for the BuildSpec. @@ -32,7 +33,7 @@ class BuildSpec(TypedDict): ## FullBuildSpec -[Show source in c2gtypes.py:62](../../../cli2gui/c2gtypes.py#L62) +[Show source in types.py:73](../../../cli2gui/types.py#L73) Representation for the FullBuildSpec (BuildSpec + ParserRep). @@ -47,7 +48,7 @@ class FullBuildSpec(TypedDict): ## GUIType -[Show source in c2gtypes.py:103](../../../cli2gui/c2gtypes.py#L103) +[Show source in types.py:114](../../../cli2gui/types.py#L114) Supported gui types. @@ -66,7 +67,7 @@ class GUIType(str, Enum): ## Group -[Show source in c2gtypes.py:45](../../../cli2gui/c2gtypes.py#L45) +[Show source in types.py:56](../../../cli2gui/types.py#L56) Representation for an argument group. @@ -81,7 +82,7 @@ class Group(TypedDict): ## Item -[Show source in c2gtypes.py:32](../../../cli2gui/c2gtypes.py#L32) +[Show source in types.py:32](../../../cli2gui/types.py#L32) Representation for an arg_item. @@ -94,9 +95,24 @@ class Item(TypedDict): +## ItemType + +[Show source in types.py:44](../../../cli2gui/types.py#L44) + +Enum of ItemTypes: + +#### Signature + +```python +class ItemType(Enum): + ... +``` + + + ## ParserRep -[Show source in c2gtypes.py:54](../../../cli2gui/c2gtypes.py#L54) +[Show source in types.py:65](../../../cli2gui/types.py#L65) Representation for a parser. @@ -111,7 +127,7 @@ class ParserRep(TypedDict): ## ParserType -[Show source in c2gtypes.py:81](../../../cli2gui/c2gtypes.py#L81) +[Show source in types.py:92](../../../cli2gui/types.py#L92) Supported parser types. diff --git a/pyproject.toml b/pyproject.toml index a09373d..433a218 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "cli2gui" -version = "2022.2.1" +version = "2022.3" license = "mit" description = "Use this module to convert a cli program to a gui" authors = ["FredHappyface"] diff --git a/tests/click/test_boolean.py b/tests/click/test_boolean.py new file mode 100644 index 0000000..2013f39 --- /dev/null +++ b/tests/click/test_boolean.py @@ -0,0 +1,26 @@ +"""Tests a simple parser + +Program from https://click.palletsprojects.com/en/7.x/#documentation +""" + +from __future__ import annotations + +import sys +from pathlib import Path + +import click + +THISDIR = str(Path(__file__).resolve().parent) +sys.path.insert(0, str(Path(THISDIR).parent.parent)) +from cli2gui import Click2Gui + + +@click.command() +@click.option("--print-version", default=True, help="Print the version?") +def hello(print_version): + if print_version: + print("v1.0") + + +Click2Gui(run_function=hello) +#hello() diff --git a/tests/click/test_choice.py b/tests/click/test_choice.py new file mode 100644 index 0000000..2546bca --- /dev/null +++ b/tests/click/test_choice.py @@ -0,0 +1,22 @@ +"""Program from https://click.palletsprojects.com/en/8.1.x/ +""" + +from __future__ import annotations + +import sys +from pathlib import Path + +import click + +THISDIR = str(Path(__file__).resolve().parent) +sys.path.insert(0, str(Path(THISDIR).parent.parent)) +from cli2gui import Click2Gui + + +@click.command() +@click.option('--hash-type', + type=click.Choice(['MD5', 'SHA1'], case_sensitive=False)) +def digest(hash_type): + click.echo(hash_type) + +Click2Gui(run_function=digest) diff --git a/tests/click/test_feat_switches.py b/tests/click/test_feat_switches.py new file mode 100644 index 0000000..ef6d795 --- /dev/null +++ b/tests/click/test_feat_switches.py @@ -0,0 +1,24 @@ +"""Program from https://click.palletsprojects.com/en/8.1.x/ +""" + +from __future__ import annotations + +import sys +from pathlib import Path + +import click + +THISDIR = str(Path(__file__).resolve().parent) +sys.path.insert(0, str(Path(THISDIR).parent.parent)) +from cli2gui import Click2Gui + +import sys + +@click.command() +@click.option('--upper', 'transformation', flag_value='upper', + default=True) +@click.option('--lower', 'transformation', flag_value='lower') +def info(transformation): + click.echo(getattr(sys.platform, transformation)()) + +Click2Gui(run_function=info) diff --git a/tests/docopt/test_11.py b/tests/docopt/test_11.py new file mode 100644 index 0000000..bc4b3e6 --- /dev/null +++ b/tests/docopt/test_11.py @@ -0,0 +1,45 @@ +""" +usage: + simple.py [-h] [--optional OPTIONAL] [--store-true] [--store-false] + [--store STORE] [--count] [--choices {choice1,choice2}] PATH + +Arguments: + PATH positional arg + +Options: + -h, --help show this help message and exit + --optional OPTIONAL optional arg + --store-true optional arg store true + --store-false optional arg store false + --store STORE optional arg store [default: store me] + --count optional arg count + --choices {choice1,choice2} + optional arg store with choices + +""" + +from __future__ import annotations + +import sys +from pathlib import Path + +import docopt + +THISDIR = str(Path(__file__).resolve().parent) +sys.path.insert(0, str(Path(THISDIR).parent.parent)) +from cli2gui import Cli2Gui + + +def handle(args): + """Handle the args.""" + print(args) + + +@Cli2Gui(run_function=handle, parser="docopt") +def cli(): + """Cli entrypoint.""" + args = docopt.docopt(__doc__) + handle(args) + + +cli() diff --git a/tests/docopt/test_advanced.py b/tests/docopt/test_advanced.py deleted file mode 100644 index 85b611b..0000000 --- a/tests/docopt/test_advanced.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Tests an advanced parser -""" -from __future__ import annotations - -# TODO diff --git a/tests/optparse/test_11.py b/tests/optparse/test_11.py new file mode 100644 index 0000000..70d06df --- /dev/null +++ b/tests/optparse/test_11.py @@ -0,0 +1,45 @@ +"""Tests a simple parser +""" + +from __future__ import annotations + +import optparse +import sys +from pathlib import Path + +THISDIR = str(Path(__file__).resolve().parent) +sys.path.insert(0, str(Path(THISDIR).parent.parent)) +from cli2gui import Cli2Gui + + +def handle(args): + """Handle the args.""" + print(args) + + +@Cli2Gui(run_function=handle, parser="optparse") +def cli(): + """Cli entrypoint.""" + parser = optparse.OptionParser("Simple Parser") + + parser.add_option("--optional", help="optional arg") + + # Store true, false, store, count, choices + parser.add_option("--store-true", action="store_true", help="optional arg store true", default=True) + parser.add_option("--store-false", action="store_false", help="optional arg store false", default=True) + parser.add_option("--store", action="store", help="optional arg store", default="store me") + parser.add_option("--count", action="count", help="optional arg count", default=1) + parser.add_option( + "--choices", + action="store", + choices=["choice1", "choice2"], + help="optional arg store with choices", + ) + + + args = parser.parse_args() + + handle(args) + + +cli() diff --git a/tests/optparse/test_advanced.py b/tests/optparse/test_advanced.py deleted file mode 100644 index 4640904..0000000 --- a/tests/optparse/test_advanced.py +++ /dev/null @@ -1 +0,0 @@ -# TODO