csvpath 0.0.535__tar.gz → 0.0.537__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.
Files changed (312) hide show
  1. {csvpath-0.0.535 → csvpath-0.0.537}/PKG-INFO +1 -1
  2. {csvpath-0.0.535 → csvpath-0.0.537/assets}/config/config.ini +17 -0
  3. {csvpath-0.0.535 → csvpath-0.0.537}/assets/config/jenkins-windows-local.ini +9 -39
  4. {csvpath-0.0.535/assets → csvpath-0.0.537}/config/config.ini +17 -0
  5. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/csvpaths.py +32 -2
  6. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/errors/error.py +9 -0
  7. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/files/file_registrar.py +3 -1
  8. csvpath-0.0.537/csvpath/managers/integrations/scripts/scripts_results_listener.py +111 -0
  9. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sftp/sftp_sender.py +3 -1
  10. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/slack/sender.py +2 -1
  11. csvpath-0.0.537/csvpath/managers/integrations/webhook/webhook_listener.py +135 -0
  12. csvpath-0.0.537/csvpath/managers/integrations/webhook/webhook_results_listener.py +149 -0
  13. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/paths/paths_manager.py +155 -2
  14. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/results/result.py +7 -0
  15. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/results/result_registrar.py +6 -9
  16. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/results/results_manager.py +136 -24
  17. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/results/results_metadata.py +4 -1
  18. csvpath-0.0.537/csvpath/managers/test_listener.py +18 -0
  19. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/util/print_parser.py +3 -2
  20. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/config.py +12 -0
  21. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/references/files_reference_finder.py +29 -13
  22. csvpath-0.0.537/csvpath/util/references/ref_utils.py +141 -0
  23. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/references/results_reference_finder.py +72 -29
  24. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/sftp/sftp_config.py +25 -0
  25. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/var_utility.py +49 -20
  26. {csvpath-0.0.535 → csvpath-0.0.537}/pyproject.toml +1 -1
  27. csvpath-0.0.535/csvpath/util/references/ref_utils.py +0 -77
  28. {csvpath-0.0.535 → csvpath-0.0.537}/LICENSE +0 -0
  29. {csvpath-0.0.535 → csvpath-0.0.537}/README.md +0 -0
  30. {csvpath-0.0.535 → csvpath-0.0.537}/assets/config/function.imports +0 -0
  31. {csvpath-0.0.535 → csvpath-0.0.537}/assets/config/jenkins-local-azure.ini +0 -0
  32. {csvpath-0.0.535 → csvpath-0.0.537}/assets/config/jenkins-local-filesystem-mysql.ini +0 -0
  33. {csvpath-0.0.535 → csvpath-0.0.537}/assets/config/jenkins-local-filesystem.ini +0 -0
  34. {csvpath-0.0.535 → csvpath-0.0.537}/assets/config/jenkins-local-gcs.ini +0 -0
  35. {csvpath-0.0.535 → csvpath-0.0.537}/assets/config/jenkins-local-sftp.ini +0 -0
  36. {csvpath-0.0.535 → csvpath-0.0.537}/assets/config/jenkins-s3.ini +0 -0
  37. {csvpath-0.0.535 → csvpath-0.0.537}/assets/config/jenkins-windows-azure.ini +0 -0
  38. {csvpath-0.0.535 → csvpath-0.0.537}/assets/config/jenkins-windows-sftp.ini +0 -0
  39. {csvpath-0.0.535 → csvpath-0.0.537}/assets/config/local-localhost-sftp.ini +0 -0
  40. {csvpath-0.0.535 → csvpath-0.0.537}/assets/integrations/sftpplus/handle_auto_arrival.bat +0 -0
  41. {csvpath-0.0.535 → csvpath-0.0.537}/assets/integrations/sftpplus/handle_auto_arrival.py +0 -0
  42. {csvpath-0.0.535 → csvpath-0.0.537}/assets/integrations/sftpplus/handle_auto_arrival.sh +0 -0
  43. {csvpath-0.0.535 → csvpath-0.0.537}/assets/integrations/sftpplus/handle_mailbox_arrival.bat +0 -0
  44. {csvpath-0.0.535 → csvpath-0.0.537}/assets/integrations/sftpplus/handle_mailbox_arrival.py +0 -0
  45. {csvpath-0.0.535 → csvpath-0.0.537}/assets/integrations/sftpplus/handle_mailbox_arrival.sh +0 -0
  46. {csvpath-0.0.535 → csvpath-0.0.537}/assets/integrations/sqlite/csvpath +0 -0
  47. {csvpath-0.0.535 → csvpath-0.0.537}/assets/integrations/sqlite/schema.sql +0 -0
  48. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/__init__.py +0 -0
  49. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/cli/__init__.py +0 -0
  50. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/cli/asker.py +0 -0
  51. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/cli/cli.py +0 -0
  52. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/cli/const.py +0 -0
  53. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/cli/debug_config.py +0 -0
  54. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/cli/drill_down.py +0 -0
  55. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/cli/function_describer.py +0 -0
  56. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/cli/function_lister.py +0 -0
  57. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/cli/selecter.py +0 -0
  58. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/csvpath.py +0 -0
  59. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/__init__.py +0 -0
  60. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/errors/error_collector.py +0 -0
  61. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/errors/error_comms.py +0 -0
  62. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/errors/error_manager.py +0 -0
  63. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/files/file_manager.py +0 -0
  64. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/files/file_metadata.py +0 -0
  65. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/files/files_listener.py +0 -0
  66. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/files/lines_and_headers_cacher.py +0 -0
  67. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ckan/ckan.py +0 -0
  68. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ckan/ckan_listener.py +0 -0
  69. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ckan/datafile.py +0 -0
  70. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ckan/dataset.py +0 -0
  71. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ol/event.py +0 -0
  72. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ol/event_result.py +0 -0
  73. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ol/file_listener_ol.py +0 -0
  74. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ol/job.py +0 -0
  75. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ol/ol_listener.py +0 -0
  76. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ol/paths_listener_ol.py +0 -0
  77. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ol/result_listener_ol.py +0 -0
  78. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ol/results_listener_ol.py +0 -0
  79. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ol/run.py +0 -0
  80. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ol/run_listener_ol.py +0 -0
  81. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ol/run_state.py +0 -0
  82. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/ol/sender.py +0 -0
  83. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/otlp/error_metrics.py +0 -0
  84. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/otlp/metrics.py +0 -0
  85. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/otlp/otlp_error_listener.py +0 -0
  86. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/otlp/otlp_listener.py +0 -0
  87. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/otlp/otlp_result_listener.py +0 -0
  88. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/otlp/otlp_results_listener.py +0 -0
  89. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sftpplus/arrival_handler.py +0 -0
  90. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sftpplus/rpc.py +0 -0
  91. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sftpplus/sftpplus_listener.py +0 -0
  92. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sftpplus/transfer_creator.py +0 -0
  93. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sftpplus/transfers.py +0 -0
  94. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/slack/event.py +0 -0
  95. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sql/engine.py +0 -0
  96. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sql/sql_file_listener.py +0 -0
  97. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sql/sql_listener.py +0 -0
  98. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sql/sql_paths_listener.py +0 -0
  99. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sql/sql_result_listener.py +0 -0
  100. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sql/sql_results_listener.py +0 -0
  101. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sql/tables.py +0 -0
  102. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sql/updates.py +0 -0
  103. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sqlite/schema.sql +0 -0
  104. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sqlite/sqlite_result_listener.py +0 -0
  105. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/integrations/sqlite/sqlite_results_listener.py +0 -0
  106. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/listener.py +0 -0
  107. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/metadata.py +0 -0
  108. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/paths/paths_listener.py +0 -0
  109. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/paths/paths_metadata.py +0 -0
  110. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/paths/paths_registrar.py +0 -0
  111. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/registrar.py +0 -0
  112. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/results/readers/file_errors_reader.py +0 -0
  113. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/results/readers/file_lines_reader.py +0 -0
  114. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/results/readers/file_printouts_reader.py +0 -0
  115. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/results/readers/file_unmatched_reader.py +0 -0
  116. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/results/readers/readers.py +0 -0
  117. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/results/result_file_reader.py +0 -0
  118. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/results/result_metadata.py +0 -0
  119. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/results/result_serializer.py +0 -0
  120. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/results/results_registrar.py +0 -0
  121. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/run/run_listener_stdout.py +0 -0
  122. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/run/run_metadata.py +0 -0
  123. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/managers/run/run_registrar.py +0 -0
  124. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/__init__.py +0 -0
  125. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/__init__.py +0 -0
  126. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/args.py +0 -0
  127. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/args_helper.py +0 -0
  128. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/boolean/all.py +0 -0
  129. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/boolean/andf.py +0 -0
  130. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/boolean/any.py +0 -0
  131. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/boolean/between.py +0 -0
  132. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/boolean/empty.py +0 -0
  133. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/boolean/exists.py +0 -0
  134. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/boolean/inf.py +0 -0
  135. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/boolean/no.py +0 -0
  136. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/boolean/notf.py +0 -0
  137. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/boolean/orf.py +0 -0
  138. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/boolean/yes.py +0 -0
  139. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/counting/count.py +0 -0
  140. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/counting/count_bytes.py +0 -0
  141. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/counting/count_headers.py +0 -0
  142. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/counting/count_lines.py +0 -0
  143. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/counting/count_scans.py +0 -0
  144. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/counting/counter.py +0 -0
  145. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/counting/every.py +0 -0
  146. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/counting/has_matches.py +0 -0
  147. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/counting/increment.py +0 -0
  148. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/counting/tally.py +0 -0
  149. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/counting/total_lines.py +0 -0
  150. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/dates/now.py +0 -0
  151. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/function.py +0 -0
  152. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/function_factory.py +0 -0
  153. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/function_finder.py +0 -0
  154. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/function_focus.py +0 -0
  155. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/headers/append.py +0 -0
  156. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/headers/collect.py +0 -0
  157. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/headers/empty_stack.py +0 -0
  158. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/headers/end.py +0 -0
  159. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/headers/header_name.py +0 -0
  160. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/headers/header_names_mismatch.py +0 -0
  161. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/headers/headers.py +0 -0
  162. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/headers/insert.py +0 -0
  163. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/headers/mismatch.py +0 -0
  164. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/headers/replace.py +0 -0
  165. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/headers/reset_headers.py +0 -0
  166. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/lines/advance.py +0 -0
  167. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/lines/after_blank.py +0 -0
  168. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/lines/dups.py +0 -0
  169. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/lines/first.py +0 -0
  170. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/lines/first_line.py +0 -0
  171. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/lines/last.py +0 -0
  172. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/lines/stop.py +0 -0
  173. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/math/above.py +0 -0
  174. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/math/add.py +0 -0
  175. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/math/divide.py +0 -0
  176. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/math/equals.py +0 -0
  177. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/math/intf.py +0 -0
  178. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/math/mod.py +0 -0
  179. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/math/multiply.py +0 -0
  180. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/math/odd.py +0 -0
  181. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/math/round.py +0 -0
  182. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/math/subtotal.py +0 -0
  183. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/math/subtract.py +0 -0
  184. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/math/sum.py +0 -0
  185. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/misc/fingerprint.py +0 -0
  186. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/misc/importf.py +0 -0
  187. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/misc/random.py +0 -0
  188. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/print/jinjaf.py +0 -0
  189. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/print/print_line.py +0 -0
  190. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/print/print_queue.py +0 -0
  191. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/print/printf.py +0 -0
  192. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/print/table.py +0 -0
  193. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/stats/minf.py +0 -0
  194. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/stats/percent.py +0 -0
  195. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/stats/percent_unique.py +0 -0
  196. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/stats/stdev.py +0 -0
  197. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/strings/alter.py +0 -0
  198. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/strings/caps.py +0 -0
  199. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/strings/concat.py +0 -0
  200. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/strings/contains.py +0 -0
  201. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/strings/length.py +0 -0
  202. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/strings/lower.py +0 -0
  203. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/strings/metaphone.py +0 -0
  204. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/strings/regex.py +0 -0
  205. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/strings/starts_with.py +0 -0
  206. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/strings/strip.py +0 -0
  207. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/strings/substring.py +0 -0
  208. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/strings/upper.py +0 -0
  209. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/testing/debug.py +0 -0
  210. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/types/__init__.py +0 -0
  211. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/types/boolean.py +0 -0
  212. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/types/datef.py +0 -0
  213. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/types/decimal.py +0 -0
  214. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/types/email.py +0 -0
  215. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/types/nonef.py +0 -0
  216. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/types/string.py +0 -0
  217. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/types/type.py +0 -0
  218. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/types/url.py +0 -0
  219. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/validity/fail.py +0 -0
  220. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/validity/failed.py +0 -0
  221. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/validity/line.py +0 -0
  222. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/variables/get.py +0 -0
  223. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/variables/pushpop.py +0 -0
  224. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/variables/put.py +0 -0
  225. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/variables/track.py +0 -0
  226. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/functions/variables/variables.py +0 -0
  227. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/lark_parser.py +0 -0
  228. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/lark_transformer.py +0 -0
  229. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/matcher.py +0 -0
  230. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/productions/__init__.py +0 -0
  231. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/productions/equality.py +0 -0
  232. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/productions/expression.py +0 -0
  233. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/productions/header.py +0 -0
  234. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/productions/matchable.py +0 -0
  235. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/productions/qualified.py +0 -0
  236. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/productions/reference.py +0 -0
  237. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/productions/term.py +0 -0
  238. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/productions/variable.py +0 -0
  239. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/util/exceptions.py +0 -0
  240. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/util/expression_encoder.py +0 -0
  241. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/util/expression_utility.py +0 -0
  242. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/util/lark_print_parser.py +0 -0
  243. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/matching/util/runtime_data_collector.py +0 -0
  244. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/modes/error_mode.py +0 -0
  245. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/modes/explain_mode.py +0 -0
  246. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/modes/files_mode.py +0 -0
  247. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/modes/logic_mode.py +0 -0
  248. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/modes/mode_controller.py +0 -0
  249. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/modes/print_mode.py +0 -0
  250. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/modes/return_mode.py +0 -0
  251. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/modes/run_mode.py +0 -0
  252. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/modes/source_mode.py +0 -0
  253. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/modes/transfer_mode.py +0 -0
  254. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/modes/unmatched_mode.py +0 -0
  255. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/modes/validation_mode.py +0 -0
  256. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/scanning/__init__.py +0 -0
  257. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/scanning/exceptions.py +0 -0
  258. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/scanning/parser.out +0 -0
  259. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/scanning/parsetab.py +0 -0
  260. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/scanning/scanner.py +0 -0
  261. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/scanning/scanning_lexer.py +0 -0
  262. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/azure/azure_data_reader.py +0 -0
  263. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/azure/azure_data_writer.py +0 -0
  264. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/azure/azure_fingerprinter.py +0 -0
  265. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/azure/azure_nos.py +0 -0
  266. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/azure/azure_utils.py +0 -0
  267. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/azure/azure_xlsx_data_reader.py +0 -0
  268. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/box.py +0 -0
  269. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/cache.py +0 -0
  270. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/caser.py +0 -0
  271. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/class_loader.py +0 -0
  272. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/code.py +0 -0
  273. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/config_exception.py +0 -0
  274. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/exceptions.py +0 -0
  275. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/file_info.py +0 -0
  276. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/file_readers.py +0 -0
  277. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/file_writers.py +0 -0
  278. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/gcs/gcs_data_reader.py +0 -0
  279. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/gcs/gcs_data_writer.py +0 -0
  280. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/gcs/gcs_fingerprinter.py +0 -0
  281. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/gcs/gcs_nos.py +0 -0
  282. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/gcs/gcs_utils.py +0 -0
  283. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/gcs/gcs_xlsx_data_reader.py +0 -0
  284. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/hasher.py +0 -0
  285. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/http/http_data_reader.py +0 -0
  286. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/intermediary.py +0 -0
  287. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/last_line_stats.py +0 -0
  288. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/line_counter.py +0 -0
  289. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/line_monitor.py +0 -0
  290. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/line_spooler.py +0 -0
  291. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/log_utility.py +0 -0
  292. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/metadata_parser.py +0 -0
  293. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/nos.py +0 -0
  294. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/pandas_data_reader.py +0 -0
  295. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/path_util.py +0 -0
  296. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/printer.py +0 -0
  297. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/references/reference_parser.py +0 -0
  298. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/run_home_maker.py +0 -0
  299. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/s3/s3_data_reader.py +0 -0
  300. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/s3/s3_data_writer.py +0 -0
  301. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/s3/s3_fingerprinter.py +0 -0
  302. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/s3/s3_nos.py +0 -0
  303. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/s3/s3_utils.py +0 -0
  304. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/s3/s3_xlsx_data_reader.py +0 -0
  305. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/sftp/sftp_data_reader.py +0 -0
  306. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/sftp/sftp_data_writer.py +0 -0
  307. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/sftp/sftp_fingerprinter.py +0 -0
  308. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/sftp/sftp_nos.py +0 -0
  309. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/sftp/sftp_walk.py +0 -0
  310. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/sftp/sftp_xlsx_data_reader.py +0 -0
  311. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/sqliter.py +0 -0
  312. {csvpath-0.0.535 → csvpath-0.0.537}/csvpath/util/template_util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: csvpath
3
- Version: 0.0.535
3
+ Version: 0.0.537
4
4
  Summary: A data preboarding framework for managing and validating CSV, Excel, and other tabular data files using a Collect, Store, Validate, Publish pattern to create a trusted publisher for downstream data consumers.
5
5
  Author: David Kershaw
6
6
  Author-email: dk107dk@hotmail.com
@@ -40,6 +40,14 @@ csvpaths = inputs/named_paths
40
40
  #files = sftp://172.17.0.3:10022/inputs/named_files
41
41
  on_unmatched_file_fingerprints = halt
42
42
 
43
+ [testing]
44
+ azure.skip=yes
45
+ gcs.skip=yes
46
+ s3.skip=yes
47
+ sftp.skip=yes
48
+
49
+
50
+
43
51
  #
44
52
  # integrations activation
45
53
  #
@@ -48,6 +56,12 @@ on_unmatched_file_fingerprints = halt
48
56
  groups =
49
57
  #slack, marquez, ckan, sftp, sftpplus, otlp, default, sqlite
50
58
 
59
+ # general purpose webhook caller
60
+ webhook.results = from csvpath.managers.integrations.webhook.webhook_results_listener import WebhookResultListener
61
+
62
+ # add a listener to exec scripts at the end of named-paths group runs
63
+ scripts.results = from csvpath.managers.integrations.scripts.scripts_results_listener import ScriptsResultsListener
64
+
51
65
  # add sql to capture staging, loads, and results in mysql, postgres, ms sql server, or sqlite
52
66
  sql.file = from csvpath.managers.integrations.sql.sql_file_listener import SqlFileListener
53
67
  sql.paths = from csvpath.managers.integrations.sql.sql_paths_listener import SqlPathsListener
@@ -145,4 +159,7 @@ verify = False
145
159
  # on-invalid-slack: webhook-minus-'https://'
146
160
  webhook_url =
147
161
 
162
+ [scripts]
163
+ run_scripts = yes
164
+ shell = /bin/bash
148
165
 
@@ -5,8 +5,8 @@ extensions = txt, csvpath, csvpaths
5
5
  extensions = txt, csv, tsv, dat, tab, psv, ssv
6
6
 
7
7
  [errors]
8
- csvpath = raise, collect, stop, fail, print
9
- csvpaths = raise, collect
8
+ csvpath = raise, collect, print
9
+ csvpaths = raise, collect, print
10
10
  use_format = full
11
11
  pattern = {time}:{file}:{line}:{paths}:{instance}:{chain}: {message}
12
12
 
@@ -16,7 +16,6 @@ csvpaths = debug
16
16
  log_file = logs\csvpath.log
17
17
  log_files_to_keep = 100
18
18
  log_file_size = 52428800
19
- # file or rotating
20
19
  handler = file
21
20
 
22
21
  [config]
@@ -37,58 +36,29 @@ files = inputs\named_files
37
36
  csvpaths = inputs\named_paths
38
37
  on_unmatched_file_fingerprints = halt
39
38
 
40
- #
41
- # integrations activation
42
- #
43
-
44
39
  [listeners]
45
- groups =
46
- #slack, marquez, ckan, sftp, sftpplus, otlp, default, sqlite
40
+ groups = scripts
41
+ scripts.results = from csvpath.managers.integrations.scripts.scripts_results_listener import ScriptsResultsListener
47
42
 
48
- # add sqlite to capture staging, loads, and results in a local sqlite db
49
43
  sqlite.result = from csvpath.managers.integrations.sqlite.sqlite_result_listener import SqliteResultListener
50
44
  sqlite.results = from csvpath.managers.integrations.sqlite.sqlite_results_listener import SqliteResultsListener
51
-
52
- # these simple default listeners track all files staged and all paths loaded in
53
- # central manifests. unlike other manifest writers, if they have multiple
54
- # concurrent users they have potential a race condition. users that do not
55
- # share inputs directories do not need to worry about this. you should vet
56
- # using them against your use case; potential utility vs. the modest but non-0
57
- # risk of lost updates. they can be disabled with little loss of function.
58
- # alternatively a database-backed version may be more suitable.
59
45
  default.file = from csvpath.managers.files.files_listener import FilesListener
60
46
  default.paths = from csvpath.managers.paths.paths_listener import PathsListener
61
-
62
- # add otlp to support any OpenTelemetry backend
63
47
  otlp.result = from csvpath.managers.integrations.otlp.otlp_result_listener import OpenTelemetryResultListener
64
48
  otlp.results = from csvpath.managers.integrations.otlp.otlp_results_listener import OpenTelemetryResultsListener
65
49
  otlp.errors = from csvpath.managers.integrations.otlp.otlp_error_listener import OpenTelemetryErrorListener
66
-
67
- # add sftpplus to the list of groups above to automate registration and named-paths group runs on file arrival at an SFTPPlus server
68
50
  sftpplus.paths = from csvpath.managers.integrations.sftpplus.sftpplus_listener import SftpPlusListener
69
-
70
- # add sftp to the list of groups above to push results to an sftp account
71
51
  sftp.results = from csvpath.managers.integrations.sftp.sftp_listener import SftpListener
72
-
73
- # add ckan to the list of groups above for alerts to slack webhooks
74
52
  ckan.results = from csvpath.managers.integrations.ckan.ckan_listener import CkanListener
75
-
76
- #add marquez to the list of groups above for OpenLineage events to a Marquez server
77
53
  marquez.file = from csvpath.managers.integrations.ol.file_listener_ol import OpenLineageFileListener
78
54
  marquez.paths = from csvpath.managers.integrations.ol.paths_listener_ol import OpenLineagePathsListener
79
55
  marquez.result = from csvpath.managers.integrations.ol.result_listener_ol import OpenLineageResultListener
80
56
  marquez.results = from csvpath.managers.integrations.ol.results_listener_ol import OpenLineageResultsListener
81
-
82
- # add slack to the list of groups above for alerts to slack webhooks
83
57
  slack.file = from csvpath.managers.integrations.slack.sender import SlackSender
84
58
  slack.paths = from csvpath.managers.integrations.slack.sender import SlackSender
85
59
  slack.result = from csvpath.managers.integrations.slack.sender import SlackSender
86
60
  slack.results = from csvpath.managers.integrations.slack.sender import SlackSender
87
61
 
88
- #
89
- # integrations setup
90
- #
91
-
92
62
  [sftp]
93
63
  server = 192.168.67.2
94
64
  port = 10022
@@ -99,12 +69,10 @@ password = tinpenny
99
69
  db = archive\csvpath.db
100
70
 
101
71
  [sftpplus]
102
- # these are only needed by the csvpath writer
103
72
  mailbox_user = MAILBOX_USER
104
73
  mailbox_password = MAILBOX_PASSWORD
105
74
  server = SFTPPLUS_SERVER
106
75
  port = SFTPPLUS_PORT
107
- # these are only needed on the server
108
76
  admin_username = SFTPPLUS_ADMIN_USERNAME
109
77
  admin_password = SFTPPLUS_ADMIN_PASSWORD
110
78
  api_url = https://localhost:10020/json
@@ -123,9 +91,11 @@ timeout = 5
123
91
  verify = False
124
92
 
125
93
  [slack]
126
- # add your main webhook here. to set webhooks on a csvpath-by-csvpath basis add
127
- # on-valid-slack: webhook-minus-'https://' and/or
128
- # on-invalid-slack: webhook-minus-'https://'
129
94
  webhook_url =
130
95
 
96
+ [scripts]
97
+ run_scripts = yes
98
+ shell = /bin/bash
99
+
100
+
131
101
 
@@ -40,6 +40,14 @@ csvpaths = inputs/named_paths
40
40
  #files = sftp://172.17.0.3:10022/inputs/named_files
41
41
  on_unmatched_file_fingerprints = halt
42
42
 
43
+ [testing]
44
+ azure.skip=yes
45
+ gcs.skip=yes
46
+ s3.skip=yes
47
+ sftp.skip=yes
48
+
49
+
50
+
43
51
  #
44
52
  # integrations activation
45
53
  #
@@ -48,6 +56,12 @@ on_unmatched_file_fingerprints = halt
48
56
  groups =
49
57
  #slack, marquez, ckan, sftp, sftpplus, otlp, default, sqlite
50
58
 
59
+ # general purpose webhook caller
60
+ webhook.results = from csvpath.managers.integrations.webhook.webhook_results_listener import WebhookResultListener
61
+
62
+ # add a listener to exec scripts at the end of named-paths group runs
63
+ scripts.results = from csvpath.managers.integrations.scripts.scripts_results_listener import ScriptsResultsListener
64
+
51
65
  # add sql to capture staging, loads, and results in mysql, postgres, ms sql server, or sqlite
52
66
  sql.file = from csvpath.managers.integrations.sql.sql_file_listener import SqlFileListener
53
67
  sql.paths = from csvpath.managers.integrations.sql.sql_paths_listener import SqlPathsListener
@@ -145,4 +159,7 @@ verify = False
145
159
  # on-invalid-slack: webhook-minus-'https://'
146
160
  webhook_url =
147
161
 
162
+ [scripts]
163
+ run_scripts = yes
164
+ shell = /bin/bash
148
165
 
@@ -128,8 +128,15 @@ class CsvPaths(CsvPathsCoordinator, ErrorCollector):
128
128
  self._fail_all = False
129
129
  self._skip_all = False
130
130
  self._advance_all = 0
131
+ #
132
+ # TODO: we probably don't need all three of these
133
+ #
131
134
  self._current_run_time = None
132
135
  self._run_time_str = None
136
+ self._last_run_dir = None
137
+ #
138
+ #
139
+ #
133
140
  self.named_paths_name = None
134
141
  """ @private """
135
142
  self.named_file_name = None
@@ -173,6 +180,10 @@ class CsvPaths(CsvPathsCoordinator, ErrorCollector):
173
180
  """@private"""
174
181
  self._ecoms = ec
175
182
 
183
+ @property
184
+ def last_run_dir(self) -> str:
185
+ return self._last_run_dir
186
+
176
187
  @property
177
188
  def file_manager(self) -> FileManager:
178
189
  return self._file_manager
@@ -297,7 +308,10 @@ class CsvPaths(CsvPathsCoordinator, ErrorCollector):
297
308
  self._run_time_str = None
298
309
  self.logger.debug("Cleared run coordination")
299
310
 
300
- def clean(self, *, paths) -> None:
311
+ #
312
+ # we do not currently use the paths param. what was the purpose?
313
+ #
314
+ def clean(self, *, paths=None) -> None:
301
315
  """@private
302
316
  at this time we do not recommend reusing CsvPaths, but it is doable
303
317
  you should clean before reuse unless you want to accumulate results."""
@@ -518,6 +532,11 @@ class CsvPaths(CsvPathsCoordinator, ErrorCollector):
518
532
  crt = maker.get_run_dir(
519
533
  paths_name=pathsname, file_name=filename, template=template
520
534
  )
535
+ #
536
+ # capture the last run dir for the benefit of the caller
537
+ #
538
+ self._last_run_dir = crt
539
+
521
540
  results = []
522
541
  #
523
542
  # run starts here
@@ -647,6 +666,10 @@ class CsvPaths(CsvPathsCoordinator, ErrorCollector):
647
666
  paths_name=pathsname, file_name=filename, template=template
648
667
  )
649
668
  #
669
+ # capture the last run dir for the benefit of the caller
670
+ #
671
+ self._last_run_dir = crt
672
+ #
650
673
  # run starts here
651
674
  #
652
675
  self.run_metadata = self.results_manager.start_run(
@@ -746,6 +769,10 @@ class CsvPaths(CsvPathsCoordinator, ErrorCollector):
746
769
  paths_name=pathsname, file_name=filename, template=template
747
770
  )
748
771
  #
772
+ # capture the last run dir for the benefit of the caller
773
+ #
774
+ self._last_run_dir = crt
775
+ #
749
776
  # run starts here
750
777
  #
751
778
  self.run_metadata = self.results_manager.start_run(
@@ -980,7 +1007,6 @@ class CsvPaths(CsvPathsCoordinator, ErrorCollector):
980
1007
  paths = self._get_named_paths(pathsname)
981
1008
  if template is None:
982
1009
  template = self.paths_manager.get_template_for_paths(pathsname)
983
-
984
1010
  #
985
1011
  # create run identity and directories
986
1012
  #
@@ -989,6 +1015,10 @@ class CsvPaths(CsvPathsCoordinator, ErrorCollector):
989
1015
  paths_name=pathsname, file_name=filename, template=template
990
1016
  )
991
1017
  #
1018
+ # capture the last run dir for the benefit of the caller
1019
+ #
1020
+ self._last_run_dir = crt
1021
+ #
992
1022
  # also use of crt below
993
1023
  #
994
1024
  csvpath_objects = self._load_csvpath_objects(
@@ -43,6 +43,9 @@ class Error(Metadata):
43
43
  self.message: str = msg
44
44
  self.expanded_message: str = None
45
45
  self.filename: str = None
46
+ self.run_dir = None
47
+ if error_manager and error_manager.csvpaths:
48
+ self.run_dir = error_manager.csvpaths.last_run_dir
46
49
  self.cwd = os.getcwd()
47
50
  self.pid = os.getpid()
48
51
 
@@ -67,6 +70,7 @@ class Error(Metadata):
67
70
  and self.message == e.message
68
71
  and self.identity == e.identity
69
72
  and self.filename == e.filename
73
+ and self.run_dir == e.run_dir
70
74
  and f"{self.time}" == f"{e.time}"
71
75
  )
72
76
 
@@ -106,6 +110,8 @@ class Error(Metadata):
106
110
  "filename": self.filename,
107
111
  "time": f"{self.time}",
108
112
  }
113
+ if self.run_dir is not None:
114
+ ret["run_dir"] = self.run_dir
109
115
  return ret
110
116
 
111
117
  def from_json(self, j: dict) -> None:
@@ -127,6 +133,8 @@ class Error(Metadata):
127
133
  self.identity = j["identity"]
128
134
  if "filename" in j:
129
135
  self.filename = j["filename"]
136
+ if "run_dir" in j:
137
+ self.run_dir = j["run_dir"]
130
138
  if "time" in j:
131
139
  time = dateutil.parser.parse(j["time"])
132
140
  self.time = time
@@ -152,6 +160,7 @@ ip_address: {self.ip_address},
152
160
  username: {self.username},
153
161
  named_paths_name: {self.named_paths_name if self.named_paths_name else ""},
154
162
  named_file_name: {self.named_file_name if self.named_file_name else ""},
163
+ run_dir: {self.run_dir if self.run_dir else ""},
155
164
  filename: {self.filename if self.filename else ""},
156
165
  path identity: {self.identity if self.identity else ""},
157
166
  expression_index: {self.expression_index if self.expression_index else ""},
@@ -194,7 +194,9 @@ class FileRegistrar(Registrar, Listener):
194
194
  #
195
195
  # log info so nobody has to dig to see why no update
196
196
  #
197
- self.csvpaths.logger.info("File has already been registered: %s", jdata)
197
+ self.csvpaths.logger.info(
198
+ "File has already been registered: %s", mdata.name_home
199
+ )
198
200
  return
199
201
  self.distribute_update(mdata)
200
202
 
@@ -0,0 +1,111 @@
1
+ import os
2
+ import subprocess
3
+ import threading
4
+ from datetime import datetime, timezone
5
+ from csvpath.managers.listener import Listener
6
+ from csvpath.managers.metadata import Metadata
7
+ from csvpath.util.file_writers import DataFileWriter
8
+
9
+
10
+ class ScriptsResultsListener(Listener, threading.Thread):
11
+ def __init__(self, config=None):
12
+ Listener.__init__(self, config=config)
13
+ threading.Thread.__init__(self)
14
+ self.csvpaths = None
15
+
16
+ def run(self):
17
+ self._metadata_update(self.metadata)
18
+
19
+ def metadata_update(self, mdata: Metadata) -> None:
20
+ self.metadata = mdata
21
+ self.start()
22
+
23
+ def _metadata_update(self, mdata: Metadata) -> None:
24
+ if not self.csvpaths:
25
+ raise RuntimeError(
26
+ "Scripts results listener cannot continue without a CsvPaths instance"
27
+ )
28
+ if mdata.time_completed is None:
29
+ return
30
+ #
31
+ # if we set a flag to run scripts we will, if any. otherwise, we skip.
32
+ #
33
+ run = self.csvpaths.config.get(section="scripts", name="run_scripts")
34
+ if run is None or run.strip() != "yes":
35
+ self.csvpaths.logger.info(
36
+ "Not running completion scripts, if any, because run_scripts is not yes"
37
+ )
38
+ return
39
+ #
40
+ # find any scripts
41
+ #
42
+ pm = self.csvpaths.paths_manager
43
+ cfg = pm.get_config_for_paths(mdata.named_paths_name)
44
+ if cfg is None:
45
+ return
46
+ #
47
+ # all runs for every execution, regardless of completeness, validity, etc.
48
+ #
49
+ t = "on_complete_all_script"
50
+ all_script = cfg.get(t)
51
+ if all_script is not None and all_script.strip() != "":
52
+ self._run(mdata=mdata, script_name=all_script, script_type=t)
53
+ #
54
+ # valid and invalid run according to the mdata:
55
+ # self.all_valid: bool = None
56
+ # self.error_count: int = None
57
+ #
58
+ if mdata.all_valid is True:
59
+ t = "on_complete_valid_script"
60
+ valid_script = cfg.get(t)
61
+ if valid_script is not None and valid_script.strip() != "":
62
+ self._run(mdata=mdata, script_name=valid_script, script_type=t)
63
+ else:
64
+ t = "on_complete_invalid_script"
65
+ invalid_script = cfg.get(t)
66
+ if invalid_script is not None and invalid_script.strip() != "":
67
+ self._run(mdata=mdata, script_name=invalid_script, script_type=t)
68
+ if mdata.error_count > 0:
69
+ t = "on_complete_error_script"
70
+ error_script = cfg.get(t)
71
+ if error_script is not None and error_script.strip() != "":
72
+ self._run(mdata=mdata, script_name=error_script, script_type=t)
73
+
74
+ def _run(self, *, mdata, script_name, script_type) -> None:
75
+ #
76
+ # get the script's bytes
77
+ # write to a temp file
78
+ # execute the file catching system out
79
+ # write system out to a script_name-timestamp.txt file in the results dir
80
+ #
81
+ try:
82
+ b = self.csvpaths.paths_manager.get_script_for_paths(
83
+ name=mdata.named_paths_name, script_type=script_type
84
+ )
85
+ path = os.path.dirname(mdata.manifest_path)
86
+ path = os.path.join(path, script_name)
87
+ with DataFileWriter(path=path) as to:
88
+ to.write(b)
89
+ #
90
+ # below is supposedly cross platform but just in case.
91
+ #
92
+ try:
93
+ os.chmod(path, 0o755)
94
+ except Exception:
95
+ ...
96
+ result = subprocess.run([path], capture_output=True, text=True, check=True)
97
+ out = result.stdout
98
+ err = result.stderr
99
+ if err is not None and err.strip() != "":
100
+ out = f"{out}\n ===================== \n{err}"
101
+ n = datetime.now(timezone.utc)
102
+ script_out_name = f"{script_name}-{n.strftime('%Y-%m-%d_%H-%M-%S_%f')}.txt"
103
+ script_out_path = mdata.run_home
104
+ script_out_path = os.path.join(script_out_path, script_out_name)
105
+ with DataFileWriter(path=script_out_path) as writer:
106
+ writer.write(out)
107
+ except Exception as e:
108
+ msg = f"Run script failed on results {mdata.named_paths_name}, script_name {script_name}, with {type(e)}: {e}"
109
+ self.csvpaths.logger.error(msg)
110
+ if self.csvpaths.ecoms.do_i_raise():
111
+ raise RuntimeError(msg) from e
@@ -48,7 +48,9 @@ class SftpSender(Listener, threading.Thread):
48
48
  self._password = VarUtility.get_str(m, v, "sftp-password")
49
49
  self._target_path = VarUtility.get_str(m, v, "sftp-target-path")
50
50
  self._original = VarUtility.get_bool(m, v, "sftp-original-data")
51
- self._files = VarUtility.get_value_pairs(m, v, "sftp-files")
51
+ self._files = VarUtility.get_value_pairs(
52
+ metadata=m, variables=v, key="sftp-files"
53
+ )
52
54
 
53
55
  def run(self):
54
56
  self.csvpaths.logger.info("Checking for requests to send result files by SFTP")
@@ -9,7 +9,8 @@ from .event import EventBuilder
9
9
 
10
10
  class SlackSender(Listener, threading.Thread):
11
11
  def __init__(self, *, config=None):
12
- super().__init__(config)
12
+ Listener.__init__(self, config=config)
13
+ threading.Thread.__init__(self)
13
14
  self._url = None
14
15
  self.csvpaths = None
15
16
  self.result = None
@@ -0,0 +1,135 @@
1
+ import requests
2
+ import threading
3
+
4
+ from abc import ABC
5
+ from csvpath.managers.metadata import Metadata
6
+ from csvpath.managers.listener import Listener
7
+ from csvpath.matching.util.expression_utility import ExpressionUtility
8
+
9
+ #
10
+ # ~
11
+ # webhook-url: https://zapier.com/hooks/asdf
12
+ # webhook-data: name > var|name, phone > $mygroup#result.variables.cell, $.csvpath.total_lines
13
+ #
14
+ #
15
+ # webhook-file: $.results.files.data, $mygroup#myinstance.results.files.errors
16
+ # $.results.
17
+ # $clean-invoices.results.acme/invoices/2025/Feb:0.step-three#var|cell
18
+ # $mygroup#myinstance.variables.cell
19
+ #
20
+ # ~
21
+ #
22
+
23
+
24
+ class WebhookException(Exception):
25
+ ...
26
+
27
+
28
+ class WebhookListener(Listener, threading.Thread):
29
+ ON_ALL = "on_complete_all_webhook"
30
+ ON_VALID = "on_complete_valid_webhook"
31
+ ON_INVALID = "on_complete_invalid_webhook"
32
+ ON_ERRORS = "on_complete_errors_webhook"
33
+
34
+ HOOKS = None
35
+ URLS = None
36
+
37
+ ALL_URL = "all_webhook_url"
38
+ VALID_URL = "valid_webhook_url"
39
+ INVALID_URL = "invalid_webhook_url"
40
+ ERRORS_URL = "errors_webhook_url"
41
+
42
+ def __init__(self, config=None):
43
+ super().__init__(config)
44
+ self._url = None
45
+ self.csvpaths = None
46
+ self.result = None
47
+ self.metadata = None
48
+ self._timeout = -1
49
+ if WebhookListener.HOOKS is None:
50
+ WebhookListener.HOOKS = [
51
+ WebhookListener.ON_ALL,
52
+ WebhookListener.ON_VALID,
53
+ WebhookListener.ON_INVALID,
54
+ WebhookListener.ON_ERRORS,
55
+ ]
56
+ if WebhookListener.URLS is None:
57
+ WebhookListener.URLS = {
58
+ WebhookListener.ON_ALL: WebhookListener.ALL_URL,
59
+ WebhookListener.ON_VALID: WebhookListener.VALID_URL,
60
+ WebhookListener.ON_INVALID: WebhookListener.INVALID_URL,
61
+ WebhookListener.ON_ERRORS: WebhookListener.ERRORS_URL,
62
+ }
63
+
64
+ @property
65
+ def timeout(self) -> int:
66
+ if self._timeout == -1:
67
+ t = self.csvpaths.config.get(section="webhook", name="timeout", default=3)
68
+ t = ExpressionUtility.to_float(t)
69
+ if isinstance(t, float):
70
+ self._timeout = t
71
+ else:
72
+ self._timeout = 3
73
+ return self._timeout
74
+
75
+ @property
76
+ def csvpath(self):
77
+ return self.result.csvpath
78
+
79
+ def run(self):
80
+ self._metadata_update(self.metadata)
81
+
82
+ def metadata_update(self, mdata: Metadata) -> None:
83
+ self.metadata = mdata
84
+ self.start()
85
+
86
+ def _metadata_update(self, mdata: Metadata) -> None:
87
+ if mdata is None:
88
+ raise ValueError("Metadata cannot be None")
89
+ for t in WebhookListener.HOOKS:
90
+ try:
91
+ self._do_hook_if(mdata=mdata, atype=t)
92
+ except Exception as e:
93
+ if isinstance(e, WebhookException):
94
+ raise
95
+ msg = f"WebhookListener could not call {t} webhook: {type(e)}: {e}"
96
+ self.csvpaths.logger.error(msg)
97
+ if self.csvpaths.ecoms.do_i_raise():
98
+ raise WebhookException(msg)
99
+
100
+ def _do_hook_if(self, *, mdata: Metadata, atype: str) -> None:
101
+ if not self._run(mdata, atype):
102
+ return
103
+ url = self._url_for_type(mdata, WebhookListener.URLS[atype])
104
+ if url is None:
105
+ self.csvpaths.logger.debug(
106
+ "Nothing to do for webhook url %s", WebhookListener.URLS[atype]
107
+ )
108
+ return
109
+ payload = self._payload_for_type(mdata, atype)
110
+ #
111
+ # prep request
112
+ #
113
+ headers = {"Content-Type": "application/json"}
114
+ #
115
+ # send
116
+ #
117
+ x = requests.post(url, json=payload, headers=headers, timeout=self.timeout)
118
+ if x and x.status_code != 200:
119
+ if self.csvpaths is not None:
120
+ self.csvpaths.logger.warning(
121
+ "WebhookListener received status code %s from %s",
122
+ x.status_code,
123
+ "",
124
+ )
125
+ elif self.result is not None:
126
+ self.result.csvpath.logger.warning(
127
+ "WebhookListener received status code %s from %s",
128
+ x.status_code,
129
+ "",
130
+ )
131
+ else:
132
+ msg = f"WebhookListener received status code {x.status_code} from {self.url}"
133
+ self.csvpaths.logger.error(msg)
134
+ if self.csvpaths.ecoms.do_i_raise():
135
+ raise WebhookException(msg)