csvpath 0.0.473__tar.gz → 0.0.475__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 (206) hide show
  1. {csvpath-0.0.473 → csvpath-0.0.475}/PKG-INFO +1 -2
  2. {csvpath-0.0.473 → csvpath-0.0.475}/config/config.ini +4 -0
  3. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/csvpath.py +1 -1
  4. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/csvpaths.py +1 -1
  5. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/function_factory.py +11 -14
  6. csvpath-0.0.475/csvpath/matching/functions/function_finder.py +55 -0
  7. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/util/config.py +107 -35
  8. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/implementing_functions.md +11 -2
  9. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions.md +14 -1
  10. {csvpath-0.0.473 → csvpath-0.0.475}/pyproject.toml +1 -2
  11. csvpath-0.0.473/csvpath/matching/functions/stats/correlate.py +0 -41
  12. {csvpath-0.0.473 → csvpath-0.0.475}/LICENSE +0 -0
  13. {csvpath-0.0.473 → csvpath-0.0.475}/README.md +0 -0
  14. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/__init__.py +0 -0
  15. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/managers/__init__.py +0 -0
  16. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/managers/csvpaths_manager.py +0 -0
  17. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/managers/file_manager.py +0 -0
  18. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/managers/result.py +0 -0
  19. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/managers/results_manager.py +0 -0
  20. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/__init__.py +0 -0
  21. {csvpath-0.0.473/csvpath/scanning → csvpath-0.0.475/csvpath/matching/functions}/__init__.py +0 -0
  22. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/boolean/all.py +0 -0
  23. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/boolean/andf.py +0 -0
  24. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/boolean/any.py +0 -0
  25. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/boolean/between.py +0 -0
  26. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/boolean/empty.py +0 -0
  27. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/boolean/exists.py +0 -0
  28. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/boolean/inf.py +0 -0
  29. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/boolean/no.py +0 -0
  30. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/boolean/notf.py +0 -0
  31. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/boolean/orf.py +0 -0
  32. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/boolean/yes.py +0 -0
  33. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/counting/count.py +0 -0
  34. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/counting/count_headers.py +0 -0
  35. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/counting/count_lines.py +0 -0
  36. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/counting/count_scans.py +0 -0
  37. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/counting/counter.py +0 -0
  38. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/counting/every.py +0 -0
  39. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/counting/has_matches.py +0 -0
  40. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/counting/increment.py +0 -0
  41. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/counting/tally.py +0 -0
  42. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/counting/total_lines.py +0 -0
  43. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/dates/datef.py +0 -0
  44. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/dates/now.py +0 -0
  45. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/function.py +0 -0
  46. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/function_focus.py +0 -0
  47. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/headers/collect.py +0 -0
  48. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/headers/empty_stack.py +0 -0
  49. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/headers/end.py +0 -0
  50. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/headers/header_name.py +0 -0
  51. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/headers/header_names_mismatch.py +0 -0
  52. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/headers/headers.py +0 -0
  53. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/headers/mismatch.py +0 -0
  54. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/headers/replace.py +0 -0
  55. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/headers/reset_headers.py +0 -0
  56. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/lines/advance.py +0 -0
  57. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/lines/after_blank.py +0 -0
  58. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/lines/dups.py +0 -0
  59. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/lines/first.py +0 -0
  60. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/lines/first_line.py +0 -0
  61. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/lines/last.py +0 -0
  62. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/lines/stop.py +0 -0
  63. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/math/above.py +0 -0
  64. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/math/add.py +0 -0
  65. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/math/divide.py +0 -0
  66. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/math/equals.py +0 -0
  67. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/math/mod.py +0 -0
  68. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/math/multiply.py +0 -0
  69. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/math/round.py +0 -0
  70. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/math/subtract.py +0 -0
  71. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/math/sum.py +0 -0
  72. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/misc/importf.py +0 -0
  73. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/misc/intf.py +0 -0
  74. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/misc/nonef.py +0 -0
  75. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/misc/random.py +0 -0
  76. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/print/jinjaf.py +0 -0
  77. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/print/print_line.py +0 -0
  78. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/print/print_queue.py +0 -0
  79. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/print/printf.py +0 -0
  80. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/print/table.py +0 -0
  81. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/stats/minf.py +0 -0
  82. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/stats/percent.py +0 -0
  83. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/stats/percent_unique.py +0 -0
  84. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/stats/stdev.py +0 -0
  85. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/strings/concat.py +0 -0
  86. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/strings/length.py +0 -0
  87. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/strings/lower.py +0 -0
  88. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/strings/metaphone.py +0 -0
  89. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/strings/num.py +0 -0
  90. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/strings/regex.py +0 -0
  91. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/strings/starts_with.py +0 -0
  92. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/strings/strip.py +0 -0
  93. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/strings/substring.py +0 -0
  94. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/strings/upper.py +0 -0
  95. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/testing/debug.py +0 -0
  96. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/validation.py +0 -0
  97. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/validity/fail.py +0 -0
  98. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/validity/failed.py +0 -0
  99. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/variables/get.py +0 -0
  100. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/variables/pushpop.py +0 -0
  101. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/variables/put.py +0 -0
  102. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/variables/track.py +0 -0
  103. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/functions/variables/variables.py +0 -0
  104. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/lark_parser.py +0 -0
  105. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/lark_transformer.py +0 -0
  106. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/matcher.py +0 -0
  107. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/productions/__init__.py +0 -0
  108. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/productions/equality.py +0 -0
  109. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/productions/expression.py +0 -0
  110. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/productions/header.py +0 -0
  111. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/productions/matchable.py +0 -0
  112. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/productions/qualified.py +0 -0
  113. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/productions/reference.py +0 -0
  114. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/productions/term.py +0 -0
  115. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/productions/variable.py +0 -0
  116. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/util/exceptions.py +0 -0
  117. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/util/expression_encoder.py +0 -0
  118. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/util/expression_utility.py +0 -0
  119. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/util/lark_print_parser.py +0 -0
  120. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/matching/util/print_parser.py +0 -0
  121. {csvpath-0.0.473/csvpath/matching/functions → csvpath-0.0.475/csvpath/scanning}/__init__.py +0 -0
  122. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/scanning/exceptions.py +0 -0
  123. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/scanning/parser.out +0 -0
  124. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/scanning/parsetab.py +0 -0
  125. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/scanning/scanner.py +0 -0
  126. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/scanning/scanning_lexer.py +0 -0
  127. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/util/cache.py +0 -0
  128. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/util/config_exception.py +0 -0
  129. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/util/error.py +0 -0
  130. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/util/exceptions.py +0 -0
  131. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/util/last_line_stats.py +0 -0
  132. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/util/line_counter.py +0 -0
  133. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/util/line_monitor.py +0 -0
  134. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/util/log_utility.py +0 -0
  135. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/util/metadata_parser.py +0 -0
  136. {csvpath-0.0.473 → csvpath-0.0.475}/csvpath/util/printer.py +0 -0
  137. {csvpath-0.0.473 → csvpath-0.0.475}/docs/asbool.md +0 -0
  138. {csvpath-0.0.473 → csvpath-0.0.475}/docs/assignment.md +0 -0
  139. {csvpath-0.0.473 → csvpath-0.0.475}/docs/config.md +0 -0
  140. {csvpath-0.0.473 → csvpath-0.0.475}/docs/examples.md +0 -0
  141. {csvpath-0.0.473 → csvpath-0.0.475}/docs/files.md +0 -0
  142. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/above.md +0 -0
  143. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/advance.md +0 -0
  144. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/after_blank.md +0 -0
  145. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/all.md +0 -0
  146. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/andor.md +0 -0
  147. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/any.md +0 -0
  148. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/average.md +0 -0
  149. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/between.md +0 -0
  150. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/collect.md +0 -0
  151. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/correlate.md +0 -0
  152. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/count.md +0 -0
  153. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/count_headers.md +0 -0
  154. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/counter.md +0 -0
  155. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/date.md +0 -0
  156. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/empty.md +0 -0
  157. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/empty_stack.md +0 -0
  158. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/end.md +0 -0
  159. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/every.md +0 -0
  160. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/fail.md +0 -0
  161. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/first.md +0 -0
  162. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/get.md +0 -0
  163. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/has_dups.md +0 -0
  164. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/has_matches.md +0 -0
  165. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/header.md +0 -0
  166. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/header_name.md +0 -0
  167. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/header_names_mismatch.md +0 -0
  168. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/import.md +0 -0
  169. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/in.md +0 -0
  170. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/increment.md +0 -0
  171. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/jinja.md +0 -0
  172. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/last.md +0 -0
  173. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/line_number.md +0 -0
  174. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/max.md +0 -0
  175. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/metaphone.md +0 -0
  176. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/mismatch.md +0 -0
  177. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/no.md +0 -0
  178. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/not.md +0 -0
  179. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/now.md +0 -0
  180. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/percent_unique.md +0 -0
  181. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/pop.md +0 -0
  182. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/print.md +0 -0
  183. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/print_line.md +0 -0
  184. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/print_queue.md +0 -0
  185. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/regex.md +0 -0
  186. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/replace.md +0 -0
  187. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/reset_headers.md +0 -0
  188. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/stdev.md +0 -0
  189. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/stop.md +0 -0
  190. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/string_functions.md +0 -0
  191. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/subtract.md +0 -0
  192. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/sum.md +0 -0
  193. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/tally.md +0 -0
  194. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/total_lines.md +0 -0
  195. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/track.md +0 -0
  196. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/variables.md +0 -0
  197. {csvpath-0.0.473 → csvpath-0.0.475}/docs/functions/variables_and_headers.md +0 -0
  198. {csvpath-0.0.473 → csvpath-0.0.475}/docs/grammar.md +0 -0
  199. {csvpath-0.0.473 → csvpath-0.0.475}/docs/headers.md +0 -0
  200. {csvpath-0.0.473 → csvpath-0.0.475}/docs/images/logo-wordmark-white-on-black-trimmed-padded.png +0 -0
  201. {csvpath-0.0.473 → csvpath-0.0.475}/docs/images/logo-wordmark-white-trimmed.png +0 -0
  202. {csvpath-0.0.473 → csvpath-0.0.475}/docs/paths.md +0 -0
  203. {csvpath-0.0.473 → csvpath-0.0.475}/docs/qualifiers.md +0 -0
  204. {csvpath-0.0.473 → csvpath-0.0.475}/docs/references.md +0 -0
  205. {csvpath-0.0.473 → csvpath-0.0.475}/docs/terms.md +0 -0
  206. {csvpath-0.0.473 → csvpath-0.0.475}/docs/variables.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: csvpath
3
- Version: 0.0.473
3
+ Version: 0.0.475
4
4
  Summary: A declarative language for data extraction and validation of CSV files
5
5
  Author: David Kershaw
6
6
  Author-email: dk107dk@hotmail.com
@@ -22,7 +22,6 @@ Requires-Dist: inflect (>=7.3.1,<8.0.0)
22
22
  Requires-Dist: jinja2 (>=3.1.4,<4.0.0)
23
23
  Requires-Dist: lark (>=1.2.2,<2.0.0)
24
24
  Requires-Dist: metaphone (>=0.6,<0.7)
25
- Requires-Dist: pandas (>=2.2.2,<3.0.0)
26
25
  Requires-Dist: ply (>=3.11,<4.0)
27
26
  Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
28
27
  Requires-Dist: tabulate (>=0.9.0,<0.10.0)
@@ -20,3 +20,7 @@ path = config/config.ini
20
20
 
21
21
  [cache]
22
22
  path = cache
23
+
24
+ [functions]
25
+ imports = config/functions.imports
26
+
@@ -318,7 +318,7 @@ class CsvPath(CsvPathPublic, ErrorCollector): # pylint: disable=R0902, R0904
318
318
  @property
319
319
  def config(self) -> Config: # pylint: disable=C0116
320
320
  if not self._config:
321
- self._config = Config(self)
321
+ self._config = Config()
322
322
  return self._config
323
323
 
324
324
  def has_errors(self) -> bool: # pylint: disable=C0116
@@ -132,7 +132,7 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator):
132
132
  self.quotechar = quotechar
133
133
  self.skip_blank_lines = skip_blank_lines
134
134
  self.current_matcher: CsvPath = None
135
- self._config = Config(self)
135
+ self._config = Config()
136
136
  self.logger = LogUtility.logger(self)
137
137
  self.logger.info("initialized CsvPaths")
138
138
  self._errors = []
@@ -1,6 +1,7 @@
1
1
  # pylint: disable=C0114
2
2
  from csvpath.matching.productions.expression import Matchable
3
3
  from .function import Function
4
+ from .function_finder import FunctionFinder
4
5
  from .dates.now import Now
5
6
  from .dates.datef import Date
6
7
  from .strings.lower import Lower
@@ -56,7 +57,8 @@ from .stats.percent import Percent
56
57
  from .stats.minf import Min, Max, Average
57
58
  from .stats.percent_unique import PercentUnique
58
59
  from .stats.stdev import Stdev
59
- from .stats.correlate import Correlate
60
+
61
+ # from .stats.correlate import Correlate
60
62
  from .print.printf import Print
61
63
  from .print.table import HeaderTable, RowTable, VarTable, RunTable
62
64
  from .print.print_line import PrintLine
@@ -260,8 +262,8 @@ class FunctionFactory:
260
262
  f = Strip(matcher, name, child)
261
263
  elif name == "jinja":
262
264
  f = Jinjaf(matcher, name, child)
263
- elif name == "correlate":
264
- f = Correlate(matcher, name, child)
265
+ # elif name == "correlate":
266
+ # f = Correlate(matcher, name, child)
265
267
  elif name in ["count_headers", "count_headers_in_line"]:
266
268
  f = CountHeaders(matcher, name, child)
267
269
  elif name == "percent_unique":
@@ -292,9 +294,6 @@ class FunctionFactory:
292
294
  f = Stack(matcher, name, child)
293
295
  elif name in ["stdev", "pstdev"]:
294
296
  f = Stdev(matcher, name, child)
295
- #
296
- # dup_lines can also decide matches
297
- #
298
297
  elif name == "has_dups":
299
298
  f = HasDups(matcher, name, child)
300
299
  elif name == "count_dups":
@@ -373,15 +372,13 @@ class FunctionFactory:
373
372
  f = Num(matcher, name, child)
374
373
  elif name == "counter":
375
374
  f = Counter(matcher, name, child)
376
-
377
375
  else:
378
- if (
379
- f is None
380
- and find_external_functions
381
- and name in FunctionFactory.NOT_MY_FUNCTION
382
- ):
383
- f = cls.NOT_MY_FUNCTION[name]
384
- f = f(matcher, name, child)
376
+ if f is None and find_external_functions:
377
+ if FunctionFinder.EXTERNALS not in FunctionFactory.NOT_MY_FUNCTION:
378
+ FunctionFinder().load(matcher, cls)
379
+ if name in FunctionFactory.NOT_MY_FUNCTION:
380
+ f = cls.NOT_MY_FUNCTION[name]
381
+ f = f(matcher, name, child)
385
382
  if not find_external_functions:
386
383
  return None
387
384
  if f is None:
@@ -0,0 +1,55 @@
1
+ # pylint: disable=C0114
2
+ import os
3
+ import importlib
4
+ from csvpath.util.config_exception import ConfigurationException
5
+ from .boolean.yes import Yes
6
+
7
+
8
+ class FunctionFinder:
9
+ EXTERNALS = "externalfunctionsloaded"
10
+
11
+ @classmethod
12
+ def load(cls, matcher, func_fact) -> None:
13
+ # any problems loading will bubble up to the nearest
14
+ # expression and be handled there.
15
+ config = matcher.csvpath.config
16
+ # find the list
17
+ path = config.function_imports
18
+ # read the list
19
+ if path is None:
20
+ matcher.csvpath.logger.error("No [functions][imports] in config.ini")
21
+ return
22
+ if not os.path.exists(path):
23
+ matcher.csvpath.logger.error(
24
+ f"[functions][imports] path in {config.configpath} does not exist"
25
+ )
26
+ return
27
+ with open(path, "r") as file:
28
+ i = 0
29
+ for line in file:
30
+ i += 1
31
+ cls._add_function(matcher, func_fact, line)
32
+ matcher.csvpath.logger.info("Added %s external functions", i)
33
+ # add a sentinel to keep us from attempting reload.
34
+ # this instance will never be found, but the dict will
35
+ # never be empty
36
+ func_fact.add_function(cls.EXTERNALS, Yes(None, cls.EXTERNALS))
37
+
38
+ @classmethod
39
+ def _add_function(cls, matcher, func_fact, s: str) -> None:
40
+ s = s.strip()
41
+ if s != "":
42
+ instance = None
43
+ # instantiate the classes
44
+ # function_name module classname
45
+ cs = s.split(" ")
46
+ if len(cs) == 6 and cs[0] == "from" and cs[2] == "import" and cs[4] == "as":
47
+ module = importlib.import_module(cs[1])
48
+ class_ = getattr(module, cs[3])
49
+ instance = class_(matcher, cs[5])
50
+ # load to FunctionFactory.add
51
+ func_fact.add_function(cs[5], instance)
52
+ else:
53
+ raise ConfigurationException(
54
+ "Unclear external function import setup: {s}"
55
+ )
@@ -42,6 +42,8 @@ class Sections(Enum):
42
42
  CSV_FILES = "csv_files"
43
43
  ERRORS = "errors"
44
44
  LOGGING = "logging"
45
+ FUNCTIONS = "functions"
46
+ CACHE = "cache"
45
47
 
46
48
 
47
49
  class Config:
@@ -50,22 +52,45 @@ class Config:
50
52
  - set a CSVPATH_CONFIG_FILE env var
51
53
  - create a Config instance set its CONFIG member and call reload
52
54
  - or set Config.CONFIG and reload to reset all instances w/o own specific settings
55
+ Also, you can pass Config(load=False) to give you the opportunity to set some/all
56
+ properties programmatically.
53
57
  """
54
58
 
55
59
  CONFIG: str = "config/config.ini"
56
60
  CSVPATH_CONFIG_FILE_ENV: str = "CSVPATH_CONFIG_PATH"
57
61
 
58
- def __init__(self, holder):
59
- self._holder = holder
62
+ def __init__(self, *, load=True):
63
+ self.load = load
64
+ self._cache_dir_path = None
65
+ self._function_imports = None
66
+ self._csvpath_file_extensions = None
67
+ self._csv_file_extensions = None
68
+ self._csvpath_errors_policy = None
69
+ self._csvpaths_errors_policy = None
70
+ self._csvpath_log_level = None
71
+ self._csvpaths_log_level = None
72
+ self._log_file = None
73
+ self._log_files_to_keep = None
74
+ self._log_file_size = None
60
75
  self._config = RawConfigParser()
61
76
  self.log_file_handler = None
62
77
  self._configpath = environ.get(Config.CSVPATH_CONFIG_FILE_ENV)
63
78
  if self._configpath is None:
64
79
  self._configpath = Config.CONFIG
65
- self._load_config()
80
+ if self.load:
81
+ self._load_config()
82
+
83
+ @property
84
+ def load(self) -> bool:
85
+ return self._load
86
+
87
+ @load.setter
88
+ def load(self, l:bool) -> None:
89
+ self._load = l
66
90
 
67
91
  def reload(self):
68
92
  self._config = RawConfigParser()
93
+ self._load = True
69
94
  self._load_config()
70
95
 
71
96
  def set_config_path_and_reload(self, path: str) -> None:
@@ -94,10 +119,19 @@ class Config:
94
119
  )
95
120
 
96
121
  def _create_default_config(self) -> None:
97
- if not path.exists("config"):
98
- os.makedirs("config")
99
- with open(Config.CONFIG, "w") as file:
100
- c = """
122
+ directory = ""
123
+ file = ""
124
+ if self._configpath is None or self._configpath.strip() == "":
125
+ raise ConfiguationException("Config path cannot be None")
126
+ if self._configpath.find(os.sep) > 0:
127
+ s = self._configpath.rfind(os.sep)
128
+ directory = self._configpath[0:s]
129
+ name = self._configpath[s+1:]
130
+ if directory != "":
131
+ if not path.exists(directory):
132
+ os.makedirs(directory)
133
+ with open(self._configpath, "w") as file:
134
+ c = """
101
135
  [csvpath_files]
102
136
  extensions = txt, csvpath, csvpaths
103
137
  [csv_files]
@@ -113,20 +147,25 @@ log_files_to_keep = 100
113
147
  log_file_size = 52428800
114
148
  [config]
115
149
  path =
116
- """
117
- file.write(c)
118
- print(f"Creating a default config file at {Config.CONFIG}.")
150
+ [functions]
151
+ imports =
152
+ [cache]
153
+ path =
154
+ """
155
+ file.write(c)
156
+ print(f"Created a default config file at {directory} with name {name}.")
119
157
  print("If you want your config to be somewhere else remember to")
120
158
  print("update the path in the default config.ini")
121
159
 
122
160
  def _assure_logs_path(self) -> None:
123
- filepath = self.log_file
124
- if not filepath:
125
- filepath = "logs/csvpath.log"
126
- self.log_file = filepath
127
- dirpath = self._get_dir_path(filepath)
128
- if dirpath and not path.exists(dirpath):
129
- os.makedirs(dirpath)
161
+ if self.load:
162
+ filepath = self.log_file
163
+ if not filepath or filepath.strip() == "":
164
+ filepath = "logs/csvpath.log"
165
+ self.log_file = filepath
166
+ dirpath = self._get_dir_path(filepath)
167
+ if dirpath and not path.exists(dirpath):
168
+ os.makedirs(dirpath)
130
169
 
131
170
  def _get_dir_path(self, filepath):
132
171
  if filepath.find(os.sep) > -1:
@@ -135,20 +174,23 @@ path =
135
174
  return None
136
175
 
137
176
  def _assure_cache_path(self) -> None:
138
- dirpath = self.cache_dir_path
139
- if dirpath and not path.exists(dirpath):
140
- os.makedirs(dirpath)
141
- elif not dirpath:
142
- raise ConfigurationException(
143
- "No cache path available. Check config.ini [cache][path]."
144
- )
177
+ if self.load:
178
+ if self.cache_dir_path is None or self.cache_dir_path.strip() == "":
179
+ self.cache_dir_path = "cache"
180
+ if not path.exists(self.cache_dir_path):
181
+ os.makedirs(self.cache_dir_path)
145
182
 
146
183
  def _assure_config_file_path(self) -> None:
147
- if not self._configpath or not os.path.isfile(self._configpath):
148
- self._configpath = Config.CONFIG
149
- self._create_default_config()
184
+ if self.load:
185
+ if not self._configpath or self._configpath.strip() == "":
186
+ self._configpath = Config.CONFIG
187
+ if not os.path.isfile(self._configpath):
188
+ self._create_default_config()
150
189
 
151
190
  def _load_config(self, norecurse=False):
191
+ if self._load is False:
192
+ print("WARNING: _load_config called on a config instance that is set to not load")
193
+ return
152
194
  self._assure_config_file_path()
153
195
  #
154
196
  #
@@ -172,6 +214,23 @@ path =
172
214
  self.log_file_size = self._get(
173
215
  Sections.LOGGING.value, LogFile.LOG_FILE_SIZE.value
174
216
  )
217
+ # path to external functions list. external functions are very optional.
218
+ # not blowing up when absent seems reasonable.
219
+ try:
220
+ self.function_imports = self._get(Sections.FUNCTIONS.value, "imports")
221
+ print(f"config fuc im: {self.function_imports}")
222
+ except Exception:
223
+ print("WARNING: config cannot load [functions][imports] from {self.configpath}")
224
+ pass
225
+ # likewise caching.
226
+ try:
227
+ self.cache_dir_path = self._get(Sections.CACHE.value, "path")
228
+ except Exception:
229
+ print("WARNING: config cannot load [cache][path] from {self.configpath}")
230
+ pass
231
+ #
232
+ # reload if another config path is set
233
+ #
175
234
  path = self._get("config", "path")
176
235
  if path:
177
236
  path = path.strip().lower()
@@ -262,16 +321,29 @@ path =
262
321
 
263
322
  # ======================================
264
323
 
324
+ @property
325
+ def configpath(self) -> str:
326
+ return self._configpath
327
+
328
+ @configpath.setter
329
+ def configpath(self, path: str) -> None:
330
+ self._configpath = path
331
+
265
332
  @property
266
333
  def cache_dir_path(self) -> str:
267
- try:
268
- path = self._get("cache", "path")
269
- except Exception:
270
- print("No cache path in config.ini at [cache][path]. Using 'cache'.")
271
- path = "config"
272
- self._config.add_section("cache")
273
- self._config.set("cache", "path", path)
274
- return path
334
+ return self._cache_dir_path
335
+
336
+ @cache_dir_path.setter
337
+ def cache_dir_path(self, p) -> None:
338
+ self._cache_dir_path = p
339
+
340
+ @property
341
+ def function_imports(self) -> str:
342
+ return self._function_imports
343
+
344
+ @function_imports.setter
345
+ def function_imports(self, path: str) -> None:
346
+ self._function_imports = path
275
347
 
276
348
  @property
277
349
  def csvpath_file_extensions(self) -> list[str]:
@@ -80,17 +80,26 @@ When your function needs its arguments you can call:
80
80
  - self._value_two(skip=skip)
81
81
  - self._siblings()
82
82
 
83
- When you need to get a value or a match from a child object you use `to_value()` or `matches()`. Remember to pass the skip list as a named argument "skip".
83
+ When you need to get a value or a match from a child object you use `to_value()` or `matches()`. Remember to pass the skip list as the named argument `skip`.
84
84
 
85
85
  ## Registering
86
86
 
87
- To register your function for use, add it to the FunctionFactory like this:
87
+ To register your function for use, add it to the `FunctionFactory` like this:
88
88
 
89
89
  ```python
90
90
  from csvpath.matching.functions.function_factory import FunctionFactory
91
91
  FunctionFactory.add_function(name='iamafunction', function=my_function_instance)
92
92
  ```
93
93
 
94
+ Alternatively, add a file path to your `config.ini` file under the key `[functions][imports]` that points to a list of functions to register. The key is like:
95
+
96
+ [functions]
97
+ imports = my_imports/functions.txt
98
+
99
+ In the file list every function on its own line using a format like that of Python imports:
100
+
101
+ from a.b.c.my_function import MyFunction as iamafunction
102
+
94
103
  To use your function do something like:
95
104
 
96
105
  ```bash
@@ -41,7 +41,20 @@ Some functions will optionally make use of an arbitrary name qualifier to better
41
41
 
42
42
  ## Custom Functions
43
43
 
44
- Creating your own function is easy. Once you create a function, you register it with the `FunctionFactory` class. You must register your functions each time you run CsvPath. Use your function in csvpaths by simply referring to it by name like any other function.
44
+ Creating your own function is easy. Once you create a function, you register it with the `FunctionFactory` class. You can register your functions either programmatically or by creating an import file listing your functions. Your import file must be referenced in your `config.ini` file at `[functions][imports]` like this:
45
+
46
+ [functions]
47
+ imports = my_project_assets/my_functions.imports
48
+
49
+ Each custom function has its own line in your imports file. The format is the same as you use for importing classes into Python files -- under the hood the mechanism is similar. E.g.
50
+
51
+ ```python
52
+ from my_function.for_stuff.me import Me as function_me
53
+ ```
54
+
55
+ In this example your class is `Me` and the name of the function you use in your csvpath is `function_me()`
56
+
57
+ Use your functions in csvpaths by simply referring to them by name like you would any built-in function.
45
58
 
46
59
  <a href='https://github.com/dk107dk/csvpath/blob/main/docs/functions/implementing_functions.md'>Read more about implementing your own functions here.</a>
47
60
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "csvpath"
3
- version = "0.0.473"
3
+ version = "0.0.475"
4
4
  description = "A declarative language for data extraction and validation of CSV files"
5
5
  authors = ["David Kershaw <dk107dk@hotmail.com>"]
6
6
  readme = "README.md"
@@ -27,7 +27,6 @@ include = ["config", "logs", "docs"]
27
27
  python = "^3.12"
28
28
  ply = "^3.11"
29
29
  python-dateutil = "^2.9.0.post0"
30
- pandas = "^2.2.2"
31
30
  jinja2 = "^3.1.4"
32
31
  inflect = "^7.3.1"
33
32
  lark = "^1.2.2"
@@ -1,41 +0,0 @@
1
- # pylint: disable=C0114
2
- import pandas as pd
3
- from ..function_focus import ValueProducer
4
-
5
-
6
- class Correlate(ValueProducer):
7
- """does a statistical correlation test on the values of two headers"""
8
-
9
- def check_valid(self) -> None:
10
- self.validate_two_args()
11
- super().check_valid()
12
-
13
- def _produce_value(self, skip=None) -> None:
14
- child = self.children[0]
15
- left = child.left
16
- right = child.right
17
- leftlist = left.to_value(skip=skip)
18
- rightlist = right.to_value(skip=skip)
19
- leftlist, rightlist = self._trim(leftlist, rightlist)
20
- ll = pd.Series(leftlist)
21
- rl = pd.Series(rightlist)
22
- corr = ll.corr(rl)
23
- f = float(corr)
24
- f = round(f, 2)
25
- self.value = f
26
-
27
- def _decide_match(self, skip=None) -> None:
28
- self.to_value(skip=skip)
29
- self.match = self._noop_match() # pragma: no cover
30
-
31
- def _trim(self, leftlist, rightlist):
32
- n = len(leftlist) if len(leftlist) < len(rightlist) else len(rightlist)
33
- ll = []
34
- rl = []
35
- for i in range(0, n):
36
- try:
37
- ll.append(float(leftlist[i]))
38
- rl.append(float(rightlist[i]))
39
- except (TypeError, ValueError):
40
- pass
41
- return ll, rl
File without changes
File without changes
File without changes