csvpath 0.0.494__tar.gz → 0.0.495__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 (238) hide show
  1. {csvpath-0.0.494 → csvpath-0.0.495}/PKG-INFO +1 -1
  2. {csvpath-0.0.494 → csvpath-0.0.495}/config/config.ini +5 -0
  3. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/csvpath.py +124 -11
  4. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/csvpaths.py +126 -24
  5. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/managers/file_manager.py +13 -1
  6. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/managers/file_registrar.py +1 -1
  7. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/managers/line_spooler.py +8 -0
  8. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/managers/paths_registrar.py +1 -1
  9. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/managers/result.py +28 -8
  10. csvpath-0.0.495/csvpath/managers/result_registrar.py +129 -0
  11. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/managers/result_serializer.py +27 -9
  12. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/managers/results_manager.py +80 -3
  13. csvpath-0.0.495/csvpath/managers/results_registrar.py +69 -0
  14. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/strings/regex.py +4 -4
  15. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/util/runtime_data_collector.py +58 -2
  16. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/config.py +31 -0
  17. csvpath-0.0.495/csvpath/util/csvpaths_registrar.py +99 -0
  18. {csvpath-0.0.494 → csvpath-0.0.495}/pyproject.toml +1 -1
  19. {csvpath-0.0.494 → csvpath-0.0.495}/LICENSE +0 -0
  20. {csvpath-0.0.494 → csvpath-0.0.495}/README.md +0 -0
  21. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/__init__.py +0 -0
  22. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/cli/__init__.py +0 -0
  23. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/cli/cli.py +0 -0
  24. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/cli/drill_down.py +0 -0
  25. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/managers/__init__.py +0 -0
  26. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/managers/paths_manager.py +0 -0
  27. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/__init__.py +0 -0
  28. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/__init__.py +0 -0
  29. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/args.py +0 -0
  30. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/boolean/all.py +0 -0
  31. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/boolean/andf.py +0 -0
  32. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/boolean/any.py +0 -0
  33. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/boolean/between.py +0 -0
  34. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/boolean/empty.py +0 -0
  35. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/boolean/exists.py +0 -0
  36. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/boolean/inf.py +0 -0
  37. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/boolean/no.py +0 -0
  38. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/boolean/notf.py +0 -0
  39. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/boolean/orf.py +0 -0
  40. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/boolean/yes.py +0 -0
  41. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/counting/count.py +0 -0
  42. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/counting/count_bytes.py +0 -0
  43. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/counting/count_headers.py +0 -0
  44. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/counting/count_lines.py +0 -0
  45. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/counting/count_scans.py +0 -0
  46. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/counting/counter.py +0 -0
  47. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/counting/every.py +0 -0
  48. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/counting/has_matches.py +0 -0
  49. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/counting/increment.py +0 -0
  50. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/counting/tally.py +0 -0
  51. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/counting/total_lines.py +0 -0
  52. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/dates/now.py +0 -0
  53. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/function.py +0 -0
  54. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/function_factory.py +0 -0
  55. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/function_finder.py +0 -0
  56. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/function_focus.py +0 -0
  57. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/headers/append.py +0 -0
  58. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/headers/collect.py +0 -0
  59. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/headers/empty_stack.py +0 -0
  60. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/headers/end.py +0 -0
  61. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/headers/header_name.py +0 -0
  62. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/headers/header_names_mismatch.py +0 -0
  63. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/headers/headers.py +0 -0
  64. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/headers/mismatch.py +0 -0
  65. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/headers/replace.py +0 -0
  66. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/headers/reset_headers.py +0 -0
  67. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/lines/advance.py +0 -0
  68. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/lines/after_blank.py +0 -0
  69. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/lines/dups.py +0 -0
  70. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/lines/first.py +0 -0
  71. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/lines/first_line.py +0 -0
  72. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/lines/last.py +0 -0
  73. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/lines/stop.py +0 -0
  74. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/math/above.py +0 -0
  75. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/math/add.py +0 -0
  76. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/math/divide.py +0 -0
  77. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/math/equals.py +0 -0
  78. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/math/intf.py +0 -0
  79. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/math/mod.py +0 -0
  80. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/math/multiply.py +0 -0
  81. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/math/round.py +0 -0
  82. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/math/subtotal.py +0 -0
  83. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/math/subtract.py +0 -0
  84. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/math/sum.py +0 -0
  85. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/misc/fingerprint.py +0 -0
  86. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/misc/importf.py +0 -0
  87. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/misc/random.py +0 -0
  88. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/print/jinjaf.py +0 -0
  89. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/print/print_line.py +0 -0
  90. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/print/print_queue.py +0 -0
  91. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/print/printf.py +0 -0
  92. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/print/table.py +0 -0
  93. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/stats/minf.py +0 -0
  94. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/stats/percent.py +0 -0
  95. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/stats/percent_unique.py +0 -0
  96. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/stats/stdev.py +0 -0
  97. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/strings/concat.py +0 -0
  98. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/strings/length.py +0 -0
  99. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/strings/lower.py +0 -0
  100. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/strings/metaphone.py +0 -0
  101. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/strings/starts_with.py +0 -0
  102. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/strings/strip.py +0 -0
  103. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/strings/substring.py +0 -0
  104. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/strings/upper.py +0 -0
  105. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/testing/debug.py +0 -0
  106. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/types/__init__.py +0 -0
  107. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/types/boolean.py +0 -0
  108. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/types/datef.py +0 -0
  109. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/types/decimal.py +0 -0
  110. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/types/nonef.py +0 -0
  111. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/types/string.py +0 -0
  112. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/types/type.py +0 -0
  113. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/validity/fail.py +0 -0
  114. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/validity/failed.py +0 -0
  115. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/validity/line.py +0 -0
  116. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/variables/get.py +0 -0
  117. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/variables/pushpop.py +0 -0
  118. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/variables/put.py +0 -0
  119. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/variables/track.py +0 -0
  120. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/functions/variables/variables.py +0 -0
  121. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/lark_parser.py +0 -0
  122. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/lark_transformer.py +0 -0
  123. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/matcher.py +0 -0
  124. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/productions/__init__.py +0 -0
  125. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/productions/equality.py +0 -0
  126. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/productions/expression.py +0 -0
  127. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/productions/header.py +0 -0
  128. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/productions/matchable.py +0 -0
  129. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/productions/qualified.py +0 -0
  130. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/productions/reference.py +0 -0
  131. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/productions/term.py +0 -0
  132. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/productions/variable.py +0 -0
  133. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/util/exceptions.py +0 -0
  134. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/util/expression_encoder.py +0 -0
  135. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/util/expression_utility.py +0 -0
  136. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/util/lark_print_parser.py +0 -0
  137. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/matching/util/print_parser.py +0 -0
  138. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/scanning/__init__.py +0 -0
  139. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/scanning/exceptions.py +0 -0
  140. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/scanning/parser.out +0 -0
  141. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/scanning/parsetab.py +0 -0
  142. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/scanning/scanner.py +0 -0
  143. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/scanning/scanning_lexer.py +0 -0
  144. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/cache.py +0 -0
  145. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/config_exception.py +0 -0
  146. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/error.py +0 -0
  147. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/exceptions.py +0 -0
  148. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/file_readers.py +0 -0
  149. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/last_line_stats.py +0 -0
  150. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/line_counter.py +0 -0
  151. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/line_monitor.py +0 -0
  152. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/log_utility.py +0 -0
  153. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/metadata_parser.py +0 -0
  154. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/pandas_data_reader.py +0 -0
  155. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/printer.py +0 -0
  156. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/reference_parser.py +0 -0
  157. {csvpath-0.0.494 → csvpath-0.0.495}/csvpath/util/s3_data_reader.py +0 -0
  158. {csvpath-0.0.494 → csvpath-0.0.495}/docs/asbool.md +0 -0
  159. {csvpath-0.0.494 → csvpath-0.0.495}/docs/assignment.md +0 -0
  160. {csvpath-0.0.494 → csvpath-0.0.495}/docs/comments.md +0 -0
  161. {csvpath-0.0.494 → csvpath-0.0.495}/docs/config.md +0 -0
  162. {csvpath-0.0.494 → csvpath-0.0.495}/docs/examples.md +0 -0
  163. {csvpath-0.0.494 → csvpath-0.0.495}/docs/files.md +0 -0
  164. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/above.md +0 -0
  165. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/advance.md +0 -0
  166. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/after_blank.md +0 -0
  167. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/all.md +0 -0
  168. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/andor.md +0 -0
  169. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/any.md +0 -0
  170. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/average.md +0 -0
  171. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/between.md +0 -0
  172. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/collect.md +0 -0
  173. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/correlate.md +0 -0
  174. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/count.md +0 -0
  175. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/count_bytes.md +0 -0
  176. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/count_headers.md +0 -0
  177. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/counter.md +0 -0
  178. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/date.md +0 -0
  179. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/empty.md +0 -0
  180. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/empty_stack.md +0 -0
  181. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/end.md +0 -0
  182. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/every.md +0 -0
  183. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/fail.md +0 -0
  184. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/fingerprint.md +0 -0
  185. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/first.md +0 -0
  186. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/get.md +0 -0
  187. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/has_dups.md +0 -0
  188. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/has_matches.md +0 -0
  189. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/header.md +0 -0
  190. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/header_name.md +0 -0
  191. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/header_names_mismatch.md +0 -0
  192. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/implementing_functions.md +0 -0
  193. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/import.md +0 -0
  194. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/in.md +0 -0
  195. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/increment.md +0 -0
  196. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/intf.md +0 -0
  197. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/jinja.md +0 -0
  198. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/last.md +0 -0
  199. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/line.md +0 -0
  200. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/line_number.md +0 -0
  201. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/max.md +0 -0
  202. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/metaphone.md +0 -0
  203. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/mismatch.md +0 -0
  204. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/no.md +0 -0
  205. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/not.md +0 -0
  206. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/now.md +0 -0
  207. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/percent_unique.md +0 -0
  208. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/pop.md +0 -0
  209. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/print.md +0 -0
  210. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/print_line.md +0 -0
  211. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/print_queue.md +0 -0
  212. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/random.md +0 -0
  213. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/regex.md +0 -0
  214. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/replace.md +0 -0
  215. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/reset_headers.md +0 -0
  216. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/stdev.md +0 -0
  217. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/stop.md +0 -0
  218. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/string_functions.md +0 -0
  219. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/subtotal.md +0 -0
  220. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/subtract.md +0 -0
  221. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/sum.md +0 -0
  222. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/tally.md +0 -0
  223. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/total_lines.md +0 -0
  224. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/track.md +0 -0
  225. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/types.md +0 -0
  226. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/variables.md +0 -0
  227. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions/variables_and_headers.md +0 -0
  228. {csvpath-0.0.494 → csvpath-0.0.495}/docs/functions.md +0 -0
  229. {csvpath-0.0.494 → csvpath-0.0.495}/docs/grammar.md +0 -0
  230. {csvpath-0.0.494 → csvpath-0.0.495}/docs/headers.md +0 -0
  231. {csvpath-0.0.494 → csvpath-0.0.495}/docs/images/logo-wordmark-white-on-black-trimmed-padded.png +0 -0
  232. {csvpath-0.0.494 → csvpath-0.0.495}/docs/images/logo-wordmark-white-trimmed.png +0 -0
  233. {csvpath-0.0.494 → csvpath-0.0.495}/docs/paths.md +0 -0
  234. {csvpath-0.0.494 → csvpath-0.0.495}/docs/printing.md +0 -0
  235. {csvpath-0.0.494 → csvpath-0.0.495}/docs/qualifiers.md +0 -0
  236. {csvpath-0.0.494 → csvpath-0.0.495}/docs/references.md +0 -0
  237. {csvpath-0.0.494 → csvpath-0.0.495}/docs/terms.md +0 -0
  238. {csvpath-0.0.494 → csvpath-0.0.495}/docs/variables.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: csvpath
3
- Version: 0.0.494
3
+ Version: 0.0.495
4
4
  Summary: A declarative language for validating CSV, Excel, and other tabular data files
5
5
  Author: David Kershaw
6
6
  Author-email: dk107dk@hotmail.com
@@ -27,3 +27,8 @@ imports = config/functions.imports
27
27
  [results]
28
28
  archive = archive
29
29
 
30
+ [inputs]
31
+ files = inputs/named_files
32
+ csvpaths = inputs/named_paths
33
+ on_unmatched_file_fingerprints = halt
34
+
@@ -233,6 +233,14 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
233
233
  self._errors: List[Error] = None
234
234
  self._error_collector = None
235
235
  #
236
+ # transfers from transfer-mode: ((data | unmatched):var-name)(,*)
237
+ # this setting tells CsvPaths to copy resulting data.csv and/or
238
+ # unmatched.csv to one or more target locations below the config.ini's
239
+ # transfer directory. the name "data" or "unmatched" is paired with
240
+ # a var name that indicates the path to write the indicated file.
241
+ #
242
+ self._transfers = None
243
+ #
236
244
  # saves the scan and match parts of paths for reference. mainly helpful
237
245
  # for testing the CsvPath library itself; not used end users. the run
238
246
  # name becomes the file name of the saved path parts.
@@ -308,7 +316,7 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
308
316
  self._function_times_value = {}
309
317
  self._created_at = datetime.now()
310
318
  self._run_started_at = None
311
-
319
+ self._all_expected_files = []
312
320
  self._collecting = False
313
321
  self._unmatched = None
314
322
  self._unmatched_available = False
@@ -364,11 +372,11 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
364
372
  return self._run_started_at
365
373
 
366
374
  @property
367
- def run_mode(self) -> bool:
375
+ def will_run(self) -> bool:
368
376
  return self._run_mode
369
377
 
370
- @run_mode.setter
371
- def run_mode(self, mode) -> None:
378
+ @will_run.setter
379
+ def will_run(self, mode) -> None:
372
380
  self._run_mode = mode
373
381
 
374
382
  def _up_function_time_match(self, c, t) -> None:
@@ -449,6 +457,7 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
449
457
  is preferred over name. E.g.:
450
458
  ~ name: my path description: an example ~
451
459
  """
460
+ # this ordering is relied on in Result and possibly elsewhere
452
461
  if not self.metadata:
453
462
  return ""
454
463
  if "id" in self.metadata:
@@ -471,7 +480,7 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
471
480
  self._config = Config()
472
481
  return self._config
473
482
 
474
- def has_errors(self) -> bool: # pylint: disable=C0116
483
+ def has_errors(self) -> bool:
475
484
  if self.errors and len(self.errors) > 0:
476
485
  return True
477
486
  if self.error_collector:
@@ -720,6 +729,7 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
720
729
  # - run-mode: no-run | run
721
730
  # - unmatched-mode: no-keep | keep
722
731
  # - source-mode: preceding | origin
732
+ # - files-mode: all | no-data | no-unmatched | no-printouts | data | unmatched | errors | meta | vars | printouts
723
733
  #
724
734
  self.update_logic_mode_if()
725
735
  self.update_run_mode_if()
@@ -729,6 +739,87 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
729
739
  self.update_arg_validation_mode_if()
730
740
  self.update_unmatched_mode_if()
731
741
  self.update_data_from_preceding_if()
742
+ self.update_expected_files_if()
743
+ self.update_transfer_mode_if()
744
+
745
+ # =====================
746
+
747
+ @property
748
+ def transfer_mode(self) -> str:
749
+ return self.metadata.get("transfer-mode")
750
+
751
+ @property
752
+ def source_mode(self) -> str:
753
+ return self.metadata.get("source-mode")
754
+
755
+ @property
756
+ def files_mode(self) -> str:
757
+ return self.metadata.get("files-mode")
758
+
759
+ @property
760
+ def validation_mode(self) -> str:
761
+ return self.metadata.get("validation-mode")
762
+
763
+ @property
764
+ def run_mode(self) -> str:
765
+ return self.metadata.get("run-mode")
766
+
767
+ @property
768
+ def logic_mode(self) -> str:
769
+ return "AND" if self.AND else "OR"
770
+
771
+ @property
772
+ def return_mode(self) -> str:
773
+ return self.metadata.get("return-mode")
774
+
775
+ @property
776
+ def explain_mode(self) -> str:
777
+ return self.metadata.get("explain-mode")
778
+
779
+ @property
780
+ def print_mode(self) -> str:
781
+ return self.metadata.get("print-mode")
782
+
783
+ @property
784
+ def unmatched_mode(self) -> str:
785
+ return self.metadata.get("unmatched-mode")
786
+
787
+ # =====================
788
+
789
+ @property
790
+ def transfers(self) -> list[tuple[str, str]]:
791
+ return self._transfers
792
+
793
+ def update_transfer_mode_if(self) -> None:
794
+ m = self.transfer_mode
795
+ if m is not None:
796
+ self._transfers = []
797
+ for t in m.split(","):
798
+ i = t.find(">")
799
+ if i == -1:
800
+ raise InputException(
801
+ "Transfer mode directive must be in the form file > location"
802
+ )
803
+ file = t[0:i].strip()
804
+ location = t[i + 1 :].strip()
805
+ self._transfers.append((file, location))
806
+
807
+ def update_expected_files_if(self) -> None:
808
+ fm = self.files_mode
809
+ if fm is None:
810
+ return []
811
+ fs = [s for s in fm.split(",")]
812
+ _ = []
813
+ for s in fs:
814
+ s = s.strip()
815
+ if s not in ["data", "unmatched", "vars", "errors", "meta", "printouts"]:
816
+ self.logger.warning(
817
+ "Unknown file-mode token %s. Mode tokens may be separated by , and will be trimmed.",
818
+ s,
819
+ )
820
+ continue
821
+ _.append(s)
822
+ self.all_expected_files = _
732
823
 
733
824
  def update_data_from_preceding_if(self) -> None:
734
825
  if self.metadata and "source-mode" in self.metadata:
@@ -758,9 +849,9 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
758
849
  def update_run_mode_if(self) -> None:
759
850
  if self.metadata and "run-mode" in self.metadata:
760
851
  if f"{self.metadata['run-mode']}".strip() == "no-run":
761
- self.run_mode = False
852
+ self.will_run = False
762
853
  elif f"{self.metadata['run-mode']}".strip() == "run":
763
- self.run_mode = True
854
+ self.will_run = True
764
855
  else:
765
856
  self.logger.warning(
766
857
  "Incorrect metadata field value 'run-mode': %s",
@@ -824,6 +915,14 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
824
915
  self.metadata["print-mode"],
825
916
  )
826
917
 
918
+ @property
919
+ def all_expected_files(self) -> list[str]:
920
+ return self._all_expected_files
921
+
922
+ @all_expected_files.setter
923
+ def all_expected_files(self, efs: list[str]) -> None:
924
+ self._all_expected_files = efs
925
+
827
926
  def _pick_named_path(self, name, *, specific=None) -> str:
828
927
  if not self.csvpaths:
829
928
  raise CsvPathsException("No CsvPaths object available")
@@ -972,6 +1071,14 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
972
1071
  def is_valid(self, tf: bool) -> None:
973
1072
  self._is_valid = tf
974
1073
 
1074
+ @property
1075
+ def completed(self) -> bool:
1076
+ if not self.scanner or not self.line_monitor:
1077
+ return False
1078
+ if self.scanner.is_last(self.line_monitor.physical_line_number):
1079
+ return True
1080
+ return False
1081
+
975
1082
  @property
976
1083
  def from_line(self): # pragma: no cover pylint: disable=C0116
977
1084
  if self.scanner is None:
@@ -1066,12 +1173,18 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
1066
1173
  nexts -= 1
1067
1174
  else:
1068
1175
  break
1069
- # we don't want to hold on to lines more than needed.
1070
- # we do want to return them if we're not spooling. the
1176
+ # we don't want to hold on to data more than needed. but
1177
+ # we do want to return data if we're not spooling. the
1071
1178
  # way we do that is to keep the local var available with the
1072
1179
  # list and/or the spooler. the caller needs to be aware of
1073
1180
  # both possibilities, but both offer __len__ and append.
1074
- self.lines = None
1181
+ #
1182
+ # we keep the self.lines if it is not a list because that
1183
+ # makes it available to the runtime data collector so we can
1184
+ # see the line count in the metadata, saving opening a
1185
+ # potentially large data.csv to find out how many lines.
1186
+ if isinstance(self.lines, list):
1187
+ self.lines = None
1075
1188
  return lines
1076
1189
 
1077
1190
  def fast_forward(self, csvpath=None) -> None:
@@ -1090,7 +1203,7 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
1090
1203
  if self.scanner is None and csvpath is not None:
1091
1204
  self.parse(csvpath)
1092
1205
  start = time.time()
1093
- if self.run_mode is True:
1206
+ if self.will_run is True:
1094
1207
  for line in self._next_line():
1095
1208
  b = self._consider_line(line)
1096
1209
  if b:
@@ -10,10 +10,12 @@ from .util.error import ErrorHandler, ErrorCollector, Error
10
10
  from .util.config import Config
11
11
  from .util.log_utility import LogUtility
12
12
  from .util.metadata_parser import MetadataParser
13
- from .util.exceptions import InputException
13
+ from .util.exceptions import InputException, CsvPathsException
14
+ from .util.csvpaths_registrar import CsvPathsRegistrar, CsvPathsFilesystemRegistrar
14
15
  from .managers.paths_manager import PathsManager
15
16
  from .managers.file_manager import FileManager
16
17
  from .managers.results_manager import ResultsManager
18
+ from .managers.results_registrar import ResultsRegistrar
17
19
  from .managers.result import Result
18
20
  from . import CsvPath
19
21
 
@@ -148,6 +150,20 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
148
150
  self._skip_all = False
149
151
  self._advance_all = 0
150
152
  self._current_run_time = None
153
+ self._csvpaths_registrars = []
154
+ self._csvpaths_registrars.append(CsvPathsFilesystemRegistrar(self))
155
+ self._run_time_str = None
156
+
157
+ def run_time_str(self, pathsname=None) -> str:
158
+ if self._run_time_str is None and pathsname is None:
159
+ raise CsvPathsException(
160
+ "Cannot have None in both run_time_str and pathsname"
161
+ )
162
+ if self._run_time_str is None:
163
+ self._run_time_str = self.results_manager.get_run_time_str(
164
+ pathsname, self.current_run_time
165
+ )
166
+ return self._run_time_str
151
167
 
152
168
  @property
153
169
  def current_run_time(self) -> datetime:
@@ -193,6 +209,15 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
193
209
  def advance_all(self, lines: int) -> None: # pragma: no cover
194
210
  self._advance_all = lines
195
211
 
212
+ @property
213
+ def csvpaths_registrars(self) -> list[CsvPathsRegistrar]:
214
+ if self._csvpaths_registrars is None:
215
+ self._csvpaths_registrars = []
216
+ return self._csvpaths_registrars
217
+
218
+ def add_csvpaths_registrar(self, creg) -> None:
219
+ self.csvpaths_registrars.append(creg)
220
+
196
221
  @property
197
222
  def errors(self) -> List[Error]: # pylint: disable=C0116
198
223
  return self._errors
@@ -216,13 +241,18 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
216
241
 
217
242
  def collect_paths(self, *, pathsname, filename) -> None:
218
243
  paths = self.paths_manager.get_named_paths(pathsname)
244
+ if paths is None:
245
+ raise InputException(f"No named-paths found for {pathsname}")
219
246
  file = self.file_manager.get_named_file(filename)
247
+ if file is None:
248
+ raise InputException(f"No named-file found for {filename}")
220
249
  self.logger.info("Prepping %s and %s", filename, pathsname)
221
250
  self.clean(paths=pathsname)
222
251
  self.logger.info(
223
252
  "Beginning collect_paths %s with %s paths", pathsname, len(paths)
224
253
  )
225
- crt = self.results_manager.get_run_time_str(pathsname, self.current_run_time)
254
+ crt = self.run_time_str(pathsname)
255
+ results = []
226
256
  for i, path in enumerate(paths):
227
257
  csvpath = self.csvpath()
228
258
  result = Result(
@@ -237,29 +267,25 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
237
267
  # want to never fail during a run
238
268
  try:
239
269
  self.results_manager.add_named_result(result)
240
- self._load_csvpath(csvpath, path=path, file=file, pathsname=pathsname)
270
+ self._load_csvpath(
271
+ csvpath=csvpath,
272
+ path=path,
273
+ file=file,
274
+ pathsname=pathsname,
275
+ filename=filename,
276
+ )
241
277
  lines = result.lines
278
+ self.logger.debug("Collecting lines using a %s", type(lines))
242
279
  csvpath.collect(lines=lines)
243
- # lines = csvpath.collect()
244
280
  if lines is None:
245
281
  self.logger.error( # pragma: no cover
246
282
  "Unexpected None for lines after collect_paths: file: %s, match: %s",
247
283
  file,
248
284
  csvpath.match,
249
285
  )
250
- """
251
286
  #
252
- # this seems to have not been very useful and with LineSpooler it seems
253
- # to not be helpful at all.
287
+ # this is obviously not a good idea for very large files!
254
288
  #
255
- if len(lines) == 0:
256
- self.logger.warning( # pragma: no cover
257
- "No lines collected in collect_paths: file: %s match: %s",
258
- file,
259
- csvpath.match,
260
- )
261
- """
262
- # result.lines = lines
263
289
  result.unmatched = csvpath.unmatched
264
290
  except Exception as ex: # pylint: disable=W0718
265
291
  ex.trace = traceback.format_exc()
@@ -272,18 +298,32 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
272
298
  self.results_manager.save(result)
273
299
  raise e
274
300
  self.results_manager.save(result)
301
+ results.append(result)
302
+ rr = ResultsRegistrar(
303
+ csvpaths=self, run_dir=crt, pathsname=pathsname, results=results
304
+ )
305
+ rr.write_manifest()
306
+ #
307
+ # update/write run manifests here
308
+ # - validity (are all paths valid)
309
+ # - paths-completeness (did they all run and complete)
310
+ # - method (collect, fast_forward, next)
311
+ # - timestamp
312
+ #
275
313
  self.clear_run_coordination()
276
314
  self.logger.info(
277
315
  "Completed collect_paths %s with %s paths", pathsname, len(paths)
278
316
  )
279
317
 
280
318
  def _load_csvpath(
281
- self, csvpath: CsvPath, path: str, file: str, pathsname: str = None
319
+ self, *, csvpath: CsvPath, path: str, file: str, pathsname: str = None, filename
282
320
  ) -> None:
321
+ # file is the physical file (+/- if preceding mode) filename is the named-file name
283
322
  self.logger.debug("Beginning to load csvpath %s with file %s", path, file)
284
323
  # we strip comments from above the path so we need to extract them first
285
324
  path = MetadataParser(self).extract_metadata(instance=csvpath, csvpath=path)
286
- self.logger.debug("Csvpath after metadata extract: %s", path)
325
+ identity = csvpath.identity
326
+ self.logger.debug("Csvpath %s after metadata extract: %s", identity, path)
287
327
  # update the settings using the metadata fields we just collected
288
328
  csvpath.update_settings_from_metadata()
289
329
  #
@@ -316,6 +356,20 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
316
356
  apath = f"${file}{path[f:]}"
317
357
  self.logger.info("Parsing csvpath %s", apath)
318
358
  csvpath.parse(apath)
359
+ #
360
+ # ready to run. time to register the run.
361
+ #
362
+ crt = self.run_time_str(pathsname)
363
+ fingerprint = self.file_manager.get_fingerprint_for_name(filename)
364
+ for _ in self.csvpaths_registrars:
365
+ _.update_manifest(
366
+ csvpath=csvpath,
367
+ filepath=file,
368
+ instancepath=crt,
369
+ fingerprint=fingerprint,
370
+ identity=identity,
371
+ )
372
+ self.logger.debug("Done loading csvpath")
319
373
 
320
374
  def fast_forward_paths(self, *, pathsname, filename):
321
375
  paths = self.paths_manager.get_named_paths(pathsname)
@@ -328,7 +382,8 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
328
382
  len(paths),
329
383
  filename,
330
384
  )
331
- crt = self.results_manager.get_run_time_str(pathsname, self.current_run_time)
385
+ crt = self.run_time_str(pathsname)
386
+ results = []
332
387
  for i, path in enumerate(paths):
333
388
  csvpath = self.csvpath()
334
389
  self.logger.debug("Beginning to FF CsvPath instance: %s", csvpath)
@@ -342,7 +397,13 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
342
397
  )
343
398
  try:
344
399
  self.results_manager.add_named_result(result)
345
- self._load_csvpath(csvpath, path=path, file=file, pathsname=pathsname)
400
+ self._load_csvpath(
401
+ csvpath=csvpath,
402
+ path=path,
403
+ file=file,
404
+ pathsname=pathsname,
405
+ filename=filename,
406
+ )
346
407
  self.logger.info(
347
408
  "Parsed csvpath %s pointed at %s and starting to fast-forward",
348
409
  i,
@@ -363,6 +424,11 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
363
424
  self.results_manager.save(result)
364
425
  raise e
365
426
  self.results_manager.save(result)
427
+ results.append(result)
428
+ rr = ResultsRegistrar(
429
+ csvpaths=self, run_dir=crt, pathsname=pathsname, results=results
430
+ )
431
+ rr.write_manifest()
366
432
  self.clear_run_coordination()
367
433
  self.logger.info(
368
434
  "Completed fast_forward_paths %s with %s paths", pathsname, len(paths)
@@ -377,7 +443,8 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
377
443
  self.logger.info("Prepping %s and %s", filename, pathsname)
378
444
  self.clean(paths=pathsname)
379
445
  self.logger.info("Beginning next_paths with %s paths", len(paths))
380
- crt = self.results_manager.get_run_time_str(pathsname, self.current_run_time)
446
+ crt = self.run_time_str(pathsname)
447
+ results = []
381
448
  for i, path in enumerate(paths):
382
449
  if self._skip_all:
383
450
  skip_err = "Found the skip-all signal set. skip_all() is"
@@ -412,7 +479,13 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
412
479
  csvpath.is_valid = False
413
480
  try:
414
481
  self.results_manager.add_named_result(result)
415
- self._load_csvpath(csvpath, path=path, file=file, pathsname=pathsname)
482
+ self._load_csvpath(
483
+ csvpath=csvpath,
484
+ path=path,
485
+ file=file,
486
+ pathsname=pathsname,
487
+ filename=filename,
488
+ )
416
489
  for line in csvpath.next():
417
490
  line.append(result)
418
491
  if collect:
@@ -430,6 +503,11 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
430
503
  self.results_manager.save(result)
431
504
  raise e
432
505
  self.results_manager.save(result)
506
+ results.append(result)
507
+ rr = ResultsRegistrar(
508
+ csvpaths=self, run_dir=crt, pathsname=pathsname, results=results
509
+ )
510
+ rr.write_manifest()
433
511
  self.clear_run_coordination()
434
512
 
435
513
  # =============== breadth first processing ================
@@ -505,10 +583,13 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
505
583
  raise InputException(
506
584
  f"Pathsname '{pathsname}' must name a list of csvpaths"
507
585
  )
586
+
508
587
  csvpath_objects = self._load_csvpath_objects(
509
588
  paths=paths,
510
589
  named_file=fn,
511
590
  collect_when_not_matched=collect_when_not_matched,
591
+ filename=filename,
592
+ pathsname=pathsname,
512
593
  )
513
594
  self._prep_csvpath_results(
514
595
  csvpath_objects=csvpath_objects, filename=filename, pathsname=pathsname
@@ -639,21 +720,42 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
639
720
  yield line
640
721
  if sum(stopped_count) == len(csvpath_objects):
641
722
  break
723
+ results = []
642
724
  for r in csvpath_objects:
643
725
  result = r[1]
726
+ results.append(result)
644
727
  result.unmatched = r[0].unmatched
645
728
  self.results_manager.save(result)
729
+ rr = ResultsRegistrar(
730
+ csvpaths=self,
731
+ run_dir=results[0].run_dir,
732
+ pathsname=pathsname,
733
+ results=results,
734
+ )
735
+ rr.write_manifest()
646
736
  self.clear_run_coordination()
647
737
 
648
738
  def _load_csvpath_objects(
649
- self, *, paths: List[str], named_file: str, collect_when_not_matched=False
739
+ self,
740
+ *,
741
+ paths: List[str],
742
+ named_file: str,
743
+ collect_when_not_matched=False,
744
+ filename,
745
+ pathsname,
650
746
  ):
651
747
  csvpath_objects = []
652
748
  for path in paths:
653
749
  csvpath = self.csvpath()
654
750
  csvpath.collect_when_not_matched = collect_when_not_matched
655
751
  try:
656
- self._load_csvpath(csvpath, path=path, file=named_file)
752
+ self._load_csvpath(
753
+ csvpath=csvpath,
754
+ path=path,
755
+ file=named_file,
756
+ filename=filename,
757
+ pathsname=pathsname,
758
+ )
657
759
  if csvpath.data_from_preceding is True:
658
760
  self.logger.warning(
659
761
  "Csvpath identified as {csvpath.identity} is set to use preceding data, but CsvPaths's by_line methods do not permit that"
@@ -671,7 +773,7 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
671
773
  return csvpath_objects
672
774
 
673
775
  def _prep_csvpath_results(self, *, csvpath_objects, filename, pathsname):
674
- crt = self.results_manager.get_run_time_str(pathsname, self.current_run_time)
776
+ crt = self.run_time_str(pathsname)
675
777
  for i, csvpath in enumerate(csvpath_objects):
676
778
  try:
677
779
  #
@@ -13,7 +13,7 @@ from ..util.error import ErrorHandler
13
13
  from ..util.cache import Cache
14
14
  from ..util.file_readers import DataFileReader
15
15
  from ..util.reference_parser import ReferenceParser
16
- from ..util.exceptions import InputException
16
+ from ..util.exceptions import InputException, FileException
17
17
  from .file_registrar import FileRegistrar
18
18
 
19
19
 
@@ -218,6 +218,18 @@ class FileManager(CsvPathsFileManager): # pylint: disable=C0115
218
218
  path, filetype=filetype, delimiter=delimiter, quotechar=quotechar
219
219
  )
220
220
 
221
+ def get_fingerprint_for_name(self, name) -> str:
222
+ if name.startswith("$"):
223
+ # atm, we don't give fingerprints for references doing rewind/replay
224
+ return ""
225
+ mpath = self.registrar.manifest_path(name)
226
+ man = self.registrar.get_manifest(mpath)
227
+ if man is None or len(man) == 0:
228
+ raise FileException(
229
+ f"No fingerprint available for named-file name: {name} at manifest path: {mpath}: manifest: {man}"
230
+ )
231
+ return man[len(man) - 1]["fingerprint"]
232
+
221
233
  def _name_from_name_part(self, name):
222
234
  i = name.rfind(".")
223
235
  if i == -1:
@@ -119,7 +119,7 @@ class FileRegistrar:
119
119
  jdata = self.get_manifest(manifestpath)
120
120
  jdata.append(mdata)
121
121
  with open(manifestpath, "w", encoding="utf-8") as file:
122
- json.dump(jdata, file)
122
+ json.dump(jdata, file, indent=2)
123
123
 
124
124
  def register_named_file(self, *, name: str, path: str) -> None:
125
125
  # does the source file exist?
@@ -69,6 +69,14 @@ class CsvLineSpooler(LineSpooler):
69
69
  self.writer = csv.writer(self.sink)
70
70
 
71
71
  def next(self):
72
+ if self.path is None:
73
+ self._instance_data_file_path()
74
+ if os.path.exists(self.path) is False:
75
+ self.result.csvpath.logger.debug(
76
+ "There is no data.csv at %s. This may or may not be a problem.",
77
+ self.path,
78
+ )
79
+ return
72
80
  for line in DataFileReader(
73
81
  self.path,
74
82
  filetype="csv",
@@ -99,7 +99,7 @@ class PathsRegistrar:
99
99
  mdata["time"] = f"{datetime.now()}"
100
100
  jdata.append(mdata)
101
101
  with open(manifestpath, "w", encoding="utf-8") as file:
102
- json.dump(jdata, file)
102
+ json.dump(jdata, file, indent=2)
103
103
 
104
104
  def assure_manifest(self, name: str) -> None:
105
105
  nhome = self.named_paths_home(name)
@@ -9,6 +9,7 @@ from ..util.printer import Printer
9
9
  from .. import CsvPath
10
10
  from .result_serializer import ResultSerializer
11
11
  from .line_spooler import LineSpooler, CsvLineSpooler
12
+ from ..util.exceptions import CsvPathsException
12
13
 
13
14
 
14
15
  class Result(ErrorCollector, Printer): # pylint: disable=R0902
@@ -48,6 +49,21 @@ class Result(ErrorCollector, Printer): # pylint: disable=R0902
48
49
  self._run_dir = run_dir
49
50
  self._unmatched = None
50
51
  self._data_file_path = None
52
+ if (
53
+ csvpath.metadata is None
54
+ or csvpath.identity is None
55
+ or csvpath.identity == ""
56
+ ):
57
+ if csvpath.metadata is None:
58
+ raise CsvPathsException(
59
+ "Metadata cannot be None. Check order of operations."
60
+ )
61
+ #
62
+ # "NAME" is the least favored identifier. if we parse metadata after setting this
63
+ # identity and the csvpath uses any of the other five identifiers it will take
64
+ # precedence over this index. if the csvpath uses NAME it will overwrite.
65
+ #
66
+ csvpath.metadata["NAME"] = self.run_index
51
67
 
52
68
  @property
53
69
  def run_time(self) -> datetime:
@@ -139,14 +155,19 @@ class Result(ErrorCollector, Printer): # pylint: disable=R0902
139
155
  self._lines = ls
140
156
 
141
157
  def append(self, line: List[Any]) -> None:
142
- if self._lines is None:
143
- self._lines = []
144
- self._lines.append(line)
158
+ self.lines.append(line)
159
+ # orig
160
+ # if self._lines is None:
161
+ # self._lines = []
162
+ # self._lines.append(line)
145
163
 
146
164
  def __len__(self) -> int:
147
- if self._lines is None:
148
- self._lines = [] # pragma: no cover
149
- return len(self._lines)
165
+ if isinstance(self.lines, list):
166
+ return len(self._lines)
167
+ i = 0
168
+ for _ in self.lines.next():
169
+ i += 1
170
+ return i
150
171
 
151
172
  @property
152
173
  def unmatched(self) -> list[list[Any]]:
@@ -183,8 +204,7 @@ class Result(ErrorCollector, Printer): # pylint: disable=R0902
183
204
  def collect_error(self, error: Error) -> None: # pylint: disable=C0116
184
205
  self._errors.append(error)
185
206
 
186
- @property
187
- def has_errors(self) -> bool: # pylint: disable=C0116
207
+ def has_errors(self) -> bool:
188
208
  return self.errors_count > 0
189
209
 
190
210
  @property