csvpath 0.0.484__tar.gz → 0.0.485__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.484 → csvpath-0.0.485}/PKG-INFO +5 -5
- {csvpath-0.0.484 → csvpath-0.0.485}/README.md +2 -2
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/csvpath.py +148 -37
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/csvpaths.py +4 -2
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/managers/csvpaths_manager.py +31 -5
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/args.py +19 -8
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/any.py +1 -1
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/empty.py +2 -2
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/function.py +41 -8
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/lines/first_line.py +2 -2
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/sum.py +1 -1
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/misc/importf.py +10 -3
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/stats/percent.py +1 -1
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/regex.py +1 -1
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/types/datef.py +10 -18
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/types/decimal.py +6 -8
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/validity/failed.py +1 -1
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/validity/line.py +7 -11
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/matcher.py +92 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/equality.py +27 -4
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/expression.py +3 -1
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/header.py +6 -2
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/matchable.py +44 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/reference.py +53 -15
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/variable.py +9 -2
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/comments.md +4 -0
- csvpath-0.0.485/docs/functions/import.md +95 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/pyproject.toml +3 -3
- csvpath-0.0.484/docs/functions/import.md +0 -47
- {csvpath-0.0.484 → csvpath-0.0.485}/LICENSE +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/config/config.ini +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/__init__.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/managers/__init__.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/managers/file_manager.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/managers/result.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/managers/results_manager.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/__init__.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/__init__.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/all.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/andf.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/between.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/exists.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/inf.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/no.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/notf.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/orf.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/yes.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/count.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/count_headers.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/count_lines.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/count_scans.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/counter.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/every.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/has_matches.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/increment.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/tally.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/total_lines.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/dates/now.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/function_factory.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/function_finder.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/function_focus.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/append.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/collect.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/empty_stack.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/end.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/header_name.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/header_names_mismatch.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/headers.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/mismatch.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/replace.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/reset_headers.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/lines/advance.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/lines/after_blank.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/lines/dups.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/lines/first.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/lines/last.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/lines/stop.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/above.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/add.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/divide.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/equals.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/intf.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/mod.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/multiply.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/round.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/subtotal.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/subtract.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/misc/random.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/print/jinjaf.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/print/print_line.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/print/print_queue.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/print/printf.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/print/table.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/stats/minf.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/stats/percent_unique.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/stats/stdev.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/concat.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/length.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/lower.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/metaphone.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/starts_with.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/strip.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/substring.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/upper.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/testing/debug.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/types/__init__.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/types/boolean.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/types/nonef.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/types/string.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/validity/fail.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/variables/get.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/variables/pushpop.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/variables/put.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/variables/track.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/variables/variables.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/lark_parser.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/lark_transformer.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/__init__.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/qualified.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/term.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/util/exceptions.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/util/expression_encoder.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/util/expression_utility.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/util/lark_print_parser.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/util/print_parser.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/scanning/__init__.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/scanning/exceptions.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/scanning/parser.out +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/scanning/parsetab.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/scanning/scanner.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/scanning/scanning_lexer.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/cache.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/config.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/config_exception.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/error.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/exceptions.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/file_readers.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/last_line_stats.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/line_counter.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/line_monitor.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/log_utility.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/metadata_parser.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/printer.py +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/asbool.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/assignment.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/config.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/examples.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/files.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/above.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/advance.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/after_blank.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/all.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/andor.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/any.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/average.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/between.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/collect.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/correlate.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/count.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/count_headers.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/counter.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/date.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/empty.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/empty_stack.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/end.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/every.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/fail.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/first.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/get.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/has_dups.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/has_matches.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/header.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/header_name.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/header_names_mismatch.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/implementing_functions.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/in.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/increment.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/intf.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/jinja.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/last.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/line.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/line_number.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/max.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/metaphone.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/mismatch.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/no.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/not.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/now.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/percent_unique.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/pop.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/print.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/print_line.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/print_queue.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/random.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/regex.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/replace.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/reset_headers.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/stdev.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/stop.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/string_functions.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/subtotal.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/subtract.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/sum.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/tally.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/total_lines.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/track.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/types.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/variables.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/variables_and_headers.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/grammar.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/headers.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/images/logo-wordmark-white-on-black-trimmed-padded.png +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/images/logo-wordmark-white-trimmed.png +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/paths.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/printing.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/qualifiers.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/references.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/terms.md +0 -0
- {csvpath-0.0.484 → csvpath-0.0.485}/docs/variables.md +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: csvpath
|
|
3
|
-
Version: 0.0.
|
|
4
|
-
Summary: A declarative language for
|
|
3
|
+
Version: 0.0.485
|
|
4
|
+
Summary: A declarative language for validation of CSV files
|
|
5
5
|
Author: David Kershaw
|
|
6
6
|
Author-email: dk107dk@hotmail.com
|
|
7
7
|
Requires-Python: >=3.9,<4.0
|
|
@@ -30,7 +30,7 @@ Requires-Dist: pylightxl (>=1.61,<2.0)
|
|
|
30
30
|
Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
|
|
31
31
|
Requires-Dist: tabulate (>=0.9.0,<0.10.0)
|
|
32
32
|
Project-URL: Csvpath.org, https://www.csvpath.org
|
|
33
|
-
Project-URL: Github, https://github.com/
|
|
33
|
+
Project-URL: Github, https://github.com/csvpath/csvpath.git
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
|
|
36
36
|
|
|
@@ -141,12 +141,12 @@ Interactive use of csvpaths can be valuable, too, of course. There is a trivial
|
|
|
141
141
|
<a name="running"></a>
|
|
142
142
|
## Running CsvPath
|
|
143
143
|
|
|
144
|
-
CsvPath is <a href='https://pypi.org/project/csvpath/'>available on Pypi here</a>. The <a href='https://github.com/
|
|
144
|
+
CsvPath is <a href='https://pypi.org/project/csvpath/'>available on Pypi here</a>. The <a href='https://github.com/csvpath/csvpath'>git repo is here</a>.
|
|
145
145
|
|
|
146
146
|
Two classes provide the functionality: CsvPath and CsvPaths. Each has only a few external methods.
|
|
147
147
|
|
|
148
148
|
### CsvPath
|
|
149
|
-
(<a href='https://github.com/
|
|
149
|
+
(<a href='https://github.com/csvpath/csvpath/blob/main/csvpath/csvpath.py'>code</a>)
|
|
150
150
|
The CsvPath class is the basic entry point for running csvpaths.
|
|
151
151
|
|method |function |
|
|
152
152
|
|----------------------------|----------------------------------------------------------------|
|
|
@@ -106,12 +106,12 @@ Interactive use of csvpaths can be valuable, too, of course. There is a trivial
|
|
|
106
106
|
<a name="running"></a>
|
|
107
107
|
## Running CsvPath
|
|
108
108
|
|
|
109
|
-
CsvPath is <a href='https://pypi.org/project/csvpath/'>available on Pypi here</a>. The <a href='https://github.com/
|
|
109
|
+
CsvPath is <a href='https://pypi.org/project/csvpath/'>available on Pypi here</a>. The <a href='https://github.com/csvpath/csvpath'>git repo is here</a>.
|
|
110
110
|
|
|
111
111
|
Two classes provide the functionality: CsvPath and CsvPaths. Each has only a few external methods.
|
|
112
112
|
|
|
113
113
|
### CsvPath
|
|
114
|
-
(<a href='https://github.com/
|
|
114
|
+
(<a href='https://github.com/csvpath/csvpath/blob/main/csvpath/csvpath.py'>code</a>)
|
|
115
115
|
The CsvPath class is the basic entry point for running csvpaths.
|
|
116
116
|
|method |function |
|
|
117
117
|
|----------------------------|----------------------------------------------------------------|
|
|
@@ -37,7 +37,9 @@ class CsvPathPublic(ABC):
|
|
|
37
37
|
"""Reads a csvpath prepares to match against CSV file lines"""
|
|
38
38
|
|
|
39
39
|
@abstractmethod
|
|
40
|
-
def parse_named_path(
|
|
40
|
+
def parse_named_path(
|
|
41
|
+
self, name, *, disposably=False, specific=None
|
|
42
|
+
): # pragma: no cover
|
|
41
43
|
"""Parses a csvpath found in this CsvPath's CsvPaths parent's
|
|
42
44
|
collection of named csvpaths"""
|
|
43
45
|
|
|
@@ -155,6 +157,16 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
155
157
|
#
|
|
156
158
|
self._freeze_path = False
|
|
157
159
|
#
|
|
160
|
+
# explain-mode: explain
|
|
161
|
+
# turns on capturing match reasoning and dumps the captured decisions to INFO
|
|
162
|
+
# at the end of a match. the reasoning is already present in the DEBUG but it
|
|
163
|
+
# is harder to see amid all the noise. we don't want to dump explainations
|
|
164
|
+
# all the time tho because it is very expensive -- potentially 25% worse
|
|
165
|
+
# performance. the explainations could be improved. atm this is an experimental
|
|
166
|
+
# feature.
|
|
167
|
+
#
|
|
168
|
+
self._explain = False
|
|
169
|
+
#
|
|
158
170
|
# counts are 1-based
|
|
159
171
|
#
|
|
160
172
|
self.scan_count = 0
|
|
@@ -256,6 +268,14 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
256
268
|
self._stop_on_validation_errors = None
|
|
257
269
|
self._fail_on_validation_errors = None
|
|
258
270
|
#
|
|
271
|
+
# run mode determines if a csvpath gets run or if it is skipped. the
|
|
272
|
+
# main reasons to set run-mode: no-run vs. run are: you want to import
|
|
273
|
+
# it into other csvpaths that are in the same named-paths group, or
|
|
274
|
+
# you want to switch off a csvpath in a named-paths group for testing
|
|
275
|
+
# a similar reason.
|
|
276
|
+
#
|
|
277
|
+
self._run_mode = True
|
|
278
|
+
#
|
|
259
279
|
# there are two logger components one for CsvPath and one for CsvPaths.
|
|
260
280
|
# the default levels are set in config.ini. to change the levels pass LogUtility
|
|
261
281
|
# your component instance and the logging level. e.g.:
|
|
@@ -264,6 +284,38 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
264
284
|
self.logger = LogUtility.logger(self)
|
|
265
285
|
self.logger.info("initialized CsvPath")
|
|
266
286
|
self._ecoms = ErrorCommsManager(csvpath=self)
|
|
287
|
+
self._function_times_match = {}
|
|
288
|
+
self._function_times_value = {}
|
|
289
|
+
|
|
290
|
+
@property
|
|
291
|
+
def run_mode(self) -> bool:
|
|
292
|
+
return self._run_mode
|
|
293
|
+
|
|
294
|
+
@run_mode.setter
|
|
295
|
+
def run_mode(self, mode) -> None:
|
|
296
|
+
self._run_mode = mode
|
|
297
|
+
|
|
298
|
+
def _up_function_time_match(self, c, t) -> None:
|
|
299
|
+
if c not in self.function_times_match:
|
|
300
|
+
self.function_times_match[c] = 0
|
|
301
|
+
st = self.function_times_match[c]
|
|
302
|
+
st += t
|
|
303
|
+
self.function_times_match[c] = st
|
|
304
|
+
|
|
305
|
+
@property
|
|
306
|
+
def function_times_match(self) -> int:
|
|
307
|
+
return self._function_times_match
|
|
308
|
+
|
|
309
|
+
def _up_function_time_value(self, c, t) -> None:
|
|
310
|
+
if c not in self.function_times_value:
|
|
311
|
+
self.function_times_value[c] = 0
|
|
312
|
+
st = self.function_times_value[c]
|
|
313
|
+
st += t
|
|
314
|
+
self.function_times_value[c] = st
|
|
315
|
+
|
|
316
|
+
@property
|
|
317
|
+
def function_times_value(self) -> int:
|
|
318
|
+
return self._function_times_value
|
|
267
319
|
|
|
268
320
|
def do_i_raise(self) -> bool:
|
|
269
321
|
return self._ecoms.do_i_raise()
|
|
@@ -507,6 +559,18 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
507
559
|
def is_frozen(self, freeze: bool) -> None:
|
|
508
560
|
self._freeze_path = freeze
|
|
509
561
|
|
|
562
|
+
@property
|
|
563
|
+
def explain(self) -> bool:
|
|
564
|
+
"""when this property is True CsvPath dumps a match explaination
|
|
565
|
+
to INFO. this can be expensive. a 25% performance hit wouldn't
|
|
566
|
+
be unexpected.
|
|
567
|
+
"""
|
|
568
|
+
return self._explain
|
|
569
|
+
|
|
570
|
+
@explain.setter
|
|
571
|
+
def explain(self, yesno: bool) -> None:
|
|
572
|
+
self._explain = yesno
|
|
573
|
+
|
|
510
574
|
@property
|
|
511
575
|
def collect_when_not_matched(self) -> bool:
|
|
512
576
|
"""when this property is True CsvPath returns the lines that do not
|
|
@@ -579,8 +643,10 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
579
643
|
# - validation-mode: (no-)print | log | (no-)raise | quiet | (no-)match
|
|
580
644
|
#
|
|
581
645
|
self.update_logic_mode_if()
|
|
646
|
+
self.update_run_mode_if()
|
|
582
647
|
self.update_match_mode_if()
|
|
583
648
|
self.update_print_mode_if()
|
|
649
|
+
self.update_explain_mode_if()
|
|
584
650
|
self.update_arg_validation_mode_if()
|
|
585
651
|
|
|
586
652
|
def update_arg_validation_mode_if(self) -> None:
|
|
@@ -598,6 +664,18 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
598
664
|
self.metadata["validation-mode"],
|
|
599
665
|
)
|
|
600
666
|
|
|
667
|
+
def update_run_mode_if(self) -> None:
|
|
668
|
+
if self.metadata and "run-mode" in self.metadata:
|
|
669
|
+
if f"{self.metadata['run-mode']}".strip() == "no-run":
|
|
670
|
+
self.run_mode = False
|
|
671
|
+
elif f"{self.metadata['run-mode']}".strip() == "run":
|
|
672
|
+
self.run_mode = True
|
|
673
|
+
else:
|
|
674
|
+
self.logger.warning(
|
|
675
|
+
"Incorrect metadata field value 'run-mode': %s",
|
|
676
|
+
self.metadata["run-mode"],
|
|
677
|
+
)
|
|
678
|
+
|
|
601
679
|
def update_logic_mode_if(self) -> None:
|
|
602
680
|
if self.metadata and "logic-mode" in self.metadata:
|
|
603
681
|
if f"{self.metadata['logic-mode']}".strip() == "AND":
|
|
@@ -622,6 +700,15 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
622
700
|
self.metadata["return-mode"],
|
|
623
701
|
)
|
|
624
702
|
|
|
703
|
+
def update_explain_mode_if(self) -> None:
|
|
704
|
+
if "explain-mode" in self.metadata:
|
|
705
|
+
if f"{self.metadata['explain-mode']}".strip() == "no-explain":
|
|
706
|
+
self._explain = False
|
|
707
|
+
elif f"{self.metadata['explain-mode']}".strip() == "explain":
|
|
708
|
+
self._explain = True
|
|
709
|
+
else:
|
|
710
|
+
self._explain = False
|
|
711
|
+
|
|
625
712
|
def update_print_mode_if(self) -> None:
|
|
626
713
|
if "print-mode" in self.metadata:
|
|
627
714
|
if f"{self.metadata['print-mode']}".strip() == "no-default":
|
|
@@ -646,32 +733,50 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
646
733
|
self.metadata["print-mode"],
|
|
647
734
|
)
|
|
648
735
|
|
|
649
|
-
def
|
|
650
|
-
"""disposably is True when a Matcher is needed for some purpose other than
|
|
651
|
-
the run we were created to do. could be that a match component wanted a
|
|
652
|
-
parsed csvpath for its own purposes. import() uses this method.
|
|
653
|
-
|
|
654
|
-
when True, we create and return the Matcher, but then forget it ever existed.
|
|
655
|
-
|
|
656
|
-
also note: the path must have a name or full filename. $[*] is not enough.
|
|
657
|
-
"""
|
|
736
|
+
def _pick_named_path(self, name, *, specific=None) -> str:
|
|
658
737
|
if not self.csvpaths:
|
|
659
738
|
raise CsvPathsException("No CsvPaths object available")
|
|
660
739
|
np = self.csvpaths.paths_manager.get_named_paths(name)
|
|
661
740
|
if not np:
|
|
662
|
-
raise CsvPathsException(f"Named
|
|
741
|
+
raise CsvPathsException(f"Named-paths '{name}' not found")
|
|
663
742
|
if len(np) == 0:
|
|
664
|
-
raise CsvPathsException(f"Named
|
|
665
|
-
if len(np)
|
|
743
|
+
raise CsvPathsException(f"Named-paths '{name}' has no csvpaths")
|
|
744
|
+
if len(np) == 1:
|
|
745
|
+
return np[0]
|
|
746
|
+
if specific is None:
|
|
666
747
|
self.logger.warning(
|
|
667
|
-
"
|
|
748
|
+
"Parse_named_path %s has %s csvpaths. Using just the first one.",
|
|
668
749
|
name,
|
|
669
750
|
len(np),
|
|
670
751
|
)
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
752
|
+
return np[0]
|
|
753
|
+
for p in np:
|
|
754
|
+
# this ends up being redundant to the caller. we do it 1x so it's not
|
|
755
|
+
# a big lift and is consistent.
|
|
756
|
+
c = CsvPath()
|
|
757
|
+
MetadataParser(c).extract_metadata(instance=c, csvpath=p)
|
|
758
|
+
if c.identity == specific:
|
|
759
|
+
return p
|
|
760
|
+
self.logger.error(
|
|
761
|
+
"Cannot find csvpath identified as %s in named-paths %s", specific, name
|
|
762
|
+
)
|
|
763
|
+
raise ParsingException(f"Cannot find path '{specific}' in named-paths '{name}'")
|
|
764
|
+
|
|
765
|
+
def parse_named_path(self, name, *, disposably=False, specific=None):
|
|
766
|
+
"""disposably is True when a Matcher is needed for some purpose other than
|
|
767
|
+
the run we were created to do. could be that a match component wanted a
|
|
768
|
+
parsed csvpath for its own purposes. import() uses this method.
|
|
769
|
+
when True, we create and return the Matcher, but then forget it ever existed.
|
|
770
|
+
also note: the path must have a name or full filename. $[*] is not enough.
|
|
771
|
+
"""
|
|
772
|
+
if not self.csvpaths:
|
|
773
|
+
raise CsvPathsException("No CsvPaths object available")
|
|
774
|
+
|
|
775
|
+
path = self._pick_named_path(name, specific=specific)
|
|
776
|
+
c = CsvPath()
|
|
777
|
+
path = MetadataParser(c).extract_metadata(instance=c, csvpath=path)
|
|
778
|
+
path = c._update_file_path(path)
|
|
779
|
+
dis = c.parse(path, disposably=disposably)
|
|
675
780
|
if disposably is True:
|
|
676
781
|
return dis
|
|
677
782
|
return None
|
|
@@ -753,6 +858,7 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
753
858
|
def __str__(self):
|
|
754
859
|
return f"""
|
|
755
860
|
path: {self.scanner.path if self.scanner else None}
|
|
861
|
+
identity: {self.identity}
|
|
756
862
|
parsers: [scanner=Ply, matcher=Lark, print=Lark]
|
|
757
863
|
from_line: {self.scanner.from_line if self.scanner else None}
|
|
758
864
|
to_line: {self.scanner.to_line if self.scanner else None}
|
|
@@ -852,25 +958,30 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
852
958
|
the csvpath. collect() and fast_forward() call next() behind the scenes.
|
|
853
959
|
"""
|
|
854
960
|
start = time.time()
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
self.
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
961
|
+
if self.run_mode is True:
|
|
962
|
+
for line in self._next_line():
|
|
963
|
+
b = self._consider_line(line)
|
|
964
|
+
if b:
|
|
965
|
+
line = self.limit_collection(line)
|
|
966
|
+
if line is None:
|
|
967
|
+
msg = "Line cannot be None"
|
|
968
|
+
self.logger.error(msg)
|
|
969
|
+
raise MatchException(msg)
|
|
970
|
+
if len(line) == 0:
|
|
971
|
+
msg = "Line cannot be len() == 0"
|
|
972
|
+
self.logger.error(msg)
|
|
973
|
+
raise MatchException(msg)
|
|
974
|
+
yield line
|
|
975
|
+
if self.stopped:
|
|
976
|
+
self.logger.info(
|
|
977
|
+
"CsvPath has been stopped at line %s",
|
|
978
|
+
self.line_monitor.physical_line_number,
|
|
979
|
+
)
|
|
980
|
+
break
|
|
981
|
+
else:
|
|
982
|
+
self.logger.warning(
|
|
983
|
+
"Csvpath identified as {self.identity} is disabled by run-mode:no-run"
|
|
984
|
+
)
|
|
874
985
|
self.finalize()
|
|
875
986
|
# moving to finalize
|
|
876
987
|
# self._freeze_path = True
|
|
@@ -206,9 +206,11 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
|
|
|
206
206
|
self.results_manager.clean_named_results(paths)
|
|
207
207
|
|
|
208
208
|
def _validate_paths_and_file(self, *, pathsname, filename) -> None:
|
|
209
|
-
if
|
|
209
|
+
if not self.paths_manager.has_named_paths(pathsname): # pragma: no cover
|
|
210
210
|
keys = list(self.paths_manager.named_paths.keys())
|
|
211
|
-
raise InputException(
|
|
211
|
+
raise InputException(
|
|
212
|
+
f"Pathsname '{pathsname}' must be a named set of paths in {keys}"
|
|
213
|
+
)
|
|
212
214
|
if filename not in self.file_manager.named_files: # pragma: no cover
|
|
213
215
|
keys = self.file_manager.named_files.keys()
|
|
214
216
|
raise InputException(f"Filename must be a named file in {keys}")
|
|
@@ -7,6 +7,9 @@ from abc import ABC, abstractmethod
|
|
|
7
7
|
from ..util.exceptions import InputException
|
|
8
8
|
from ..util.error import ErrorHandler
|
|
9
9
|
|
|
10
|
+
from csvpath import CsvPath
|
|
11
|
+
from csvpath.util.metadata_parser import MetadataParser
|
|
12
|
+
|
|
10
13
|
|
|
11
14
|
class CsvPathsManager(ABC):
|
|
12
15
|
"""holds paths (the path itself, not a file name or reference) in a named set.
|
|
@@ -169,10 +172,33 @@ class PathsManager(CsvPathsManager): # pylint: disable=C0115, C0116
|
|
|
169
172
|
# files_manager and let csvpaths call the shots.
|
|
170
173
|
#
|
|
171
174
|
def get_named_paths(self, name: str) -> List[str]:
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
175
|
+
ret = None
|
|
176
|
+
p2 = self._paths_name_path(name)
|
|
177
|
+
if p2[1] is None and p2[0] in self.named_paths:
|
|
178
|
+
ret = self.named_paths[p2[0]]
|
|
179
|
+
elif p2[1] is not None:
|
|
180
|
+
ret = self._find_one(p2)
|
|
181
|
+
return ret
|
|
182
|
+
|
|
183
|
+
def _paths_name_path(self, pathsname) -> tuple[str, str]:
|
|
184
|
+
specificpath = None
|
|
185
|
+
i = pathsname.find("#")
|
|
186
|
+
if i > 0:
|
|
187
|
+
specificpath = pathsname[i + 1 :]
|
|
188
|
+
pathsname = pathsname[0:i]
|
|
189
|
+
return (pathsname, specificpath)
|
|
190
|
+
|
|
191
|
+
def _find_one(self, p2: tuple[str]) -> str:
|
|
192
|
+
if p2[1] is not None:
|
|
193
|
+
paths = self.get_named_paths(p2[0])
|
|
194
|
+
for path in paths:
|
|
195
|
+
c = CsvPath()
|
|
196
|
+
MetadataParser(c).extract_metadata(instance=c, csvpath=path)
|
|
197
|
+
if c.identity == p2[1]:
|
|
198
|
+
return [path]
|
|
199
|
+
raise InputException(
|
|
200
|
+
f"Path identified as '{p2[1]}' must be in the group identitied as '{p2[0]}'"
|
|
201
|
+
)
|
|
176
202
|
|
|
177
203
|
def remove_named_paths(self, name: str) -> None:
|
|
178
204
|
if name in self.named_paths:
|
|
@@ -181,7 +207,7 @@ class PathsManager(CsvPathsManager): # pylint: disable=C0115, C0116
|
|
|
181
207
|
raise InputException("{name} not found")
|
|
182
208
|
|
|
183
209
|
def has_named_paths(self, name: str) -> bool:
|
|
184
|
-
return
|
|
210
|
+
return self.get_named_paths(name)
|
|
185
211
|
|
|
186
212
|
def number_of_named_paths(self) -> bool:
|
|
187
213
|
return len(self.named_paths) # pragma: no cover
|
|
@@ -400,9 +400,16 @@ class Args:
|
|
|
400
400
|
if _m is None:
|
|
401
401
|
good = True
|
|
402
402
|
if not good:
|
|
403
|
+
# _ = f" at {self.matchable.my_chain}" if self.matchable else ""
|
|
404
|
+
# msg = f"{self._csvpath_id()} Incorrectly written{_}. Wrong type or number of args: {_m}."
|
|
405
|
+
# raise ChildrenException(msg)
|
|
406
|
+
#
|
|
403
407
|
_ = f" at {self.matchable.my_chain}" if self.matchable else ""
|
|
404
|
-
msg = f"
|
|
405
|
-
|
|
408
|
+
msg = f"Incorrectly written{_}. Wrong type or number of args: {_m}."
|
|
409
|
+
if self._matchable is None:
|
|
410
|
+
# this should only be testing
|
|
411
|
+
raise ChildrenException(msg)
|
|
412
|
+
self._matchable.raiseChildrenException(msg)
|
|
406
413
|
self.validated = True
|
|
407
414
|
|
|
408
415
|
def matches(self, actuals: List[Any]) -> None:
|
|
@@ -451,10 +458,14 @@ class Args:
|
|
|
451
458
|
self._args_match = False
|
|
452
459
|
pm = f"mismatch in {self.matchable.my_chain}: {mismatches}"
|
|
453
460
|
# when would we not have a csvpath?
|
|
454
|
-
pln = (
|
|
455
|
-
|
|
456
|
-
)
|
|
457
|
-
csvpathid = f"{self._csvpath_id()} " if self._csvpath_id() else ""
|
|
461
|
+
# pln = (
|
|
462
|
+
# self._csvpath.line_monitor.physical_line_number if self._csvpath else 0
|
|
463
|
+
# )
|
|
464
|
+
# csvpathid = f"{self._csvpath_id()} " if self._csvpath_id() else ""
|
|
465
|
+
# ei = ExpressionUtility.get_my_expressions_index(self._matchable)
|
|
466
|
+
# pm = f"{csvpathid}Wrong value in match component {ei} at line {pln}: {pm}"
|
|
467
|
+
# raise ChildrenValidationException(pm)
|
|
468
|
+
#
|
|
458
469
|
ei = ExpressionUtility.get_my_expressions_index(self._matchable)
|
|
459
|
-
pm = f"
|
|
460
|
-
|
|
470
|
+
pm = f"Wrong value in match component {ei}: {pm}"
|
|
471
|
+
self._matchable.raiseChildrenException(pm)
|
|
@@ -35,11 +35,11 @@ class Empty(MatchDecider):
|
|
|
35
35
|
for s in sibs:
|
|
36
36
|
# both structure / children exceptions
|
|
37
37
|
if isinstance(s, Headers) and len(sibs) > 1:
|
|
38
|
-
|
|
38
|
+
self.raiseChildrenException(
|
|
39
39
|
"If empty() has a headers() argument it can only have 1 argument"
|
|
40
40
|
)
|
|
41
41
|
if isinstance(s, Term):
|
|
42
|
-
|
|
42
|
+
self.raiseChildrenException(
|
|
43
43
|
"empty() arguments cannot include terms"
|
|
44
44
|
) # pragma: no cover
|
|
45
45
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# pylint: disable=C0114
|
|
2
2
|
import traceback
|
|
3
3
|
import signal
|
|
4
|
+
import time
|
|
4
5
|
from typing import Any
|
|
5
6
|
from ..productions.matchable import Matchable
|
|
6
7
|
from ..util.exceptions import ChildrenException
|
|
@@ -39,7 +40,14 @@ class Function(Matchable):
|
|
|
39
40
|
if not skip:
|
|
40
41
|
skip = []
|
|
41
42
|
if self in skip: # pragma: no cover
|
|
42
|
-
|
|
43
|
+
ret = self._noop_value()
|
|
44
|
+
self.valuing().result(ret).because("skip")
|
|
45
|
+
return ret
|
|
46
|
+
#
|
|
47
|
+
# experiment -- timing
|
|
48
|
+
#
|
|
49
|
+
startval = time.perf_counter_ns()
|
|
50
|
+
# exp end
|
|
43
51
|
if self.do_frozen():
|
|
44
52
|
# doing frozen means not doing anything else. this is the
|
|
45
53
|
# inverse of onmatch and other qualifiers. but it makes sense
|
|
@@ -80,17 +88,29 @@ class Function(Matchable):
|
|
|
80
88
|
# Term and Header, but maybe not for Function?
|
|
81
89
|
if isinstance(self.value, str):
|
|
82
90
|
self.value = self.value.strip()
|
|
91
|
+
#
|
|
92
|
+
# experiment - timing
|
|
93
|
+
#
|
|
94
|
+
endval = time.perf_counter_ns()
|
|
95
|
+
t = (endval - startval) / 1000000
|
|
96
|
+
self.matcher.csvpath._up_function_time_value(self.__class__, t)
|
|
97
|
+
#
|
|
98
|
+
# exp end
|
|
99
|
+
#
|
|
83
100
|
return self.value
|
|
84
101
|
|
|
85
102
|
def matches(self, *, skip=None) -> bool:
|
|
86
103
|
if not skip:
|
|
87
104
|
skip = []
|
|
88
105
|
if self in skip: # pragma: no cover
|
|
89
|
-
|
|
106
|
+
ret = self.default_match()
|
|
107
|
+
self.matching().result(ret).because("skip")
|
|
108
|
+
return ret
|
|
90
109
|
#
|
|
91
|
-
# experiment
|
|
92
|
-
# them at the end of the line.
|
|
110
|
+
# experiment -- timing
|
|
93
111
|
#
|
|
112
|
+
startmatch = time.perf_counter_ns()
|
|
113
|
+
# exp end
|
|
94
114
|
try:
|
|
95
115
|
#
|
|
96
116
|
#
|
|
@@ -101,7 +121,9 @@ class Function(Matchable):
|
|
|
101
121
|
# and we're not talking about a qualifier, in any case. the
|
|
102
122
|
# csvpath writer doesn't know anything about this.
|
|
103
123
|
self.matcher.csvpath.logger.debug("We're frozen in %s", self)
|
|
104
|
-
|
|
124
|
+
ret = self._noop_value()
|
|
125
|
+
self.matching().result(ret).because("frozen")
|
|
126
|
+
return ret
|
|
105
127
|
if self.match is None:
|
|
106
128
|
if self.do_onmatch():
|
|
107
129
|
#
|
|
@@ -136,9 +158,9 @@ class Function(Matchable):
|
|
|
136
158
|
#
|
|
137
159
|
sibs = self.sibling_values(skip=skip)
|
|
138
160
|
if Matchable.FAILED_VALUE in sibs:
|
|
139
|
-
pln = self.matcher.csvpath.line_monitor.physical_line_number
|
|
140
|
-
|
|
141
|
-
f"
|
|
161
|
+
# pln = self.matcher.csvpath.line_monitor.physical_line_number
|
|
162
|
+
self.raiseChildrenException(
|
|
163
|
+
f"Cannot continue with {self.my_chain} due to an invalid child"
|
|
142
164
|
)
|
|
143
165
|
#
|
|
144
166
|
# ready to run the match!
|
|
@@ -178,16 +200,27 @@ class Function(Matchable):
|
|
|
178
200
|
self.matcher.csvpath.logger.debug(
|
|
179
201
|
"Function.matches _decide_match returned %s", self.match
|
|
180
202
|
)
|
|
203
|
+
self.matching().result(self.match)
|
|
181
204
|
else:
|
|
182
205
|
self.match = self.default_match()
|
|
183
206
|
self.matcher.csvpath.logger.debug(
|
|
184
207
|
f"@{self}: appling default match, {self.match}, because !do_onmatch"
|
|
185
208
|
)
|
|
209
|
+
self.matching().result(self.match).because("onmatch")
|
|
186
210
|
except Exception as e:
|
|
187
211
|
e.trace = traceback.format_exc()
|
|
188
212
|
e.source = self
|
|
189
213
|
e.json = self.to_json()
|
|
190
214
|
self.my_expression.handle_error(e)
|
|
215
|
+
#
|
|
216
|
+
# experiment - timing
|
|
217
|
+
#
|
|
218
|
+
endmatch = time.perf_counter_ns()
|
|
219
|
+
t = (endmatch - startmatch) / 1000000
|
|
220
|
+
self.matcher.csvpath._up_function_time_match(self.__class__, t)
|
|
221
|
+
#
|
|
222
|
+
# exp end
|
|
223
|
+
#
|
|
191
224
|
return self.match
|
|
192
225
|
|
|
193
226
|
def _produce_value(self, skip=None) -> None:
|
|
@@ -17,12 +17,12 @@ class FirstLine(MatchDecider):
|
|
|
17
17
|
if len(self.children) == 1 and isinstance(self.children[0], Equality):
|
|
18
18
|
if not self.children[0].op == "=":
|
|
19
19
|
# correct as structure / children exception
|
|
20
|
-
|
|
20
|
+
self.raiseChildrenException(
|
|
21
21
|
"Child can only be either a function or a variable assignment"
|
|
22
22
|
)
|
|
23
23
|
if self.name not in ["firstmatch", "firstscan", "firstline"]:
|
|
24
24
|
# correct as structure / children exception
|
|
25
|
-
|
|
25
|
+
self.raiseChildrenException(f"Unknown function name: {self.name}")
|
|
26
26
|
super().check_valid()
|
|
27
27
|
|
|
28
28
|
def _produce_value(self, skip=None) -> None:
|
|
@@ -12,7 +12,7 @@ class Sum(ValueProducer):
|
|
|
12
12
|
def check_valid(self) -> None:
|
|
13
13
|
self.args = Args(matchable=self)
|
|
14
14
|
a = self.args.argset(1)
|
|
15
|
-
a.arg(types=[Variable, Function, Term, Header], actuals=[int])
|
|
15
|
+
a.arg(types=[Variable, Function, Term, Header], actuals=[int, float])
|
|
16
16
|
self.args.validate(self.siblings())
|
|
17
17
|
super().check_valid()
|
|
18
18
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pylint: disable=C0114
|
|
2
2
|
from typing import Any
|
|
3
|
-
from csvpath.matching.productions import Term
|
|
3
|
+
from csvpath.matching.productions import Term, Reference
|
|
4
4
|
from csvpath.matching.util.exceptions import MatchComponentException
|
|
5
5
|
from csvpath.matching.util.expression_utility import ExpressionUtility
|
|
6
6
|
from csvpath.matching.util.expression_encoder import ExpressionEncoder
|
|
@@ -18,7 +18,7 @@ class Import(SideEffect):
|
|
|
18
18
|
def check_valid(self) -> None:
|
|
19
19
|
self.args = Args(matchable=self)
|
|
20
20
|
a = self.args.argset(1)
|
|
21
|
-
a.arg(types=[Term], actuals=[str])
|
|
21
|
+
a.arg(types=[Term, Reference], actuals=[str])
|
|
22
22
|
self.args.validate(self.siblings())
|
|
23
23
|
super().check_valid()
|
|
24
24
|
#
|
|
@@ -43,13 +43,20 @@ class Import(SideEffect):
|
|
|
43
43
|
if name is None:
|
|
44
44
|
raise MatchComponentException("Name of import csvpath cannot be None")
|
|
45
45
|
|
|
46
|
+
specific = None
|
|
47
|
+
if name.find("#") > -1:
|
|
48
|
+
specific = name[name.find("#") + 1 :]
|
|
49
|
+
name = name[0 : name.find("#")]
|
|
50
|
+
|
|
46
51
|
self.matcher.csvpath.logger.info("Starting import from %s", name)
|
|
47
52
|
|
|
48
53
|
e = ExpressionUtility.get_my_expression(self)
|
|
49
54
|
if e is None:
|
|
50
55
|
raise MatchComponentException("Cannot find my expression: {self}")
|
|
51
56
|
|
|
52
|
-
amatcher = self.matcher.csvpath.parse_named_path(
|
|
57
|
+
amatcher = self.matcher.csvpath.parse_named_path(
|
|
58
|
+
name=name, disposably=True, specific=specific
|
|
59
|
+
)
|
|
53
60
|
if (
|
|
54
61
|
amatcher is None
|
|
55
62
|
or not amatcher.expressions
|
|
@@ -21,7 +21,7 @@ class Percent(ValueProducer):
|
|
|
21
21
|
if which not in ["scan", "match", "line"]:
|
|
22
22
|
# correct structure / children exception. we could probably do this
|
|
23
23
|
# in check_validate since we're requiring a Term, but this is fine.
|
|
24
|
-
|
|
24
|
+
self.raiseChildrenException(
|
|
25
25
|
"percent() argument must be scan, match, or line"
|
|
26
26
|
) # pragma: no cover
|
|
27
27
|
if which == "line":
|
|
@@ -57,7 +57,7 @@ class Regex(MatchDecider):
|
|
|
57
57
|
return theregex, thevalue, group
|
|
58
58
|
else:
|
|
59
59
|
# correct structure / children exception
|
|
60
|
-
|
|
60
|
+
self.raiseChildrenException("No regular expression available")
|
|
61
61
|
|
|
62
62
|
def _produce_value(self, skip=None) -> None:
|
|
63
63
|
child = self.children[0]
|