csvpath 0.0.482__tar.gz → 0.0.484__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {csvpath-0.0.482 → csvpath-0.0.484}/PKG-INFO +2 -2
- {csvpath-0.0.482 → csvpath-0.0.484}/README.md +0 -1
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/csvpath.py +20 -9
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/csvpaths.py +100 -94
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/managers/file_manager.py +11 -2
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/managers/result.py +10 -2
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/args.py +16 -9
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/all.py +3 -1
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/andf.py +3 -7
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/any.py +3 -3
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/empty.py +2 -26
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/inf.py +2 -2
- csvpath-0.0.484/csvpath/matching/functions/boolean/orf.py +57 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/count.py +2 -5
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/every.py +2 -2
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/increment.py +3 -3
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/tally.py +2 -8
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/dates/now.py +2 -4
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/function.py +5 -3
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/function_factory.py +11 -8
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/collect.py +1 -1
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/end.py +1 -5
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/reset_headers.py +4 -2
- {csvpath-0.0.482/csvpath/matching/functions/types → csvpath-0.0.484/csvpath/matching/functions/math}/intf.py +6 -4
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/print/jinjaf.py +1 -1
- csvpath-0.0.484/csvpath/matching/functions/types/__init__.py +7 -0
- csvpath-0.0.484/csvpath/matching/functions/types/boolean.py +49 -0
- csvpath-0.0.484/csvpath/matching/functions/types/datef.py +138 -0
- csvpath-0.0.484/csvpath/matching/functions/types/decimal.py +92 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/types/nonef.py +28 -3
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/types/string.py +8 -6
- csvpath-0.0.484/csvpath/matching/functions/validity/line.py +166 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/variables/get.py +4 -1
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/variables/pushpop.py +1 -1
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/matcher.py +45 -3
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/matchable.py +14 -1
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/qualified.py +1 -1
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/util/expression_utility.py +32 -9
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/error.py +5 -30
- csvpath-0.0.484/csvpath/util/file_readers.py +70 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/line_counter.py +21 -20
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/comments.md +2 -2
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/header_names_mismatch.md +2 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/line.md +2 -2
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/now.md +5 -0
- csvpath-0.0.484/docs/functions/types.md +48 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/pyproject.toml +2 -1
- csvpath-0.0.482/csvpath/matching/functions/boolean/orf.py +0 -37
- csvpath-0.0.482/csvpath/matching/functions/types/boolean.py +0 -31
- csvpath-0.0.482/csvpath/matching/functions/types/datef.py +0 -40
- csvpath-0.0.482/csvpath/matching/functions/validity/line.py +0 -92
- {csvpath-0.0.482 → csvpath-0.0.484}/LICENSE +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/config/config.ini +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/__init__.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/managers/__init__.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/managers/csvpaths_manager.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/managers/results_manager.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/__init__.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/__init__.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/between.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/exists.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/no.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/notf.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/yes.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/count_headers.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/count_lines.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/count_scans.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/counter.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/has_matches.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/total_lines.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/function_finder.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/function_focus.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/append.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/empty_stack.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/header_name.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/header_names_mismatch.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/headers.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/mismatch.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/replace.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/lines/advance.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/lines/after_blank.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/lines/dups.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/lines/first.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/lines/first_line.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/lines/last.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/lines/stop.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/above.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/add.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/divide.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/equals.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/mod.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/multiply.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/round.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/subtotal.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/subtract.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/sum.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/misc/importf.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/misc/random.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/print/print_line.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/print/print_queue.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/print/printf.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/print/table.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/stats/minf.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/stats/percent.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/stats/percent_unique.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/stats/stdev.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/concat.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/length.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/lower.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/metaphone.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/regex.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/starts_with.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/strip.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/substring.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/upper.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/testing/debug.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/validity/fail.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/validity/failed.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/variables/put.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/variables/track.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/variables/variables.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/lark_parser.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/lark_transformer.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/__init__.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/equality.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/expression.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/header.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/reference.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/term.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/variable.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/util/exceptions.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/util/expression_encoder.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/util/lark_print_parser.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/util/print_parser.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/scanning/__init__.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/scanning/exceptions.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/scanning/parser.out +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/scanning/parsetab.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/scanning/scanner.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/scanning/scanning_lexer.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/cache.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/config.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/config_exception.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/exceptions.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/last_line_stats.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/line_monitor.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/log_utility.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/metadata_parser.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/printer.py +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/asbool.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/assignment.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/config.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/examples.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/files.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/above.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/advance.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/after_blank.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/all.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/andor.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/any.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/average.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/between.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/collect.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/correlate.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/count.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/count_headers.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/counter.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/date.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/empty.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/empty_stack.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/end.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/every.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/fail.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/first.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/get.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/has_dups.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/has_matches.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/header.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/header_name.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/implementing_functions.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/import.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/in.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/increment.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/intf.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/jinja.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/last.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/line_number.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/max.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/metaphone.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/mismatch.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/no.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/not.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/percent_unique.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/pop.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/print.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/print_line.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/print_queue.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/random.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/regex.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/replace.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/reset_headers.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/stdev.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/stop.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/string_functions.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/subtotal.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/subtract.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/sum.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/tally.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/total_lines.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/track.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/variables.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/variables_and_headers.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/grammar.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/headers.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/images/logo-wordmark-white-on-black-trimmed-padded.png +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/images/logo-wordmark-white-trimmed.png +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/paths.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/printing.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/qualifiers.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/references.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/terms.md +0 -0
- {csvpath-0.0.482 → csvpath-0.0.484}/docs/variables.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: csvpath
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.484
|
|
4
4
|
Summary: A declarative language for data extraction and validation of CSV files
|
|
5
5
|
Author: David Kershaw
|
|
6
6
|
Author-email: dk107dk@hotmail.com
|
|
@@ -26,6 +26,7 @@ Requires-Dist: jinja2 (>=3.1.4,<4.0.0)
|
|
|
26
26
|
Requires-Dist: lark (>=1.2.2,<2.0.0)
|
|
27
27
|
Requires-Dist: metaphone (>=0.6,<0.7)
|
|
28
28
|
Requires-Dist: ply (>=3.11,<4.0)
|
|
29
|
+
Requires-Dist: pylightxl (>=1.61,<2.0)
|
|
29
30
|
Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
|
|
30
31
|
Requires-Dist: tabulate (>=0.9.0,<0.10.0)
|
|
31
32
|
Project-URL: Csvpath.org, https://www.csvpath.org
|
|
@@ -48,7 +49,6 @@ And do it all in an automation-friendly way.
|
|
|
48
49
|
Though much simpler, it is inspired by:
|
|
49
50
|
- XPath. CsvPath is to CSV files like XPath is to XML files.
|
|
50
51
|
- Validation of XML using <a href='https://schematron.com/'>Schematron rules</a>
|
|
51
|
-
- The way CSS selectors pick out HTML structures
|
|
52
52
|
|
|
53
53
|
CsvPath is intended to fit with other DataOps and data quality tools. Files are streamed. The interface is simple. New functions are easy to create.
|
|
54
54
|
|
|
@@ -14,7 +14,6 @@ And do it all in an automation-friendly way.
|
|
|
14
14
|
Though much simpler, it is inspired by:
|
|
15
15
|
- XPath. CsvPath is to CSV files like XPath is to XML files.
|
|
16
16
|
- Validation of XML using <a href='https://schematron.com/'>Schematron rules</a>
|
|
17
|
-
- The way CSS selectors pick out HTML structures
|
|
18
17
|
|
|
19
18
|
CsvPath is intended to fit with other DataOps and data quality tools. Files are streamed. The interface is simple. New functions are easy to create.
|
|
20
19
|
|
|
@@ -14,7 +14,7 @@ from csvpath.util.log_utility import LogUtility
|
|
|
14
14
|
from .matching.matcher import Matcher
|
|
15
15
|
from .scanning.scanner import Scanner
|
|
16
16
|
from .util.metadata_parser import MetadataParser
|
|
17
|
-
from .util.error import Error, ErrorCollector
|
|
17
|
+
from .util.error import Error, ErrorCollector, ErrorCommsManager
|
|
18
18
|
from .util.printer import StdOutPrinter
|
|
19
19
|
from .util.line_counter import LineCounter
|
|
20
20
|
from .util.exceptions import VariableException, InputException, ParsingException
|
|
@@ -26,6 +26,7 @@ from .util.exceptions import (
|
|
|
26
26
|
)
|
|
27
27
|
from .matching.util.exceptions import MatchException
|
|
28
28
|
from csvpath.util.printer import Printer
|
|
29
|
+
from csvpath.util.file_readers import CsvDataFileReader
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
class CsvPathPublic(ABC):
|
|
@@ -262,6 +263,10 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
262
263
|
#
|
|
263
264
|
self.logger = LogUtility.logger(self)
|
|
264
265
|
self.logger.info("initialized CsvPath")
|
|
266
|
+
self._ecoms = ErrorCommsManager(csvpath=self)
|
|
267
|
+
|
|
268
|
+
def do_i_raise(self) -> bool:
|
|
269
|
+
return self._ecoms.do_i_raise()
|
|
265
270
|
|
|
266
271
|
@property
|
|
267
272
|
def advance_count(self) -> int: # pragma: no cover
|
|
@@ -569,7 +574,7 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
569
574
|
#
|
|
570
575
|
# settings:
|
|
571
576
|
# - logic-mode: AND | OR
|
|
572
|
-
# -
|
|
577
|
+
# - return-mode: matches | no-matches
|
|
573
578
|
# - print-mode: default | no-default
|
|
574
579
|
# - validation-mode: (no-)print | log | (no-)raise | quiet | (no-)match
|
|
575
580
|
#
|
|
@@ -606,15 +611,15 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
606
611
|
)
|
|
607
612
|
|
|
608
613
|
def update_match_mode_if(self) -> None:
|
|
609
|
-
if "
|
|
610
|
-
if f"{self.metadata['
|
|
614
|
+
if "return-mode" in self.metadata:
|
|
615
|
+
if f"{self.metadata['return-mode']}".strip() == "matches":
|
|
611
616
|
self.collect_when_not_matched = False
|
|
612
|
-
elif f"{self.metadata['
|
|
617
|
+
elif f"{self.metadata['return-mode']}".strip() == "no-matches":
|
|
613
618
|
self.collect_when_not_matched = True
|
|
614
619
|
else:
|
|
615
620
|
self.logger.warning(
|
|
616
|
-
"Incorrect metadata field value '
|
|
617
|
-
self.metadata["
|
|
621
|
+
"Incorrect metadata field value 'return-mode': %s",
|
|
622
|
+
self.metadata["return-mode"],
|
|
618
623
|
)
|
|
619
624
|
|
|
620
625
|
def update_print_mode_if(self) -> None:
|
|
@@ -891,13 +896,19 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
891
896
|
#
|
|
892
897
|
if self.scanner.filename is None:
|
|
893
898
|
raise FileException("There is no filename")
|
|
899
|
+
"""
|
|
894
900
|
with open(self.scanner.filename, "r", encoding="utf-8") as file:
|
|
895
901
|
reader = csv.reader(
|
|
896
902
|
file, delimiter=self.delimiter, quotechar=self.quotechar
|
|
897
903
|
)
|
|
898
904
|
for line in reader:
|
|
899
|
-
|
|
900
|
-
|
|
905
|
+
"""
|
|
906
|
+
reader = CsvDataFileReader(
|
|
907
|
+
self.scanner.filename, delimiter=self.delimiter, quotechar=self.quotechar
|
|
908
|
+
)
|
|
909
|
+
for line in reader.next():
|
|
910
|
+
self.track_line(line=line)
|
|
911
|
+
yield line
|
|
901
912
|
self.finalize()
|
|
902
913
|
|
|
903
914
|
"""
|
|
@@ -273,14 +273,14 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
|
|
|
273
273
|
self.logger.info("Cleaning out any %s and %s results", filename, pathsname)
|
|
274
274
|
self.clean(paths=pathsname)
|
|
275
275
|
self.logger.info(
|
|
276
|
-
"Beginning
|
|
276
|
+
"Beginning FF %s with %s paths against file %s. No match results will be held.",
|
|
277
277
|
pathsname,
|
|
278
278
|
len(paths),
|
|
279
279
|
filename,
|
|
280
280
|
)
|
|
281
281
|
for i, path in enumerate(paths):
|
|
282
282
|
csvpath = self.csvpath()
|
|
283
|
-
self.logger.
|
|
283
|
+
self.logger.debug("Beginning to FF CsvPath instance: %s", csvpath)
|
|
284
284
|
result = Result(csvpath=csvpath, file_name=filename, paths_name=pathsname)
|
|
285
285
|
try:
|
|
286
286
|
self.results_manager.add_named_result(result)
|
|
@@ -439,6 +439,7 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
|
|
|
439
439
|
# but we'll do it for consistency.
|
|
440
440
|
#
|
|
441
441
|
self.logger.info("Beginning next_by_line with %s paths", len(csvpath_objects))
|
|
442
|
+
"""
|
|
442
443
|
with open(fn, "r", encoding="utf-8") as file:
|
|
443
444
|
reader = csv.reader(
|
|
444
445
|
file, delimiter=self.delimiter, quotechar=self.quotechar
|
|
@@ -446,105 +447,110 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
|
|
|
446
447
|
#
|
|
447
448
|
# re: R1702 -- totally agreed! deferring.
|
|
448
449
|
#
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
continue
|
|
478
|
-
if self._advance_all > 0:
|
|
479
|
-
logtxt = "Advance-all set. Setting advance. "
|
|
480
|
-
logtxt = f"{logtxt}CsvPath and its Matcher will handle the advancing."
|
|
481
|
-
self.logger.info(logtxt)
|
|
482
|
-
#
|
|
483
|
-
# CsvPath will handle advancing so we don't need to do
|
|
484
|
-
# anything, including track_line(line). we just need to
|
|
485
|
-
# see if we're setting advance or increasing it.
|
|
486
|
-
#
|
|
487
|
-
a = self.current_matcher.advance_count
|
|
488
|
-
if self._advance_all > a:
|
|
489
|
-
self.current_matcher.advance_count = self._advance_all
|
|
490
|
-
#
|
|
491
|
-
# all following CsvPaths must have their
|
|
492
|
-
# advance incremented -- with the advance not being simply
|
|
493
|
-
# additive, have to be mindful of any existing advance
|
|
494
|
-
# count!
|
|
495
|
-
#
|
|
496
|
-
if self.current_matcher.stopped: # pylint: disable=R1724
|
|
497
|
-
continue
|
|
498
|
-
|
|
450
|
+
"""
|
|
451
|
+
reader = FileManager.get_reader(
|
|
452
|
+
fn, delimiter=self.delimiter, quotechar=self.quotechar
|
|
453
|
+
)
|
|
454
|
+
stopped_count: List[int] = []
|
|
455
|
+
for line in reader.next():
|
|
456
|
+
# for line in reader: # pylint: disable=R1702
|
|
457
|
+
# question to self: should this default be in a central place
|
|
458
|
+
# so that we can switch to OR, in part by changing the default?
|
|
459
|
+
keep = if_all_agree
|
|
460
|
+
self._skip_all = False
|
|
461
|
+
self._advance_all = 0
|
|
462
|
+
try:
|
|
463
|
+
# p is a (CsvPath, List[List[str]]) where the second item is
|
|
464
|
+
# the line-by-line results of the first item's matching
|
|
465
|
+
for p in csvpath_objects:
|
|
466
|
+
self.current_matcher = p[0]
|
|
467
|
+
if self._fail_all:
|
|
468
|
+
self.logger.warning(
|
|
469
|
+
"Fail-all set. Setting CsvPath is_valid to False."
|
|
470
|
+
)
|
|
471
|
+
self.current_matcher.is_valid = False
|
|
472
|
+
if self._stop_all:
|
|
473
|
+
self.logger.warning("Stop-all set. Shutting down run.")
|
|
474
|
+
self.current_matcher.stopped = True
|
|
475
|
+
continue
|
|
476
|
+
if self._skip_all:
|
|
477
|
+
self.logger.warning("Skip-all set. Continuing to next.")
|
|
499
478
|
#
|
|
500
|
-
#
|
|
501
|
-
#
|
|
502
|
-
# results in different named-results, as well as the
|
|
503
|
-
# union
|
|
479
|
+
# all following CsvPaths must have their
|
|
480
|
+
# line_monitors incremented
|
|
504
481
|
#
|
|
505
|
-
self.logger.debug(
|
|
506
|
-
"considering line with csvpath identified as: %s",
|
|
507
|
-
self.current_matcher.identity,
|
|
508
|
-
)
|
|
509
|
-
matched = False
|
|
510
482
|
self.current_matcher.track_line(line)
|
|
483
|
+
continue
|
|
484
|
+
if self._advance_all > 0:
|
|
485
|
+
logtxt = "Advance-all set. Setting advance. "
|
|
486
|
+
logtxt = f"{logtxt}CsvPath and its Matcher will handle the advancing."
|
|
487
|
+
self.logger.info(logtxt)
|
|
511
488
|
#
|
|
512
|
-
#
|
|
489
|
+
# CsvPath will handle advancing so we don't need to do
|
|
490
|
+
# anything, including track_line(line). we just need to
|
|
491
|
+
# see if we're setting advance or increasing it.
|
|
513
492
|
#
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
)
|
|
518
|
-
)
|
|
519
|
-
if self.current_matcher.stopped:
|
|
520
|
-
stopped_count.append(1)
|
|
521
|
-
if if_all_agree:
|
|
522
|
-
keep = keep and matched
|
|
523
|
-
else:
|
|
524
|
-
keep = keep or matched
|
|
493
|
+
a = self.current_matcher.advance_count
|
|
494
|
+
if self._advance_all > a:
|
|
495
|
+
self.current_matcher.advance_count = self._advance_all
|
|
525
496
|
#
|
|
526
|
-
#
|
|
527
|
-
#
|
|
528
|
-
#
|
|
497
|
+
# all following CsvPaths must have their
|
|
498
|
+
# advance incremented -- with the advance not being simply
|
|
499
|
+
# additive, have to be mindful of any existing advance
|
|
500
|
+
# count!
|
|
529
501
|
#
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
502
|
+
if self.current_matcher.stopped: # pylint: disable=R1724
|
|
503
|
+
continue
|
|
504
|
+
|
|
505
|
+
#
|
|
506
|
+
# allowing the match to happen regardless of keep
|
|
507
|
+
# because we may want side-effects or to have different
|
|
508
|
+
# results in different named-results, as well as the
|
|
509
|
+
# union
|
|
510
|
+
#
|
|
511
|
+
self.logger.debug(
|
|
512
|
+
"considering line with csvpath identified as: %s",
|
|
513
|
+
self.current_matcher.identity,
|
|
514
|
+
)
|
|
515
|
+
matched = False
|
|
516
|
+
self.current_matcher.track_line(line)
|
|
517
|
+
#
|
|
518
|
+
# re: W0212: treating _consider_line something like package private
|
|
519
|
+
#
|
|
520
|
+
matched = (
|
|
521
|
+
self.current_matcher._consider_line( # pylint:disable=W0212
|
|
522
|
+
line
|
|
523
|
+
)
|
|
524
|
+
)
|
|
525
|
+
if self.current_matcher.stopped:
|
|
526
|
+
stopped_count.append(1)
|
|
527
|
+
if if_all_agree:
|
|
528
|
+
keep = keep and matched
|
|
529
|
+
else:
|
|
530
|
+
keep = keep or matched
|
|
531
|
+
#
|
|
532
|
+
# not doing continue if we have if_all_agree and not keep as we
|
|
533
|
+
# used to do allows individual results to have lines that in
|
|
534
|
+
# aggregate we do not keep.
|
|
535
|
+
#
|
|
536
|
+
if matched and collect:
|
|
537
|
+
line = self.current_matcher.limit_collection(line)
|
|
538
|
+
p[1].append(line)
|
|
539
|
+
except Exception as ex: # pylint: disable=W0718
|
|
540
|
+
ex.trace = traceback.format_exc()
|
|
541
|
+
ex.source = self
|
|
542
|
+
ErrorHandler(
|
|
543
|
+
csvpaths=self, error_collector=self.current_matcher
|
|
544
|
+
).handle_error(ex)
|
|
545
|
+
# we yield even if we stopped in this iteration.
|
|
546
|
+
# caller needs to see what we stopped on.
|
|
547
|
+
#
|
|
548
|
+
# ! we only yield if keep is True
|
|
549
|
+
#
|
|
550
|
+
if keep:
|
|
551
|
+
yield line
|
|
552
|
+
if sum(stopped_count) == len(csvpath_objects):
|
|
553
|
+
break
|
|
548
554
|
self.clear_run_coordination()
|
|
549
555
|
|
|
550
556
|
def _load_csvpath_objects(
|
|
@@ -3,13 +3,14 @@ import os
|
|
|
3
3
|
import json
|
|
4
4
|
import csv
|
|
5
5
|
import hashlib
|
|
6
|
+
from abc import ABC, abstractmethod
|
|
6
7
|
from json import JSONDecodeError
|
|
7
8
|
from typing import Dict, List, Tuple
|
|
8
|
-
from abc import ABC, abstractmethod
|
|
9
9
|
from ..util.line_counter import LineCounter
|
|
10
10
|
from ..util.line_monitor import LineMonitor
|
|
11
11
|
from ..util.error import ErrorHandler
|
|
12
12
|
from ..util.cache import Cache
|
|
13
|
+
from ..util.file_readers import CsvDataFileReader
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class CsvPathsFileManager(ABC):
|
|
@@ -53,7 +54,7 @@ class CsvPathsFileManager(ABC):
|
|
|
53
54
|
|
|
54
55
|
|
|
55
56
|
class FileManager(CsvPathsFileManager): # pylint: disable=C0115
|
|
56
|
-
def __init__(self, *, named_files: Dict[str, str] = None, csvpaths):
|
|
57
|
+
def __init__(self, *, named_files: Dict[str, str] = None, csvpaths=None):
|
|
57
58
|
if named_files is None:
|
|
58
59
|
named_files = {}
|
|
59
60
|
self.named_files: Dict[str, str] = named_files
|
|
@@ -142,6 +143,14 @@ class FileManager(CsvPathsFileManager): # pylint: disable=C0115
|
|
|
142
143
|
return None
|
|
143
144
|
return self.named_files[name]
|
|
144
145
|
|
|
146
|
+
def get_named_file_reader(self, name: str) -> CsvDataFileReader:
|
|
147
|
+
path = self.get_named_file(name)
|
|
148
|
+
return FileManager.get_reader(path)
|
|
149
|
+
|
|
150
|
+
@classmethod
|
|
151
|
+
def get_reader(cls, path: str, delimiter=None, quotechar=None) -> CsvDataFileReader:
|
|
152
|
+
return CsvDataFileReader(path, delimiter=delimiter, quotechar=quotechar)
|
|
153
|
+
|
|
145
154
|
def remove_named_file(self, name: str) -> None:
|
|
146
155
|
if name in self.named_files:
|
|
147
156
|
del self.named_files[name]
|
|
@@ -163,14 +163,22 @@ class Result(ErrorCollector, Printer): # pylint: disable=R0902
|
|
|
163
163
|
return i
|
|
164
164
|
|
|
165
165
|
def __str__(self) -> str:
|
|
166
|
+
lastline = 0
|
|
167
|
+
endline = -1
|
|
168
|
+
try:
|
|
169
|
+
# if we haven't started yet -- common situation -- we may blow up.
|
|
170
|
+
lastline = self.csvpath.line_monitor.physical_line_number
|
|
171
|
+
endline = self.csvpath.line_monitor.physical_end_line_number
|
|
172
|
+
except Exception:
|
|
173
|
+
pass
|
|
166
174
|
return f"""Result
|
|
167
175
|
file:{self.csvpath.scanner.filename if self.csvpath.scanner else None};
|
|
168
176
|
name of paths:{self.paths_name};
|
|
169
177
|
name of file:{self.file_name};
|
|
170
178
|
valid:{self.csvpath.is_valid};
|
|
171
179
|
stopped:{self.csvpath.stopped};
|
|
172
|
-
last line processed:{
|
|
173
|
-
total file lines:{
|
|
180
|
+
last line processed:{lastline};
|
|
181
|
+
total file lines:{endline};
|
|
174
182
|
matches:{self.csvpath.match_count};
|
|
175
183
|
lines captured:{len(self.lines) if self.lines else 0};
|
|
176
184
|
print statements:{self.print_statements_count()};
|
|
@@ -16,9 +16,12 @@ from csvpath.util.config_exception import ConfigurationException
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class Arg:
|
|
19
|
-
def __init__(
|
|
19
|
+
def __init__(
|
|
20
|
+
self, *, name: str = None, types: list[Type] = None, actuals: list[Type] = None
|
|
21
|
+
):
|
|
20
22
|
self.is_noneable = False
|
|
21
23
|
self._types = None
|
|
24
|
+
self._name = name
|
|
22
25
|
self._x_actuals = None
|
|
23
26
|
self.types: list[Type] = types or [None]
|
|
24
27
|
self.actuals: list[Type] = actuals or []
|
|
@@ -100,8 +103,10 @@ class ArgSet:
|
|
|
100
103
|
# setup time
|
|
101
104
|
# ----------------------------
|
|
102
105
|
|
|
103
|
-
def arg(
|
|
104
|
-
|
|
106
|
+
def arg(
|
|
107
|
+
self, *, name: str = None, types: list[Type] = None, actuals: list[Type] = None
|
|
108
|
+
) -> Arg:
|
|
109
|
+
arg = Arg(name=name, types=types, actuals=actuals)
|
|
105
110
|
self._args.append(arg)
|
|
106
111
|
if len(self._args) > self.max_length and self.max_length != -1:
|
|
107
112
|
self.max_length = len(self._args)
|
|
@@ -194,16 +199,17 @@ class ArgSet:
|
|
|
194
199
|
self._args = args
|
|
195
200
|
self.max_length = len(self._args)
|
|
196
201
|
|
|
197
|
-
def validate_structure(self, siblings: List[Matchable]) -> None:
|
|
202
|
+
def validate_structure(self, siblings: List[Matchable]) -> None | str:
|
|
198
203
|
b = self._validate_length(siblings)
|
|
199
204
|
if b is False:
|
|
200
|
-
return
|
|
205
|
+
return "incorrect number of args"
|
|
201
206
|
self._pad_or_shrink(siblings)
|
|
202
207
|
for i, s in enumerate(siblings):
|
|
203
208
|
t = tuple(self._args[i].types)
|
|
204
209
|
if not isinstance(s, t):
|
|
205
|
-
|
|
206
|
-
|
|
210
|
+
ii = i + 1
|
|
211
|
+
return f"type mismatch at arg {ii}"
|
|
212
|
+
return None
|
|
207
213
|
|
|
208
214
|
# ----------------------------
|
|
209
215
|
# match actuals line-by-line
|
|
@@ -390,11 +396,12 @@ class Args:
|
|
|
390
396
|
#
|
|
391
397
|
good = False
|
|
392
398
|
for aset in self._argsets:
|
|
393
|
-
|
|
399
|
+
_m = aset.validate_structure(siblings)
|
|
400
|
+
if _m is None:
|
|
394
401
|
good = True
|
|
395
402
|
if not good:
|
|
396
403
|
_ = f" at {self.matchable.my_chain}" if self.matchable else ""
|
|
397
|
-
msg = f"{self._csvpath_id()} Incorrectly written{_}. Wrong type or number of args."
|
|
404
|
+
msg = f"{self._csvpath_id()} Incorrectly written{_}. Wrong type or number of args: {_m}."
|
|
398
405
|
raise ChildrenException(msg)
|
|
399
406
|
self.validated = True
|
|
400
407
|
|
|
@@ -19,7 +19,9 @@ class All(MatchDecider):
|
|
|
19
19
|
self.args = Args(matchable=self)
|
|
20
20
|
self.args.argset(0)
|
|
21
21
|
self.args.argset(1).arg(types=[None, Variables, Headers], actuals=[])
|
|
22
|
-
self.args.argset().arg(
|
|
22
|
+
self.args.argset().arg(
|
|
23
|
+
types=[None, Function, Variable, Header], actuals=[None, Any]
|
|
24
|
+
)
|
|
23
25
|
self.args.validate(self.siblings())
|
|
24
26
|
super().check_valid()
|
|
25
27
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Any
|
|
4
4
|
from ..function_focus import MatchDecider
|
|
5
|
-
from csvpath.matching.productions import
|
|
5
|
+
from csvpath.matching.productions import Matchable
|
|
6
6
|
from ..function import Function
|
|
7
7
|
from ..args import Args
|
|
8
8
|
|
|
@@ -15,12 +15,8 @@ class And(MatchDecider):
|
|
|
15
15
|
def check_valid(self) -> None: # pragma: no cover
|
|
16
16
|
self.args = Args(matchable=self)
|
|
17
17
|
a = self.args.argset()
|
|
18
|
-
a.arg(
|
|
19
|
-
|
|
20
|
-
)
|
|
21
|
-
a.arg(
|
|
22
|
-
types=[Term, Variable, Header, Function, Reference, Equality], actuals=[Any]
|
|
23
|
-
)
|
|
18
|
+
a.arg(types=[Matchable], actuals=[None, Any])
|
|
19
|
+
a.arg(types=[Matchable], actuals=[None, Any])
|
|
24
20
|
self.args.validate(self.siblings_or_equality())
|
|
25
21
|
super().check_valid()
|
|
26
22
|
|
|
@@ -24,11 +24,11 @@ class Any(MatchDecider):
|
|
|
24
24
|
a = self.args.argset(0)
|
|
25
25
|
|
|
26
26
|
a = self.args.argset(2)
|
|
27
|
-
a.arg(types=[Variables, Headers], actuals=[Any])
|
|
28
|
-
a.arg(types=[typing.Any], actuals=[typing.Any])
|
|
27
|
+
a.arg(types=[Variables, Headers], actuals=[None, typing.Any])
|
|
28
|
+
a.arg(types=[typing.Any], actuals=[None, typing.Any])
|
|
29
29
|
|
|
30
30
|
a = self.args.argset(1)
|
|
31
|
-
a.arg(types=[typing.Any, Variables, Headers], actuals=[typing.Any])
|
|
31
|
+
a.arg(types=[typing.Any, Variables, Headers], actuals=[None, typing.Any])
|
|
32
32
|
|
|
33
33
|
self.args.validate(self.siblings())
|
|
34
34
|
super().check_valid()
|
|
@@ -33,7 +33,7 @@ class Empty(MatchDecider):
|
|
|
33
33
|
def _validate(self):
|
|
34
34
|
sibs = self.siblings()
|
|
35
35
|
for s in sibs:
|
|
36
|
-
# both
|
|
36
|
+
# both structure / children exceptions
|
|
37
37
|
if isinstance(s, Headers) and len(sibs) > 1:
|
|
38
38
|
raise ChildrenException(
|
|
39
39
|
"If empty() has a headers() argument it can only have 1 argument"
|
|
@@ -73,12 +73,7 @@ class Empty(MatchDecider):
|
|
|
73
73
|
self.match = ret
|
|
74
74
|
|
|
75
75
|
def _do_many(self, skip=None):
|
|
76
|
-
siblings =
|
|
77
|
-
if isinstance(self.children[0], Equality):
|
|
78
|
-
siblings = self.children[0].commas_to_list()
|
|
79
|
-
else:
|
|
80
|
-
siblings = self.children[0]
|
|
81
|
-
|
|
76
|
+
siblings = self.siblings()
|
|
82
77
|
for s in siblings:
|
|
83
78
|
self._do_one(s)
|
|
84
79
|
if self.match is False:
|
|
@@ -87,22 +82,3 @@ class Empty(MatchDecider):
|
|
|
87
82
|
def _do_one(self, child, skip=None):
|
|
88
83
|
v = child.to_value(skip=skip)
|
|
89
84
|
self.match = ExpressionUtility.is_empty(v)
|
|
90
|
-
|
|
91
|
-
"""
|
|
92
|
-
def _is_empty(self, v):
|
|
93
|
-
ret = True
|
|
94
|
-
if v is None:
|
|
95
|
-
ret = True
|
|
96
|
-
elif f"{v}".strip() == "":
|
|
97
|
-
ret = True
|
|
98
|
-
elif isinstance(v, list) or isinstance(v, tuple):
|
|
99
|
-
for item in v:
|
|
100
|
-
ret = self._is_empty(item)
|
|
101
|
-
if not ret:
|
|
102
|
-
break
|
|
103
|
-
elif isinstance(v, dict):
|
|
104
|
-
ret = len(v) > 0
|
|
105
|
-
else:
|
|
106
|
-
ret = False
|
|
107
|
-
return ret
|
|
108
|
-
"""
|
|
@@ -13,8 +13,8 @@ class In(MatchDecider):
|
|
|
13
13
|
def check_valid(self) -> None:
|
|
14
14
|
self.args = Args(matchable=self)
|
|
15
15
|
a = self.args.argset()
|
|
16
|
-
a.arg(types=[Term, Variable, Header, Function, Reference], actuals=[Any])
|
|
17
|
-
a.arg(types=[Term, Variable, Header, Function, Reference], actuals=[Any])
|
|
16
|
+
a.arg(types=[Term, Variable, Header, Function, Reference], actuals=[None, Any])
|
|
17
|
+
a.arg(types=[Term, Variable, Header, Function, Reference], actuals=[None, Any])
|
|
18
18
|
self.args.validate(self.siblings())
|
|
19
19
|
super().check_valid()
|
|
20
20
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# pylint: disable=C0114
|
|
2
|
+
from typing import Any
|
|
3
|
+
from ..function_focus import MatchDecider
|
|
4
|
+
from csvpath.matching.productions import (
|
|
5
|
+
Term,
|
|
6
|
+
Variable,
|
|
7
|
+
Header,
|
|
8
|
+
Reference,
|
|
9
|
+
Equality,
|
|
10
|
+
Matchable,
|
|
11
|
+
)
|
|
12
|
+
from ..function import Function
|
|
13
|
+
from ..args import Args
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Or(MatchDecider):
|
|
17
|
+
"""does a logical OR of match components"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, matcher: Any, name: str, child: Matchable = None) -> None:
|
|
20
|
+
super().__init__(matcher, name=name, child=child)
|
|
21
|
+
self.hold = []
|
|
22
|
+
|
|
23
|
+
def reset(self) -> None:
|
|
24
|
+
self.hold = []
|
|
25
|
+
super().reset()
|
|
26
|
+
|
|
27
|
+
def check_valid(self) -> None:
|
|
28
|
+
self.args = Args(matchable=self)
|
|
29
|
+
a = self.args.argset()
|
|
30
|
+
a.arg(types=[Matchable], actuals=[None, Any])
|
|
31
|
+
a.arg(types=[Matchable], actuals=[None, Any])
|
|
32
|
+
self.args.validate(self.siblings_or_equality())
|
|
33
|
+
super().check_valid()
|
|
34
|
+
|
|
35
|
+
def raise_if(self, e, *, cause=None) -> None:
|
|
36
|
+
# not bubbling up until we know we don't have a
|
|
37
|
+
# match on all options
|
|
38
|
+
self.hold.append((e, cause))
|
|
39
|
+
|
|
40
|
+
def _produce_value(self, skip=None) -> None:
|
|
41
|
+
self.value = self.matches(skip=skip)
|
|
42
|
+
|
|
43
|
+
def _decide_match(self, skip=None) -> None:
|
|
44
|
+
child = self.children[0]
|
|
45
|
+
siblings = child.commas_to_list()
|
|
46
|
+
for sib in siblings:
|
|
47
|
+
b = sib.matches(skip=skip)
|
|
48
|
+
if b:
|
|
49
|
+
self.match = True
|
|
50
|
+
# if we find a True we succeed and dump any errors
|
|
51
|
+
self.hold = []
|
|
52
|
+
return
|
|
53
|
+
self.match = False
|
|
54
|
+
# if we fail we progress any errors up the stack
|
|
55
|
+
for err in self.hold:
|
|
56
|
+
super().raise_if(err[0], cause=err[1])
|
|
57
|
+
self.hold = []
|
|
@@ -3,7 +3,7 @@ from typing import Any
|
|
|
3
3
|
from ..function_focus import ValueProducer
|
|
4
4
|
from ..function import Function
|
|
5
5
|
from ..args import Args
|
|
6
|
-
from csvpath.matching.productions import
|
|
6
|
+
from csvpath.matching.productions import Matchable
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class Count(ValueProducer):
|
|
@@ -16,10 +16,7 @@ class Count(ValueProducer):
|
|
|
16
16
|
self.args = Args(matchable=self)
|
|
17
17
|
a = self.args.argset(0)
|
|
18
18
|
a = self.args.argset()
|
|
19
|
-
a.arg(
|
|
20
|
-
types=[None, Variable, Function, Header, Term, Equality],
|
|
21
|
-
actuals=[None, Any],
|
|
22
|
-
)
|
|
19
|
+
a.arg(types=[None, Matchable], actuals=[None, Any])
|
|
23
20
|
self.args.validate(self.siblings())
|
|
24
21
|
#
|
|
25
22
|
super().check_valid() # pylint: disable=W0246
|