relationalai 0.13.0.dev0__py3-none-any.whl → 0.13.2__py3-none-any.whl

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 (838) hide show
  1. frontend/debugger/dist/.gitignore +2 -0
  2. frontend/debugger/dist/assets/favicon-Dy0ZgA6N.png +0 -0
  3. frontend/debugger/dist/assets/index-Cssla-O7.js +208 -0
  4. frontend/debugger/dist/assets/index-DlHsYx1V.css +9 -0
  5. frontend/debugger/dist/index.html +17 -0
  6. relationalai/__init__.py +256 -1
  7. relationalai/clients/__init__.py +18 -0
  8. relationalai/clients/client.py +947 -0
  9. relationalai/clients/config.py +673 -0
  10. relationalai/clients/direct_access_client.py +118 -0
  11. relationalai/clients/exec_txn_poller.py +91 -0
  12. relationalai/clients/hash_util.py +31 -0
  13. relationalai/clients/local.py +586 -0
  14. relationalai/clients/profile_polling.py +73 -0
  15. relationalai/clients/resources/__init__.py +8 -0
  16. relationalai/clients/resources/azure/azure.py +502 -0
  17. relationalai/clients/resources/snowflake/__init__.py +20 -0
  18. relationalai/clients/resources/snowflake/cli_resources.py +98 -0
  19. relationalai/clients/resources/snowflake/direct_access_resources.py +734 -0
  20. relationalai/clients/resources/snowflake/engine_service.py +381 -0
  21. relationalai/clients/resources/snowflake/engine_state_handlers.py +315 -0
  22. relationalai/clients/resources/snowflake/error_handlers.py +240 -0
  23. relationalai/clients/resources/snowflake/export_procedure.py.jinja +249 -0
  24. relationalai/clients/resources/snowflake/resources_factory.py +99 -0
  25. relationalai/clients/resources/snowflake/snowflake.py +3185 -0
  26. relationalai/clients/resources/snowflake/use_index_poller.py +1019 -0
  27. relationalai/clients/resources/snowflake/use_index_resources.py +188 -0
  28. relationalai/clients/resources/snowflake/util.py +387 -0
  29. relationalai/clients/result_helpers.py +420 -0
  30. relationalai/clients/types.py +118 -0
  31. relationalai/clients/util.py +356 -0
  32. relationalai/debugging.py +389 -0
  33. relationalai/dsl.py +1749 -0
  34. relationalai/early_access/builder/__init__.py +30 -0
  35. relationalai/early_access/builder/builder/__init__.py +35 -0
  36. relationalai/early_access/builder/snowflake/__init__.py +12 -0
  37. relationalai/early_access/builder/std/__init__.py +25 -0
  38. relationalai/early_access/builder/std/decimals/__init__.py +12 -0
  39. relationalai/early_access/builder/std/integers/__init__.py +12 -0
  40. relationalai/early_access/builder/std/math/__init__.py +12 -0
  41. relationalai/early_access/builder/std/strings/__init__.py +14 -0
  42. relationalai/early_access/devtools/__init__.py +12 -0
  43. relationalai/early_access/devtools/benchmark_lqp/__init__.py +12 -0
  44. relationalai/early_access/devtools/extract_lqp/__init__.py +12 -0
  45. relationalai/early_access/dsl/adapters/orm/adapter_qb.py +427 -0
  46. relationalai/early_access/dsl/adapters/orm/parser.py +636 -0
  47. relationalai/early_access/dsl/adapters/owl/adapter.py +176 -0
  48. relationalai/early_access/dsl/adapters/owl/parser.py +160 -0
  49. relationalai/early_access/dsl/bindings/common.py +402 -0
  50. relationalai/early_access/dsl/bindings/csv.py +170 -0
  51. relationalai/early_access/dsl/bindings/legacy/binding_models.py +143 -0
  52. relationalai/early_access/dsl/bindings/snowflake.py +64 -0
  53. relationalai/early_access/dsl/codegen/binder.py +411 -0
  54. relationalai/early_access/dsl/codegen/common.py +79 -0
  55. relationalai/early_access/dsl/codegen/helpers.py +23 -0
  56. relationalai/early_access/dsl/codegen/relations.py +700 -0
  57. relationalai/early_access/dsl/codegen/weaver.py +417 -0
  58. relationalai/early_access/dsl/core/builders/__init__.py +47 -0
  59. relationalai/early_access/dsl/core/builders/logic.py +19 -0
  60. relationalai/early_access/dsl/core/builders/scalar_constraint.py +11 -0
  61. relationalai/early_access/dsl/core/constraints/predicate/atomic.py +455 -0
  62. relationalai/early_access/dsl/core/constraints/predicate/universal.py +73 -0
  63. relationalai/early_access/dsl/core/constraints/scalar.py +310 -0
  64. relationalai/early_access/dsl/core/context.py +13 -0
  65. relationalai/early_access/dsl/core/cset.py +132 -0
  66. relationalai/early_access/dsl/core/exprs/__init__.py +116 -0
  67. relationalai/early_access/dsl/core/exprs/relational.py +18 -0
  68. relationalai/early_access/dsl/core/exprs/scalar.py +412 -0
  69. relationalai/early_access/dsl/core/instances.py +44 -0
  70. relationalai/early_access/dsl/core/logic/__init__.py +193 -0
  71. relationalai/early_access/dsl/core/logic/aggregation.py +98 -0
  72. relationalai/early_access/dsl/core/logic/exists.py +223 -0
  73. relationalai/early_access/dsl/core/logic/helper.py +163 -0
  74. relationalai/early_access/dsl/core/namespaces.py +32 -0
  75. relationalai/early_access/dsl/core/relations.py +276 -0
  76. relationalai/early_access/dsl/core/rules.py +112 -0
  77. relationalai/early_access/dsl/core/std/__init__.py +45 -0
  78. relationalai/early_access/dsl/core/temporal/recall.py +6 -0
  79. relationalai/early_access/dsl/core/types/__init__.py +270 -0
  80. relationalai/early_access/dsl/core/types/concepts.py +128 -0
  81. relationalai/early_access/dsl/core/types/constrained/__init__.py +267 -0
  82. relationalai/early_access/dsl/core/types/constrained/nominal.py +143 -0
  83. relationalai/early_access/dsl/core/types/constrained/subtype.py +124 -0
  84. relationalai/early_access/dsl/core/types/standard.py +92 -0
  85. relationalai/early_access/dsl/core/types/unconstrained.py +50 -0
  86. relationalai/early_access/dsl/core/types/variables.py +203 -0
  87. relationalai/early_access/dsl/ir/compiler.py +318 -0
  88. relationalai/early_access/dsl/ir/executor.py +260 -0
  89. relationalai/early_access/dsl/ontologies/constraints.py +88 -0
  90. relationalai/early_access/dsl/ontologies/export.py +30 -0
  91. relationalai/early_access/dsl/ontologies/models.py +453 -0
  92. relationalai/early_access/dsl/ontologies/python_printer.py +303 -0
  93. relationalai/early_access/dsl/ontologies/readings.py +60 -0
  94. relationalai/early_access/dsl/ontologies/relationships.py +322 -0
  95. relationalai/early_access/dsl/ontologies/roles.py +87 -0
  96. relationalai/early_access/dsl/ontologies/subtyping.py +55 -0
  97. relationalai/early_access/dsl/orm/constraints.py +438 -0
  98. relationalai/early_access/dsl/orm/measures/dimensions.py +200 -0
  99. relationalai/early_access/dsl/orm/measures/initializer.py +16 -0
  100. relationalai/early_access/dsl/orm/measures/measure_rules.py +275 -0
  101. relationalai/early_access/dsl/orm/measures/measures.py +299 -0
  102. relationalai/early_access/dsl/orm/measures/role_exprs.py +268 -0
  103. relationalai/early_access/dsl/orm/models.py +256 -0
  104. relationalai/early_access/dsl/orm/object_oriented_printer.py +344 -0
  105. relationalai/early_access/dsl/orm/printer.py +469 -0
  106. relationalai/early_access/dsl/orm/reasoners.py +480 -0
  107. relationalai/early_access/dsl/orm/relations.py +19 -0
  108. relationalai/early_access/dsl/orm/relationships.py +251 -0
  109. relationalai/early_access/dsl/orm/types.py +42 -0
  110. relationalai/early_access/dsl/orm/utils.py +79 -0
  111. relationalai/early_access/dsl/orm/verb.py +204 -0
  112. relationalai/early_access/dsl/physical_metadata/tables.py +133 -0
  113. relationalai/early_access/dsl/relations.py +170 -0
  114. relationalai/early_access/dsl/rulesets.py +69 -0
  115. relationalai/early_access/dsl/schemas/__init__.py +450 -0
  116. relationalai/early_access/dsl/schemas/builder.py +48 -0
  117. relationalai/early_access/dsl/schemas/comp_names.py +51 -0
  118. relationalai/early_access/dsl/schemas/components.py +203 -0
  119. relationalai/early_access/dsl/schemas/contexts.py +156 -0
  120. relationalai/early_access/dsl/schemas/exprs.py +89 -0
  121. relationalai/early_access/dsl/schemas/fragments.py +464 -0
  122. relationalai/early_access/dsl/serialization.py +79 -0
  123. relationalai/early_access/dsl/serialize/exporter.py +163 -0
  124. relationalai/early_access/dsl/snow/api.py +105 -0
  125. relationalai/early_access/dsl/snow/common.py +76 -0
  126. relationalai/early_access/dsl/state_mgmt/__init__.py +129 -0
  127. relationalai/early_access/dsl/state_mgmt/state_charts.py +125 -0
  128. relationalai/early_access/dsl/state_mgmt/transitions.py +130 -0
  129. relationalai/early_access/dsl/types/__init__.py +40 -0
  130. relationalai/early_access/dsl/types/concepts.py +12 -0
  131. relationalai/early_access/dsl/types/entities.py +135 -0
  132. relationalai/early_access/dsl/types/values.py +17 -0
  133. relationalai/early_access/dsl/utils.py +102 -0
  134. relationalai/early_access/graphs/__init__.py +13 -0
  135. relationalai/early_access/lqp/__init__.py +12 -0
  136. relationalai/early_access/lqp/compiler/__init__.py +12 -0
  137. relationalai/early_access/lqp/constructors/__init__.py +18 -0
  138. relationalai/early_access/lqp/executor/__init__.py +12 -0
  139. relationalai/early_access/lqp/ir/__init__.py +12 -0
  140. relationalai/early_access/lqp/passes/__init__.py +12 -0
  141. relationalai/early_access/lqp/pragmas/__init__.py +12 -0
  142. relationalai/early_access/lqp/primitives/__init__.py +12 -0
  143. relationalai/early_access/lqp/types/__init__.py +12 -0
  144. relationalai/early_access/lqp/utils/__init__.py +12 -0
  145. relationalai/early_access/lqp/validators/__init__.py +12 -0
  146. relationalai/early_access/metamodel/__init__.py +58 -0
  147. relationalai/early_access/metamodel/builtins/__init__.py +12 -0
  148. relationalai/early_access/metamodel/compiler/__init__.py +12 -0
  149. relationalai/early_access/metamodel/dependency/__init__.py +12 -0
  150. relationalai/early_access/metamodel/factory/__init__.py +17 -0
  151. relationalai/early_access/metamodel/helpers/__init__.py +12 -0
  152. relationalai/early_access/metamodel/ir/__init__.py +14 -0
  153. relationalai/early_access/metamodel/rewrite/__init__.py +7 -0
  154. relationalai/early_access/metamodel/typer/__init__.py +3 -0
  155. relationalai/early_access/metamodel/typer/typer/__init__.py +12 -0
  156. relationalai/early_access/metamodel/types/__init__.py +15 -0
  157. relationalai/early_access/metamodel/util/__init__.py +15 -0
  158. relationalai/early_access/metamodel/visitor/__init__.py +12 -0
  159. relationalai/early_access/rel/__init__.py +12 -0
  160. relationalai/early_access/rel/executor/__init__.py +12 -0
  161. relationalai/early_access/rel/rel_utils/__init__.py +12 -0
  162. relationalai/early_access/rel/rewrite/__init__.py +7 -0
  163. relationalai/early_access/solvers/__init__.py +19 -0
  164. relationalai/early_access/sql/__init__.py +11 -0
  165. relationalai/early_access/sql/executor/__init__.py +3 -0
  166. relationalai/early_access/sql/rewrite/__init__.py +3 -0
  167. relationalai/early_access/tests/logging/__init__.py +12 -0
  168. relationalai/early_access/tests/test_snapshot_base/__init__.py +12 -0
  169. relationalai/early_access/tests/utils/__init__.py +12 -0
  170. relationalai/environments/__init__.py +35 -0
  171. relationalai/environments/base.py +381 -0
  172. relationalai/environments/colab.py +14 -0
  173. relationalai/environments/generic.py +71 -0
  174. relationalai/environments/ipython.py +68 -0
  175. relationalai/environments/jupyter.py +9 -0
  176. relationalai/environments/snowbook.py +169 -0
  177. relationalai/errors.py +2496 -0
  178. relationalai/experimental/SF.py +38 -0
  179. relationalai/experimental/inspect.py +47 -0
  180. relationalai/experimental/pathfinder/__init__.py +158 -0
  181. relationalai/experimental/pathfinder/api.py +160 -0
  182. relationalai/experimental/pathfinder/automaton.py +584 -0
  183. relationalai/experimental/pathfinder/bridge.py +226 -0
  184. relationalai/experimental/pathfinder/compiler.py +416 -0
  185. relationalai/experimental/pathfinder/datalog.py +214 -0
  186. relationalai/experimental/pathfinder/diagnostics.py +56 -0
  187. relationalai/experimental/pathfinder/filter.py +236 -0
  188. relationalai/experimental/pathfinder/glushkov.py +439 -0
  189. relationalai/experimental/pathfinder/options.py +265 -0
  190. relationalai/experimental/pathfinder/pathfinder-v0.7.0.rel +1951 -0
  191. relationalai/experimental/pathfinder/rpq.py +344 -0
  192. relationalai/experimental/pathfinder/transition.py +200 -0
  193. relationalai/experimental/pathfinder/utils.py +26 -0
  194. relationalai/experimental/paths/README.md +107 -0
  195. relationalai/experimental/paths/api.py +143 -0
  196. relationalai/experimental/paths/benchmarks/grid_graph.py +37 -0
  197. relationalai/experimental/paths/code_organization.md +2 -0
  198. relationalai/experimental/paths/examples/Movies.ipynb +16328 -0
  199. relationalai/experimental/paths/examples/basic_example.py +40 -0
  200. relationalai/experimental/paths/examples/minimal_engine_warmup.py +3 -0
  201. relationalai/experimental/paths/examples/movie_example.py +77 -0
  202. relationalai/experimental/paths/examples/movies_data/actedin.csv +193 -0
  203. relationalai/experimental/paths/examples/movies_data/directed.csv +45 -0
  204. relationalai/experimental/paths/examples/movies_data/follows.csv +7 -0
  205. relationalai/experimental/paths/examples/movies_data/movies.csv +39 -0
  206. relationalai/experimental/paths/examples/movies_data/person.csv +134 -0
  207. relationalai/experimental/paths/examples/movies_data/produced.csv +16 -0
  208. relationalai/experimental/paths/examples/movies_data/ratings.csv +10 -0
  209. relationalai/experimental/paths/examples/movies_data/wrote.csv +11 -0
  210. relationalai/experimental/paths/examples/paths_benchmark.py +115 -0
  211. relationalai/experimental/paths/examples/paths_example.py +116 -0
  212. relationalai/experimental/paths/examples/pattern_to_automaton.py +28 -0
  213. relationalai/experimental/paths/find_paths_via_automaton.py +85 -0
  214. relationalai/experimental/paths/graph.py +185 -0
  215. relationalai/experimental/paths/path_algorithms/find_paths.py +280 -0
  216. relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +26 -0
  217. relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +111 -0
  218. relationalai/experimental/paths/path_algorithms/single.py +59 -0
  219. relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +39 -0
  220. relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +103 -0
  221. relationalai/experimental/paths/path_algorithms/usp-old.py +130 -0
  222. relationalai/experimental/paths/path_algorithms/usp-tuple.py +183 -0
  223. relationalai/experimental/paths/path_algorithms/usp.py +150 -0
  224. relationalai/experimental/paths/product_graph.py +93 -0
  225. relationalai/experimental/paths/rpq/automaton.py +584 -0
  226. relationalai/experimental/paths/rpq/diagnostics.py +56 -0
  227. relationalai/experimental/paths/rpq/rpq.py +378 -0
  228. relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +90 -0
  229. relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +119 -0
  230. relationalai/experimental/paths/tests/tests_limit_sp_single.py +104 -0
  231. relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +113 -0
  232. relationalai/experimental/paths/tests/tests_limit_walks_single.py +149 -0
  233. relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +70 -0
  234. relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +64 -0
  235. relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +115 -0
  236. relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +75 -0
  237. relationalai/experimental/paths/tests/tests_single_paths.py +152 -0
  238. relationalai/experimental/paths/tests/tests_single_walks.py +208 -0
  239. relationalai/experimental/paths/tests/tests_single_walks_undirected.py +297 -0
  240. relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +107 -0
  241. relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +76 -0
  242. relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +76 -0
  243. relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +110 -0
  244. relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +229 -0
  245. relationalai/experimental/paths/tests/tests_usp_nsp_single.py +108 -0
  246. relationalai/experimental/paths/tree_agg.py +168 -0
  247. relationalai/experimental/paths/utilities/iterators.py +27 -0
  248. relationalai/experimental/paths/utilities/prefix_sum.py +91 -0
  249. relationalai/experimental/solvers.py +1087 -0
  250. relationalai/loaders/csv.py +195 -0
  251. relationalai/loaders/loader.py +177 -0
  252. relationalai/loaders/types.py +23 -0
  253. relationalai/rel_emitter.py +373 -0
  254. relationalai/rel_utils.py +185 -0
  255. relationalai/semantics/__init__.py +22 -146
  256. relationalai/semantics/designs/query_builder/identify_by.md +106 -0
  257. relationalai/semantics/devtools/benchmark_lqp.py +535 -0
  258. relationalai/semantics/devtools/compilation_manager.py +294 -0
  259. relationalai/semantics/devtools/extract_lqp.py +110 -0
  260. relationalai/semantics/internal/internal.py +3785 -0
  261. relationalai/semantics/internal/snowflake.py +325 -0
  262. relationalai/semantics/lqp/README.md +34 -0
  263. relationalai/semantics/lqp/builtins.py +16 -0
  264. relationalai/semantics/lqp/compiler.py +22 -0
  265. relationalai/semantics/lqp/constructors.py +68 -0
  266. relationalai/semantics/lqp/executor.py +469 -0
  267. relationalai/semantics/lqp/intrinsics.py +24 -0
  268. relationalai/semantics/lqp/model2lqp.py +877 -0
  269. relationalai/semantics/lqp/passes.py +680 -0
  270. relationalai/semantics/lqp/primitives.py +252 -0
  271. relationalai/semantics/lqp/result_helpers.py +202 -0
  272. relationalai/semantics/lqp/rewrite/annotate_constraints.py +57 -0
  273. relationalai/semantics/lqp/rewrite/cdc.py +216 -0
  274. relationalai/semantics/lqp/rewrite/extract_common.py +338 -0
  275. relationalai/semantics/lqp/rewrite/extract_keys.py +512 -0
  276. relationalai/semantics/lqp/rewrite/function_annotations.py +114 -0
  277. relationalai/semantics/lqp/rewrite/functional_dependencies.py +314 -0
  278. relationalai/semantics/lqp/rewrite/quantify_vars.py +296 -0
  279. relationalai/semantics/lqp/rewrite/splinter.py +76 -0
  280. relationalai/semantics/lqp/types.py +101 -0
  281. relationalai/semantics/lqp/utils.py +160 -0
  282. relationalai/semantics/lqp/validators.py +57 -0
  283. relationalai/semantics/metamodel/__init__.py +40 -6
  284. relationalai/semantics/metamodel/builtins.py +771 -205
  285. relationalai/semantics/metamodel/compiler.py +133 -0
  286. relationalai/semantics/metamodel/dependency.py +862 -0
  287. relationalai/semantics/metamodel/executor.py +61 -0
  288. relationalai/semantics/metamodel/factory.py +287 -0
  289. relationalai/semantics/metamodel/helpers.py +361 -0
  290. relationalai/semantics/metamodel/rewrite/discharge_constraints.py +39 -0
  291. relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +210 -0
  292. relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +78 -0
  293. relationalai/semantics/metamodel/rewrite/flatten.py +554 -0
  294. relationalai/semantics/metamodel/rewrite/format_outputs.py +165 -0
  295. relationalai/semantics/metamodel/typer/checker.py +353 -0
  296. relationalai/semantics/metamodel/typer/typer.py +1399 -0
  297. relationalai/semantics/metamodel/util.py +506 -0
  298. relationalai/semantics/reasoners/__init__.py +10 -0
  299. relationalai/semantics/reasoners/graph/README.md +620 -0
  300. relationalai/semantics/reasoners/graph/__init__.py +37 -0
  301. relationalai/semantics/reasoners/graph/core.py +9019 -0
  302. relationalai/semantics/reasoners/graph/design/beyond_demand_transform.md +797 -0
  303. relationalai/semantics/reasoners/graph/tests/README.md +21 -0
  304. relationalai/semantics/reasoners/optimization/__init__.py +68 -0
  305. relationalai/semantics/reasoners/optimization/common.py +88 -0
  306. relationalai/semantics/reasoners/optimization/solvers_dev.py +568 -0
  307. relationalai/semantics/reasoners/optimization/solvers_pb.py +1414 -0
  308. relationalai/semantics/rel/builtins.py +40 -0
  309. relationalai/semantics/rel/compiler.py +989 -0
  310. relationalai/semantics/rel/executor.py +362 -0
  311. relationalai/semantics/rel/rel.py +482 -0
  312. relationalai/semantics/rel/rel_utils.py +276 -0
  313. relationalai/semantics/snowflake/__init__.py +3 -0
  314. relationalai/semantics/sql/compiler.py +2503 -0
  315. relationalai/semantics/sql/executor/duck_db.py +52 -0
  316. relationalai/semantics/sql/executor/result_helpers.py +64 -0
  317. relationalai/semantics/sql/executor/snowflake.py +149 -0
  318. relationalai/semantics/sql/rewrite/denormalize.py +222 -0
  319. relationalai/semantics/sql/rewrite/double_negation.py +49 -0
  320. relationalai/semantics/sql/rewrite/recursive_union.py +127 -0
  321. relationalai/semantics/sql/rewrite/sort_output_query.py +246 -0
  322. relationalai/semantics/sql/sql.py +504 -0
  323. relationalai/semantics/std/__init__.py +40 -60
  324. relationalai/semantics/std/constraints.py +43 -37
  325. relationalai/semantics/std/datetime.py +135 -246
  326. relationalai/semantics/std/decimals.py +52 -45
  327. relationalai/semantics/std/floats.py +5 -13
  328. relationalai/semantics/std/integers.py +11 -26
  329. relationalai/semantics/std/math.py +112 -183
  330. relationalai/semantics/std/pragmas.py +11 -0
  331. relationalai/semantics/std/re.py +62 -80
  332. relationalai/semantics/std/std.py +14 -0
  333. relationalai/semantics/std/strings.py +60 -117
  334. relationalai/semantics/tests/test_snapshot_abstract.py +143 -0
  335. relationalai/semantics/tests/test_snapshot_base.py +9 -0
  336. relationalai/semantics/tests/utils.py +46 -0
  337. relationalai/std/__init__.py +70 -0
  338. relationalai/tools/cli.py +2089 -0
  339. relationalai/tools/cli_controls.py +1826 -0
  340. relationalai/tools/cli_helpers.py +802 -0
  341. relationalai/tools/debugger.py +183 -289
  342. relationalai/tools/debugger_client.py +109 -0
  343. relationalai/tools/debugger_server.py +302 -0
  344. relationalai/tools/dev.py +685 -0
  345. relationalai/tools/notes +7 -0
  346. relationalai/tools/qb_debugger.py +425 -0
  347. relationalai/util/clean_up_databases.py +95 -0
  348. relationalai/util/format.py +106 -48
  349. relationalai/util/list_databases.py +9 -0
  350. relationalai/util/otel_configuration.py +26 -0
  351. relationalai/util/otel_handler.py +484 -0
  352. relationalai/util/snowflake_handler.py +88 -0
  353. relationalai/util/span_format_test.py +43 -0
  354. relationalai/util/span_tracker.py +207 -0
  355. relationalai/util/spans_file_handler.py +72 -0
  356. relationalai/util/tracing_handler.py +34 -0
  357. relationalai-0.13.2.dist-info/METADATA +74 -0
  358. relationalai-0.13.2.dist-info/RECORD +460 -0
  359. relationalai-0.13.2.dist-info/WHEEL +4 -0
  360. relationalai-0.13.2.dist-info/entry_points.txt +3 -0
  361. relationalai-0.13.2.dist-info/licenses/LICENSE +202 -0
  362. relationalai_test_util/__init__.py +4 -0
  363. relationalai_test_util/fixtures.py +233 -0
  364. relationalai_test_util/snapshot.py +252 -0
  365. relationalai_test_util/traceback.py +118 -0
  366. relationalai/config/__init__.py +0 -56
  367. relationalai/config/config.py +0 -289
  368. relationalai/config/config_fields.py +0 -86
  369. relationalai/config/connections/__init__.py +0 -46
  370. relationalai/config/connections/base.py +0 -23
  371. relationalai/config/connections/duckdb.py +0 -29
  372. relationalai/config/connections/snowflake.py +0 -243
  373. relationalai/config/external/__init__.py +0 -17
  374. relationalai/config/external/dbt_converter.py +0 -101
  375. relationalai/config/external/dbt_models.py +0 -93
  376. relationalai/config/external/snowflake_converter.py +0 -41
  377. relationalai/config/external/snowflake_models.py +0 -85
  378. relationalai/config/external/utils.py +0 -19
  379. relationalai/semantics/backends/lqp/annotations.py +0 -11
  380. relationalai/semantics/backends/sql/sql_compiler.py +0 -327
  381. relationalai/semantics/frontend/base.py +0 -1707
  382. relationalai/semantics/frontend/core.py +0 -179
  383. relationalai/semantics/frontend/front_compiler.py +0 -1313
  384. relationalai/semantics/frontend/pprint.py +0 -408
  385. relationalai/semantics/metamodel/metamodel.py +0 -437
  386. relationalai/semantics/metamodel/metamodel_analyzer.py +0 -519
  387. relationalai/semantics/metamodel/metamodel_compiler.py +0 -0
  388. relationalai/semantics/metamodel/pprint.py +0 -412
  389. relationalai/semantics/metamodel/rewriter.py +0 -266
  390. relationalai/semantics/metamodel/typer.py +0 -1378
  391. relationalai/semantics/std/aggregates.py +0 -149
  392. relationalai/semantics/std/common.py +0 -44
  393. relationalai/semantics/std/numbers.py +0 -86
  394. relationalai/shims/executor.py +0 -147
  395. relationalai/shims/helpers.py +0 -126
  396. relationalai/shims/hoister.py +0 -221
  397. relationalai/shims/mm2v0.py +0 -1290
  398. relationalai/tools/cli/__init__.py +0 -6
  399. relationalai/tools/cli/cli.py +0 -90
  400. relationalai/tools/cli/components/__init__.py +0 -5
  401. relationalai/tools/cli/components/progress_reader.py +0 -1524
  402. relationalai/tools/cli/components/utils.py +0 -58
  403. relationalai/tools/cli/config_template.py +0 -45
  404. relationalai/tools/cli/dev.py +0 -19
  405. relationalai/tools/typer_debugger.py +0 -93
  406. relationalai/util/dataclasses.py +0 -43
  407. relationalai/util/docutils.py +0 -40
  408. relationalai/util/error.py +0 -199
  409. relationalai/util/naming.py +0 -145
  410. relationalai/util/python.py +0 -35
  411. relationalai/util/runtime.py +0 -156
  412. relationalai/util/schema.py +0 -197
  413. relationalai/util/source.py +0 -185
  414. relationalai/util/structures.py +0 -163
  415. relationalai/util/tracing.py +0 -261
  416. relationalai-0.13.0.dev0.dist-info/METADATA +0 -46
  417. relationalai-0.13.0.dev0.dist-info/RECORD +0 -488
  418. relationalai-0.13.0.dev0.dist-info/WHEEL +0 -5
  419. relationalai-0.13.0.dev0.dist-info/entry_points.txt +0 -3
  420. relationalai-0.13.0.dev0.dist-info/top_level.txt +0 -2
  421. v0/relationalai/__init__.py +0 -216
  422. v0/relationalai/clients/__init__.py +0 -5
  423. v0/relationalai/clients/azure.py +0 -477
  424. v0/relationalai/clients/client.py +0 -912
  425. v0/relationalai/clients/config.py +0 -673
  426. v0/relationalai/clients/direct_access_client.py +0 -118
  427. v0/relationalai/clients/hash_util.py +0 -31
  428. v0/relationalai/clients/local.py +0 -571
  429. v0/relationalai/clients/profile_polling.py +0 -73
  430. v0/relationalai/clients/result_helpers.py +0 -420
  431. v0/relationalai/clients/snowflake.py +0 -3869
  432. v0/relationalai/clients/types.py +0 -113
  433. v0/relationalai/clients/use_index_poller.py +0 -980
  434. v0/relationalai/clients/util.py +0 -356
  435. v0/relationalai/debugging.py +0 -389
  436. v0/relationalai/dsl.py +0 -1749
  437. v0/relationalai/early_access/builder/__init__.py +0 -30
  438. v0/relationalai/early_access/builder/builder/__init__.py +0 -35
  439. v0/relationalai/early_access/builder/snowflake/__init__.py +0 -12
  440. v0/relationalai/early_access/builder/std/__init__.py +0 -25
  441. v0/relationalai/early_access/builder/std/decimals/__init__.py +0 -12
  442. v0/relationalai/early_access/builder/std/integers/__init__.py +0 -12
  443. v0/relationalai/early_access/builder/std/math/__init__.py +0 -12
  444. v0/relationalai/early_access/builder/std/strings/__init__.py +0 -14
  445. v0/relationalai/early_access/devtools/__init__.py +0 -12
  446. v0/relationalai/early_access/devtools/benchmark_lqp/__init__.py +0 -12
  447. v0/relationalai/early_access/devtools/extract_lqp/__init__.py +0 -12
  448. v0/relationalai/early_access/dsl/adapters/orm/adapter_qb.py +0 -427
  449. v0/relationalai/early_access/dsl/adapters/orm/parser.py +0 -636
  450. v0/relationalai/early_access/dsl/adapters/owl/adapter.py +0 -176
  451. v0/relationalai/early_access/dsl/adapters/owl/parser.py +0 -160
  452. v0/relationalai/early_access/dsl/bindings/common.py +0 -402
  453. v0/relationalai/early_access/dsl/bindings/csv.py +0 -170
  454. v0/relationalai/early_access/dsl/bindings/legacy/binding_models.py +0 -143
  455. v0/relationalai/early_access/dsl/bindings/snowflake.py +0 -64
  456. v0/relationalai/early_access/dsl/codegen/binder.py +0 -411
  457. v0/relationalai/early_access/dsl/codegen/common.py +0 -79
  458. v0/relationalai/early_access/dsl/codegen/helpers.py +0 -23
  459. v0/relationalai/early_access/dsl/codegen/relations.py +0 -700
  460. v0/relationalai/early_access/dsl/codegen/weaver.py +0 -417
  461. v0/relationalai/early_access/dsl/core/builders/__init__.py +0 -47
  462. v0/relationalai/early_access/dsl/core/builders/logic.py +0 -19
  463. v0/relationalai/early_access/dsl/core/builders/scalar_constraint.py +0 -11
  464. v0/relationalai/early_access/dsl/core/constraints/predicate/atomic.py +0 -455
  465. v0/relationalai/early_access/dsl/core/constraints/predicate/universal.py +0 -73
  466. v0/relationalai/early_access/dsl/core/constraints/scalar.py +0 -310
  467. v0/relationalai/early_access/dsl/core/context.py +0 -13
  468. v0/relationalai/early_access/dsl/core/cset.py +0 -132
  469. v0/relationalai/early_access/dsl/core/exprs/__init__.py +0 -116
  470. v0/relationalai/early_access/dsl/core/exprs/relational.py +0 -18
  471. v0/relationalai/early_access/dsl/core/exprs/scalar.py +0 -412
  472. v0/relationalai/early_access/dsl/core/instances.py +0 -44
  473. v0/relationalai/early_access/dsl/core/logic/__init__.py +0 -193
  474. v0/relationalai/early_access/dsl/core/logic/aggregation.py +0 -98
  475. v0/relationalai/early_access/dsl/core/logic/exists.py +0 -223
  476. v0/relationalai/early_access/dsl/core/logic/helper.py +0 -163
  477. v0/relationalai/early_access/dsl/core/namespaces.py +0 -32
  478. v0/relationalai/early_access/dsl/core/relations.py +0 -276
  479. v0/relationalai/early_access/dsl/core/rules.py +0 -112
  480. v0/relationalai/early_access/dsl/core/std/__init__.py +0 -45
  481. v0/relationalai/early_access/dsl/core/temporal/recall.py +0 -6
  482. v0/relationalai/early_access/dsl/core/types/__init__.py +0 -270
  483. v0/relationalai/early_access/dsl/core/types/concepts.py +0 -128
  484. v0/relationalai/early_access/dsl/core/types/constrained/__init__.py +0 -267
  485. v0/relationalai/early_access/dsl/core/types/constrained/nominal.py +0 -143
  486. v0/relationalai/early_access/dsl/core/types/constrained/subtype.py +0 -124
  487. v0/relationalai/early_access/dsl/core/types/standard.py +0 -92
  488. v0/relationalai/early_access/dsl/core/types/unconstrained.py +0 -50
  489. v0/relationalai/early_access/dsl/core/types/variables.py +0 -203
  490. v0/relationalai/early_access/dsl/ir/compiler.py +0 -318
  491. v0/relationalai/early_access/dsl/ir/executor.py +0 -260
  492. v0/relationalai/early_access/dsl/ontologies/constraints.py +0 -88
  493. v0/relationalai/early_access/dsl/ontologies/export.py +0 -30
  494. v0/relationalai/early_access/dsl/ontologies/models.py +0 -453
  495. v0/relationalai/early_access/dsl/ontologies/python_printer.py +0 -303
  496. v0/relationalai/early_access/dsl/ontologies/readings.py +0 -60
  497. v0/relationalai/early_access/dsl/ontologies/relationships.py +0 -322
  498. v0/relationalai/early_access/dsl/ontologies/roles.py +0 -87
  499. v0/relationalai/early_access/dsl/ontologies/subtyping.py +0 -55
  500. v0/relationalai/early_access/dsl/orm/constraints.py +0 -438
  501. v0/relationalai/early_access/dsl/orm/measures/dimensions.py +0 -200
  502. v0/relationalai/early_access/dsl/orm/measures/initializer.py +0 -16
  503. v0/relationalai/early_access/dsl/orm/measures/measure_rules.py +0 -275
  504. v0/relationalai/early_access/dsl/orm/measures/measures.py +0 -299
  505. v0/relationalai/early_access/dsl/orm/measures/role_exprs.py +0 -268
  506. v0/relationalai/early_access/dsl/orm/models.py +0 -256
  507. v0/relationalai/early_access/dsl/orm/object_oriented_printer.py +0 -344
  508. v0/relationalai/early_access/dsl/orm/printer.py +0 -469
  509. v0/relationalai/early_access/dsl/orm/reasoners.py +0 -480
  510. v0/relationalai/early_access/dsl/orm/relations.py +0 -19
  511. v0/relationalai/early_access/dsl/orm/relationships.py +0 -251
  512. v0/relationalai/early_access/dsl/orm/types.py +0 -42
  513. v0/relationalai/early_access/dsl/orm/utils.py +0 -79
  514. v0/relationalai/early_access/dsl/orm/verb.py +0 -204
  515. v0/relationalai/early_access/dsl/physical_metadata/tables.py +0 -133
  516. v0/relationalai/early_access/dsl/relations.py +0 -170
  517. v0/relationalai/early_access/dsl/rulesets.py +0 -69
  518. v0/relationalai/early_access/dsl/schemas/__init__.py +0 -450
  519. v0/relationalai/early_access/dsl/schemas/builder.py +0 -48
  520. v0/relationalai/early_access/dsl/schemas/comp_names.py +0 -51
  521. v0/relationalai/early_access/dsl/schemas/components.py +0 -203
  522. v0/relationalai/early_access/dsl/schemas/contexts.py +0 -156
  523. v0/relationalai/early_access/dsl/schemas/exprs.py +0 -89
  524. v0/relationalai/early_access/dsl/schemas/fragments.py +0 -464
  525. v0/relationalai/early_access/dsl/serialization.py +0 -79
  526. v0/relationalai/early_access/dsl/serialize/exporter.py +0 -163
  527. v0/relationalai/early_access/dsl/snow/api.py +0 -104
  528. v0/relationalai/early_access/dsl/snow/common.py +0 -76
  529. v0/relationalai/early_access/dsl/state_mgmt/__init__.py +0 -129
  530. v0/relationalai/early_access/dsl/state_mgmt/state_charts.py +0 -125
  531. v0/relationalai/early_access/dsl/state_mgmt/transitions.py +0 -130
  532. v0/relationalai/early_access/dsl/types/__init__.py +0 -40
  533. v0/relationalai/early_access/dsl/types/concepts.py +0 -12
  534. v0/relationalai/early_access/dsl/types/entities.py +0 -135
  535. v0/relationalai/early_access/dsl/types/values.py +0 -17
  536. v0/relationalai/early_access/dsl/utils.py +0 -102
  537. v0/relationalai/early_access/graphs/__init__.py +0 -13
  538. v0/relationalai/early_access/lqp/__init__.py +0 -12
  539. v0/relationalai/early_access/lqp/compiler/__init__.py +0 -12
  540. v0/relationalai/early_access/lqp/constructors/__init__.py +0 -18
  541. v0/relationalai/early_access/lqp/executor/__init__.py +0 -12
  542. v0/relationalai/early_access/lqp/ir/__init__.py +0 -12
  543. v0/relationalai/early_access/lqp/passes/__init__.py +0 -12
  544. v0/relationalai/early_access/lqp/pragmas/__init__.py +0 -12
  545. v0/relationalai/early_access/lqp/primitives/__init__.py +0 -12
  546. v0/relationalai/early_access/lqp/types/__init__.py +0 -12
  547. v0/relationalai/early_access/lqp/utils/__init__.py +0 -12
  548. v0/relationalai/early_access/lqp/validators/__init__.py +0 -12
  549. v0/relationalai/early_access/metamodel/__init__.py +0 -58
  550. v0/relationalai/early_access/metamodel/builtins/__init__.py +0 -12
  551. v0/relationalai/early_access/metamodel/compiler/__init__.py +0 -12
  552. v0/relationalai/early_access/metamodel/dependency/__init__.py +0 -12
  553. v0/relationalai/early_access/metamodel/factory/__init__.py +0 -17
  554. v0/relationalai/early_access/metamodel/helpers/__init__.py +0 -12
  555. v0/relationalai/early_access/metamodel/ir/__init__.py +0 -14
  556. v0/relationalai/early_access/metamodel/rewrite/__init__.py +0 -7
  557. v0/relationalai/early_access/metamodel/typer/__init__.py +0 -3
  558. v0/relationalai/early_access/metamodel/typer/typer/__init__.py +0 -12
  559. v0/relationalai/early_access/metamodel/types/__init__.py +0 -15
  560. v0/relationalai/early_access/metamodel/util/__init__.py +0 -15
  561. v0/relationalai/early_access/metamodel/visitor/__init__.py +0 -12
  562. v0/relationalai/early_access/rel/__init__.py +0 -12
  563. v0/relationalai/early_access/rel/executor/__init__.py +0 -12
  564. v0/relationalai/early_access/rel/rel_utils/__init__.py +0 -12
  565. v0/relationalai/early_access/rel/rewrite/__init__.py +0 -7
  566. v0/relationalai/early_access/solvers/__init__.py +0 -19
  567. v0/relationalai/early_access/sql/__init__.py +0 -11
  568. v0/relationalai/early_access/sql/executor/__init__.py +0 -3
  569. v0/relationalai/early_access/sql/rewrite/__init__.py +0 -3
  570. v0/relationalai/early_access/tests/logging/__init__.py +0 -12
  571. v0/relationalai/early_access/tests/test_snapshot_base/__init__.py +0 -12
  572. v0/relationalai/early_access/tests/utils/__init__.py +0 -12
  573. v0/relationalai/environments/__init__.py +0 -35
  574. v0/relationalai/environments/base.py +0 -381
  575. v0/relationalai/environments/colab.py +0 -14
  576. v0/relationalai/environments/generic.py +0 -71
  577. v0/relationalai/environments/ipython.py +0 -68
  578. v0/relationalai/environments/jupyter.py +0 -9
  579. v0/relationalai/environments/snowbook.py +0 -169
  580. v0/relationalai/errors.py +0 -2455
  581. v0/relationalai/experimental/SF.py +0 -38
  582. v0/relationalai/experimental/inspect.py +0 -47
  583. v0/relationalai/experimental/pathfinder/__init__.py +0 -158
  584. v0/relationalai/experimental/pathfinder/api.py +0 -160
  585. v0/relationalai/experimental/pathfinder/automaton.py +0 -584
  586. v0/relationalai/experimental/pathfinder/bridge.py +0 -226
  587. v0/relationalai/experimental/pathfinder/compiler.py +0 -416
  588. v0/relationalai/experimental/pathfinder/datalog.py +0 -214
  589. v0/relationalai/experimental/pathfinder/diagnostics.py +0 -56
  590. v0/relationalai/experimental/pathfinder/filter.py +0 -236
  591. v0/relationalai/experimental/pathfinder/glushkov.py +0 -439
  592. v0/relationalai/experimental/pathfinder/options.py +0 -265
  593. v0/relationalai/experimental/pathfinder/rpq.py +0 -344
  594. v0/relationalai/experimental/pathfinder/transition.py +0 -200
  595. v0/relationalai/experimental/pathfinder/utils.py +0 -26
  596. v0/relationalai/experimental/paths/api.py +0 -143
  597. v0/relationalai/experimental/paths/benchmarks/grid_graph.py +0 -37
  598. v0/relationalai/experimental/paths/examples/basic_example.py +0 -40
  599. v0/relationalai/experimental/paths/examples/minimal_engine_warmup.py +0 -3
  600. v0/relationalai/experimental/paths/examples/movie_example.py +0 -77
  601. v0/relationalai/experimental/paths/examples/paths_benchmark.py +0 -115
  602. v0/relationalai/experimental/paths/examples/paths_example.py +0 -116
  603. v0/relationalai/experimental/paths/examples/pattern_to_automaton.py +0 -28
  604. v0/relationalai/experimental/paths/find_paths_via_automaton.py +0 -85
  605. v0/relationalai/experimental/paths/graph.py +0 -185
  606. v0/relationalai/experimental/paths/path_algorithms/find_paths.py +0 -280
  607. v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +0 -26
  608. v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +0 -111
  609. v0/relationalai/experimental/paths/path_algorithms/single.py +0 -59
  610. v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +0 -39
  611. v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +0 -103
  612. v0/relationalai/experimental/paths/path_algorithms/usp-old.py +0 -130
  613. v0/relationalai/experimental/paths/path_algorithms/usp-tuple.py +0 -183
  614. v0/relationalai/experimental/paths/path_algorithms/usp.py +0 -150
  615. v0/relationalai/experimental/paths/product_graph.py +0 -93
  616. v0/relationalai/experimental/paths/rpq/automaton.py +0 -584
  617. v0/relationalai/experimental/paths/rpq/diagnostics.py +0 -56
  618. v0/relationalai/experimental/paths/rpq/rpq.py +0 -378
  619. v0/relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +0 -90
  620. v0/relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +0 -119
  621. v0/relationalai/experimental/paths/tests/tests_limit_sp_single.py +0 -104
  622. v0/relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +0 -113
  623. v0/relationalai/experimental/paths/tests/tests_limit_walks_single.py +0 -149
  624. v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +0 -70
  625. v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +0 -64
  626. v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +0 -115
  627. v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +0 -75
  628. v0/relationalai/experimental/paths/tests/tests_single_paths.py +0 -152
  629. v0/relationalai/experimental/paths/tests/tests_single_walks.py +0 -208
  630. v0/relationalai/experimental/paths/tests/tests_single_walks_undirected.py +0 -297
  631. v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +0 -107
  632. v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +0 -76
  633. v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +0 -76
  634. v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +0 -110
  635. v0/relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +0 -229
  636. v0/relationalai/experimental/paths/tests/tests_usp_nsp_single.py +0 -108
  637. v0/relationalai/experimental/paths/tree_agg.py +0 -168
  638. v0/relationalai/experimental/paths/utilities/iterators.py +0 -27
  639. v0/relationalai/experimental/paths/utilities/prefix_sum.py +0 -91
  640. v0/relationalai/experimental/solvers.py +0 -1087
  641. v0/relationalai/loaders/csv.py +0 -195
  642. v0/relationalai/loaders/loader.py +0 -177
  643. v0/relationalai/loaders/types.py +0 -23
  644. v0/relationalai/rel_emitter.py +0 -373
  645. v0/relationalai/rel_utils.py +0 -185
  646. v0/relationalai/semantics/__init__.py +0 -29
  647. v0/relationalai/semantics/devtools/benchmark_lqp.py +0 -536
  648. v0/relationalai/semantics/devtools/compilation_manager.py +0 -294
  649. v0/relationalai/semantics/devtools/extract_lqp.py +0 -110
  650. v0/relationalai/semantics/internal/internal.py +0 -3785
  651. v0/relationalai/semantics/internal/snowflake.py +0 -324
  652. v0/relationalai/semantics/lqp/builtins.py +0 -16
  653. v0/relationalai/semantics/lqp/compiler.py +0 -22
  654. v0/relationalai/semantics/lqp/constructors.py +0 -68
  655. v0/relationalai/semantics/lqp/executor.py +0 -469
  656. v0/relationalai/semantics/lqp/intrinsics.py +0 -24
  657. v0/relationalai/semantics/lqp/model2lqp.py +0 -839
  658. v0/relationalai/semantics/lqp/passes.py +0 -680
  659. v0/relationalai/semantics/lqp/primitives.py +0 -252
  660. v0/relationalai/semantics/lqp/result_helpers.py +0 -202
  661. v0/relationalai/semantics/lqp/rewrite/annotate_constraints.py +0 -57
  662. v0/relationalai/semantics/lqp/rewrite/cdc.py +0 -216
  663. v0/relationalai/semantics/lqp/rewrite/extract_common.py +0 -338
  664. v0/relationalai/semantics/lqp/rewrite/extract_keys.py +0 -449
  665. v0/relationalai/semantics/lqp/rewrite/function_annotations.py +0 -114
  666. v0/relationalai/semantics/lqp/rewrite/functional_dependencies.py +0 -314
  667. v0/relationalai/semantics/lqp/rewrite/quantify_vars.py +0 -296
  668. v0/relationalai/semantics/lqp/rewrite/splinter.py +0 -76
  669. v0/relationalai/semantics/lqp/types.py +0 -101
  670. v0/relationalai/semantics/lqp/utils.py +0 -160
  671. v0/relationalai/semantics/lqp/validators.py +0 -57
  672. v0/relationalai/semantics/metamodel/__init__.py +0 -40
  673. v0/relationalai/semantics/metamodel/builtins.py +0 -774
  674. v0/relationalai/semantics/metamodel/compiler.py +0 -133
  675. v0/relationalai/semantics/metamodel/dependency.py +0 -862
  676. v0/relationalai/semantics/metamodel/executor.py +0 -61
  677. v0/relationalai/semantics/metamodel/factory.py +0 -287
  678. v0/relationalai/semantics/metamodel/helpers.py +0 -361
  679. v0/relationalai/semantics/metamodel/rewrite/discharge_constraints.py +0 -39
  680. v0/relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +0 -210
  681. v0/relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +0 -78
  682. v0/relationalai/semantics/metamodel/rewrite/flatten.py +0 -549
  683. v0/relationalai/semantics/metamodel/rewrite/format_outputs.py +0 -165
  684. v0/relationalai/semantics/metamodel/typer/checker.py +0 -353
  685. v0/relationalai/semantics/metamodel/typer/typer.py +0 -1395
  686. v0/relationalai/semantics/metamodel/util.py +0 -505
  687. v0/relationalai/semantics/reasoners/__init__.py +0 -10
  688. v0/relationalai/semantics/reasoners/graph/__init__.py +0 -37
  689. v0/relationalai/semantics/reasoners/graph/core.py +0 -9020
  690. v0/relationalai/semantics/reasoners/optimization/__init__.py +0 -68
  691. v0/relationalai/semantics/reasoners/optimization/common.py +0 -88
  692. v0/relationalai/semantics/reasoners/optimization/solvers_dev.py +0 -568
  693. v0/relationalai/semantics/reasoners/optimization/solvers_pb.py +0 -1163
  694. v0/relationalai/semantics/rel/builtins.py +0 -40
  695. v0/relationalai/semantics/rel/compiler.py +0 -989
  696. v0/relationalai/semantics/rel/executor.py +0 -359
  697. v0/relationalai/semantics/rel/rel.py +0 -482
  698. v0/relationalai/semantics/rel/rel_utils.py +0 -276
  699. v0/relationalai/semantics/snowflake/__init__.py +0 -3
  700. v0/relationalai/semantics/sql/compiler.py +0 -2503
  701. v0/relationalai/semantics/sql/executor/duck_db.py +0 -52
  702. v0/relationalai/semantics/sql/executor/result_helpers.py +0 -64
  703. v0/relationalai/semantics/sql/executor/snowflake.py +0 -145
  704. v0/relationalai/semantics/sql/rewrite/denormalize.py +0 -222
  705. v0/relationalai/semantics/sql/rewrite/double_negation.py +0 -49
  706. v0/relationalai/semantics/sql/rewrite/recursive_union.py +0 -127
  707. v0/relationalai/semantics/sql/rewrite/sort_output_query.py +0 -246
  708. v0/relationalai/semantics/sql/sql.py +0 -504
  709. v0/relationalai/semantics/std/__init__.py +0 -54
  710. v0/relationalai/semantics/std/constraints.py +0 -43
  711. v0/relationalai/semantics/std/datetime.py +0 -363
  712. v0/relationalai/semantics/std/decimals.py +0 -62
  713. v0/relationalai/semantics/std/floats.py +0 -7
  714. v0/relationalai/semantics/std/integers.py +0 -22
  715. v0/relationalai/semantics/std/math.py +0 -141
  716. v0/relationalai/semantics/std/pragmas.py +0 -11
  717. v0/relationalai/semantics/std/re.py +0 -83
  718. v0/relationalai/semantics/std/std.py +0 -14
  719. v0/relationalai/semantics/std/strings.py +0 -63
  720. v0/relationalai/semantics/tests/__init__.py +0 -0
  721. v0/relationalai/semantics/tests/test_snapshot_abstract.py +0 -143
  722. v0/relationalai/semantics/tests/test_snapshot_base.py +0 -9
  723. v0/relationalai/semantics/tests/utils.py +0 -46
  724. v0/relationalai/std/__init__.py +0 -70
  725. v0/relationalai/tools/__init__.py +0 -0
  726. v0/relationalai/tools/cli.py +0 -1940
  727. v0/relationalai/tools/cli_controls.py +0 -1826
  728. v0/relationalai/tools/cli_helpers.py +0 -390
  729. v0/relationalai/tools/debugger.py +0 -183
  730. v0/relationalai/tools/debugger_client.py +0 -109
  731. v0/relationalai/tools/debugger_server.py +0 -302
  732. v0/relationalai/tools/dev.py +0 -685
  733. v0/relationalai/tools/qb_debugger.py +0 -425
  734. v0/relationalai/util/clean_up_databases.py +0 -95
  735. v0/relationalai/util/format.py +0 -123
  736. v0/relationalai/util/list_databases.py +0 -9
  737. v0/relationalai/util/otel_configuration.py +0 -25
  738. v0/relationalai/util/otel_handler.py +0 -484
  739. v0/relationalai/util/snowflake_handler.py +0 -88
  740. v0/relationalai/util/span_format_test.py +0 -43
  741. v0/relationalai/util/span_tracker.py +0 -207
  742. v0/relationalai/util/spans_file_handler.py +0 -72
  743. v0/relationalai/util/tracing_handler.py +0 -34
  744. /relationalai/{semantics/frontend → analysis}/__init__.py +0 -0
  745. {v0/relationalai → relationalai}/analysis/mechanistic.py +0 -0
  746. {v0/relationalai → relationalai}/analysis/whynot.py +0 -0
  747. /relationalai/{shims → auth}/__init__.py +0 -0
  748. {v0/relationalai → relationalai}/auth/jwt_generator.py +0 -0
  749. {v0/relationalai → relationalai}/auth/oauth_callback_server.py +0 -0
  750. {v0/relationalai → relationalai}/auth/token_handler.py +0 -0
  751. {v0/relationalai → relationalai}/auth/util.py +0 -0
  752. {v0/relationalai/clients → relationalai/clients/resources/snowflake}/cache_store.py +0 -0
  753. {v0/relationalai → relationalai}/compiler.py +0 -0
  754. {v0/relationalai → relationalai}/dependencies.py +0 -0
  755. {v0/relationalai → relationalai}/docutils.py +0 -0
  756. {v0/relationalai/analysis → relationalai/early_access}/__init__.py +0 -0
  757. {v0/relationalai → relationalai}/early_access/dsl/__init__.py +0 -0
  758. {v0/relationalai/auth → relationalai/early_access/dsl/adapters}/__init__.py +0 -0
  759. {v0/relationalai/early_access → relationalai/early_access/dsl/adapters/orm}/__init__.py +0 -0
  760. {v0/relationalai → relationalai}/early_access/dsl/adapters/orm/model.py +0 -0
  761. {v0/relationalai/early_access/dsl/adapters → relationalai/early_access/dsl/adapters/owl}/__init__.py +0 -0
  762. {v0/relationalai → relationalai}/early_access/dsl/adapters/owl/model.py +0 -0
  763. {v0/relationalai/early_access/dsl/adapters/orm → relationalai/early_access/dsl/bindings}/__init__.py +0 -0
  764. {v0/relationalai/early_access/dsl/adapters/owl → relationalai/early_access/dsl/bindings/legacy}/__init__.py +0 -0
  765. {v0/relationalai/early_access/dsl/bindings → relationalai/early_access/dsl/codegen}/__init__.py +0 -0
  766. {v0/relationalai → relationalai}/early_access/dsl/constants.py +0 -0
  767. {v0/relationalai → relationalai}/early_access/dsl/core/__init__.py +0 -0
  768. {v0/relationalai → relationalai}/early_access/dsl/core/constraints/__init__.py +0 -0
  769. {v0/relationalai → relationalai}/early_access/dsl/core/constraints/predicate/__init__.py +0 -0
  770. {v0/relationalai → relationalai}/early_access/dsl/core/stack.py +0 -0
  771. {v0/relationalai/early_access/dsl/bindings/legacy → relationalai/early_access/dsl/core/temporal}/__init__.py +0 -0
  772. {v0/relationalai → relationalai}/early_access/dsl/core/utils.py +0 -0
  773. {v0/relationalai/early_access/dsl/codegen → relationalai/early_access/dsl/ir}/__init__.py +0 -0
  774. {v0/relationalai/early_access/dsl/core/temporal → relationalai/early_access/dsl/ontologies}/__init__.py +0 -0
  775. {v0/relationalai → relationalai}/early_access/dsl/ontologies/raw_source.py +0 -0
  776. {v0/relationalai/early_access/dsl/ir → relationalai/early_access/dsl/orm}/__init__.py +0 -0
  777. {v0/relationalai/early_access/dsl/ontologies → relationalai/early_access/dsl/orm/measures}/__init__.py +0 -0
  778. {v0/relationalai → relationalai}/early_access/dsl/orm/reasoner_errors.py +0 -0
  779. {v0/relationalai/early_access/dsl/orm → relationalai/early_access/dsl/physical_metadata}/__init__.py +0 -0
  780. {v0/relationalai/early_access/dsl/orm/measures → relationalai/early_access/dsl/serialize}/__init__.py +0 -0
  781. {v0/relationalai → relationalai}/early_access/dsl/serialize/binding_model.py +0 -0
  782. {v0/relationalai → relationalai}/early_access/dsl/serialize/model.py +0 -0
  783. {v0/relationalai/early_access/dsl/physical_metadata → relationalai/early_access/dsl/snow}/__init__.py +0 -0
  784. {v0/relationalai → relationalai}/early_access/tests/__init__.py +0 -0
  785. {v0/relationalai → relationalai}/environments/ci.py +0 -0
  786. {v0/relationalai → relationalai}/environments/hex.py +0 -0
  787. {v0/relationalai → relationalai}/environments/terminal.py +0 -0
  788. {v0/relationalai → relationalai}/experimental/__init__.py +0 -0
  789. {v0/relationalai → relationalai}/experimental/graphs.py +0 -0
  790. {v0/relationalai → relationalai}/experimental/paths/__init__.py +0 -0
  791. {v0/relationalai → relationalai}/experimental/paths/benchmarks/__init__.py +0 -0
  792. {v0/relationalai → relationalai}/experimental/paths/path_algorithms/__init__.py +0 -0
  793. {v0/relationalai → relationalai}/experimental/paths/rpq/__init__.py +0 -0
  794. {v0/relationalai → relationalai}/experimental/paths/rpq/filter.py +0 -0
  795. {v0/relationalai → relationalai}/experimental/paths/rpq/glushkov.py +0 -0
  796. {v0/relationalai → relationalai}/experimental/paths/rpq/transition.py +0 -0
  797. {v0/relationalai → relationalai}/experimental/paths/utilities/__init__.py +0 -0
  798. {v0/relationalai → relationalai}/experimental/paths/utilities/utilities.py +0 -0
  799. {v0/relationalai/early_access/dsl/serialize → relationalai/loaders}/__init__.py +0 -0
  800. {v0/relationalai → relationalai}/metagen.py +0 -0
  801. {v0/relationalai → relationalai}/metamodel.py +0 -0
  802. {v0/relationalai → relationalai}/rel.py +0 -0
  803. {v0/relationalai → relationalai}/semantics/devtools/__init__.py +0 -0
  804. {v0/relationalai → relationalai}/semantics/internal/__init__.py +0 -0
  805. {v0/relationalai → relationalai}/semantics/internal/annotations.py +0 -0
  806. {v0/relationalai → relationalai}/semantics/lqp/__init__.py +0 -0
  807. {v0/relationalai → relationalai}/semantics/lqp/ir.py +0 -0
  808. {v0/relationalai → relationalai}/semantics/lqp/pragmas.py +0 -0
  809. {v0/relationalai → relationalai}/semantics/lqp/rewrite/__init__.py +0 -0
  810. {v0/relationalai → relationalai}/semantics/metamodel/dataflow.py +0 -0
  811. {v0/relationalai → relationalai}/semantics/metamodel/ir.py +0 -0
  812. {v0/relationalai → relationalai}/semantics/metamodel/rewrite/__init__.py +0 -0
  813. {v0/relationalai → relationalai}/semantics/metamodel/typer/__init__.py +0 -0
  814. {v0/relationalai → relationalai}/semantics/metamodel/types.py +0 -0
  815. {v0/relationalai → relationalai}/semantics/metamodel/visitor.py +0 -0
  816. {v0/relationalai → relationalai}/semantics/reasoners/experimental/__init__.py +0 -0
  817. {v0/relationalai → relationalai}/semantics/rel/__init__.py +0 -0
  818. {v0/relationalai → relationalai}/semantics/sql/__init__.py +0 -0
  819. {v0/relationalai → relationalai}/semantics/sql/executor/__init__.py +0 -0
  820. {v0/relationalai → relationalai}/semantics/sql/rewrite/__init__.py +0 -0
  821. {v0/relationalai/early_access/dsl/snow → relationalai/semantics/tests}/__init__.py +0 -0
  822. {v0/relationalai → relationalai}/semantics/tests/logging.py +0 -0
  823. {v0/relationalai → relationalai}/std/aggregates.py +0 -0
  824. {v0/relationalai → relationalai}/std/dates.py +0 -0
  825. {v0/relationalai → relationalai}/std/graphs.py +0 -0
  826. {v0/relationalai → relationalai}/std/inspect.py +0 -0
  827. {v0/relationalai → relationalai}/std/math.py +0 -0
  828. {v0/relationalai → relationalai}/std/re.py +0 -0
  829. {v0/relationalai → relationalai}/std/strings.py +0 -0
  830. {v0/relationalai/loaders → relationalai/tools}/__init__.py +0 -0
  831. {v0/relationalai → relationalai}/tools/cleanup_snapshots.py +0 -0
  832. {v0/relationalai → relationalai}/tools/constants.py +0 -0
  833. {v0/relationalai → relationalai}/tools/query_utils.py +0 -0
  834. {v0/relationalai → relationalai}/tools/snapshot_viewer.py +0 -0
  835. {v0/relationalai → relationalai}/util/__init__.py +0 -0
  836. {v0/relationalai → relationalai}/util/constants.py +0 -0
  837. {v0/relationalai → relationalai}/util/graph.py +0 -0
  838. {v0/relationalai → relationalai}/util/timeout.py +0 -0
@@ -1,1395 +0,0 @@
1
- from __future__ import annotations
2
- from collections import defaultdict
3
- from dataclasses import dataclass
4
- import dataclasses
5
- import datetime
6
- from decimal import Decimal as PyDecimal
7
- from typing import Optional, Union, Tuple
8
- from v0.relationalai import debugging
9
- from v0.relationalai.semantics.metamodel import builtins, helpers, ir, types, visitor, compiler, factory as f
10
- from v0.relationalai.semantics.metamodel.util import OrderedSet, ordered_set
11
- import rich
12
- import sys
13
-
14
- #--------------------------------------------------
15
- # Helpers
16
- #--------------------------------------------------
17
-
18
- def to_relation(node:ir.Lookup|ir.Update|ir.Aggregate) -> ir.Relation:
19
- """ Get the relation being referred to by this node. """
20
- if isinstance(node, ir.Aggregate):
21
- return node.aggregation
22
- return node.relation
23
-
24
- def to_name(type:ir.Type) -> str:
25
- """ Get a human-readable name representing a type. """
26
- if isinstance(type, ir.DecimalType):
27
- return f"Decimal({type.precision},{type.scale})"
28
- elif isinstance(type, ir.ScalarType):
29
- return type.name
30
- elif isinstance(type, ir.UnionType):
31
- return '|'.join([to_name(t) for t in type.types])
32
- elif isinstance(type, ir.ListType):
33
- return f"[{to_name(type.element_type)}]"
34
- else:
35
- raise TypeError(f"Unknown type: {type}")
36
-
37
- def check_int64(value: int):
38
- INT64_MIN = -(2 ** 63)
39
- INT64_MAX = 2 ** 63 - 1
40
-
41
- if not (INT64_MIN <= value <= INT64_MAX):
42
- raise OverflowError(f"Value '{value}' does not fit in Int64.")
43
-
44
- #--------------------------------------------------
45
- # Constants
46
- #--------------------------------------------------
47
-
48
- # map potential type conversions to their cost
49
- # The differences in the costs of converting from one type to another should be
50
- # smaller than the cost of a literal conversion.
51
- # Otherwise, we'll introduce spurious conversions of say Int->Decimal64 plus a cheap literal conversion
52
- # Float->Decimal64, rather than a single literal conversion Int->Float.
53
- # Use a large enough number here so that if all arguments are literals, it's cheaper to convert
54
- # the literals (cost 10) rather than not convert some literals and convert a non-literal instead.
55
- # For instance, for `y=1+x` is should be cheaper to convert 1 to float and not convert x and y, than it would be
56
- # convert both x and y to integer.
57
- # We do however, want to prefer converting to number types lower in the lattice.
58
- # So we make the cost depend only on the result type.
59
- # Making all the costs the same would introduce spurious unions of conversions.
60
-
61
- CONVERSION_LATTICE:dict[tuple[ir.Type, ir.Type], int] = {
62
- # Make the cost depend only on the result type.
63
- (types.Int64, types.Int128): 1000,
64
- (types.Int64, types.GenericDecimal): 1002,
65
- (types.Int64, types.Float): 1004,
66
- (types.Int128, types.GenericDecimal): 1002,
67
- (types.GenericDecimal, types.Float): 1003,
68
- (types.Int128, types.Float): 1004,
69
- # Int -> Hash (UInt128)
70
- (types.Int64, types.Hash): 1001,
71
- (types.Int128, types.Hash): 1001,
72
- (types.Int128, types.UInt128): 1001,
73
- }
74
-
75
- def conversion_lattice_cost(from_type, to_type):
76
- """
77
- Lookup the conversion cost in the conversion lattice to convert from_type to to_type.
78
- Return inf is the conversion is not allowed.
79
- """
80
- # the conversion lattice only has generic decimals as placeholders
81
- if isinstance(from_type, ir.DecimalType):
82
- from_type = types.GenericDecimal
83
- if isinstance(to_type, ir.DecimalType):
84
- to_type = types.GenericDecimal
85
-
86
- if (from_type, to_type) in CONVERSION_LATTICE:
87
- return CONVERSION_LATTICE[(from_type, to_type)]
88
- return float("inf")
89
-
90
- # list of non-parametric types that are primitives. Avoid using this constant, use
91
- # is_base_primitive instead because it accounts for parametric types like decimals.
92
- _NON_PARAMETRIC_PRIMITIVES = [
93
- types.Int64,
94
- types.Int128,
95
- types.UInt128,
96
- types.Float,
97
- types.GenericDecimal,
98
- types.Bool,
99
- types.String,
100
- types.Date,
101
- types.DateTime,
102
- types.Hash
103
- ]
104
-
105
- ENTITY_LIKES = [types.RowId]
106
-
107
- # these are relations that try to preserve their input types
108
- # e.g. if you add a USD and a Decimal, the result is still a USD
109
- TYPE_PRESERVERS = [
110
- *builtins.plus.overloads,
111
- *builtins.minus.overloads,
112
- *builtins.mul.overloads,
113
- *builtins.mod.overloads,
114
- builtins.trunc_div,
115
- builtins.concat,
116
- *builtins.abs.overloads,
117
- *builtins.sum.overloads,
118
- *builtins.max.overloads,
119
- *builtins.min.overloads,
120
- # Exclude div overloads (like Int/Int -> Float) where the result type is different from the input types
121
- *(filter(lambda x: x.fields[0].type == x.fields[1].type == x.fields[2].type, builtins.div.overloads)),
122
- # Exclude avg overloads (avg Int -> Float) where the result type is different from the input types
123
- *(filter(lambda x: x.fields[0].type == x.fields[1].type, builtins.avg.overloads)),
124
- ]
125
-
126
- #--------------------------------------------------
127
- # Type helpers
128
- #--------------------------------------------------
129
-
130
- def is_abstract(type:ir.Type) -> bool:
131
- return types.is_abstract_type(type)
132
-
133
- def to_type(value: ir.Value|ir.Field) -> ir.Type:
134
- if isinstance(value, (ir.Var, ir.Field, ir.Literal)):
135
- return value.type
136
-
137
- if isinstance(value, tuple):
138
- return types.AnyList
139
-
140
- if isinstance(value, ir.Relation):
141
- return types.AnyList
142
-
143
- raise TypeError(f"Cannot determine IR type for value: {value} of type {type(value).__name__}")
144
-
145
- def type_matches(actual:ir.Type, expected:ir.Type, allow_expected_parents=False) -> bool:
146
- """
147
- True iff we can use a value of the actual type when expecting the expected type.
148
-
149
- TODO: document allow_expected_parents (useful for checking that a Person is an Adult)
150
- """
151
- # exact match
152
- if actual == expected:
153
- return True
154
-
155
- # any matches anything
156
- if actual == types.Any or expected == types.Any:
157
- return True
158
-
159
- # any entity matches any entity (surprise surprise!)
160
- if extends_any_entity(expected) and not is_primitive(actual):
161
- return True
162
-
163
- # all decimals match across each other
164
- if types.is_decimal(actual) and types.is_decimal(expected):
165
- return True
166
-
167
- # scalar matches with super-type handling
168
- is_scalar = isinstance(actual, ir.ScalarType)
169
- exp_is_scalar = isinstance(expected, ir.ScalarType)
170
- if is_scalar and any([type_matches(parent, expected) for parent in actual.super_types]):
171
- return True
172
- if allow_expected_parents and exp_is_scalar and any([type_matches(actual, parent, allow_expected_parents) for parent in expected.super_types]):
173
- return True
174
- if not is_primitive(expected) and exp_is_scalar and actual in ENTITY_LIKES:
175
- return True
176
-
177
- # a union type matches if any of its types match the expected type
178
- if isinstance(actual, ir.UnionType):
179
- for t in actual.types:
180
- if type_matches(t, expected):
181
- return True
182
-
183
- # types that match Number
184
- if actual == types.Number and types.is_number(expected):
185
- return True
186
- if expected == types.Number and types.is_number(actual):
187
- return True
188
- return False
189
-
190
-
191
- def conversion_allowed(arg:ir.Value, actual:ir.Type, expected:ir.Type, arg_types:set[ir.Type]=set()) -> bool:
192
- return conversion_cost(arg, actual, expected, arg_types) < float("inf")
193
-
194
- def literal_conversion_allowed(actual:ir.Type, expected:ir.Type) -> bool:
195
- if actual in (types.Int64, types.Int128) and (expected == types.Hash or types.is_number(expected)):
196
- return True
197
- elif types.is_decimal(actual) and expected == types.Float:
198
- return True
199
- elif types.is_decimal(actual) and types.is_decimal(expected):
200
- return True
201
- return False
202
-
203
- def conversion_cost(arg: ir.Value, actual:ir.Type, expected:ir.Type, arg_types:set[ir.Type]) -> float:
204
- if type_matches(actual, expected):
205
- return 0
206
-
207
- # if we have a type variable and all the types in the expression
208
- # match, then there's no promotion needed and this is a valid overload
209
- if expected is types.EntityTypeVar and not is_primitive(actual) and len(arg_types) == 1:
210
- return 0
211
-
212
- # Literal numbers can be converted to other number types (but not to value types).
213
- if isinstance(arg, ir.Literal):
214
- if literal_conversion_allowed(actual, expected):
215
- return 50
216
-
217
- # Value types that don't match
218
- if is_value_type(actual) and is_value_type(expected):
219
- return float("inf")
220
-
221
- base_actual = to_base_primitive(actual)
222
- base_expected = to_base_primitive(expected)
223
-
224
- if not base_actual or not base_expected:
225
- return float("inf")
226
-
227
- if type_matches(base_actual, base_expected):
228
- return 0
229
-
230
- return conversion_lattice_cost(base_actual, base_expected)
231
-
232
-
233
- def merge_types(type1: ir.Type, type2: ir.Type, is_literal1:bool, is_literal2:bool) -> ir.Type:
234
- if type1 == type2:
235
- return type1
236
-
237
- # give precedence to nominal types (e.g. merging USD(decimal) with decimal gives USD(decimal))
238
- base_primitive_type1 = to_base_primitive(type1)
239
- base_primitive_type2 = to_base_primitive(type2)
240
- if base_primitive_type1 == base_primitive_type2:
241
- if is_base_primitive(type1):
242
- return type2
243
- elif is_base_primitive(type2):
244
- return type1
245
-
246
- combined = ordered_set()
247
- types_to_process = [type1, type2]
248
-
249
- # Iterative flattening of union types
250
- while types_to_process:
251
- t = types_to_process.pop()
252
- if isinstance(t, ir.UnionType):
253
- types_to_process.extend(t.types)
254
- else:
255
- combined.add(t)
256
-
257
- # If we have multiple types and Any is one of them, remove Any
258
- if len(combined) > 1 and types.Any in combined:
259
- combined.remove(types.Any)
260
-
261
- # If we have multiple types and one is a literal and the other is not,
262
- # we can try to convert the literal to the other type.
263
- if len(combined) > 1:
264
- if is_literal1 and not is_literal2 and literal_conversion_allowed(type1, type2):
265
- return type2
266
- if is_literal2 and not is_literal1 and literal_conversion_allowed(type2, type1):
267
- return type1
268
-
269
- # Return single type or create a union
270
- return next(iter(combined)) if len(combined) == 1 else f.union_type(list(combined))
271
-
272
- def to_base_primitive(type:ir.Type) -> Optional[ir.Type]:
273
- if isinstance(type, ir.ScalarType):
274
- if is_base_primitive(type):
275
- return type
276
- # walk the hierarchy to find a base primitive
277
- for parent in type.super_types:
278
- if found := to_base_primitive(parent):
279
- return found
280
- if isinstance(type, ir.UnionType):
281
- for t in type.types:
282
- if found := to_base_primitive(t):
283
- return found
284
- return None
285
-
286
- def is_value_type(type:ir.Type):
287
- return isinstance(type, ir.ScalarType) and is_primitive(type) and not is_base_primitive(type)
288
-
289
- def is_base_primitive(type:ir.Type) -> bool:
290
- return type in _NON_PARAMETRIC_PRIMITIVES or types.is_decimal(type)
291
-
292
- def is_primitive(type:ir.Type) -> bool:
293
- return to_base_primitive(type) is not None
294
-
295
- def extends_any_entity(type:ir.Type) -> bool:
296
- if type == types.AnyEntity:
297
- return True
298
- if isinstance(type, ir.ScalarType):
299
- for parent in type.super_types:
300
- if extends_any_entity(parent):
301
- return True
302
- return False
303
-
304
- def invalid_type(type:ir.Type) -> bool:
305
- if isinstance(type, ir.UnionType):
306
- # if there are multiple primitives, or a primtive and a non-primitive
307
- # then we have an invalid type
308
- if len(type.types) > 1:
309
- return any([is_primitive(t) for t in type.types])
310
- return False
311
-
312
- def try_preserve_type(types:set[ir.Type]) -> Optional[ir.Type]:
313
- # we keep the input type as the output type if either all inputs
314
- # are the exact same type or there's one nominal and its base primitive
315
- # type, e.g. USD + Decimal
316
- if len(types) == 1:
317
- return next(iter(types))
318
- if len(types) == 2:
319
- t1, t2 = types
320
- # type preservation is not applicable to decimal types
321
- if isinstance(t1, ir.DecimalType) and isinstance(t2, ir.DecimalType):
322
- return None
323
- base_equivalent = type_matches(t1, t2, allow_expected_parents=True)
324
- if base_equivalent:
325
- # as long as one of the types is a base primitive, we can use the
326
- # other type as final preserved type
327
- if is_base_primitive(t1):
328
- return t2
329
- elif is_base_primitive(t2):
330
- return t1
331
- return None
332
-
333
- # Was this variable created for a shared literal?
334
- def var_is_from_literal(var: ir.Var) -> bool:
335
- return var.name.startswith("__literal__")
336
-
337
- #--------------------------------------------------
338
- # Type Errors
339
- #--------------------------------------------------
340
-
341
- @dataclass
342
- class TyperError():
343
- node: ir.Node
344
-
345
- @dataclass
346
- class TypeMismatch(TyperError):
347
- expected: ir.Type
348
- actual: ir.Type
349
- def __str__(self):
350
- return f"[red bold][Type Mismatch][/red bold] expected [yellow]{to_name(self.expected)}[/yellow], got [red]{to_name(self.actual)}[/red]: [white]{str(self.node).strip()}[/white]"
351
-
352
- @dataclass
353
- class InvalidType(TyperError):
354
- type: ir.Type
355
- def __str__(self):
356
- return f"[red bold][Invalid Type][/red bold] incompatible types [red]{to_name(self.type)}[/red]: [white]{str(self.node).strip()}[/white]"
357
-
358
- @dataclass
359
- class UnresolvedOverload(TyperError):
360
- arg_types: list[ir.Type]
361
- def __str__(self):
362
- assert isinstance(self.node, (ir.Lookup, ir.Update, ir.Aggregate))
363
- rel = to_relation(self.node)
364
- types = ', '.join([to_name(t) for t in self.arg_types])
365
- return f"[red bold][Unresolved Overload][/red bold] [yellow]{rel.name}({types})[/yellow]: [white]{str(self.node).strip()}[/white]"
366
-
367
- @dataclass
368
- class UnresolvedType(TyperError):
369
- def __str__(self):
370
- return f"[red bold][Unresolved Type][/red bold] [white]{str(self.node).strip()}[/white]"
371
- pass
372
-
373
- class TyperContextEnricher(visitor.Visitor):
374
- def __init__(self):
375
- super().__init__()
376
- # store mapping from the concept population relation var id to a concept population type
377
- self.concept_population_types:dict[int, ir.Type] = {}
378
-
379
- def visit_lookup(self, node: ir.Lookup, parent: Optional[ir.Node]):
380
- rel = to_relation(node)
381
- if helpers.is_concept_lookup(rel):
382
- for arg, field in zip(node.args, rel.fields):
383
- if isinstance(arg, ir.Var):
384
- arg_type = arg.type
385
- field_type = field.type
386
- # When the rule declares something like `Adult(v::Person)`, we must record that `v` is actually of type
387
- # `Adult` so this refined type is remembered for later checks.
388
- if field_type != arg_type and type_matches(arg_type, field_type, True):
389
- self.concept_population_types[arg.id] = field_type
390
-
391
- #--------------------------------------------------
392
- # Propagation Network
393
- #--------------------------------------------------
394
-
395
- # The core idea of the typer is to build a propagation network where nodes are vars, fields,
396
- # or overloaded lookups/updates/aggregates. The intuition is that _all_ types in the IR
397
- # ultimately flow from relation fields, so if we figure those out we just need to propagate
398
- # their types to unknown vars, which may then flow into other fields and so on.
399
- #
400
- # This means the network only needs to contain nodes that either directly flow into
401
- # an abstract node or are themselves abstract. We need to track overloads because
402
- # their arguments effectively act like abstract vars until we've resolved the final types.
403
-
404
- Node = Union[ir.Var, ir.Field, ir.Lookup, ir.Update, ir.Aggregate, ir.Literal]
405
-
406
- class PropagationNetwork():
407
- def __init__(self):
408
-
409
- # track the set of nodes that represent entry points into the network
410
- self.roots = ordered_set()
411
- # we separately want to track nodes that were loaded from a previous run
412
- # so that even if we have edges to them, we _still_ consider them roots
413
- # and properly propagate types from them at the beginning
414
- self.loaded_roots = set()
415
- self.edges:dict[Node, dict[int, Node]] = defaultdict(dict)
416
- self.has_incoming = set()
417
- self.type_requirements:dict[Node, OrderedSet[ir.Field]] = defaultdict(lambda: ordered_set())
418
-
419
- self.errors:list[TyperError] = []
420
- # all fields for which types were resolved
421
- self.fields = set()
422
- self.resolved_types:dict[int, ir.Type] = {}
423
- # overloads resolved for a lookup/update/aggregate, by node id
424
- self.resolved_overloads:dict[int, list[ir.Relation]] = {}
425
- # if the node resolves to an overload the uses GenericDecimal, the concrete
426
- # DecimalType to be used (assumes there's a single overload with decimals for a node)
427
- self.resolved_overload_decimal:dict[int, ir.DecimalType] = {}
428
- self.node_is_literal:dict[int, bool] = {}
429
-
430
- #--------------------------------------------------
431
- # Mismatches
432
- #--------------------------------------------------
433
-
434
- def mismatch(self, node:Node, expected:ir.Type, actual:ir.Type):
435
- self.errors.append(TypeMismatch(node, expected, actual))
436
-
437
- def invalid_type(self, node:Node, type:ir.Type):
438
- self.errors.append(InvalidType(node, type))
439
-
440
- def unresolved_overload(self, node:ir.Lookup|ir.Update|ir.Aggregate):
441
- self.errors.append(UnresolvedOverload(node, [self.resolve(a) for a in node.args]))
442
-
443
- def unresolved_type(self, node:Node):
444
- self.errors.append(UnresolvedType(node))
445
-
446
- def has_errors(self, node:Node) -> bool:
447
- for mismatch in self.errors:
448
- if mismatch.node == node:
449
- return True
450
- return False
451
-
452
- #--------------------------------------------------
453
- # Types and Edges
454
- #--------------------------------------------------
455
-
456
- def add_edge(self, source:Node, target:Node):
457
- if target not in self.loaded_roots:
458
- self.roots.remove(target)
459
- if source not in self.has_incoming:
460
- self.roots.add(source)
461
- self.edges[source][target.id] = target
462
- self.has_incoming.add(target)
463
-
464
- def add_type(self, node:Node, type:ir.Type, is_literal:bool):
465
- if isinstance(node, ir.Field):
466
- self.fields.add(node)
467
-
468
- if node.id in self.resolved_types:
469
- if isinstance(node, ir.Literal) and self.resolved_types[node.id] == node.type:
470
- # if the previous "resolved type" was just the literal type itself, we can
471
- # replace it; this is safe because literals are only part of one task
472
- self.resolved_types[node.id] = type
473
- else:
474
- self.resolved_types[node.id] = merge_types(self.resolved_types[node.id], type, self.node_is_literal[node.id], is_literal)
475
- else:
476
- self.resolved_types[node.id] = type
477
-
478
- if node.id in self.node_is_literal:
479
- is_literal &= self.node_is_literal[node.id]
480
- self.node_is_literal[node.id] = is_literal
481
-
482
- def add_type_requirement(self, source:Node, field:ir.Field):
483
- self.type_requirements[source].add(field)
484
-
485
- #--------------------------------------------------
486
- # Load previous types
487
- #--------------------------------------------------
488
-
489
- def load_types(self, type_dict:dict[ir.Field, ir.Type]):
490
- for node, type in type_dict.items():
491
- self.add_type(node, type, False)
492
- self.loaded_roots.add(node)
493
- self.roots.add(node)
494
-
495
- #--------------------------------------------------
496
- # Resolve
497
- #--------------------------------------------------
498
-
499
- def resolve(self, value:Node|ir.Value) -> ir.Type:
500
- if isinstance(value, (ir.Var, ir.Field)):
501
- return self.resolved_types.get(value.id) or to_type(value)
502
- assert not isinstance(value, (ir.Lookup, ir.Update, ir.Aggregate)), "Should never try to resolve a task"
503
- return to_type(value)
504
-
505
- #--------------------------------------------------
506
- # Overloads
507
- #--------------------------------------------------
508
-
509
- def resolve_overload_deps(self, op:ir.Lookup|ir.Update|ir.Aggregate, keep_known=False):
510
- # We need to find which args flow into this task, which flow out, and
511
- # if some are inputs, then they are required before we can resolve
512
- incoming:list[Node] = []
513
- outgoing:list[Node] = []
514
- required:list[Node] = []
515
- relation = to_relation(op)
516
- field_args = zip(relation.fields, [self.resolve(a) for a in op.args], op.args)
517
- has_inputs = any([field.input for field in relation.fields])
518
- for field, arg_type, arg in field_args:
519
- if not isinstance(arg, (ir.Var, ir.Literal)):
520
- continue
521
- arg_is_abstract = is_abstract(arg_type)
522
- if not arg_is_abstract and not keep_known:
523
- continue
524
- elif field.input or not arg_is_abstract:
525
- incoming.append(arg)
526
- required.append(arg)
527
- elif not has_inputs:
528
- incoming.append(arg)
529
- outgoing.append(arg)
530
- else:
531
- outgoing.append(arg)
532
-
533
- # check if the overloads of this relation are fully resolved, if any aren't
534
- # then their fields are incoming edges to this node
535
- for overload in relation.overloads:
536
- for field in overload.fields:
537
- resolved_type = self.resolve(field)
538
- if resolved_type != types.GenericDecimal and is_abstract(resolved_type):
539
- incoming.append(field)
540
- required.append(field)
541
-
542
- return incoming, outgoing, required
543
-
544
- def resolve_overload(self, op:ir.Lookup|ir.Update|ir.Aggregate) -> Optional[list[ir.Relation]]:
545
- # check if we have any unresolved args that are required, if all of our args
546
- # are unresolved (len(incoming) == len(relation.fields)) then we have no information
547
- # to try and resolve the overloads with
548
- incoming, outgoing, required = self.resolve_overload_deps(op)
549
- relation = to_relation(op)
550
- if required or len(incoming) == len(relation.fields):
551
- return
552
-
553
- overloads = relation.overloads
554
- if not overloads:
555
- overloads = [relation]
556
-
557
- # otherwise we compute the cost of each overload and return the set of relations
558
- # that have the lowest cost. This can be multiple in e.g. the Person.pets.name
559
- # case where Cat_name and Dog_name are equally valid
560
- inf = float("inf")
561
- min_cost = inf
562
- matches = []
563
- for overload in overloads:
564
- arg_types = set(self.resolve(arg) for arg, field in zip(op.args, overload.fields) if field.input)
565
- total = 0
566
- for arg, field in zip(op.args, overload.fields):
567
- arg_type = self.resolve(arg)
568
- field_type = self.resolve(field)
569
- total += conversion_cost(arg, arg_type, field_type, arg_types)
570
- if total == inf:
571
- break
572
- if total != inf and total <= min_cost:
573
- if total < min_cost:
574
- min_cost = total
575
- matches.clear()
576
- matches.append(overload)
577
- return matches
578
-
579
- #--------------------------------------------------
580
- # Propagation
581
- #--------------------------------------------------
582
-
583
- def propagate(self):
584
- edges = self.edges
585
- work_list = []
586
-
587
- # go through all the roots and find any that are not abstract, they'll
588
- # be the first nodes to push types through the network
589
- unhandled = ordered_set()
590
- for node in self.roots:
591
- if not isinstance(node, (ir.Var, ir.Field, ir.Literal)):
592
- continue
593
- node_type = self.resolve(node)
594
- if not is_abstract(node_type):
595
- is_literal = isinstance(node, ir.Literal) or (isinstance(node, ir.Var) and var_is_from_literal(node))
596
- self.add_type(node, node_type, is_literal)
597
- work_list.append(node)
598
- else:
599
- unhandled.add(node)
600
-
601
- # We need to visit nodes in topological order; that is we need to visit all predecessors
602
- # of a node before the node itself.
603
-
604
- # push known type nodes through the edges
605
- while work_list:
606
- source = work_list.pop(0)
607
- unhandled.remove(source)
608
- source_type = self.resolve(source)
609
- is_literal = self.node_is_literal.get(source.id, False)
610
- # check to see if the source has ended up with a set of types that
611
- # aren't valid, e.g. a union of primitives
612
- if invalid_type(source_type):
613
- self.invalid_type(source, source_type)
614
-
615
- # propagate our type to each outgoing edge
616
- for out in edges.get(source, {}).values():
617
- # if this is an overload then we need to try and resolve it
618
- if isinstance(out, (ir.Update, ir.Lookup, ir.Aggregate)):
619
- found = self.resolve_overload(out)
620
- if found is not None:
621
- start_arg_types = [self.resolve(arg) for arg in out.args]
622
- self.propagate_overloads(out, found)
623
- final_arg_types = [self.resolve(arg) for arg in out.args]
624
- for arg, start, final in zip(out.args, start_arg_types, final_arg_types):
625
- if start != final:
626
- work_list.append(arg)
627
- # otherwise, we just add to the outgoing node's type and if it
628
- # changes we add it to the work list
629
- elif start := self.resolve(out):
630
- self.add_type(out, source_type, is_literal)
631
- if start != self.resolve(out) or out in unhandled:
632
- work_list.append(out)
633
-
634
- for source in unhandled:
635
- self.unresolved_type(source)
636
-
637
- # now that we've pushed all the types through the network, we need to validate
638
- # that all type requirements of those nodes are met
639
- for node, fields in self.type_requirements.items():
640
- node_type = self.resolve(node)
641
- for field in fields:
642
- field_type = self.resolve(field)
643
- if not type_matches(node_type, field_type):
644
- node_base = to_base_primitive(node_type)
645
- field_base = to_base_primitive(field_type)
646
- if conversion_lattice_cost(node_base, field_base) == float("inf"):
647
- self.mismatch(node, field_type, node_type)
648
-
649
- # return the resolved type for fields only
650
- field_types = {}
651
- for field in self.fields:
652
- if field.id in self.resolved_types:
653
- field_types[field] = self.resolved_types[field.id]
654
- return field_types
655
-
656
-
657
- def propagate_overloads(self, node:ir.Lookup|ir.Update|ir.Aggregate, overloads:list[ir.Relation]):
658
- if not overloads:
659
- return self.unresolved_overload(node)
660
-
661
- # we've resolved the overloads, so store that
662
- self.resolved_overloads[node.id] = overloads
663
-
664
- # we need to determine the final types of our args but taking all the overloads
665
- # and adding the type of their fields back to the args.
666
- resolved_args = [self.resolve(a) for a in node.args]
667
- for overload in overloads:
668
- resolved_fields = [self.resolve(f) for f in overload.fields]
669
- if types.GenericDecimal in resolved_fields:
670
- # this overload contains generic decimals, so find which specific type of
671
- # decimal to use given the arguments being passed
672
- decimal, resolved_fields = self.specialize_decimal_overload(resolved_fields, resolved_args)
673
- self.resolved_overload_decimal[node.id] = decimal
674
-
675
- # if our overload preserves types, we check to see if there's a preserved
676
- # output type given the inputs and if so, shadow the field's type with the
677
- # preserved type
678
- if overload in TYPE_PRESERVERS:
679
- input_types = set([arg_type for field, arg_type
680
- in zip(overload.fields, resolved_args)
681
- if field.input])
682
- if out_type := try_preserve_type(input_types):
683
- resolved_fields = [field_type if field.input else out_type
684
- for field, field_type in zip(overload.fields, resolved_fields)]
685
-
686
- for field_type, arg_type, arg in zip(resolved_fields, resolved_args, node.args):
687
- if isinstance(arg, ir.Var) and is_abstract(arg_type):
688
- is_literal = var_is_from_literal(arg)
689
- self.add_type(arg, field_type, is_literal)
690
- elif isinstance(arg, ir.Literal) and arg_type != field_type:
691
- self.add_type(arg, field_type, True)
692
-
693
- return None
694
-
695
- def specialize_decimal_overload(self, field_types:list[ir.Type], arg_types:list[ir.Type]) -> Tuple[ir.DecimalType, list[ir.Type]]:
696
- """
697
- Find the decimal type to use for an overload that has GenericDecimals in its field_types,
698
- and which is being referred to with these arg_types.
699
-
700
- Return a tuple where the first element is the specialized decimal type, and the second
701
- element is a new list that contains the same types as field_types but with
702
- GenericDecimal replaced by this specialized decimal.
703
- """
704
- decimal = None
705
- for arg_type in arg_types:
706
- x = types.decimal_supertype(arg_type)
707
- if isinstance(x, ir.DecimalType):
708
- # the current specialization policy is to select the decimal with largest
709
- # scale and, if there multiple with the largest scale, the one with the
710
- # largest precision. This is safe because when converting a decimal to the
711
- # specialized decimal, we never truncate fractional digits (because we
712
- # selected the largest scale) and, if the non-fractional digits are too
713
- # large to fit the specialized decimal, we will have a runtime overflow,
714
- # which should alert the user of the problem.
715
- #
716
- # In the future we can implement more complex policies. For example,
717
- # snowflake has well documented behavior for how the output of operations
718
- # behave in face of different decimal types, and we may use that:
719
- # https://docs.snowflake.com/en/sql-reference/operators-arithmetic#scale-and-precision-in-arithmetic-operations
720
- if decimal is None or x.scale > decimal.scale or (x.scale == decimal.scale and x.precision > decimal.precision):
721
- decimal = x
722
- assert(isinstance(decimal, ir.DecimalType))
723
- return decimal, [decimal if field_type == types.GenericDecimal else field_type
724
- for field_type in field_types]
725
-
726
-
727
- #--------------------------------------------------
728
- # Display
729
- #--------------------------------------------------
730
-
731
- # draw the network as a mermaid graph for the debugger
732
- def to_mermaid(self, max_edges=500) -> str:
733
- resolved = self.resolved_types
734
- nodes = ordered_set()
735
- link_strs = []
736
- for src, dsts in self.edges.items():
737
- nodes.add(src)
738
- for dst in dsts.values():
739
- if len(link_strs) > max_edges:
740
- break
741
- nodes.add(dst)
742
- link_strs.append(f"n{src.id} --> n{dst.id}")
743
- if len(link_strs) > max_edges:
744
- break
745
-
746
- for src, dsts in self.type_requirements.items():
747
- nodes.add(src)
748
- for dst in dsts:
749
- if len(link_strs) > max_edges:
750
- break
751
- nodes.add(dst)
752
- link_strs.append(f"n{src.id} --> n{dst.id}")
753
- if len(link_strs) > max_edges:
754
- break
755
-
756
- def type_span(t:ir.Type) -> str:
757
- type_str = t.name if isinstance(t, ir.ScalarType) else str(t)
758
- return f"<span style='color:cyan;'>{type_str.strip()}</span>"
759
-
760
- def overload_span(rel:ir.Relation, arg_types:list[ir.Type]) -> str:
761
- args = []
762
- for field, arg_type in zip(rel.fields, arg_types):
763
- field_type = self.resolve(field)
764
- if not type_matches(arg_type, field_type) and field_type != types.EntityTypeVar:
765
- args.append(f"<span style='color:yellow;'>{str(arg_type).strip()} -> {str(field_type).strip()}</span>")
766
- elif isinstance(arg_type, ir.UnionType):
767
- args.append(type_span(field_type))
768
- else:
769
- args.append(type_span(arg_type))
770
- return f'{rel.name}({", ".join(args)})'
771
-
772
- node_strs = []
773
- for node in nodes:
774
- klass = ""
775
- if isinstance(node, ir.Var):
776
- ir_type = resolved.get(node.id) or self.resolve(node)
777
- type_str = type_span(ir_type)
778
- # if this is one of our vars that is a placeholder for a literal, just use the type
779
- if isinstance(ir_type, ir.ScalarType) and var_is_from_literal(node):
780
- label = f'(["Literal {type_str}"])'
781
- else:
782
- label = f'(["{node.name}: {type_str}"])'
783
- elif isinstance(node, ir.Literal):
784
- ir_type = resolved.get(node.id) or self.resolve(node)
785
- type_str = type_span(ir_type)
786
- label = f'(["Literal {type_str}"])'
787
- elif isinstance(node, ir.Field):
788
- ir_type = resolved.get(node.id) or self.resolve(node)
789
- type_str = type_span(ir_type)
790
- klass = ":::field"
791
- label = f"{{{{\"{node.name}: {type_str}\"}}}}"
792
- elif isinstance(node, (ir.Lookup, ir.Update, ir.Aggregate)):
793
- arg_types = [self.resolve(arg) for arg in node.args]
794
- if node.id in self.resolved_overloads:
795
- overloads = self.resolved_overloads[node.id]
796
- content = "<br/>".join([overload_span(o, arg_types) for o in overloads])
797
- else:
798
- content = overload_span(to_relation(node), arg_types)
799
- label = f'[/"{content}"/]'
800
- else:
801
- raise NotImplementedError(f"Unknown node type: {type(node)}")
802
- if self.has_errors(node):
803
- klass = ":::error"
804
- node_strs.append(f"n{node.id}{label}{klass}")
805
-
806
- node_str = "\n ".join(node_strs)
807
- link_str = "\n ".join(link_strs)
808
- template = f"""
809
- %%{{init: {{'theme':'dark', 'flowchart':{{'useMaxWidth':false, 'htmlLabels': true}}}}}}%%
810
- flowchart TD
811
- linkStyle default stroke:#666
812
- classDef field fill:#245,stroke:#478
813
- classDef error fill:#624,stroke:#945,color:#f9a
814
- classDef default stroke:#444,stroke-width:2px, font-size:12px
815
-
816
- %% nodes
817
- {node_str}
818
-
819
- %% edges
820
- {link_str}
821
- """
822
- return template
823
-
824
- # simplified, less verbose (compared to mermaid) output for snapshot testing
825
- def to_fish(self) -> str:
826
- resolved = self.resolved_types
827
- nodes = ordered_set()
828
- for src, dsts in self.edges.items():
829
- nodes.add(src)
830
- nodes.update(dsts.values())
831
- for src, dsts in self.type_requirements.items():
832
- nodes.add(src)
833
- nodes.update(dsts)
834
-
835
- def type_to_str(t:ir.Type) -> str:
836
- type_str = t.name if isinstance(t, ir.ScalarType) else str(t)
837
- return type_str.strip()
838
-
839
- def overload_str(rel:ir.Relation, arg_types:list[ir.Type]) -> str:
840
- args = []
841
- for field, arg_type in zip(rel.fields, arg_types):
842
- field_type = self.resolve(field)
843
- if not type_matches(arg_type, field_type):
844
- args.append(f"{str(arg_type).strip()} -?> {str(field_type).strip()}")
845
- elif isinstance(arg_type, ir.UnionType):
846
- args.append(type_to_str(field_type))
847
- else:
848
- args.append(type_to_str(arg_type))
849
- return f'{rel.name}({", ".join(args)})'
850
-
851
- def node_kind(node:ir.Node) -> str:
852
- if isinstance(node, (ir.Lookup, ir.Update, ir.Aggregate)):
853
- return "overload"
854
- return type(node).__name__.lower()
855
-
856
- def error_info(err:TyperError) -> str:
857
- if isinstance(err, TypeMismatch):
858
- return f'Type Mismatch|expected {to_name(err.expected)}, got {to_name(err.actual)}'
859
- return f'{type(err).__name__}'
860
-
861
- nl = "\n"
862
- node_strs = []
863
- for node in nodes:
864
- info = ""
865
- if isinstance(node, ir.Var):
866
- ir_type = resolved.get(node.id) or self.resolve(node)
867
- if not(isinstance(ir_type, ir.ScalarType) and var_is_from_literal(node)):
868
- info = f'{node.name}|{type_to_str(ir_type)}'
869
- elif isinstance(node, ir.Literal):
870
- ir_type = resolved.get(node.id) or self.resolve(node)
871
- if not(isinstance(ir_type, ir.ScalarType)):
872
- info = f'Literal|{type_to_str(ir_type)}'
873
- elif isinstance(node, ir.Field):
874
- ir_type = resolved.get(node.id) or self.resolve(node)
875
- info = f'{node.name}|{type_to_str(ir_type)}'
876
- elif isinstance(node, (ir.Lookup, ir.Update, ir.Aggregate)):
877
- arg_types = [self.resolve(arg) for arg in node.args]
878
- if node.id in self.resolved_overloads:
879
- overloads = self.resolved_overloads[node.id]
880
- content = nl.join([overload_str(o, arg_types) for o in overloads])
881
- else:
882
- content = overload_str(to_relation(node), arg_types)
883
- info = f'{content}'
884
- else:
885
- raise NotImplementedError(f"Unknown node type: {type(node)}")
886
-
887
- if info:
888
- error_suffix = " !" if self.has_errors(node) else ""
889
- node_strs.append(f'{node_kind(node)}|{info}{error_suffix}')
890
-
891
- node_strs.sort()
892
- if self.errors:
893
- node_strs.append("---ERRORS---")
894
- for err in self.errors:
895
- node_strs.append(f'{error_info(err)} ({str(err.node).strip()})')
896
-
897
- return f"""{nl.join(node_strs)}"""
898
-
899
- #--------------------------------------------------
900
- # Analyzer
901
- #--------------------------------------------------
902
-
903
- class Analyzer(visitor.Visitor):
904
- def __init__(self):
905
- super().__init__()
906
- self.net = PropagationNetwork()
907
- self.context_enricher = TyperContextEnricher()
908
-
909
- # this is a map of literal types to a var representing that literal in
910
- # the graph. This allows us to collapse all literals into a single node
911
- # and avoids exploding node count if lots of data gets added directly
912
- self.shared_literal_vars:dict[ir.Type, ir.Var] = {
913
- t: f.var(f"__literal__{t.name}", t)
914
- for t in types.builtin_types
915
- if isinstance(t, ir.ScalarType)
916
- }
917
-
918
- #--------------------------------------------------
919
- # Literal types
920
- #--------------------------------------------------
921
-
922
- # given a literal type, lookup or create a var for it
923
- def shared_literal_var(self, node:ir.Type) -> ir.Var:
924
- assert isinstance(node, ir.ScalarType)
925
- if node not in self.shared_literal_vars:
926
- self.shared_literal_vars[node] = f.var(node.name, node)
927
- return self.shared_literal_vars[node]
928
-
929
- #--------------------------------------------------
930
- # Lookups + Aggregates
931
- #--------------------------------------------------
932
-
933
- def visit_lookup(self, node: ir.Lookup, parent: Optional[ir.Node]):
934
- self.visit_rel_op(node, parent)
935
-
936
- def visit_aggregate(self, node: ir.Aggregate, parent: ir.Node | None):
937
- self.visit_rel_op(node, parent)
938
-
939
- def visit_rel_op(self, node: ir.Lookup|ir.Aggregate, parent: Optional[ir.Node]):
940
- rel = to_relation(node)
941
- if isinstance(node, ir.Lookup) and builtins.is_eq(rel):
942
- return self.visit_eq(node, parent)
943
- if isinstance(node, ir.Lookup) and rel == builtins.cast:
944
- return self.visit_cast(node, parent)
945
-
946
- if rel.overloads:
947
- return self.visit_overloaded(node, parent)
948
-
949
- # if this is a population check, then it's fine to pass a subtype in to do the check
950
- # e.g. Employee(Person) is a valid way to check if a person is an employee
951
- is_concept_lookup = helpers.is_concept_lookup(rel)
952
- arg_types = set(self.net.resolve(arg) for arg, field in zip(node.args, rel.fields) if field.input)
953
- for arg, field in zip(node.args, rel.fields):
954
- field_type = field.type
955
- arg_type = self.net.resolve(arg)
956
- is_var = isinstance(arg, ir.Var)
957
- if not type_matches(arg_type, field_type, is_concept_lookup or is_abstract(arg_type)):
958
- # If the rule explicitly specifies a refined type, e.g. `Adult(v::Person)`,
959
- # then `v` should be treated as `Adult` (not just `Person`).
960
- # In that case, check the declared population type first before checking conversions.
961
- if is_var and self.context_enricher.concept_population_types.get(arg.id, arg_type) == field_type:
962
- continue
963
- # Do not complain if we can convert the arg to the field type.
964
- if not conversion_allowed(arg, arg_type, field_type, arg_types):
965
- self.net.mismatch(node, field_type, arg_type)
966
- continue
967
- # if we have an abstract var then this field will ultimately propagate to that
968
- # var's type
969
- elif is_var and is_abstract(arg_type) and not field.input:
970
- self.net.add_edge(field, arg)
971
- continue
972
-
973
- return None
974
-
975
- #--------------------------------------------------
976
- # Overloads
977
- #--------------------------------------------------
978
-
979
- def visit_overloaded(self, node: ir.Lookup|ir.Update|ir.Aggregate, parent: Optional[ir.Node]):
980
- incoming, outgoing, required = self.net.resolve_overload_deps(node, keep_known=True)
981
- for arg in incoming:
982
- self.net.add_edge(arg, node)
983
- for arg in outgoing:
984
- self.net.add_edge(node, arg)
985
-
986
- #--------------------------------------------------
987
- # Eq
988
- #--------------------------------------------------
989
-
990
- def visit_eq(self, node: ir.Lookup, parent: Optional[ir.Node]):
991
- (left, right) = node.args
992
- left_type = self.net.resolve(left)
993
- right_type = self.net.resolve(right)
994
- if is_abstract(left_type) and is_abstract(right_type):
995
- assert isinstance(left, ir.Var) and isinstance(right, ir.Var)
996
- # if both sides are abstract, then whatever we find out about
997
- # either should propagate to the other
998
- self.net.add_edge(left, right)
999
- self.net.add_edge(right, left)
1000
- elif is_abstract(left_type):
1001
- assert isinstance(left, ir.Var)
1002
- if isinstance(right, ir.Var):
1003
- self.net.add_edge(right, left)
1004
- else:
1005
- literal_var = self.shared_literal_var(right_type)
1006
- self.net.add_edge(literal_var, left)
1007
- elif is_abstract(right_type):
1008
- assert isinstance(right, ir.Var)
1009
- if isinstance(left, ir.Var):
1010
- self.net.add_edge(left, right)
1011
- else:
1012
- literal_var = self.shared_literal_var(left_type)
1013
- self.net.add_edge(literal_var, right)
1014
- elif not type_matches(left_type, right_type):
1015
- if not conversion_allowed(left, left_type, right_type) and not conversion_allowed(right, right_type, left_type):
1016
- self.net.mismatch(node, left_type, right_type)
1017
-
1018
- #--------------------------------------------------
1019
- # Cast
1020
- #--------------------------------------------------
1021
-
1022
- def visit_cast(self, node: ir.Lookup, parent: Optional[ir.Node]):
1023
- # Cast has fields: to_type (input), source (input), target (output)
1024
- assert len(node.args) == 3, f"Expected 3 arguments for cast builtin, but got: {node.args}"
1025
- (to_type, source, target) = node.args
1026
- assert isinstance(to_type, ir.Type), f"Invalid target type for cast: {to_type}"
1027
- assert isinstance(target, ir.Var), f"Invalid target variable for cast: {target}"
1028
-
1029
- if not is_abstract(to_type):
1030
- # If target is abstract, it should get the type from to_type
1031
- target_type = self.net.resolve(target)
1032
- if is_abstract(target_type) and isinstance(target, ir.Var):
1033
- self.net.add_type(target, to_type, False)
1034
-
1035
- #--------------------------------------------------
1036
- # Update
1037
- #--------------------------------------------------
1038
-
1039
- def visit_update(self, node: ir.Update, parent: Optional[ir.Node]):
1040
- rel = node.relation
1041
- # if this is a population check, then it's fine to pass a subtype in to do the population
1042
- # e.g. Employee(Person) should be a valid way to populate a person
1043
- allow_any_parents = helpers.is_concept_lookup(rel)
1044
- for arg, field in zip(node.args, rel.fields):
1045
- field_type = field.type
1046
- arg_type = self.net.resolve(arg)
1047
- is_var = isinstance(arg, ir.Var)
1048
-
1049
- # if the arg is abstract, but the field isn't, then we need to make
1050
- # sure that once the arg is resolved we check that it matches the field
1051
- # type
1052
- if is_var and is_abstract(arg_type) and not is_abstract(field_type):
1053
- self.net.add_type_requirement(arg, field)
1054
-
1055
- # if the field is abstract, then eventually this var will help determine
1056
- # the field's type
1057
- elif is_abstract(field_type):
1058
- source = self.shared_literal_var(arg_type) if not is_var else arg
1059
- self.net.add_edge(source, field)
1060
-
1061
- elif not type_matches(arg_type, field_type, allow_expected_parents=allow_any_parents):
1062
- # If the rule explicitly specifies a refined type, e.g. `Adult(v::Person)`,
1063
- # then `v` should be treated as `Adult` (not just `Person`).
1064
- # In that case, check the declared population type first before checking conversions.
1065
- if is_var and self.context_enricher.concept_population_types.get(arg.id, arg_type) == field_type:
1066
- continue
1067
- if not conversion_allowed(arg, arg_type, field_type):
1068
- self.net.mismatch(node, field_type, arg_type)
1069
-
1070
- #--------------------------------------------------
1071
- # Replacer
1072
- #--------------------------------------------------
1073
-
1074
- # Once we've pushed all the types through the network, we need to replace the types of
1075
- # fields and vars that we may have discovered. We also need to replace overloaded lookups
1076
- # with the choosen overloads and do any conversions that are needed.
1077
- @dataclass
1078
- class Replacer(visitor.Rewriter):
1079
- net: PropagationNetwork = dataclasses.field(init=True)
1080
- new_relations:OrderedSet[ir.Relation] = dataclasses.field(default_factory=OrderedSet[ir.Relation])
1081
-
1082
- def handle_model(self, model: ir.Model, parent: None):
1083
- model = super().handle_model(model, parent)
1084
- return model.reconstruct(
1085
- relations=model.relations | self.new_relations
1086
- )
1087
-
1088
- def handle_field(self, node: ir.Field, parent: ir.Node):
1089
- if node.id in self.net.resolved_types:
1090
- return f.field(node.name, self.net.resolved_types[node.id], node.input)
1091
- return node
1092
-
1093
- def handle_var(self, node: ir.Var, parent: ir.Node):
1094
- if node.id in self.net.resolved_types:
1095
- return f.var(node.name, self.net.resolved_types[node.id])
1096
- return node
1097
-
1098
- def handle_literal(self, node: ir.Literal, parent: ir.Node):
1099
- # Up until now, we allow literals to have a non-builtin types. This code converts the value
1100
- # to a builtin Python type and lifts the literal to that supertype.
1101
- t = self.net.resolved_types[node.id] if node.id in self.net.resolved_types else node.type
1102
- v, t = self.convert_literal_value(node.value, t)
1103
- return node.reconstruct(value=v, type=t)
1104
-
1105
- def handle_update(self, node: ir.Update, parent: ir.Node):
1106
- node = super().handle_update(node, parent)
1107
-
1108
- # we may do conversions, so we can end up with multiple tasks
1109
- # in this branch and we need to track what the final args are
1110
- tasks = []
1111
- final_args = []
1112
- for arg, field in zip(node.args, node.relation.fields):
1113
- arg_type = to_type(arg)
1114
- field_type = to_type(field)
1115
- # the typer previously made sure that this should be valid so
1116
- # a type mismatch means we need to convert as long as this isn't
1117
- # a type variable
1118
- if field_type != types.EntityTypeVar and not type_matches(arg_type, field_type):
1119
- arg_base = to_base_primitive(arg_type)
1120
- field_base = to_base_primitive(field_type)
1121
- if arg_base is not None and field_base is not None and conversion_allowed(arg, arg_base, field_base):
1122
- new_arg = self.convert(arg, arg_base, field_base, tasks)
1123
- final_args.append(new_arg)
1124
- else:
1125
- final_args.append(arg)
1126
- else:
1127
- final_args.append(arg)
1128
- tasks.append(node.reconstruct(args=tuple(final_args)))
1129
-
1130
- if len(tasks) == 1:
1131
- return tasks[0]
1132
- else:
1133
- return f.logical(tasks, [])
1134
-
1135
- def handle_aggregate(self, node: ir.Aggregate, parent: ir.Node):
1136
- node = super().handle_aggregate(node, parent)
1137
- lookup_args = list(node.args)
1138
- hoists = helpers.get_agg_outputs(node)
1139
-
1140
- if len(node.aggregation.fields) == len(lookup_args):
1141
- tasks = []
1142
- for i in range(len(lookup_args)):
1143
- if not conversion_allowed(lookup_args[i], to_type(lookup_args[i]), node.aggregation.fields[i].type):
1144
- self.net.mismatch(node, node.aggregation.fields[i].type, to_type(lookup_args[i]))
1145
- elif not type_matches(to_type(lookup_args[i]), node.aggregation.fields[i].type):
1146
- lookup_args[i] = self.convert(lookup_args[i], to_type(lookup_args[i]), node.aggregation.fields[i].type, tasks)
1147
- tasks.append(node.reconstruct(args=tuple(lookup_args)))
1148
- if len(tasks) == 1:
1149
- return tasks[0]
1150
- else:
1151
- return f.logical(tasks, hoists)
1152
-
1153
- return node
1154
-
1155
- def handle_lookup(self, node: ir.Lookup, parent: ir.Node):
1156
- node = super().handle_lookup(node, parent)
1157
- lookup_args = node.args
1158
-
1159
- # we can resolve to multiple overloads, that we'd need to union
1160
- # so we'll need to hoist all the vars being output to make sure
1161
- # everything joins correctly
1162
- hoists = helpers.get_outputs(node)
1163
- branches:list[ir.Logical] = []
1164
-
1165
- # Special case this solver primitive because the type system cannot handle what it
1166
- # needs, which is an input field types as List[Union[Int64,Float64,String,Hash]].
1167
- # So this code makes sure that any in128 that flows into the second argument, which
1168
- # is represented as a tuple, is converted into an int64, which is lossy but should
1169
- # work for most cases
1170
- if node.relation == builtins.rel_primitive_solverlib_fo_appl and len(node.relation.fields) == 3 and len(lookup_args) == 3:
1171
- tasks = []
1172
- # Make lookup_args mutable.
1173
- lookup_args = list(lookup_args)
1174
-
1175
- # Convert the first and third arguments to the field types.
1176
- for i in [0, 2]:
1177
- if not conversion_allowed(lookup_args[i], to_type(lookup_args[i]), node.relation.fields[i].type):
1178
- self.net.mismatch(node, node.relation.fields[i].type, to_type(lookup_args[i]))
1179
- elif not type_matches(to_type(lookup_args[i]), node.relation.fields[i].type):
1180
- lookup_args[i] = self.convert(lookup_args[i], to_type(lookup_args[i]), node.relation.fields[i].type, tasks)
1181
-
1182
- varargs = lookup_args[1]
1183
- final_varargs = []
1184
- assert isinstance(varargs, tuple)
1185
- for arg in varargs:
1186
- t = to_type(arg)
1187
- if t == types.Int128:
1188
- final_varargs.append(self.convert(arg, t, types.Int64, tasks))
1189
- else:
1190
- final_varargs.append(arg)
1191
- lookup_args[1] = tuple(final_varargs)
1192
- tasks.append(node.reconstruct(args=tuple(lookup_args)))
1193
- branches.append(f.logical(tasks, hoists))
1194
-
1195
- elif builtins.is_eq(node.relation):
1196
- tasks = []
1197
-
1198
- # We need to handle eq specially because its arguments can be converted symmetrically
1199
- (left, right) = lookup_args
1200
- left_type = to_type(left)
1201
- right_type = to_type(right)
1202
- mismatch = False
1203
- if not type_matches(left_type, right_type):
1204
- if conversion_allowed(left, left_type, right_type):
1205
- new_left = self.convert(left, left_type, right_type, tasks)
1206
- final_args = [new_left, right]
1207
- elif conversion_allowed(right, right_type, left_type):
1208
- new_right = self.convert(right, right_type, left_type, tasks)
1209
- final_args = [left, new_right]
1210
- else:
1211
- self.net.mismatch(node, left_type, right_type)
1212
- final_args = [left, right]
1213
- mismatch = True
1214
- else:
1215
- final_args = [left, right]
1216
-
1217
- if not mismatch:
1218
- min_cost = float('inf')
1219
- arg_types = set(to_type(arg) for arg in final_args)
1220
- resolved = []
1221
- for o in node.relation.overloads:
1222
- total = 0
1223
- for arg, field in zip(final_args, o.fields):
1224
- arg_type = to_type(arg)
1225
- field_type = to_type(field)
1226
- total += conversion_cost(arg, arg_type, field_type, arg_types)
1227
- if total <= min_cost:
1228
- if total < min_cost:
1229
- resolved.clear()
1230
- min_cost = total
1231
- resolved.append(o)
1232
-
1233
- if len(resolved) == 1:
1234
- tasks.append(f.lookup(resolved[0], final_args))
1235
- else:
1236
- # If we cannot resolve the overload, just leave it.
1237
- self.net.unresolved_overload(node)
1238
- tasks.append(f.lookup(node.relation, final_args))
1239
- else:
1240
- # If there's a mismatch, just leave the original relation.
1241
- tasks.append(f.lookup(node.relation, final_args))
1242
-
1243
- branches.append(f.logical(tasks, hoists))
1244
- elif node.relation == builtins.cast:
1245
- assert len(node.args) == 3, f"Invalid number of arguments for cast: {node.args}"
1246
- (tgt_type, src, tgt) = node.args
1247
- assert isinstance(tgt_type, ir.Type), f"Invalid target type for cast: {tgt_type}"
1248
- src_type = to_type(src)
1249
-
1250
- # if we are casting a literal into a var, we can just set the var to a new literal
1251
- # with the same value but with the same type as the variable
1252
- if isinstance(src, ir.Literal) and literal_conversion_allowed(src_type, tgt_type):
1253
- annos = node.annotations
1254
- return f.lookup(builtins.eq, (ir.Literal(tgt_type, src.value), tgt), annos=(list(annos) + [builtins.from_cast_annotation]))
1255
-
1256
- src_base = to_base_primitive(src_type)
1257
- tgt_base = to_base_primitive(tgt_type)
1258
-
1259
- if src_base and tgt_base and src_base == tgt_base:
1260
- annos = node.annotations
1261
- return f.lookup(builtins.eq, (src, tgt), annos=(list(annos) + [builtins.from_cast_annotation]))
1262
-
1263
- if conversion_allowed(node.args[0], src_type, tgt_type):
1264
- if tgt_base:
1265
- return node.reconstruct(args=(tgt_base, src, tgt))
1266
- else:
1267
- return node
1268
- else:
1269
- # TODO: we are simply ignoring this, assuming there's some way to cast it
1270
- # self.net.mismatch(node, src_type, tgt_type)
1271
- return node
1272
- else:
1273
- if node.id in self.net.resolved_overloads:
1274
- resolved = self.net.resolved_overloads[node.id]
1275
- else:
1276
- resolved = [node.relation]
1277
- decimal_type = self.net.resolved_overload_decimal.get(node.id)
1278
-
1279
- for overload in resolved:
1280
- # we may do conversions, so we can end up with multiple tasks
1281
- # in this branch and we need to track what the final args are
1282
- tasks = []
1283
- final_args = []
1284
-
1285
- for arg, field in zip(lookup_args, overload.fields):
1286
- arg_type = to_type(arg)
1287
- field_type = to_type(field)
1288
- # the typer previously made sure that this should be valid so
1289
- # a type mismatch means we need to convert as long as this isn't
1290
- # a type variable
1291
- if field_type == types.GenericDecimal or (field_type != types.EntityTypeVar and not arg_type == field_type):
1292
- arg_base = to_base_primitive(arg_type)
1293
- field_base = to_base_primitive(field_type)
1294
- if field_base == types.GenericDecimal:
1295
- field_base = decimal_type
1296
- if arg_base is not None and field_base is not None and conversion_allowed(arg, arg_base, field_base):
1297
- new_arg = self.convert(arg, arg_base, field_base, tasks)
1298
- final_args.append(new_arg)
1299
- else:
1300
- final_args.append(arg)
1301
- else:
1302
- final_args.append(arg)
1303
- tasks.append(f.lookup(overload, final_args))
1304
- branches.append(f.logical(tasks, hoists))
1305
- # unwrap if we don't actually need a union
1306
- if len(branches) == 1:
1307
- if len(branches[0].body) == 1:
1308
- return branches[0].body[0]
1309
- else:
1310
- return branches[0]
1311
- else:
1312
- return f.union(branches, hoists)
1313
-
1314
- def convert(self, arg:ir.Value, actual:ir.Type, expected:ir.Type, tasks:list[ir.Task]) -> ir.Value:
1315
- if actual == expected:
1316
- return arg
1317
- value = None
1318
- if isinstance(arg, ir.Literal):
1319
- value = arg.value
1320
- elif isinstance(arg, (int, float, PyDecimal)):
1321
- value = arg
1322
- if value is not None:
1323
- if isinstance(value, int) and expected in (types.Int64, types.Int128):
1324
- if expected == types.Int64:
1325
- check_int64(value)
1326
- return f.literal(value, expected)
1327
- if isinstance(value, (int, float, PyDecimal)) and expected == types.Float:
1328
- return f.literal(float(value), expected)
1329
- if isinstance(value, (int, float, PyDecimal)) and types.is_decimal(expected):
1330
- # Converting str(value) rather than value avoids precision loss with Float->Decimal conversion.
1331
- return f.literal(PyDecimal(str(value)), expected)
1332
-
1333
- name = helpers.sanitize(arg.name + "_" + to_name(expected) if isinstance(arg, ir.Var) else f"v{to_name(expected)}")
1334
- expected_base = to_base_primitive(expected) or expected
1335
- new_arg = f.var(name, expected_base)
1336
- self.new_relations.add(builtins.cast)
1337
- tasks.append(f.lookup(builtins.cast, (expected_base, arg, new_arg)))
1338
- self.new_relations.add(builtins.cast)
1339
- return new_arg
1340
-
1341
- @staticmethod
1342
- def convert_literal_value(value, t: ir.Type):
1343
- if types.is_subtype(t, types.String):
1344
- return value, types.String
1345
- if isinstance(value, str) and types.is_subtype(t, types.DateTime):
1346
- return datetime.datetime.fromisoformat(value), types.DateTime
1347
- if isinstance(value, str) and types.is_subtype(t, types.Date):
1348
- return datetime.date.fromisoformat(value), types.Date
1349
- if isinstance(value, int) and types.is_subtype(t, types.Int64):
1350
- check_int64(value)
1351
- return value, types.Int64
1352
- if isinstance(value, int) and types.is_subtype(t, types.Int128):
1353
- return value, types.Int128
1354
- if isinstance(value, (int, float, PyDecimal)) and types.is_subtype(t, types.Float):
1355
- return float(value), types.Float
1356
- if isinstance(value, (int, float, PyDecimal)) and types.is_decimal_subtype(t):
1357
- return PyDecimal(str(value)), types.decimal_supertype(t)
1358
- return value, t
1359
-
1360
- #--------------------------------------------------
1361
- # Typer pass
1362
- #--------------------------------------------------
1363
-
1364
- class InferTypes(compiler.Pass):
1365
- def __init__(self):
1366
- super().__init__()
1367
- self.historical = {}
1368
-
1369
- def rewrite(self, model: ir.Model, options:dict={}) -> ir.Model:
1370
- w = Analyzer()
1371
- w.net.load_types(self.historical)
1372
-
1373
- # collect some type info before analyzing it
1374
- with debugging.span("type.collect"):
1375
- model.root.accept(w.context_enricher, model)
1376
-
1377
- # build the propagation network
1378
- with debugging.span("type.analyze"):
1379
- model.root.accept(w, model)
1380
-
1381
- # propagate the types through the network
1382
- with debugging.span("type.propagate") as end_span:
1383
- field_types = w.net.propagate()
1384
- self.historical.update(field_types)
1385
- end_span["type_graph"] = w.net.to_mermaid()
1386
- end_span["type_report"] = w.net.to_fish()
1387
-
1388
- # replace the fields in the model with the new types
1389
- with debugging.span("type.replace"):
1390
- final = Replacer(w.net).walk(model)
1391
-
1392
- for err in w.net.errors:
1393
- rich.print(str(err), file=sys.stderr)
1394
-
1395
- return final