diff --git a/jc/__init__.py b/jc/__init__.py index 0579852b..4e8baa4b 100644 --- a/jc/__init__.py +++ b/jc/__init__.py @@ -69,5 +69,5 @@ Use `help(jc.lib)` for details: Get a list of plugin parser module names. This list is a subset of parser_mod_list(). """ -from .lib import (__version__, parse, parser_mod_list, - plugin_parser_mod_list, get_help) +from .lib import (__version__, parse, parser_mod_list, plugin_parser_mod_list, + parser_info, all_parser_info, get_help) diff --git a/jc/cli.py b/jc/cli.py index 9798f7a8..ea82b0f4 100644 --- a/jc/cli.py +++ b/jc/cli.py @@ -10,7 +10,8 @@ import signal import shlex import subprocess import json -from .lib import __version__, parsers, local_parsers +from .lib import (__version__, parser_info, parsers, local_parsers, + _parser_argument, _get_parser) from . import utils from . import tracebackplus from .exceptions import LibraryNotInstalled, ParseError @@ -147,29 +148,12 @@ def parser_shortname(parser_arg): return parser_arg[2:] -def parser_argument(parser): - """Return short name of the parser with dashes and with -- prefix""" - return f'--{parser}' - - -def parser_mod_shortname(parser): - """Return short name of the parser's module name (no -- prefix and dashes converted to underscores)""" - return parser.replace('--', '').replace('-', '_') - - -def parser_module(parser): - """Import the module just in time and return the module object""" - shortname = parser_mod_shortname(parser) - path = ('jcparsers.' if shortname in local_parsers else 'jc.parsers.') - return importlib.import_module(path + shortname) - - def parsers_text(indent=0, pad=0): """Return the argument and description information from each parser""" ptext = '' for parser in parsers: - parser_arg = parser_argument(parser) - parser_mod = parser_module(parser) + parser_arg = _parser_argument(parser) + parser_mod = _get_parser(parser) if hasattr(parser_mod, 'info'): parser_desc = parser_mod.info.description @@ -184,22 +168,7 @@ def parsers_text(indent=0, pad=0): def about_jc(): """Return jc info and the contents of each parser.info as a dictionary""" - parser_list = [] - - for parser in parsers: - parser_mod = parser_module(parser) - - if hasattr(parser_mod, 'info'): - info_dict = {} - info_dict['name'] = parser_mod.__name__.split('.')[-1] - info_dict['argument'] = parser_argument(parser) - parser_entry = vars(parser_mod.info) - - for k, v in parser_entry.items(): - if not k.startswith('__'): - info_dict[k] = v - - parser_list.append(info_dict) + parser_list = [parser_info(p) for p in parsers] return { 'name': 'jc', @@ -264,8 +233,7 @@ def help_doc(options): parser_name = parser_shortname(arg) if parser_name in parsers: - # load parser module just in time so we don't need to load all modules - parser = parser_module(arg) + parser = _get_parser(arg) compatible = ', '.join(parser.info.compatible) doc_text = \ f'{parser.__doc__}\n'\ @@ -491,7 +459,7 @@ def main(): # find the correct parser if magic_found_parser: - parser = parser_module(magic_found_parser) + parser = _get_parser(magic_found_parser) parser_name = parser_shortname(magic_found_parser) else: @@ -500,7 +468,7 @@ def main(): parser_name = parser_shortname(arg) if parser_name in parsers: - parser = parser_module(arg) + parser = _get_parser(arg) found = True break diff --git a/jc/lib.py b/jc/lib.py index 917a80b2..1d1fb3a0 100644 --- a/jc/lib.py +++ b/jc/lib.py @@ -98,6 +98,14 @@ parsers = [ 'zipinfo' ] +def _cliname_to_modname(parser_cli_name): + """Return real module name (dashes converted to underscores)""" + return parser_cli_name.replace('--', '').replace('-', '_') + +def _modname_to_cliname(parser_mod_name): + """Return module's cli name (underscores converted to dashes)""" + return parser_mod_name.replace('_', '-') + # Create the local_parsers list. This is a list of custom or # override parsers from /jc/jcparsers/*.py. # Once this list is created, extend the parsers list with it. @@ -109,25 +117,24 @@ if os.path.isdir(local_parsers_dir): for name in os.listdir(local_parsers_dir): if re.match(r'\w+\.py$', name) and os.path.isfile(os.path.join(local_parsers_dir, name)): plugin_name = name[0:-3] - local_parsers.append(plugin_name) + local_parsers.append(_modname_to_cliname(plugin_name)) if plugin_name not in parsers: - parsers.append(plugin_name) + parsers.append(_modname_to_cliname(plugin_name)) try: del name except Exception: pass - -def _cliname_to_modname(parser_cli_name): - """Return real module name (dashes converted to underscores)""" - return parser_cli_name.replace('-', '_') - -def _modname_to_cliname(parser_mod_name): - """Return module's cli name (underscores converted to dashes)""" - return parser_mod_name.replace('_', '-') +def _parser_argument(parser_mod_name): + """Return short name of the parser with dashes and with -- prefix""" + parser = _modname_to_cliname(parser_mod_name) + return f'--{parser}' def _get_parser(parser_mod_name): """Return the parser module object""" + # ensure parser_mod_name is a true module name and not a cli name + parser_mod_name = _cliname_to_modname(parser_mod_name) + parser_cli_name = _modname_to_cliname(parser_mod_name) modpath = 'jcparsers.' if parser_cli_name in local_parsers else 'jc.parsers.' return importlib.import_module(f'{modpath}{parser_mod_name}') @@ -170,7 +177,10 @@ def parse(parser_mod_name, data, Parameters: - parser_mod_name: (string) name of the parser module + parser_mod_name: (string) name of the parser module. This + function will accept module_name, + cli-name, and --argument-name + variants of the module name. data: (string or data to parse (string for normal iterator) parsers, iterator of strings for @@ -207,6 +217,38 @@ def plugin_parser_mod_list(): """ return [_cliname_to_modname(p) for p in local_parsers] +def parser_info(parser_mod_name): + """ + Returns a dictionary that includes the module metadata. + + This function will accept module_name, cli-name, and --argument-name + variants of the module name string. + """ + # ensure parser_mod_name is a true module name and not a cli name + parser_mod_name = _cliname_to_modname(parser_mod_name) + + parser_mod = _get_parser(parser_mod_name) + + if hasattr(parser_mod, 'info'): + info_dict = {} + info_dict['name'] = parser_mod_name + info_dict['argument'] = _parser_argument(parser_mod_name) + parser_entry = vars(parser_mod.info) + + for k, v in parser_entry.items(): + if not k.startswith('__'): + info_dict[k] = v + + return info_dict + +def all_parser_info(): + return [parser_info(_cliname_to_modname(p)) for p in parsers] + def get_help(parser_mod_name): - """Show help screen for the selected parser.""" + """ + Show help screen for the selected parser. + + This function will accept module_name, cli-name, and --argument-name + variants of the module name string. + """ help(_get_parser(parser_mod_name))