diff --git a/doc2md.py b/doc2md.py new file mode 100755 index 00000000..3300b9f4 --- /dev/null +++ b/doc2md.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 + +""" +Convert parser doc string to markdown +""" +import sys +import importlib +from inspect import isfunction, signature, cleandoc +import yapf +import os +import sys + +ignore_lib_functions = [ + 'cast', + 'wraps', + 'lru_cache', + 'namedtuple' +] + +sys.path.append(os.getcwd() + '/jc') +mod_path = sys.argv[1] +mod_name = mod_path.split('.')[-1] +module = importlib.import_module(f'{mod_path}') + +######## HEADER ######## +header = f'''[Home](https://kellyjonbrazil.github.io/jc/) + + +# {mod_path} +''' + +summary = module.__doc__ + +functions = [] +for attribute in dir(module): + if isfunction(getattr(module, attribute)) \ + and not getattr(module, attribute).__name__.startswith('_'): + + if 'jc.parsers.' in mod_path and not 'universal' in mod_path: + if attribute == 'parse': + functions.append(attribute) + + else: + if not attribute in ignore_lib_functions: + functions.append(attribute) + +######## TABLE OF CONTENTS ######## +toc = f'# Table of Contents\n\n*[{mod_path}](#{mod_path})\n' +for api in functions: + toc = f'{toc} *[{api}](#{mod_path}.{api})\n' + +######## API DOCS ######## +api_docs = '' +for api in functions: + api_function = getattr(module, api) + + this_header = f'\n\n### {api}\n' + this_sig = str(signature(api_function)) + formatted_sig = yapf.yapf_api.FormatCode(f'def {api_function.__name__}{this_sig}:\n pass' ) + formatted_sig = formatted_sig[0].split(':\n pass')[0] + this_name_and_sig = f'{this_header}\n```python\n{formatted_sig}\n```' + + this_doc = cleandoc(api_function.__doc__) + api_docs = api_docs + this_name_and_sig + '\n\n' + this_doc + '\n\n' + +######## FOOTER ######## +footer = '' +if 'jc.parsers.' in mod_path and not 'universal' in mod_path: + footer = '### Parser Information\n' + comp = ', '.join(module.info.compatible) + ver = module.info.version + author = module.info.author + author_email = module.info.author_email + slurpable = 'slurpable' in module.info.tags + footer = footer + f'Compatibility: {comp}\n\n' + footer = footer + f'Source: [`jc/parsers/{mod_name}.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/{mod_name}.py)\n\n' + if slurpable: + footer = footer + 'This parser can be used with the `--slurp` command-line option.\n\n' + footer = footer + f'Version {ver} by {author} ({author_email})\n' + +if 'jc.parsers.' in mod_path and not 'universal' in mod_path: + final_doc = header + '\n' + summary + '\n\n' + api_docs + '\n' + footer +elif mod_path == 'jc': + final_doc = header + '\n' + summary +else: + final_doc = header + '\n' + toc + '\n' + summary + '\n\n' + api_docs + +print(final_doc) + + + + diff --git a/docgen.sh b/docgen.sh index a403c627..990add17 100755 --- a/docgen.sh +++ b/docgen.sh @@ -1,107 +1,34 @@ #!/bin/bash -# Generate docs.md -# requires pydoc-markdown 4.6.1 +# Generate markdown document files (*.md) + +# Requires the yapf python library # use ./docgen all to generate all docs -readme_config=$(cat <<'EOF' -{ - "processors": [ - { - "type": "filter" - }, - { - "type": "pydocmd" - } - ], - "renderer": { - "type": "markdown", - "header_level_by_type": { - "Module": 1, - "Class": 3, - "Method": 3, - "Function": 3, - "Variable": 3 - } - } -} -EOF -) - -toc_config=$(cat <<'EOF' -{ - "processors": [ - { - "type": "filter" - }, - { - "type": "pydocmd" - } - ], - "renderer": { - "type": "markdown", - "render_toc": true, - "header_level_by_type": { - "Module": 1, - "Class": 3, - "Method": 3, - "Function": 3, - "Variable": 3 - } - } -} -EOF -) - -parser_config=$(cat <<'EOF' -{ - "processors": [ - { - "type": "filter", - "expression": "not name == \"info\" and not name.startswith(\"_\") and default()" - }, - { - "type": "pydocmd" - } - ], - "renderer": { - "type": "markdown", - "header_level_by_type": { - "Module": 1, - "Class": 3, - "Method": 3, - "Function": 3, - "Variable": 3 - } - } -} -EOF -) - cd jc ( echo Building docs for: package - pydoc-markdown -m jc "${readme_config}" > ../docs/readme.md; echo "+++ package docs complete" + ../doc2md.py jc > ../docs/readme.md && echo "+++ package docs complete" || echo "*** PACKAGE DOCS FAILED" ) & ( echo Building docs for: lib - pydoc-markdown -m jc.lib "${toc_config}" > ../docs/lib.md; echo "+++ lib docs complete" + ../doc2md.py jc.lib > ../docs/lib.md && echo "+++ lib docs complete" || echo "*** LIB DOCS FAILED" ) & ( echo Building docs for: utils - pydoc-markdown -m jc.utils "${toc_config}" > ../docs/utils.md; echo "+++ utils docs complete" + ../doc2md.py jc.utils > ../docs/utils.md && echo "+++ utils docs complete" || echo "*** UTILS DOCS FAILED" ) & ( echo Building docs for: streaming - pydoc-markdown -m jc.streaming "${toc_config}" > ../docs/streaming.md; echo "+++ streaming docs complete" + ../doc2md.py jc.streaming > ../docs/streaming.md && echo "+++ streaming docs complete" || echo "*** STREAMING DOCS FAILED" ) & ( echo Building docs for: universal parser - pydoc-markdown -m jc.parsers.universal "${toc_config}" > ../docs/parsers/universal.md; echo "+++ universal parser docs complete" + ../doc2md.py jc.parsers.universal > ../docs/parsers/universal.md && echo "+++ universal parser docs complete" || echo "*** UNIVERSAL PARSER DOCS FAILED" ) & # a bit of inception here... jc is being used to help @@ -119,27 +46,8 @@ for parser in "${parsers[@]}"; do parser_name=$(jq -r '.name' <<< "$parser") { if [[ $1 == "all" ]] || ! git diff --quiet --exit-code HEAD~5 -- "parsers/${parser_name}.py"; then - compatible=$(jq -r '.compatible | join(", ")' <<< "$parser") - version=$(jq -r '.version' <<< "$parser") - author=$(jq -r '.author' <<< "$parser") - author_email=$(jq -r '.author_email' <<< "$parser") - echo "Building docs for: ${parser_name}" - echo "[Home](https://kellyjonbrazil.github.io/jc/)" > ../docs/parsers/"${parser_name}".md - pydoc-markdown -m jc.parsers."${parser_name}" "${parser_config}" >> ../docs/parsers/"${parser_name}".md - echo "### Parser Information" >> ../docs/parsers/"${parser_name}".md - echo "Compatibility: ${compatible}" >> ../docs/parsers/"${parser_name}".md - echo >> ../docs/parsers/"${parser_name}".md - echo "Source: [\`jc/parsers/${parser_name}.py\`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/${parser_name}.py)" >> ../docs/parsers/"${parser_name}".md - echo >> ../docs/parsers/"${parser_name}".md - - if $(jq -e '.tags | contains(["slurpable"])' <<< "$parser"); then - echo "This parser can be used with the \`--slurp\` command-line option." >> ../docs/parsers/"${parser_name}".md - echo >> ../docs/parsers/"${parser_name}".md - fi - - echo "Version ${version} by ${author} (${author_email})" >> ../docs/parsers/"${parser_name}".md - echo "+++ ${parser_name} docs complete" + ../doc2md.py jc.parsers."${parser_name}" > ../docs/parsers/"${parser_name}".md && echo "+++ ${parser_name} docs complete" || echo "*** ${parser_name} DOCS FAILED" fi } & done diff --git a/docs/lib.md b/docs/lib.md index 060a5c8b..935d3519 100644 --- a/docs/lib.md +++ b/docs/lib.md @@ -1,29 +1,67 @@ -# Table of Contents - -* [jc.lib](#jc.lib) - * [get\_parser](#jc.lib.get_parser) - * [parse](#jc.lib.parse) - * [parser\_mod\_list](#jc.lib.parser_mod_list) - * [plugin\_parser\_mod\_list](#jc.lib.plugin_parser_mod_list) - * [standard\_parser\_mod\_list](#jc.lib.standard_parser_mod_list) - * [streaming\_parser\_mod\_list](#jc.lib.streaming_parser_mod_list) - * [slurpable\_parser\_mod\_list](#jc.lib.slurpable_parser_mod_list) - * [parser\_info](#jc.lib.parser_info) - * [all\_parser\_info](#jc.lib.all_parser_info) - * [get\_help](#jc.lib.get_help) - +[Home](https://kellyjonbrazil.github.io/jc/) # jc.lib +# Table of Contents + +*[jc.lib](#jc.lib) + *[all_parser_info](#jc.lib.all_parser_info) + *[get_help](#jc.lib.get_help) + *[get_parser](#jc.lib.get_parser) + *[parse](#jc.lib.parse) + *[parser_info](#jc.lib.parser_info) + *[parser_mod_list](#jc.lib.parser_mod_list) + *[plugin_parser_mod_list](#jc.lib.plugin_parser_mod_list) + *[slurpable_parser_mod_list](#jc.lib.slurpable_parser_mod_list) + *[standard_parser_mod_list](#jc.lib.standard_parser_mod_list) + *[streaming_parser_mod_list](#jc.lib.streaming_parser_mod_list) + jc - JSON Convert lib module + + +### all_parser_info + +```python +def all_parser_info( + documentation: bool = False, + show_hidden: bool = False, + show_deprecated: bool = False) -> List[jc.jc_types.ParserInfoType] +``` + +Returns a list of dictionaries that includes metadata for all parser +modules. By default only non-hidden, non-deprecated parsers are +returned. + +Parameters: + + documentation: (boolean) include parser docstrings if True + show_hidden: (boolean) also show parsers marked as hidden + in their info metadata. + show_deprecated: (boolean) also show parsers marked as + deprecated in their info metadata. + + + +### get_help + +```python +def get_help(parser_mod_name: Union[str, module]) -> None +``` + +Show help screen for the selected parser. + +This function will accept **module_name**, **cli-name**, and +**--argument-name** variants of the module name string as well as a +parser module object. + -### get\_parser +### get_parser ```python -def get_parser(parser_mod_name: Union[str, ModuleType]) -> ModuleType +def get_parser(parser_mod_name: Union[str, module]) -> module ``` Return the parser module object and check that the module is a valid @@ -56,13 +94,13 @@ Raises: ```python def parse( - parser_mod_name: Union[str, ModuleType], + parser_mod_name: Union[str, module], data: Union[str, bytes, Iterable[str]], quiet: bool = False, raw: bool = False, ignore_exceptions: Optional[bool] = None, **kwargs -) -> Union[JSONDictType, List[JSONDictType], Iterator[JSONDictType]] +) -> Union[Dict[str, Any], List[Dict[str, Any]], Iterator[Dict[str, Any]]] ``` Parse the data (string or bytes) using the supplied parser (string or @@ -152,73 +190,13 @@ Returns: Standard Parsers: Dictionary or List of Dictionaries Streaming Parsers: Generator Object containing Dictionaries - - -### parser\_mod\_list - -```python -def parser_mod_list(show_hidden: bool = False, - show_deprecated: bool = False) -> List[str] -``` - -Returns a list of all available parser module names. - - - -### plugin\_parser\_mod\_list - -```python -def plugin_parser_mod_list(show_hidden: bool = False, - show_deprecated: bool = False) -> List[str] -``` - -Returns a list of plugin parser module names. This function is a -subset of `parser_mod_list()`. - - - -### standard\_parser\_mod\_list - -```python -def standard_parser_mod_list(show_hidden: bool = False, - show_deprecated: bool = False) -> List[str] -``` - -Returns a list of standard parser module names. This function is a -subset of `parser_mod_list()` and does not contain any streaming -parsers. - - - -### streaming\_parser\_mod\_list - -```python -def streaming_parser_mod_list(show_hidden: bool = False, - show_deprecated: bool = False) -> List[str] -``` - -Returns a list of streaming parser module names. This function is a -subset of `parser_mod_list()`. - - - -### slurpable\_parser\_mod\_list - -```python -def slurpable_parser_mod_list(show_hidden: bool = False, - show_deprecated: bool = False) -> List[str] -``` - -Returns a list of slurpable parser module names. This function is a -subset of `parser_mod_list()`. - -### parser\_info +### parser_info ```python -def parser_info(parser_mod_name: Union[str, ModuleType], - documentation: bool = False) -> ParserInfoType +def parser_info(parser_mod_name: Union[str, module], + documentation: bool = False) -> jc.jc_types.ParserInfoType ``` Returns a dictionary that includes the parser module metadata. @@ -233,39 +211,64 @@ Parameters: documentation: (boolean) include parser docstring if True - + -### all\_parser\_info +### parser_mod_list ```python -def all_parser_info(documentation: bool = False, - show_hidden: bool = False, - show_deprecated: bool = False) -> List[ParserInfoType] +def parser_mod_list(show_hidden: bool = False, + show_deprecated: bool = False) -> List[str] ``` -Returns a list of dictionaries that includes metadata for all parser -modules. By default only non-hidden, non-deprecated parsers are -returned. +Returns a list of all available parser module names. -Parameters: + - documentation: (boolean) include parser docstrings if True - show_hidden: (boolean) also show parsers marked as hidden - in their info metadata. - show_deprecated: (boolean) also show parsers marked as - deprecated in their info metadata. - - - -### get\_help +### plugin_parser_mod_list ```python -def get_help(parser_mod_name: Union[str, ModuleType]) -> None +def plugin_parser_mod_list(show_hidden: bool = False, + show_deprecated: bool = False) -> List[str] ``` -Show help screen for the selected parser. +Returns a list of plugin parser module names. This function is a +subset of `parser_mod_list()`. + + + +### slurpable_parser_mod_list + +```python +def slurpable_parser_mod_list(show_hidden: bool = False, + show_deprecated: bool = False) -> List[str] +``` + +Returns a list of slurpable parser module names. This function is a +subset of `parser_mod_list()`. + + + +### standard_parser_mod_list + +```python +def standard_parser_mod_list(show_hidden: bool = False, + show_deprecated: bool = False) -> List[str] +``` + +Returns a list of standard parser module names. This function is a +subset of `parser_mod_list()` and does not contain any streaming +parsers. + + + +### streaming_parser_mod_list + +```python +def streaming_parser_mod_list(show_hidden: bool = False, + show_deprecated: bool = False) -> List[str] +``` + +Returns a list of streaming parser module names. This function is a +subset of `parser_mod_list()`. -This function will accept **module_name**, **cli-name**, and -**--argument-name** variants of the module name string as well as a -parser module object. diff --git a/docs/parsers/apt_get_sqq.md b/docs/parsers/apt_get_sqq.md index 8c57918c..89916a17 100644 --- a/docs/parsers/apt_get_sqq.md +++ b/docs/parsers/apt_get_sqq.md @@ -1,7 +1,7 @@ [Home](https://kellyjonbrazil.github.io/jc/) -# jc.parsers.apt\_get\_sqq +# jc.parsers.apt_get_sqq jc - JSON Convert `apt-get -sqq` command output parser @@ -28,7 +28,7 @@ Schema: "package": string, "broken": string/null, "proposed_pkg_ver": string, - "existing_src": string/null, + "existing_pkg_ver": string/null, "architecture": string } ] @@ -42,7 +42,7 @@ Examples: "package": "dpkg", "broken": "1.19.7", "proposed_pkg_ver": "1.19.8 Debian:10.13/oldstable", - "existing_src": "Debian-Security:10/oldstable", + "existing_pkg_ver": "Debian-Security:10/oldstable", "architecture": "amd64" }, { @@ -50,7 +50,7 @@ Examples: "package": "dpkg", "broken": null, "proposed_pkg_ver": "1.19.8 Debian:10.13/oldstable", - "existing_src": "Debian-Security:10/oldstable", + "existing_pkg_ver": "Debian-Security:10/oldstable", "architecture": "amd64" }, { @@ -58,7 +58,7 @@ Examples: "package": "dpkg", "broken": "1.19.7", "proposed_pkg_ver": "1.19.8 Debian:10.13/oldstable", - "existing_src": "Debian-Security:10/oldstable", + "existing_pkg_ver": "Debian-Security:10/oldstable", "architecture": "amd64" }, { @@ -66,7 +66,7 @@ Examples: "package": "dpkg", "broken": "1.19.7", "proposed_pkg_ver": "1.19.8 Debian:10.13/oldstable", - "existing_src": "Debian-Security:10/oldstable", + "existing_pkg_ver": "Debian-Security:10/oldstable", "architecture": "amd64" }, { @@ -74,7 +74,7 @@ Examples: "package": "base-files", "broken": "10.3+deb10u4", "proposed_pkg_ver": "10.3+deb10u13 Debian:10.13/oldstable", - "existing_src": null, + "existing_pkg_ver": null, "architecture": "amd64" }, { @@ -82,7 +82,7 @@ Examples: "package": "base-files", "broken": null, "proposed_pkg_ver": "10.3+deb10u13 Debian:10.13/oldstable", - "existing_src": null, + "existing_pkg_ver": null, "architecture": "amd64" }, { @@ -90,7 +90,7 @@ Examples: "package": "dpkg", "broken": "1.19.7", "proposed_pkg_ver": "1.19.8 Debian:10.13/oldstable", - "existing_src": "Debian-Security:10/oldstable", + "existing_pkg_ver": "Debian-Security:10/oldstable", "architecture": "amd64" }, { @@ -98,7 +98,7 @@ Examples: "package": "dpkg", "broken": null, "proposed_pkg_ver": "1.19.8 Debian:10.13/oldstable", - "existing_src": "Debian-Security:10/oldstable", + "existing_pkg_ver": "Debian-Security:10/oldstable", "architecture": "amd64" } ] @@ -110,7 +110,7 @@ Examples: "package": "dpkg", "broken": "1.19.7", "proposed_pkg_ver": "1.19.8 Debian:10.13/oldstable", - "existing_src": "Debian-Security:10/oldstable", + "existing_pkg_ver": "Debian-Security:10/oldstable", "architecture": "amd64" }, { @@ -118,7 +118,7 @@ Examples: "package": "dpkg", "broken": null, "proposed_pkg_ver": "1.19.8 Debian:10.13/oldstable", - "existing_src": "Debian-Security:10/oldstable", + "existing_pkg_ver": "Debian-Security:10/oldstable", "architecture": "amd64" }, { @@ -126,7 +126,7 @@ Examples: "package": "dpkg", "broken": "1.19.7", "proposed_pkg_ver": "1.19.8 Debian:10.13/oldstable", - "existing_src": "Debian-Security:10/oldstable", + "existing_pkg_ver": "Debian-Security:10/oldstable", "architecture": "amd64" }, { @@ -134,7 +134,7 @@ Examples: "package": "dpkg", "broken": "1.19.7", "proposed_pkg_ver": "1.19.8 Debian:10.13/oldstable", - "existing_src": "Debian-Security:10/oldstable", + "existing_pkg_ver": "Debian-Security:10/oldstable", "architecture": "amd64" }, { @@ -142,7 +142,7 @@ Examples: "package": "base-files", "broken": "10.3+deb10u4", "proposed_pkg_ver": "10.3+deb10u13 Debian:10.13/oldstable", - "existing_src": null, + "existing_pkg_ver": null, "architecture": "amd64" }, { @@ -150,7 +150,7 @@ Examples: "package": "base-files", "broken": null, "proposed_pkg_ver": "10.3+deb10u13 Debian:10.13/oldstable", - "existing_src": null, + "existing_pkg_ver": null, "architecture": "amd64" }, { @@ -158,7 +158,7 @@ Examples: "package": "dpkg", "broken": "1.19.7", "proposed_pkg_ver": "1.19.8 Debian:10.13/oldstable", - "existing_src": "Debian-Security:10/oldstable", + "existing_pkg_ver": "Debian-Security:10/oldstable", "architecture": "amd64" }, { @@ -166,11 +166,12 @@ Examples: "package": "dpkg", "broken": null, "proposed_pkg_ver": "1.19.8 Debian:10.13/oldstable", - "existing_src": "Debian-Security:10/oldstable", + "existing_pkg_ver": "Debian-Security:10/oldstable", "architecture": "amd64" } ] + ### parse @@ -178,7 +179,7 @@ Examples: ```python def parse(data: str, raw: bool = False, - quiet: bool = False) -> List[JSONDictType] + quiet: bool = False) -> List[Dict[str, Any]] ``` Main text parsing function @@ -193,9 +194,11 @@ Returns: List of Dictionaries. Raw or processed structured data. + ### Parser Information -Compatibility: linux +Compatibility: linux Source: [`jc/parsers/apt_get_sqq.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/apt_get_sqq.py) Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) + diff --git a/docs/parsers/dir.md b/docs/parsers/dir.md index 7e8dda09..80ad5d20 100644 --- a/docs/parsers/dir.md +++ b/docs/parsers/dir.md @@ -120,6 +120,7 @@ Examples: ... ] + ### parse @@ -140,9 +141,11 @@ Returns: List of Dictionaries. Raw or processed structured data. + ### Parser Information -Compatibility: win32 +Compatibility: win32 Source: [`jc/parsers/dir.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/dir.py) Version 1.6 by Rasheed Elsaleh (rasheed@rebelliondefense.com) + diff --git a/docs/parsers/ethtool.md b/docs/parsers/ethtool.md index 711f95b5..f23f42db 100644 --- a/docs/parsers/ethtool.md +++ b/docs/parsers/ethtool.md @@ -166,12 +166,13 @@ Examples: "br_margin_min": "0%" } + ### parse ```python -def parse(data: str, raw: bool = False, quiet: bool = False) -> JSONDictType +def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict[str, Any] ``` Main text parsing function @@ -186,9 +187,11 @@ Returns: List of Dictionaries. Raw or processed structured data. + ### Parser Information -Compatibility: linux +Compatibility: linux Source: [`jc/parsers/ethtool.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/ethtool.py) Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) + diff --git a/docs/parsers/universal.md b/docs/parsers/universal.md index ab8b1266..d532eed2 100644 --- a/docs/parsers/universal.md +++ b/docs/parsers/universal.md @@ -1,18 +1,19 @@ -# Table of Contents - -* [jc.parsers.universal](#jc.parsers.universal) - * [simple\_table\_parse](#jc.parsers.universal.simple_table_parse) - * [sparse\_table\_parse](#jc.parsers.universal.sparse_table_parse) - +[Home](https://kellyjonbrazil.github.io/jc/) # jc.parsers.universal +# Table of Contents + +*[jc.parsers.universal](#jc.parsers.universal) + *[simple_table_parse](#jc.parsers.universal.simple_table_parse) + *[sparse_table_parse](#jc.parsers.universal.sparse_table_parse) + jc - JSON Convert universal parsers -### simple\_table\_parse +### simple_table_parse ```python def simple_table_parse(data: Iterable[str]) -> List[Dict] @@ -50,7 +51,7 @@ Returns: -### sparse\_table\_parse +### sparse_table_parse ```python def sparse_table_parse(data: Iterable[str], @@ -86,7 +87,7 @@ Parameters: Also, ensure there are no blank line items. - delim: (string) Delimiter to use. By default `u\\2063` + delim: (string) Delimiter to use. By default `u\2063` (invisible separator) is used since it is unlikely to ever be seen in terminal output. You can change this for troubleshooting purposes or if there is a @@ -96,3 +97,4 @@ Returns: List of Dictionaries + diff --git a/docs/parsers/ver.md b/docs/parsers/ver.md index b1948934..82c911f8 100644 --- a/docs/parsers/ver.md +++ b/docs/parsers/ver.md @@ -86,12 +86,13 @@ Examples: "strict": false } + ### parse ```python -def parse(data: str, raw: bool = False, quiet: bool = False) -> JSONDictType +def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict[str, Any] ``` Main text parsing function @@ -106,11 +107,13 @@ Returns: List of Dictionaries. Raw or processed structured data. + ### Parser Information -Compatibility: linux, darwin, cygwin, win32, aix, freebsd +Compatibility: linux, darwin, cygwin, win32, aix, freebsd Source: [`jc/parsers/ver.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/ver.py) This parser can be used with the `--slurp` command-line option. -Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com) +Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com) + diff --git a/docs/readme.md b/docs/readme.md index 488c3d00..8ae72436 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -1,3 +1,4 @@ +[Home](https://kellyjonbrazil.github.io/jc/) # jc diff --git a/docs/streaming.md b/docs/streaming.md index 3b593a96..cb1f3526 100644 --- a/docs/streaming.md +++ b/docs/streaming.md @@ -1,67 +1,26 @@ -# Table of Contents - -* [jc.streaming](#jc.streaming) - * [streaming\_input\_type\_check](#jc.streaming.streaming_input_type_check) - * [streaming\_line\_input\_type\_check](#jc.streaming.streaming_line_input_type_check) - * [stream\_success](#jc.streaming.stream_success) - * [stream\_error](#jc.streaming.stream_error) - * [add\_jc\_meta](#jc.streaming.add_jc_meta) - * [raise\_or\_yield](#jc.streaming.raise_or_yield) - +[Home](https://kellyjonbrazil.github.io/jc/) # jc.streaming +# Table of Contents + +*[jc.streaming](#jc.streaming) + *[add_jc_meta](#jc.streaming.add_jc_meta) + *[raise_or_yield](#jc.streaming.raise_or_yield) + *[stream_error](#jc.streaming.stream_error) + *[stream_success](#jc.streaming.stream_success) + *[streaming_input_type_check](#jc.streaming.streaming_input_type_check) + *[streaming_line_input_type_check](#jc.streaming.streaming_line_input_type_check) + jc - JSON Convert streaming utils - - -### streaming\_input\_type\_check - -```python -def streaming_input_type_check(data: Iterable[Union[str, bytes]]) -> None -``` - -Ensure input data is an iterable, but not a string or bytes. Raises -`TypeError` if not. - - - -### streaming\_line\_input\_type\_check - -```python -def streaming_line_input_type_check(line: str) -> None -``` - -Ensure each line is a string. Raises `TypeError` if not. - - - -### stream\_success - -```python -def stream_success(output_line: JSONDictType, - ignore_exceptions: bool) -> JSONDictType -``` - -Add `_jc_meta` object to output line if `ignore_exceptions=True` - - - -### stream\_error - -```python -def stream_error(e: BaseException, line: str) -> JSONDictType -``` - -Return an error `_jc_meta` field. - -### add\_jc\_meta +### add_jc_meta ```python -def add_jc_meta(func: F) -> F +def add_jc_meta(func: ~F) -> ~F ``` Decorator for streaming parsers to add stream_success and stream_error @@ -103,7 +62,7 @@ In all cases above: -### raise\_or\_yield +### raise_or_yield ```python def raise_or_yield(ignore_exceptions: bool, e: BaseException, @@ -114,3 +73,46 @@ Return the exception object and line string if ignore_exceptions is True. Otherwise, re-raise the exception from the exception object with an annotation. + + +### stream_error + +```python +def stream_error(e: BaseException, line: str) -> Dict[str, Any] +``` + +Return an error `_jc_meta` field. + + + +### stream_success + +```python +def stream_success(output_line: Dict[str, Any], + ignore_exceptions: bool) -> Dict[str, Any] +``` + +Add `_jc_meta` object to output line if `ignore_exceptions=True` + + + +### streaming_input_type_check + +```python +def streaming_input_type_check(data: Iterable[Union[str, bytes]]) -> None +``` + +Ensure input data is an iterable, but not a string or bytes. Raises +`TypeError` if not. + + + +### streaming_line_input_type_check + +```python +def streaming_line_input_type_check(line: str) -> None +``` + +Ensure each line is a string. Raises `TypeError` if not. + + diff --git a/docs/utils.md b/docs/utils.md index 30899517..5465d57b 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -1,78 +1,27 @@ -# Table of Contents - -* [jc.utils](#jc.utils) - * [warning\_message](#jc.utils.warning_message) - * [error\_message](#jc.utils.error_message) - * [is\_compatible](#jc.utils.is_compatible) - * [compatibility](#jc.utils.compatibility) - * [has\_data](#jc.utils.has_data) - * [remove\_quotes](#jc.utils.remove_quotes) - * [normalize\_key](#jc.utils.normalize_key) - * [convert\_to\_int](#jc.utils.convert_to_int) - * [convert\_to\_float](#jc.utils.convert_to_float) - * [convert\_to\_bool](#jc.utils.convert_to_bool) - * [convert\_size\_to\_int](#jc.utils.convert_size_to_int) - * [input\_type\_check](#jc.utils.input_type_check) - * [line\_slice](#jc.utils.line_slice) - * [timestamp](#jc.utils.timestamp) - * [\_\_init\_\_](#jc.utils.timestamp.__init__) - +[Home](https://kellyjonbrazil.github.io/jc/) # jc.utils +# Table of Contents + +*[jc.utils](#jc.utils) + *[compatibility](#jc.utils.compatibility) + *[convert_size_to_int](#jc.utils.convert_size_to_int) + *[convert_to_bool](#jc.utils.convert_to_bool) + *[convert_to_float](#jc.utils.convert_to_float) + *[convert_to_int](#jc.utils.convert_to_int) + *[error_message](#jc.utils.error_message) + *[has_data](#jc.utils.has_data) + *[input_type_check](#jc.utils.input_type_check) + *[is_compatible](#jc.utils.is_compatible) + *[line_slice](#jc.utils.line_slice) + *[normalize_key](#jc.utils.normalize_key) + *[remove_quotes](#jc.utils.remove_quotes) + *[warning_message](#jc.utils.warning_message) + jc - JSON Convert utils - - -### warning\_message - -```python -def warning_message(message_lines: List[str]) -> None -``` - -Prints warning message to `STDERR` for non-fatal issues. The first line -is prepended with 'jc: Warning - ' and subsequent lines are indented. -Wraps text as needed based on the terminal width. - -Parameters: - - message: (list) list of string lines - -Returns: - - None - just prints output to STDERR - - - -### error\_message - -```python -def error_message(message_lines: List[str]) -> None -``` - -Prints an error message to `STDERR` for fatal issues. The first line is -prepended with 'jc: Error - ' and subsequent lines are indented. -Wraps text as needed based on the terminal width. - -Parameters: - - message: (list) list of string lines - -Returns: - - None - just prints output to STDERR - - - -### is\_compatible - -```python -def is_compatible(compatible: List[str]) -> bool -``` - -Returns True if the parser is compatible with the running OS platform. - ### compatibility @@ -101,135 +50,9 @@ Returns: None - just prints output to STDERR - - -### has\_data - -```python -def has_data(data: Union[str, bytes]) -> bool -``` - -Checks if the string input contains data. If there are any -non-whitespace characters then return `True`, else return `False`. - -For bytes, returns True if there is any data. - -Parameters: - - data: (string, bytes) input to check whether it contains data - -Returns: - - Boolean True if input string (data) contains non-whitespace - characters, otherwise False. For bytes data, returns - True if there is any data, otherwise False. - - - -### remove\_quotes - -```python -def remove_quotes(data: str) -> str -``` - -Remove single or double quotes surrounding a string. If no quotes are -found then the string is returned unmodified. - -Parameters: - - data: (string) Input value - -Returns: - - string - - - -### normalize\_key - -```python -def normalize_key(data: str) -> str -``` - -Normalize a key name by shifting to lower-case and converting special -characters to underscores. - -Special characters are defined as `space` and the following: - - !"#$%&'()*+,-./:;<=>?@[\]^`{|}~ - -This is a lossy algorithm. Repeating and trailing underscores are -removed. - -Parameters: - - data: (string) Input value - -Returns: - - string - - - -### convert\_to\_int - -```python -def convert_to_int(value: object) -> Optional[int] -``` - -Converts string and float input to int. Strips all non-numeric -characters from strings. - -Parameters: - - value: (string/float) Input value - -Returns: - - integer/None Integer if successful conversion, otherwise None - - - -### convert\_to\_float - -```python -def convert_to_float(value: object) -> Optional[float] -``` - -Converts string and int input to float. Strips all non-numeric -characters from strings. - -Parameters: - - value: (string/integer) Input value - -Returns: - - float/None Float if successful conversion, otherwise None - - - -### convert\_to\_bool - -```python -def convert_to_bool(value: object) -> bool -``` - -Converts string, integer, or float input to boolean by checking -for 'truthy' values. - -Parameters: - - value: (string/integer/float) Input value - -Returns: - - True/False False unless a 'truthy' number or string is found - ('y', 'yes', 'true', '1', 1, -1, etc.) - -### convert\_size\_to\_int +### convert_size_to_int ```python def convert_size_to_int(size: str, binary: bool = False) -> Optional[int] @@ -269,9 +92,110 @@ gigabytes, terabytes and petabytes. Some examples: >>> convert_size_to_int('1.5 GB', binary=True) 1610612736 + + +### convert_to_bool + +```python +def convert_to_bool(value: object) -> bool +``` + +Converts string, integer, or float input to boolean by checking +for 'truthy' values. + +Parameters: + + value: (string/integer/float) Input value + +Returns: + + True/False False unless a 'truthy' number or string is found + ('y', 'yes', 'true', '1', 1, -1, etc.) + + + +### convert_to_float + +```python +def convert_to_float(value: object) -> Optional[float] +``` + +Converts string and int input to float. Strips all non-numeric +characters from strings. + +Parameters: + + value: (string/integer) Input value + +Returns: + + float/None Float if successful conversion, otherwise None + + + +### convert_to_int + +```python +def convert_to_int(value: object) -> Optional[int] +``` + +Converts string and float input to int. Strips all non-numeric +characters from strings. + +Parameters: + + value: (string/float) Input value + +Returns: + + integer/None Integer if successful conversion, otherwise None + + + +### error_message + +```python +def error_message(message_lines: List[str]) -> None +``` + +Prints an error message to `STDERR` for fatal issues. The first line is +prepended with 'jc: Error - ' and subsequent lines are indented. +Wraps text as needed based on the terminal width. + +Parameters: + + message: (list) list of string lines + +Returns: + + None - just prints output to STDERR + + + +### has_data + +```python +def has_data(data: Union[str, bytes]) -> bool +``` + +Checks if the string input contains data. If there are any +non-whitespace characters then return `True`, else return `False`. + +For bytes, returns True if there is any data. + +Parameters: + + data: (string, bytes) input to check whether it contains data + +Returns: + + Boolean True if input string (data) contains non-whitespace + characters, otherwise False. For bytes data, returns + True if there is any data, otherwise False. + -### input\_type\_check +### input_type_check ```python def input_type_check(data: object) -> None @@ -279,16 +203,26 @@ def input_type_check(data: object) -> None Ensure input data is a string. Raises `TypeError` if not. + + +### is_compatible + +```python +def is_compatible(compatible: List[str]) -> bool +``` + +Returns True if the parser is compatible with the running OS platform. + -### line\_slice +### line_slice ```python def line_slice( - data: Union[str, Iterable[str], TextIO, bytes, None], + data: Union[str, Iterable[str], TextIO, bytes, NoneType], slice_start: Optional[int] = None, slice_end: Optional[int] = None -) -> Union[str, Iterable[str], TextIO, bytes, None] +) -> Union[str, Iterable[str], TextIO, bytes, NoneType] ``` Slice input data by lines - lazily, if possible. @@ -310,51 +244,69 @@ Returns: string if input is a string. iterable of strings if input is an iterable (for streaming parsers) - + -### timestamp Objects +### normalize_key ```python -class timestamp() +def normalize_key(data: str) -> str ``` - +Normalize a key name by shifting to lower-case and converting special +characters to underscores. -### \_\_init\_\_ +Special characters are defined as `space` and the following: -```python -def __init__(datetime_string: Optional[str], - format_hint: Optional[Iterable[int]] = None) -> None -``` + !"#$%&'()*+,-./:;<=>?@[\]^`{|}~ -Input a datetime text string of several formats and convert to a -naive or timezone-aware epoch timestamp in UTC. +This is a lossy algorithm. Repeating and trailing underscores are +removed. Parameters: - datetime_string (str): a string representation of a - datetime in several supported formats + data: (string) Input value - format_hint (iterable): an optional iterable of format ID - integers to instruct the timestamp object to try those - formats first in the order given. Other formats will be - tried after the format hint list is exhausted. This can - speed up timestamp conversion so several different formats - don't have to be tried in brute-force fashion. +Returns: -Returns a timestamp object with the following attributes: + string - string (str): the input datetime string + - format (int | None): the format rule that was used to decode - the datetime string. None if conversion fails. +### remove_quotes - naive (int | None): timestamp based on locally configured - timezone. None if conversion fails. +```python +def remove_quotes(data: str) -> str +``` - utc (int | None): aware timestamp only if UTC timezone - detected in datetime string. None if conversion fails. +Remove single or double quotes surrounding a string. If no quotes are +found then the string is returned unmodified. + +Parameters: + + data: (string) Input value + +Returns: + + string + + + +### warning_message + +```python +def warning_message(message_lines: List[str]) -> None +``` + +Prints warning message to `STDERR` for non-fatal issues. The first line +is prepended with 'jc: Warning - ' and subsequent lines are indented. +Wraps text as needed based on the terminal width. + +Parameters: + + message: (list) list of string lines + +Returns: + + None - just prints output to STDERR - iso (str | None): ISO string - timezone information is output - only if UTC timezone is detected in the datetime string. diff --git a/jc/parsers/ver.py b/jc/parsers/ver.py index a34d764f..8a5b35fe 100644 --- a/jc/parsers/ver.py +++ b/jc/parsers/ver.py @@ -89,7 +89,7 @@ import jc.utils class info(): """Provides parser metadata (version, author, etc.)""" - version = '1.1' + version = '1.2' description = 'Version string parser' author = 'Kelly Brazil' author_email = 'kellyjonbrazil@gmail.com' @@ -132,7 +132,7 @@ def _process(proc_data: JSONDictType) -> JSONDictType: return proc_data -def strict_parse(vstring): +def _strict_parse(vstring): version_re = re.compile(r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$', re.VERBOSE) match = version_re.match(vstring) if not match: @@ -158,7 +158,7 @@ def strict_parse(vstring): } -def loose_parse(vstring): +def _loose_parse(vstring): component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE) components = [x for x in component_re.split(vstring) if x and x != '.'] @@ -197,10 +197,10 @@ def parse( data = data.strip() try: - raw_output = strict_parse(data) + raw_output = _strict_parse(data) except ValueError: - raw_output['components'] = loose_parse(data) + raw_output['components'] = _loose_parse(data) strict = False if raw_output: diff --git a/man/jc.1 b/man/jc.1 index 8ee8b80a..17492eed 100644 --- a/man/jc.1 +++ b/man/jc.1 @@ -1,4 +1,4 @@ -.TH jc 1 2024-03-01 1.25.2 "JSON Convert" +.TH jc 1 2024-03-14 1.25.2 "JSON Convert" .SH NAME \fBjc\fP \- JSON Convert JSONifies the output of many CLI tools, file-types, and strings