From 16bc7b1b1e82bcd25e51e99300b61f797f6579c0 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 10 Jun 2021 17:47:50 -0700 Subject: [PATCH 01/68] clean up exception messages --- jello/cli.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index 9e10eea..7034064 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -488,6 +488,7 @@ def main(data=None, query='_'): if data and not data.isspace(): # load the JSON or JSON Lines + list_dict_data = None try: list_dict_data = load_json(data) except Exception as e: @@ -498,6 +499,7 @@ def main(data=None, query='_'): print_error(f'''jello: {msg}''') # run the query and check for various errors + response = '' try: response = pyquery(list_dict_data, query) @@ -536,22 +538,23 @@ def main(data=None, query='_'): jello: {msg} ''')) - except Exception as e: + except Exception as e: + query = query.replace('\n', '; ') + if len(str(list_dict_data)) > 70: err_data = str(list_dict_data)[0:35] + ' ... ' + str(list_dict_data)[-35:-1] - + if len(str(query)) > 70: query = str(query)[0:35] + ' ... ' + str(query)[-35:-1] - + if len(str(response)) > 70: response = str(response)[0:35] + ' ... ' + str(response)[-35:-1] - msg = textwrap.dedent(f'''Query Exception: {e} - query: {query} - data: {err_data} - output: {response}''') print_error(textwrap.dedent(f'''\ - jello: {msg} + jello: Query Exception: {e} + query: {query} + data: {err_data} + response: {response} ''')) # if DotMap returns a bound function then we know it was a reserved attribute name @@ -576,6 +579,7 @@ class JelloStyle(Style): } # output as a schema if the user desires, otherwise generate JSON or Lines + output = '' try: if opts.schema: if not sys.stdout.isatty(): @@ -586,6 +590,8 @@ class JelloStyle(Style): else: output = create_json(response) except Exception as e: + query = query.replace('\n', '; ') + if len(str(list_dict_data)) > 70: list_dict_data = str(list_dict_data)[0:35] + ' ... ' + str(list_dict_data)[-35:-1] @@ -612,6 +618,8 @@ class JelloStyle(Style): print(output) except Exception as e: + query = query.replace('\n', '; ') + if len(str(list_dict_data)) > 70: list_dict_data = str(list_dict_data)[0:35] + ' ... ' + str(list_dict_data)[-35:-1] From 300f67690dd205991c4db68643bbb495f42917a1 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 10 Jun 2021 18:02:25 -0700 Subject: [PATCH 02/68] move hasattr __self__ check inside pyquery() and raise a ValueError instead of sys.exit() in main() --- jello/cli.py | 14 +++++--------- tests/test_pyquery.py | 8 ++++++++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index 7034064..5d1c883 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -409,6 +409,10 @@ def pyquery(data, query): elif isinstance(output, DotMap): output = output.toDict() + # if DotMap returns a bound function then we know it was a reserved attribute name + if hasattr(output, '__self__'): + raise ValueError('A reserved key name with dotted notation was used in the query. Please use python bracket dict notation to access this key.') + return output @@ -541,6 +545,7 @@ def main(data=None, query='_'): except Exception as e: query = query.replace('\n', '; ') + err_data = '' if len(str(list_dict_data)) > 70: err_data = str(list_dict_data)[0:35] + ' ... ' + str(list_dict_data)[-35:-1] @@ -557,15 +562,6 @@ def main(data=None, query='_'): response: {response} ''')) - # if DotMap returns a bound function then we know it was a reserved attribute name - if hasattr(response, '__self__'): - print_error(textwrap.dedent(f'''\ - jello: A reserved key name with dotted notation was used in the query. - Please use python bracket dict notation to access this key. - - query: {query} - ''')) - set_env_colors() # create JelloStyle class with user values from set_env_colors() or default values diff --git a/tests/test_pyquery.py b/tests/test_pyquery.py index c282859..116b5f0 100644 --- a/tests/test_pyquery.py +++ b/tests/test_pyquery.py @@ -155,6 +155,14 @@ def test_NameError(self): self.query = 'variable' self.assertRaises(NameError, jello.cli.pyquery, self.data_in, self.query) + def test_ValueError(self): + """ + Test _.get (ValueError) + """ + self.data_in = {"foo": "bar"} + self.query = '_.get' + self.assertRaises(ValueError, jello.cli.pyquery, self.data_in, self.query) + if __name__ == '__main__': unittest.main() From 58426fcd45406f8b6dfbc1ffea9fe7605d2d6dcd Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 10 Jun 2021 18:04:29 -0700 Subject: [PATCH 03/68] version bump --- CHANGELOG | 4 ++++ jello/cli.py | 2 +- setup.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7fc674f..5784b60 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ jello changelog +20210610 v1.3.7 +- Enhance error handling when a dict method is raised +- Enhance exception error messages + 20210609 v1.3.6 - Documentation fixes for packages and binaries hosting diff --git a/jello/cli.py b/jello/cli.py index 5d1c883..86d2686 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -15,7 +15,7 @@ from jello.dotmap import DotMap -__version__ = '1.3.6' +__version__ = '1.3.7' AUTHOR = 'Kelly Brazil' WEBSITE = 'https://github.com/kellyjonbrazil/jello' COPYRIGHT = '© 2020-2021 Kelly Brazil' diff --git a/setup.py b/setup.py index 1d6c8f1..3eade7a 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name='jello', - version='1.3.6', + version='1.3.7', author='Kelly Brazil', author_email='kellyjonbrazil@gmail.com', description='Filter JSON and JSON Lines data with Python syntax.', From 0167f92a101fc4f641f6dfb61f8e4239a992d3ec Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 09:58:40 -0700 Subject: [PATCH 04/68] standardize exceptions using format_exception() function --- jello/cli.py | 120 +++++++++++++++++++-------------------------------- 1 file changed, 45 insertions(+), 75 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index 86d2686..202bbb0 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -264,7 +264,7 @@ def create_json(data): break if opts.lines and list_includes_list: - raise ValueError('Cannot print list of lists as lines. Try normal JSON output.\n') + raise ValueError('Cannot print list of lists as lines. Try normal JSON output.') # print lines for a flat list else: @@ -411,7 +411,7 @@ def pyquery(data, query): # if DotMap returns a bound function then we know it was a reserved attribute name if hasattr(output, '__self__'): - raise ValueError('A reserved key name with dotted notation was used in the query. Please use python bracket dict notation to access this key.') + raise ValueError('Reserved key name. Use bracket notation to access this key.') return output @@ -425,6 +425,27 @@ def load_json(data): return json_dict +def format_exception(e=None, list_dict_data='', query='', response='', output=''): + query = str(query).replace('\n', '; ') + e_text = '' + + if hasattr(e, 'text'): + e_text = e.text + + if len(str(list_dict_data)) > 70: + list_dict_data = str(list_dict_data)[0:35] + ' ... ' + str(list_dict_data)[-35:-1] + + if len(str(query)) > 70: + query = str(query)[0:35] + ' ... ' + str(query)[-35:-1] + + if len(str(response)) > 70: + response = str(response)[0:35] + ' ... ' + str(response)[-35:-1] + + if len(str(output)) > 70: + output = str(output)[0:35] + ' ... ' + str(output)[-35:-1] + + return e, e_text, list_dict_data, query, response, output + def main(data=None, query='_'): # break on ctrl-c keyboard interrupt @@ -507,59 +528,17 @@ def main(data=None, query='_'): try: response = pyquery(list_dict_data, query) - except KeyError as e: - msg = f'Key does not exist: {e}' - print_error(textwrap.dedent(f'''\ - jello: {msg} - ''')) - - except IndexError as e: - print_error(textwrap.dedent(f'''\ - jello: {e} - ''')) - - except SyntaxError as e: - print_error(textwrap.dedent(f'''\ - jello: {e} - {e.text} - ''')) - - except TypeError as e: - msg = f'TypeError: {e}' - print_error(textwrap.dedent(f'''\ - jello: {msg} - ''')) - - except AttributeError as e: - msg = f'AttributeError: {e}' - print_error(textwrap.dedent(f'''\ - jello: {msg} - ''')) - - except NameError as e: - msg = f'NameError: {e}' - print_error(textwrap.dedent(f'''\ - jello: {msg} - ''')) - except Exception as e: - query = query.replace('\n', '; ') - - err_data = '' - if len(str(list_dict_data)) > 70: - err_data = str(list_dict_data)[0:35] + ' ... ' + str(list_dict_data)[-35:-1] - - if len(str(query)) > 70: - query = str(query)[0:35] + ' ... ' + str(query)[-35:-1] - - if len(str(response)) > 70: - response = str(response)[0:35] + ' ... ' + str(response)[-35:-1] + e, e_text, list_dict_data, query, response, output = format_exception(e, + list_dict_data, + query) print_error(textwrap.dedent(f'''\ - jello: Query Exception: {e} + jello: Query Exception: {e.__class__.__name__} + {e} + {e_text} query: {query} - data: {err_data} - response: {response} + data: {list_dict_data} ''')) set_env_colors() @@ -586,18 +565,15 @@ class JelloStyle(Style): else: output = create_json(response) except Exception as e: - query = query.replace('\n', '; ') - - if len(str(list_dict_data)) > 70: - list_dict_data = str(list_dict_data)[0:35] + ' ... ' + str(list_dict_data)[-35:-1] - - if len(str(response)) > 70: - response = str(response)[0:35] + ' ... ' + str(response)[-35:-1] + e, e_text, list_dict_data, query, response, output = format_exception(e, + list_dict_data, + query, + response) - if len(str(query)) > 70: - query = str(query)[0:35] + ' ... ' + str(query)[-35:-1] print_error(textwrap.dedent(f'''\ - jello: Formatting Exception: {e} + jello: Formatting Exception: {e.__class__.__name__} + {e} + {e_text} query: {query} data: {list_dict_data} response: {response} @@ -614,22 +590,16 @@ class JelloStyle(Style): print(output) except Exception as e: - query = query.replace('\n', '; ') - - if len(str(list_dict_data)) > 70: - list_dict_data = str(list_dict_data)[0:35] + ' ... ' + str(list_dict_data)[-35:-1] - - if len(str(response)) > 70: - response = str(response)[0:35] + ' ... ' + str(response)[-35:-1] - - if len(str(output)) > 70: - output = str(output)[0:35] + ' ... ' + str(output)[-35:-1] - - if len(str(query)) > 70: - query = str(query)[0:35] + ' ... ' + str(query)[-35:-1] + e, e_text, list_dict_data, query, response, output = format_exception(e, + list_dict_data, + query, + response, + output) print_error(textwrap.dedent(f'''\ - jello: Output Exception: {e} + jello: Output Exception: {e.__class__.__name__} + {e} + {e_text} query: {query} data: {list_dict_data} response: {response} From ba542e62684ab43415448389adfa60cad9d12aba Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 10:12:26 -0700 Subject: [PATCH 05/68] use exception instead of print_error inside pyquery function --- jello/cli.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index 202bbb0..c54814d 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -337,9 +337,10 @@ def pyquery(data, query): with open(conf_file, 'r') as f: jelloconf = f.read() except FileNotFoundError: - print_error(textwrap.dedent(f'''\ - jello: Initialization file not found: {conf_file} - ''')) + raise FileNotFoundError(f'-i used and initialization file not found: {conf_file}') + # print_error(textwrap.dedent(f'''\ + # jello: Initialization file not found: {conf_file} + # ''')) query = jelloconf + query output = None @@ -564,6 +565,7 @@ class JelloStyle(Style): sys.exit() else: output = create_json(response) + except Exception as e: e, e_text, list_dict_data, query, response, output = format_exception(e, list_dict_data, From c9e094a3b68ec31ff55417704271e2d52f3663d7 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 10:22:27 -0700 Subject: [PATCH 06/68] remove comments and shorten exception output --- jello/cli.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index c54814d..da2c10d 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -338,9 +338,6 @@ def pyquery(data, query): jelloconf = f.read() except FileNotFoundError: raise FileNotFoundError(f'-i used and initialization file not found: {conf_file}') - # print_error(textwrap.dedent(f'''\ - # jello: Initialization file not found: {conf_file} - # ''')) query = jelloconf + query output = None @@ -434,16 +431,16 @@ def format_exception(e=None, list_dict_data='', query='', response='', output='' e_text = e.text if len(str(list_dict_data)) > 70: - list_dict_data = str(list_dict_data)[0:35] + ' ... ' + str(list_dict_data)[-35:-1] + list_dict_data = str(list_dict_data)[:34] + ' ... ' + str(list_dict_data)[-34:] if len(str(query)) > 70: - query = str(query)[0:35] + ' ... ' + str(query)[-35:-1] + query = str(query)[:34] + ' ... ' + str(query)[-34:] if len(str(response)) > 70: - response = str(response)[0:35] + ' ... ' + str(response)[-35:-1] + response = str(response)[:34] + ' ... ' + str(response)[-34:] if len(str(output)) > 70: - output = str(output)[0:35] + ' ... ' + str(output)[-35:-1] + output = str(output)[0:34] + ' ... ' + str(output)[-34:] return e, e_text, list_dict_data, query, response, output From 5de2462bf7e24920f878daa05a8548edc165abce Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 10:25:29 -0700 Subject: [PATCH 07/68] declare conf_file in case it is never assigned --- jello/cli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/jello/cli.py b/jello/cli.py index da2c10d..9525c99 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -326,6 +326,7 @@ def pyquery(data, query): _ = data jelloconf = '' + conf_file = '' if opts.initialize: if platform.system() == 'Windows': From 8867d37af83181927e4acdd22f6864da1658d8d4 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 10:43:47 -0700 Subject: [PATCH 08/68] formatting --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f716a3a..7bd9b1c 100644 --- a/README.md +++ b/README.md @@ -89,15 +89,15 @@ echo '{"foo":"bar","baz":[1,2,3]}' | jello -l _.baz 3 ``` -You can also create [JSON Lines](https://jsonlines.org/) with the `-l` option: +The `-l` option also allows you to create [JSON Lines](https://jsonlines.org/): ```bash -echo '[{"foo":"bar","baz":[1,2,3]},{"foo":"bar","baz":[1,2,3]}]' | jello -l +echo '[{"foo":"bar","baz":[1,2,3]},{"fiz":"boo","buz":[3,4,5]}]' | jello -l {"foo":"bar","baz":[1,2,3]} -{"foo":"bar","baz":[1,2,3]} +{"fiz":"boo","buz":[3,4,5]} ``` -You can also print a grep-able schema by using the `-s` option: +You can print a grep-able schema by using the `-s` option: ```bash echo '{"foo":"bar","baz":[1,2,3]}' | jello -s @@ -109,7 +109,7 @@ echo '{"foo":"bar","baz":[1,2,3]}' | jello -s #### Assigning Results to a Bash Array -Use the `-l` option to print JSON array output in a manner suitable to be assigned to a bash array. The `-r` option can be used to remove quotation marks around strings. If you want `null` values to be printed as `null`, use the `-n` option, otherwise they are blank lines. +Use the `-l` option to print JSON array output in a manner suitable to be assigned to a bash array. The `-r` option can be used to remove quotation marks around strings. If you want `null` values to be printed as `null`, use the `-n` option, otherwise they are printed as blank lines. Bash variable: ``` From 0d77d9b075033730eec748305a8d9093cb5ddd24 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 10:45:32 -0700 Subject: [PATCH 09/68] formatting --- jello/man/jello.1 | 4 ++-- man/jello.1 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jello/man/jello.1 b/jello/man/jello.1 index 1e82062..2edbe4b 100644 --- a/jello/man/jello.1 +++ b/jello/man/jello.1 @@ -1,4 +1,4 @@ -.TH jello 1 2021-06-10 1.3.6 "Jello JSON Filter" +.TH jello 1 2021-06-11 1.3.7 "Jello JSON Filter" .SH NAME Jello \- Filter JSON and JSON Lines data with Python syntax .SH SYNOPSIS @@ -133,7 +133,7 @@ $ echo \[aq]{\[dq]foo\[dq]:\[dq]bar\[dq],\[dq]baz\[dq]:[1,2,3]}\[aq] | jello -s .SS Assigning Results to a Bash Array .PP Use the \fB-l\fP option to print JSON array output in a manner suitable to be assigned to a bash array. -The \fB-r\fP option can be used to remove quotation marks around strings. If you want null values to be printed as null, use the \fB-n\fP option, otherwise they are blank lines. +The \fB-r\fP option can be used to remove quotation marks around strings. If you want null values to be printed as null, use the \fB-n\fP option, otherwise they are printed as blank lines. .PP Bash variable: .IP diff --git a/man/jello.1 b/man/jello.1 index 1e82062..2edbe4b 100644 --- a/man/jello.1 +++ b/man/jello.1 @@ -1,4 +1,4 @@ -.TH jello 1 2021-06-10 1.3.6 "Jello JSON Filter" +.TH jello 1 2021-06-11 1.3.7 "Jello JSON Filter" .SH NAME Jello \- Filter JSON and JSON Lines data with Python syntax .SH SYNOPSIS @@ -133,7 +133,7 @@ $ echo \[aq]{\[dq]foo\[dq]:\[dq]bar\[dq],\[dq]baz\[dq]:[1,2,3]}\[aq] | jello -s .SS Assigning Results to a Bash Array .PP Use the \fB-l\fP option to print JSON array output in a manner suitable to be assigned to a bash array. -The \fB-r\fP option can be used to remove quotation marks around strings. If you want null values to be printed as null, use the \fB-n\fP option, otherwise they are blank lines. +The \fB-r\fP option can be used to remove quotation marks around strings. If you want null values to be printed as null, use the \fB-n\fP option, otherwise they are printed as blank lines. .PP Bash variable: .IP From 03eff8ac3119d4821de33c7039d87256ba4001b3 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 13:04:31 -0700 Subject: [PATCH 10/68] refactor to split cli and lib --- jello/__init__.py | 8 ++ jello/cli.py | 309 ++-------------------------------------------- jello/lib.py | 274 ++++++++++++++++++++++++++++++++++++++++ jello/options.py | 24 ++++ 4 files changed, 317 insertions(+), 298 deletions(-) create mode 100644 jello/lib.py create mode 100644 jello/options.py diff --git a/jello/__init__.py b/jello/__init__.py index e69de29..80034f3 100644 --- a/jello/__init__.py +++ b/jello/__init__.py @@ -0,0 +1,8 @@ +"""jello - query JSON at the command line with python syntax""" + + +__version__ = '1.3.7' +AUTHOR = 'Kelly Brazil' +WEBSITE = 'https://github.com/kellyjonbrazil/jello' +COPYRIGHT = '© 2020-2021 Kelly Brazil' +LICENSE = 'MIT License' diff --git a/jello/cli.py b/jello/cli.py index 9525c99..57e4a4c 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -4,7 +4,6 @@ import sys import platform import textwrap -import json import signal import ast from pygments import highlight @@ -12,15 +11,11 @@ from pygments.token import (Name, Number, String, Keyword) from pygments.lexers import JsonLexer from pygments.formatters import Terminal256Formatter -from jello.dotmap import DotMap +import jello +from jello.lib import load_json, create_schema, create_json, pyquery +from jello.options import opts, JelloTheme -__version__ = '1.3.7' -AUTHOR = 'Kelly Brazil' -WEBSITE = 'https://github.com/kellyjonbrazil/jello' -COPYRIGHT = '© 2020-2021 Kelly Brazil' -LICENSE = 'MIT License' - color_map = { 'black': ('ansiblack', '\33[30m'), 'red': ('ansired', '\33[31m'), @@ -41,32 +36,6 @@ } -class opts: - initialize = None - version_info = None - helpme = None - compact = None - nulls = None - raw = None - lines = None - mono = None - schema = None - keyname_color = None - keyword_color = None - number_color = None - string_color = None - arrayid_color = None - arraybracket_color = None - - -schema_list = [] - - -class JelloTheme: - """this class will contain the colors dictionary generated from set_env_colors()""" - pass - - def set_env_colors(): """ This function does not return a value. It just updates the JelloTheme.colors dictionary. @@ -168,262 +137,6 @@ def helptext(): sys.exit() -def create_schema(src, path=''): - """ - Creates a grep-able schema representation of the JSON. - - This function is recursive, so output is stored within the schema_list list. Make sure to - initialize schema_list to a blank list and set colors by calling set_env_colors() before - calling this function. - """ - if not opts.mono: - CEND = '\33[0m' - CBOLD = '\33[1m' - CKEYNAME = f'{JelloTheme.colors["key_name"][1]}' - CKEYWORD = f'{JelloTheme.colors["keyword"][1]}' - CNUMBER = f'{JelloTheme.colors["number"][1]}' - CSTRING = f'{JelloTheme.colors["string"][1]}' - CARRAYID = f'{JelloTheme.colors["array_id"][1]}' - CARRAYBRACKET = f'{JelloTheme.colors["array_bracket"][1]}' - - else: - CEND = '' - CBOLD = '' - CKEYNAME = '' - CKEYWORD = '' - CNUMBER = '' - CSTRING = '' - CARRAYID = '' - CARRAYBRACKET = '' - - if isinstance(src, list) and path == '': - for i, item in enumerate(src): - create_schema(item, path=f'.{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') - - elif isinstance(src, list): - for i, item in enumerate(src): - create_schema(item, path=f'{path}.{CBOLD}{CKEYNAME}{src}{CEND}{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') - - elif isinstance(src, dict): - for k, v in src.items(): - if isinstance(v, list): - for i, item in enumerate(v): - create_schema(item, path=f'{path}.{CBOLD}{CKEYNAME}{k}{CEND}{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') - - elif isinstance(v, dict): - if not opts.mono: - k = f'{CBOLD}{CKEYNAME}{k}{CEND}' - create_schema(v, path=f'{path}.{k}') - - else: - k = f'{CBOLD}{CKEYNAME}{k}{CEND}' - val = json.dumps(v, ensure_ascii=False) - if val == 'true' or val == 'false' or val == 'null': - val = f'{CKEYWORD}{val}{CEND}' - elif val.replace('.', '', 1).isdigit(): - val = f'{CNUMBER}{val}{CEND}' - else: - val = f'{CSTRING}{val}{CEND}' - - schema_list.append(f'{path}.{k} = {val};') - - else: - val = json.dumps(src, ensure_ascii=False) - if val == 'true' or val == 'false' or val == 'null': - val = f'{CKEYWORD}{val}{CEND}' - elif val.replace('.', '', 1).isdigit(): - val = f'{CNUMBER}{val}{CEND}' - else: - val = f'{CSTRING}{val}{CEND}' - - path = path or '.' - - schema_list.append(f'{path} = {val};') - - -def create_json(data): - separators = None - indent = 2 - - if opts.compact or opts.lines: - separators = (',', ':') - indent = None - - if isinstance(data, dict): - return json.dumps(data, separators=separators, indent=indent, ensure_ascii=False) - - if isinstance(data, list): - if not opts.lines: - return json.dumps(data, separators=separators, indent=indent, ensure_ascii=False) - - # check if this list includes lists - list_includes_list = False - for item in data: - if isinstance(item, list): - list_includes_list = True - break - - if opts.lines and list_includes_list: - raise ValueError('Cannot print list of lists as lines. Try normal JSON output.') - - # print lines for a flat list - else: - flat_list = '' - for entry in data: - if entry is None: - if opts.nulls: - flat_list += 'null\n' - else: - flat_list += '\n' - - elif isinstance(entry, (dict, bool, int, float)): - flat_list += json.dumps(entry, separators=separators, ensure_ascii=False) + '\n' - - elif isinstance(entry, str): - # replace \n with \\n here so lines with newlines literally print the \n char - entry = entry.replace('\n', '\\n') - if opts.raw: - flat_list += f'{entry}' + '\n' - else: - flat_list += f'"{entry}"' + '\n' - - return flat_list.rstrip() - - # naked single item return case - elif data is None: - if opts.nulls: - return 'null' - else: - return '' - - elif isinstance(data, (bool, int, float)): - return json.dumps(data, ensure_ascii=False) - - elif isinstance(data, str): - # replace \n with \\n here so lines with newlines literally print the \n char - data = data.replace('\n', '\\n') - if opts.raw: - return f'{data}' - else: - return f'"{data}"' - - # only non-serializable types are left. Force an exception from json.dumps() - else: - json.dumps(data) - # this code should not run, but just in case something slips by above - raise TypeError(f'Object is not JSON serializable') - -def pyquery(data, query): - # if data is a list of dictionaries, then need to iterate through and convert all dictionaries to DotMap - if isinstance(data, list): - _ = [DotMap(i, _dynamic=False, _prevent_method_masking=True) if isinstance(i, dict) - else i for i in data] - - elif isinstance(data, dict): - _ = DotMap(data, _dynamic=False, _prevent_method_masking=True) - - else: - _ = data - - jelloconf = '' - conf_file = '' - - if opts.initialize: - if platform.system() == 'Windows': - conf_file = os.path.join(os.environ['APPDATA'], '.jelloconf.py') - else: - conf_file = os.path.join(os.environ["HOME"], '.jelloconf.py') - - try: - with open(conf_file, 'r') as f: - jelloconf = f.read() - except FileNotFoundError: - raise FileNotFoundError(f'-i used and initialization file not found: {conf_file}') - - query = jelloconf + query - output = None - - # extract jello options from .jelloconf.py (compact, raw, lines, nulls, mono, and custom colors) - for expr in ast.parse(jelloconf).body: - if isinstance(expr, ast.Assign): - if expr.targets[0].id == 'compact': - opts.compact = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'raw': - opts.raw = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'lines': - opts.lines = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'nulls': - opts.nulls = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'mono': - opts.mono = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'schema': - opts.schema = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'keyname_color': - opts.keyname_color = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'keyword_color': - opts.keyword_color = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'number_color': - opts.number_color = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'string_color': - opts.string_color = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'arrayid_color': - opts.arrayid_color = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'arraybracket_color': - opts.arraybracket_color = eval(compile(ast.Expression(expr.value), '', "eval")) - - # validate the data in the initialization file - warn_options = False - warn_colors = False - - for option in [opts.compact, opts.raw, opts.lines, opts.nulls, opts.mono, opts.schema]: - if not isinstance(option, bool): - opts.compact = opts.raw = opts.lines = opts.nulls = opts.mono = opts.schema = None - warn_options = True - - for color_config in [opts.keyname_color, opts.keyword_color, opts.number_color, - opts.string_color, opts.arrayid_color, opts.arraybracket_color]: - valid_colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'gray', 'brightblack', 'brightred', - 'brightgreen', 'brightyellow', 'brightblue', 'brightmagenta', 'brightcyan', 'white'] - if color_config not in valid_colors and color_config is not None: - opts.keyname_color = opts.keyword_color = opts.number_color = opts.string_color = opts.arrayid_color = opts.arraybracket_color = None - warn_colors = True - - if warn_options: - print(f'Jello: Warning: Options must be set to True or False in {conf_file}\n Unsetting all options.\n') - - if warn_colors: - valid_colors_string = ', '.join(valid_colors) - print(f'Jello: Warning: Colors must be set to one of: {valid_colors_string} in {conf_file}\n Unsetting all colors.\n') - - # run the query - block = ast.parse(query, mode='exec') - last = ast.Expression(block.body.pop().value) # assumes last node is an expression - exec(compile(block, '', mode='exec')) - output = eval(compile(last, '', mode='eval')) - - # convert output back to normal dict - if isinstance(output, list): - output = [i.toDict() if isinstance(i, DotMap) else i for i in output] - - elif isinstance(output, DotMap): - output = output.toDict() - - # if DotMap returns a bound function then we know it was a reserved attribute name - if hasattr(output, '__self__'): - raise ValueError('Reserved key name. Use bracket notation to access this key.') - - return output - - -def load_json(data): - try: - json_dict = json.loads(data) - except Exception: - # if json.loads fails, assume the data is json lines and parse - json_dict = [json.loads(i) for i in data.splitlines()] - - return json_dict - def format_exception(e=None, list_dict_data='', query='', response='', output=''): query = str(query).replace('\n', '; ') e_text = '' @@ -433,7 +146,7 @@ def format_exception(e=None, list_dict_data='', query='', response='', output='' if len(str(list_dict_data)) > 70: list_dict_data = str(list_dict_data)[:34] + ' ... ' + str(list_dict_data)[-34:] - + if len(str(query)) > 70: query = str(query)[:34] + ' ... ' + str(query)[-34:] @@ -497,11 +210,11 @@ def main(data=None, query='_'): if opts.version_info: print(textwrap.dedent(f'''\ - jello: Version: {__version__} - Author: {AUTHOR} - Website: {WEBSITE} - Copyright: {COPYRIGHT} - License: {LICENSE} + jello: Version: {jello.__version__} + Author: {jello.AUTHOR} + Website: {jello.WEBSITE} + Copyright: {jello.COPYRIGHT} + License: {jello.LICENSE} ''')) sys.exit() @@ -527,7 +240,7 @@ def main(data=None, query='_'): try: response = pyquery(list_dict_data, query) - except Exception as e: + except Exception as e: e, e_text, list_dict_data, query, response, output = format_exception(e, list_dict_data, query) @@ -559,7 +272,7 @@ class JelloStyle(Style): if not sys.stdout.isatty(): opts.mono = True create_schema(response) - print('\n'.join(schema_list)) + print('\n'.join(jello.lib.schema_list)) sys.exit() else: output = create_json(response) diff --git a/jello/lib.py b/jello/lib.py new file mode 100644 index 0000000..431f17d --- /dev/null +++ b/jello/lib.py @@ -0,0 +1,274 @@ +"""jello - query JSON at the command line with python syntax""" + +import os +import sys +import platform +import ast +import json +from jello.dotmap import DotMap +from jello.options import opts, JelloTheme + + +schema_list = [] + + +def load_json(data): + try: + json_dict = json.loads(data) + except Exception: + # if json.loads fails, assume the data is json lines and parse + json_dict = [json.loads(i) for i in data.splitlines()] + + return json_dict + + +def create_schema(src, path=''): + """ + Creates a grep-able schema representation of the JSON. + + This function is recursive, so output is stored within the schema_list list. Make sure to + initialize schema_list to a blank list and set colors by calling set_env_colors() before + calling this function. + """ + if not opts.mono: + CEND = '\33[0m' + CBOLD = '\33[1m' + CKEYNAME = f'{JelloTheme.colors["key_name"][1]}' + CKEYWORD = f'{JelloTheme.colors["keyword"][1]}' + CNUMBER = f'{JelloTheme.colors["number"][1]}' + CSTRING = f'{JelloTheme.colors["string"][1]}' + CARRAYID = f'{JelloTheme.colors["array_id"][1]}' + CARRAYBRACKET = f'{JelloTheme.colors["array_bracket"][1]}' + + else: + CEND = '' + CBOLD = '' + CKEYNAME = '' + CKEYWORD = '' + CNUMBER = '' + CSTRING = '' + CARRAYID = '' + CARRAYBRACKET = '' + + if isinstance(src, list) and path == '': + for i, item in enumerate(src): + create_schema(item, path=f'.{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') + + elif isinstance(src, list): + for i, item in enumerate(src): + create_schema(item, path=f'{path}.{CBOLD}{CKEYNAME}{src}{CEND}{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') + + elif isinstance(src, dict): + for k, v in src.items(): + if isinstance(v, list): + for i, item in enumerate(v): + create_schema(item, path=f'{path}.{CBOLD}{CKEYNAME}{k}{CEND}{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') + + elif isinstance(v, dict): + if not opts.mono: + k = f'{CBOLD}{CKEYNAME}{k}{CEND}' + create_schema(v, path=f'{path}.{k}') + + else: + k = f'{CBOLD}{CKEYNAME}{k}{CEND}' + val = json.dumps(v, ensure_ascii=False) + if val == 'true' or val == 'false' or val == 'null': + val = f'{CKEYWORD}{val}{CEND}' + elif val.replace('.', '', 1).isdigit(): + val = f'{CNUMBER}{val}{CEND}' + else: + val = f'{CSTRING}{val}{CEND}' + + schema_list.append(f'{path}.{k} = {val};') + + else: + val = json.dumps(src, ensure_ascii=False) + if val == 'true' or val == 'false' or val == 'null': + val = f'{CKEYWORD}{val}{CEND}' + elif val.replace('.', '', 1).isdigit(): + val = f'{CNUMBER}{val}{CEND}' + else: + val = f'{CSTRING}{val}{CEND}' + + path = path or '.' + + schema_list.append(f'{path} = {val};') + + +def create_json(data): + separators = None + indent = 2 + + if opts.compact or opts.lines: + separators = (',', ':') + indent = None + + if isinstance(data, dict): + return json.dumps(data, separators=separators, indent=indent, ensure_ascii=False) + + if isinstance(data, list): + if not opts.lines: + return json.dumps(data, separators=separators, indent=indent, ensure_ascii=False) + + # check if this list includes lists + list_includes_list = False + for item in data: + if isinstance(item, list): + list_includes_list = True + break + + if opts.lines and list_includes_list: + raise ValueError('Cannot print list of lists as lines. Try normal JSON output.') + + # print lines for a flat list + else: + flat_list = '' + for entry in data: + if entry is None: + if opts.nulls: + flat_list += 'null\n' + else: + flat_list += '\n' + + elif isinstance(entry, (dict, bool, int, float)): + flat_list += json.dumps(entry, separators=separators, ensure_ascii=False) + '\n' + + elif isinstance(entry, str): + # replace \n with \\n here so lines with newlines literally print the \n char + entry = entry.replace('\n', '\\n') + if opts.raw: + flat_list += f'{entry}' + '\n' + else: + flat_list += f'"{entry}"' + '\n' + + return flat_list.rstrip() + + # naked single item return case + elif data is None: + if opts.nulls: + return 'null' + else: + return '' + + elif isinstance(data, (bool, int, float)): + return json.dumps(data, ensure_ascii=False) + + elif isinstance(data, str): + # replace \n with \\n here so lines with newlines literally print the \n char + data = data.replace('\n', '\\n') + if opts.raw: + return f'{data}' + else: + return f'"{data}"' + + # only non-serializable types are left. Force an exception from json.dumps() + else: + json.dumps(data) + # this code should not run, but just in case something slips by above + raise TypeError(f'Object is not JSON serializable') + + +def pyquery(data, query): + # if data is a list of dictionaries, then need to iterate through and convert all dictionaries to DotMap + if isinstance(data, list): + _ = [DotMap(i, _dynamic=False, _prevent_method_masking=True) if isinstance(i, dict) + else i for i in data] + + elif isinstance(data, dict): + _ = DotMap(data, _dynamic=False, _prevent_method_masking=True) + + else: + _ = data + + jelloconf = '' + conf_file = '' + + if opts.initialize: + if sys.platform.startswith('win32'): + conf_file = os.path.join(os.environ['APPDATA'], '.jelloconf.py') + else: + conf_file = os.path.join(os.environ["HOME"], '.jelloconf.py') + + try: + with open(conf_file, 'r') as f: + jelloconf = f.read() + except FileNotFoundError: + raise FileNotFoundError(f'-i used and initialization file not found: {conf_file}') + + query = jelloconf + query + output = None + + # extract jello options from .jelloconf.py (compact, raw, lines, nulls, mono, and custom colors) + for expr in ast.parse(jelloconf).body: + if isinstance(expr, ast.Assign): + if expr.targets[0].id == 'compact': + opts.compact = eval(compile(ast.Expression(expr.value), '', "eval")) + if expr.targets[0].id == 'raw': + opts.raw = eval(compile(ast.Expression(expr.value), '', "eval")) + if expr.targets[0].id == 'lines': + opts.lines = eval(compile(ast.Expression(expr.value), '', "eval")) + if expr.targets[0].id == 'nulls': + opts.nulls = eval(compile(ast.Expression(expr.value), '', "eval")) + if expr.targets[0].id == 'mono': + opts.mono = eval(compile(ast.Expression(expr.value), '', "eval")) + if expr.targets[0].id == 'schema': + opts.schema = eval(compile(ast.Expression(expr.value), '', "eval")) + if expr.targets[0].id == 'keyname_color': + opts.keyname_color = eval(compile(ast.Expression(expr.value), '', "eval")) + if expr.targets[0].id == 'keyword_color': + opts.keyword_color = eval(compile(ast.Expression(expr.value), '', "eval")) + if expr.targets[0].id == 'number_color': + opts.number_color = eval(compile(ast.Expression(expr.value), '', "eval")) + if expr.targets[0].id == 'string_color': + opts.string_color = eval(compile(ast.Expression(expr.value), '', "eval")) + if expr.targets[0].id == 'arrayid_color': + opts.arrayid_color = eval(compile(ast.Expression(expr.value), '', "eval")) + if expr.targets[0].id == 'arraybracket_color': + opts.arraybracket_color = eval(compile(ast.Expression(expr.value), '', "eval")) + + # validate the data in the initialization file + warn_options = False + warn_colors = False + + for option in [opts.compact, opts.raw, opts.lines, opts.nulls, opts.mono, opts.schema]: + if not isinstance(option, bool): + opts.compact = opts.raw = opts.lines = opts.nulls = opts.mono = opts.schema = None + warn_options = True + + for color_config in [opts.keyname_color, opts.keyword_color, opts.number_color, + opts.string_color, opts.arrayid_color, opts.arraybracket_color]: + valid_colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'gray', 'brightblack', 'brightred', + 'brightgreen', 'brightyellow', 'brightblue', 'brightmagenta', 'brightcyan', 'white'] + if color_config not in valid_colors and color_config is not None: + opts.keyname_color = opts.keyword_color = opts.number_color = opts.string_color = opts.arrayid_color = opts.arraybracket_color = None + warn_colors = True + + if warn_options: + print(f'Jello: Warning: Options must be set to True or False in {conf_file}\n Unsetting all options.\n') + + if warn_colors: + valid_colors_string = ', '.join(valid_colors) + print(f'Jello: Warning: Colors must be set to one of: {valid_colors_string} in {conf_file}\n Unsetting all colors.\n') + + # run the query + block = ast.parse(query, mode='exec') + last = ast.Expression(block.body.pop().value) # assumes last node is an expression + exec(compile(block, '', mode='exec')) + output = eval(compile(last, '', mode='eval')) + + # convert output back to normal dict + if isinstance(output, list): + output = [i.toDict() if isinstance(i, DotMap) else i for i in output] + + elif isinstance(output, DotMap): + output = output.toDict() + + # if DotMap returns a bound function then we know it was a reserved attribute name + if hasattr(output, '__self__'): + raise ValueError('Reserved key name. Use bracket notation to access this key.') + + return output + + +if __name__ == '__main__': + main() diff --git a/jello/options.py b/jello/options.py new file mode 100644 index 0000000..7a671f3 --- /dev/null +++ b/jello/options.py @@ -0,0 +1,24 @@ +"""jello - query JSON at the command line with python syntax""" + + +class opts: + initialize = None + version_info = None + helpme = None + compact = None + nulls = None + raw = None + lines = None + mono = None + schema = None + keyname_color = None + keyword_color = None + number_color = None + string_color = None + arrayid_color = None + arraybracket_color = None + + +class JelloTheme: + """this class will contain the colors dictionary generated from set_env_colors()""" + pass From 5c255686fbdac5f16fbf1db3432a8132ecde4396 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 13:22:06 -0700 Subject: [PATCH 11/68] fix tests --- jello/cli.py | 80 +-------------------- jello/lib.py | 77 +++++++++++++++++++- tests/test_create_schema.py | 137 ++++++++++++++++++------------------ tests/test_main.py | 4 +- 4 files changed, 148 insertions(+), 150 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index 57e4a4c..93b7079 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -2,96 +2,18 @@ import os import sys -import platform import textwrap import signal -import ast from pygments import highlight from pygments.style import Style from pygments.token import (Name, Number, String, Keyword) from pygments.lexers import JsonLexer from pygments.formatters import Terminal256Formatter import jello -from jello.lib import load_json, create_schema, create_json, pyquery +from jello.lib import set_env_colors, load_json, create_schema, create_json, pyquery from jello.options import opts, JelloTheme -color_map = { - 'black': ('ansiblack', '\33[30m'), - 'red': ('ansired', '\33[31m'), - 'green': ('ansigreen', '\33[32m'), - 'yellow': ('ansiyellow', '\33[33m'), - 'blue': ('ansiblue', '\33[34m'), - 'magenta': ('ansimagenta', '\33[35m'), - 'cyan': ('ansicyan', '\33[36m'), - 'gray': ('ansigray', '\33[37m'), - 'brightblack': ('ansibrightblack', '\33[90m'), - 'brightred': ('ansibrightred', '\33[91m'), - 'brightgreen': ('ansibrightgreen', '\33[92m'), - 'brightyellow': ('ansibrightyellow', '\33[93m'), - 'brightblue': ('ansibrightblue', '\33[94m'), - 'brightmagenta': ('ansibrightmagenta', '\33[95m'), - 'brightcyan': ('ansibrightcyan', '\33[96m'), - 'white': ('ansiwhite', '\33[97m'), -} - - -def set_env_colors(): - """ - This function does not return a value. It just updates the JelloTheme.colors dictionary. - - Grab custom colors from JELLO_COLORS environment variable and .jelloconf.py file. Individual colors from JELLO_COLORS - take precedence over .jelloconf.py. Individual colors from JELLO_COLORS will fall back to .jelloconf.py or default - if the env variable color is set to 'default' - - JELLO_COLORS env variable takes 6 comma separated string values and should be in the format of: - - JELLO_COLORS=,,,,, - - Where colors are: black, red, green, yellow, blue, magenta, cyan, gray, brightblack, brightred, - brightgreen, brightyellow, brightblue, brightmagenta, brightcyan, white, default - - Default colors: - - JELLO_COLORS=blue,brightblack,magenta,green,red,magenta - or - JELLO_COLORS=default,default,default,default,default,default - - """ - env_colors = os.getenv('JELLO_COLORS') - input_error = False - - if env_colors: - color_list = env_colors.split(',') - - if env_colors and len(color_list) != 6: - input_error = True - - if env_colors: - for color in color_list: - if color not in ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'gray', 'brightblack', 'brightred', - 'brightgreen', 'brightyellow', 'brightblue', 'brightmagenta', 'brightcyan', 'white', 'default']: - input_error = True - else: - color_list = ['default', 'default', 'default', 'default', 'default', 'default'] - - # if there is an issue with the env variable, just set all colors to default and move on - if input_error: - print('jello: Warning: could not parse JELLO_COLORS environment variable\n', file=sys.stderr) - color_list = ['default', 'default', 'default', 'default', 'default', 'default'] - - # Try the color set in the JELLO_COLORS env variable first. If it is set to default, then fall back to .jelloconf.py - # configuration. If nothing is set in jelloconf.py, then use the default colors. - JelloTheme.colors = { - 'key_name': color_map[color_list[0]] if not color_list[0] == 'default' else color_map[opts.keyname_color] if opts.keyname_color else color_map['blue'], - 'keyword': color_map[color_list[1]] if not color_list[1] == 'default' else color_map[opts.keyword_color] if opts.keyword_color else color_map['brightblack'], - 'number': color_map[color_list[2]] if not color_list[2] == 'default' else color_map[opts.number_color] if opts.number_color else color_map['magenta'], - 'string': color_map[color_list[3]] if not color_list[3] == 'default' else color_map[opts.string_color] if opts.string_color else color_map['green'], - 'array_id': color_map[color_list[4]] if not color_list[4] == 'default' else color_map[opts.arrayid_color] if opts.arrayid_color else color_map['red'], - 'array_bracket': color_map[color_list[5]] if not color_list[5] == 'default' else color_map[opts.arraybracket_color] if opts.arraybracket_color else color_map['magenta'] - } - - def ctrlc(signum, frame): """exit with error on SIGINT""" sys.exit(1) diff --git a/jello/lib.py b/jello/lib.py index 431f17d..70b2e8a 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -2,7 +2,6 @@ import os import sys -import platform import ast import json from jello.dotmap import DotMap @@ -12,6 +11,82 @@ schema_list = [] +color_map = { + 'black': ('ansiblack', '\33[30m'), + 'red': ('ansired', '\33[31m'), + 'green': ('ansigreen', '\33[32m'), + 'yellow': ('ansiyellow', '\33[33m'), + 'blue': ('ansiblue', '\33[34m'), + 'magenta': ('ansimagenta', '\33[35m'), + 'cyan': ('ansicyan', '\33[36m'), + 'gray': ('ansigray', '\33[37m'), + 'brightblack': ('ansibrightblack', '\33[90m'), + 'brightred': ('ansibrightred', '\33[91m'), + 'brightgreen': ('ansibrightgreen', '\33[92m'), + 'brightyellow': ('ansibrightyellow', '\33[93m'), + 'brightblue': ('ansibrightblue', '\33[94m'), + 'brightmagenta': ('ansibrightmagenta', '\33[95m'), + 'brightcyan': ('ansibrightcyan', '\33[96m'), + 'white': ('ansiwhite', '\33[97m'), +} + + +def set_env_colors(): + """ + This function does not return a value. It just updates the JelloTheme.colors dictionary. + + Grab custom colors from JELLO_COLORS environment variable and .jelloconf.py file. Individual colors from JELLO_COLORS + take precedence over .jelloconf.py. Individual colors from JELLO_COLORS will fall back to .jelloconf.py or default + if the env variable color is set to 'default' + + JELLO_COLORS env variable takes 6 comma separated string values and should be in the format of: + + JELLO_COLORS=,,,,, + + Where colors are: black, red, green, yellow, blue, magenta, cyan, gray, brightblack, brightred, + brightgreen, brightyellow, brightblue, brightmagenta, brightcyan, white, default + + Default colors: + + JELLO_COLORS=blue,brightblack,magenta,green,red,magenta + or + JELLO_COLORS=default,default,default,default,default,default + + """ + env_colors = os.getenv('JELLO_COLORS') + input_error = False + + if env_colors: + color_list = env_colors.split(',') + + if env_colors and len(color_list) != 6: + input_error = True + + if env_colors: + for color in color_list: + if color not in ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'gray', 'brightblack', 'brightred', + 'brightgreen', 'brightyellow', 'brightblue', 'brightmagenta', 'brightcyan', 'white', 'default']: + input_error = True + else: + color_list = ['default', 'default', 'default', 'default', 'default', 'default'] + + # if there is an issue with the env variable, just set all colors to default and move on + if input_error: + print('jello: Warning: could not parse JELLO_COLORS environment variable\n', file=sys.stderr) + color_list = ['default', 'default', 'default', 'default', 'default', 'default'] + + # Try the color set in the JELLO_COLORS env variable first. If it is set to default, then fall back to .jelloconf.py + # configuration. If nothing is set in jelloconf.py, then use the default colors. + JelloTheme.colors = { + 'key_name': color_map[color_list[0]] if not color_list[0] == 'default' else color_map[opts.keyname_color] if opts.keyname_color else color_map['blue'], + 'keyword': color_map[color_list[1]] if not color_list[1] == 'default' else color_map[opts.keyword_color] if opts.keyword_color else color_map['brightblack'], + 'number': color_map[color_list[2]] if not color_list[2] == 'default' else color_map[opts.number_color] if opts.number_color else color_map['magenta'], + 'string': color_map[color_list[3]] if not color_list[3] == 'default' else color_map[opts.string_color] if opts.string_color else color_map['green'], + 'array_id': color_map[color_list[4]] if not color_list[4] == 'default' else color_map[opts.arrayid_color] if opts.arrayid_color else color_map['red'], + 'array_bracket': color_map[color_list[5]] if not color_list[5] == 'default' else color_map[opts.arraybracket_color] if opts.arraybracket_color else color_map['magenta'] + } + + def load_json(data): try: json_dict = json.loads(data) diff --git a/tests/test_create_schema.py b/tests/test_create_schema.py index 95939f8..eaec5a3 100644 --- a/tests/test_create_schema.py +++ b/tests/test_create_schema.py @@ -2,8 +2,9 @@ import unittest import os -import jello.cli -from jello.cli import opts +import jello +from jello.options import opts +from jello.lib import set_env_colors, create_schema class MyTests(unittest.TestCase): @@ -26,13 +27,13 @@ def setUp(self): opts.arraybracket_color = None # initialize schema_list - jello.cli.schema_list = [] + jello.lib.schema_list = [] # initialize JELLO_COLORS env variable os.environ['JELLO_COLORS'] = 'default,default,default,default,default,default' # set the colors - jello.cli.set_env_colors() + set_env_colors() # create samples self.dict_sample = { @@ -127,8 +128,8 @@ def test_true(self): """ self.data_in = True self.expected = '. = \x1b[90mtrue\x1b[0m;' - jello.cli.create_schema(self.data_in) - self.assertEqual('\n'.join(jello.cli.schema_list), self.expected) + create_schema(self.data_in) + self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) def test_true_m(self): """ @@ -137,8 +138,8 @@ def test_true_m(self): self.data_in = True self.expected = '. = true;' opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual('\n'.join(jello.cli.schema_list), self.expected) + create_schema(self.data_in) + self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) # # Naked False @@ -150,8 +151,8 @@ def test_false(self): """ self.data_in = False self.expected = '. = \x1b[90mfalse\x1b[0m;' - jello.cli.create_schema(self.data_in) - self.assertEqual('\n'.join(jello.cli.schema_list), self.expected) + create_schema(self.data_in) + self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) def test_false_m(self): """ @@ -160,8 +161,8 @@ def test_false_m(self): self.data_in = False self.expected = '. = false;' opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual('\n'.join(jello.cli.schema_list), self.expected) + create_schema(self.data_in) + self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) # # Naked null @@ -173,8 +174,8 @@ def test_null(self): """ self.data_in = None self.expected = '. = \x1b[90mnull\x1b[0m;' - jello.cli.create_schema(self.data_in) - self.assertEqual('\n'.join(jello.cli.schema_list), self.expected) + create_schema(self.data_in) + self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) def test_null_m(self): """ @@ -183,8 +184,8 @@ def test_null_m(self): self.data_in = None self.expected = '. = null;' opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual('\n'.join(jello.cli.schema_list), self.expected) + create_schema(self.data_in) + self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) # # naked int @@ -196,8 +197,8 @@ def test_int(self): """ self.data_in = 42 self.expected = '. = \x1b[35m42\x1b[0m;' - jello.cli.create_schema(self.data_in) - self.assertEqual('\n'.join(jello.cli.schema_list), self.expected) + create_schema(self.data_in) + self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) def test_int_m(self): """ @@ -206,8 +207,8 @@ def test_int_m(self): self.data_in = 42 self.expected = '. = 42;' opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual('\n'.join(jello.cli.schema_list), self.expected) + create_schema(self.data_in) + self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) # # naked float @@ -219,8 +220,8 @@ def test_float(self): """ self.data_in = 3.14 self.expected = '. = \x1b[35m3.14\x1b[0m;' - jello.cli.create_schema(self.data_in) - self.assertEqual('\n'.join(jello.cli.schema_list), self.expected) + create_schema(self.data_in) + self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) def test_float_m(self): """ @@ -229,8 +230,8 @@ def test_float_m(self): self.data_in = 3.14 self.expected = '. = 3.14;' opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual('\n'.join(jello.cli.schema_list), self.expected) + create_schema(self.data_in) + self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) # # naked string @@ -242,8 +243,8 @@ def test_string(self): """ self.data_in = '"string with\\nnewline char"' self.expected = '. = \x1b[32m"\\"string with\\\\nnewline char\\""\x1b[0m;' - jello.cli.create_schema(self.data_in) - self.assertEqual('\n'.join(jello.cli.schema_list), self.expected) + create_schema(self.data_in) + self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) def test_string_m(self): """ @@ -252,8 +253,8 @@ def test_string_m(self): self.data_in = '"string with\\nnewline char"' self.expected = '. = "\\"string with\\\\nnewline char\\"";' opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual('\n'.join(jello.cli.schema_list), self.expected) + create_schema(self.data_in) + self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) # # Naked Dict @@ -265,8 +266,8 @@ def test_dict(self): """ self.data_in = self.dict_sample self.expected = ['.\x1b[1m\x1b[34mstring\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[1m\x1b[34mtrue\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[1m\x1b[34mfalse\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[1m\x1b[34mnull\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[1m\x1b[34mint\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[1m\x1b[34mfloat\x1b[0m = \x1b[35m3.14\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;'] - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) def test_dict_m(self): """ @@ -275,8 +276,8 @@ def test_dict_m(self): self.data_in = self.dict_sample self.expected = ['.string = "string\\nwith newline\\ncharacters in it";', '.true = true;', '.false = false;', '.null = null;', '.int = 42;', '.float = 3.14;', '.array[0] = "string\\nwith newline\\ncharacters in it";', '.array[1] = true;', '.array[2] = false;', '.array[3] = null;', '.array[4] = 42;', '.array[5] = 3.14;'] opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) # # true in a list @@ -288,8 +289,8 @@ def test_list_true(self): """ self.data_in = [True] self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;'] - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) def test_list_true_m(self): """ @@ -298,8 +299,8 @@ def test_list_true_m(self): self.data_in = [True] self.expected = ['.[0] = true;'] opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) # # false in a list @@ -311,8 +312,8 @@ def test_list_false(self): """ self.data_in = [False] self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;'] - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) def test_list_false_m(self): """ @@ -321,8 +322,8 @@ def test_list_false_m(self): self.data_in = [False] self.expected = ['.[0] = false;'] opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) # # null in a list @@ -334,8 +335,8 @@ def test_list_null(self): """ self.data_in = [None] self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;'] - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) def test_list_null_m(self): """ @@ -344,8 +345,8 @@ def test_list_null_m(self): self.data_in = [None] self.expected = ['.[0] = null;'] opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) # # Int in a list @@ -357,8 +358,8 @@ def test_list_int(self): """ self.data_in = [42] self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;'] - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) def test_list_int_m(self): """ @@ -367,8 +368,8 @@ def test_list_int_m(self): self.data_in = [42] self.expected = ['.[0] = 42;'] opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) # # Float in a list @@ -380,8 +381,8 @@ def test_list_float(self): """ self.data_in = [3.14] self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;'] - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) def test_list_float_m(self): """ @@ -390,8 +391,8 @@ def test_list_float_m(self): self.data_in = [3.14] self.expected = ['.[0] = 3.14;'] opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) # # String in a list @@ -403,8 +404,8 @@ def test_list_str(self): """ self.data_in = ['string with spaces\nand newline\ncharacters'] self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string with spaces\\nand newline\\ncharacters"\x1b[0m;'] - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) def test_list_str_m(self): """ @@ -413,8 +414,8 @@ def test_list_str_m(self): self.data_in = ['string with spaces\nand newline\ncharacters'] self.expected = ['.[0] = "string with spaces\\nand newline\\ncharacters";'] opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) # # List with different types of elements @@ -426,8 +427,8 @@ def test_list_sample(self): """ self.data_in = self.list_sample self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;'] - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) def test_list_sample_m(self): """ @@ -436,8 +437,8 @@ def test_list_sample_m(self): self.data_in = self.list_sample self.expected = ['.[0] = "string\\nwith newline\\ncharacters in it";', '.[1] = true;', '.[2] = false;', '.[3] = null;', '.[4] = 42;', '.[5] = 3.14;'] opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) # # Dicts in a list @@ -449,8 +450,8 @@ def test_list_dict(self): """ self.data_in = self.list_of_dicts_sample self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mstring\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mtrue\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mfalse\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mnull\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mint\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mfloat\x1b[0m = \x1b[35m3.14\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mstring\x1b[0m = \x1b[32m"another string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mtrue\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mfalse\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mnull\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mint\x1b[0m = \x1b[35m10001\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mfloat\x1b[0m = \x1b[32m-400.45\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m-6000034\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m999999.854321\x1b[0m;'] - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) def test_list_dict_m(self): """ @@ -459,8 +460,8 @@ def test_list_dict_m(self): self.data_in = self.list_of_dicts_sample self.expected = ['.[0].string = "string\\nwith newline\\ncharacters in it";', '.[0].true = true;', '.[0].false = false;', '.[0].null = null;', '.[0].int = 42;', '.[0].float = 3.14;', '.[0].array[0] = "string\\nwith newline\\ncharacters in it";', '.[0].array[1] = true;', '.[0].array[2] = false;', '.[0].array[3] = null;', '.[0].array[4] = 42;', '.[0].array[5] = 3.14;', '.[1].string = "another string\\nwith newline\\ncharacters in it";', '.[1].true = true;', '.[1].false = false;', '.[1].null = null;', '.[1].int = 10001;', '.[1].float = -400.45;', '.[1].array[0] = "string\\nwith newline\\ncharacters in it";', '.[1].array[1] = true;', '.[1].array[2] = false;', '.[1].array[3] = null;', '.[1].array[4] = -6000034;', '.[1].array[5] = 999999.854321;'] opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) # # lists in list @@ -472,8 +473,8 @@ def test_list_list(self): """ self.data_in = self.list_of_lists_sample self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;", '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"another string\\nwith newline\\ncharacters in it"\x1b[0m;', ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42001\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m-3.14\x1b[0m;"] - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) def test_list_list_m(self): """ @@ -482,8 +483,8 @@ def test_list_list_m(self): self.data_in = self.list_of_lists_sample self.expected = ['.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][0] = "string\\nwith newline\\ncharacters in it";', ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][1] = true;", ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][2] = false;", ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][3] = null;", ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][4] = 42;", ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][5] = 3.14;", '.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][0] = "another string\\nwith newline\\ncharacters in it";', ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][1] = true;", ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][2] = false;", ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][3] = null;", ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][4] = 42001;", ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][5] = -3.14;"] opts.mono = True - jello.cli.create_schema(self.data_in) - self.assertEqual(jello.cli.schema_list, self.expected) + create_schema(self.data_in) + self.assertEqual(jello.lib.schema_list, self.expected) if __name__ == '__main__': diff --git a/tests/test_main.py b/tests/test_main.py index 8d20029..65c2a82 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -7,7 +7,7 @@ import unittest from unittest.mock import patch import jello.cli -from jello.cli import opts +from jello.options import opts THIS_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -34,7 +34,7 @@ def setUp(self): opts.arraybracket_color = None # initialize schema_list - jello.cli.schema_list = [] + jello.lib.schema_list = [] self.jc_a_output = '''{"name": "jc", "version": "1.9.3", "description": "jc cli output JSON conversion tool", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "parser_count": 50, "parsers": [{"name": "airport", "argument": "--airport", "version": "1.0", "description": "airport -I command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["darwin"], "magic_commands": ["airport -I"]}, {"name": "airport_s", "argument": "--airport-s", "version": "1.0", "description": "airport -s command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["darwin"], "magic_commands": ["airport -s"]}, {"name": "arp", "argument": "--arp", "version": "1.2", "description": "arp command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "aix", "freebsd", "darwin"], "magic_commands": ["arp"]}, {"name": "blkid", "argument": "--blkid", "version": "1.0", "description": "blkid command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["blkid"]}, {"name": "crontab", "argument": "--crontab", "version": "1.1", "description": "crontab command and file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"], "magic_commands": ["crontab"]}, {"name": "crontab_u", "argument": "--crontab-u", "version": "1.0", "description": "crontab file parser with user support", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"]}, {"name": "csv", "argument": "--csv", "version": "1.0", "description": "CSV file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "details": "Using the python standard csv library", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"]}, {"name": "df", "argument": "--df", "version": "1.1", "description": "df command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin"], "magic_commands": ["df"]}, {"name": "dig", "argument": "--dig", "version": "1.1", "description": "dig command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "aix", "freebsd", "darwin"], "magic_commands": ["dig"]}, {"name": "du", "argument": "--du", "version": "1.1", "description": "du command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"], "magic_commands": ["du"]}, {"name": "env", "argument": "--env", "version": "1.1", "description": "env command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"], "magic_commands": ["env"]}, {"name": "file", "argument": "--file", "version": "1.1", "description": "file command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "aix", "freebsd", "darwin"], "magic_commands": ["file"]}, {"name": "free", "argument": "--free", "version": "1.0", "description": "free command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["free"]}, {"name": "fstab", "argument": "--fstab", "version": "1.0", "description": "fstab file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"]}, {"name": "group", "argument": "--group", "version": "1.0", "description": "/etc/group file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"]}, {"name": "gshadow", "argument": "--gshadow", "version": "1.0", "description": "/etc/gshadow file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "aix", "freebsd"]}, {"name": "history", "argument": "--history", "version": "1.2", "description": "history command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "details": "Optimizations by https://github.com/philippeitis", "compatible": ["linux", "darwin", "cygwin", "aix", "freebsd"]}, {"name": "hosts", "argument": "--hosts", "version": "1.0", "description": "/etc/hosts file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"]}, {"name": "id", "argument": "--id", "version": "1.0", "description": "id command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"], "magic_commands": ["id"]}, {"name": "ifconfig", "argument": "--ifconfig", "version": "1.5", "description": "ifconfig command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "details": "Using ifconfig-parser package from https://github.com/KnightWhoSayNi/ifconfig-parser", "compatible": ["linux", "aix", "freebsd", "darwin"], "magic_commands": ["ifconfig"]}, {"name": "ini", "argument": "--ini", "version": "1.0", "description": "INI file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "details": "Using configparser from the standard library", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"]}, {"name": "iptables", "argument": "--iptables", "version": "1.1", "description": "iptables command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["iptables"]}, {"name": "jobs", "argument": "--jobs", "version": "1.0", "description": "jobs command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "aix", "freebsd"], "magic_commands": ["jobs"]}, {"name": "last", "argument": "--last", "version": "1.0", "description": "last and lastb command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"], "magic_commands": ["last", "lastb"]}, {"name": "ls", "argument": "--ls", "version": "1.3", "description": "ls command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "aix", "freebsd"], "magic_commands": ["ls"]}, {"name": "lsblk", "argument": "--lsblk", "version": "1.3", "description": "lsblk command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["lsblk"]}, {"name": "lsmod", "argument": "--lsmod", "version": "1.1", "description": "lsmod command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["lsmod"]}, {"name": "lsof", "argument": "--lsof", "version": "1.0", "description": "lsof command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["lsof"]}, {"name": "mount", "argument": "--mount", "version": "1.1", "description": "mount command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin"], "magic_commands": ["mount"]}, {"name": "netstat", "argument": "--netstat", "version": "1.2", "description": "netstat command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["netstat"]}, {"name": "ntpq", "argument": "--ntpq", "version": "1.0", "description": "ntpq -p command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["ntpq"]}, {"name": "passwd", "argument": "--passwd", "version": "1.0", "description": "/etc/passwd file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"]}, {"name": "pip_list", "argument": "--pip-list", "version": "1.0", "description": "pip list command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"], "magic_commands": ["pip list", "pip3 list"]}, {"name": "pip_show", "argument": "--pip-show", "version": "1.0", "description": "pip show command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"], "magic_commands": ["pip show", "pip3 show"]}, {"name": "ps", "argument": "--ps", "version": "1.1", "description": "ps command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "aix", "freebsd"], "magic_commands": ["ps"]}, {"name": "route", "argument": "--route", "version": "1.0", "description": "route command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["route"]}, {"name": "shadow", "argument": "--shadow", "version": "1.0", "description": "/etc/shadow file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"]}, {"name": "ss", "argument": "--ss", "version": "1.0", "description": "ss command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["ss"]}, {"name": "stat", "argument": "--stat", "version": "1.0", "description": "stat command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["stat"]}, {"name": "systemctl", "argument": "--systemctl", "version": "1.0", "description": "systemctl command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["systemctl"]}, {"name": "systemctl_lj", "argument": "--systemctl-lj", "version": "1.0", "description": "systemctl list-jobs command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["systemctl list-jobs"]}, {"name": "systemctl_ls", "argument": "--systemctl-ls", "version": "1.0", "description": "systemctl list-sockets command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["systemctl list-sockets"]}, {"name": "systemctl_luf", "argument": "--systemctl-luf", "version": "1.0", "description": "systemctl list-unit-files command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["systemctl list-unit-files"]}, {"name": "timedatectl", "argument": "--timedatectl", "version": "1.0", "description": "timedatectl status command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["timedatectl", "timedatectl status"]}, {"name": "uname", "argument": "--uname", "version": "1.1", "description": "uname -a command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin"], "magic_commands": ["uname"]}, {"name": "uptime", "argument": "--uptime", "version": "1.0", "description": "uptime command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "aix", "freebsd"], "magic_commands": ["uptime"]}, {"name": "w", "argument": "--w", "version": "1.0", "description": "w command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "aix", "freebsd"], "magic_commands": ["w"]}, {"name": "who", "argument": "--who", "version": "1.0", "description": "who command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "aix", "freebsd"], "magic_commands": ["who"]}, {"name": "xml", "argument": "--xml", "version": "1.0", "description": "XML file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "details": "Using the xmltodict library at https://github.com/martinblech/xmltodict", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"]}, {"name": "yaml", "argument": "--yaml", "version": "1.0", "description": "YAML file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "details": "Using the ruamel.yaml library at https://pypi.org/project/ruamel.yaml", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"]}]}''' From 90a76d34754e7bff9db6c46cf7121741f0c2092d Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 13:34:55 -0700 Subject: [PATCH 12/68] remove options.py --- jello/cli.py | 3 +-- jello/lib.py | 30 ++++++++++++++++++++++++------ jello/options.py | 24 ------------------------ tests/test_create_schema.py | 3 +-- tests/test_main.py | 2 +- 5 files changed, 27 insertions(+), 35 deletions(-) delete mode 100644 jello/options.py diff --git a/jello/cli.py b/jello/cli.py index 93b7079..3ac2c58 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -10,8 +10,7 @@ from pygments.lexers import JsonLexer from pygments.formatters import Terminal256Formatter import jello -from jello.lib import set_env_colors, load_json, create_schema, create_json, pyquery -from jello.options import opts, JelloTheme +from jello.lib import opts, JelloTheme, set_env_colors, load_json, create_schema, create_json, pyquery def ctrlc(signum, frame): diff --git a/jello/lib.py b/jello/lib.py index 70b2e8a..2eb05cb 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -5,10 +5,29 @@ import ast import json from jello.dotmap import DotMap -from jello.options import opts, JelloTheme -schema_list = [] +class opts: + initialize = None + version_info = None + helpme = None + compact = None + nulls = None + raw = None + lines = None + mono = None + schema = None + keyname_color = None + keyword_color = None + number_color = None + string_color = None + arrayid_color = None + arraybracket_color = None + + +class JelloTheme: + """this class will contain the colors dictionary generated from set_env_colors()""" + pass color_map = { @@ -31,6 +50,9 @@ } +schema_list = [] + + def set_env_colors(): """ This function does not return a value. It just updates the JelloTheme.colors dictionary. @@ -343,7 +365,3 @@ def pyquery(data, query): raise ValueError('Reserved key name. Use bracket notation to access this key.') return output - - -if __name__ == '__main__': - main() diff --git a/jello/options.py b/jello/options.py deleted file mode 100644 index 7a671f3..0000000 --- a/jello/options.py +++ /dev/null @@ -1,24 +0,0 @@ -"""jello - query JSON at the command line with python syntax""" - - -class opts: - initialize = None - version_info = None - helpme = None - compact = None - nulls = None - raw = None - lines = None - mono = None - schema = None - keyname_color = None - keyword_color = None - number_color = None - string_color = None - arrayid_color = None - arraybracket_color = None - - -class JelloTheme: - """this class will contain the colors dictionary generated from set_env_colors()""" - pass diff --git a/tests/test_create_schema.py b/tests/test_create_schema.py index eaec5a3..4ebe9c1 100644 --- a/tests/test_create_schema.py +++ b/tests/test_create_schema.py @@ -3,8 +3,7 @@ import unittest import os import jello -from jello.options import opts -from jello.lib import set_env_colors, create_schema +from jello.lib import opts, set_env_colors, create_schema class MyTests(unittest.TestCase): diff --git a/tests/test_main.py b/tests/test_main.py index 65c2a82..1a14f3e 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -7,7 +7,7 @@ import unittest from unittest.mock import patch import jello.cli -from jello.options import opts +from jello.lib import opts THIS_DIR = os.path.dirname(os.path.abspath(__file__)) From 0b6f9546e41efde30876c0b94bebc192e04d02a8 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 13:35:34 -0700 Subject: [PATCH 13/68] add code refactor --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 5784b60..92d639d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ jello changelog 20210610 v1.3.7 - Enhance error handling when a dict method is raised - Enhance exception error messages +- Code refactor to split cli from lib 20210609 v1.3.6 - Documentation fixes for packages and binaries hosting From 5cf6c972619282044a6c56b0ac5feced89d94fd1 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 14:20:24 -0700 Subject: [PATCH 14/68] fix exception formatting for variables with newlines. move JelloTheme under color highlighting branch --- jello/cli.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index 3ac2c58..0e2ea79 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -59,7 +59,10 @@ def helptext(): def format_exception(e=None, list_dict_data='', query='', response='', output=''): - query = str(query).replace('\n', '; ') + list_dict_data = str(list_dict_data).replace('\n', '\\n') + query = str(query).replace('\n', '\\n') + response = str(response).replace('\n', '\\n') + output = str(output).replace('\n', '\\n') e_text = '' if hasattr(e, 'text'): @@ -96,8 +99,6 @@ def main(data=None, query='_'): if data is None: data = get_stdin() - # for debugging - # data = r'''["word", null, false, 1, 3.14, true, "multiple words", false, "words\nwith\nnewlines", 42]''' options = [] long_options = {} @@ -176,16 +177,6 @@ def main(data=None, query='_'): set_env_colors() - # create JelloStyle class with user values from set_env_colors() or default values - # need to do this here (not at global level), otherwise default values will not be updated - class JelloStyle(Style): - styles = { - Name.Tag: f'bold {JelloTheme.colors["key_name"][0]}', # key names - Keyword: f'{JelloTheme.colors["keyword"][0]}', # true, false, null - Number: f'{JelloTheme.colors["number"][0]}', # int, float - String: f'{JelloTheme.colors["string"][0]}' # string - } - # output as a schema if the user desires, otherwise generate JSON or Lines output = '' try: @@ -216,6 +207,16 @@ class JelloStyle(Style): # Print colorized or mono JSON to STDOUT try: if not opts.mono and not opts.raw and sys.stdout.isatty(): + # create JelloStyle class with user values from set_env_colors() or default values + # need to do this here (not at global level), otherwise default values will not be updated + class JelloStyle(Style): + styles = { + Name.Tag: f'bold {JelloTheme.colors["key_name"][0]}', # key names + Keyword: f'{JelloTheme.colors["keyword"][0]}', # true, false, null + Number: f'{JelloTheme.colors["number"][0]}', # int, float + String: f'{JelloTheme.colors["string"][0]}' # string + } + lexer = JsonLexer() formatter = Terminal256Formatter(style=JelloStyle) highlighted_json = highlight(output, lexer, formatter) From 2aadf52217058e43c764baf679220b1a726efe6a Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 15:16:05 -0700 Subject: [PATCH 15/68] reorganize creation and printing of schema to match JSON creation and output steps --- jello/cli.py | 44 ++++++++++++++++++++++++-------------------- tests/test_main.py | 45 ++++++++++++++++++++------------------------- 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index 0e2ea79..448bb8a 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -177,15 +177,14 @@ def main(data=None, query='_'): set_env_colors() - # output as a schema if the user desires, otherwise generate JSON or Lines + # Create schema or JSON/JSON-Lines/Lines output = '' try: if opts.schema: if not sys.stdout.isatty(): opts.mono = True create_schema(response) - print('\n'.join(jello.lib.schema_list)) - sys.exit() + output = '\n'.join(jello.lib.schema_list) else: output = create_json(response) @@ -204,26 +203,31 @@ def main(data=None, query='_'): response: {response} ''')) - # Print colorized or mono JSON to STDOUT + # Print colorized or mono Schema or JSON to STDOUT try: - if not opts.mono and not opts.raw and sys.stdout.isatty(): - # create JelloStyle class with user values from set_env_colors() or default values - # need to do this here (not at global level), otherwise default values will not be updated - class JelloStyle(Style): - styles = { - Name.Tag: f'bold {JelloTheme.colors["key_name"][0]}', # key names - Keyword: f'{JelloTheme.colors["keyword"][0]}', # true, false, null - Number: f'{JelloTheme.colors["number"][0]}', # int, float - String: f'{JelloTheme.colors["string"][0]}' # string - } - - lexer = JsonLexer() - formatter = Terminal256Formatter(style=JelloStyle) - highlighted_json = highlight(output, lexer, formatter) - print(highlighted_json[0:-1]) - else: + if opts.schema: print(output) + else: + if not opts.mono and not opts.raw and sys.stdout.isatty(): + # create JelloStyle class with user values from set_env_colors() or default values + # need to do this here (not at global level), otherwise default values will not be updated + class JelloStyle(Style): + styles = { + Name.Tag: f'bold {JelloTheme.colors["key_name"][0]}', # key names + Keyword: f'{JelloTheme.colors["keyword"][0]}', # true, false, null + Number: f'{JelloTheme.colors["number"][0]}', # int, float + String: f'{JelloTheme.colors["string"][0]}' # string + } + + lexer = JsonLexer() + formatter = Terminal256Formatter(style=JelloStyle) + highlighted_json = highlight(output, lexer, formatter) + print(highlighted_json[0:-1]) + + else: + print(output) + except Exception as e: e, e_text, list_dict_data, query, response, output = format_exception(e, list_dict_data, diff --git a/tests/test_main.py b/tests/test_main.py index 1a14f3e..9e9999b 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1376,11 +1376,10 @@ def test_jc_a_s(self): .parsers[49].compatible[5] = "freebsd"; ''' f = io.StringIO() - with self.assertRaises(SystemExit): - with contextlib.redirect_stdout(f): - testargs = ['jello', '-s'] - with patch.object(sys, 'argv', testargs): - _ = jello.cli.main(data=self.jc_a_output) + with contextlib.redirect_stdout(f): + testargs = ['jello', '-s'] + with patch.object(sys, 'argv', testargs): + _ = jello.cli.main(data=self.jc_a_output) self.assertEqual(f.getvalue(), self.expected) def test_jc_a_parsers(self): @@ -2695,11 +2694,10 @@ def test_jc_a_s_parsers_dot(self): .[49].compatible[5] = "freebsd"; ''' f = io.StringIO() - with self.assertRaises(SystemExit): - with contextlib.redirect_stdout(f): - testargs = ['jello', '-s', '_.parsers'] - with patch.object(sys, 'argv', testargs): - _ = jello.cli.main(data=self.jc_a_output) + with contextlib.redirect_stdout(f): + testargs = ['jello', '-s', '_.parsers'] + with patch.object(sys, 'argv', testargs): + _ = jello.cli.main(data=self.jc_a_output) self.assertEqual(f.getvalue(), self.expected) def test_jc_a_c_parsers(self): @@ -2932,11 +2930,10 @@ def test_jc_a_s_parsers_18_dot(self): .magic_commands[0] = "id"; ''' f = io.StringIO() - with self.assertRaises(SystemExit): - with contextlib.redirect_stdout(f): - testargs = ['jello', '-s', '_.parsers[18]'] - with patch.object(sys, 'argv', testargs): - _ = jello.cli.main(data=self.jc_a_output) + with contextlib.redirect_stdout(f): + testargs = ['jello', '-s', '_.parsers[18]'] + with patch.object(sys, 'argv', testargs): + _ = jello.cli.main(data=self.jc_a_output) self.assertEqual(f.getvalue(), self.expected) def test_jc_a_parsers_18_name(self): @@ -3066,11 +3063,10 @@ def test_jc_a_s_parsers_18_compatible_dot(self): .[3] = "freebsd"; ''' f = io.StringIO() - with self.assertRaises(SystemExit): - with contextlib.redirect_stdout(f): - testargs = ['jello', '-s', '_.parsers[18].compatible'] - with patch.object(sys, 'argv', testargs): - _ = jello.cli.main(data=self.jc_a_output) + with contextlib.redirect_stdout(f): + testargs = ['jello', '-s', '_.parsers[18].compatible'] + with patch.object(sys, 'argv', testargs): + _ = jello.cli.main(data=self.jc_a_output) self.assertEqual(f.getvalue(), self.expected) def test_jc_a_c_parsers_18_compatible(self): @@ -3298,11 +3294,10 @@ def test_twitter_lines_table_schema(self): self.expected = self.twitter_table_output_schema f = io.StringIO() - with self.assertRaises(SystemExit): - with contextlib.redirect_stdout(f): - testargs = ['jello', '-s', self.query] - with patch.object(sys, 'argv', testargs): - _ = jello.cli.main(data=self.twitterdata) + with contextlib.redirect_stdout(f): + testargs = ['jello', '-s', self.query] + with patch.object(sys, 'argv', testargs): + _ = jello.cli.main(data=self.twitterdata) self.assertEqual(f.getvalue(), self.expected) def test_twitter_lines_table_dot(self): From 24908ffaaaa607374349f38664dfbf92b887c460 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 15:24:39 -0700 Subject: [PATCH 16/68] fixup JSON load exception error message --- jello/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index 448bb8a..797ae17 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -152,8 +152,8 @@ def main(data=None, query='_'): list_dict_data = load_json(data) except Exception as e: # can't parse the data. Throw an error and quit - msg = f'''JSON Load Exception: {e} - Cannot parse the data (Not valid JSON or JSON Lines) + msg = f'''JSON Load Exception: Cannot parse the data (Not valid JSON or JSON Lines) + {e} ''' print_error(f'''jello: {msg}''') From 8ada8c78e4808fb0fdbac5fca9e1b0ad541205d8 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 15:30:06 -0700 Subject: [PATCH 17/68] remove unused import --- jello/dotmap.py | 1 - 1 file changed, 1 deletion(-) diff --git a/jello/dotmap.py b/jello/dotmap.py index 034c7e2..396fcfe 100644 --- a/jello/dotmap.py +++ b/jello/dotmap.py @@ -26,7 +26,6 @@ from collections import MutableMapping, Iterable from json import dumps from pprint import pprint -from sys import version_info from inspect import ismethod From 427d1d1231f73ae02f884e13571d68c5bb31cc80 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 15:38:02 -0700 Subject: [PATCH 18/68] add JELLO_COLORS env variable info to readme and remove from Advance Usage --- ADVANCED_USAGE.md | 17 ----------------- README.md | 20 +++++++++++++++++++- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/ADVANCED_USAGE.md b/ADVANCED_USAGE.md index cce39c8..fac458c 100644 --- a/ADVANCED_USAGE.md +++ b/ADVANCED_USAGE.md @@ -61,20 +61,3 @@ jc -a | jello -i 'g("parsers.6.compatible")' "freebsd" ] ``` -## Setting Custom Colors via Environment Variable -In addition to setting custom colors in the `.jelloconf.py` intialization file, you can also set them via the `JELLO_COLORS` environment variable. Any colors set in the environment variable will take precedence over any colors set in the initialization file. - -The `JELLO_COLORS` environment variable takes six comma separated string values in the following format: -``` -JELLO_COLORS=,,,,, -``` -Where colors are: `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `gray`, `brightblack`, `brightred`, `brightgreen`, `brightyellow`, `brightblue`, `brightmagenta`, `brightcyan`, `white`, or `default` - -For example, to set to the default colors: -``` -JELLO_COLORS=blue,brightblack,magenta,green,red,magenta -``` -or -``` -JELLO_COLORS=default,default,default,default,default,default -``` diff --git a/README.md b/README.md index 7bd9b1c..c5b0f3b 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,25 @@ while read -r value; do done < <(cat data.json | jello -rl _.foo) ``` -Here is more [advanced usage](https://github.com/kellyjonbrazil/jello/blob/master/ADVANCED_USAGE.md) information. +### Setting Custom Colors via Environment Variable +Custom colors can be set via the `JELLO_COLORS` environment variable. Any colors set in the environment variable will take precedence over any colors set in the initialization file. (see [Advanced Usage](https://github.com/kellyjonbrazil/jello/blob/master/ADVANCED_USAGE.md)) + +The `JELLO_COLORS` environment variable takes six comma separated string values in the following format: +``` +JELLO_COLORS=,,,,, +``` +Where colors are: `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `gray`, `brightblack`, `brightred`, `brightgreen`, `brightyellow`, `brightblue`, `brightmagenta`, `brightcyan`, `white`, or `default` + +For example, to set to the default colors: +``` +JELLO_COLORS=blue,brightblack,magenta,green,red,magenta +``` +or +``` +JELLO_COLORS=default,default,default,default,default,default +``` + +Here is more [Advanced Usage](https://github.com/kellyjonbrazil/jello/blob/master/ADVANCED_USAGE.md) information. ## Examples: ### Printing the Grep-able Schema From 5257036a0cabec7dbad721381534e2c341c7f88a Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 11 Jun 2021 15:59:29 -0700 Subject: [PATCH 19/68] fixup json lines examples --- README.md | 4 ++-- jello/man/jello.1 | 8 ++++---- man/jello.1 | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c5b0f3b..176cb62 100644 --- a/README.md +++ b/README.md @@ -91,10 +91,10 @@ echo '{"foo":"bar","baz":[1,2,3]}' | jello -l _.baz The `-l` option also allows you to create [JSON Lines](https://jsonlines.org/): ```bash -echo '[{"foo":"bar","baz":[1,2,3]},{"fiz":"boo","buz":[3,4,5]}]' | jello -l +echo '[{"foo":"bar","baz":[1,2,3]},{"fiz":"boo","buz":[4,5,6]}]' | jello -l {"foo":"bar","baz":[1,2,3]} -{"fiz":"boo","buz":[3,4,5]} +{"fiz":"boo","buz":[4,5,6]} ``` You can print a grep-able schema by using the `-s` option: diff --git a/jello/man/jello.1 b/jello/man/jello.1 index 2edbe4b..2951f55 100644 --- a/jello/man/jello.1 +++ b/jello/man/jello.1 @@ -109,17 +109,17 @@ $ echo \[aq]{\[dq]foo\[dq]:\[dq]bar\[dq],\[dq]baz\[dq]:[1,2,3]}\[aq] | jello -l .fi .PP -Create JSON Lines by combining the \fB-c\fP and \fB-l\fP options: +The \fB-l\fP option also allows you to create JSON Lines: .IP .nf -$ echo \[aq][{\[dq]foo\[dq]:\[dq]bar\[dq],\[dq]baz\[dq]:[1,2,3]},{\[dq]foo\[dq]:\[dq]bar\[dq],\[dq]baz\[dq]:[1,2,3]}]\[aq] | jello -cl -{\[dq]foo\[dq]:\[dq]bar\[dq],\[dq]baz\[dq]:[1,2,3]} +$ echo \[aq][{\[dq]foo\[dq]:\[dq]bar\[dq],\[dq]baz\[dq]:[1,2,3]},{\[dq]fiz\[dq]:\[dq]boo\[dq],\[dq]buz\[dq]:[4,5,6]}]\[aq] | jello -l {\[dq]foo\[dq]:\[dq]bar\[dq],\[dq]baz\[dq]:[1,2,3]} +{\[dq]fiz\[dq]:\[dq]boo\[dq],\[dq]buz\[dq]:[4,5,6]} .fi .PP -You can also print a grep-able schema by using the \fB-s\fP option: +You can print a grep-able schema by using the \fB-s\fP option: .IP .nf diff --git a/man/jello.1 b/man/jello.1 index 2edbe4b..2951f55 100644 --- a/man/jello.1 +++ b/man/jello.1 @@ -109,17 +109,17 @@ $ echo \[aq]{\[dq]foo\[dq]:\[dq]bar\[dq],\[dq]baz\[dq]:[1,2,3]}\[aq] | jello -l .fi .PP -Create JSON Lines by combining the \fB-c\fP and \fB-l\fP options: +The \fB-l\fP option also allows you to create JSON Lines: .IP .nf -$ echo \[aq][{\[dq]foo\[dq]:\[dq]bar\[dq],\[dq]baz\[dq]:[1,2,3]},{\[dq]foo\[dq]:\[dq]bar\[dq],\[dq]baz\[dq]:[1,2,3]}]\[aq] | jello -cl -{\[dq]foo\[dq]:\[dq]bar\[dq],\[dq]baz\[dq]:[1,2,3]} +$ echo \[aq][{\[dq]foo\[dq]:\[dq]bar\[dq],\[dq]baz\[dq]:[1,2,3]},{\[dq]fiz\[dq]:\[dq]boo\[dq],\[dq]buz\[dq]:[4,5,6]}]\[aq] | jello -l {\[dq]foo\[dq]:\[dq]bar\[dq],\[dq]baz\[dq]:[1,2,3]} +{\[dq]fiz\[dq]:\[dq]boo\[dq],\[dq]buz\[dq]:[4,5,6]} .fi .PP -You can also print a grep-able schema by using the \fB-s\fP option: +You can print a grep-able schema by using the \fB-s\fP option: .IP .nf From 4e0ef51a6a5104732a14253aa7a2c1b2324389b9 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sat, 12 Jun 2021 19:51:06 -0700 Subject: [PATCH 20/68] print exceptions from print_exception() function --- jello/cli.py | 83 +++++++++++++++++++++------------------------------- 1 file changed, 34 insertions(+), 49 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index 797ae17..f98988c 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -26,12 +26,6 @@ def get_stdin(): return sys.stdin.read() -def print_error(message): - """print error messages to STDERR and quit with error code""" - print(message, file=sys.stderr) - sys.exit(1) - - def helptext(): print(textwrap.dedent('''\ jello: query JSON at the command line with python syntax @@ -58,7 +52,13 @@ def helptext(): sys.exit() -def format_exception(e=None, list_dict_data='', query='', response='', output=''): +def print_error(message): + """print error messages to STDERR and quit with error code""" + print(message, file=sys.stderr) + sys.exit(1) + + +def print_exception(e=None, list_dict_data='', query='', response='', output='', ex_type=''): list_dict_data = str(list_dict_data).replace('\n', '\\n') query = str(query).replace('\n', '\\n') response = str(response).replace('\n', '\\n') @@ -66,7 +66,7 @@ def format_exception(e=None, list_dict_data='', query='', response='', output='' e_text = '' if hasattr(e, 'text'): - e_text = e.text + e_text = e.text.replace('\n', '') if len(str(list_dict_data)) > 70: list_dict_data = str(list_dict_data)[:34] + ' ... ' + str(list_dict_data)[-34:] @@ -80,7 +80,28 @@ def format_exception(e=None, list_dict_data='', query='', response='', output='' if len(str(output)) > 70: output = str(output)[0:34] + ' ... ' + str(output)[-34:] - return e, e_text, list_dict_data, query, response, output + ex_type = ex_type + ' ' or '' + + exception_message = f'jello: {ex_type}Exception: {e.__class__.__name__}\n' + + ex_map = { + 'query': query, + 'data': list_dict_data, + 'response': response, + 'output': output + } + + exception_message += f' {e}\n' + + if e_text: + exception_message += f' {e_text}\n' + + for item_name, item in ex_map.items(): + if item: + exception_message += f' {item_name}: {item}\n' + + print(exception_message, file=sys.stderr) + sys.exit(1) def main(data=None, query='_'): @@ -155,7 +176,7 @@ def main(data=None, query='_'): msg = f'''JSON Load Exception: Cannot parse the data (Not valid JSON or JSON Lines) {e} ''' - print_error(f'''jello: {msg}''') + print_error(f'jello: {msg}') # run the query and check for various errors response = '' @@ -163,17 +184,7 @@ def main(data=None, query='_'): response = pyquery(list_dict_data, query) except Exception as e: - e, e_text, list_dict_data, query, response, output = format_exception(e, - list_dict_data, - query) - - print_error(textwrap.dedent(f'''\ - jello: Query Exception: {e.__class__.__name__} - {e} - {e_text} - query: {query} - data: {list_dict_data} - ''')) + print_exception(e, list_dict_data, query, ex_type='Query') set_env_colors() @@ -189,19 +200,7 @@ def main(data=None, query='_'): output = create_json(response) except Exception as e: - e, e_text, list_dict_data, query, response, output = format_exception(e, - list_dict_data, - query, - response) - - print_error(textwrap.dedent(f'''\ - jello: Formatting Exception: {e.__class__.__name__} - {e} - {e_text} - query: {query} - data: {list_dict_data} - response: {response} - ''')) + print_exception(e, list_dict_data, query, response, ex_type='Formatting') # Print colorized or mono Schema or JSON to STDOUT try: @@ -229,21 +228,7 @@ class JelloStyle(Style): print(output) except Exception as e: - e, e_text, list_dict_data, query, response, output = format_exception(e, - list_dict_data, - query, - response, - output) - - print_error(textwrap.dedent(f'''\ - jello: Output Exception: {e.__class__.__name__} - {e} - {e_text} - query: {query} - data: {list_dict_data} - response: {response} - output: {output} - ''')) + print_exception(e, list_dict_data, query, response, output, ex_type='Output') if __name__ == '__main__': From 3e12d7053dbd792d4e90d202212528da219f6770 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sat, 12 Jun 2021 20:39:45 -0700 Subject: [PATCH 21/68] refactor to use classes --- jello/cli.py | 24 +- jello/lib.py | 467 ++++++++++++++++++------------------ tests/test_create_schema.py | 136 +++++------ 3 files changed, 322 insertions(+), 305 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index f98988c..479eb4e 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -10,7 +10,7 @@ from pygments.lexers import JsonLexer from pygments.formatters import Terminal256Formatter import jello -from jello.lib import opts, JelloTheme, set_env_colors, load_json, create_schema, create_json, pyquery +from jello.lib import opts, JelloTheme, Schema, pyquery, load_json, create_json def ctrlc(signum, frame): @@ -171,6 +171,7 @@ def main(data=None, query='_'): list_dict_data = None try: list_dict_data = load_json(data) + except Exception as e: # can't parse the data. Throw an error and quit msg = f'''JSON Load Exception: Cannot parse the data (Not valid JSON or JSON Lines) @@ -186,16 +187,21 @@ def main(data=None, query='_'): except Exception as e: print_exception(e, list_dict_data, query, ex_type='Query') - set_env_colors() + jello_theme = JelloTheme() + jello_theme.set_env_colors() # Create schema or JSON/JSON-Lines/Lines output = '' try: if opts.schema: + schema = Schema() + schema.colors = jello_theme.colors + if not sys.stdout.isatty(): opts.mono = True - create_schema(response) - output = '\n'.join(jello.lib.schema_list) + + schema.create_schema(response) + output = '\n'.join(schema.schema_list) else: output = create_json(response) @@ -209,14 +215,12 @@ def main(data=None, query='_'): else: if not opts.mono and not opts.raw and sys.stdout.isatty(): - # create JelloStyle class with user values from set_env_colors() or default values - # need to do this here (not at global level), otherwise default values will not be updated class JelloStyle(Style): styles = { - Name.Tag: f'bold {JelloTheme.colors["key_name"][0]}', # key names - Keyword: f'{JelloTheme.colors["keyword"][0]}', # true, false, null - Number: f'{JelloTheme.colors["number"][0]}', # int, float - String: f'{JelloTheme.colors["string"][0]}' # string + Name.Tag: f'bold {jello_theme.colors["key_name"][0]}', # key names + Keyword: f'{jello_theme.colors["keyword"][0]}', # true, false, null + Number: f'{jello_theme.colors["number"][0]}', # int, float + String: f'{jello_theme.colors["string"][0]}' # string } lexer = JsonLexer() diff --git a/jello/lib.py b/jello/lib.py index 2eb05cb..0235c32 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -26,243 +26,173 @@ class opts: class JelloTheme: - """this class will contain the colors dictionary generated from set_env_colors()""" - pass - - -color_map = { - 'black': ('ansiblack', '\33[30m'), - 'red': ('ansired', '\33[31m'), - 'green': ('ansigreen', '\33[32m'), - 'yellow': ('ansiyellow', '\33[33m'), - 'blue': ('ansiblue', '\33[34m'), - 'magenta': ('ansimagenta', '\33[35m'), - 'cyan': ('ansicyan', '\33[36m'), - 'gray': ('ansigray', '\33[37m'), - 'brightblack': ('ansibrightblack', '\33[90m'), - 'brightred': ('ansibrightred', '\33[91m'), - 'brightgreen': ('ansibrightgreen', '\33[92m'), - 'brightyellow': ('ansibrightyellow', '\33[93m'), - 'brightblue': ('ansibrightblue', '\33[94m'), - 'brightmagenta': ('ansibrightmagenta', '\33[95m'), - 'brightcyan': ('ansibrightcyan', '\33[96m'), - 'white': ('ansiwhite', '\33[97m'), -} - - -schema_list = [] - - -def set_env_colors(): - """ - This function does not return a value. It just updates the JelloTheme.colors dictionary. - - Grab custom colors from JELLO_COLORS environment variable and .jelloconf.py file. Individual colors from JELLO_COLORS - take precedence over .jelloconf.py. Individual colors from JELLO_COLORS will fall back to .jelloconf.py or default - if the env variable color is set to 'default' - - JELLO_COLORS env variable takes 6 comma separated string values and should be in the format of: - - JELLO_COLORS=,,,,, - - Where colors are: black, red, green, yellow, blue, magenta, cyan, gray, brightblack, brightred, - brightgreen, brightyellow, brightblue, brightmagenta, brightcyan, white, default - - Default colors: - - JELLO_COLORS=blue,brightblack,magenta,green,red,magenta - or - JELLO_COLORS=default,default,default,default,default,default - - """ - env_colors = os.getenv('JELLO_COLORS') - input_error = False - - if env_colors: - color_list = env_colors.split(',') - - if env_colors and len(color_list) != 6: - input_error = True - - if env_colors: - for color in color_list: - if color not in ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'gray', 'brightblack', 'brightred', - 'brightgreen', 'brightyellow', 'brightblue', 'brightmagenta', 'brightcyan', 'white', 'default']: - input_error = True - else: - color_list = ['default', 'default', 'default', 'default', 'default', 'default'] - - # if there is an issue with the env variable, just set all colors to default and move on - if input_error: - print('jello: Warning: could not parse JELLO_COLORS environment variable\n', file=sys.stderr) - color_list = ['default', 'default', 'default', 'default', 'default', 'default'] - - # Try the color set in the JELLO_COLORS env variable first. If it is set to default, then fall back to .jelloconf.py - # configuration. If nothing is set in jelloconf.py, then use the default colors. - JelloTheme.colors = { - 'key_name': color_map[color_list[0]] if not color_list[0] == 'default' else color_map[opts.keyname_color] if opts.keyname_color else color_map['blue'], - 'keyword': color_map[color_list[1]] if not color_list[1] == 'default' else color_map[opts.keyword_color] if opts.keyword_color else color_map['brightblack'], - 'number': color_map[color_list[2]] if not color_list[2] == 'default' else color_map[opts.number_color] if opts.number_color else color_map['magenta'], - 'string': color_map[color_list[3]] if not color_list[3] == 'default' else color_map[opts.string_color] if opts.string_color else color_map['green'], - 'array_id': color_map[color_list[4]] if not color_list[4] == 'default' else color_map[opts.arrayid_color] if opts.arrayid_color else color_map['red'], - 'array_bracket': color_map[color_list[5]] if not color_list[5] == 'default' else color_map[opts.arraybracket_color] if opts.arraybracket_color else color_map['magenta'] - } - - -def load_json(data): - try: - json_dict = json.loads(data) - except Exception: - # if json.loads fails, assume the data is json lines and parse - json_dict = [json.loads(i) for i in data.splitlines()] - - return json_dict - - -def create_schema(src, path=''): - """ - Creates a grep-able schema representation of the JSON. - - This function is recursive, so output is stored within the schema_list list. Make sure to - initialize schema_list to a blank list and set colors by calling set_env_colors() before - calling this function. - """ - if not opts.mono: - CEND = '\33[0m' - CBOLD = '\33[1m' - CKEYNAME = f'{JelloTheme.colors["key_name"][1]}' - CKEYWORD = f'{JelloTheme.colors["keyword"][1]}' - CNUMBER = f'{JelloTheme.colors["number"][1]}' - CSTRING = f'{JelloTheme.colors["string"][1]}' - CARRAYID = f'{JelloTheme.colors["array_id"][1]}' - CARRAYBRACKET = f'{JelloTheme.colors["array_bracket"][1]}' - - else: - CEND = '' - CBOLD = '' - CKEYNAME = '' - CKEYWORD = '' - CNUMBER = '' - CSTRING = '' - CARRAYID = '' - CARRAYBRACKET = '' - - if isinstance(src, list) and path == '': - for i, item in enumerate(src): - create_schema(item, path=f'.{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') - - elif isinstance(src, list): - for i, item in enumerate(src): - create_schema(item, path=f'{path}.{CBOLD}{CKEYNAME}{src}{CEND}{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') - - elif isinstance(src, dict): - for k, v in src.items(): - if isinstance(v, list): - for i, item in enumerate(v): - create_schema(item, path=f'{path}.{CBOLD}{CKEYNAME}{k}{CEND}{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') - - elif isinstance(v, dict): - if not opts.mono: - k = f'{CBOLD}{CKEYNAME}{k}{CEND}' - create_schema(v, path=f'{path}.{k}') - - else: - k = f'{CBOLD}{CKEYNAME}{k}{CEND}' - val = json.dumps(v, ensure_ascii=False) - if val == 'true' or val == 'false' or val == 'null': - val = f'{CKEYWORD}{val}{CEND}' - elif val.replace('.', '', 1).isdigit(): - val = f'{CNUMBER}{val}{CEND}' - else: - val = f'{CSTRING}{val}{CEND}' - - schema_list.append(f'{path}.{k} = {val};') - - else: - val = json.dumps(src, ensure_ascii=False) - if val == 'true' or val == 'false' or val == 'null': - val = f'{CKEYWORD}{val}{CEND}' - elif val.replace('.', '', 1).isdigit(): - val = f'{CNUMBER}{val}{CEND}' + def __init__(self): + self.colors = { + 'key_name': ('ansiblue', '\33[34m'), + 'keyword': ('ansibrightblack', '\33[90m'), + 'number': ('ansimagenta', '\33[35m'), + 'string': ('ansigreen', '\33[32m'), + 'array_id': ('ansired', '\33[31m'), + 'array_bracket': ('ansimagenta', '\33[35m') + } + + self.color_map = { + 'black': ('ansiblack', '\33[30m'), + 'red': ('ansired', '\33[31m'), + 'green': ('ansigreen', '\33[32m'), + 'yellow': ('ansiyellow', '\33[33m'), + 'blue': ('ansiblue', '\33[34m'), + 'magenta': ('ansimagenta', '\33[35m'), + 'cyan': ('ansicyan', '\33[36m'), + 'gray': ('ansigray', '\33[37m'), + 'brightblack': ('ansibrightblack', '\33[90m'), + 'brightred': ('ansibrightred', '\33[91m'), + 'brightgreen': ('ansibrightgreen', '\33[92m'), + 'brightyellow': ('ansibrightyellow', '\33[93m'), + 'brightblue': ('ansibrightblue', '\33[94m'), + 'brightmagenta': ('ansibrightmagenta', '\33[95m'), + 'brightcyan': ('ansibrightcyan', '\33[96m'), + 'white': ('ansiwhite', '\33[97m'), + } + + def set_env_colors(self): + """ + updates the JelloTheme.colors dictionary. + + Grab custom colors from JELLO_COLORS environment variable and .jelloconf.py file. Individual + colors from JELLO_COLORS take precedence over .jelloconf.py. Individual colors from JELLO_COLORS + will fall back to .jelloconf.py or default if the env variable color is set to 'default' + + JELLO_COLORS env variable takes 6 comma separated string values and should be in the format of: + + JELLO_COLORS=,,,,, + + Where colors are: black, red, green, yellow, blue, magenta, cyan, gray, brightblack, brightred, + brightgreen, brightyellow, brightblue, brightmagenta, brightcyan, white, default + + Default colors: + JELLO_COLORS=blue,brightblack,magenta,green,red,magenta + or + JELLO_COLORS=default,default,default,default,default,default + """ + env_colors = os.getenv('JELLO_COLORS') + input_error = False + + if env_colors: + color_list = env_colors.split(',') + + if env_colors and len(color_list) != 6: + input_error = True + + if env_colors: + for color in color_list: + if color not in ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'gray', 'brightblack', 'brightred', + 'brightgreen', 'brightyellow', 'brightblue', 'brightmagenta', 'brightcyan', 'white', 'default']: + input_error = True else: - val = f'{CSTRING}{val}{CEND}' - - path = path or '.' - - schema_list.append(f'{path} = {val};') - - -def create_json(data): - separators = None - indent = 2 - - if opts.compact or opts.lines: - separators = (',', ':') - indent = None - - if isinstance(data, dict): - return json.dumps(data, separators=separators, indent=indent, ensure_ascii=False) - - if isinstance(data, list): - if not opts.lines: - return json.dumps(data, separators=separators, indent=indent, ensure_ascii=False) - - # check if this list includes lists - list_includes_list = False - for item in data: - if isinstance(item, list): - list_includes_list = True - break - - if opts.lines and list_includes_list: - raise ValueError('Cannot print list of lists as lines. Try normal JSON output.') + color_list = ['default', 'default', 'default', 'default', 'default', 'default'] + + # if there is an issue with the env variable, just set all colors to default and move on + if input_error: + print('jello: Warning: could not parse JELLO_COLORS environment variable\n', file=sys.stderr) + color_list = ['default', 'default', 'default', 'default', 'default', 'default'] + + # Try the color set in the JELLO_COLORS env variable first. If it is set to default, then fall back to + # .jelloconf.py configuration. If nothing is set in jelloconf.py, then use the default colors. + self.colors = { + 'key_name': self.color_map[color_list[0]] if not color_list[0] == 'default' else self.color_map[opts.keyname_color] if opts.keyname_color else self.color_map['blue'], + 'keyword': self.color_map[color_list[1]] if not color_list[1] == 'default' else self.color_map[opts.keyword_color] if opts.keyword_color else self.color_map['brightblack'], + 'number': self.color_map[color_list[2]] if not color_list[2] == 'default' else self.color_map[opts.number_color] if opts.number_color else self.color_map['magenta'], + 'string': self.color_map[color_list[3]] if not color_list[3] == 'default' else self.color_map[opts.string_color] if opts.string_color else self.color_map['green'], + 'array_id': self.color_map[color_list[4]] if not color_list[4] == 'default' else self.color_map[opts.arrayid_color] if opts.arrayid_color else self.color_map['red'], + 'array_bracket': self.color_map[color_list[5]] if not color_list[5] == 'default' else self.color_map[opts.arraybracket_color] if opts.arraybracket_color else self.color_map['magenta'] + } + + +class Schema: + def __init__(self): + self.schema_list = [] + + self.colors = { + 'key_name': ('ansiblue', '\33[34m'), + 'keyword': ('ansibrightblack', '\33[90m'), + 'number': ('ansimagenta', '\33[35m'), + 'string': ('ansigreen', '\33[32m'), + 'array_id': ('ansired', '\33[31m'), + 'array_bracket': ('ansimagenta', '\33[35m') + } + + def create_schema(self, src, path=''): + """ + Creates a grep-able schema representation of the JSON. + + This function is recursive, so output is stored within the schema_list list. Make sure to + initialize schema_list to a blank list and set colors by calling set_env_colors() before + calling this function. + """ + if not opts.mono: + CEND = '\33[0m' + CBOLD = '\33[1m' + CKEYNAME = f'{self.colors["key_name"][1]}' + CKEYWORD = f'{self.colors["keyword"][1]}' + CNUMBER = f'{self.colors["number"][1]}' + CSTRING = f'{self.colors["string"][1]}' + CARRAYID = f'{self.colors["array_id"][1]}' + CARRAYBRACKET = f'{self.colors["array_bracket"][1]}' - # print lines for a flat list else: - flat_list = '' - for entry in data: - if entry is None: - if opts.nulls: - flat_list += 'null\n' - else: - flat_list += '\n' - - elif isinstance(entry, (dict, bool, int, float)): - flat_list += json.dumps(entry, separators=separators, ensure_ascii=False) + '\n' + CEND = '' + CBOLD = '' + CKEYNAME = '' + CKEYWORD = '' + CNUMBER = '' + CSTRING = '' + CARRAYID = '' + CARRAYBRACKET = '' + + if isinstance(src, list) and path == '': + for i, item in enumerate(src): + self.create_schema(item, path=f'.{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') + + elif isinstance(src, list): + for i, item in enumerate(src): + self.create_schema(item, path=f'{path}.{CBOLD}{CKEYNAME}{src}{CEND}{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') + + elif isinstance(src, dict): + for k, v in src.items(): + if isinstance(v, list): + for i, item in enumerate(v): + self.create_schema(item, path=f'{path}.{CBOLD}{CKEYNAME}{k}{CEND}{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') + + elif isinstance(v, dict): + if not opts.mono: + k = f'{CBOLD}{CKEYNAME}{k}{CEND}' + self.create_schema(v, path=f'{path}.{k}') - elif isinstance(entry, str): - # replace \n with \\n here so lines with newlines literally print the \n char - entry = entry.replace('\n', '\\n') - if opts.raw: - flat_list += f'{entry}' + '\n' + else: + k = f'{CBOLD}{CKEYNAME}{k}{CEND}' + val = json.dumps(v, ensure_ascii=False) + if val == 'true' or val == 'false' or val == 'null': + val = f'{CKEYWORD}{val}{CEND}' + elif val.replace('.', '', 1).isdigit(): + val = f'{CNUMBER}{val}{CEND}' else: - flat_list += f'"{entry}"' + '\n' + val = f'{CSTRING}{val}{CEND}' - return flat_list.rstrip() + self.schema_list.append(f'{path}.{k} = {val};') - # naked single item return case - elif data is None: - if opts.nulls: - return 'null' else: - return '' - - elif isinstance(data, (bool, int, float)): - return json.dumps(data, ensure_ascii=False) + val = json.dumps(src, ensure_ascii=False) + if val == 'true' or val == 'false' or val == 'null': + val = f'{CKEYWORD}{val}{CEND}' + elif val.replace('.', '', 1).isdigit(): + val = f'{CNUMBER}{val}{CEND}' + else: + val = f'{CSTRING}{val}{CEND}' - elif isinstance(data, str): - # replace \n with \\n here so lines with newlines literally print the \n char - data = data.replace('\n', '\\n') - if opts.raw: - return f'{data}' - else: - return f'"{data}"' + path = path or '.' - # only non-serializable types are left. Force an exception from json.dumps() - else: - json.dumps(data) - # this code should not run, but just in case something slips by above - raise TypeError(f'Object is not JSON serializable') + self.schema_list.append(f'{path} = {val};') def pyquery(data, query): @@ -365,3 +295,86 @@ def pyquery(data, query): raise ValueError('Reserved key name. Use bracket notation to access this key.') return output + + +def load_json(data): + try: + json_dict = json.loads(data) + except Exception: + # if json.loads fails, assume the data is json lines and parse + json_dict = [json.loads(i) for i in data.splitlines()] + + return json_dict + + +def create_json(data): + separators = None + indent = 2 + + if opts.compact or opts.lines: + separators = (',', ':') + indent = None + + if isinstance(data, dict): + return json.dumps(data, separators=separators, indent=indent, ensure_ascii=False) + + if isinstance(data, list): + if not opts.lines: + return json.dumps(data, separators=separators, indent=indent, ensure_ascii=False) + + # check if this list includes lists + list_includes_list = False + for item in data: + if isinstance(item, list): + list_includes_list = True + break + + if opts.lines and list_includes_list: + raise ValueError('Cannot print list of lists as lines. Try normal JSON output.') + + # print lines for a flat list + else: + flat_list = '' + for entry in data: + if entry is None: + if opts.nulls: + flat_list += 'null\n' + else: + flat_list += '\n' + + elif isinstance(entry, (dict, bool, int, float)): + flat_list += json.dumps(entry, separators=separators, ensure_ascii=False) + '\n' + + elif isinstance(entry, str): + # replace \n with \\n here so lines with newlines literally print the \n char + entry = entry.replace('\n', '\\n') + if opts.raw: + flat_list += f'{entry}' + '\n' + else: + flat_list += f'"{entry}"' + '\n' + + return flat_list.rstrip() + + # naked single item return case + elif data is None: + if opts.nulls: + return 'null' + else: + return '' + + elif isinstance(data, (bool, int, float)): + return json.dumps(data, ensure_ascii=False) + + elif isinstance(data, str): + # replace \n with \\n here so lines with newlines literally print the \n char + data = data.replace('\n', '\\n') + if opts.raw: + return f'{data}' + else: + return f'"{data}"' + + # only non-serializable types are left. Force an exception from json.dumps() + else: + json.dumps(data) + # this code should not run, but just in case something slips by above + raise TypeError(f'Object is not JSON serializable') diff --git a/tests/test_create_schema.py b/tests/test_create_schema.py index 4ebe9c1..25c76ed 100644 --- a/tests/test_create_schema.py +++ b/tests/test_create_schema.py @@ -2,8 +2,7 @@ import unittest import os -import jello -from jello.lib import opts, set_env_colors, create_schema +from jello.lib import opts, JelloTheme, Schema class MyTests(unittest.TestCase): @@ -26,13 +25,14 @@ def setUp(self): opts.arraybracket_color = None # initialize schema_list - jello.lib.schema_list = [] + self.schema = Schema() # initialize JELLO_COLORS env variable os.environ['JELLO_COLORS'] = 'default,default,default,default,default,default' # set the colors - set_env_colors() + self.jello_theme = JelloTheme() + self.jello_theme.set_env_colors() # create samples self.dict_sample = { @@ -127,8 +127,8 @@ def test_true(self): """ self.data_in = True self.expected = '. = \x1b[90mtrue\x1b[0m;' - create_schema(self.data_in) - self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual('\n'.join(self.schema.schema_list), self.expected) def test_true_m(self): """ @@ -137,8 +137,8 @@ def test_true_m(self): self.data_in = True self.expected = '. = true;' opts.mono = True - create_schema(self.data_in) - self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual('\n'.join(self.schema.schema_list), self.expected) # # Naked False @@ -150,8 +150,8 @@ def test_false(self): """ self.data_in = False self.expected = '. = \x1b[90mfalse\x1b[0m;' - create_schema(self.data_in) - self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual('\n'.join(self.schema.schema_list), self.expected) def test_false_m(self): """ @@ -160,8 +160,8 @@ def test_false_m(self): self.data_in = False self.expected = '. = false;' opts.mono = True - create_schema(self.data_in) - self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual('\n'.join(self.schema.schema_list), self.expected) # # Naked null @@ -173,8 +173,8 @@ def test_null(self): """ self.data_in = None self.expected = '. = \x1b[90mnull\x1b[0m;' - create_schema(self.data_in) - self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual('\n'.join(self.schema.schema_list), self.expected) def test_null_m(self): """ @@ -183,8 +183,8 @@ def test_null_m(self): self.data_in = None self.expected = '. = null;' opts.mono = True - create_schema(self.data_in) - self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual('\n'.join(self.schema.schema_list), self.expected) # # naked int @@ -196,8 +196,8 @@ def test_int(self): """ self.data_in = 42 self.expected = '. = \x1b[35m42\x1b[0m;' - create_schema(self.data_in) - self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual('\n'.join(self.schema.schema_list), self.expected) def test_int_m(self): """ @@ -206,8 +206,8 @@ def test_int_m(self): self.data_in = 42 self.expected = '. = 42;' opts.mono = True - create_schema(self.data_in) - self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual('\n'.join(self.schema.schema_list), self.expected) # # naked float @@ -219,8 +219,8 @@ def test_float(self): """ self.data_in = 3.14 self.expected = '. = \x1b[35m3.14\x1b[0m;' - create_schema(self.data_in) - self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual('\n'.join(self.schema.schema_list), self.expected) def test_float_m(self): """ @@ -229,8 +229,8 @@ def test_float_m(self): self.data_in = 3.14 self.expected = '. = 3.14;' opts.mono = True - create_schema(self.data_in) - self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual('\n'.join(self.schema.schema_list), self.expected) # # naked string @@ -242,8 +242,8 @@ def test_string(self): """ self.data_in = '"string with\\nnewline char"' self.expected = '. = \x1b[32m"\\"string with\\\\nnewline char\\""\x1b[0m;' - create_schema(self.data_in) - self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual('\n'.join(self.schema.schema_list), self.expected) def test_string_m(self): """ @@ -252,8 +252,8 @@ def test_string_m(self): self.data_in = '"string with\\nnewline char"' self.expected = '. = "\\"string with\\\\nnewline char\\"";' opts.mono = True - create_schema(self.data_in) - self.assertEqual('\n'.join(jello.lib.schema_list), self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual('\n'.join(self.schema.schema_list), self.expected) # # Naked Dict @@ -265,8 +265,8 @@ def test_dict(self): """ self.data_in = self.dict_sample self.expected = ['.\x1b[1m\x1b[34mstring\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[1m\x1b[34mtrue\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[1m\x1b[34mfalse\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[1m\x1b[34mnull\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[1m\x1b[34mint\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[1m\x1b[34mfloat\x1b[0m = \x1b[35m3.14\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;'] - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) def test_dict_m(self): """ @@ -275,8 +275,8 @@ def test_dict_m(self): self.data_in = self.dict_sample self.expected = ['.string = "string\\nwith newline\\ncharacters in it";', '.true = true;', '.false = false;', '.null = null;', '.int = 42;', '.float = 3.14;', '.array[0] = "string\\nwith newline\\ncharacters in it";', '.array[1] = true;', '.array[2] = false;', '.array[3] = null;', '.array[4] = 42;', '.array[5] = 3.14;'] opts.mono = True - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) # # true in a list @@ -288,8 +288,8 @@ def test_list_true(self): """ self.data_in = [True] self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;'] - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) def test_list_true_m(self): """ @@ -298,8 +298,8 @@ def test_list_true_m(self): self.data_in = [True] self.expected = ['.[0] = true;'] opts.mono = True - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) # # false in a list @@ -311,8 +311,8 @@ def test_list_false(self): """ self.data_in = [False] self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;'] - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) def test_list_false_m(self): """ @@ -321,8 +321,8 @@ def test_list_false_m(self): self.data_in = [False] self.expected = ['.[0] = false;'] opts.mono = True - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) # # null in a list @@ -334,8 +334,8 @@ def test_list_null(self): """ self.data_in = [None] self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;'] - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) def test_list_null_m(self): """ @@ -344,8 +344,8 @@ def test_list_null_m(self): self.data_in = [None] self.expected = ['.[0] = null;'] opts.mono = True - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) # # Int in a list @@ -357,8 +357,8 @@ def test_list_int(self): """ self.data_in = [42] self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;'] - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) def test_list_int_m(self): """ @@ -367,8 +367,8 @@ def test_list_int_m(self): self.data_in = [42] self.expected = ['.[0] = 42;'] opts.mono = True - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) # # Float in a list @@ -380,8 +380,8 @@ def test_list_float(self): """ self.data_in = [3.14] self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;'] - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) def test_list_float_m(self): """ @@ -390,8 +390,8 @@ def test_list_float_m(self): self.data_in = [3.14] self.expected = ['.[0] = 3.14;'] opts.mono = True - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) # # String in a list @@ -403,8 +403,8 @@ def test_list_str(self): """ self.data_in = ['string with spaces\nand newline\ncharacters'] self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string with spaces\\nand newline\\ncharacters"\x1b[0m;'] - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) def test_list_str_m(self): """ @@ -413,8 +413,8 @@ def test_list_str_m(self): self.data_in = ['string with spaces\nand newline\ncharacters'] self.expected = ['.[0] = "string with spaces\\nand newline\\ncharacters";'] opts.mono = True - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) # # List with different types of elements @@ -426,8 +426,8 @@ def test_list_sample(self): """ self.data_in = self.list_sample self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;'] - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) def test_list_sample_m(self): """ @@ -436,8 +436,8 @@ def test_list_sample_m(self): self.data_in = self.list_sample self.expected = ['.[0] = "string\\nwith newline\\ncharacters in it";', '.[1] = true;', '.[2] = false;', '.[3] = null;', '.[4] = 42;', '.[5] = 3.14;'] opts.mono = True - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) # # Dicts in a list @@ -449,8 +449,8 @@ def test_list_dict(self): """ self.data_in = self.list_of_dicts_sample self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mstring\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mtrue\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mfalse\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mnull\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mint\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mfloat\x1b[0m = \x1b[35m3.14\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mstring\x1b[0m = \x1b[32m"another string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mtrue\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mfalse\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mnull\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mint\x1b[0m = \x1b[35m10001\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mfloat\x1b[0m = \x1b[32m-400.45\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m-6000034\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m999999.854321\x1b[0m;'] - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) def test_list_dict_m(self): """ @@ -459,8 +459,8 @@ def test_list_dict_m(self): self.data_in = self.list_of_dicts_sample self.expected = ['.[0].string = "string\\nwith newline\\ncharacters in it";', '.[0].true = true;', '.[0].false = false;', '.[0].null = null;', '.[0].int = 42;', '.[0].float = 3.14;', '.[0].array[0] = "string\\nwith newline\\ncharacters in it";', '.[0].array[1] = true;', '.[0].array[2] = false;', '.[0].array[3] = null;', '.[0].array[4] = 42;', '.[0].array[5] = 3.14;', '.[1].string = "another string\\nwith newline\\ncharacters in it";', '.[1].true = true;', '.[1].false = false;', '.[1].null = null;', '.[1].int = 10001;', '.[1].float = -400.45;', '.[1].array[0] = "string\\nwith newline\\ncharacters in it";', '.[1].array[1] = true;', '.[1].array[2] = false;', '.[1].array[3] = null;', '.[1].array[4] = -6000034;', '.[1].array[5] = 999999.854321;'] opts.mono = True - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) # # lists in list @@ -472,8 +472,8 @@ def test_list_list(self): """ self.data_in = self.list_of_lists_sample self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;", '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"another string\\nwith newline\\ncharacters in it"\x1b[0m;', ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42001\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m-3.14\x1b[0m;"] - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) def test_list_list_m(self): """ @@ -482,8 +482,8 @@ def test_list_list_m(self): self.data_in = self.list_of_lists_sample self.expected = ['.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][0] = "string\\nwith newline\\ncharacters in it";', ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][1] = true;", ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][2] = false;", ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][3] = null;", ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][4] = 42;", ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][5] = 3.14;", '.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][0] = "another string\\nwith newline\\ncharacters in it";', ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][1] = true;", ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][2] = false;", ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][3] = null;", ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][4] = 42001;", ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][5] = -3.14;"] opts.mono = True - create_schema(self.data_in) - self.assertEqual(jello.lib.schema_list, self.expected) + self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.schema_list, self.expected) if __name__ == '__main__': From 5d1ad67828d675ae1eeec978ebd1ef0b2a4742d3 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 13 Jun 2021 11:57:22 -0700 Subject: [PATCH 22/68] bump to 1.4.0 and make pygments library optional --- CHANGELOG | 3 ++- jello/__init__.py | 2 +- jello/cli.py | 20 +++++++++++++------- jello/man/jello.1 | 2 +- man/jello.1 | 2 +- setup.py | 2 +- 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 92d639d..4419164 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,8 +1,9 @@ jello changelog -20210610 v1.3.7 +20210613 v1.4.0 - Enhance error handling when a dict method is raised - Enhance exception error messages +- Pygments library dependency is now optional - Code refactor to split cli from lib 20210609 v1.3.6 diff --git a/jello/__init__.py b/jello/__init__.py index 80034f3..122e1c1 100644 --- a/jello/__init__.py +++ b/jello/__init__.py @@ -1,7 +1,7 @@ """jello - query JSON at the command line with python syntax""" -__version__ = '1.3.7' +__version__ = '1.4.0' AUTHOR = 'Kelly Brazil' WEBSITE = 'https://github.com/kellyjonbrazil/jello' COPYRIGHT = '© 2020-2021 Kelly Brazil' diff --git a/jello/cli.py b/jello/cli.py index 479eb4e..454d3bd 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -4,14 +4,20 @@ import sys import textwrap import signal -from pygments import highlight -from pygments.style import Style -from pygments.token import (Name, Number, String, Keyword) -from pygments.lexers import JsonLexer -from pygments.formatters import Terminal256Formatter import jello from jello.lib import opts, JelloTheme, Schema, pyquery, load_json, create_json +# make pygments import optional +try: + from pygments import highlight + from pygments.style import Style + from pygments.token import (Name, Number, String, Keyword) + from pygments.lexers import JsonLexer + from pygments.formatters import Terminal256Formatter + PYGMENTS_INSTALLED = True +except Exception: + PYGMENTS_INSTALLED = False + def ctrlc(signum, frame): """exit with error on SIGINT""" @@ -197,7 +203,7 @@ def main(data=None, query='_'): schema = Schema() schema.colors = jello_theme.colors - if not sys.stdout.isatty(): + if not sys.stdout.isatty() or not PYGMENTS_INSTALLED: opts.mono = True schema.create_schema(response) @@ -214,7 +220,7 @@ def main(data=None, query='_'): print(output) else: - if not opts.mono and not opts.raw and sys.stdout.isatty(): + if not opts.mono and not opts.raw and sys.stdout.isatty() and PYGMENTS_INSTALLED: class JelloStyle(Style): styles = { Name.Tag: f'bold {jello_theme.colors["key_name"][0]}', # key names diff --git a/jello/man/jello.1 b/jello/man/jello.1 index 2951f55..c8305d5 100644 --- a/jello/man/jello.1 +++ b/jello/man/jello.1 @@ -1,4 +1,4 @@ -.TH jello 1 2021-06-11 1.3.7 "Jello JSON Filter" +.TH jello 1 2021-06-13 1.4.0 "Jello JSON Filter" .SH NAME Jello \- Filter JSON and JSON Lines data with Python syntax .SH SYNOPSIS diff --git a/man/jello.1 b/man/jello.1 index 2951f55..c8305d5 100644 --- a/man/jello.1 +++ b/man/jello.1 @@ -1,4 +1,4 @@ -.TH jello 1 2021-06-11 1.3.7 "Jello JSON Filter" +.TH jello 1 2021-06-13 1.4.0 "Jello JSON Filter" .SH NAME Jello \- Filter JSON and JSON Lines data with Python syntax .SH SYNOPSIS diff --git a/setup.py b/setup.py index 3eade7a..bd1354f 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name='jello', - version='1.3.7', + version='1.4.0', author='Kelly Brazil', author_email='kellyjonbrazil@gmail.com', description='Filter JSON and JSON Lines data with Python syntax.', From b7c4d291f2c414089d5bfae145d0486fc0025c94 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 13 Jun 2021 13:22:42 -0700 Subject: [PATCH 23/68] use opts class to set options --- jello/lib.py | 83 +++++++++++++++++++--------------------------------- 1 file changed, 30 insertions(+), 53 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 0235c32..4af5c3a 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -196,6 +196,10 @@ def create_schema(self, src, path=''): def pyquery(data, query): + '''Sets options and runs the user's query''' + output = None + + # read data into '_' variable # if data is a list of dictionaries, then need to iterate through and convert all dictionaries to DotMap if isinstance(data, list): _ = [DotMap(i, _dynamic=False, _prevent_method_masking=True) if isinstance(i, dict) @@ -207,6 +211,7 @@ def pyquery(data, query): else: _ = data + # read initialization file to set colors, options, and user-defined functions jelloconf = '' conf_file = '' @@ -222,60 +227,32 @@ def pyquery(data, query): except FileNotFoundError: raise FileNotFoundError(f'-i used and initialization file not found: {conf_file}') - query = jelloconf + query - output = None + warn_options = False + warn_colors = False + + i_block = ast.parse(jelloconf, mode='exec') + exec(compile(i_block, '', mode='exec')) + + for option in [opts.compact, opts.raw, opts.lines, opts.nulls, opts.mono, opts.schema]: + if not isinstance(option, bool) and option is not None: + opts.compact = opts.raw = opts.lines = opts.nulls = opts.mono = opts.schema = False + warn_options = True + + for color_config in [opts.keyname_color, opts.keyword_color, opts.number_color, + opts.string_color, opts.arrayid_color, opts.arraybracket_color]: + valid_colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'gray', 'brightblack', 'brightred', + 'brightgreen', 'brightyellow', 'brightblue', 'brightmagenta', 'brightcyan', 'white'] + + if color_config not in valid_colors and color_config is not None: + opts.keyname_color = opts.keyword_color = opts.number_color = opts.string_color = opts.arrayid_color = opts.arraybracket_color = None + warn_colors = True + + if warn_options: + print(f'Jello: Warning: Options must be set to True or False in {conf_file}\n Unsetting all options.\n', file=sys.stderr) - # extract jello options from .jelloconf.py (compact, raw, lines, nulls, mono, and custom colors) - for expr in ast.parse(jelloconf).body: - if isinstance(expr, ast.Assign): - if expr.targets[0].id == 'compact': - opts.compact = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'raw': - opts.raw = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'lines': - opts.lines = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'nulls': - opts.nulls = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'mono': - opts.mono = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'schema': - opts.schema = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'keyname_color': - opts.keyname_color = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'keyword_color': - opts.keyword_color = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'number_color': - opts.number_color = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'string_color': - opts.string_color = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'arrayid_color': - opts.arrayid_color = eval(compile(ast.Expression(expr.value), '', "eval")) - if expr.targets[0].id == 'arraybracket_color': - opts.arraybracket_color = eval(compile(ast.Expression(expr.value), '', "eval")) - - # validate the data in the initialization file - warn_options = False - warn_colors = False - - for option in [opts.compact, opts.raw, opts.lines, opts.nulls, opts.mono, opts.schema]: - if not isinstance(option, bool): - opts.compact = opts.raw = opts.lines = opts.nulls = opts.mono = opts.schema = None - warn_options = True - - for color_config in [opts.keyname_color, opts.keyword_color, opts.number_color, - opts.string_color, opts.arrayid_color, opts.arraybracket_color]: - valid_colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'gray', 'brightblack', 'brightred', - 'brightgreen', 'brightyellow', 'brightblue', 'brightmagenta', 'brightcyan', 'white'] - if color_config not in valid_colors and color_config is not None: - opts.keyname_color = opts.keyword_color = opts.number_color = opts.string_color = opts.arrayid_color = opts.arraybracket_color = None - warn_colors = True - - if warn_options: - print(f'Jello: Warning: Options must be set to True or False in {conf_file}\n Unsetting all options.\n') - - if warn_colors: - valid_colors_string = ', '.join(valid_colors) - print(f'Jello: Warning: Colors must be set to one of: {valid_colors_string} in {conf_file}\n Unsetting all colors.\n') + if warn_colors: + valid_colors_string = ', '.join(valid_colors) + print(f'Jello: Warning: Colors must be set to one of: {valid_colors_string} in {conf_file}\n Unsetting all colors.\n', file=sys.stderr) # run the query block = ast.parse(query, mode='exec') From 355c7bc5bbfc8dbcfca56ee28e39604dbb6cd269 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 13 Jun 2021 13:23:11 -0700 Subject: [PATCH 24/68] update comments --- jello/cli.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jello/cli.py b/jello/cli.py index 454d3bd..69d19f8 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -185,7 +185,7 @@ def main(data=None, query='_'): ''' print_error(f'jello: {msg}') - # run the query and check for various errors + # Read .jelloconf.py (if it exists) and run the query response = '' try: response = pyquery(list_dict_data, query) @@ -193,6 +193,7 @@ def main(data=None, query='_'): except Exception as e: print_exception(e, list_dict_data, query, ex_type='Query') + # Read environment variables to set colors jello_theme = JelloTheme() jello_theme.set_env_colors() From a2d5657b98feddf2fef716b6ed0609754e1f48c0 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 13 Jun 2021 13:23:22 -0700 Subject: [PATCH 25/68] pep8 fixes --- tests/test_pyquery.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_pyquery.py b/tests/test_pyquery.py index 116b5f0..907b63f 100644 --- a/tests/test_pyquery.py +++ b/tests/test_pyquery.py @@ -119,7 +119,7 @@ def test_IndexError(self): """ Test _.foo[99] (IndexError) """ - self.data_in = [1,2,3] + self.data_in = [1, 2, 3] self.query = '_[9]' self.assertRaises(IndexError, jello.cli.pyquery, self.data_in, self.query) @@ -127,7 +127,7 @@ def test_SyntaxError(self): """ Test % (SyntaxError) """ - self.data_in = [1,2,3] + self.data_in = [1, 2, 3] self.query = '%' self.assertRaises(SyntaxError, jello.cli.pyquery, self.data_in, self.query) @@ -143,7 +143,7 @@ def test_AttributeError(self): """ Test _.items() on list (AttributeError) """ - self.data_in = [1,2,3] + self.data_in = [1, 2, 3] self.query = '_.items()' self.assertRaises(AttributeError, jello.cli.pyquery, self.data_in, self.query) From 16f63dd58698ecfa89ee2657a939b9f983557882 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 13 Jun 2021 13:33:41 -0700 Subject: [PATCH 26/68] update docs for setting options/colors in .jelloconf.py --- ADVANCED_USAGE.md | 32 +++++++++++++++++--------------- jello/man/jello.1 | 30 ++++++++++++++++-------------- man/jello.1 | 30 ++++++++++++++++-------------- 3 files changed, 49 insertions(+), 43 deletions(-) diff --git a/ADVANCED_USAGE.md b/ADVANCED_USAGE.md index fac458c..6c85aa2 100644 --- a/ADVANCED_USAGE.md +++ b/ADVANCED_USAGE.md @@ -9,24 +9,26 @@ The file must be named `.jelloconf.py` and must be located in the proper directo - Windows: `%appdata%/` ##### Setting Options -To set `jello` options in the `.jelloconf.py` file, add any of the following and set to `True` or `False`: +To set `jello` options in the `.jelloconf.py` file, import the `jello.lib.opts` class, add any of the following and set to `True` or `False`: ``` -mono = True # -m option -compact = True # -c option -lines = True # -l option -raw = True # -r option -nulls = True # -n option -schema = True # -s option +from jello.lib import opts +opts.mono = True # -m option +opts.compact = True # -c option +opts.lines = True # -l option +opts.raw = True # -r option +opts.nulls = True # -n option +opts.schema = True # -s option ``` ##### Setting Colors -You can customize the colors by setting the following variables to one of the following string values: `'black'`, `'red'`, `'green'`, `'yellow'`, `'blue'`, `'magenta'`, `'cyan'`, `'gray'`, `'brightblack'`, `'brightred'`, `'brightgreen'`, `'brightyellow'`, `'brightblue'`, `'brightmagenta'`, `'brightcyan'`, or `'white'`. -``` -keyname_color = 'blue' # Key names -keyword_color = 'brightblack' # true, false, null -number_color = 'magenta' # integers, floats -string_color = 'green' # strings -arrayid_color = 'red' # array IDs in Schema view -arraybracket_color = 'magenta' # array brackets in Schema view +You can customize the colors by importing the `jello.lib.opts` class and setting the following variables to one of the following string values: `'black'`, `'red'`, `'green'`, `'yellow'`, `'blue'`, `'magenta'`, `'cyan'`, `'gray'`, `'brightblack'`, `'brightred'`, `'brightgreen'`, `'brightyellow'`, `'brightblue'`, `'brightmagenta'`, `'brightcyan'`, or `'white'`. +``` +from jello.lib import opts +opts.keyname_color = 'blue' # Key names +opts.keyword_color = 'brightblack' # true, false, null +opts.number_color = 'magenta' # integers, floats +opts.string_color = 'green' # strings +opts.arrayid_color = 'red' # array IDs in Schema view +opts.arraybracket_color = 'magenta' # array brackets in Schema view ``` > Note: Any colors set via the `JELLO_COLORS` environment variable will take precedence over any color values set in the `.jelloconf.py` configuration file diff --git a/jello/man/jello.1 b/jello/man/jello.1 index c8305d5..a809864 100644 --- a/jello/man/jello.1 +++ b/jello/man/jello.1 @@ -320,28 +320,30 @@ Linux, unix, macOS: \fB\[ti]/\fP Windows: \fB%appdata%/\fP .SS Setting Options .PP -To set jello options in the \fB.jelloconf.py\fP file, add any of the following and set to \fBTrue\fP or \fBFalse\fP: +To set jello options in the \fB.jelloconf.py\fP file, import the \fBjello.lib.opts\fP class, add any of the following and set to \fBTrue\fP or \fBFalse\fP: .IP .nf -mono = True # -m option -compact = True # -c option -lines = True # -l option -raw = True # -r option -nulls = True # -n option -schema = True # -s option +from jello.lib import opts +opts.mono = True # -m option +opts.compact = True # -c option +opts.lines = True # -l option +opts.raw = True # -r option +opts.nulls = True # -n option +opts.schema = True # -s option .fi .SS Setting Colors .PP -You can customize the colors by setting the following variables to one of the following string values: \fBblack\fP, \fBred\fP, \fBgreen\fP, \fByellow\fP, \fBblue\fP, \fBmagenta\fP, \fBcyan\fP, \fBgray\fP, \fBbrightblack\fP, \fBbrightred\fP, \fBbrightgreen\fP, \fBbrightyellow\fP, \fBbrightblue\fP, \fBbrightmagenta\fP, \fBbrightcyan\fP, or \fBwhite\fP. +You can customize the colors by importing the \fBjello.lib.opts\fP class and setting the following variables to one of the following string values: \fBblack\fP, \fBred\fP, \fBgreen\fP, \fByellow\fP, \fBblue\fP, \fBmagenta\fP, \fBcyan\fP, \fBgray\fP, \fBbrightblack\fP, \fBbrightred\fP, \fBbrightgreen\fP, \fBbrightyellow\fP, \fBbrightblue\fP, \fBbrightmagenta\fP, \fBbrightcyan\fP, or \fBwhite\fP. .IP .nf \f[C] -keyname_color = \[aq]blue\[aq] # Key names -keyword_color = \[aq]brightblack\[aq] # true, false, null -number_color = \[aq]magenta\[aq] # integers, floats -string_color = \[aq]green\[aq] # strings -arrayid_color = \[aq]red\[aq] # array IDs in Schema view -arraybracket_color = \[aq]magenta\[aq] # array brackets in Schema view +from jello.lib import opts +opts.keyname_color = \[aq]blue\[aq] # Key names +opts.keyword_color = \[aq]brightblack\[aq] # true, false, null +opts.number_color = \[aq]magenta\[aq] # integers, floats +opts.string_color = \[aq]green\[aq] # strings +opts.arrayid_color = \[aq]red\[aq] # array IDs in Schema view +opts.arraybracket_color = \[aq]magenta\[aq] # array brackets in Schema view \f[R] .fi .RS diff --git a/man/jello.1 b/man/jello.1 index c8305d5..a809864 100644 --- a/man/jello.1 +++ b/man/jello.1 @@ -320,28 +320,30 @@ Linux, unix, macOS: \fB\[ti]/\fP Windows: \fB%appdata%/\fP .SS Setting Options .PP -To set jello options in the \fB.jelloconf.py\fP file, add any of the following and set to \fBTrue\fP or \fBFalse\fP: +To set jello options in the \fB.jelloconf.py\fP file, import the \fBjello.lib.opts\fP class, add any of the following and set to \fBTrue\fP or \fBFalse\fP: .IP .nf -mono = True # -m option -compact = True # -c option -lines = True # -l option -raw = True # -r option -nulls = True # -n option -schema = True # -s option +from jello.lib import opts +opts.mono = True # -m option +opts.compact = True # -c option +opts.lines = True # -l option +opts.raw = True # -r option +opts.nulls = True # -n option +opts.schema = True # -s option .fi .SS Setting Colors .PP -You can customize the colors by setting the following variables to one of the following string values: \fBblack\fP, \fBred\fP, \fBgreen\fP, \fByellow\fP, \fBblue\fP, \fBmagenta\fP, \fBcyan\fP, \fBgray\fP, \fBbrightblack\fP, \fBbrightred\fP, \fBbrightgreen\fP, \fBbrightyellow\fP, \fBbrightblue\fP, \fBbrightmagenta\fP, \fBbrightcyan\fP, or \fBwhite\fP. +You can customize the colors by importing the \fBjello.lib.opts\fP class and setting the following variables to one of the following string values: \fBblack\fP, \fBred\fP, \fBgreen\fP, \fByellow\fP, \fBblue\fP, \fBmagenta\fP, \fBcyan\fP, \fBgray\fP, \fBbrightblack\fP, \fBbrightred\fP, \fBbrightgreen\fP, \fBbrightyellow\fP, \fBbrightblue\fP, \fBbrightmagenta\fP, \fBbrightcyan\fP, or \fBwhite\fP. .IP .nf \f[C] -keyname_color = \[aq]blue\[aq] # Key names -keyword_color = \[aq]brightblack\[aq] # true, false, null -number_color = \[aq]magenta\[aq] # integers, floats -string_color = \[aq]green\[aq] # strings -arrayid_color = \[aq]red\[aq] # array IDs in Schema view -arraybracket_color = \[aq]magenta\[aq] # array brackets in Schema view +from jello.lib import opts +opts.keyname_color = \[aq]blue\[aq] # Key names +opts.keyword_color = \[aq]brightblack\[aq] # true, false, null +opts.number_color = \[aq]magenta\[aq] # integers, floats +opts.string_color = \[aq]green\[aq] # strings +opts.arrayid_color = \[aq]red\[aq] # array IDs in Schema view +opts.arraybracket_color = \[aq]magenta\[aq] # array brackets in Schema view \f[R] .fi .RS From 68fba1b2ae58b26430cf973961b1d0da76e707e7 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 13 Jun 2021 13:45:17 -0700 Subject: [PATCH 27/68] add init file message tip --- ADVANCED_USAGE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ADVANCED_USAGE.md b/ADVANCED_USAGE.md index 6c85aa2..1417d28 100644 --- a/ADVANCED_USAGE.md +++ b/ADVANCED_USAGE.md @@ -63,3 +63,5 @@ jc -a | jello -i 'g("parsers.6.compatible")' "freebsd" ] ``` + +> Tip: Add a line to print a message to STDERR in your `.jelloconf.py` file to show when the initialization file is being used: `print('Running initialization file', file=sys.stderr)` From 71f4799492739bcab035e2a69574cad5e74558f2 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 13 Jun 2021 14:36:57 -0700 Subject: [PATCH 28/68] update comments --- jello/lib.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 4af5c3a..2f6b6f5 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -57,10 +57,10 @@ def __init__(self): def set_env_colors(self): """ - updates the JelloTheme.colors dictionary. + Updates the JelloTheme.colors dictionary. - Grab custom colors from JELLO_COLORS environment variable and .jelloconf.py file. Individual - colors from JELLO_COLORS take precedence over .jelloconf.py. Individual colors from JELLO_COLORS + Grab custom colors from JELLO_COLORS environment variable and opts class set by .jelloconf.py file. + Individual colors from JELLO_COLORS take precedence over .jelloconf.py. Individual colors from JELLO_COLORS will fall back to .jelloconf.py or default if the env variable color is set to 'default' JELLO_COLORS env variable takes 6 comma separated string values and should be in the format of: From 430c9cfee33bef944265dc200464c9a00a3c9103 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 13 Jun 2021 16:06:24 -0700 Subject: [PATCH 29/68] simplify color setting code --- jello/lib.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 2f6b6f5..e597df9 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -27,6 +27,7 @@ class opts: class JelloTheme: def __init__(self): + # default colors self.colors = { 'key_name': ('ansiblue', '\33[34m'), 'keyword': ('ansibrightblack', '\33[90m'), @@ -60,8 +61,8 @@ def set_env_colors(self): Updates the JelloTheme.colors dictionary. Grab custom colors from JELLO_COLORS environment variable and opts class set by .jelloconf.py file. - Individual colors from JELLO_COLORS take precedence over .jelloconf.py. Individual colors from JELLO_COLORS - will fall back to .jelloconf.py or default if the env variable color is set to 'default' + Individual colors from JELLO_COLORS take precedence over .jelloconf.py. Individual colors from + JELLO_COLORS will fall back to .jelloconf.py or default if the env variable color is set to 'default' JELLO_COLORS env variable takes 6 comma separated string values and should be in the format of: @@ -97,15 +98,24 @@ def set_env_colors(self): print('jello: Warning: could not parse JELLO_COLORS environment variable\n', file=sys.stderr) color_list = ['default', 'default', 'default', 'default', 'default', 'default'] - # Try the color set in the JELLO_COLORS env variable first. If it is set to default, then fall back to - # .jelloconf.py configuration. If nothing is set in jelloconf.py, then use the default colors. + # first set colors from opts class or fallback to defaults self.colors = { - 'key_name': self.color_map[color_list[0]] if not color_list[0] == 'default' else self.color_map[opts.keyname_color] if opts.keyname_color else self.color_map['blue'], - 'keyword': self.color_map[color_list[1]] if not color_list[1] == 'default' else self.color_map[opts.keyword_color] if opts.keyword_color else self.color_map['brightblack'], - 'number': self.color_map[color_list[2]] if not color_list[2] == 'default' else self.color_map[opts.number_color] if opts.number_color else self.color_map['magenta'], - 'string': self.color_map[color_list[3]] if not color_list[3] == 'default' else self.color_map[opts.string_color] if opts.string_color else self.color_map['green'], - 'array_id': self.color_map[color_list[4]] if not color_list[4] == 'default' else self.color_map[opts.arrayid_color] if opts.arrayid_color else self.color_map['red'], - 'array_bracket': self.color_map[color_list[5]] if not color_list[5] == 'default' else self.color_map[opts.arraybracket_color] if opts.arraybracket_color else self.color_map['magenta'] + 'key_name': self.color_map[opts.keyname_color] if opts.keyname_color else self.colors['key_name'], + 'keyword': self.color_map[opts.keyword_color] if opts.keyword_color else self.colors['keyword'], + 'number': self.color_map[opts.number_color] if opts.number_color else self.colors['number'], + 'string': self.color_map[opts.string_color] if opts.string_color else self.colors['string'], + 'array_id': self.color_map[opts.arrayid_color] if opts.arrayid_color else self.colors['array_id'], + 'array_bracket': self.color_map[opts.arraybracket_color] if opts.arraybracket_color else self.colors['array_bracket'] + } + + # then set colors from JELLO_COLORS env variable or fallback to existing colors + self.colors = { + 'key_name': self.color_map[color_list[0]] if not color_list[0] == 'default' else self.colors['key_name'], + 'keyword': self.color_map[color_list[1]] if not color_list[1] == 'default' else self.colors['keyword'], + 'number': self.color_map[color_list[2]] if not color_list[2] == 'default' else self.colors['number'], + 'string': self.color_map[color_list[3]] if not color_list[3] == 'default' else self.colors['string'], + 'array_id': self.color_map[color_list[4]] if not color_list[4] == 'default' else self.colors['array_id'], + 'array_bracket': self.color_map[color_list[5]] if not color_list[5] == 'default' else self.colors['array_bracket'] } From d4ac44480d97bfd578e19b1145ff6e29be84f64d Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 13 Jun 2021 16:09:04 -0700 Subject: [PATCH 30/68] update comment --- jello/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jello/lib.py b/jello/lib.py index e597df9..aa2a9ee 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -58,7 +58,7 @@ def __init__(self): def set_env_colors(self): """ - Updates the JelloTheme.colors dictionary. + Updates the JelloTheme.colors dictionary used by the JelloStyle class. Grab custom colors from JELLO_COLORS environment variable and opts class set by .jelloconf.py file. Individual colors from JELLO_COLORS take precedence over .jelloconf.py. Individual colors from From 198244cfc1bd5939ecf5e0f4faa9878a59b20f24 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 13 Jun 2021 16:14:47 -0700 Subject: [PATCH 31/68] shorten set_env_colors to set_colors --- jello/cli.py | 16 ++++++++-------- jello/lib.py | 2 +- tests/test_create_schema.py | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index 69d19f8..d95ffa2 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -193,16 +193,16 @@ def main(data=None, query='_'): except Exception as e: print_exception(e, list_dict_data, query, ex_type='Query') - # Read environment variables to set colors - jello_theme = JelloTheme() - jello_theme.set_env_colors() + # Read environment variables and set colors to be used by Schema and JelloStyle + theme = JelloTheme() + theme.set_colors() # Create schema or JSON/JSON-Lines/Lines output = '' try: if opts.schema: schema = Schema() - schema.colors = jello_theme.colors + schema.colors = theme.colors if not sys.stdout.isatty() or not PYGMENTS_INSTALLED: opts.mono = True @@ -224,10 +224,10 @@ def main(data=None, query='_'): if not opts.mono and not opts.raw and sys.stdout.isatty() and PYGMENTS_INSTALLED: class JelloStyle(Style): styles = { - Name.Tag: f'bold {jello_theme.colors["key_name"][0]}', # key names - Keyword: f'{jello_theme.colors["keyword"][0]}', # true, false, null - Number: f'{jello_theme.colors["number"][0]}', # int, float - String: f'{jello_theme.colors["string"][0]}' # string + Name.Tag: f'bold {theme.colors["key_name"][0]}', # key names + Keyword: f'{theme.colors["keyword"][0]}', # true, false, null + Number: f'{theme.colors["number"][0]}', # int, float + String: f'{theme.colors["string"][0]}' # string } lexer = JsonLexer() diff --git a/jello/lib.py b/jello/lib.py index aa2a9ee..25c31f8 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -56,7 +56,7 @@ def __init__(self): 'white': ('ansiwhite', '\33[97m'), } - def set_env_colors(self): + def set_colors(self): """ Updates the JelloTheme.colors dictionary used by the JelloStyle class. diff --git a/tests/test_create_schema.py b/tests/test_create_schema.py index 25c76ed..09ccc2e 100644 --- a/tests/test_create_schema.py +++ b/tests/test_create_schema.py @@ -32,7 +32,7 @@ def setUp(self): # set the colors self.jello_theme = JelloTheme() - self.jello_theme.set_env_colors() + self.jello_theme.set_colors() # create samples self.dict_sample = { From f0c17348e1200e2e5ec61b2c9b0d98c37a629b12 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 13 Jun 2021 16:21:45 -0700 Subject: [PATCH 32/68] simplify default colors --- jello/lib.py | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 25c31f8..50a25a0 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -26,17 +26,17 @@ class opts: class JelloTheme: - def __init__(self): - # default colors - self.colors = { - 'key_name': ('ansiblue', '\33[34m'), - 'keyword': ('ansibrightblack', '\33[90m'), - 'number': ('ansimagenta', '\33[35m'), - 'string': ('ansigreen', '\33[32m'), - 'array_id': ('ansired', '\33[31m'), - 'array_bracket': ('ansimagenta', '\33[35m') - } + # default colors + colors = { + 'key_name': ('ansiblue', '\33[34m'), + 'keyword': ('ansibrightblack', '\33[90m'), + 'number': ('ansimagenta', '\33[35m'), + 'string': ('ansigreen', '\33[32m'), + 'array_id': ('ansired', '\33[31m'), + 'array_bracket': ('ansimagenta', '\33[35m') + } + def __init__(self): self.color_map = { 'black': ('ansiblack', '\33[30m'), 'red': ('ansired', '\33[31m'), @@ -123,14 +123,8 @@ class Schema: def __init__(self): self.schema_list = [] - self.colors = { - 'key_name': ('ansiblue', '\33[34m'), - 'keyword': ('ansibrightblack', '\33[90m'), - 'number': ('ansimagenta', '\33[35m'), - 'string': ('ansigreen', '\33[32m'), - 'array_id': ('ansired', '\33[31m'), - 'array_bracket': ('ansimagenta', '\33[35m') - } + # default colors + self.colors = JelloTheme.colors def create_schema(self, src, path=''): """ From a654d970193424099f8974140c71aa890d0b88e7 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 13 Jun 2021 16:25:53 -0700 Subject: [PATCH 33/68] move color_map to class variable --- jello/lib.py | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 50a25a0..3b1f3f4 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -36,25 +36,24 @@ class JelloTheme: 'array_bracket': ('ansimagenta', '\33[35m') } - def __init__(self): - self.color_map = { - 'black': ('ansiblack', '\33[30m'), - 'red': ('ansired', '\33[31m'), - 'green': ('ansigreen', '\33[32m'), - 'yellow': ('ansiyellow', '\33[33m'), - 'blue': ('ansiblue', '\33[34m'), - 'magenta': ('ansimagenta', '\33[35m'), - 'cyan': ('ansicyan', '\33[36m'), - 'gray': ('ansigray', '\33[37m'), - 'brightblack': ('ansibrightblack', '\33[90m'), - 'brightred': ('ansibrightred', '\33[91m'), - 'brightgreen': ('ansibrightgreen', '\33[92m'), - 'brightyellow': ('ansibrightyellow', '\33[93m'), - 'brightblue': ('ansibrightblue', '\33[94m'), - 'brightmagenta': ('ansibrightmagenta', '\33[95m'), - 'brightcyan': ('ansibrightcyan', '\33[96m'), - 'white': ('ansiwhite', '\33[97m'), - } + color_map = { + 'black': ('ansiblack', '\33[30m'), + 'red': ('ansired', '\33[31m'), + 'green': ('ansigreen', '\33[32m'), + 'yellow': ('ansiyellow', '\33[33m'), + 'blue': ('ansiblue', '\33[34m'), + 'magenta': ('ansimagenta', '\33[35m'), + 'cyan': ('ansicyan', '\33[36m'), + 'gray': ('ansigray', '\33[37m'), + 'brightblack': ('ansibrightblack', '\33[90m'), + 'brightred': ('ansibrightred', '\33[91m'), + 'brightgreen': ('ansibrightgreen', '\33[92m'), + 'brightyellow': ('ansibrightyellow', '\33[93m'), + 'brightblue': ('ansibrightblue', '\33[94m'), + 'brightmagenta': ('ansibrightmagenta', '\33[95m'), + 'brightcyan': ('ansibrightcyan', '\33[96m'), + 'white': ('ansiwhite', '\33[97m'), + } def set_colors(self): """ From b12b35c56663dfc9ec2973d0ba2aba48b48f91cc Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 14 Jun 2021 07:17:21 -0700 Subject: [PATCH 34/68] Schema inherits colors dict and method from JelloTheme --- jello/cli.py | 15 ++++++--------- jello/lib.py | 11 ++++------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index d95ffa2..0d6e9e3 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -64,7 +64,7 @@ def print_error(message): sys.exit(1) -def print_exception(e=None, list_dict_data='', query='', response='', output='', ex_type=''): +def print_exception(e=None, list_dict_data='', query='', response='', output='', ex_type='Runtime'): list_dict_data = str(list_dict_data).replace('\n', '\\n') query = str(query).replace('\n', '\\n') response = str(response).replace('\n', '\\n') @@ -86,9 +86,7 @@ def print_exception(e=None, list_dict_data='', query='', response='', output='', if len(str(output)) > 70: output = str(output)[0:34] + ' ... ' + str(output)[-34:] - ex_type = ex_type + ' ' or '' - - exception_message = f'jello: {ex_type}Exception: {e.__class__.__name__}\n' + exception_message = f'jello: {ex_type} Exception: {e.__class__.__name__}\n' ex_map = { 'query': query, @@ -193,16 +191,12 @@ def main(data=None, query='_'): except Exception as e: print_exception(e, list_dict_data, query, ex_type='Query') - # Read environment variables and set colors to be used by Schema and JelloStyle - theme = JelloTheme() - theme.set_colors() - # Create schema or JSON/JSON-Lines/Lines output = '' try: if opts.schema: schema = Schema() - schema.colors = theme.colors + schema.set_colors() if not sys.stdout.isatty() or not PYGMENTS_INSTALLED: opts.mono = True @@ -222,6 +216,9 @@ def main(data=None, query='_'): else: if not opts.mono and not opts.raw and sys.stdout.isatty() and PYGMENTS_INSTALLED: + theme = JelloTheme() + theme.set_colors() + class JelloStyle(Style): styles = { Name.Tag: f'bold {theme.colors["key_name"][0]}', # key names diff --git a/jello/lib.py b/jello/lib.py index 3b1f3f4..e32d99b 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -118,20 +118,17 @@ def set_colors(self): } -class Schema: +class Schema(JelloTheme): + '''Inherits colors and set_colors from JelloTheme''' def __init__(self): self.schema_list = [] - # default colors - self.colors = JelloTheme.colors - def create_schema(self, src, path=''): """ Creates a grep-able schema representation of the JSON. - This function is recursive, so output is stored within the schema_list list. Make sure to - initialize schema_list to a blank list and set colors by calling set_env_colors() before - calling this function. + This function is recursive, so output is stored within self.schema_list list. Default colors are + used unles set_colors() is called to change them. """ if not opts.mono: CEND = '\33[0m' From c9c90b1882d7ea378725e2c657da08d223887b3a Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 14 Jun 2021 07:27:37 -0700 Subject: [PATCH 35/68] use schema_text() method instead of join in cli --- jello/cli.py | 3 +-- jello/lib.py | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index 0d6e9e3..f076a6e 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -177,7 +177,6 @@ def main(data=None, query='_'): list_dict_data = load_json(data) except Exception as e: - # can't parse the data. Throw an error and quit msg = f'''JSON Load Exception: Cannot parse the data (Not valid JSON or JSON Lines) {e} ''' @@ -202,7 +201,7 @@ def main(data=None, query='_'): opts.mono = True schema.create_schema(response) - output = '\n'.join(schema.schema_list) + output = schema.schema_text() else: output = create_json(response) diff --git a/jello/lib.py b/jello/lib.py index e32d99b..096bbd2 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -120,9 +120,16 @@ def set_colors(self): class Schema(JelloTheme): '''Inherits colors and set_colors from JelloTheme''' + def __init__(self): self.schema_list = [] + def schema_text(self): + return '\n'.join(self.schema_list) + + def schema_html(self): + return '
'.join(self.schema_list) + def create_schema(self, src, path=''): """ Creates a grep-able schema representation of the JSON. From 139e01199385818173d597bf8975cf9e3d27e39b Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 14 Jun 2021 08:12:06 -0700 Subject: [PATCH 36/68] fixup comments and docstrings --- jello/lib.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 096bbd2..56be97d 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -119,7 +119,7 @@ def set_colors(self): class Schema(JelloTheme): - '''Inherits colors and set_colors from JelloTheme''' + '''Inherits colors and set_colors() from JelloTheme''' def __init__(self): self.schema_list = [] @@ -134,8 +134,8 @@ def create_schema(self, src, path=''): """ Creates a grep-able schema representation of the JSON. - This function is recursive, so output is stored within self.schema_list list. Default colors are - used unles set_colors() is called to change them. + This method is recursive, so output is stored within self.schema_list (list). Default colors are + used unless set_colors() is called to change them. """ if not opts.mono: CEND = '\33[0m' @@ -285,7 +285,7 @@ def load_json(data): try: json_dict = json.loads(data) except Exception: - # if json.loads fails, assume the data is json lines and parse + # if json.loads fails, try loading as json lines json_dict = [json.loads(i) for i in data.splitlines()] return json_dict From ca9fe894b30cefb09c4c3f3117b577647fa99922 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 14 Jun 2021 10:18:35 -0700 Subject: [PATCH 37/68] call schema.set_colors() only if colors are selected. rename helptext() to print_help() --- jello/cli.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index f076a6e..e15305e 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -32,7 +32,7 @@ def get_stdin(): return sys.stdin.read() -def helptext(): +def print_help(): print(textwrap.dedent('''\ jello: query JSON at the command line with python syntax @@ -137,7 +137,7 @@ def main(data=None, query='_'): k, v = arg[2:].split('=') long_options[k] = int(v) except Exception: - helptext() + print_help() else: query = arg @@ -153,7 +153,7 @@ def main(data=None, query='_'): opts.helpme = opts.helpme or 'h' in options if opts.helpme: - helptext() + print_help() if opts.version_info: print(textwrap.dedent(f'''\ @@ -175,7 +175,6 @@ def main(data=None, query='_'): list_dict_data = None try: list_dict_data = load_json(data) - except Exception as e: msg = f'''JSON Load Exception: Cannot parse the data (Not valid JSON or JSON Lines) {e} @@ -186,7 +185,6 @@ def main(data=None, query='_'): response = '' try: response = pyquery(list_dict_data, query) - except Exception as e: print_exception(e, list_dict_data, query, ex_type='Query') @@ -195,13 +193,15 @@ def main(data=None, query='_'): try: if opts.schema: schema = Schema() - schema.set_colors() if not sys.stdout.isatty() or not PYGMENTS_INSTALLED: opts.mono = True + else: + schema.set_colors() schema.create_schema(response) output = schema.schema_text() + else: output = create_json(response) From ad341a592deafa72cb521a09b3928f05e794f71f Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 14 Jun 2021 17:46:29 -0700 Subject: [PATCH 38/68] remove pygments library from cli --- jello/cli.py | 48 ++------ jello/lib.py | 199 ++++++++++++++++++------------- tests/test_create_json.py | 232 ++++++++++++++++++------------------ tests/test_create_schema.py | 31 +++-- 4 files changed, 258 insertions(+), 252 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index e15305e..1e6073e 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -5,18 +5,7 @@ import textwrap import signal import jello -from jello.lib import opts, JelloTheme, Schema, pyquery, load_json, create_json - -# make pygments import optional -try: - from pygments import highlight - from pygments.style import Style - from pygments.token import (Name, Number, String, Keyword) - from pygments.lexers import JsonLexer - from pygments.formatters import Terminal256Formatter - PYGMENTS_INSTALLED = True -except Exception: - PYGMENTS_INSTALLED = False +from jello.lib import opts, load_json, pyquery, Schema, Json def ctrlc(signum, frame): @@ -194,7 +183,7 @@ def main(data=None, query='_'): if opts.schema: schema = Schema() - if not sys.stdout.isatty() or not PYGMENTS_INSTALLED: + if not sys.stdout.isatty(): opts.mono = True else: schema.set_colors() @@ -203,36 +192,21 @@ def main(data=None, query='_'): output = schema.schema_text() else: - output = create_json(response) + json_out = Json() + + if opts.mono or opts.raw or not sys.stdout.isatty(): + output = json_out.create_json(response) + else: + json_out.set_colors() + output = json_out.create_json(response) + output = json_out.color_output(output) except Exception as e: print_exception(e, list_dict_data, query, response, ex_type='Formatting') # Print colorized or mono Schema or JSON to STDOUT try: - if opts.schema: - print(output) - - else: - if not opts.mono and not opts.raw and sys.stdout.isatty() and PYGMENTS_INSTALLED: - theme = JelloTheme() - theme.set_colors() - - class JelloStyle(Style): - styles = { - Name.Tag: f'bold {theme.colors["key_name"][0]}', # key names - Keyword: f'{theme.colors["keyword"][0]}', # true, false, null - Number: f'{theme.colors["number"][0]}', # int, float - String: f'{theme.colors["string"][0]}' # string - } - - lexer = JsonLexer() - formatter = Terminal256Formatter(style=JelloStyle) - highlighted_json = highlight(output, lexer, formatter) - print(highlighted_json[0:-1]) - - else: - print(output) + print(output) except Exception as e: print_exception(e, list_dict_data, query, response, output, ex_type='Output') diff --git a/jello/lib.py b/jello/lib.py index 56be97d..43f1741 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -6,6 +6,17 @@ import json from jello.dotmap import DotMap +# make pygments import optional +try: + from pygments import highlight + from pygments.style import Style + from pygments.token import (Name, Number, String, Keyword) + from pygments.lexers import JsonLexer + from pygments.formatters import Terminal256Formatter + PYGMENTS_INSTALLED = True +except Exception: + PYGMENTS_INSTALLED = False + class opts: initialize = None @@ -137,7 +148,7 @@ def create_schema(self, src, path=''): This method is recursive, so output is stored within self.schema_list (list). Default colors are used unless set_colors() is called to change them. """ - if not opts.mono: + if not opts.mono and PYGMENTS_INSTALLED: CEND = '\33[0m' CBOLD = '\33[1m' CKEYNAME = f'{self.colors["key_name"][1]}' @@ -202,6 +213,109 @@ def create_schema(self, src, path=''): self.schema_list.append(f'{path} = {val};') +class Json(JelloTheme): + '''Inherits colors and set_colors() from JelloTheme''' + + def color_output(self, data): + if not opts.mono and PYGMENTS_INSTALLED: + class JelloStyle(Style): + styles = { + Name.Tag: f'bold {self.colors["key_name"][0]}', # key names + Keyword: f'{self.colors["keyword"][0]}', # true, false, null + Number: f'{self.colors["number"][0]}', # int, float + String: f'{self.colors["string"][0]}' # string + } + + lexer = JsonLexer() + formatter = Terminal256Formatter(style=JelloStyle) + return highlight(data, lexer, formatter)[0:-1] + + else: + return self.output + + def create_json(self, data): + separators = None + indent = 2 + + if opts.compact or opts.lines: + separators = (',', ':') + indent = None + + if isinstance(data, dict): + return json.dumps(data, separators=separators, indent=indent, ensure_ascii=False) + + if isinstance(data, list): + if not opts.lines: + return json.dumps(data, separators=separators, indent=indent, ensure_ascii=False) + + # check if this list includes lists + list_includes_list = False + for item in data: + if isinstance(item, list): + list_includes_list = True + break + + if opts.lines and list_includes_list: + raise ValueError('Cannot print list of lists as lines. Try normal JSON output.') + + # print lines for a flat list + else: + flat_list = '' + for entry in data: + if entry is None: + if opts.nulls: + flat_list += 'null\n' + else: + flat_list += '\n' + + elif isinstance(entry, (dict, bool, int, float)): + flat_list += json.dumps(entry, separators=separators, ensure_ascii=False) + '\n' + + elif isinstance(entry, str): + # replace \n with \\n here so lines with newlines literally print the \n char + entry = entry.replace('\n', '\\n') + if opts.raw: + flat_list += f'{entry}' + '\n' + else: + flat_list += f'"{entry}"' + '\n' + + return flat_list.rstrip() + + # naked single item return case + elif data is None: + if opts.nulls: + return 'null' + else: + return '' + + elif isinstance(data, (bool, int, float)): + return json.dumps(data, ensure_ascii=False) + + elif isinstance(data, str): + # replace \n with \\n here so lines with newlines literally print the \n char + data = data.replace('\n', '\\n') + if opts.raw: + return f'{data}' + else: + return f'"{data}"' + + # only non-serializable types are left. Force an exception from json.dumps() + else: + json.dumps(data) + # this code should not run, but just in case something slips by above + raise TypeError(f'Object is not JSON serializable') + + +def load_json(data): + try: + json_dict = json.loads(data) + except Exception: + # if json.loads fails, try loading as json lines + json_dict = [json.loads(i) for i in data.splitlines()] + + return json_dict + + def pyquery(data, query): '''Sets options and runs the user's query''' output = None @@ -279,86 +393,3 @@ def pyquery(data, query): raise ValueError('Reserved key name. Use bracket notation to access this key.') return output - - -def load_json(data): - try: - json_dict = json.loads(data) - except Exception: - # if json.loads fails, try loading as json lines - json_dict = [json.loads(i) for i in data.splitlines()] - - return json_dict - - -def create_json(data): - separators = None - indent = 2 - - if opts.compact or opts.lines: - separators = (',', ':') - indent = None - - if isinstance(data, dict): - return json.dumps(data, separators=separators, indent=indent, ensure_ascii=False) - - if isinstance(data, list): - if not opts.lines: - return json.dumps(data, separators=separators, indent=indent, ensure_ascii=False) - - # check if this list includes lists - list_includes_list = False - for item in data: - if isinstance(item, list): - list_includes_list = True - break - - if opts.lines and list_includes_list: - raise ValueError('Cannot print list of lists as lines. Try normal JSON output.') - - # print lines for a flat list - else: - flat_list = '' - for entry in data: - if entry is None: - if opts.nulls: - flat_list += 'null\n' - else: - flat_list += '\n' - - elif isinstance(entry, (dict, bool, int, float)): - flat_list += json.dumps(entry, separators=separators, ensure_ascii=False) + '\n' - - elif isinstance(entry, str): - # replace \n with \\n here so lines with newlines literally print the \n char - entry = entry.replace('\n', '\\n') - if opts.raw: - flat_list += f'{entry}' + '\n' - else: - flat_list += f'"{entry}"' + '\n' - - return flat_list.rstrip() - - # naked single item return case - elif data is None: - if opts.nulls: - return 'null' - else: - return '' - - elif isinstance(data, (bool, int, float)): - return json.dumps(data, ensure_ascii=False) - - elif isinstance(data, str): - # replace \n with \\n here so lines with newlines literally print the \n char - data = data.replace('\n', '\\n') - if opts.raw: - return f'{data}' - else: - return f'"{data}"' - - # only non-serializable types are left. Force an exception from json.dumps() - else: - json.dumps(data) - # this code should not run, but just in case something slips by above - raise TypeError(f'Object is not JSON serializable') diff --git a/tests/test_create_json.py b/tests/test_create_json.py index 7b3d6d7..e9e8712 100644 --- a/tests/test_create_json.py +++ b/tests/test_create_json.py @@ -2,8 +2,7 @@ import unittest from collections import OrderedDict -import jello.cli -from jello.cli import opts +from jello.lib import opts, Json class MyTests(unittest.TestCase): @@ -25,6 +24,9 @@ def setUp(self): opts.arrayid_color = None opts.arraybracket_color = None + # initialize Json class + self.json_out = Json() + # create samples self.dict_sample = { 'string': 'string\nwith newline\ncharacters in it', @@ -118,7 +120,7 @@ def test_true(self): """ self.data_in = True self.expected = 'true' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_true_r(self): """ @@ -127,7 +129,7 @@ def test_true_r(self): self.data_in = True self.expected = 'true' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_true_l(self): """ @@ -136,7 +138,7 @@ def test_true_l(self): self.data_in = True self.expected = 'true' opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_true_rl(self): """ @@ -146,7 +148,7 @@ def test_true_rl(self): self.expected = 'true' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # Naked False @@ -158,7 +160,7 @@ def test_false(self): """ self.data_in = False self.expected = 'false' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_false_r(self): """ @@ -167,7 +169,7 @@ def test_false_r(self): self.data_in = False self.expected = 'false' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_false_l(self): """ @@ -176,7 +178,7 @@ def test_false_l(self): self.data_in = False self.expected = 'false' opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_false_rl(self): """ @@ -186,7 +188,7 @@ def test_false_rl(self): self.expected = 'false' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # Naked null @@ -198,7 +200,7 @@ def test_null(self): """ self.data_in = None self.expected = '' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_null_n(self): """ @@ -207,7 +209,7 @@ def test_null_n(self): self.data_in = None self.expected = 'null' opts.nulls = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_null_r(self): """ @@ -216,7 +218,7 @@ def test_null_r(self): self.data_in = None self.expected = '' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_null_rl(self): """ @@ -226,7 +228,7 @@ def test_null_rl(self): self.expected = '' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_null_rln(self): """ @@ -237,7 +239,7 @@ def test_null_rln(self): opts.raw = True opts.lines = True opts.nulls = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # naked int @@ -249,7 +251,7 @@ def test_int(self): """ self.data_in = 42 self.expected = '42' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_int_r(self): """ @@ -258,7 +260,7 @@ def test_int_r(self): self.data_in = 42 self.expected = '42' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_int_l(self): """ @@ -267,7 +269,7 @@ def test_int_l(self): self.data_in = 42 self.expected = '42' opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_int_rl(self): """ @@ -277,7 +279,7 @@ def test_int_rl(self): self.expected = '42' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # naked float @@ -289,7 +291,7 @@ def test_float(self): """ self.data_in = 3.14 self.expected = '3.14' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_float_r(self): """ @@ -298,7 +300,7 @@ def test_float_r(self): self.data_in = 3.14 self.expected = '3.14' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_float_l(self): """ @@ -307,7 +309,7 @@ def test_float_l(self): self.data_in = 3.14 self.expected = '3.14' opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_float_rl(self): """ @@ -317,7 +319,7 @@ def test_float_rl(self): self.expected = '3.14' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # naked string @@ -329,7 +331,7 @@ def test_string(self): """ self.data_in = '"string with\nnewline char"' self.expected = '""string with\\nnewline char""' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_string_r(self): """ @@ -338,7 +340,7 @@ def test_string_r(self): self.data_in = '"string with\nnewline char"' self.expected = '"string with\\nnewline char"' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_string_l(self): """ @@ -347,7 +349,7 @@ def test_string_l(self): self.data_in = '"string with\nnewline char"' self.expected = '""string with\\nnewline char""' opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_string_rl(self): """ @@ -357,7 +359,7 @@ def test_string_rl(self): self.expected = '"string with\\nnewline char"' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # Naked Dict @@ -369,7 +371,7 @@ def test_dict(self): """ self.data_in = self.dict_sample self.expected = '{\n "string": "string\\nwith newline\\ncharacters in it",\n "true": true,\n "false": false,\n "null": null,\n "int": 42,\n "float": 3.14,\n "array": [\n "string\\nwith newline\\ncharacters in it",\n true,\n false,\n null,\n 42,\n 3.14\n ]\n}' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_dict_r(self): """ @@ -378,7 +380,7 @@ def test_dict_r(self): self.data_in = self.dict_sample self.expected = '{\n "string": "string\\nwith newline\\ncharacters in it",\n "true": true,\n "false": false,\n "null": null,\n "int": 42,\n "float": 3.14,\n "array": [\n "string\\nwith newline\\ncharacters in it",\n true,\n false,\n null,\n 42,\n 3.14\n ]\n}' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_dict_l(self): """ @@ -387,7 +389,7 @@ def test_dict_l(self): self.data_in = self.dict_sample self.expected = '{"string":"string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":42,"float":3.14,"array":["string\\nwith newline\\ncharacters in it",true,false,null,42,3.14]}' opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_dict_c(self): """ @@ -396,7 +398,7 @@ def test_dict_c(self): self.data_in = self.dict_sample self.expected = '{"string":"string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":42,"float":3.14,"array":["string\\nwith newline\\ncharacters in it",true,false,null,42,3.14]}' opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_dict_rl(self): """ @@ -406,7 +408,7 @@ def test_dict_rl(self): self.expected = '{"string":"string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":42,"float":3.14,"array":["string\\nwith newline\\ncharacters in it",true,false,null,42,3.14]}' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_dict_cl(self): """ @@ -416,7 +418,7 @@ def test_dict_cl(self): self.expected = '{"string":"string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":42,"float":3.14,"array":["string\\nwith newline\\ncharacters in it",true,false,null,42,3.14]}' opts.compact = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_dict_cr(self): """ @@ -426,7 +428,7 @@ def test_dict_cr(self): self.expected = '{"string":"string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":42,"float":3.14,"array":["string\\nwith newline\\ncharacters in it",true,false,null,42,3.14]}' opts.compact = True opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_dict_crl(self): """ @@ -437,7 +439,7 @@ def test_dict_crl(self): opts.compact = True opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # true in a list @@ -449,7 +451,7 @@ def test_list_true(self): """ self.data_in = [True] self.expected = '[\n true\n]' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_true_c(self): """ @@ -458,7 +460,7 @@ def test_list_true_c(self): self.data_in = [True] self.expected = '[true]' opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_true_r(self): """ @@ -467,7 +469,7 @@ def test_list_true_r(self): self.data_in = [True] self.expected = '[\n true\n]' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_true_l(self): """ @@ -476,7 +478,7 @@ def test_list_true_l(self): self.data_in = [True] self.expected = 'true' opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_true_cl(self): """ @@ -486,7 +488,7 @@ def test_list_true_cl(self): self.expected = 'true' opts.compact = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_true_rl(self): """ @@ -496,7 +498,7 @@ def test_list_true_rl(self): self.expected = 'true' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_true_cr(self): """ @@ -506,7 +508,7 @@ def test_list_true_cr(self): self.expected = '[true]' opts.compact = True opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_true_crl(self): """ @@ -517,7 +519,7 @@ def test_list_true_crl(self): opts.compact = True opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # false in a list @@ -529,7 +531,7 @@ def test_list_false(self): """ self.data_in = [False] self.expected = '[\n false\n]' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_false_c(self): """ @@ -538,7 +540,7 @@ def test_list_false_c(self): self.data_in = [False] self.expected = '[false]' opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_false_r(self): """ @@ -547,7 +549,7 @@ def test_list_false_r(self): self.data_in = [False] self.expected = '[\n false\n]' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_false_l(self): """ @@ -556,7 +558,7 @@ def test_list_false_l(self): self.data_in = [False] self.expected = 'false' opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_false_cl(self): """ @@ -566,7 +568,7 @@ def test_list_false_cl(self): self.expected = 'false' opts.compact = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_false_rl(self): """ @@ -576,7 +578,7 @@ def test_list_false_rl(self): self.expected = 'false' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_false_cr(self): """ @@ -586,7 +588,7 @@ def test_list_false_cr(self): self.expected = '[false]' opts.compact = True opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_false_crl(self): """ @@ -597,7 +599,7 @@ def test_list_false_crl(self): opts.compact = True opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # null in a list @@ -609,7 +611,7 @@ def test_list_null(self): """ self.data_in = [None] self.expected = '[\n null\n]' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_c(self): """ @@ -618,7 +620,7 @@ def test_list_null_c(self): self.data_in = [None] self.expected = '[null]' opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_r(self): """ @@ -627,7 +629,7 @@ def test_list_null_r(self): self.data_in = [None] self.expected = '[\n null\n]' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_l(self): """ @@ -636,7 +638,7 @@ def test_list_null_l(self): self.data_in = [None] self.expected = '' opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_cl(self): """ @@ -646,7 +648,7 @@ def test_list_null_cl(self): self.expected = '' opts.compact = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_rl(self): """ @@ -656,7 +658,7 @@ def test_list_null_rl(self): self.expected = '' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_cr(self): """ @@ -666,7 +668,7 @@ def test_list_null_cr(self): self.expected = '[null]' opts.compact = True opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_crl(self): """ @@ -677,7 +679,7 @@ def test_list_null_crl(self): opts.compact = True opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_n(self): """ @@ -686,7 +688,7 @@ def test_list_null_n(self): self.data_in = [None] self.expected = '[\n null\n]' opts.nulls = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_nc(self): """ @@ -696,7 +698,7 @@ def test_list_null_nc(self): self.expected = '[null]' opts.nulls = True opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_nl(self): """ @@ -706,7 +708,7 @@ def test_list_null_nl(self): self.expected = 'null' opts.nulls = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_nr(self): """ @@ -716,7 +718,7 @@ def test_list_null_nr(self): self.expected = '[\n null\n]' opts.nulls = True opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_ncr(self): """ @@ -727,7 +729,7 @@ def test_list_null_ncr(self): opts.nulls = True opts.compact = True opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_ncl(self): """ @@ -738,7 +740,7 @@ def test_list_null_ncl(self): opts.nulls = True opts.compact = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_nlr(self): """ @@ -749,7 +751,7 @@ def test_list_null_nlr(self): opts.nulls = True opts.lines = True opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_null_nlrc(self): """ @@ -761,7 +763,7 @@ def test_list_null_nlrc(self): opts.lines = True opts.raw = True opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # Int in a list @@ -773,7 +775,7 @@ def test_list_int(self): """ self.data_in = [42] self.expected = '[\n 42\n]' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_int_c(self): """ @@ -782,7 +784,7 @@ def test_list_int_c(self): self.data_in = [42] self.expected = '[42]' opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_int_l(self): """ @@ -791,7 +793,7 @@ def test_list_int_l(self): self.data_in = [42] self.expected = '42' opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_int_r(self): """ @@ -800,7 +802,7 @@ def test_list_int_r(self): self.data_in = [42] self.expected = '[\n 42\n]' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_int_rl(self): """ @@ -810,7 +812,7 @@ def test_list_int_rl(self): self.expected = '42' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_int_cl(self): """ @@ -820,7 +822,7 @@ def test_list_int_cl(self): self.expected = '42' opts.compact = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_int_crl(self): """ @@ -831,7 +833,7 @@ def test_list_int_crl(self): opts.compact = True opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # Float in a list @@ -843,7 +845,7 @@ def test_list_float(self): """ self.data_in = [3.14] self.expected = '[\n 3.14\n]' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_float_c(self): """ @@ -852,7 +854,7 @@ def test_list_float_c(self): self.data_in = [3.14] self.expected = '[3.14]' opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_float_l(self): """ @@ -861,7 +863,7 @@ def test_list_float_l(self): self.data_in = [3.14] self.expected = '3.14' opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_float_r(self): """ @@ -870,7 +872,7 @@ def test_list_float_r(self): self.data_in = [3.14] self.expected = '[\n 3.14\n]' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_float_rl(self): """ @@ -880,7 +882,7 @@ def test_list_float_rl(self): self.expected = '3.14' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_float_rc(self): """ @@ -890,7 +892,7 @@ def test_list_float_rc(self): self.expected = '[3.14]' opts.raw = True opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_float_rcl(self): """ @@ -901,7 +903,7 @@ def test_list_float_rcl(self): opts.raw = True opts.compact = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # String in a list @@ -913,7 +915,7 @@ def test_list_str(self): """ self.data_in = ['string with spaces\nand newline\ncharacters'] self.expected = '[\n "string with spaces\\nand newline\\ncharacters"\n]' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_str_l(self): """ @@ -922,7 +924,7 @@ def test_list_str_l(self): self.data_in = ['string with spaces\nand newline\ncharacters'] self.expected = '"string with spaces\\nand newline\\ncharacters"' opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_str_r(self): """ @@ -931,7 +933,7 @@ def test_list_str_r(self): self.data_in = ['string with spaces\nand newline\ncharacters'] self.expected = '[\n "string with spaces\\nand newline\\ncharacters"\n]' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_str_c(self): """ @@ -940,7 +942,7 @@ def test_list_str_c(self): self.data_in = ['string with spaces\nand newline\ncharacters'] self.expected = '["string with spaces\\nand newline\\ncharacters"]' opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_str_rl(self): """ @@ -950,7 +952,7 @@ def test_list_str_rl(self): self.expected = 'string with spaces\\nand newline\\ncharacters' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_str_rc(self): """ @@ -960,7 +962,7 @@ def test_list_str_rc(self): self.expected = '["string with spaces\\nand newline\\ncharacters"]' opts.raw = True opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_str_cl(self): """ @@ -970,7 +972,7 @@ def test_list_str_cl(self): self.expected = '"string with spaces\\nand newline\\ncharacters"' opts.compact = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_str_crl(self): """ @@ -981,7 +983,7 @@ def test_list_str_crl(self): opts.compact = True opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # List with different types of elements @@ -993,7 +995,7 @@ def test_list_sample(self): """ self.data_in = self.list_sample self.expected = '[\n "string\\nwith newline\\ncharacters in it",\n true,\n false,\n null,\n 42,\n 3.14\n]' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_sample_l(self): """ @@ -1002,7 +1004,7 @@ def test_list_sample_l(self): self.data_in = self.list_sample self.expected = '"string\\nwith newline\\ncharacters in it"\ntrue\nfalse\n\n42\n3.14' opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_sample_r(self): """ @@ -1011,7 +1013,7 @@ def test_list_sample_r(self): self.data_in = self.list_sample self.expected = '[\n "string\\nwith newline\\ncharacters in it",\n true,\n false,\n null,\n 42,\n 3.14\n]' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_sample_c(self): """ @@ -1020,7 +1022,7 @@ def test_list_sample_c(self): self.data_in = self.list_sample self.expected = '["string\\nwith newline\\ncharacters in it",true,false,null,42,3.14]' opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_sample_rl(self): """ @@ -1030,7 +1032,7 @@ def test_list_sample_rl(self): self.expected = 'string\\nwith newline\\ncharacters in it\ntrue\nfalse\n\n42\n3.14' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_sample_rc(self): """ @@ -1040,7 +1042,7 @@ def test_list_sample_rc(self): self.expected = '["string\\nwith newline\\ncharacters in it",true,false,null,42,3.14]' opts.raw = True opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_sample_cl(self): """ @@ -1050,7 +1052,7 @@ def test_list_sample_cl(self): self.expected = '"string\\nwith newline\\ncharacters in it"\ntrue\nfalse\n\n42\n3.14' opts.compact = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_sample_crl(self): """ @@ -1061,7 +1063,7 @@ def test_list_sample_crl(self): opts.compact = True opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # Dicts in a list @@ -1073,7 +1075,7 @@ def test_list_dict(self): """ self.data_in = self.list_of_dicts_sample self.expected = '[\n {\n "string": "string\\nwith newline\\ncharacters in it",\n "true": true,\n "false": false,\n "null": null,\n "int": 42,\n "float": 3.14,\n "array": [\n "string\\nwith newline\\ncharacters in it",\n true,\n false,\n null,\n 42,\n 3.14\n ]\n },\n {\n "string": "another string\\nwith newline\\ncharacters in it",\n "true": true,\n "false": false,\n "null": null,\n "int": 10001,\n "float": -400.45,\n "array": [\n "string\\nwith newline\\ncharacters in it",\n true,\n false,\n null,\n -6000034,\n 999999.854321\n ]\n }\n]' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_dict_c(self): """ @@ -1082,7 +1084,7 @@ def test_list_dict_c(self): self.data_in = self.list_of_dicts_sample self.expected = '[{"string":"string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":42,"float":3.14,"array":["string\\nwith newline\\ncharacters in it",true,false,null,42,3.14]},{"string":"another string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":10001,"float":-400.45,"array":["string\\nwith newline\\ncharacters in it",true,false,null,-6000034,999999.854321]}]' opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_dict_r(self): """ @@ -1091,7 +1093,7 @@ def test_list_dict_r(self): self.data_in = self.list_of_dicts_sample self.expected = '[\n {\n "string": "string\\nwith newline\\ncharacters in it",\n "true": true,\n "false": false,\n "null": null,\n "int": 42,\n "float": 3.14,\n "array": [\n "string\\nwith newline\\ncharacters in it",\n true,\n false,\n null,\n 42,\n 3.14\n ]\n },\n {\n "string": "another string\\nwith newline\\ncharacters in it",\n "true": true,\n "false": false,\n "null": null,\n "int": 10001,\n "float": -400.45,\n "array": [\n "string\\nwith newline\\ncharacters in it",\n true,\n false,\n null,\n -6000034,\n 999999.854321\n ]\n }\n]' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_dict_l(self): """ @@ -1100,7 +1102,7 @@ def test_list_dict_l(self): self.data_in = self.list_of_dicts_sample self.expected = '{"string":"string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":42,"float":3.14,"array":["string\\nwith newline\\ncharacters in it",true,false,null,42,3.14]}\n{"string":"another string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":10001,"float":-400.45,"array":["string\\nwith newline\\ncharacters in it",true,false,null,-6000034,999999.854321]}' opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_dict_cr(self): """ @@ -1110,7 +1112,7 @@ def test_list_dict_cr(self): self.expected = '[{"string":"string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":42,"float":3.14,"array":["string\\nwith newline\\ncharacters in it",true,false,null,42,3.14]},{"string":"another string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":10001,"float":-400.45,"array":["string\\nwith newline\\ncharacters in it",true,false,null,-6000034,999999.854321]}]' opts.compact = True opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_dict_cl(self): """ @@ -1120,7 +1122,7 @@ def test_list_dict_cl(self): self.expected = '{"string":"string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":42,"float":3.14,"array":["string\\nwith newline\\ncharacters in it",true,false,null,42,3.14]}\n{"string":"another string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":10001,"float":-400.45,"array":["string\\nwith newline\\ncharacters in it",true,false,null,-6000034,999999.854321]}' opts.compact = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_dict_rl(self): """ @@ -1130,7 +1132,7 @@ def test_list_dict_rl(self): self.expected = '{"string":"string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":42,"float":3.14,"array":["string\\nwith newline\\ncharacters in it",true,false,null,42,3.14]}\n{"string":"another string\\nwith newline\\ncharacters in it","true":true,"false":false,"null":null,"int":10001,"float":-400.45,"array":["string\\nwith newline\\ncharacters in it",true,false,null,-6000034,999999.854321]}' opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_dict_crl(self): """ @@ -1141,7 +1143,7 @@ def test_list_dict_crl(self): opts.compact = True opts.raw = True opts.lines = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) # # lists in list @@ -1153,7 +1155,7 @@ def test_list_list(self): """ self.data_in = self.list_of_lists_sample self.expected = '[\n [\n "string\\nwith newline\\ncharacters in it",\n true,\n false,\n null,\n 42,\n 3.14\n ],\n [\n "another string\\nwith newline\\ncharacters in it",\n true,\n false,\n null,\n 42001,\n -3.14\n ]\n]' - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_list_c(self): """ @@ -1162,7 +1164,7 @@ def test_list_list_c(self): self.data_in = self.list_of_lists_sample self.expected = '[["string\\nwith newline\\ncharacters in it",true,false,null,42,3.14],["another string\\nwith newline\\ncharacters in it",true,false,null,42001,-3.14]]' opts.compact = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_list_r(self): """ @@ -1171,7 +1173,7 @@ def test_list_list_r(self): self.data_in = self.list_of_lists_sample self.expected = '[\n [\n "string\\nwith newline\\ncharacters in it",\n true,\n false,\n null,\n 42,\n 3.14\n ],\n [\n "another string\\nwith newline\\ncharacters in it",\n true,\n false,\n null,\n 42001,\n -3.14\n ]\n]' opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_list_l(self): """ @@ -1179,7 +1181,7 @@ def test_list_list_l(self): """ self.data_in = self.list_of_lists_sample opts.lines = True - self.assertRaises(ValueError, jello.cli.create_json, self.data_in) + self.assertRaises(ValueError, self.json_out.create_json, self.data_in) def test_list_list_cr(self): """ @@ -1189,7 +1191,7 @@ def test_list_list_cr(self): self.expected = '[["string\\nwith newline\\ncharacters in it",true,false,null,42,3.14],["another string\\nwith newline\\ncharacters in it",true,false,null,42001,-3.14]]' opts.compact = True opts.raw = True - self.assertEqual(jello.cli.create_json(self.data_in), self.expected) + self.assertEqual(self.json_out.create_json(self.data_in), self.expected) def test_list_list_cl(self): """ @@ -1198,7 +1200,7 @@ def test_list_list_cl(self): self.data_in = self.list_of_lists_sample opts.compact = True opts.lines = True - self.assertRaises(ValueError, jello.cli.create_json, self.data_in) + self.assertRaises(ValueError, self.json_out.create_json, self.data_in) def test_list_list_rl(self): """ @@ -1207,7 +1209,7 @@ def test_list_list_rl(self): self.data_in = self.list_of_lists_sample opts.raw = True opts.lines = True - self.assertRaises(ValueError, jello.cli.create_json, self.data_in) + self.assertRaises(ValueError, self.json_out.create_json, self.data_in) def test_list_list_crl(self): """ @@ -1217,14 +1219,14 @@ def test_list_list_crl(self): opts.compact = True opts.raw = True opts.lines = True - self.assertRaises(ValueError, jello.cli.create_json, self.data_in) + self.assertRaises(ValueError, self.json_out.create_json, self.data_in) def test_non_serializable(self): """ Test _.items() """ self.data_in = OrderedDict(foo='bar').items() - self.assertRaises(TypeError, jello.cli.create_json, self.data_in) + self.assertRaises(TypeError, self.json_out.create_json, self.data_in) def test_non_serializable_l(self): """ @@ -1232,7 +1234,7 @@ def test_non_serializable_l(self): """ self.data_in = OrderedDict(foo='bar').items() opts.lines = True - self.assertRaises(TypeError, jello.cli.create_json, self.data_in) + self.assertRaises(TypeError, self.json_out.create_json, self.data_in) if __name__ == '__main__': diff --git a/tests/test_create_schema.py b/tests/test_create_schema.py index 09ccc2e..8dd688d 100644 --- a/tests/test_create_schema.py +++ b/tests/test_create_schema.py @@ -2,7 +2,7 @@ import unittest import os -from jello.lib import opts, JelloTheme, Schema +from jello.lib import opts, Schema class MyTests(unittest.TestCase): @@ -24,15 +24,14 @@ def setUp(self): opts.arrayid_color = None opts.arraybracket_color = None - # initialize schema_list + # initialize schema_lists self.schema = Schema() # initialize JELLO_COLORS env variable os.environ['JELLO_COLORS'] = 'default,default,default,default,default,default' # set the colors - self.jello_theme = JelloTheme() - self.jello_theme.set_colors() + self.schema.set_colors() # create samples self.dict_sample = { @@ -128,7 +127,7 @@ def test_true(self): self.data_in = True self.expected = '. = \x1b[90mtrue\x1b[0m;' self.schema.create_schema(self.data_in) - self.assertEqual('\n'.join(self.schema.schema_list), self.expected) + self.assertEqual(self.schema.schema_text(), self.expected) def test_true_m(self): """ @@ -138,7 +137,7 @@ def test_true_m(self): self.expected = '. = true;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual('\n'.join(self.schema.schema_list), self.expected) + self.assertEqual(self.schema.schema_text(), self.expected) # # Naked False @@ -151,7 +150,7 @@ def test_false(self): self.data_in = False self.expected = '. = \x1b[90mfalse\x1b[0m;' self.schema.create_schema(self.data_in) - self.assertEqual('\n'.join(self.schema.schema_list), self.expected) + self.assertEqual(self.schema.schema_text(), self.expected) def test_false_m(self): """ @@ -161,7 +160,7 @@ def test_false_m(self): self.expected = '. = false;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual('\n'.join(self.schema.schema_list), self.expected) + self.assertEqual(self.schema.schema_text(), self.expected) # # Naked null @@ -174,7 +173,7 @@ def test_null(self): self.data_in = None self.expected = '. = \x1b[90mnull\x1b[0m;' self.schema.create_schema(self.data_in) - self.assertEqual('\n'.join(self.schema.schema_list), self.expected) + self.assertEqual(self.schema.schema_text(), self.expected) def test_null_m(self): """ @@ -184,7 +183,7 @@ def test_null_m(self): self.expected = '. = null;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual('\n'.join(self.schema.schema_list), self.expected) + self.assertEqual(self.schema.schema_text(), self.expected) # # naked int @@ -197,7 +196,7 @@ def test_int(self): self.data_in = 42 self.expected = '. = \x1b[35m42\x1b[0m;' self.schema.create_schema(self.data_in) - self.assertEqual('\n'.join(self.schema.schema_list), self.expected) + self.assertEqual(self.schema.schema_text(), self.expected) def test_int_m(self): """ @@ -207,7 +206,7 @@ def test_int_m(self): self.expected = '. = 42;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual('\n'.join(self.schema.schema_list), self.expected) + self.assertEqual(self.schema.schema_text(), self.expected) # # naked float @@ -220,7 +219,7 @@ def test_float(self): self.data_in = 3.14 self.expected = '. = \x1b[35m3.14\x1b[0m;' self.schema.create_schema(self.data_in) - self.assertEqual('\n'.join(self.schema.schema_list), self.expected) + self.assertEqual(self.schema.schema_text(), self.expected) def test_float_m(self): """ @@ -230,7 +229,7 @@ def test_float_m(self): self.expected = '. = 3.14;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual('\n'.join(self.schema.schema_list), self.expected) + self.assertEqual(self.schema.schema_text(), self.expected) # # naked string @@ -243,7 +242,7 @@ def test_string(self): self.data_in = '"string with\\nnewline char"' self.expected = '. = \x1b[32m"\\"string with\\\\nnewline char\\""\x1b[0m;' self.schema.create_schema(self.data_in) - self.assertEqual('\n'.join(self.schema.schema_list), self.expected) + self.assertEqual(self.schema.schema_text(), self.expected) def test_string_m(self): """ @@ -253,7 +252,7 @@ def test_string_m(self): self.expected = '. = "\\"string with\\\\nnewline char\\"";' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual('\n'.join(self.schema.schema_list), self.expected) + self.assertEqual(self.schema.schema_text(), self.expected) # # Naked Dict From 39d21531cdbe044ec08576cef4a943f3c6cbe93e Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 14 Jun 2021 17:52:15 -0700 Subject: [PATCH 39/68] fix an exception when Pygments is not installed --- jello/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jello/lib.py b/jello/lib.py index 43f1741..34d17c0 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -231,7 +231,7 @@ class JelloStyle(Style): return highlight(data, lexer, formatter)[0:-1] else: - return self.output + return data def create_json(self, data): separators = None From 1e0351fd6dc4f546e640302bb7522d04273ca187 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 14 Jun 2021 18:12:04 -0700 Subject: [PATCH 40/68] don't run schema.set_colors() if opts.mono is set --- jello/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jello/cli.py b/jello/cli.py index 1e6073e..312a06c 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -183,7 +183,7 @@ def main(data=None, query='_'): if opts.schema: schema = Schema() - if not sys.stdout.isatty(): + if opts.mono or not sys.stdout.isatty(): opts.mono = True else: schema.set_colors() From e63b27df9b8245e261d30094a3edd776bb4d1d7c Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 14 Jun 2021 18:31:57 -0700 Subject: [PATCH 41/68] add main gate at the end --- jello/lib.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jello/lib.py b/jello/lib.py index 34d17c0..736de24 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -393,3 +393,7 @@ def pyquery(data, query): raise ValueError('Reserved key name. Use bracket notation to access this key.') return output + + +if __name__ == '__main__': + pass From b9710a97a4f2eae931374ca60b4b811b3ac42222 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 14 Jun 2021 20:45:10 -0700 Subject: [PATCH 42/68] add html_output method --- jello/lib.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jello/lib.py b/jello/lib.py index 736de24..158cf41 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -13,6 +13,7 @@ from pygments.token import (Name, Number, String, Keyword) from pygments.lexers import JsonLexer from pygments.formatters import Terminal256Formatter + from pygments.formatters import HtmlFormatter PYGMENTS_INSTALLED = True except Exception: PYGMENTS_INSTALLED = False @@ -233,6 +234,9 @@ class JelloStyle(Style): else: return data + def html_output(self, data): + return highlight(data, JsonLexer(), HtmlFormatter(noclasses=True)) + def create_json(self, data): separators = None indent = 2 From 715811e6be345d57dde81afd701a131dcf84ab36 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 14 Jun 2021 21:14:17 -0700 Subject: [PATCH 43/68] clarfify dict method item --- CHANGELOG | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4419164..1fab96f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,7 @@ jello changelog -20210613 v1.4.0 -- Enhance error handling when a dict method is raised +20210614 v1.4.0 +- Enhance error handling when a dict method is accessed (e.g. .get) - Enhance exception error messages - Pygments library dependency is now optional - Code refactor to split cli from lib From 251c299f56a8f7b0a7baeeb3cf1e05d78c016db9 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 15 Jun 2021 08:34:50 -0700 Subject: [PATCH 44/68] simplify default colors assignment --- jello/lib.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 158cf41..abc1058 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -38,16 +38,6 @@ class opts: class JelloTheme: - # default colors - colors = { - 'key_name': ('ansiblue', '\33[34m'), - 'keyword': ('ansibrightblack', '\33[90m'), - 'number': ('ansimagenta', '\33[35m'), - 'string': ('ansigreen', '\33[32m'), - 'array_id': ('ansired', '\33[31m'), - 'array_bracket': ('ansimagenta', '\33[35m') - } - color_map = { 'black': ('ansiblack', '\33[30m'), 'red': ('ansired', '\33[31m'), @@ -67,6 +57,16 @@ class JelloTheme: 'white': ('ansiwhite', '\33[97m'), } + # default colors + colors = { + 'key_name': color_map['blue'], + 'keyword': color_map['brightblack'], + 'number': color_map['magenta'], + 'string': color_map['green'], + 'array_id': color_map['red'], + 'array_bracket': color_map['magenta'] + } + def set_colors(self): """ Updates the JelloTheme.colors dictionary used by the JelloStyle class. From 973576f03372b35357423144e349d634db42635a Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 15 Jun 2021 08:46:47 -0700 Subject: [PATCH 45/68] simplify mono logic --- jello/cli.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index 312a06c..024b338 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -183,9 +183,9 @@ def main(data=None, query='_'): if opts.schema: schema = Schema() - if opts.mono or not sys.stdout.isatty(): + if not sys.stdout.isatty(): opts.mono = True - else: + elif not opts.mono: schema.set_colors() schema.create_schema(response) @@ -193,12 +193,10 @@ def main(data=None, query='_'): else: json_out = Json() + output = json_out.create_json(response) - if opts.mono or opts.raw or not sys.stdout.isatty(): - output = json_out.create_json(response) - else: + if not opts.mono and not opts.raw and sys.stdout.isatty(): json_out.set_colors() - output = json_out.create_json(response) output = json_out.color_output(output) except Exception as e: From e58d3d5f117bc97b1a5a513c3fa2b4221d094b46 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 15 Jun 2021 09:35:04 -0700 Subject: [PATCH 46/68] comment update --- jello/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jello/cli.py b/jello/cli.py index 024b338..3cda03b 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -202,7 +202,7 @@ def main(data=None, query='_'): except Exception as e: print_exception(e, list_dict_data, query, response, ex_type='Formatting') - # Print colorized or mono Schema or JSON to STDOUT + # Print colorized or mono Schema or JSON/JSON-Lines/Lines to STDOUT try: print(output) From 77ce6836c07cefd40b0cec0a19c5a17b523bb165 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 15 Jun 2021 10:25:18 -0700 Subject: [PATCH 47/68] move final print to eliminate unneeded exception block and simplify print_exception() code --- jello/cli.py | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index 3cda03b..529e7c0 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -53,35 +53,30 @@ def print_error(message): sys.exit(1) -def print_exception(e=None, list_dict_data='', query='', response='', output='', ex_type='Runtime'): +def print_exception(e=None, list_dict_data='', query='', response='', ex_type='Runtime'): list_dict_data = str(list_dict_data).replace('\n', '\\n') query = str(query).replace('\n', '\\n') response = str(response).replace('\n', '\\n') - output = str(output).replace('\n', '\\n') e_text = '' if hasattr(e, 'text'): e_text = e.text.replace('\n', '') - if len(str(list_dict_data)) > 70: - list_dict_data = str(list_dict_data)[:34] + ' ... ' + str(list_dict_data)[-34:] + if len(list_dict_data) > 70: + list_dict_data = list_dict_data[:34] + ' ... ' + list_dict_data[-34:] - if len(str(query)) > 70: - query = str(query)[:34] + ' ... ' + str(query)[-34:] + if len(query) > 70: + query = query[:34] + ' ... ' + query[-34:] - if len(str(response)) > 70: - response = str(response)[:34] + ' ... ' + str(response)[-34:] - - if len(str(output)) > 70: - output = str(output)[0:34] + ' ... ' + str(output)[-34:] + if len(response) > 70: + response = response[:34] + ' ... ' + response[-34:] exception_message = f'jello: {ex_type} Exception: {e.__class__.__name__}\n' ex_map = { 'query': query, 'data': list_dict_data, - 'response': response, - 'output': output + 'response': response } exception_message += f' {e}\n' @@ -177,7 +172,7 @@ def main(data=None, query='_'): except Exception as e: print_exception(e, list_dict_data, query, ex_type='Query') - # Create schema or JSON/JSON-Lines/Lines + # Create and print schema or JSON/JSON-Lines/Lines output = '' try: if opts.schema: @@ -199,15 +194,10 @@ def main(data=None, query='_'): json_out.set_colors() output = json_out.color_output(output) - except Exception as e: - print_exception(e, list_dict_data, query, response, ex_type='Formatting') - - # Print colorized or mono Schema or JSON/JSON-Lines/Lines to STDOUT - try: print(output) except Exception as e: - print_exception(e, list_dict_data, query, response, output, ex_type='Output') + print_exception(e, list_dict_data, query, response, ex_type='Formatting') if __name__ == '__main__': From a288191af1df54988cde5441d3f2fea6fdc02cd2 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 15 Jun 2021 15:42:53 -0700 Subject: [PATCH 48/68] use pygments to colorize schema --- jello/cli.py | 11 ++-- jello/lib.py | 146 ++++++++++++++++++++++++--------------------------- 2 files changed, 73 insertions(+), 84 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index 529e7c0..eb5d410 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -177,14 +177,13 @@ def main(data=None, query='_'): try: if opts.schema: schema = Schema() + schema.create_schema(response) - if not sys.stdout.isatty(): - opts.mono = True - elif not opts.mono: + if not opts.mono and sys.stdout.isatty(): schema.set_colors() - - schema.create_schema(response) - output = schema.schema_text() + output = schema.color_output() + else: + output = schema.mono_output() else: json_out = Json() diff --git a/jello/lib.py b/jello/lib.py index abc1058..986ae30 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -12,6 +12,7 @@ from pygments.style import Style from pygments.token import (Name, Number, String, Keyword) from pygments.lexers import JsonLexer + from pygments.lexers.javascript import JavascriptLexer from pygments.formatters import Terminal256Formatter from pygments.formatters import HtmlFormatter PYGMENTS_INSTALLED = True @@ -33,28 +34,26 @@ class opts: keyword_color = None number_color = None string_color = None - arrayid_color = None - arraybracket_color = None class JelloTheme: color_map = { - 'black': ('ansiblack', '\33[30m'), - 'red': ('ansired', '\33[31m'), - 'green': ('ansigreen', '\33[32m'), - 'yellow': ('ansiyellow', '\33[33m'), - 'blue': ('ansiblue', '\33[34m'), - 'magenta': ('ansimagenta', '\33[35m'), - 'cyan': ('ansicyan', '\33[36m'), - 'gray': ('ansigray', '\33[37m'), - 'brightblack': ('ansibrightblack', '\33[90m'), - 'brightred': ('ansibrightred', '\33[91m'), - 'brightgreen': ('ansibrightgreen', '\33[92m'), - 'brightyellow': ('ansibrightyellow', '\33[93m'), - 'brightblue': ('ansibrightblue', '\33[94m'), - 'brightmagenta': ('ansibrightmagenta', '\33[95m'), - 'brightcyan': ('ansibrightcyan', '\33[96m'), - 'white': ('ansiwhite', '\33[97m'), + 'black': 'ansiblack', + 'red': 'ansired', + 'green': 'ansigreen', + 'yellow': 'ansiyellow', + 'blue': 'ansiblue', + 'magenta': 'ansimagenta', + 'cyan': 'ansicyan', + 'gray': 'ansigray', + 'brightblack': 'ansibrightblack', + 'brightred': 'ansibrightred', + 'brightgreen': 'ansibrightgreen', + 'brightyellow': 'ansibrightyellow', + 'brightblue': 'ansibrightblue', + 'brightmagenta': 'ansibrightmagenta', + 'brightcyan': 'ansibrightcyan', + 'white': 'ansiwhite', } # default colors @@ -62,9 +61,7 @@ class JelloTheme: 'key_name': color_map['blue'], 'keyword': color_map['brightblack'], 'number': color_map['magenta'], - 'string': color_map['green'], - 'array_id': color_map['red'], - 'array_bracket': color_map['magenta'] + 'string': color_map['green'] } def set_colors(self): @@ -75,17 +72,17 @@ def set_colors(self): Individual colors from JELLO_COLORS take precedence over .jelloconf.py. Individual colors from JELLO_COLORS will fall back to .jelloconf.py or default if the env variable color is set to 'default' - JELLO_COLORS env variable takes 6 comma separated string values and should be in the format of: + JELLO_COLORS env variable takes 4 comma separated string values and should be in the format of: - JELLO_COLORS=,,,,, + JELLO_COLORS=,,, Where colors are: black, red, green, yellow, blue, magenta, cyan, gray, brightblack, brightred, brightgreen, brightyellow, brightblue, brightmagenta, brightcyan, white, default Default colors: - JELLO_COLORS=blue,brightblack,magenta,green,red,magenta + JELLO_COLORS=blue,brightblack,magenta,green or - JELLO_COLORS=default,default,default,default,default,default + JELLO_COLORS=default,default,default,default """ env_colors = os.getenv('JELLO_COLORS') input_error = False @@ -93,7 +90,7 @@ def set_colors(self): if env_colors: color_list = env_colors.split(',') - if env_colors and len(color_list) != 6: + if env_colors and len(color_list) != 4: input_error = True if env_colors: @@ -102,21 +99,19 @@ def set_colors(self): 'brightgreen', 'brightyellow', 'brightblue', 'brightmagenta', 'brightcyan', 'white', 'default']: input_error = True else: - color_list = ['default', 'default', 'default', 'default', 'default', 'default'] + color_list = ['default', 'default', 'default', 'default'] # if there is an issue with the env variable, just set all colors to default and move on if input_error: print('jello: Warning: could not parse JELLO_COLORS environment variable\n', file=sys.stderr) - color_list = ['default', 'default', 'default', 'default', 'default', 'default'] + color_list = ['default', 'default', 'default', 'default'] # first set colors from opts class or fallback to defaults self.colors = { 'key_name': self.color_map[opts.keyname_color] if opts.keyname_color else self.colors['key_name'], 'keyword': self.color_map[opts.keyword_color] if opts.keyword_color else self.colors['keyword'], 'number': self.color_map[opts.number_color] if opts.number_color else self.colors['number'], - 'string': self.color_map[opts.string_color] if opts.string_color else self.colors['string'], - 'array_id': self.color_map[opts.arrayid_color] if opts.arrayid_color else self.colors['array_id'], - 'array_bracket': self.color_map[opts.arraybracket_color] if opts.arraybracket_color else self.colors['array_bracket'] + 'string': self.color_map[opts.string_color] if opts.string_color else self.colors['string'] } # then set colors from JELLO_COLORS env variable or fallback to existing colors @@ -124,9 +119,7 @@ def set_colors(self): 'key_name': self.color_map[color_list[0]] if not color_list[0] == 'default' else self.colors['key_name'], 'keyword': self.color_map[color_list[1]] if not color_list[1] == 'default' else self.colors['keyword'], 'number': self.color_map[color_list[2]] if not color_list[2] == 'default' else self.colors['number'], - 'string': self.color_map[color_list[3]] if not color_list[3] == 'default' else self.colors['string'], - 'array_id': self.color_map[color_list[4]] if not color_list[4] == 'default' else self.colors['array_id'], - 'array_bracket': self.color_map[color_list[5]] if not color_list[5] == 'default' else self.colors['array_bracket'] + 'string': self.color_map[color_list[3]] if not color_list[3] == 'default' else self.colors['string'] } @@ -136,78 +129,76 @@ class Schema(JelloTheme): def __init__(self): self.schema_list = [] - def schema_text(self): + def mono_output(self): return '\n'.join(self.schema_list) - def schema_html(self): - return '
'.join(self.schema_list) + def color_output(self): + data_string = '\n'.join(self.schema_list) - def create_schema(self, src, path=''): - """ - Creates a grep-able schema representation of the JSON. - - This method is recursive, so output is stored within self.schema_list (list). Default colors are - used unless set_colors() is called to change them. - """ if not opts.mono and PYGMENTS_INSTALLED: - CEND = '\33[0m' - CBOLD = '\33[1m' - CKEYNAME = f'{self.colors["key_name"][1]}' - CKEYWORD = f'{self.colors["keyword"][1]}' - CNUMBER = f'{self.colors["number"][1]}' - CSTRING = f'{self.colors["string"][1]}' - CARRAYID = f'{self.colors["array_id"][1]}' - CARRAYBRACKET = f'{self.colors["array_bracket"][1]}' + class JelloStyle(Style): + styles = { + Name: f'bold {self.colors["key_name"]}', # key names + Keyword: f'{self.colors["keyword"]}', # true, false, null + Number: f'{self.colors["number"]}', # int, float + String: f'{self.colors["string"]}' # string + } + + lexer = JavascriptLexer() + formatter = Terminal256Formatter(style=JelloStyle) + return highlight(data_string, lexer, formatter)[0:-1] else: - CEND = '' - CBOLD = '' - CKEYNAME = '' - CKEYWORD = '' - CNUMBER = '' - CSTRING = '' - CARRAYID = '' - CARRAYBRACKET = '' + return data_string + def html_output(self): + data_string = '\n'.join(self.schema_list) + return highlight(data_string, JavascriptLexer(), HtmlFormatter(noclasses=True)) + + def create_schema(self, src, path=''): + """ + Creates a grep-able schema representation of the JSON. + This method is recursive, and output is stored within self.schema_list (list). + """ if isinstance(src, list) and path == '': for i, item in enumerate(src): - self.create_schema(item, path=f'.{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') + self.create_schema(item, path=f'.[{i}]') elif isinstance(src, list): for i, item in enumerate(src): - self.create_schema(item, path=f'{path}.{CBOLD}{CKEYNAME}{src}{CEND}{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') + self.create_schema(item, path=f'{path}.{src}[{i}]') elif isinstance(src, dict): for k, v in src.items(): if isinstance(v, list): for i, item in enumerate(v): - self.create_schema(item, path=f'{path}.{CBOLD}{CKEYNAME}{k}{CEND}{CARRAYBRACKET}[{CEND}{CARRAYID}{i}{CEND}{CARRAYBRACKET}]{CEND}') + self.create_schema(item, path=f'{path}.{k}[{i}]') elif isinstance(v, dict): if not opts.mono: - k = f'{CBOLD}{CKEYNAME}{k}{CEND}' + k = f'{k}' self.create_schema(v, path=f'{path}.{k}') else: - k = f'{CBOLD}{CKEYNAME}{k}{CEND}' + k = f'{k}' val = json.dumps(v, ensure_ascii=False) if val == 'true' or val == 'false' or val == 'null': - val = f'{CKEYWORD}{val}{CEND}' + val = f'{val}' elif val.replace('.', '', 1).isdigit(): - val = f'{CNUMBER}{val}{CEND}' + val = f'{val}' else: - val = f'{CSTRING}{val}{CEND}' + val = f'{val}' self.schema_list.append(f'{path}.{k} = {val};') else: val = json.dumps(src, ensure_ascii=False) if val == 'true' or val == 'false' or val == 'null': - val = f'{CKEYWORD}{val}{CEND}' + val = f'{val}' elif val.replace('.', '', 1).isdigit(): - val = f'{CNUMBER}{val}{CEND}' + val = f'{val}' else: - val = f'{CSTRING}{val}{CEND}' + val = f'{val}' path = path or '.' @@ -221,10 +212,10 @@ def color_output(self, data): if not opts.mono and PYGMENTS_INSTALLED: class JelloStyle(Style): styles = { - Name.Tag: f'bold {self.colors["key_name"][0]}', # key names - Keyword: f'{self.colors["keyword"][0]}', # true, false, null - Number: f'{self.colors["number"][0]}', # int, float - String: f'{self.colors["string"][0]}' # string + Name: f'bold {self.colors["key_name"]}', # key names + Keyword: f'{self.colors["keyword"]}', # true, false, null + Number: f'{self.colors["number"]}', # int, float + String: f'{self.colors["string"]}' # string } lexer = JsonLexer() @@ -363,13 +354,12 @@ def pyquery(data, query): opts.compact = opts.raw = opts.lines = opts.nulls = opts.mono = opts.schema = False warn_options = True - for color_config in [opts.keyname_color, opts.keyword_color, opts.number_color, - opts.string_color, opts.arrayid_color, opts.arraybracket_color]: + for color_config in [opts.keyname_color, opts.keyword_color, opts.number_color, opts.string_color]: valid_colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'gray', 'brightblack', 'brightred', 'brightgreen', 'brightyellow', 'brightblue', 'brightmagenta', 'brightcyan', 'white'] if color_config not in valid_colors and color_config is not None: - opts.keyname_color = opts.keyword_color = opts.number_color = opts.string_color = opts.arrayid_color = opts.arraybracket_color = None + opts.keyname_color = opts.keyword_color = opts.number_color = opts.string_color = None warn_colors = True if warn_options: From f35b1188f859882376a665f9750a3458a9e50c27 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 15 Jun 2021 20:07:19 -0700 Subject: [PATCH 49/68] add schema type annotation option. make pygments theme optional with new refactor --- CHANGELOG | 1 + README.md | 9 ++-- jello/cli.py | 2 + jello/lib.py | 105 +++++++++++++++++++++--------------- jello/man/jello.1 | 15 +++--- man/jello.1 | 15 +++--- tests/test_create_json.py | 3 +- tests/test_create_schema.py | 3 +- tests/test_main.py | 3 +- tests/test_pyquery.py | 3 +- 10 files changed, 90 insertions(+), 69 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1fab96f..d3f9e02 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ jello changelog 20210614 v1.4.0 +- Add type annotation option for Schema view - Enhance error handling when a dict method is accessed (e.g. .get) - Enhance exception error messages - Pygments library dependency is now optional diff --git a/README.md b/README.md index 176cb62..f66394c 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ cat data.json | jello '_["foo"]' - `-n` print selected `null` values - `-r` raw output of selected strings (no quotes) - `-s` print the JSON schema in grep-able format +- `-t` print type annotations in schema view - `-h` help - `-v` version info @@ -127,19 +128,19 @@ done < <(cat data.json | jello -rl _.foo) ### Setting Custom Colors via Environment Variable Custom colors can be set via the `JELLO_COLORS` environment variable. Any colors set in the environment variable will take precedence over any colors set in the initialization file. (see [Advanced Usage](https://github.com/kellyjonbrazil/jello/blob/master/ADVANCED_USAGE.md)) -The `JELLO_COLORS` environment variable takes six comma separated string values in the following format: +The `JELLO_COLORS` environment variable takes four comma separated string values in the following format: ``` -JELLO_COLORS=,,,,, +JELLO_COLORS=,,, ``` Where colors are: `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `gray`, `brightblack`, `brightred`, `brightgreen`, `brightyellow`, `brightblue`, `brightmagenta`, `brightcyan`, `white`, or `default` For example, to set to the default colors: ``` -JELLO_COLORS=blue,brightblack,magenta,green,red,magenta +JELLO_COLORS=blue,brightblack,magenta,green ``` or ``` -JELLO_COLORS=default,default,default,default,default,default +JELLO_COLORS=default,default,default,default ``` Here is more [Advanced Usage](https://github.com/kellyjonbrazil/jello/blob/master/ADVANCED_USAGE.md) information. diff --git a/jello/cli.py b/jello/cli.py index eb5d410..dc49049 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -34,6 +34,7 @@ def print_help(): -n print selected null values -r raw string output (no quotes) -s print the JSON schema in grep-able format + -t print type annotations in schema view -v version info -h help @@ -133,6 +134,7 @@ def main(data=None, query='_'): opts.nulls = opts.nulls or 'n' in options opts.raw = opts.raw or 'r' in options opts.schema = opts.schema or 's' in options + opts.types = opts.types or 't' in options opts.version_info = opts.version_info or 'v' in options opts.helpme = opts.helpme or 'h' in options diff --git a/jello/lib.py b/jello/lib.py index 986ae30..7972db6 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -30,6 +30,7 @@ class opts: lines = None mono = None schema = None + types = None keyname_color = None keyword_color = None number_color = None @@ -64,9 +65,17 @@ class JelloTheme: 'string': color_map['green'] } + if PYGMENTS_INSTALLED: + theme = { + Name: f'bold {colors["key_name"]}', + Keyword: colors['keyword'], + Number: colors['number'], + String: colors['string'] + } + def set_colors(self): """ - Updates the JelloTheme.colors dictionary used by the JelloStyle class. + Updates the JelloTheme.theme dictionary used by the JelloStyle class. Grab custom colors from JELLO_COLORS environment variable and opts class set by .jelloconf.py file. Individual colors from JELLO_COLORS take precedence over .jelloconf.py. Individual colors from @@ -106,21 +115,22 @@ def set_colors(self): print('jello: Warning: could not parse JELLO_COLORS environment variable\n', file=sys.stderr) color_list = ['default', 'default', 'default', 'default'] - # first set colors from opts class or fallback to defaults - self.colors = { - 'key_name': self.color_map[opts.keyname_color] if opts.keyname_color else self.colors['key_name'], - 'keyword': self.color_map[opts.keyword_color] if opts.keyword_color else self.colors['keyword'], - 'number': self.color_map[opts.number_color] if opts.number_color else self.colors['number'], - 'string': self.color_map[opts.string_color] if opts.string_color else self.colors['string'] - } + # first set theme from opts class or fallback to defaults + if PYGMENTS_INSTALLED: + self.theme = { + Name: f'bold {self.color_map[opts.keyname_color]}' if opts.keyname_color else f"bold {self.colors['key_name']}", + Keyword: self.color_map[opts.keyword_color] if opts.keyword_color else self.colors['keyword'], + Number: self.color_map[opts.number_color] if opts.number_color else self.colors['number'], + String: self.color_map[opts.string_color] if opts.string_color else self.colors['string'] + } - # then set colors from JELLO_COLORS env variable or fallback to existing colors - self.colors = { - 'key_name': self.color_map[color_list[0]] if not color_list[0] == 'default' else self.colors['key_name'], - 'keyword': self.color_map[color_list[1]] if not color_list[1] == 'default' else self.colors['keyword'], - 'number': self.color_map[color_list[2]] if not color_list[2] == 'default' else self.colors['number'], - 'string': self.color_map[color_list[3]] if not color_list[3] == 'default' else self.colors['string'] - } + # then set theme from JELLO_COLORS env variable or fallback to existing colors + self.theme = { + Name: f'bold {self.color_map[color_list[0]]}' if not color_list[0] == 'default' else self.theme[Name], + Keyword: self.color_map[color_list[1]] if not color_list[1] == 'default' else self.theme[Keyword], + Number: self.color_map[color_list[2]] if not color_list[2] == 'default' else self.theme[Number], + String: self.color_map[color_list[3]] if not color_list[3] == 'default' else self.theme[String] + } class Schema(JelloTheme): @@ -137,12 +147,7 @@ def color_output(self): if not opts.mono and PYGMENTS_INSTALLED: class JelloStyle(Style): - styles = { - Name: f'bold {self.colors["key_name"]}', # key names - Keyword: f'{self.colors["keyword"]}', # true, false, null - Number: f'{self.colors["number"]}', # int, float - String: f'{self.colors["string"]}' # string - } + styles = self.theme lexer = JavascriptLexer() formatter = Terminal256Formatter(style=JelloStyle) @@ -153,7 +158,13 @@ class JelloStyle(Style): def html_output(self): data_string = '\n'.join(self.schema_list) - return highlight(data_string, JavascriptLexer(), HtmlFormatter(noclasses=True)) + + class JelloStyle(Style): + styles = self.theme + + lexer = JavascriptLexer() + formatter = HtmlFormatter(style=JelloStyle, noclasses=True) + return highlight(data_string, lexer, formatter) def create_schema(self, src, path=''): """ @@ -182,27 +193,35 @@ def create_schema(self, src, path=''): else: k = f'{k}' val = json.dumps(v, ensure_ascii=False) - if val == 'true' or val == 'false' or val == 'null': - val = f'{val}' - elif val.replace('.', '', 1).isdigit(): - val = f'{val}' - else: - val = f'{val}' + val_type = '' + if opts.types: + if val == 'true' or val == 'false': + val_type = ' // (boolean)' + elif val == 'null': + val_type = ' // (null)' + elif val.replace('.', '', 1).isdigit(): + val_type = ' // (number)' + else: + val_type = ' // (string)' - self.schema_list.append(f'{path}.{k} = {val};') + self.schema_list.append(f'{path}.{k} = {val};{val_type}') else: val = json.dumps(src, ensure_ascii=False) - if val == 'true' or val == 'false' or val == 'null': - val = f'{val}' - elif val.replace('.', '', 1).isdigit(): - val = f'{val}' - else: - val = f'{val}' + val_type = '' + if opts.types: + if val == 'true' or val == 'false': + val_type = ' // (boolean)' + elif val == 'null': + val_type = ' // (null)' + elif val.replace('.', '', 1).isdigit(): + val_type = ' // (number)' + else: + val_type = ' // (string)' path = path or '.' - self.schema_list.append(f'{path} = {val};') + self.schema_list.append(f'{path} = {val};{val_type}') class Json(JelloTheme): @@ -211,12 +230,7 @@ class Json(JelloTheme): def color_output(self, data): if not opts.mono and PYGMENTS_INSTALLED: class JelloStyle(Style): - styles = { - Name: f'bold {self.colors["key_name"]}', # key names - Keyword: f'{self.colors["keyword"]}', # true, false, null - Number: f'{self.colors["number"]}', # int, float - String: f'{self.colors["string"]}' # string - } + styles = self.theme lexer = JsonLexer() formatter = Terminal256Formatter(style=JelloStyle) @@ -226,7 +240,12 @@ class JelloStyle(Style): return data def html_output(self, data): - return highlight(data, JsonLexer(), HtmlFormatter(noclasses=True)) + class JelloStyle(Style): + styles = self.theme + + lexer = JsonLexer() + formatter = HtmlFormatter(style=JelloStyle, noclasses=True) + return highlight(data, lexer, formatter) def create_json(self, data): separators = None diff --git a/jello/man/jello.1 b/jello/man/jello.1 index a809864..6b63585 100644 --- a/jello/man/jello.1 +++ b/jello/man/jello.1 @@ -1,4 +1,4 @@ -.TH jello 1 2021-06-13 1.4.0 "Jello JSON Filter" +.TH jello 1 2021-06-15 1.4.0 "Jello JSON Filter" .SH NAME Jello \- Filter JSON and JSON Lines data with Python syntax .SH SYNOPSIS @@ -66,6 +66,8 @@ $ cat data.json | jello \[aq]_[\[dq]foo\[dq]]\[aq] .IP \fB-s\fP print the JSON schema in grep-able format .IP +\fB-t\fP print type annotations in schema view +.IP \fB-h\fP help .IP \fB-v\fP version info @@ -330,6 +332,7 @@ opts.lines = True # -l option opts.raw = True # -r option opts.nulls = True # -n option opts.schema = True # -s option +opts.types = True # -t option .fi .SS Setting Colors .PP @@ -342,8 +345,6 @@ opts.keyname_color = \[aq]blue\[aq] # Key names opts.keyword_color = \[aq]brightblack\[aq] # true, false, null opts.number_color = \[aq]magenta\[aq] # integers, floats opts.string_color = \[aq]green\[aq] # strings -opts.arrayid_color = \[aq]red\[aq] # array IDs in Schema view -opts.arraybracket_color = \[aq]magenta\[aq] # array brackets in Schema view \f[R] .fi .RS @@ -400,11 +401,11 @@ $ jc -a | jello -i \[aq]g(\[dq]parsers.6.compatible\[dq])\[aq] In addition to setting custom colors in the \fB.jelloconf.py\fP intialization file, you can also set them via the \fBJELLO_COLORS\fP environment variable. Any colors set in the environment variable will take precedence over any colors set in the initialization file. .PP -The \fBJELLO_COLORS\fP environment variable takes six comma separated string values in the following format: +The \fBJELLO_COLORS\fP environment variable takes four comma separated string values in the following format: .IP .nf \f[C] -JELLO_COLORS=,,,,, +JELLO_COLORS=,,, \f[R] .fi .PP @@ -419,7 +420,7 @@ For example, to set to the default colors: .IP .nf \f[C] -JELLO_COLORS=blue,brightblack,magenta,green,red,magenta +JELLO_COLORS=blue,brightblack,magenta,green \f[R] .fi .PP @@ -427,7 +428,7 @@ or .IP .nf \f[C] -JELLO_COLORS=default,default,default,default,default,default +JELLO_COLORS=default,default,default,default \f[R] .fi diff --git a/man/jello.1 b/man/jello.1 index a809864..6b63585 100644 --- a/man/jello.1 +++ b/man/jello.1 @@ -1,4 +1,4 @@ -.TH jello 1 2021-06-13 1.4.0 "Jello JSON Filter" +.TH jello 1 2021-06-15 1.4.0 "Jello JSON Filter" .SH NAME Jello \- Filter JSON and JSON Lines data with Python syntax .SH SYNOPSIS @@ -66,6 +66,8 @@ $ cat data.json | jello \[aq]_[\[dq]foo\[dq]]\[aq] .IP \fB-s\fP print the JSON schema in grep-able format .IP +\fB-t\fP print type annotations in schema view +.IP \fB-h\fP help .IP \fB-v\fP version info @@ -330,6 +332,7 @@ opts.lines = True # -l option opts.raw = True # -r option opts.nulls = True # -n option opts.schema = True # -s option +opts.types = True # -t option .fi .SS Setting Colors .PP @@ -342,8 +345,6 @@ opts.keyname_color = \[aq]blue\[aq] # Key names opts.keyword_color = \[aq]brightblack\[aq] # true, false, null opts.number_color = \[aq]magenta\[aq] # integers, floats opts.string_color = \[aq]green\[aq] # strings -opts.arrayid_color = \[aq]red\[aq] # array IDs in Schema view -opts.arraybracket_color = \[aq]magenta\[aq] # array brackets in Schema view \f[R] .fi .RS @@ -400,11 +401,11 @@ $ jc -a | jello -i \[aq]g(\[dq]parsers.6.compatible\[dq])\[aq] In addition to setting custom colors in the \fB.jelloconf.py\fP intialization file, you can also set them via the \fBJELLO_COLORS\fP environment variable. Any colors set in the environment variable will take precedence over any colors set in the initialization file. .PP -The \fBJELLO_COLORS\fP environment variable takes six comma separated string values in the following format: +The \fBJELLO_COLORS\fP environment variable takes four comma separated string values in the following format: .IP .nf \f[C] -JELLO_COLORS=,,,,, +JELLO_COLORS=,,, \f[R] .fi .PP @@ -419,7 +420,7 @@ For example, to set to the default colors: .IP .nf \f[C] -JELLO_COLORS=blue,brightblack,magenta,green,red,magenta +JELLO_COLORS=blue,brightblack,magenta,green \f[R] .fi .PP @@ -427,7 +428,7 @@ or .IP .nf \f[C] -JELLO_COLORS=default,default,default,default,default,default +JELLO_COLORS=default,default,default,default \f[R] .fi diff --git a/tests/test_create_json.py b/tests/test_create_json.py index e9e8712..cbabe36 100644 --- a/tests/test_create_json.py +++ b/tests/test_create_json.py @@ -17,12 +17,11 @@ def setUp(self): opts.lines = None opts.mono = None opts.schema = None + opts.types = None opts.keyname_color = None opts.keyword_color = None opts.number_color = None opts.string_color = None - opts.arrayid_color = None - opts.arraybracket_color = None # initialize Json class self.json_out = Json() diff --git a/tests/test_create_schema.py b/tests/test_create_schema.py index 8dd688d..54e637e 100644 --- a/tests/test_create_schema.py +++ b/tests/test_create_schema.py @@ -17,12 +17,11 @@ def setUp(self): opts.lines = None opts.mono = None opts.schema = None + opts.types = None opts.keyname_color = None opts.keyword_color = None opts.number_color = None opts.string_color = None - opts.arrayid_color = None - opts.arraybracket_color = None # initialize schema_lists self.schema = Schema() diff --git a/tests/test_main.py b/tests/test_main.py index 9e9999b..cb56e1c 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -26,12 +26,11 @@ def setUp(self): opts.lines = None opts.mono = None opts.schema = None + opts.types = None opts.keyname_color = None opts.keyword_color = None opts.number_color = None opts.string_color = None - opts.arrayid_color = None - opts.arraybracket_color = None # initialize schema_list jello.lib.schema_list = [] diff --git a/tests/test_pyquery.py b/tests/test_pyquery.py index 907b63f..c42611e 100644 --- a/tests/test_pyquery.py +++ b/tests/test_pyquery.py @@ -17,12 +17,11 @@ def setUp(self): opts.lines = None opts.mono = None opts.schema = None + opts.types = None opts.keyname_color = None opts.keyword_color = None opts.number_color = None opts.string_color = None - opts.arrayid_color = None - opts.arraybracket_color = None # create samples self.dict_sample = { From 3c28641b5e2f63199f05cd51ce36d9cd0b4dc634 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 15 Jun 2021 21:05:49 -0700 Subject: [PATCH 50/68] fix tests for pygments support --- tests/test_create_schema.py | 118 ++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/tests/test_create_schema.py b/tests/test_create_schema.py index 54e637e..3af7047 100644 --- a/tests/test_create_schema.py +++ b/tests/test_create_schema.py @@ -27,7 +27,7 @@ def setUp(self): self.schema = Schema() # initialize JELLO_COLORS env variable - os.environ['JELLO_COLORS'] = 'default,default,default,default,default,default' + os.environ['JELLO_COLORS'] = 'default,default,default,default' # set the colors self.schema.set_colors() @@ -124,9 +124,9 @@ def test_true(self): Test True """ self.data_in = True - self.expected = '. = \x1b[90mtrue\x1b[0m;' + self.expected = '. = \x1b[90mtrue\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_text(), self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_true_m(self): """ @@ -136,7 +136,7 @@ def test_true_m(self): self.expected = '. = true;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_text(), self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # Naked False @@ -147,9 +147,9 @@ def test_false(self): Test False """ self.data_in = False - self.expected = '. = \x1b[90mfalse\x1b[0m;' + self.expected = '. = \x1b[90mfalse\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_text(), self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_false_m(self): """ @@ -159,7 +159,7 @@ def test_false_m(self): self.expected = '. = false;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_text(), self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # Naked null @@ -170,9 +170,9 @@ def test_null(self): Test None """ self.data_in = None - self.expected = '. = \x1b[90mnull\x1b[0m;' + self.expected = '. = \x1b[90mnull\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_text(), self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_null_m(self): """ @@ -182,7 +182,7 @@ def test_null_m(self): self.expected = '. = null;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_text(), self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # naked int @@ -193,9 +193,9 @@ def test_int(self): Test int """ self.data_in = 42 - self.expected = '. = \x1b[35m42\x1b[0m;' + self.expected = '. = \x1b[35m42\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_text(), self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_int_m(self): """ @@ -205,7 +205,7 @@ def test_int_m(self): self.expected = '. = 42;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_text(), self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # naked float @@ -216,9 +216,9 @@ def test_float(self): Test float """ self.data_in = 3.14 - self.expected = '. = \x1b[35m3.14\x1b[0m;' + self.expected = '. = \x1b[35m3.14\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_text(), self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_float_m(self): """ @@ -228,7 +228,7 @@ def test_float_m(self): self.expected = '. = 3.14;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_text(), self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # naked string @@ -239,9 +239,9 @@ def test_string(self): Test string """ self.data_in = '"string with\\nnewline char"' - self.expected = '. = \x1b[32m"\\"string with\\\\nnewline char\\""\x1b[0m;' + self.expected = '. = \x1b[32m"\\"string with\\\\nnewline char\\""\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_text(), self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_string_m(self): """ @@ -251,7 +251,7 @@ def test_string_m(self): self.expected = '. = "\\"string with\\\\nnewline char\\"";' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_text(), self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # Naked Dict @@ -262,19 +262,19 @@ def test_dict(self): Test self.dict_sample """ self.data_in = self.dict_sample - self.expected = ['.\x1b[1m\x1b[34mstring\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[1m\x1b[34mtrue\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[1m\x1b[34mfalse\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[1m\x1b[34mnull\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[1m\x1b[34mint\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[1m\x1b[34mfloat\x1b[0m = \x1b[35m3.14\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;'] + self.expected = '.\x1b[34;01mstring\x1b[39;00m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m;\n.\x1b[90mtrue\x1b[39m = \x1b[90mtrue\x1b[39m;\n.\x1b[90mfalse\x1b[39m = \x1b[90mfalse\x1b[39m;\n.\x1b[90mnull\x1b[39m = \x1b[90mnull\x1b[39m;\n.\x1b[90mint\x1b[39m = \x1b[35m42\x1b[39m;\n.\x1b[90mfloat\x1b[39m = \x1b[35m3.14\x1b[39m;\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m0\x1b[39m] = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m;\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m;\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m;\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m;\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m4\x1b[39m] = \x1b[35m42\x1b[39m;\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m5\x1b[39m] = \x1b[35m3.14\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_dict_m(self): """ Test self.dict_sample -m """ self.data_in = self.dict_sample - self.expected = ['.string = "string\\nwith newline\\ncharacters in it";', '.true = true;', '.false = false;', '.null = null;', '.int = 42;', '.float = 3.14;', '.array[0] = "string\\nwith newline\\ncharacters in it";', '.array[1] = true;', '.array[2] = false;', '.array[3] = null;', '.array[4] = 42;', '.array[5] = 3.14;'] + self.expected = '.string = "string\\nwith newline\\ncharacters in it";\n.true = true;\n.false = false;\n.null = null;\n.int = 42;\n.float = 3.14;\n.array[0] = "string\\nwith newline\\ncharacters in it";\n.array[1] = true;\n.array[2] = false;\n.array[3] = null;\n.array[4] = 42;\n.array[5] = 3.14;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # true in a list @@ -285,19 +285,19 @@ def test_list_true(self): Test [True] """ self.data_in = [True] - self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;'] + self.expected = '.[\x1b[35m0\x1b[39m] = \x1b[90mtrue\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_list_true_m(self): """ Test [True] -m """ self.data_in = [True] - self.expected = ['.[0] = true;'] + self.expected = '.[0] = true;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # false in a list @@ -308,19 +308,19 @@ def test_list_false(self): Test [False] """ self.data_in = [False] - self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;'] + self.expected = '.[\x1b[35m0\x1b[39m] = \x1b[90mfalse\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_list_false_m(self): """ Test [False] -m """ self.data_in = [False] - self.expected = ['.[0] = false;'] + self.expected = '.[0] = false;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # null in a list @@ -331,19 +331,19 @@ def test_list_null(self): Test [None] """ self.data_in = [None] - self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;'] + self.expected = '.[\x1b[35m0\x1b[39m] = \x1b[90mnull\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_list_null_m(self): """ Test [None] -m """ self.data_in = [None] - self.expected = ['.[0] = null;'] + self.expected = '.[0] = null;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # Int in a list @@ -354,19 +354,19 @@ def test_list_int(self): Test [42] """ self.data_in = [42] - self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;'] + self.expected = '.[\x1b[35m0\x1b[39m] = \x1b[35m42\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_list_int_m(self): """ Test [42] -m """ self.data_in = [42] - self.expected = ['.[0] = 42;'] + self.expected = '.[0] = 42;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # Float in a list @@ -377,19 +377,19 @@ def test_list_float(self): Test [3.14] """ self.data_in = [3.14] - self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;'] + self.expected = '.[\x1b[35m0\x1b[39m] = \x1b[35m3.14\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_list_float_m(self): """ Test [3.14] -m """ self.data_in = [3.14] - self.expected = ['.[0] = 3.14;'] + self.expected = '.[0] = 3.14;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # String in a list @@ -400,19 +400,19 @@ def test_list_str(self): Test ['string with spaces\nand newline\ncharacters'] """ self.data_in = ['string with spaces\nand newline\ncharacters'] - self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string with spaces\\nand newline\\ncharacters"\x1b[0m;'] + self.expected = '.[\x1b[35m0\x1b[39m] = \x1b[32m"string with spaces\\nand newline\\ncharacters"\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_list_str_m(self): """ Test ['string with spaces\nand newline\ncharacters'] -m """ self.data_in = ['string with spaces\nand newline\ncharacters'] - self.expected = ['.[0] = "string with spaces\\nand newline\\ncharacters";'] + self.expected = '.[0] = "string with spaces\\nand newline\\ncharacters";' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # List with different types of elements @@ -423,19 +423,19 @@ def test_list_sample(self): Test self.list_sample """ self.data_in = self.list_sample - self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;'] + self.expected = '.[\x1b[35m0\x1b[39m] = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m;\n.[\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m;\n.[\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m;\n.[\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m;\n.[\x1b[35m4\x1b[39m] = \x1b[35m42\x1b[39m;\n.[\x1b[35m5\x1b[39m] = \x1b[35m3.14\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_list_sample_m(self): """ Test self.list_sample -m """ self.data_in = self.list_sample - self.expected = ['.[0] = "string\\nwith newline\\ncharacters in it";', '.[1] = true;', '.[2] = false;', '.[3] = null;', '.[4] = 42;', '.[5] = 3.14;'] + self.expected = '.[0] = "string\\nwith newline\\ncharacters in it";\n.[1] = true;\n.[2] = false;\n.[3] = null;\n.[4] = 42;\n.[5] = 3.14;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # Dicts in a list @@ -446,19 +446,19 @@ def test_list_dict(self): Test self.list_of_dicts_sample """ self.data_in = self.list_of_dicts_sample - self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mstring\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mtrue\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mfalse\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mnull\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mint\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mfloat\x1b[0m = \x1b[35m3.14\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mstring\x1b[0m = \x1b[32m"another string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mtrue\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mfalse\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mnull\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mint\x1b[0m = \x1b[35m10001\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34mfloat\x1b[0m = \x1b[32m-400.45\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m-6000034\x1b[0m;', '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34marray\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m999999.854321\x1b[0m;'] + self.expected = '.[\x1b[35m0\x1b[39m].\x1b[34;01mstring\x1b[39;00m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[90mtrue\x1b[39m = \x1b[90mtrue\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[90mfalse\x1b[39m = \x1b[90mfalse\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[90mnull\x1b[39m = \x1b[90mnull\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[90mint\x1b[39m = \x1b[35m42\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[90mfloat\x1b[39m = \x1b[35m3.14\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m0\x1b[39m] = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m4\x1b[39m] = \x1b[35m42\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m5\x1b[39m] = \x1b[35m3.14\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[34;01mstring\x1b[39;00m = \x1b[32m"another string\\nwith newline\\ncharacters in it"\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[90mtrue\x1b[39m = \x1b[90mtrue\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[90mfalse\x1b[39m = \x1b[90mfalse\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[90mnull\x1b[39m = \x1b[90mnull\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[90mint\x1b[39m = \x1b[35m10001\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[90mfloat\x1b[39m = -\x1b[35m400.45\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m0\x1b[39m] = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m4\x1b[39m] = -\x1b[35m6000034\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m5\x1b[39m] = \x1b[35m999999.854321\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_list_dict_m(self): """ Test self.list_of_dicts_sample -m """ self.data_in = self.list_of_dicts_sample - self.expected = ['.[0].string = "string\\nwith newline\\ncharacters in it";', '.[0].true = true;', '.[0].false = false;', '.[0].null = null;', '.[0].int = 42;', '.[0].float = 3.14;', '.[0].array[0] = "string\\nwith newline\\ncharacters in it";', '.[0].array[1] = true;', '.[0].array[2] = false;', '.[0].array[3] = null;', '.[0].array[4] = 42;', '.[0].array[5] = 3.14;', '.[1].string = "another string\\nwith newline\\ncharacters in it";', '.[1].true = true;', '.[1].false = false;', '.[1].null = null;', '.[1].int = 10001;', '.[1].float = -400.45;', '.[1].array[0] = "string\\nwith newline\\ncharacters in it";', '.[1].array[1] = true;', '.[1].array[2] = false;', '.[1].array[3] = null;', '.[1].array[4] = -6000034;', '.[1].array[5] = 999999.854321;'] + self.expected = '.[0].string = "string\\nwith newline\\ncharacters in it";\n.[0].true = true;\n.[0].false = false;\n.[0].null = null;\n.[0].int = 42;\n.[0].float = 3.14;\n.[0].array[0] = "string\\nwith newline\\ncharacters in it";\n.[0].array[1] = true;\n.[0].array[2] = false;\n.[0].array[3] = null;\n.[0].array[4] = 42;\n.[0].array[5] = 3.14;\n.[1].string = "another string\\nwith newline\\ncharacters in it";\n.[1].true = true;\n.[1].false = false;\n.[1].null = null;\n.[1].int = 10001;\n.[1].float = -400.45;\n.[1].array[0] = "string\\nwith newline\\ncharacters in it";\n.[1].array[1] = true;\n.[1].array[2] = false;\n.[1].array[3] = null;\n.[1].array[4] = -6000034;\n.[1].array[5] = 999999.854321;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) # # lists in list @@ -469,19 +469,19 @@ def test_list_list(self): Test self.list_of_lists_sample """ self.data_in = self.list_of_lists_sample - self.expected = ['.\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[0m;', ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m3.14\x1b[0m;", '.\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m0\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m"another string\\nwith newline\\ncharacters in it"\x1b[0m;', ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mtrue\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m2\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mfalse\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m3\x1b[0m\x1b[35m]\x1b[0m = \x1b[90mnull\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m4\x1b[0m\x1b[35m]\x1b[0m = \x1b[35m42001\x1b[0m;", ".\x1b[35m[\x1b[0m\x1b[31m1\x1b[0m\x1b[35m]\x1b[0m.\x1b[1m\x1b[34m['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14]\x1b[0m\x1b[35m[\x1b[0m\x1b[31m5\x1b[0m\x1b[35m]\x1b[0m = \x1b[32m-3.14\x1b[0m;"] + self.expected = '.[\x1b[35m0\x1b[39m].[\x1b[32m\'string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42\x1b[39m, \x1b[35m3.14\x1b[39m][\x1b[35m0\x1b[39m] = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m;\n.[\x1b[35m0\x1b[39m].[\x1b[32m\'string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42\x1b[39m, \x1b[35m3.14\x1b[39m][\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m;\n.[\x1b[35m0\x1b[39m].[\x1b[32m\'string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42\x1b[39m, \x1b[35m3.14\x1b[39m][\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m;\n.[\x1b[35m0\x1b[39m].[\x1b[32m\'string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42\x1b[39m, \x1b[35m3.14\x1b[39m][\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m;\n.[\x1b[35m0\x1b[39m].[\x1b[32m\'string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42\x1b[39m, \x1b[35m3.14\x1b[39m][\x1b[35m4\x1b[39m] = \x1b[35m42\x1b[39m;\n.[\x1b[35m0\x1b[39m].[\x1b[32m\'string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42\x1b[39m, \x1b[35m3.14\x1b[39m][\x1b[35m5\x1b[39m] = \x1b[35m3.14\x1b[39m;\n.[\x1b[35m1\x1b[39m].[\x1b[32m\'another string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42001\x1b[39m, -\x1b[35m3.14\x1b[39m][\x1b[35m0\x1b[39m] = \x1b[32m"another string\\nwith newline\\ncharacters in it"\x1b[39m;\n.[\x1b[35m1\x1b[39m].[\x1b[32m\'another string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42001\x1b[39m, -\x1b[35m3.14\x1b[39m][\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m;\n.[\x1b[35m1\x1b[39m].[\x1b[32m\'another string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42001\x1b[39m, -\x1b[35m3.14\x1b[39m][\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m;\n.[\x1b[35m1\x1b[39m].[\x1b[32m\'another string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42001\x1b[39m, -\x1b[35m3.14\x1b[39m][\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m;\n.[\x1b[35m1\x1b[39m].[\x1b[32m\'another string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42001\x1b[39m, -\x1b[35m3.14\x1b[39m][\x1b[35m4\x1b[39m] = \x1b[35m42001\x1b[39m;\n.[\x1b[35m1\x1b[39m].[\x1b[32m\'another string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42001\x1b[39m, -\x1b[35m3.14\x1b[39m][\x1b[35m5\x1b[39m] = -\x1b[35m3.14\x1b[39m;' self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.color_output(), self.expected) def test_list_list_m(self): """ Test self.list_of_lists_sample -m """ self.data_in = self.list_of_lists_sample - self.expected = ['.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][0] = "string\\nwith newline\\ncharacters in it";', ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][1] = true;", ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][2] = false;", ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][3] = null;", ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][4] = 42;", ".[0].['string\\nwith newline\\ncharacters in it', True, False, None, 42, 3.14][5] = 3.14;", '.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][0] = "another string\\nwith newline\\ncharacters in it";', ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][1] = true;", ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][2] = false;", ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][3] = null;", ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][4] = 42001;", ".[1].['another string\\nwith newline\\ncharacters in it', True, False, None, 42001, -3.14][5] = -3.14;"] + self.expected = '.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][0] = "string\\nwith newline\\ncharacters in it";\n.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][1] = true;\n.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][2] = false;\n.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][3] = null;\n.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][4] = 42;\n.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][5] = 3.14;\n.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][0] = "another string\\nwith newline\\ncharacters in it";\n.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][1] = true;\n.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][2] = false;\n.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][3] = null;\n.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][4] = 42001;\n.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][5] = -3.14;' opts.mono = True self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.schema_list, self.expected) + self.assertEqual(self.schema.mono_output(), self.expected) if __name__ == '__main__': From d9765f79dc0a41772289a7ff9b7badeb5797ebe3 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 15 Jun 2021 21:55:32 -0700 Subject: [PATCH 51/68] add opts.types and remove arrayid_color and arraybracket_color --- ADVANCED_USAGE.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ADVANCED_USAGE.md b/ADVANCED_USAGE.md index 1417d28..56253e9 100644 --- a/ADVANCED_USAGE.md +++ b/ADVANCED_USAGE.md @@ -18,6 +18,7 @@ opts.lines = True # -l option opts.raw = True # -r option opts.nulls = True # -n option opts.schema = True # -s option +opts.types = True # -t option ``` ##### Setting Colors You can customize the colors by importing the `jello.lib.opts` class and setting the following variables to one of the following string values: `'black'`, `'red'`, `'green'`, `'yellow'`, `'blue'`, `'magenta'`, `'cyan'`, `'gray'`, `'brightblack'`, `'brightred'`, `'brightgreen'`, `'brightyellow'`, `'brightblue'`, `'brightmagenta'`, `'brightcyan'`, or `'white'`. @@ -27,8 +28,6 @@ opts.keyname_color = 'blue' # Key names opts.keyword_color = 'brightblack' # true, false, null opts.number_color = 'magenta' # integers, floats opts.string_color = 'green' # strings -opts.arrayid_color = 'red' # array IDs in Schema view -opts.arraybracket_color = 'magenta' # array brackets in Schema view ``` > Note: Any colors set via the `JELLO_COLORS` environment variable will take precedence over any color values set in the `.jelloconf.py` configuration file From 104286176962379acb1dec3cf7ab9a726cfad150 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 16 Jun 2021 07:51:59 -0700 Subject: [PATCH 52/68] simplify theme color code --- jello/lib.py | 51 ++++++++++++++++----------------------------------- 1 file changed, 16 insertions(+), 35 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 7972db6..d29e32a 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -38,39 +38,20 @@ class opts: class JelloTheme: - color_map = { - 'black': 'ansiblack', - 'red': 'ansired', - 'green': 'ansigreen', - 'yellow': 'ansiyellow', - 'blue': 'ansiblue', - 'magenta': 'ansimagenta', - 'cyan': 'ansicyan', - 'gray': 'ansigray', - 'brightblack': 'ansibrightblack', - 'brightred': 'ansibrightred', - 'brightgreen': 'ansibrightgreen', - 'brightyellow': 'ansibrightyellow', - 'brightblue': 'ansibrightblue', - 'brightmagenta': 'ansibrightmagenta', - 'brightcyan': 'ansibrightcyan', - 'white': 'ansiwhite', - } - # default colors colors = { - 'key_name': color_map['blue'], - 'keyword': color_map['brightblack'], - 'number': color_map['magenta'], - 'string': color_map['green'] + 'key_name': 'blue', + 'keyword': 'brightblack', + 'number': 'magenta', + 'string': 'green' } if PYGMENTS_INSTALLED: theme = { - Name: f'bold {colors["key_name"]}', - Keyword: colors['keyword'], - Number: colors['number'], - String: colors['string'] + Name: f'bold ansi{colors["key_name"]}', + Keyword: f"ansi{colors['keyword']}", + Number: f"ansi{colors['number']}", + String: f"ansi{colors['string']}" } def set_colors(self): @@ -118,18 +99,18 @@ def set_colors(self): # first set theme from opts class or fallback to defaults if PYGMENTS_INSTALLED: self.theme = { - Name: f'bold {self.color_map[opts.keyname_color]}' if opts.keyname_color else f"bold {self.colors['key_name']}", - Keyword: self.color_map[opts.keyword_color] if opts.keyword_color else self.colors['keyword'], - Number: self.color_map[opts.number_color] if opts.number_color else self.colors['number'], - String: self.color_map[opts.string_color] if opts.string_color else self.colors['string'] + Name: f'bold ansi{opts.keyname_color}' if opts.keyname_color else f"bold ansi{self.colors['key_name']}", + Keyword: f'ansi{opts.keyword_color}' if opts.keyword_color else f"ansi{self.colors['keyword']}", + Number: f'ansi{opts.number_color}' if opts.number_color else f"ansi{self.colors['number']}", + String: f'ansi{opts.string_color}' if opts.string_color else f"ansi{self.colors['string']}" } # then set theme from JELLO_COLORS env variable or fallback to existing colors self.theme = { - Name: f'bold {self.color_map[color_list[0]]}' if not color_list[0] == 'default' else self.theme[Name], - Keyword: self.color_map[color_list[1]] if not color_list[1] == 'default' else self.theme[Keyword], - Number: self.color_map[color_list[2]] if not color_list[2] == 'default' else self.theme[Number], - String: self.color_map[color_list[3]] if not color_list[3] == 'default' else self.theme[String] + Name: f'bold ansi{color_list[0]}' if not color_list[0] == 'default' else self.theme[Name], + Keyword: f'ansi{color_list[1]}' if not color_list[1] == 'default' else self.theme[Keyword], + Number: f'ansi{color_list[2]}' if not color_list[2] == 'default' else self.theme[Number], + String: f'ansi{color_list[3]}' if not color_list[3] == 'default' else self.theme[String] } From aec4519b36449ee4baca8cc6a4830e0bbcb6332e Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 16 Jun 2021 07:55:03 -0700 Subject: [PATCH 53/68] move comment --- jello/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jello/lib.py b/jello/lib.py index d29e32a..3ee21aa 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -96,8 +96,8 @@ def set_colors(self): print('jello: Warning: could not parse JELLO_COLORS environment variable\n', file=sys.stderr) color_list = ['default', 'default', 'default', 'default'] - # first set theme from opts class or fallback to defaults if PYGMENTS_INSTALLED: + # first set theme from opts class or fallback to defaults self.theme = { Name: f'bold ansi{opts.keyname_color}' if opts.keyname_color else f"bold ansi{self.colors['key_name']}", Keyword: f'ansi{opts.keyword_color}' if opts.keyword_color else f"ansi{self.colors['keyword']}", From 81a13d6e41221b62931f05f9648d1d94590d30fe Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 16 Jun 2021 08:02:16 -0700 Subject: [PATCH 54/68] further simplify set_color method --- jello/lib.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 3ee21aa..0ad3cbb 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -38,20 +38,12 @@ class opts: class JelloTheme: - # default colors - colors = { - 'key_name': 'blue', - 'keyword': 'brightblack', - 'number': 'magenta', - 'string': 'green' - } - if PYGMENTS_INSTALLED: theme = { - Name: f'bold ansi{colors["key_name"]}', - Keyword: f"ansi{colors['keyword']}", - Number: f"ansi{colors['number']}", - String: f"ansi{colors['string']}" + Name: f'bold ansiblue', + Keyword: f'ansibrightblack', + Number: f'ansimagenta', + String: f'ansigreen' } def set_colors(self): @@ -99,10 +91,10 @@ def set_colors(self): if PYGMENTS_INSTALLED: # first set theme from opts class or fallback to defaults self.theme = { - Name: f'bold ansi{opts.keyname_color}' if opts.keyname_color else f"bold ansi{self.colors['key_name']}", - Keyword: f'ansi{opts.keyword_color}' if opts.keyword_color else f"ansi{self.colors['keyword']}", - Number: f'ansi{opts.number_color}' if opts.number_color else f"ansi{self.colors['number']}", - String: f'ansi{opts.string_color}' if opts.string_color else f"ansi{self.colors['string']}" + Name: f'bold ansi{opts.keyname_color}' if opts.keyname_color else self.theme[Name], + Keyword: f'ansi{opts.keyword_color}' if opts.keyword_color else self.theme[Keyword], + Number: f'ansi{opts.number_color}' if opts.number_color else self.theme[Number], + String: f'ansi{opts.string_color}' if opts.string_color else self.theme[String] } # then set theme from JELLO_COLORS env variable or fallback to existing colors From 8e37413d25be6963a6987259f05a18ef23620699 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 16 Jun 2021 08:06:50 -0700 Subject: [PATCH 55/68] docstrings to double quotes --- jello/lib.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 0ad3cbb..867f507 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -107,7 +107,7 @@ def set_colors(self): class Schema(JelloTheme): - '''Inherits colors and set_colors() from JelloTheme''' + """Inherits colors and set_colors() from JelloTheme""" def __init__(self): self.schema_list = [] @@ -198,7 +198,7 @@ def create_schema(self, src, path=''): class Json(JelloTheme): - '''Inherits colors and set_colors() from JelloTheme''' + """Inherits colors and set_colors() from JelloTheme""" def color_output(self, data): if not opts.mono and PYGMENTS_INSTALLED: @@ -304,7 +304,7 @@ def load_json(data): def pyquery(data, query): - '''Sets options and runs the user's query''' + """Sets options and runs the user's query""" output = None # read data into '_' variable From 3d760a272618f313b2d8497339a141ac8eaccc84 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 16 Jun 2021 08:07:55 -0700 Subject: [PATCH 56/68] docstring update --- jello/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 867f507..ddc01ca 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -107,7 +107,7 @@ def set_colors(self): class Schema(JelloTheme): - """Inherits colors and set_colors() from JelloTheme""" + """Inherits theme and set_colors() from JelloTheme""" def __init__(self): self.schema_list = [] @@ -198,7 +198,7 @@ def create_schema(self, src, path=''): class Json(JelloTheme): - """Inherits colors and set_colors() from JelloTheme""" + """Inherits theme and set_colors() from JelloTheme""" def color_output(self, data): if not opts.mono and PYGMENTS_INSTALLED: From 94281cb8869277e08b20656222ce04202846eac9 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 16 Jun 2021 16:57:07 -0700 Subject: [PATCH 57/68] make create_schema behave the same as create_json --- jello/cli.py | 6 +- jello/lib.py | 31 ++++----- tests/test_create_schema.py | 128 ++++++++++++++---------------------- 3 files changed, 64 insertions(+), 101 deletions(-) diff --git a/jello/cli.py b/jello/cli.py index dc49049..5f5bad2 100644 --- a/jello/cli.py +++ b/jello/cli.py @@ -179,13 +179,11 @@ def main(data=None, query='_'): try: if opts.schema: schema = Schema() - schema.create_schema(response) + output = schema.create_schema(response) if not opts.mono and sys.stdout.isatty(): schema.set_colors() - output = schema.color_output() - else: - output = schema.mono_output() + output = schema.color_output(output) else: json_out = Json() diff --git a/jello/lib.py b/jello/lib.py index ddc01ca..b48ee32 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -112,56 +112,53 @@ class Schema(JelloTheme): def __init__(self): self.schema_list = [] - def mono_output(self): - return '\n'.join(self.schema_list) - - def color_output(self): - data_string = '\n'.join(self.schema_list) - + def color_output(self, data): if not opts.mono and PYGMENTS_INSTALLED: class JelloStyle(Style): styles = self.theme lexer = JavascriptLexer() formatter = Terminal256Formatter(style=JelloStyle) - return highlight(data_string, lexer, formatter)[0:-1] + return highlight(data, lexer, formatter)[0:-1] else: - return data_string - - def html_output(self): - data_string = '\n'.join(self.schema_list) + return data + def html_output(self, data): class JelloStyle(Style): styles = self.theme lexer = JavascriptLexer() formatter = HtmlFormatter(style=JelloStyle, noclasses=True) - return highlight(data_string, lexer, formatter) + return highlight(data, lexer, formatter) + + def create_schema(self, data): + self._schema_gen(data) + return '\n'.join(self.schema_list) - def create_schema(self, src, path=''): + def _schema_gen(self, src, path=''): """ Creates a grep-able schema representation of the JSON. This method is recursive, and output is stored within self.schema_list (list). """ if isinstance(src, list) and path == '': for i, item in enumerate(src): - self.create_schema(item, path=f'.[{i}]') + self._schema_gen(item, path=f'.[{i}]') elif isinstance(src, list): for i, item in enumerate(src): - self.create_schema(item, path=f'{path}.{src}[{i}]') + self._schema_gen(item, path=f'{path}.{src}[{i}]') elif isinstance(src, dict): for k, v in src.items(): if isinstance(v, list): for i, item in enumerate(v): - self.create_schema(item, path=f'{path}.{k}[{i}]') + self._schema_gen(item, path=f'{path}.{k}[{i}]') elif isinstance(v, dict): if not opts.mono: k = f'{k}' - self.create_schema(v, path=f'{path}.{k}') + self._schema_gen(v, path=f'{path}.{k}') else: k = f'{k}' diff --git a/tests/test_create_schema.py b/tests/test_create_schema.py index 3af7047..7c2c331 100644 --- a/tests/test_create_schema.py +++ b/tests/test_create_schema.py @@ -125,8 +125,8 @@ def test_true(self): """ self.data_in = True self.expected = '. = \x1b[90mtrue\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_true_m(self): """ @@ -134,9 +134,7 @@ def test_true_m(self): """ self.data_in = True self.expected = '. = true;' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # Naked False @@ -148,8 +146,8 @@ def test_false(self): """ self.data_in = False self.expected = '. = \x1b[90mfalse\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_false_m(self): """ @@ -157,9 +155,7 @@ def test_false_m(self): """ self.data_in = False self.expected = '. = false;' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # Naked null @@ -171,8 +167,8 @@ def test_null(self): """ self.data_in = None self.expected = '. = \x1b[90mnull\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_null_m(self): """ @@ -180,9 +176,7 @@ def test_null_m(self): """ self.data_in = None self.expected = '. = null;' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # naked int @@ -194,8 +188,8 @@ def test_int(self): """ self.data_in = 42 self.expected = '. = \x1b[35m42\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_int_m(self): """ @@ -203,9 +197,7 @@ def test_int_m(self): """ self.data_in = 42 self.expected = '. = 42;' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # naked float @@ -217,8 +209,8 @@ def test_float(self): """ self.data_in = 3.14 self.expected = '. = \x1b[35m3.14\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_float_m(self): """ @@ -226,9 +218,7 @@ def test_float_m(self): """ self.data_in = 3.14 self.expected = '. = 3.14;' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # naked string @@ -240,8 +230,8 @@ def test_string(self): """ self.data_in = '"string with\\nnewline char"' self.expected = '. = \x1b[32m"\\"string with\\\\nnewline char\\""\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_string_m(self): """ @@ -249,9 +239,7 @@ def test_string_m(self): """ self.data_in = '"string with\\nnewline char"' self.expected = '. = "\\"string with\\\\nnewline char\\"";' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # Naked Dict @@ -263,8 +251,8 @@ def test_dict(self): """ self.data_in = self.dict_sample self.expected = '.\x1b[34;01mstring\x1b[39;00m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m;\n.\x1b[90mtrue\x1b[39m = \x1b[90mtrue\x1b[39m;\n.\x1b[90mfalse\x1b[39m = \x1b[90mfalse\x1b[39m;\n.\x1b[90mnull\x1b[39m = \x1b[90mnull\x1b[39m;\n.\x1b[90mint\x1b[39m = \x1b[35m42\x1b[39m;\n.\x1b[90mfloat\x1b[39m = \x1b[35m3.14\x1b[39m;\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m0\x1b[39m] = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m;\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m;\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m;\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m;\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m4\x1b[39m] = \x1b[35m42\x1b[39m;\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m5\x1b[39m] = \x1b[35m3.14\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_dict_m(self): """ @@ -272,9 +260,7 @@ def test_dict_m(self): """ self.data_in = self.dict_sample self.expected = '.string = "string\\nwith newline\\ncharacters in it";\n.true = true;\n.false = false;\n.null = null;\n.int = 42;\n.float = 3.14;\n.array[0] = "string\\nwith newline\\ncharacters in it";\n.array[1] = true;\n.array[2] = false;\n.array[3] = null;\n.array[4] = 42;\n.array[5] = 3.14;' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # true in a list @@ -286,8 +272,8 @@ def test_list_true(self): """ self.data_in = [True] self.expected = '.[\x1b[35m0\x1b[39m] = \x1b[90mtrue\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_list_true_m(self): """ @@ -295,9 +281,7 @@ def test_list_true_m(self): """ self.data_in = [True] self.expected = '.[0] = true;' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # false in a list @@ -309,8 +293,8 @@ def test_list_false(self): """ self.data_in = [False] self.expected = '.[\x1b[35m0\x1b[39m] = \x1b[90mfalse\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_list_false_m(self): """ @@ -318,9 +302,7 @@ def test_list_false_m(self): """ self.data_in = [False] self.expected = '.[0] = false;' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # null in a list @@ -332,8 +314,8 @@ def test_list_null(self): """ self.data_in = [None] self.expected = '.[\x1b[35m0\x1b[39m] = \x1b[90mnull\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_list_null_m(self): """ @@ -341,9 +323,7 @@ def test_list_null_m(self): """ self.data_in = [None] self.expected = '.[0] = null;' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # Int in a list @@ -355,8 +335,8 @@ def test_list_int(self): """ self.data_in = [42] self.expected = '.[\x1b[35m0\x1b[39m] = \x1b[35m42\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_list_int_m(self): """ @@ -364,9 +344,7 @@ def test_list_int_m(self): """ self.data_in = [42] self.expected = '.[0] = 42;' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # Float in a list @@ -378,8 +356,8 @@ def test_list_float(self): """ self.data_in = [3.14] self.expected = '.[\x1b[35m0\x1b[39m] = \x1b[35m3.14\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_list_float_m(self): """ @@ -387,9 +365,7 @@ def test_list_float_m(self): """ self.data_in = [3.14] self.expected = '.[0] = 3.14;' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # String in a list @@ -401,8 +377,8 @@ def test_list_str(self): """ self.data_in = ['string with spaces\nand newline\ncharacters'] self.expected = '.[\x1b[35m0\x1b[39m] = \x1b[32m"string with spaces\\nand newline\\ncharacters"\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_list_str_m(self): """ @@ -410,9 +386,7 @@ def test_list_str_m(self): """ self.data_in = ['string with spaces\nand newline\ncharacters'] self.expected = '.[0] = "string with spaces\\nand newline\\ncharacters";' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # List with different types of elements @@ -424,8 +398,8 @@ def test_list_sample(self): """ self.data_in = self.list_sample self.expected = '.[\x1b[35m0\x1b[39m] = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m;\n.[\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m;\n.[\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m;\n.[\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m;\n.[\x1b[35m4\x1b[39m] = \x1b[35m42\x1b[39m;\n.[\x1b[35m5\x1b[39m] = \x1b[35m3.14\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_list_sample_m(self): """ @@ -433,9 +407,7 @@ def test_list_sample_m(self): """ self.data_in = self.list_sample self.expected = '.[0] = "string\\nwith newline\\ncharacters in it";\n.[1] = true;\n.[2] = false;\n.[3] = null;\n.[4] = 42;\n.[5] = 3.14;' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # Dicts in a list @@ -447,8 +419,8 @@ def test_list_dict(self): """ self.data_in = self.list_of_dicts_sample self.expected = '.[\x1b[35m0\x1b[39m].\x1b[34;01mstring\x1b[39;00m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[90mtrue\x1b[39m = \x1b[90mtrue\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[90mfalse\x1b[39m = \x1b[90mfalse\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[90mnull\x1b[39m = \x1b[90mnull\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[90mint\x1b[39m = \x1b[35m42\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[90mfloat\x1b[39m = \x1b[35m3.14\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m0\x1b[39m] = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m4\x1b[39m] = \x1b[35m42\x1b[39m;\n.[\x1b[35m0\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m5\x1b[39m] = \x1b[35m3.14\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[34;01mstring\x1b[39;00m = \x1b[32m"another string\\nwith newline\\ncharacters in it"\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[90mtrue\x1b[39m = \x1b[90mtrue\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[90mfalse\x1b[39m = \x1b[90mfalse\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[90mnull\x1b[39m = \x1b[90mnull\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[90mint\x1b[39m = \x1b[35m10001\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[90mfloat\x1b[39m = -\x1b[35m400.45\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m0\x1b[39m] = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m4\x1b[39m] = -\x1b[35m6000034\x1b[39m;\n.[\x1b[35m1\x1b[39m].\x1b[34;01marray\x1b[39;00m[\x1b[35m5\x1b[39m] = \x1b[35m999999.854321\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_list_dict_m(self): """ @@ -456,9 +428,7 @@ def test_list_dict_m(self): """ self.data_in = self.list_of_dicts_sample self.expected = '.[0].string = "string\\nwith newline\\ncharacters in it";\n.[0].true = true;\n.[0].false = false;\n.[0].null = null;\n.[0].int = 42;\n.[0].float = 3.14;\n.[0].array[0] = "string\\nwith newline\\ncharacters in it";\n.[0].array[1] = true;\n.[0].array[2] = false;\n.[0].array[3] = null;\n.[0].array[4] = 42;\n.[0].array[5] = 3.14;\n.[1].string = "another string\\nwith newline\\ncharacters in it";\n.[1].true = true;\n.[1].false = false;\n.[1].null = null;\n.[1].int = 10001;\n.[1].float = -400.45;\n.[1].array[0] = "string\\nwith newline\\ncharacters in it";\n.[1].array[1] = true;\n.[1].array[2] = false;\n.[1].array[3] = null;\n.[1].array[4] = -6000034;\n.[1].array[5] = 999999.854321;' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # # lists in list @@ -470,8 +440,8 @@ def test_list_list(self): """ self.data_in = self.list_of_lists_sample self.expected = '.[\x1b[35m0\x1b[39m].[\x1b[32m\'string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42\x1b[39m, \x1b[35m3.14\x1b[39m][\x1b[35m0\x1b[39m] = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m;\n.[\x1b[35m0\x1b[39m].[\x1b[32m\'string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42\x1b[39m, \x1b[35m3.14\x1b[39m][\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m;\n.[\x1b[35m0\x1b[39m].[\x1b[32m\'string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42\x1b[39m, \x1b[35m3.14\x1b[39m][\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m;\n.[\x1b[35m0\x1b[39m].[\x1b[32m\'string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42\x1b[39m, \x1b[35m3.14\x1b[39m][\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m;\n.[\x1b[35m0\x1b[39m].[\x1b[32m\'string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42\x1b[39m, \x1b[35m3.14\x1b[39m][\x1b[35m4\x1b[39m] = \x1b[35m42\x1b[39m;\n.[\x1b[35m0\x1b[39m].[\x1b[32m\'string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42\x1b[39m, \x1b[35m3.14\x1b[39m][\x1b[35m5\x1b[39m] = \x1b[35m3.14\x1b[39m;\n.[\x1b[35m1\x1b[39m].[\x1b[32m\'another string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42001\x1b[39m, -\x1b[35m3.14\x1b[39m][\x1b[35m0\x1b[39m] = \x1b[32m"another string\\nwith newline\\ncharacters in it"\x1b[39m;\n.[\x1b[35m1\x1b[39m].[\x1b[32m\'another string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42001\x1b[39m, -\x1b[35m3.14\x1b[39m][\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m;\n.[\x1b[35m1\x1b[39m].[\x1b[32m\'another string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42001\x1b[39m, -\x1b[35m3.14\x1b[39m][\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m;\n.[\x1b[35m1\x1b[39m].[\x1b[32m\'another string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42001\x1b[39m, -\x1b[35m3.14\x1b[39m][\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m;\n.[\x1b[35m1\x1b[39m].[\x1b[32m\'another string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42001\x1b[39m, -\x1b[35m3.14\x1b[39m][\x1b[35m4\x1b[39m] = \x1b[35m42001\x1b[39m;\n.[\x1b[35m1\x1b[39m].[\x1b[32m\'another string\\nwith newline\\ncharacters in it\'\x1b[39m, \x1b[34;01mTrue\x1b[39;00m, \x1b[34;01mFalse\x1b[39;00m, \x1b[34;01mNone\x1b[39;00m, \x1b[35m42001\x1b[39m, -\x1b[35m3.14\x1b[39m][\x1b[35m5\x1b[39m] = -\x1b[35m3.14\x1b[39m;' - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.color_output(), self.expected) + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) def test_list_list_m(self): """ @@ -479,9 +449,7 @@ def test_list_list_m(self): """ self.data_in = self.list_of_lists_sample self.expected = '.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][0] = "string\\nwith newline\\ncharacters in it";\n.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][1] = true;\n.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][2] = false;\n.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][3] = null;\n.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][4] = 42;\n.[0].[\'string\\nwith newline\\ncharacters in it\', True, False, None, 42, 3.14][5] = 3.14;\n.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][0] = "another string\\nwith newline\\ncharacters in it";\n.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][1] = true;\n.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][2] = false;\n.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][3] = null;\n.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][4] = 42001;\n.[1].[\'another string\\nwith newline\\ncharacters in it\', True, False, None, 42001, -3.14][5] = -3.14;' - opts.mono = True - self.schema.create_schema(self.data_in) - self.assertEqual(self.schema.mono_output(), self.expected) + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) if __name__ == '__main__': From 2ec49e8d7537a3d5ae0cd2378743f5d908db29f1 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 17 Jun 2021 07:47:13 -0700 Subject: [PATCH 58/68] make _schema_list a private attribute. delete _schema_list after schema is created to reduce memory use --- jello/lib.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index b48ee32..8022e99 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -110,7 +110,7 @@ class Schema(JelloTheme): """Inherits theme and set_colors() from JelloTheme""" def __init__(self): - self.schema_list = [] + self._schema_list = [] def color_output(self, data): if not opts.mono and PYGMENTS_INSTALLED: @@ -134,12 +134,15 @@ class JelloStyle(Style): def create_schema(self, data): self._schema_gen(data) - return '\n'.join(self.schema_list) + myschema = '\n'.join(self._schema_list) + # unsure if this is helpful, but trying to reduce memory footprint + del self._schema_list + return myschema def _schema_gen(self, src, path=''): """ Creates a grep-able schema representation of the JSON. - This method is recursive, and output is stored within self.schema_list (list). + This method is recursive, and output is stored within self._schema_list (list). """ if isinstance(src, list) and path == '': for i, item in enumerate(src): @@ -174,7 +177,7 @@ def _schema_gen(self, src, path=''): else: val_type = ' // (string)' - self.schema_list.append(f'{path}.{k} = {val};{val_type}') + self._schema_list.append(f'{path}.{k} = {val};{val_type}') else: val = json.dumps(src, ensure_ascii=False) @@ -191,7 +194,7 @@ def _schema_gen(self, src, path=''): path = path or '.' - self.schema_list.append(f'{path} = {val};{val_type}') + self._schema_list.append(f'{path} = {val};{val_type}') class Json(JelloTheme): From 8ee600ad1b34e89dfc260bf1a7f846b2bf25f820 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 17 Jun 2021 15:46:50 -0600 Subject: [PATCH 59/68] clear list instead of deleting so we don't break _schema_gen if it is run again --- jello/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 8022e99..5371574 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -135,8 +135,8 @@ class JelloStyle(Style): def create_schema(self, data): self._schema_gen(data) myschema = '\n'.join(self._schema_list) - # unsure if this is helpful, but trying to reduce memory footprint - del self._schema_list + # unsure if this is helpful, but trying to reduce memory footprint by clearing the list + self._schema_list *= 0 return myschema def _schema_gen(self, src, path=''): From c6a3774c274a6a67a28c9f342d9cf72417c130b0 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 17 Jun 2021 17:09:18 -0600 Subject: [PATCH 60/68] make annotation types prettier --- jello/lib.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 5371574..ad2a230 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -167,34 +167,44 @@ def _schema_gen(self, src, path=''): k = f'{k}' val = json.dumps(v, ensure_ascii=False) val_type = '' + padding = '' if opts.types: if val == 'true' or val == 'false': - val_type = ' // (boolean)' + val_type = '// (boolean)' elif val == 'null': - val_type = ' // (null)' + val_type = '// (null)' elif val.replace('.', '', 1).isdigit(): - val_type = ' // (number)' + val_type = '// (number)' else: - val_type = ' // (string)' + val_type = '// (string)' - self._schema_list.append(f'{path}.{k} = {val};{val_type}') + padding = ' ' + if len(path) + len(k) + len(val) + len(val_type) < 60: + padding = ' ' * (59 - (len(path) + len(k) + len(val) + len(val_type))) + + self._schema_list.append(f'{path}.{k} = {val};{padding}{val_type}') else: val = json.dumps(src, ensure_ascii=False) val_type = '' + padding = '' if opts.types: if val == 'true' or val == 'false': - val_type = ' // (boolean)' + val_type = '// (boolean)' elif val == 'null': - val_type = ' // (null)' + val_type = '// (null)' elif val.replace('.', '', 1).isdigit(): - val_type = ' // (number)' + val_type = '// (number)' else: - val_type = ' // (string)' + val_type = '// (string)' path = path or '.' - self._schema_list.append(f'{path} = {val};{val_type}') + padding = ' ' + if len(path) + len(val) + len(val_type) < 60: + padding = ' ' * (60 - (len(path) + len(val) + len(val_type))) + + self._schema_list.append(f'{path} = {val};{padding}{val_type}') class Json(JelloTheme): From 641bf11117a6fa2b8fbec8211944979b993b21c6 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 17 Jun 2021 21:45:34 -0600 Subject: [PATCH 61/68] push string padding out to 70 --- jello/lib.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index ad2a230..de2109e 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -179,8 +179,8 @@ def _schema_gen(self, src, path=''): val_type = '// (string)' padding = ' ' - if len(path) + len(k) + len(val) + len(val_type) < 60: - padding = ' ' * (59 - (len(path) + len(k) + len(val) + len(val_type))) + if len(path) + len(k) + len(val) + len(val_type) < 70: + padding = ' ' * (69 - (len(path) + len(k) + len(val) + len(val_type))) self._schema_list.append(f'{path}.{k} = {val};{padding}{val_type}') @@ -201,8 +201,8 @@ def _schema_gen(self, src, path=''): path = path or '.' padding = ' ' - if len(path) + len(val) + len(val_type) < 60: - padding = ' ' * (60 - (len(path) + len(val) + len(val_type))) + if len(path) + len(val) + len(val_type) < 70: + padding = ' ' * (70 - (len(path) + len(val) + len(val_type))) self._schema_list.append(f'{path} = {val};{padding}{val_type}') From e434bb52327af228af820f91c747ad48a837ba2f Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 17 Jun 2021 22:09:25 -0600 Subject: [PATCH 62/68] move padding under types option --- jello/lib.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index de2109e..ad2c984 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -198,11 +198,11 @@ def _schema_gen(self, src, path=''): else: val_type = '// (string)' - path = path or '.' + padding = ' ' + if len(path) + len(val) + len(val_type) < 70: + padding = ' ' * (70 - (len(path) + len(val) + len(val_type))) - padding = ' ' - if len(path) + len(val) + len(val_type) < 70: - padding = ' ' * (70 - (len(path) + len(val) + len(val_type))) + path = path or '.' self._schema_list.append(f'{path} = {val};{padding}{val_type}') From d12dd9d1b255e040f74cb669f293f00c1238bd10 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 17 Jun 2021 22:09:47 -0600 Subject: [PATCH 63/68] remove schema_list initialization --- tests/test_main.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index cb56e1c..336e3e0 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -32,9 +32,6 @@ def setUp(self): opts.number_color = None opts.string_color = None - # initialize schema_list - jello.lib.schema_list = [] - self.jc_a_output = '''{"name": "jc", "version": "1.9.3", "description": "jc cli output JSON conversion tool", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "parser_count": 50, "parsers": [{"name": "airport", "argument": "--airport", "version": "1.0", "description": "airport -I command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["darwin"], "magic_commands": ["airport -I"]}, {"name": "airport_s", "argument": "--airport-s", "version": "1.0", "description": "airport -s command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["darwin"], "magic_commands": ["airport -s"]}, {"name": "arp", "argument": "--arp", "version": "1.2", "description": "arp command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "aix", "freebsd", "darwin"], "magic_commands": ["arp"]}, {"name": "blkid", "argument": "--blkid", "version": "1.0", "description": "blkid command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["blkid"]}, {"name": "crontab", "argument": "--crontab", "version": "1.1", "description": "crontab command and file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"], "magic_commands": ["crontab"]}, {"name": "crontab_u", "argument": "--crontab-u", "version": "1.0", "description": "crontab file parser with user support", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"]}, {"name": "csv", "argument": "--csv", "version": "1.0", "description": "CSV file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "details": "Using the python standard csv library", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"]}, {"name": "df", "argument": "--df", "version": "1.1", "description": "df command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin"], "magic_commands": ["df"]}, {"name": "dig", "argument": "--dig", "version": "1.1", "description": "dig command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "aix", "freebsd", "darwin"], "magic_commands": ["dig"]}, {"name": "du", "argument": "--du", "version": "1.1", "description": "du command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"], "magic_commands": ["du"]}, {"name": "env", "argument": "--env", "version": "1.1", "description": "env command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"], "magic_commands": ["env"]}, {"name": "file", "argument": "--file", "version": "1.1", "description": "file command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "aix", "freebsd", "darwin"], "magic_commands": ["file"]}, {"name": "free", "argument": "--free", "version": "1.0", "description": "free command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["free"]}, {"name": "fstab", "argument": "--fstab", "version": "1.0", "description": "fstab file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"]}, {"name": "group", "argument": "--group", "version": "1.0", "description": "/etc/group file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"]}, {"name": "gshadow", "argument": "--gshadow", "version": "1.0", "description": "/etc/gshadow file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "aix", "freebsd"]}, {"name": "history", "argument": "--history", "version": "1.2", "description": "history command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "details": "Optimizations by https://github.com/philippeitis", "compatible": ["linux", "darwin", "cygwin", "aix", "freebsd"]}, {"name": "hosts", "argument": "--hosts", "version": "1.0", "description": "/etc/hosts file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"]}, {"name": "id", "argument": "--id", "version": "1.0", "description": "id command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"], "magic_commands": ["id"]}, {"name": "ifconfig", "argument": "--ifconfig", "version": "1.5", "description": "ifconfig command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "details": "Using ifconfig-parser package from https://github.com/KnightWhoSayNi/ifconfig-parser", "compatible": ["linux", "aix", "freebsd", "darwin"], "magic_commands": ["ifconfig"]}, {"name": "ini", "argument": "--ini", "version": "1.0", "description": "INI file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "details": "Using configparser from the standard library", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"]}, {"name": "iptables", "argument": "--iptables", "version": "1.1", "description": "iptables command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["iptables"]}, {"name": "jobs", "argument": "--jobs", "version": "1.0", "description": "jobs command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "aix", "freebsd"], "magic_commands": ["jobs"]}, {"name": "last", "argument": "--last", "version": "1.0", "description": "last and lastb command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"], "magic_commands": ["last", "lastb"]}, {"name": "ls", "argument": "--ls", "version": "1.3", "description": "ls command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "aix", "freebsd"], "magic_commands": ["ls"]}, {"name": "lsblk", "argument": "--lsblk", "version": "1.3", "description": "lsblk command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["lsblk"]}, {"name": "lsmod", "argument": "--lsmod", "version": "1.1", "description": "lsmod command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["lsmod"]}, {"name": "lsof", "argument": "--lsof", "version": "1.0", "description": "lsof command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["lsof"]}, {"name": "mount", "argument": "--mount", "version": "1.1", "description": "mount command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin"], "magic_commands": ["mount"]}, {"name": "netstat", "argument": "--netstat", "version": "1.2", "description": "netstat command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["netstat"]}, {"name": "ntpq", "argument": "--ntpq", "version": "1.0", "description": "ntpq -p command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["ntpq"]}, {"name": "passwd", "argument": "--passwd", "version": "1.0", "description": "/etc/passwd file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"]}, {"name": "pip_list", "argument": "--pip-list", "version": "1.0", "description": "pip list command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"], "magic_commands": ["pip list", "pip3 list"]}, {"name": "pip_show", "argument": "--pip-show", "version": "1.0", "description": "pip show command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"], "magic_commands": ["pip show", "pip3 show"]}, {"name": "ps", "argument": "--ps", "version": "1.1", "description": "ps command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "aix", "freebsd"], "magic_commands": ["ps"]}, {"name": "route", "argument": "--route", "version": "1.0", "description": "route command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["route"]}, {"name": "shadow", "argument": "--shadow", "version": "1.0", "description": "/etc/shadow file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "aix", "freebsd"]}, {"name": "ss", "argument": "--ss", "version": "1.0", "description": "ss command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["ss"]}, {"name": "stat", "argument": "--stat", "version": "1.0", "description": "stat command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["stat"]}, {"name": "systemctl", "argument": "--systemctl", "version": "1.0", "description": "systemctl command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["systemctl"]}, {"name": "systemctl_lj", "argument": "--systemctl-lj", "version": "1.0", "description": "systemctl list-jobs command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["systemctl list-jobs"]}, {"name": "systemctl_ls", "argument": "--systemctl-ls", "version": "1.0", "description": "systemctl list-sockets command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["systemctl list-sockets"]}, {"name": "systemctl_luf", "argument": "--systemctl-luf", "version": "1.0", "description": "systemctl list-unit-files command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["systemctl list-unit-files"]}, {"name": "timedatectl", "argument": "--timedatectl", "version": "1.0", "description": "timedatectl status command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux"], "magic_commands": ["timedatectl", "timedatectl status"]}, {"name": "uname", "argument": "--uname", "version": "1.1", "description": "uname -a command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin"], "magic_commands": ["uname"]}, {"name": "uptime", "argument": "--uptime", "version": "1.0", "description": "uptime command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "aix", "freebsd"], "magic_commands": ["uptime"]}, {"name": "w", "argument": "--w", "version": "1.0", "description": "w command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "aix", "freebsd"], "magic_commands": ["w"]}, {"name": "who", "argument": "--who", "version": "1.0", "description": "who command parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "compatible": ["linux", "darwin", "cygwin", "aix", "freebsd"], "magic_commands": ["who"]}, {"name": "xml", "argument": "--xml", "version": "1.0", "description": "XML file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "details": "Using the xmltodict library at https://github.com/martinblech/xmltodict", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"]}, {"name": "yaml", "argument": "--yaml", "version": "1.0", "description": "YAML file parser", "author": "Kelly Brazil", "author_email": "kellyjonbrazil@gmail.com", "details": "Using the ruamel.yaml library at https://pypi.org/project/ruamel.yaml", "compatible": ["linux", "darwin", "cygwin", "win32", "aix", "freebsd"]}]}''' with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/twitterdata.jlines'), 'r', encoding='utf-8') as f: From 3e57f03b6fff462bc4693b41917820eb75d425c0 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 17 Jun 2021 22:20:04 -0600 Subject: [PATCH 64/68] fix spacing in schema types view --- jello/lib.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index ad2c984..464142a 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -172,11 +172,11 @@ def _schema_gen(self, src, path=''): if val == 'true' or val == 'false': val_type = '// (boolean)' elif val == 'null': - val_type = '// (null)' + val_type = '// (null)' elif val.replace('.', '', 1).isdigit(): - val_type = '// (number)' + val_type = '// (number)' else: - val_type = '// (string)' + val_type = '// (string)' padding = ' ' if len(path) + len(k) + len(val) + len(val_type) < 70: @@ -192,11 +192,11 @@ def _schema_gen(self, src, path=''): if val == 'true' or val == 'false': val_type = '// (boolean)' elif val == 'null': - val_type = '// (null)' + val_type = '// (null)' elif val.replace('.', '', 1).isdigit(): - val_type = '// (number)' + val_type = '// (number)' else: - val_type = '// (string)' + val_type = '// (string)' padding = ' ' if len(path) + len(val) + len(val_type) < 70: From cd61ceb340ea2afe41e628b5bcc962c287551a9c Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 18 Jun 2021 08:06:02 -0600 Subject: [PATCH 65/68] move path fix --- jello/lib.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 464142a..24ff337 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -185,6 +185,7 @@ def _schema_gen(self, src, path=''): self._schema_list.append(f'{path}.{k} = {val};{padding}{val_type}') else: + path = path or '.' val = json.dumps(src, ensure_ascii=False) val_type = '' padding = '' @@ -202,8 +203,6 @@ def _schema_gen(self, src, path=''): if len(path) + len(val) + len(val_type) < 70: padding = ' ' * (70 - (len(path) + len(val) + len(val_type))) - path = path or '.' - self._schema_list.append(f'{path} = {val};{padding}{val_type}') From a113b8e2d27aeb6225f3931f5a196316a1c9b939 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 18 Jun 2021 14:03:41 -0600 Subject: [PATCH 66/68] add schema type annotation, json html, and json color output tests --- tests/test_create_json.py | 18 ++++++++++++++++++ tests/test_create_schema.py | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/tests/test_create_json.py b/tests/test_create_json.py index cbabe36..e1b117d 100644 --- a/tests/test_create_json.py +++ b/tests/test_create_json.py @@ -440,6 +440,24 @@ def test_dict_crl(self): opts.lines = True self.assertEqual(self.json_out.create_json(self.data_in), self.expected) + def test_dict_html(self): + """ + Test self.dict_sample html output + """ + self.data_in = self.dict_sample + self.expected = '
{\n  "string": "string\\nwith newline\\ncharacters in it",\n  "true": true,\n  "false": false,\n  "null": null,\n  "int": 42,\n  "float": 3.14,\n  "array": [\n    "string\\nwith newline\\ncharacters in it",\n    true,\n    false,\n    null,\n    42,\n    3.14\n  ]\n}\n
\n' + output = self.json_out.create_json(self.data_in) + self.assertEqual(self.json_out.html_output(output), self.expected) + + def test_dict_color(self): + """ + Test self.dict_sample color output + """ + self.data_in = self.dict_sample + self.expected = '{\n \x1b[34;01m"string"\x1b[39;00m: \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m,\n \x1b[34;01m"true"\x1b[39;00m: \x1b[90mtrue\x1b[39m,\n \x1b[34;01m"false"\x1b[39;00m: \x1b[90mfalse\x1b[39m,\n \x1b[34;01m"null"\x1b[39;00m: \x1b[90mnull\x1b[39m,\n \x1b[34;01m"int"\x1b[39;00m: \x1b[35m42\x1b[39m,\n \x1b[34;01m"float"\x1b[39;00m: \x1b[35m3.14\x1b[39m,\n \x1b[34;01m"array"\x1b[39;00m: [\n \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m,\n \x1b[90mtrue\x1b[39m,\n \x1b[90mfalse\x1b[39m,\n \x1b[90mnull\x1b[39m,\n \x1b[35m42\x1b[39m,\n \x1b[35m3.14\x1b[39m\n ]\n}' + output = self.json_out.create_json(self.data_in) + self.assertEqual(self.json_out.color_output(output), self.expected) + # # true in a list # diff --git a/tests/test_create_schema.py b/tests/test_create_schema.py index 7c2c331..72cc47d 100644 --- a/tests/test_create_schema.py +++ b/tests/test_create_schema.py @@ -254,6 +254,16 @@ def test_dict(self): output = self.schema.create_schema(self.data_in) self.assertEqual(self.schema.color_output(output), self.expected) + def test_dict_t(self): + """ + Test self.dict_sample -t + """ + opts.types = True + self.data_in = self.dict_sample + self.expected = '.\x1b[34;01mstring\x1b[39;00m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m; // (string)\n.\x1b[90mtrue\x1b[39m = \x1b[90mtrue\x1b[39m; // (boolean)\n.\x1b[90mfalse\x1b[39m = \x1b[90mfalse\x1b[39m; // (boolean)\n.\x1b[90mnull\x1b[39m = \x1b[90mnull\x1b[39m; // (null)\n.\x1b[90mint\x1b[39m = \x1b[35m42\x1b[39m; // (number)\n.\x1b[90mfloat\x1b[39m = \x1b[35m3.14\x1b[39m; // (number)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m0\x1b[39m] = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m; // (string)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m; // (boolean)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m; // (boolean)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m; // (null)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m4\x1b[39m] = \x1b[35m42\x1b[39m; // (number)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m5\x1b[39m] = \x1b[35m3.14\x1b[39m; // (number)' + output = self.schema.create_schema(self.data_in) + self.assertEqual(self.schema.color_output(output), self.expected) + def test_dict_m(self): """ Test self.dict_sample -m @@ -262,6 +272,15 @@ def test_dict_m(self): self.expected = '.string = "string\\nwith newline\\ncharacters in it";\n.true = true;\n.false = false;\n.null = null;\n.int = 42;\n.float = 3.14;\n.array[0] = "string\\nwith newline\\ncharacters in it";\n.array[1] = true;\n.array[2] = false;\n.array[3] = null;\n.array[4] = 42;\n.array[5] = 3.14;' self.assertEqual(self.schema.create_schema(self.data_in), self.expected) + def test_dict_mt(self): + """ + Test self.dict_sample -mt + """ + opts.types = True + self.data_in = self.dict_sample + self.expected = '.string = "string\\nwith newline\\ncharacters in it"; // (string)\n.true = true; // (boolean)\n.false = false; // (boolean)\n.null = null; // (null)\n.int = 42; // (number)\n.float = 3.14; // (number)\n.array[0] = "string\\nwith newline\\ncharacters in it"; // (string)\n.array[1] = true; // (boolean)\n.array[2] = false; // (boolean)\n.array[3] = null; // (null)\n.array[4] = 42; // (number)\n.array[5] = 3.14; // (number)' + self.assertEqual(self.schema.create_schema(self.data_in), self.expected) + # # true in a list # From 8ff5e9d96964262fa787de935114e58c6ea4c798 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sat, 19 Jun 2021 10:14:06 -0700 Subject: [PATCH 67/68] optimize type annotations for 80 column terminal --- jello/lib.py | 8 ++++---- tests/test_create_schema.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/jello/lib.py b/jello/lib.py index 24ff337..ed1c225 100644 --- a/jello/lib.py +++ b/jello/lib.py @@ -179,8 +179,8 @@ def _schema_gen(self, src, path=''): val_type = '// (string)' padding = ' ' - if len(path) + len(k) + len(val) + len(val_type) < 70: - padding = ' ' * (69 - (len(path) + len(k) + len(val) + len(val_type))) + if len(path) + len(k) + len(val) + len(val_type) < 76: + padding = ' ' * (75 - (len(path) + len(k) + len(val) + len(val_type))) self._schema_list.append(f'{path}.{k} = {val};{padding}{val_type}') @@ -200,8 +200,8 @@ def _schema_gen(self, src, path=''): val_type = '// (string)' padding = ' ' - if len(path) + len(val) + len(val_type) < 70: - padding = ' ' * (70 - (len(path) + len(val) + len(val_type))) + if len(path) + len(val) + len(val_type) < 76: + padding = ' ' * (76 - (len(path) + len(val) + len(val_type))) self._schema_list.append(f'{path} = {val};{padding}{val_type}') diff --git a/tests/test_create_schema.py b/tests/test_create_schema.py index 72cc47d..aa9be02 100644 --- a/tests/test_create_schema.py +++ b/tests/test_create_schema.py @@ -260,7 +260,7 @@ def test_dict_t(self): """ opts.types = True self.data_in = self.dict_sample - self.expected = '.\x1b[34;01mstring\x1b[39;00m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m; // (string)\n.\x1b[90mtrue\x1b[39m = \x1b[90mtrue\x1b[39m; // (boolean)\n.\x1b[90mfalse\x1b[39m = \x1b[90mfalse\x1b[39m; // (boolean)\n.\x1b[90mnull\x1b[39m = \x1b[90mnull\x1b[39m; // (null)\n.\x1b[90mint\x1b[39m = \x1b[35m42\x1b[39m; // (number)\n.\x1b[90mfloat\x1b[39m = \x1b[35m3.14\x1b[39m; // (number)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m0\x1b[39m] = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m; // (string)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m; // (boolean)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m; // (boolean)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m; // (null)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m4\x1b[39m] = \x1b[35m42\x1b[39m; // (number)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m5\x1b[39m] = \x1b[35m3.14\x1b[39m; // (number)' + self.expected = '.\x1b[34;01mstring\x1b[39;00m = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m; // (string)\n.\x1b[90mtrue\x1b[39m = \x1b[90mtrue\x1b[39m; // (boolean)\n.\x1b[90mfalse\x1b[39m = \x1b[90mfalse\x1b[39m; // (boolean)\n.\x1b[90mnull\x1b[39m = \x1b[90mnull\x1b[39m; // (null)\n.\x1b[90mint\x1b[39m = \x1b[35m42\x1b[39m; // (number)\n.\x1b[90mfloat\x1b[39m = \x1b[35m3.14\x1b[39m; // (number)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m0\x1b[39m] = \x1b[32m"string\\nwith newline\\ncharacters in it"\x1b[39m; // (string)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m1\x1b[39m] = \x1b[90mtrue\x1b[39m; // (boolean)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m2\x1b[39m] = \x1b[90mfalse\x1b[39m; // (boolean)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m3\x1b[39m] = \x1b[90mnull\x1b[39m; // (null)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m4\x1b[39m] = \x1b[35m42\x1b[39m; // (number)\n.\x1b[34;01marray\x1b[39;00m[\x1b[35m5\x1b[39m] = \x1b[35m3.14\x1b[39m; // (number)' output = self.schema.create_schema(self.data_in) self.assertEqual(self.schema.color_output(output), self.expected) @@ -278,7 +278,7 @@ def test_dict_mt(self): """ opts.types = True self.data_in = self.dict_sample - self.expected = '.string = "string\\nwith newline\\ncharacters in it"; // (string)\n.true = true; // (boolean)\n.false = false; // (boolean)\n.null = null; // (null)\n.int = 42; // (number)\n.float = 3.14; // (number)\n.array[0] = "string\\nwith newline\\ncharacters in it"; // (string)\n.array[1] = true; // (boolean)\n.array[2] = false; // (boolean)\n.array[3] = null; // (null)\n.array[4] = 42; // (number)\n.array[5] = 3.14; // (number)' + self.expected = '.string = "string\\nwith newline\\ncharacters in it"; // (string)\n.true = true; // (boolean)\n.false = false; // (boolean)\n.null = null; // (null)\n.int = 42; // (number)\n.float = 3.14; // (number)\n.array[0] = "string\\nwith newline\\ncharacters in it"; // (string)\n.array[1] = true; // (boolean)\n.array[2] = false; // (boolean)\n.array[3] = null; // (null)\n.array[4] = 42; // (number)\n.array[5] = 3.14; // (number)' self.assertEqual(self.schema.create_schema(self.data_in), self.expected) # From daec2cf0cc6263a400593576990795c02d8e469c Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sat, 19 Jun 2021 10:18:16 -0700 Subject: [PATCH 68/68] add schema type annotations example --- README.md | 53 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index f66394c..b888f78 100644 --- a/README.md +++ b/README.md @@ -149,24 +149,51 @@ Here is more [Advanced Usage](https://github.com/kellyjonbrazil/jello/blob/maste ### Printing the Grep-able Schema ```bash jc -a | jello -s - .name = "jc"; -.version = "1.10.2"; -.description = "jc cli output JSON conversion tool"; +.version = "1.15.5"; +.description = "JSON CLI output utility"; .author = "Kelly Brazil"; .author_email = "kellyjonbrazil@gmail.com"; -.parser_count = 50; -.parsers[0].name = "airport"; -.parsers[0].argument = "--airport"; -.parsers[0].version = "1.0"; -.parsers[0].description = "airport -I command parser"; +.website = "https://github.com/kellyjonbrazil/jc"; +.copyright = "© 2019-2021 Kelly Brazil"; +.license = "MIT License"; +.parser_count = 73; +.parsers[0].name = "acpi"; +.parsers[0].argument = "--acpi"; +.parsers[0].version = "1.2"; +.parsers[0].description = "`acpi` command parser"; .parsers[0].author = "Kelly Brazil"; .parsers[0].author_email = "kellyjonbrazil@gmail.com"; -.parsers[0].compatible[0] = "darwin"; -.parsers[0].magic_commands[0] = "airport -I"; -.parsers[1].name = "airport_s"; -.parsers[1].argument = "--airport-s"; -.parsers[1].version = "1.0"; +.parsers[0].compatible[0] = "linux"; +.parsers[0].magic_commands[0] = "acpi"; +.parsers[1].name = "airport"; +.parsers[1].argument = "--airport"; +.parsers[1].version = "1.3"; +... +``` +### Printing the Grep-able Schema with type annotations (useful for grepping types) +```bash +jc -a | jello -st +.name = "jc"; // (string) +.version = "1.15.5"; // (string) +.description = "JSON CLI output utility"; // (string) +.author = "Kelly Brazil"; // (string) +.author_email = "kellyjonbrazil@gmail.com"; // (string) +.website = "https://github.com/kellyjonbrazil/jc"; // (string) +.copyright = "© 2019-2021 Kelly Brazil"; // (string) +.license = "MIT License"; // (string) +.parser_count = 73; // (number) +.parsers[0].name = "acpi"; // (string) +.parsers[0].argument = "--acpi"; // (string) +.parsers[0].version = "1.2"; // (string) +.parsers[0].description = "`acpi` command parser"; // (string) +.parsers[0].author = "Kelly Brazil"; // (string) +.parsers[0].author_email = "kellyjonbrazil@gmail.com"; // (string) +.parsers[0].compatible[0] = "linux"; // (string) +.parsers[0].magic_commands[0] = "acpi"; // (string) +.parsers[1].name = "airport"; // (string) +.parsers[1].argument = "--airport"; // (string) +.parsers[1].version = "1.3"; // (string) ... ``` ### Lambda Functions and Math