csvpath 0.0.514__tar.gz → 0.0.516__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.514 → csvpath-0.0.516}/PKG-INFO +37 -33
- {csvpath-0.0.514 → csvpath-0.0.516}/README.md +36 -32
- {csvpath-0.0.514 → csvpath-0.0.516}/config/config.ini +15 -2
- csvpath-0.0.516/csvpath/cli/asker.py +90 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/cli/cli.py +68 -22
- csvpath-0.0.516/csvpath/cli/debug_config.py +94 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/cli/drill_down.py +14 -10
- csvpath-0.0.514/csvpath/cli/select.py → csvpath-0.0.516/csvpath/cli/selecter.py +24 -8
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/csvpath.py +3 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/errors/error_comms.py +19 -2
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/errors/error_manager.py +40 -4
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/files/file_manager.py +17 -5
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/files/file_metadata.py +3 -3
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/files/file_registrar.py +7 -1
- csvpath-0.0.516/csvpath/managers/files/files_listener.py +84 -0
- csvpath-0.0.516/csvpath/managers/paths/paths_listener.py +72 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/paths/paths_manager.py +25 -40
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/paths/paths_metadata.py +2 -2
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/paths/paths_registrar.py +2 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/function_factory.py +6 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/headers/append.py +1 -1
- csvpath-0.0.516/csvpath/matching/functions/math/odd.py +31 -0
- csvpath-0.0.516/csvpath/matching/functions/strings/caps.py +40 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/productions/qualified.py +20 -2
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/productions/variable.py +7 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/modes/error_mode.py +1 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/config.py +19 -1
- csvpath-0.0.516/docs/functions/odd.md +15 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/string_functions.md +5 -1
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions.md +2 -0
- csvpath-0.0.516/docs/images/sftpplus-logo2.png +0 -0
- csvpath-0.0.516/docs/images/sftpplus-logo3.png +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/qualifiers.md +9 -1
- {csvpath-0.0.514 → csvpath-0.0.516}/pyproject.toml +1 -1
- csvpath-0.0.514/csvpath/cli/error.py +0 -61
- {csvpath-0.0.514 → csvpath-0.0.516}/LICENSE +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/__init__.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/cli/__init__.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/csvpaths.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/__init__.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/errors/error.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/errors/error_collector.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/files/file_cacher.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ckan/ckan.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ckan/ckan_listener.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ckan/datafile.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ckan/dataset.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ol/event.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ol/event_result.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ol/file_listener_ol.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ol/job.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ol/ol_listener.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ol/paths_listener_ol.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ol/result_listener_ol.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ol/results_listener_ol.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ol/run.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ol/run_listener_ol.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ol/run_state.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/ol/sender.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/otlp/error_metrics.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/otlp/metrics.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/otlp/otlp_error_listener.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/otlp/otlp_listener.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/otlp/otlp_result_listener.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/otlp/otlp_results_listener.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/sftp/sftp_sender.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/sftpplus/arrival_handler.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/sftpplus/rpc.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/sftpplus/sftpplus_listener.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/sftpplus/transfer_creator.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/sftpplus/transfers.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/slack/event.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/integrations/slack/sender.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/listener.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/metadata.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/registrar.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/results/readers/file_errors_reader.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/results/readers/file_lines_reader.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/results/readers/file_printouts_reader.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/results/readers/file_unmatched_reader.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/results/readers/readers.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/results/result.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/results/result_file_reader.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/results/result_metadata.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/results/result_registrar.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/results/result_serializer.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/results/results_manager.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/results/results_metadata.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/results/results_registrar.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/run/run_listener_stdout.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/run/run_metadata.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/managers/run/run_registrar.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/__init__.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/__init__.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/args.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/args_helper.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/boolean/all.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/boolean/andf.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/boolean/any.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/boolean/between.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/boolean/empty.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/boolean/exists.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/boolean/inf.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/boolean/no.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/boolean/notf.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/boolean/orf.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/boolean/yes.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/counting/count.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/counting/count_bytes.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/counting/count_headers.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/counting/count_lines.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/counting/count_scans.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/counting/counter.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/counting/every.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/counting/has_matches.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/counting/increment.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/counting/tally.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/counting/total_lines.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/dates/now.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/function.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/function_finder.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/function_focus.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/headers/collect.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/headers/empty_stack.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/headers/end.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/headers/header_name.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/headers/header_names_mismatch.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/headers/headers.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/headers/mismatch.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/headers/replace.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/headers/reset_headers.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/lines/advance.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/lines/after_blank.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/lines/dups.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/lines/first.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/lines/first_line.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/lines/last.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/lines/stop.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/math/above.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/math/add.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/math/divide.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/math/equals.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/math/intf.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/math/mod.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/math/multiply.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/math/round.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/math/subtotal.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/math/subtract.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/math/sum.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/misc/fingerprint.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/misc/importf.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/misc/random.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/print/jinjaf.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/print/print_line.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/print/print_queue.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/print/printf.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/print/table.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/stats/minf.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/stats/percent.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/stats/percent_unique.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/stats/stdev.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/strings/concat.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/strings/contains.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/strings/length.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/strings/lower.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/strings/metaphone.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/strings/regex.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/strings/starts_with.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/strings/strip.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/strings/substring.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/strings/upper.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/testing/debug.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/types/__init__.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/types/boolean.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/types/datef.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/types/decimal.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/types/email.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/types/nonef.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/types/string.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/types/type.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/types/url.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/validity/fail.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/validity/failed.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/validity/line.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/variables/get.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/variables/pushpop.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/variables/put.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/variables/track.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/functions/variables/variables.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/lark_parser.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/lark_transformer.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/matcher.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/productions/__init__.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/productions/equality.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/productions/expression.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/productions/header.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/productions/matchable.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/productions/reference.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/productions/term.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/util/exceptions.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/util/expression_encoder.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/util/expression_utility.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/util/lark_print_parser.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/util/print_parser.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/matching/util/runtime_data_collector.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/modes/explain_mode.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/modes/files_mode.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/modes/logic_mode.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/modes/mode_controller.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/modes/print_mode.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/modes/return_mode.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/modes/run_mode.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/modes/source_mode.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/modes/transfer_mode.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/modes/unmatched_mode.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/modes/validation_mode.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/scanning/__init__.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/scanning/exceptions.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/scanning/parser.out +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/scanning/parsetab.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/scanning/scanner.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/scanning/scanning_lexer.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/box.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/cache.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/class_loader.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/config_exception.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/exceptions.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/file_info.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/file_readers.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/file_writers.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/hasher.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/last_line_stats.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/line_counter.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/line_monitor.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/line_spooler.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/log_utility.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/metadata_parser.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/nos.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/pandas_data_reader.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/printer.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/reference_parser.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/s3/s3_data_reader.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/s3/s3_data_writer.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/s3/s3_fingerprinter.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/s3/s3_utils.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/s3/s3_xlsx_data_reader.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/csvpath/util/var_utility.py +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/asbool.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/assignment.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/comments.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/config.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/examples.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/files.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/above.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/advance.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/after_blank.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/all.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/andor.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/any.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/average.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/between.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/collect.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/contains.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/correlate.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/count.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/count_bytes.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/count_headers.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/counter.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/date.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/email.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/empty.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/empty_stack.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/end.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/equal.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/every.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/fail.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/fingerprint.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/first.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/get.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/has_dups.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/has_matches.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/header.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/header_name.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/header_names_mismatch.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/implementing_functions.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/import.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/in.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/increment.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/intf.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/jinja.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/last.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/line.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/line_number.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/max.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/metaphone.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/mismatch.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/no.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/not.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/now.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/percent_unique.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/pop.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/print.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/print_line.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/print_queue.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/random.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/regex.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/replace.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/reset_headers.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/stdev.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/stop.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/subtotal.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/subtract.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/sum.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/tally.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/total_lines.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/track.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/types.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/variables.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/functions/variables_and_headers.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/grammar.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/headers.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/images/ckan-logo-sm.png +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/images/csvpath-icon-sm.png +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/images/csvpath-logo-wordmark-tight-2.svg +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/images/logo-wordmark-3.svg +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/images/logo-wordmark-4.svg +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/images/logo-wordmark-white-on-black-trimmed-padded.png +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/images/logo-wordmark-white-trimmed.png +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/images/marquez-logo-sm.png +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/images/openlineage-logo-sm.png +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/images/opentelemetry.png +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/paths.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/printing.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/references.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/docs/terms.md +0 -0
- {csvpath-0.0.514 → csvpath-0.0.516}/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.516
|
|
4
4
|
Summary: An edge governance framework for managing and validating CSV, Excel, and other tabular data files
|
|
5
5
|
Author: David Kershaw
|
|
6
6
|
Author-email: dk107dk@hotmail.com
|
|
@@ -49,22 +49,22 @@ Description-Content-Type: text/markdown
|
|
|
49
49
|
|
|
50
50
|
# <a href='https://www.csvpath.org/'><img src='https://github.com/csvpath/csvpath/blob/main/docs/images/logo-wordmark-4.svg'/></a>
|
|
51
51
|
|
|
52
|
-
The CsvPath
|
|
52
|
+
The CsvPath Language defines a declarative syntax for inspecting and validating CSV and Excel files, and other tabular data.
|
|
53
53
|
|
|
54
|
-
The CsvPath
|
|
55
|
-
- Registers files
|
|
56
|
-
- Validates
|
|
57
|
-
-
|
|
58
|
-
- Shapes files
|
|
59
|
-
- And stages
|
|
54
|
+
The CsvPath Framework makes it easy to setup a <a href='https://www.atestaanalytics.com/s/The-Collect-Store-Validate-Pattern-Atesta-Analytics.pdf'>Collect, Store, Validate Pattern</a> flat-file landing zone that:
|
|
55
|
+
- Registers files for **clear and durable identity**
|
|
56
|
+
- **Validates the data** against expectations
|
|
57
|
+
- Provides **operations and validity reports**
|
|
58
|
+
- Shapes files with **copy-on-write canonicalization**
|
|
59
|
+
- And **stages data for consistent loading** to a data lake or applications
|
|
60
60
|
|
|
61
61
|
And does it all in an automation-friendly way.
|
|
62
62
|
|
|
63
|
-
CsvPath
|
|
63
|
+
CsvPath Language validation is inspired by:
|
|
64
64
|
- XPath for XML files
|
|
65
65
|
- The ISO standard <a href='https://schematron.com/'>Schematron validation</a>
|
|
66
66
|
|
|
67
|
-
CsvPath is intended to fit tightly with other DataOps and data quality tools. Files are streamed. The interface is simple. Metadata is plentiful. New functions and listeners are easy to create.
|
|
67
|
+
The CsvPath Framework is intended to fit tightly with other DataOps and data quality tools. Files are streamed. The interface is simple. Metadata is plentiful. New functions and listeners are easy to create.
|
|
68
68
|
|
|
69
69
|
CsvPath can stream lineage events to an OpenLineage server, such as the open source Marquez server. Read about <a href="https://www.csvpath.org/getting-started/getting-started-with-csvpath-+-openlineage" target="_blank">CsvPath and OpenLineage here</a>.
|
|
70
70
|
<br/><a href='https://openlineage.io' >
|
|
@@ -75,6 +75,10 @@ CsvPath can stream lineage events to an OpenLineage server, such as the open sou
|
|
|
75
75
|
DataOps demands observability! Pipe CsvPath events through OpenTelemetry to your APM or observability platform. Read about <a href='https://www.csvpath.org/getting-started/integrations/getting-started-with-csvpath-+-opentelemetry' target="_blank">how to get started here</a>, with an example using Grafana.
|
|
76
76
|
<br/><img target='_blank' src="https://github.com/csvpath/csvpath/blob/main/docs/images/opentelemetry.png" alt="OpenTelemetry Logo"/>
|
|
77
77
|
|
|
78
|
+
CsvPath has multiple MFT options including SFTPPlus. <a href="https://www.csvpath.org/getting-started/dataops-integrations/getting-started-with-csvpath-+-sftpplus" target="_blank">See how SFTPPlus + CsvPath improves data onboarding</a>.
|
|
79
|
+
<a href="https://sftpplus.com/" target="_blank"><img target='_blank' src="https://github.com/csvpath/csvpath/blob/main/docs/images/sftpplus-logo3.png" alt="MFT with SFTPPlus"/></a>
|
|
80
|
+
|
|
81
|
+
|
|
78
82
|
Need to publish validated datasets to a CKAN data portal? <a href="https://www.csvpath.org/getting-started/getting-started-with-csvpath-+-ckan" target="_blank">Read about how CsvPath is integrated with CKAN</a>.
|
|
79
83
|
<a href="https://ckan.org/" target="_blank"><img target='_blank' src="https://github.com/csvpath/csvpath/blob/main/docs/images/ckan-logo-sm.png" alt="CKAN Data Portal"/></a>
|
|
80
84
|
|
|
@@ -118,9 +122,13 @@ CSV files are everywhere!
|
|
|
118
122
|
|
|
119
123
|
The majority of companies depend on file processing for significant revenue operations. Research organizations and archives are awash in CSVs. And everyone's favorite issue tracker, database GUI, spreadsheet, APM platform, and most any other type of tool we use spits out CSV or Excel files for sharing. Delimited and tabular files are the lowest of common dominators. Many are invalid or broken in some way. Often times a lot of manual effort goes into finding problems and fixing them.
|
|
120
124
|
|
|
121
|
-
|
|
125
|
+
This project tackles two needs:
|
|
126
|
+
- A more robust validation language for delimited and tabular data
|
|
127
|
+
- A systems integration framework for flat-file landing and staging
|
|
128
|
+
|
|
129
|
+
CsvPath Language is first and foremost a validation language. It supports both schema definitions and rules-based validation. CsvPath Language describes data so you can easily tell if a file is valid. CsvPath can also extract and shape data and create reports. Overall the goal is to automate human judgement out of the processing loop and instead move it to the process definition stage.
|
|
122
130
|
|
|
123
|
-
The CsvPath
|
|
131
|
+
The CsvPath Framework implements CsvPath Language, but goes far beyond it to provide a full <a href='https://www.atestaanalytics.com/s/The-Collect-Store-Validate-Pattern-Atesta-Analytics.pdf'>Collect, Store, Validate Pattern</a> framework for landing flat files, registering them, validating them, shaping them to a consistent and comparable form, and staging them for a data lake. In that way, CsvPath fills the gap commonly found between an organization's MFT (managed file transfer) and a typical data lake architecture.
|
|
124
132
|
|
|
125
133
|
CsvPath's goal is to make simple validations almost trivial and more complex situations more manageable. It is a library and framework, not a system, so it relies on being easy to integrate with other DataOps tools.
|
|
126
134
|
|
|
@@ -128,36 +136,27 @@ CsvPath's goal is to make simple validations almost trivial and more complex sit
|
|
|
128
136
|
<a name="install"></a>
|
|
129
137
|
# Install
|
|
130
138
|
|
|
131
|
-
<a href='https://pypi.org/project/csvpath/'>CsvPath is available on PyPi</a>. It has been tested on 3.10, 3.11 and 3.13.
|
|
139
|
+
<a href='https://pypi.org/project/csvpath/'>CsvPath is available on PyPi</a>. It has been tested on 3.10, 3.11 and 3.13.
|
|
140
|
+
|
|
141
|
+
The CsvPath Framework project uses Poetry. You can also install it with:
|
|
132
142
|
```
|
|
133
143
|
pip install csvpath
|
|
134
144
|
```
|
|
135
145
|
|
|
136
|
-
CsvPath has
|
|
137
|
-
|
|
138
|
-
- <a target='_blank' href='https://pypi.org/project/pandas/'>Pandas</a>
|
|
139
|
-
- <a target='_blank' href='https://pypi.org/project/smart-open/'>Smart-open</a>
|
|
140
|
-
|
|
141
|
-
Pandas data frames can be used as a data source, much like Excel or CSV files. Install CsvPath with the Pandas option:
|
|
146
|
+
CsvPath has an optional dependency on Pandas. Pandas data frames can be used as a data source, much like Excel or CSV files. To install CsvPath with the Pandas option do:
|
|
142
147
|
```
|
|
143
148
|
pip install csvpath[pandas]
|
|
144
149
|
```
|
|
145
150
|
|
|
146
|
-
|
|
147
|
-
```
|
|
148
|
-
pip install csvpath[smart-open]
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
Both of these optional dependencies can make it harder to use CsvPath in certain specific use cases. For e.g., using Pandas in an AWS Lambda layer may be less straightforward. If you need the capabilities, they are easy to install, but if you don't CsvPath is lighter weight without.
|
|
152
|
-
|
|
151
|
+
Pandas and its dependencies can make it harder to use CsvPath in certain specific MFT use cases. For e.g., using Pandas in an AWS Lambda layer may be less straightforward. If you need the capability, though, it is easy to install.
|
|
153
152
|
|
|
154
153
|
# Description
|
|
155
154
|
<a name="description"></a>
|
|
156
155
|
|
|
157
|
-
CsvPath paths have three parts:
|
|
156
|
+
CsvPath Language is for creating "paths" that walk line-by-line through tabular data. They have three parts:
|
|
158
157
|
- a "root" file name
|
|
159
|
-
- a scanning part
|
|
160
|
-
- a matching part
|
|
158
|
+
- a scanning part that says what lines to validate
|
|
159
|
+
- a matching part that decides if a line is valid
|
|
161
160
|
|
|
162
161
|
The root of a csvpath starts with `$`. The match and scan parts are enclosed by brackets. Newlines are ignored.
|
|
163
162
|
|
|
@@ -167,7 +166,12 @@ A very simple csvpath might look like this:
|
|
|
167
166
|
$filename[*][yes()]
|
|
168
167
|
```
|
|
169
168
|
|
|
170
|
-
This csvpath says
|
|
169
|
+
This csvpath says:
|
|
170
|
+
- Open the file: `filename`
|
|
171
|
+
- Scan all the lines: `*`
|
|
172
|
+
- And match every line scanned: `yes()`
|
|
173
|
+
|
|
174
|
+
In this case a match is considered a valid line. Treating matches as valid is a simple approach. There are <a href='https://www.csvpath.org/topics/validation' target='_blank'>many possible validation strategies</a> when its time to be more ambitious in your validation.
|
|
171
175
|
|
|
172
176
|
A slightly more functional csvpath could look like this:
|
|
173
177
|
|
|
@@ -274,14 +278,14 @@ There are a small number of configuration options. Read <a href='https://github.
|
|
|
274
278
|
|
|
275
279
|
Before we get into the details of scanning and matching, let's look at what CsvPath can print. The `print` function has several important uses, including:
|
|
276
280
|
|
|
277
|
-
- Validating CSV files
|
|
281
|
+
- Validating CSV and Excel files
|
|
278
282
|
- Debugging csvpaths
|
|
279
283
|
- Creating new CSV files based on an existing file
|
|
280
284
|
|
|
281
285
|
You can <a href='https://github.com/dk107dk/csvpath/blob/main/docs/printing.md'>read more about the mechanics of printing here</a>.
|
|
282
286
|
|
|
283
287
|
<a name="validating"></a>
|
|
284
|
-
### Validating CSV
|
|
288
|
+
### Validating CSV and Excel
|
|
285
289
|
|
|
286
290
|
CsvPath paths can be used for rules based validation. Rules based validation checks a file against content and structure rules but does not validate the file's structure against a schema. This validation approach is similar to XML's Schematron validation, where XPath rules are applied to XML.
|
|
287
291
|
|
|
@@ -312,7 +316,7 @@ CsvPaths have file scanning instructions, match components, and comments. Commen
|
|
|
312
316
|
|
|
313
317
|
As well as documentation, comments outside the csvpath can:
|
|
314
318
|
- Contribute to a collection of metadata fields associated with a csvpath
|
|
315
|
-
- Switch on/off certain validation settings
|
|
319
|
+
- Switch on/off certain validation and DataOps tool integration settings
|
|
316
320
|
- Set the identity of a csvpath within a group of csvpaths
|
|
317
321
|
|
|
318
322
|
A comment starts and ends with a `~` character. Within the comment, any word that has a colon after it is considered a metadata key. The metadata value is anything following the key up till a new metadata key word is seen or the comment ends.
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
|
|
2
2
|
# <a href='https://www.csvpath.org/'><img src='https://github.com/csvpath/csvpath/blob/main/docs/images/logo-wordmark-4.svg'/></a>
|
|
3
3
|
|
|
4
|
-
The CsvPath
|
|
4
|
+
The CsvPath Language defines a declarative syntax for inspecting and validating CSV and Excel files, and other tabular data.
|
|
5
5
|
|
|
6
|
-
The CsvPath
|
|
7
|
-
- Registers files
|
|
8
|
-
- Validates
|
|
9
|
-
-
|
|
10
|
-
- Shapes files
|
|
11
|
-
- And stages
|
|
6
|
+
The CsvPath Framework makes it easy to setup a <a href='https://www.atestaanalytics.com/s/The-Collect-Store-Validate-Pattern-Atesta-Analytics.pdf'>Collect, Store, Validate Pattern</a> flat-file landing zone that:
|
|
7
|
+
- Registers files for **clear and durable identity**
|
|
8
|
+
- **Validates the data** against expectations
|
|
9
|
+
- Provides **operations and validity reports**
|
|
10
|
+
- Shapes files with **copy-on-write canonicalization**
|
|
11
|
+
- And **stages data for consistent loading** to a data lake or applications
|
|
12
12
|
|
|
13
13
|
And does it all in an automation-friendly way.
|
|
14
14
|
|
|
15
|
-
CsvPath
|
|
15
|
+
CsvPath Language validation is inspired by:
|
|
16
16
|
- XPath for XML files
|
|
17
17
|
- The ISO standard <a href='https://schematron.com/'>Schematron validation</a>
|
|
18
18
|
|
|
19
|
-
CsvPath is intended to fit tightly with other DataOps and data quality tools. Files are streamed. The interface is simple. Metadata is plentiful. New functions and listeners are easy to create.
|
|
19
|
+
The CsvPath Framework is intended to fit tightly with other DataOps and data quality tools. Files are streamed. The interface is simple. Metadata is plentiful. New functions and listeners are easy to create.
|
|
20
20
|
|
|
21
21
|
CsvPath can stream lineage events to an OpenLineage server, such as the open source Marquez server. Read about <a href="https://www.csvpath.org/getting-started/getting-started-with-csvpath-+-openlineage" target="_blank">CsvPath and OpenLineage here</a>.
|
|
22
22
|
<br/><a href='https://openlineage.io' >
|
|
@@ -27,6 +27,10 @@ CsvPath can stream lineage events to an OpenLineage server, such as the open sou
|
|
|
27
27
|
DataOps demands observability! Pipe CsvPath events through OpenTelemetry to your APM or observability platform. Read about <a href='https://www.csvpath.org/getting-started/integrations/getting-started-with-csvpath-+-opentelemetry' target="_blank">how to get started here</a>, with an example using Grafana.
|
|
28
28
|
<br/><img target='_blank' src="https://github.com/csvpath/csvpath/blob/main/docs/images/opentelemetry.png" alt="OpenTelemetry Logo"/>
|
|
29
29
|
|
|
30
|
+
CsvPath has multiple MFT options including SFTPPlus. <a href="https://www.csvpath.org/getting-started/dataops-integrations/getting-started-with-csvpath-+-sftpplus" target="_blank">See how SFTPPlus + CsvPath improves data onboarding</a>.
|
|
31
|
+
<a href="https://sftpplus.com/" target="_blank"><img target='_blank' src="https://github.com/csvpath/csvpath/blob/main/docs/images/sftpplus-logo3.png" alt="MFT with SFTPPlus"/></a>
|
|
32
|
+
|
|
33
|
+
|
|
30
34
|
Need to publish validated datasets to a CKAN data portal? <a href="https://www.csvpath.org/getting-started/getting-started-with-csvpath-+-ckan" target="_blank">Read about how CsvPath is integrated with CKAN</a>.
|
|
31
35
|
<a href="https://ckan.org/" target="_blank"><img target='_blank' src="https://github.com/csvpath/csvpath/blob/main/docs/images/ckan-logo-sm.png" alt="CKAN Data Portal"/></a>
|
|
32
36
|
|
|
@@ -70,9 +74,13 @@ CSV files are everywhere!
|
|
|
70
74
|
|
|
71
75
|
The majority of companies depend on file processing for significant revenue operations. Research organizations and archives are awash in CSVs. And everyone's favorite issue tracker, database GUI, spreadsheet, APM platform, and most any other type of tool we use spits out CSV or Excel files for sharing. Delimited and tabular files are the lowest of common dominators. Many are invalid or broken in some way. Often times a lot of manual effort goes into finding problems and fixing them.
|
|
72
76
|
|
|
73
|
-
|
|
77
|
+
This project tackles two needs:
|
|
78
|
+
- A more robust validation language for delimited and tabular data
|
|
79
|
+
- A systems integration framework for flat-file landing and staging
|
|
80
|
+
|
|
81
|
+
CsvPath Language is first and foremost a validation language. It supports both schema definitions and rules-based validation. CsvPath Language describes data so you can easily tell if a file is valid. CsvPath can also extract and shape data and create reports. Overall the goal is to automate human judgement out of the processing loop and instead move it to the process definition stage.
|
|
74
82
|
|
|
75
|
-
The CsvPath
|
|
83
|
+
The CsvPath Framework implements CsvPath Language, but goes far beyond it to provide a full <a href='https://www.atestaanalytics.com/s/The-Collect-Store-Validate-Pattern-Atesta-Analytics.pdf'>Collect, Store, Validate Pattern</a> framework for landing flat files, registering them, validating them, shaping them to a consistent and comparable form, and staging them for a data lake. In that way, CsvPath fills the gap commonly found between an organization's MFT (managed file transfer) and a typical data lake architecture.
|
|
76
84
|
|
|
77
85
|
CsvPath's goal is to make simple validations almost trivial and more complex situations more manageable. It is a library and framework, not a system, so it relies on being easy to integrate with other DataOps tools.
|
|
78
86
|
|
|
@@ -80,36 +88,27 @@ CsvPath's goal is to make simple validations almost trivial and more complex sit
|
|
|
80
88
|
<a name="install"></a>
|
|
81
89
|
# Install
|
|
82
90
|
|
|
83
|
-
<a href='https://pypi.org/project/csvpath/'>CsvPath is available on PyPi</a>. It has been tested on 3.10, 3.11 and 3.13.
|
|
91
|
+
<a href='https://pypi.org/project/csvpath/'>CsvPath is available on PyPi</a>. It has been tested on 3.10, 3.11 and 3.13.
|
|
92
|
+
|
|
93
|
+
The CsvPath Framework project uses Poetry. You can also install it with:
|
|
84
94
|
```
|
|
85
95
|
pip install csvpath
|
|
86
96
|
```
|
|
87
97
|
|
|
88
|
-
CsvPath has
|
|
89
|
-
|
|
90
|
-
- <a target='_blank' href='https://pypi.org/project/pandas/'>Pandas</a>
|
|
91
|
-
- <a target='_blank' href='https://pypi.org/project/smart-open/'>Smart-open</a>
|
|
92
|
-
|
|
93
|
-
Pandas data frames can be used as a data source, much like Excel or CSV files. Install CsvPath with the Pandas option:
|
|
98
|
+
CsvPath has an optional dependency on Pandas. Pandas data frames can be used as a data source, much like Excel or CSV files. To install CsvPath with the Pandas option do:
|
|
94
99
|
```
|
|
95
100
|
pip install csvpath[pandas]
|
|
96
101
|
```
|
|
97
102
|
|
|
98
|
-
|
|
99
|
-
```
|
|
100
|
-
pip install csvpath[smart-open]
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Both of these optional dependencies can make it harder to use CsvPath in certain specific use cases. For e.g., using Pandas in an AWS Lambda layer may be less straightforward. If you need the capabilities, they are easy to install, but if you don't CsvPath is lighter weight without.
|
|
104
|
-
|
|
103
|
+
Pandas and its dependencies can make it harder to use CsvPath in certain specific MFT use cases. For e.g., using Pandas in an AWS Lambda layer may be less straightforward. If you need the capability, though, it is easy to install.
|
|
105
104
|
|
|
106
105
|
# Description
|
|
107
106
|
<a name="description"></a>
|
|
108
107
|
|
|
109
|
-
CsvPath paths have three parts:
|
|
108
|
+
CsvPath Language is for creating "paths" that walk line-by-line through tabular data. They have three parts:
|
|
110
109
|
- a "root" file name
|
|
111
|
-
- a scanning part
|
|
112
|
-
- a matching part
|
|
110
|
+
- a scanning part that says what lines to validate
|
|
111
|
+
- a matching part that decides if a line is valid
|
|
113
112
|
|
|
114
113
|
The root of a csvpath starts with `$`. The match and scan parts are enclosed by brackets. Newlines are ignored.
|
|
115
114
|
|
|
@@ -119,7 +118,12 @@ A very simple csvpath might look like this:
|
|
|
119
118
|
$filename[*][yes()]
|
|
120
119
|
```
|
|
121
120
|
|
|
122
|
-
This csvpath says
|
|
121
|
+
This csvpath says:
|
|
122
|
+
- Open the file: `filename`
|
|
123
|
+
- Scan all the lines: `*`
|
|
124
|
+
- And match every line scanned: `yes()`
|
|
125
|
+
|
|
126
|
+
In this case a match is considered a valid line. Treating matches as valid is a simple approach. There are <a href='https://www.csvpath.org/topics/validation' target='_blank'>many possible validation strategies</a> when its time to be more ambitious in your validation.
|
|
123
127
|
|
|
124
128
|
A slightly more functional csvpath could look like this:
|
|
125
129
|
|
|
@@ -226,14 +230,14 @@ There are a small number of configuration options. Read <a href='https://github.
|
|
|
226
230
|
|
|
227
231
|
Before we get into the details of scanning and matching, let's look at what CsvPath can print. The `print` function has several important uses, including:
|
|
228
232
|
|
|
229
|
-
- Validating CSV files
|
|
233
|
+
- Validating CSV and Excel files
|
|
230
234
|
- Debugging csvpaths
|
|
231
235
|
- Creating new CSV files based on an existing file
|
|
232
236
|
|
|
233
237
|
You can <a href='https://github.com/dk107dk/csvpath/blob/main/docs/printing.md'>read more about the mechanics of printing here</a>.
|
|
234
238
|
|
|
235
239
|
<a name="validating"></a>
|
|
236
|
-
### Validating CSV
|
|
240
|
+
### Validating CSV and Excel
|
|
237
241
|
|
|
238
242
|
CsvPath paths can be used for rules based validation. Rules based validation checks a file against content and structure rules but does not validate the file's structure against a schema. This validation approach is similar to XML's Schematron validation, where XPath rules are applied to XML.
|
|
239
243
|
|
|
@@ -264,7 +268,7 @@ CsvPaths have file scanning instructions, match components, and comments. Commen
|
|
|
264
268
|
|
|
265
269
|
As well as documentation, comments outside the csvpath can:
|
|
266
270
|
- Contribute to a collection of metadata fields associated with a csvpath
|
|
267
|
-
- Switch on/off certain validation settings
|
|
271
|
+
- Switch on/off certain validation and DataOps tool integration settings
|
|
268
272
|
- Set the identity of a csvpath within a group of csvpaths
|
|
269
273
|
|
|
270
274
|
A comment starts and ends with a `~` character. Within the comment, any word that has a colon after it is considered a metadata key. The metadata value is anything following the key up till a new metadata key word is seen or the comment ends.
|
|
@@ -7,6 +7,8 @@ extensions = txt, csv, tsv, dat, tab, psv, ssv
|
|
|
7
7
|
[errors]
|
|
8
8
|
csvpath = raise, collect, stop, fail, print
|
|
9
9
|
csvpaths = raise, collect
|
|
10
|
+
use_format = full
|
|
11
|
+
pattern = {time}:{file}:{line}:{paths}:{instance}:{chain}: {message}
|
|
10
12
|
|
|
11
13
|
[logging]
|
|
12
14
|
csvpath = info
|
|
@@ -26,8 +28,19 @@ imports = config/functions.imports
|
|
|
26
28
|
|
|
27
29
|
[listeners]
|
|
28
30
|
groups =
|
|
29
|
-
#slack, marquez, ckan, sftp, sftpplus, otlp
|
|
30
|
-
|
|
31
|
+
#slack, marquez, ckan, sftp, sftpplus, otlp, default
|
|
32
|
+
|
|
33
|
+
# these simple default listeners track all files staged and all paths loaded in
|
|
34
|
+
# central manifests. unlike other manifest writers, if they have multiple
|
|
35
|
+
# concurrent users they have potential a race condition. users that do not
|
|
36
|
+
# share inputs directories do not need to worry about this. you should vet
|
|
37
|
+
# using them against your use case; potential utility vs. the modest but non-0
|
|
38
|
+
# risk of lost updates. they can be disabled with little loss of function.
|
|
39
|
+
# alternatively a database-backed version may be available.
|
|
40
|
+
default.file = from csvpath.managers.files.files_listener import FilesListener
|
|
41
|
+
default.paths = from csvpath.managers.paths.paths_listener import PathsListener
|
|
42
|
+
|
|
43
|
+
# add otlp to support any OpenTelemetry backend
|
|
31
44
|
otlp.result = from csvpath.managers.integrations.otlp.otlp_result_listener import OpenTelemetryResultListener
|
|
32
45
|
otlp.results = from csvpath.managers.integrations.otlp.otlp_results_listener import OpenTelemetryResultsListener
|
|
33
46
|
otlp.errors = from csvpath.managers.integrations.otlp.otlp_error_listener import OpenTelemetryErrorListener
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from prompt_toolkit import Application
|
|
2
|
+
from prompt_toolkit.buffer import Buffer
|
|
3
|
+
from prompt_toolkit.layout.containers import (
|
|
4
|
+
HSplit,
|
|
5
|
+
VSplit,
|
|
6
|
+
Window,
|
|
7
|
+
ConditionalContainer,
|
|
8
|
+
)
|
|
9
|
+
from prompt_toolkit.layout.menus import CompletionsMenu
|
|
10
|
+
from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
|
|
11
|
+
from prompt_toolkit.layout.layout import Layout
|
|
12
|
+
from prompt_toolkit.key_binding import KeyBindings
|
|
13
|
+
from prompt_toolkit.completion import WordCompleter
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Asker:
|
|
17
|
+
def __init__(self, cli, *, name_type) -> None:
|
|
18
|
+
self._cli = cli
|
|
19
|
+
names = None
|
|
20
|
+
if name_type == "files":
|
|
21
|
+
names = self._cli.csvpaths.file_manager.named_file_names
|
|
22
|
+
names.sort()
|
|
23
|
+
elif name_type == "paths":
|
|
24
|
+
names = self._cli.csvpaths.file_manager.named_file_names
|
|
25
|
+
names.sort()
|
|
26
|
+
else:
|
|
27
|
+
raise ValueError("Name type must be files or paths")
|
|
28
|
+
self.completer = WordCompleter(names, ignore_case=True)
|
|
29
|
+
self.result = None
|
|
30
|
+
|
|
31
|
+
def create_prompt_application(self, prompt_text="Named-file name? "):
|
|
32
|
+
# Create a buffer to store input
|
|
33
|
+
buffer = Buffer(completer=self.completer, complete_while_typing=True)
|
|
34
|
+
|
|
35
|
+
# Create key bindings
|
|
36
|
+
kb = KeyBindings()
|
|
37
|
+
|
|
38
|
+
@kb.add("enter")
|
|
39
|
+
def _(event):
|
|
40
|
+
self.result = buffer.text
|
|
41
|
+
event.app.exit()
|
|
42
|
+
|
|
43
|
+
@kb.add("c-c")
|
|
44
|
+
@kb.add("c-q")
|
|
45
|
+
def _(event):
|
|
46
|
+
event.app.exit()
|
|
47
|
+
|
|
48
|
+
# Create the layout
|
|
49
|
+
layout = Layout(
|
|
50
|
+
HSplit(
|
|
51
|
+
[
|
|
52
|
+
# The actual prompt layout
|
|
53
|
+
VSplit(
|
|
54
|
+
[
|
|
55
|
+
# Prompt text
|
|
56
|
+
Window(
|
|
57
|
+
content=FormattedTextControl(prompt_text),
|
|
58
|
+
width=len(prompt_text),
|
|
59
|
+
dont_extend_width=True,
|
|
60
|
+
),
|
|
61
|
+
# Input field with completions menu wrapped in a Window
|
|
62
|
+
Window(content=BufferControl(buffer=buffer)),
|
|
63
|
+
]
|
|
64
|
+
)
|
|
65
|
+
]
|
|
66
|
+
# , align_right=False
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Create and return the application
|
|
71
|
+
return Application(
|
|
72
|
+
layout=layout,
|
|
73
|
+
key_bindings=kb,
|
|
74
|
+
mouse_support=True,
|
|
75
|
+
full_screen=False,
|
|
76
|
+
erase_when_done=True,
|
|
77
|
+
# complete_while_typing=True
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def ask(self) -> str:
|
|
81
|
+
try:
|
|
82
|
+
app = self.create_prompt_application()
|
|
83
|
+
app.run()
|
|
84
|
+
return self.result
|
|
85
|
+
except Exception as e:
|
|
86
|
+
print(f"Error: {e}")
|
|
87
|
+
import traceback
|
|
88
|
+
|
|
89
|
+
print(traceback.format_exc())
|
|
90
|
+
return None
|
|
@@ -4,13 +4,29 @@ import time
|
|
|
4
4
|
import traceback
|
|
5
5
|
from csvpath import CsvPaths
|
|
6
6
|
from .drill_down import DrillDown
|
|
7
|
-
from .
|
|
8
|
-
from .
|
|
7
|
+
from .selecter import Selecter
|
|
8
|
+
from .debug_config import DebugConfig
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class Cli:
|
|
12
12
|
def __init__(self):
|
|
13
13
|
self.csvpaths = CsvPaths()
|
|
14
|
+
self.clear()
|
|
15
|
+
splash = """
|
|
16
|
+
*** * ****** ** **
|
|
17
|
+
*** ** * ** ** **** **
|
|
18
|
+
** ** ** * ** *** ***** ** *****
|
|
19
|
+
** * **** **** ***** *** ** ** ** **
|
|
20
|
+
** **** ****** ** ** ** *** ** ** **
|
|
21
|
+
*** **** * ** *** ** **** **
|
|
22
|
+
***************************
|
|
23
|
+
CsvPath Command Line Interface
|
|
24
|
+
Try tab completion and menu-by-key.
|
|
25
|
+
For help see https://www.csvpath.org
|
|
26
|
+
"""
|
|
27
|
+
print(splash)
|
|
28
|
+
self._return_to_cont()
|
|
29
|
+
self.clear()
|
|
14
30
|
|
|
15
31
|
def clear(self):
|
|
16
32
|
print(chr(27) + "[2J")
|
|
@@ -28,6 +44,7 @@ class Cli:
|
|
|
28
44
|
STOP_HERE2 = "👍 pick this dir"
|
|
29
45
|
CANCEL = f"{SIDEBAR_COLOR}{ITALIC}... cancel{REVERT}"
|
|
30
46
|
CANCEL2 = "← cancel"
|
|
47
|
+
QUIT = "← quit"
|
|
31
48
|
|
|
32
49
|
def _return_to_cont(self):
|
|
33
50
|
print(
|
|
@@ -52,14 +69,18 @@ class Cli:
|
|
|
52
69
|
def end(self) -> None:
|
|
53
70
|
print(chr(27) + "[2J")
|
|
54
71
|
|
|
55
|
-
def ask(self, choices: list[str]) -> str:
|
|
72
|
+
def ask(self, choices: list[str], q=None) -> str:
|
|
56
73
|
self.clear()
|
|
74
|
+
if len(choices) == 0:
|
|
75
|
+
return
|
|
76
|
+
if q is not None:
|
|
77
|
+
print(q)
|
|
57
78
|
if choices[len(choices) - 1] == Cli.CANCEL:
|
|
58
79
|
choices[len(choices) - 1] = Cli.CANCEL2
|
|
59
80
|
if choices[len(choices) - 2] == Cli.STOP_HERE:
|
|
60
81
|
choices[len(choices) - 2] = Cli.STOP_HERE2
|
|
61
82
|
cs = [(s, s) for s in choices]
|
|
62
|
-
t =
|
|
83
|
+
t = Selecter().ask(title="", values=cs, cancel_value="CANCEL")
|
|
63
84
|
self.clear()
|
|
64
85
|
return t
|
|
65
86
|
|
|
@@ -70,22 +91,22 @@ class Cli:
|
|
|
70
91
|
choices = [
|
|
71
92
|
"named-files",
|
|
72
93
|
"named-paths",
|
|
73
|
-
"
|
|
94
|
+
"archive",
|
|
74
95
|
"run",
|
|
75
96
|
"config",
|
|
76
|
-
|
|
97
|
+
self.QUIT,
|
|
77
98
|
]
|
|
78
99
|
t = self.ask(choices)
|
|
79
100
|
except KeyboardInterrupt:
|
|
80
101
|
self.end()
|
|
81
102
|
return
|
|
82
103
|
t = self._do(t)
|
|
83
|
-
if t ==
|
|
104
|
+
if t == Cli.QUIT:
|
|
84
105
|
self.end()
|
|
85
106
|
return
|
|
86
107
|
|
|
87
108
|
def _do(self, t: str) -> str | None:
|
|
88
|
-
if t ==
|
|
109
|
+
if t == Cli.QUIT:
|
|
89
110
|
return t
|
|
90
111
|
try:
|
|
91
112
|
if t == "run":
|
|
@@ -94,21 +115,21 @@ class Cli:
|
|
|
94
115
|
self._files()
|
|
95
116
|
if t == "named-paths":
|
|
96
117
|
self._paths()
|
|
97
|
-
if t == "
|
|
118
|
+
if t == "archive":
|
|
98
119
|
self._results()
|
|
99
120
|
if t == "config":
|
|
100
121
|
self._config()
|
|
101
122
|
except KeyboardInterrupt:
|
|
102
|
-
return
|
|
123
|
+
return Cli.QUIT
|
|
103
124
|
except Exception:
|
|
104
125
|
print(traceback.format_exc())
|
|
105
126
|
self._return_to_cont()
|
|
106
127
|
|
|
107
128
|
def _config(self) -> None:
|
|
108
|
-
|
|
129
|
+
DebugConfig(self).show()
|
|
109
130
|
|
|
110
131
|
def _files(self) -> None:
|
|
111
|
-
choices = ["add named-file", "list named-files",
|
|
132
|
+
choices = ["add named-file", "list named-files", self.CANCEL2]
|
|
112
133
|
t = self.ask(choices)
|
|
113
134
|
if t == "add named-file":
|
|
114
135
|
DrillDown(self).name_file()
|
|
@@ -116,7 +137,7 @@ class Cli:
|
|
|
116
137
|
self.list_named_files()
|
|
117
138
|
|
|
118
139
|
def _paths(self) -> None:
|
|
119
|
-
choices = ["add named-paths", "list named-paths",
|
|
140
|
+
choices = ["add named-paths", "list named-paths", self.CANCEL2]
|
|
120
141
|
t = self.ask(choices)
|
|
121
142
|
if t == "add named-paths":
|
|
122
143
|
DrillDown(self).name_paths()
|
|
@@ -124,7 +145,7 @@ class Cli:
|
|
|
124
145
|
self.list_named_paths()
|
|
125
146
|
|
|
126
147
|
def _results(self) -> None:
|
|
127
|
-
choices = ["open named-result", "list named-results",
|
|
148
|
+
choices = ["open named-result", "list named-results", self.CANCEL2]
|
|
128
149
|
t = self.ask(choices)
|
|
129
150
|
if t == "open named-result":
|
|
130
151
|
self.open_named_result()
|
|
@@ -136,6 +157,8 @@ class Cli:
|
|
|
136
157
|
names = self.csvpaths.results_manager.list_named_results()
|
|
137
158
|
print(f"{len(names)} named-results names:")
|
|
138
159
|
for n in names:
|
|
160
|
+
if n.find(".") > -1:
|
|
161
|
+
continue
|
|
139
162
|
self._response(f" {n}")
|
|
140
163
|
self._return_to_cont()
|
|
141
164
|
|
|
@@ -143,6 +166,7 @@ class Cli:
|
|
|
143
166
|
self.clear()
|
|
144
167
|
try:
|
|
145
168
|
names = self.csvpaths.results_manager.list_named_results()
|
|
169
|
+
names = [n for n in names if n.find(".") == -1]
|
|
146
170
|
print(f"{len(names)} named-results names:")
|
|
147
171
|
names.append(self.CANCEL)
|
|
148
172
|
t = self.ask(names)
|
|
@@ -176,18 +200,25 @@ class Cli:
|
|
|
176
200
|
|
|
177
201
|
def run(self):
|
|
178
202
|
self.clear()
|
|
179
|
-
print("What named-file? ")
|
|
180
203
|
files = self.csvpaths.file_manager.named_file_names
|
|
181
|
-
|
|
204
|
+
if len(files) == 0:
|
|
205
|
+
input("You must add a named-file. Press any key to continue.")
|
|
206
|
+
return
|
|
207
|
+
files.sort()
|
|
208
|
+
file = self.ask(files, q="What named-file? ")
|
|
182
209
|
self.clear()
|
|
183
|
-
print("What named-paths? ")
|
|
184
210
|
allpaths = self.csvpaths.paths_manager.named_paths_names
|
|
185
|
-
|
|
211
|
+
if len(allpaths) == 0:
|
|
212
|
+
input("You must add a named-paths file. Press any key to continue.")
|
|
213
|
+
return
|
|
214
|
+
allpaths.sort()
|
|
215
|
+
paths = self.ask(allpaths, q="What named-paths? ")
|
|
186
216
|
self.clear()
|
|
187
|
-
choices = ["collect", "fast-forward"]
|
|
188
|
-
|
|
189
|
-
method = self.ask(choices)
|
|
217
|
+
choices = ["collect", "fast-forward", Cli.CANCEL2]
|
|
218
|
+
method = self.ask(choices, q="What method? ")
|
|
190
219
|
self.clear()
|
|
220
|
+
if method == Cli.CANCEL2:
|
|
221
|
+
return
|
|
191
222
|
self.action(f"Running {paths} against {file} using {method}\n")
|
|
192
223
|
self.pause()
|
|
193
224
|
try:
|
|
@@ -196,7 +227,22 @@ class Cli:
|
|
|
196
227
|
else:
|
|
197
228
|
self.csvpaths.fast_forward_paths(filename=file, pathsname=paths)
|
|
198
229
|
except Exception:
|
|
199
|
-
|
|
230
|
+
cfg = None
|
|
231
|
+
while cfg in [None, "c", "e"]:
|
|
232
|
+
print("\nThere was an error.")
|
|
233
|
+
print("Click 'e' and return to print the stack trace. ")
|
|
234
|
+
print("Click 'c' and return to change config options. ")
|
|
235
|
+
print("Click return to continue. ")
|
|
236
|
+
cfg = input("")
|
|
237
|
+
if cfg == "c":
|
|
238
|
+
DebugConfig(self).show()
|
|
239
|
+
elif cfg == "e":
|
|
240
|
+
self.clear()
|
|
241
|
+
print(traceback.format_exc())
|
|
242
|
+
input("\n\nClick return to continue")
|
|
243
|
+
else:
|
|
244
|
+
return
|
|
245
|
+
self.clear()
|
|
200
246
|
self._return_to_cont()
|
|
201
247
|
|
|
202
248
|
|