1
0
mirror of https://github.com/kellyjonbrazil/jc.git synced 2025-06-19 00:17:51 +02:00

add add_jc_meta decorator

This commit is contained in:
Kelly Brazil
2022-02-03 15:44:18 -08:00
parent 2986771f07
commit 49929c714c
9 changed files with 139 additions and 52 deletions

View File

@ -66,13 +66,13 @@ Examples:
import itertools import itertools
import csv import csv
import jc.utils import jc.utils
from jc.utils import stream_success, stream_error from jc.utils import add_jc_meta
from jc.exceptions import ParseError from jc.exceptions import ParseError
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.2' version = '1.3'
description = 'CSV file streaming parser' description = 'CSV file streaming parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -101,6 +101,7 @@ def _process(proc_data):
return proc_data return proc_data
@add_jc_meta
def parse(data, raw=False, quiet=False, ignore_exceptions=False): def parse(data, raw=False, quiet=False, ignore_exceptions=False):
""" """
Main text parsing generator function. Returns an iterator object. Main text parsing generator function. Returns an iterator object.
@ -112,7 +113,10 @@ def parse(data, raw=False, quiet=False, ignore_exceptions=False):
raw: (boolean) unprocessed output if True raw: (boolean) unprocessed output if True
quiet: (boolean) suppress warning messages if True quiet: (boolean) suppress warning messages if True
ignore_exceptions: (boolean) ignore parsing exceptions if True ignore_exceptions: (boolean) ignore parsing exceptions if True.
This can be used directly or
(preferably) by being passed to the
@add_jc_meta decorator.
Yields: Yields:
@ -155,6 +159,6 @@ def parse(data, raw=False, quiet=False, ignore_exceptions=False):
for row in reader: for row in reader:
try: try:
yield stream_success(row, ignore_exceptions) if raw else stream_success(_process(row), ignore_exceptions) yield row if raw else _process(row)
except Exception as e: except Exception as e:
yield stream_error(e, ignore_exceptions, row) yield e, row

View File

@ -49,9 +49,9 @@ Examples:
{example output} {example output}
... ...
""" """
from typing import Dict, Iterable from typing import Dict, Iterable, Union
import jc.utils import jc.utils
from jc.utils import stream_success, stream_error from jc.utils import add_jc_meta
from jc.exceptions import ParseError from jc.exceptions import ParseError
@ -91,12 +91,13 @@ def _process(proc_data: Dict) -> Dict:
return proc_data return proc_data
@add_jc_meta
def parse( def parse(
data: Iterable[str], data: Iterable[str],
raw: bool = False, raw: bool = False,
quiet: bool = False, quiet: bool = False,
ignore_exceptions: bool = False ignore_exceptions: bool = False
) -> Iterable[Dict]: ) -> Union[Iterable[Dict], tuple]:
""" """
Main text parsing generator function. Returns an iterator object. Main text parsing generator function. Returns an iterator object.
@ -107,7 +108,10 @@ def parse(
raw: (boolean) unprocessed output if True raw: (boolean) unprocessed output if True
quiet: (boolean) suppress warning messages if True quiet: (boolean) suppress warning messages if True
ignore_exceptions: (boolean) ignore parsing exceptions if True ignore_exceptions: (boolean) ignore parsing exceptions if True.
This can be used directly or
(preferably) by being passed to the
@add_jc_meta decorator.
Yields: Yields:
@ -131,9 +135,9 @@ def parse(
# and jc.parsers.universal # and jc.parsers.universal
if output_line: if output_line:
yield stream_success(output_line, ignore_exceptions) if raw else stream_success(_process(output_line), ignore_exceptions) yield output_line if raw else _process(output_line)
else: else:
raise ParseError('Not foo data') raise ParseError('Not foo data')
except Exception as e: except Exception as e:
yield stream_error(e, ignore_exceptions, line) yield e, line

View File

@ -101,14 +101,14 @@ Examples:
... ...
""" """
import jc.utils import jc.utils
from jc.utils import stream_success, stream_error from jc.utils import add_jc_meta
from jc.exceptions import ParseError from jc.exceptions import ParseError
import jc.parsers.universal import jc.parsers.universal
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.0' version = '1.1'
description = '`iostat` command streaming parser' description = '`iostat` command streaming parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -159,6 +159,8 @@ def _create_obj_list(section_list, section_name):
item['type'] = section_name item['type'] = section_name
return output_list return output_list
@add_jc_meta
def parse(data, raw=False, quiet=False, ignore_exceptions=False): def parse(data, raw=False, quiet=False, ignore_exceptions=False):
""" """
Main text parsing generator function. Returns an iterator object. Main text parsing generator function. Returns an iterator object.
@ -170,7 +172,10 @@ def parse(data, raw=False, quiet=False, ignore_exceptions=False):
raw: (boolean) unprocessed output if True raw: (boolean) unprocessed output if True
quiet: (boolean) suppress warning messages if True quiet: (boolean) suppress warning messages if True
ignore_exceptions: (boolean) ignore parsing exceptions if True ignore_exceptions: (boolean) ignore parsing exceptions if True.
This can be used directly or
(preferably) by being passed to the
@add_jc_meta decorator.
Yields: Yields:
@ -223,9 +228,9 @@ def parse(data, raw=False, quiet=False, ignore_exceptions=False):
device_list = [] device_list = []
if output_line: if output_line:
yield stream_success(output_line, ignore_exceptions) if raw else stream_success(_process(output_line), ignore_exceptions) yield output_line if raw else _process(output_line)
else: else:
raise ParseError('Not iostat data') raise ParseError('Not iostat data')
except Exception as e: except Exception as e:
yield stream_error(e, ignore_exceptions, line) yield e, line

View File

@ -79,13 +79,13 @@ Examples:
""" """
import re import re
import jc.utils import jc.utils
from jc.utils import stream_success, stream_error from jc.utils import add_jc_meta
from jc.exceptions import ParseError from jc.exceptions import ParseError
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '0.6' version = '1.0'
description = '`ls` command streaming parser' description = '`ls` command streaming parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -123,6 +123,7 @@ def _process(proc_data):
return proc_data return proc_data
@add_jc_meta
def parse(data, raw=False, quiet=False, ignore_exceptions=False): def parse(data, raw=False, quiet=False, ignore_exceptions=False):
""" """
Main text parsing generator function. Returns an iterator object. Main text parsing generator function. Returns an iterator object.
@ -134,7 +135,10 @@ def parse(data, raw=False, quiet=False, ignore_exceptions=False):
raw: (boolean) unprocessed output if True raw: (boolean) unprocessed output if True
quiet: (boolean) suppress warning messages if True quiet: (boolean) suppress warning messages if True
ignore_exceptions: (boolean) ignore parsing exceptions if True ignore_exceptions: (boolean) ignore parsing exceptions if True.
This can be used directly or
(preferably) by being passed to the
@add_jc_meta decorator.
Yields: Yields:
@ -196,7 +200,7 @@ def parse(data, raw=False, quiet=False, ignore_exceptions=False):
output_line['size'] = parsed_line[4] output_line['size'] = parsed_line[4]
output_line['date'] = ' '.join(parsed_line[5:8]) output_line['date'] = ' '.join(parsed_line[5:8])
yield stream_success(output_line, ignore_exceptions) if raw else stream_success(_process(output_line), ignore_exceptions) yield output_line if raw else _process(output_line)
except Exception as e: except Exception as e:
yield stream_error(e, ignore_exceptions, line) yield e, line

View File

@ -87,12 +87,12 @@ import string
import ipaddress import ipaddress
import jc.utils import jc.utils
from jc.exceptions import ParseError from jc.exceptions import ParseError
from jc.utils import stream_success, stream_error from jc.utils import add_jc_meta
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '0.6' version = '1.0'
description = '`ping` and `ping6` command streaming parser' description = '`ping` and `ping6` command streaming parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -469,6 +469,7 @@ def _linux_parse(line, s):
return output_line return output_line
@add_jc_meta
def parse(data, raw=False, quiet=False, ignore_exceptions=False): def parse(data, raw=False, quiet=False, ignore_exceptions=False):
""" """
Main text parsing generator function. Returns an iterator object. Main text parsing generator function. Returns an iterator object.
@ -480,7 +481,10 @@ def parse(data, raw=False, quiet=False, ignore_exceptions=False):
raw: (boolean) unprocessed output if True raw: (boolean) unprocessed output if True
quiet: (boolean) suppress warning messages if True quiet: (boolean) suppress warning messages if True
ignore_exceptions: (boolean) ignore parsing exceptions if True ignore_exceptions: (boolean) ignore parsing exceptions if True.
This can be used directly or
(preferably) by being passed to the
@add_jc_meta decorator.
Yields: Yields:
@ -542,9 +546,9 @@ def parse(data, raw=False, quiet=False, ignore_exceptions=False):
# yield the output line if it has data # yield the output line if it has data
if output_line: if output_line:
yield stream_success(output_line, ignore_exceptions) if raw else stream_success(_process(output_line), ignore_exceptions) yield output_line if raw else _process(output_line)
else: else:
continue continue
except Exception as e: except Exception as e:
yield stream_error(e, ignore_exceptions, line) yield e, line

View File

@ -87,15 +87,15 @@ Examples:
... ...
""" """
import re import re
from typing import Dict, Iterable from typing import Dict, Iterable, Union
import jc.utils import jc.utils
from jc.utils import stream_success, stream_error from jc.utils import add_jc_meta
from jc.exceptions import ParseError from jc.exceptions import ParseError
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '1.0' version = '1.1'
description = '`rsync` command streaming parser' description = '`rsync` command streaming parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -140,12 +140,13 @@ def _process(proc_data: Dict) -> Dict:
return proc_data return proc_data
@add_jc_meta
def parse( def parse(
data: Iterable[str], data: Iterable[str],
raw: bool = False, raw: bool = False,
quiet: bool = False, quiet: bool = False,
ignore_exceptions: bool = False ignore_exceptions: bool = False
) -> Iterable[Dict]: ) -> Union[Iterable[Dict], tuple]:
""" """
Main text parsing generator function. Returns an iterator object. Main text parsing generator function. Returns an iterator object.
@ -156,7 +157,10 @@ def parse(
raw: (boolean) unprocessed output if True raw: (boolean) unprocessed output if True
quiet: (boolean) suppress warning messages if True quiet: (boolean) suppress warning messages if True
ignore_exceptions: (boolean) ignore parsing exceptions if True ignore_exceptions: (boolean) ignore parsing exceptions if True.
This can be used directly or
(preferably) by being passed to the
@add_jc_meta decorator.
Yields: Yields:
@ -300,7 +304,7 @@ def parse(
'extended_attribute_different': extended_attribute_different[meta[10]] 'extended_attribute_different': extended_attribute_different[meta[10]]
} }
yield stream_success(output_line, ignore_exceptions) if raw else stream_success(_process(output_line), ignore_exceptions) yield output_line if raw else _process(output_line)
continue continue
file_line_mac = file_line_mac_re.match(line) file_line_mac = file_line_mac_re.match(line)
@ -322,14 +326,14 @@ def parse(
'group_different': group_different[meta[7]] 'group_different': group_different[meta[7]]
} }
yield stream_success(output_line, ignore_exceptions) if raw else stream_success(_process(output_line), ignore_exceptions) yield output_line if raw else _process(output_line)
continue continue
file_line_log = file_line_log_re.match(line) file_line_log = file_line_log_re.match(line)
if file_line_log: if file_line_log:
if process != last_process: if process != last_process:
if summary: if summary:
yield stream_success(summary, ignore_exceptions) if raw else stream_success(_process(summary), ignore_exceptions) yield output_line if raw else _process(output_line)
last_process = process last_process = process
summary = {} summary = {}
@ -358,14 +362,14 @@ def parse(
'extended_attribute_different': extended_attribute_different[meta[10]] 'extended_attribute_different': extended_attribute_different[meta[10]]
} }
yield stream_success(output_line, ignore_exceptions) if raw else stream_success(_process(output_line), ignore_exceptions) yield output_line if raw else _process(output_line)
continue continue
file_line_log_mac = file_line_log_mac_re.match(line) file_line_log_mac = file_line_log_mac_re.match(line)
if file_line_log_mac: if file_line_log_mac:
if process != last_process: if process != last_process:
if summary: if summary:
yield stream_success(summary, ignore_exceptions) if raw else stream_success(_process(summary), ignore_exceptions) yield output_line if raw else _process(output_line)
last_process = process last_process = process
summary = {} summary = {}
@ -392,7 +396,7 @@ def parse(
'group_different': group_different[meta[7]] 'group_different': group_different[meta[7]]
} }
yield stream_success(output_line, ignore_exceptions) if raw else stream_success(_process(output_line), ignore_exceptions) yield output_line if raw else _process(output_line)
continue continue
stat1_line = stat1_line_re.match(line) stat1_line = stat1_line_re.match(line)
@ -452,7 +456,7 @@ def parse(
continue continue
if summary: if summary:
yield stream_success(summary, ignore_exceptions) if raw else stream_success(_process(summary), ignore_exceptions) yield summary if raw else _process(summary)
except Exception as e: except Exception as e:
yield stream_error(e, ignore_exceptions, line) yield e, line

View File

@ -83,13 +83,13 @@ Examples:
""" """
import shlex import shlex
import jc.utils import jc.utils
from jc.utils import stream_success, stream_error from jc.utils import add_jc_meta
from jc.exceptions import ParseError from jc.exceptions import ParseError
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '0.5' version = '1.0'
description = '`stat` command streaming parser' description = '`stat` command streaming parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -130,6 +130,8 @@ def _process(proc_data):
return proc_data return proc_data
@add_jc_meta
def parse(data, raw=False, quiet=False, ignore_exceptions=False): def parse(data, raw=False, quiet=False, ignore_exceptions=False):
""" """
Main text parsing generator function. Returns an iterator object. Main text parsing generator function. Returns an iterator object.
@ -141,7 +143,10 @@ def parse(data, raw=False, quiet=False, ignore_exceptions=False):
raw: (boolean) unprocessed output if True raw: (boolean) unprocessed output if True
quiet: (boolean) suppress warning messages if True quiet: (boolean) suppress warning messages if True
ignore_exceptions: (boolean) ignore parsing exceptions if True ignore_exceptions: (boolean) ignore parsing exceptions if True.
This can be used directly or
(preferably) by being passed to the
@add_jc_meta decorator.
Yields: Yields:
@ -175,7 +180,7 @@ def parse(data, raw=False, quiet=False, ignore_exceptions=False):
# line #1 # line #1
if line.startswith(' File: '): if line.startswith(' File: '):
if output_line: if output_line:
yield stream_success(output_line, ignore_exceptions) if raw else stream_success(_process(output_line), ignore_exceptions) yield output_line if raw else _process(output_line)
output_line = {} output_line = {}
line_list = line.split(maxsplit=1) line_list = line.split(maxsplit=1)
@ -281,16 +286,16 @@ def parse(data, raw=False, quiet=False, ignore_exceptions=False):
} }
if output_line: if output_line:
yield stream_success(output_line, ignore_exceptions) if raw else stream_success(_process(output_line), ignore_exceptions) yield output_line if raw else _process(output_line)
output_line = {} output_line = {}
except Exception as e: except Exception as e:
yield stream_error(e, ignore_exceptions, line) yield e, line
output_line = {} output_line = {}
# gather final item # gather final item
if output_line: if output_line:
try: try:
yield stream_success(output_line, ignore_exceptions) if raw else stream_success(_process(output_line), ignore_exceptions) yield output_line if raw else _process(output_line)
except Exception as e: except Exception as e:
yield stream_error(e, ignore_exceptions, line) yield e, line

View File

@ -101,13 +101,13 @@ Examples:
... ...
""" """
import jc.utils import jc.utils
from jc.utils import stream_success, stream_error from jc.utils import add_jc_meta
from jc.exceptions import ParseError from jc.exceptions import ParseError
class info(): class info():
"""Provides parser metadata (version, author, etc.)""" """Provides parser metadata (version, author, etc.)"""
version = '0.6' version = '1.0'
description = '`vmstat` command streaming parser' description = '`vmstat` command streaming parser'
author = 'Kelly Brazil' author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com' author_email = 'kellyjonbrazil@gmail.com'
@ -150,6 +150,7 @@ def _process(proc_data):
return proc_data return proc_data
@add_jc_meta
def parse(data, raw=False, quiet=False, ignore_exceptions=False): def parse(data, raw=False, quiet=False, ignore_exceptions=False):
""" """
Main text parsing generator function. Returns an iterator object. Main text parsing generator function. Returns an iterator object.
@ -161,7 +162,10 @@ def parse(data, raw=False, quiet=False, ignore_exceptions=False):
raw: (boolean) unprocessed output if True raw: (boolean) unprocessed output if True
quiet: (boolean) suppress warning messages if True quiet: (boolean) suppress warning messages if True
ignore_exceptions: (boolean) ignore parsing exceptions if True ignore_exceptions: (boolean) ignore parsing exceptions if True.
This can be used directly or
(preferably) by being passed to the
@add_jc_meta decorator.
Yields: Yields:
@ -266,9 +270,9 @@ def parse(data, raw=False, quiet=False, ignore_exceptions=False):
} }
if output_line: if output_line:
yield stream_success(output_line, ignore_exceptions) if raw else stream_success(_process(output_line), ignore_exceptions) yield output_line if raw else _process(output_line)
else: else:
raise ParseError('Not vmstat data') raise ParseError('Not vmstat data')
except Exception as e: except Exception as e:
yield stream_error(e, ignore_exceptions, line) yield e, line

View File

@ -3,6 +3,7 @@ import sys
import re import re
import locale import locale
import shutil import shutil
from functools import wraps
from datetime import datetime, timezone from datetime import datetime, timezone
from textwrap import TextWrapper from textwrap import TextWrapper
from typing import Dict, Iterable, List, Union, Optional from typing import Dict, Iterable, List, Union, Optional
@ -248,6 +249,58 @@ def stream_error(e: BaseException, ignore_exceptions: bool, line: str) -> Dict:
} }
def add_jc_meta(func):
"""
Decorator for streaming parsers to add stream_success and stream_error
objects. This simplifies the yield lines in the streaming parsers.
With the decorator on parse():
# successfully parsed line:
yield output_line if raw else _process(output_line)
# unsuccessfully parsed line:
except Exception as e:
yield e, line
Without the decorator on parse():
# successfully parsed line:
yield stream_success(output_line, ignore_exceptions) if raw else stream_success(_process(output_line), ignore_exceptions)
# unsuccessfully parsed line:
except Exception as e:
yield stream_error(e, ignore_exceptions, line)
In all cases above:
output_line: (Dict): successfully parsed line yielded as a dict
e: (BaseException): exception object as the first value
of the tuple if the line was not successfully parsed.
line: (str): string of the original line that did not
successfully parse.
"""
@wraps(func)
def wrapper(*args, **kwargs):
ignore_exceptions = kwargs.get('ignore_exceptions', False)
gen = func(*args, **kwargs)
for value in gen:
# if the yielded value is a dict, then we know it was a
# successfully parsed line
if isinstance(value, dict):
yield stream_success(value, ignore_exceptions)
# otherwise it will be a tuple and we know it was an error
else:
exception_obj = value[0]
line = value[1]
yield stream_error(exception_obj, ignore_exceptions, line)
return wrapper
def input_type_check(data: str) -> None: def input_type_check(data: str) -> None:
"""Ensure input data is a string. Raises `TypeError` if not.""" """Ensure input data is a string. Raises `TypeError` if not."""
if not isinstance(data, str): if not isinstance(data, str):