relationalai 0.13.5__py3-none-any.whl → 1.0.0a2__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 (856) hide show
  1. relationalai/__init__.py +1 -256
  2. relationalai/config/__init__.py +56 -0
  3. relationalai/config/config.py +289 -0
  4. relationalai/config/config_fields.py +86 -0
  5. relationalai/config/connections/__init__.py +46 -0
  6. relationalai/config/connections/base.py +23 -0
  7. relationalai/config/connections/duckdb.py +29 -0
  8. relationalai/config/connections/snowflake.py +243 -0
  9. relationalai/config/external/__init__.py +17 -0
  10. relationalai/config/external/dbt_converter.py +101 -0
  11. relationalai/config/external/dbt_models.py +93 -0
  12. relationalai/config/external/snowflake_converter.py +41 -0
  13. relationalai/config/external/snowflake_models.py +85 -0
  14. relationalai/config/external/utils.py +19 -0
  15. relationalai/config/shims.py +1 -0
  16. relationalai/semantics/__init__.py +146 -22
  17. relationalai/semantics/backends/lqp/annotations.py +11 -0
  18. relationalai/semantics/backends/sql/sql_compiler.py +327 -0
  19. relationalai/semantics/frontend/base.py +1719 -0
  20. relationalai/semantics/frontend/core.py +179 -0
  21. relationalai/semantics/frontend/front_compiler.py +1316 -0
  22. relationalai/semantics/frontend/pprint.py +408 -0
  23. relationalai/semantics/metamodel/__init__.py +6 -40
  24. relationalai/semantics/metamodel/builtins.py +206 -772
  25. relationalai/semantics/metamodel/metamodel.py +465 -0
  26. relationalai/semantics/metamodel/metamodel_analyzer.py +519 -0
  27. relationalai/semantics/metamodel/pprint.py +414 -0
  28. relationalai/semantics/metamodel/rewriter.py +266 -0
  29. relationalai/semantics/metamodel/typer.py +1213 -0
  30. relationalai/semantics/std/__init__.py +60 -40
  31. relationalai/semantics/std/aggregates.py +148 -0
  32. relationalai/semantics/std/common.py +44 -0
  33. relationalai/semantics/std/constraints.py +37 -43
  34. relationalai/semantics/std/datetime.py +249 -135
  35. relationalai/semantics/std/decimals.py +45 -52
  36. relationalai/semantics/std/floats.py +13 -5
  37. relationalai/semantics/std/integers.py +26 -11
  38. relationalai/semantics/std/math.py +183 -112
  39. relationalai/semantics/std/numbers.py +86 -0
  40. relationalai/semantics/std/re.py +80 -62
  41. relationalai/semantics/std/strings.py +101 -46
  42. relationalai/shims/executor.py +179 -0
  43. relationalai/shims/helpers.py +126 -0
  44. relationalai/shims/hoister.py +221 -0
  45. relationalai/shims/mm2v0.py +1394 -0
  46. relationalai/tools/cli/__init__.py +6 -0
  47. relationalai/tools/cli/cli.py +90 -0
  48. relationalai/tools/cli/components/__init__.py +5 -0
  49. relationalai/tools/cli/components/progress_reader.py +1524 -0
  50. relationalai/tools/cli/components/utils.py +58 -0
  51. relationalai/tools/cli/config_template.py +45 -0
  52. relationalai/tools/cli/dev.py +19 -0
  53. relationalai/tools/debugger.py +289 -183
  54. relationalai/tools/typer_debugger.py +93 -0
  55. relationalai/util/dataclasses.py +43 -0
  56. relationalai/util/docutils.py +40 -0
  57. relationalai/util/error.py +199 -0
  58. relationalai/util/format.py +48 -109
  59. relationalai/util/naming.py +145 -0
  60. relationalai/util/python.py +35 -0
  61. relationalai/util/runtime.py +156 -0
  62. relationalai/util/schema.py +197 -0
  63. relationalai/util/source.py +185 -0
  64. relationalai/util/structures.py +163 -0
  65. relationalai/util/tracing.py +261 -0
  66. relationalai-1.0.0a2.dist-info/METADATA +44 -0
  67. relationalai-1.0.0a2.dist-info/RECORD +489 -0
  68. relationalai-1.0.0a2.dist-info/WHEEL +5 -0
  69. relationalai-1.0.0a2.dist-info/entry_points.txt +3 -0
  70. relationalai-1.0.0a2.dist-info/top_level.txt +2 -0
  71. v0/relationalai/__init__.py +216 -0
  72. v0/relationalai/clients/__init__.py +5 -0
  73. v0/relationalai/clients/azure.py +477 -0
  74. v0/relationalai/clients/client.py +912 -0
  75. v0/relationalai/clients/config.py +673 -0
  76. v0/relationalai/clients/direct_access_client.py +118 -0
  77. v0/relationalai/clients/hash_util.py +31 -0
  78. v0/relationalai/clients/local.py +571 -0
  79. v0/relationalai/clients/profile_polling.py +73 -0
  80. v0/relationalai/clients/result_helpers.py +420 -0
  81. v0/relationalai/clients/snowflake.py +3869 -0
  82. v0/relationalai/clients/types.py +113 -0
  83. v0/relationalai/clients/use_index_poller.py +980 -0
  84. v0/relationalai/clients/util.py +356 -0
  85. v0/relationalai/debugging.py +389 -0
  86. v0/relationalai/dsl.py +1749 -0
  87. v0/relationalai/early_access/builder/__init__.py +30 -0
  88. v0/relationalai/early_access/builder/builder/__init__.py +35 -0
  89. v0/relationalai/early_access/builder/snowflake/__init__.py +12 -0
  90. v0/relationalai/early_access/builder/std/__init__.py +25 -0
  91. v0/relationalai/early_access/builder/std/decimals/__init__.py +12 -0
  92. v0/relationalai/early_access/builder/std/integers/__init__.py +12 -0
  93. v0/relationalai/early_access/builder/std/math/__init__.py +12 -0
  94. v0/relationalai/early_access/builder/std/strings/__init__.py +14 -0
  95. v0/relationalai/early_access/devtools/__init__.py +12 -0
  96. v0/relationalai/early_access/devtools/benchmark_lqp/__init__.py +12 -0
  97. v0/relationalai/early_access/devtools/extract_lqp/__init__.py +12 -0
  98. v0/relationalai/early_access/dsl/adapters/orm/adapter_qb.py +427 -0
  99. v0/relationalai/early_access/dsl/adapters/orm/parser.py +636 -0
  100. v0/relationalai/early_access/dsl/adapters/owl/adapter.py +176 -0
  101. v0/relationalai/early_access/dsl/adapters/owl/parser.py +160 -0
  102. v0/relationalai/early_access/dsl/bindings/common.py +402 -0
  103. v0/relationalai/early_access/dsl/bindings/csv.py +170 -0
  104. v0/relationalai/early_access/dsl/bindings/legacy/binding_models.py +143 -0
  105. v0/relationalai/early_access/dsl/bindings/snowflake.py +64 -0
  106. v0/relationalai/early_access/dsl/codegen/binder.py +411 -0
  107. v0/relationalai/early_access/dsl/codegen/common.py +79 -0
  108. v0/relationalai/early_access/dsl/codegen/helpers.py +23 -0
  109. v0/relationalai/early_access/dsl/codegen/relations.py +700 -0
  110. v0/relationalai/early_access/dsl/codegen/weaver.py +417 -0
  111. v0/relationalai/early_access/dsl/core/builders/__init__.py +47 -0
  112. v0/relationalai/early_access/dsl/core/builders/logic.py +19 -0
  113. v0/relationalai/early_access/dsl/core/builders/scalar_constraint.py +11 -0
  114. v0/relationalai/early_access/dsl/core/constraints/predicate/atomic.py +455 -0
  115. v0/relationalai/early_access/dsl/core/constraints/predicate/universal.py +73 -0
  116. v0/relationalai/early_access/dsl/core/constraints/scalar.py +310 -0
  117. v0/relationalai/early_access/dsl/core/context.py +13 -0
  118. v0/relationalai/early_access/dsl/core/cset.py +132 -0
  119. v0/relationalai/early_access/dsl/core/exprs/__init__.py +116 -0
  120. v0/relationalai/early_access/dsl/core/exprs/relational.py +18 -0
  121. v0/relationalai/early_access/dsl/core/exprs/scalar.py +412 -0
  122. v0/relationalai/early_access/dsl/core/instances.py +44 -0
  123. v0/relationalai/early_access/dsl/core/logic/__init__.py +193 -0
  124. v0/relationalai/early_access/dsl/core/logic/aggregation.py +98 -0
  125. v0/relationalai/early_access/dsl/core/logic/exists.py +223 -0
  126. v0/relationalai/early_access/dsl/core/logic/helper.py +163 -0
  127. v0/relationalai/early_access/dsl/core/namespaces.py +32 -0
  128. v0/relationalai/early_access/dsl/core/relations.py +276 -0
  129. v0/relationalai/early_access/dsl/core/rules.py +112 -0
  130. v0/relationalai/early_access/dsl/core/std/__init__.py +45 -0
  131. v0/relationalai/early_access/dsl/core/temporal/recall.py +6 -0
  132. v0/relationalai/early_access/dsl/core/types/__init__.py +270 -0
  133. v0/relationalai/early_access/dsl/core/types/concepts.py +128 -0
  134. v0/relationalai/early_access/dsl/core/types/constrained/__init__.py +267 -0
  135. v0/relationalai/early_access/dsl/core/types/constrained/nominal.py +143 -0
  136. v0/relationalai/early_access/dsl/core/types/constrained/subtype.py +124 -0
  137. v0/relationalai/early_access/dsl/core/types/standard.py +92 -0
  138. v0/relationalai/early_access/dsl/core/types/unconstrained.py +50 -0
  139. v0/relationalai/early_access/dsl/core/types/variables.py +203 -0
  140. v0/relationalai/early_access/dsl/ir/compiler.py +318 -0
  141. v0/relationalai/early_access/dsl/ir/executor.py +260 -0
  142. v0/relationalai/early_access/dsl/ontologies/constraints.py +88 -0
  143. v0/relationalai/early_access/dsl/ontologies/export.py +30 -0
  144. v0/relationalai/early_access/dsl/ontologies/models.py +453 -0
  145. v0/relationalai/early_access/dsl/ontologies/python_printer.py +303 -0
  146. v0/relationalai/early_access/dsl/ontologies/readings.py +60 -0
  147. v0/relationalai/early_access/dsl/ontologies/relationships.py +322 -0
  148. v0/relationalai/early_access/dsl/ontologies/roles.py +87 -0
  149. v0/relationalai/early_access/dsl/ontologies/subtyping.py +55 -0
  150. v0/relationalai/early_access/dsl/orm/constraints.py +438 -0
  151. v0/relationalai/early_access/dsl/orm/measures/dimensions.py +200 -0
  152. v0/relationalai/early_access/dsl/orm/measures/initializer.py +16 -0
  153. v0/relationalai/early_access/dsl/orm/measures/measure_rules.py +275 -0
  154. v0/relationalai/early_access/dsl/orm/measures/measures.py +299 -0
  155. v0/relationalai/early_access/dsl/orm/measures/role_exprs.py +268 -0
  156. v0/relationalai/early_access/dsl/orm/models.py +256 -0
  157. v0/relationalai/early_access/dsl/orm/object_oriented_printer.py +344 -0
  158. v0/relationalai/early_access/dsl/orm/printer.py +469 -0
  159. v0/relationalai/early_access/dsl/orm/reasoners.py +480 -0
  160. v0/relationalai/early_access/dsl/orm/relations.py +19 -0
  161. v0/relationalai/early_access/dsl/orm/relationships.py +251 -0
  162. v0/relationalai/early_access/dsl/orm/types.py +42 -0
  163. v0/relationalai/early_access/dsl/orm/utils.py +79 -0
  164. v0/relationalai/early_access/dsl/orm/verb.py +204 -0
  165. v0/relationalai/early_access/dsl/physical_metadata/tables.py +133 -0
  166. v0/relationalai/early_access/dsl/relations.py +170 -0
  167. v0/relationalai/early_access/dsl/rulesets.py +69 -0
  168. v0/relationalai/early_access/dsl/schemas/__init__.py +450 -0
  169. v0/relationalai/early_access/dsl/schemas/builder.py +48 -0
  170. v0/relationalai/early_access/dsl/schemas/comp_names.py +51 -0
  171. v0/relationalai/early_access/dsl/schemas/components.py +203 -0
  172. v0/relationalai/early_access/dsl/schemas/contexts.py +156 -0
  173. v0/relationalai/early_access/dsl/schemas/exprs.py +89 -0
  174. v0/relationalai/early_access/dsl/schemas/fragments.py +464 -0
  175. v0/relationalai/early_access/dsl/serialization.py +79 -0
  176. v0/relationalai/early_access/dsl/serialize/exporter.py +163 -0
  177. v0/relationalai/early_access/dsl/snow/api.py +104 -0
  178. v0/relationalai/early_access/dsl/snow/common.py +76 -0
  179. v0/relationalai/early_access/dsl/state_mgmt/__init__.py +129 -0
  180. v0/relationalai/early_access/dsl/state_mgmt/state_charts.py +125 -0
  181. v0/relationalai/early_access/dsl/state_mgmt/transitions.py +130 -0
  182. v0/relationalai/early_access/dsl/types/__init__.py +40 -0
  183. v0/relationalai/early_access/dsl/types/concepts.py +12 -0
  184. v0/relationalai/early_access/dsl/types/entities.py +135 -0
  185. v0/relationalai/early_access/dsl/types/values.py +17 -0
  186. v0/relationalai/early_access/dsl/utils.py +102 -0
  187. v0/relationalai/early_access/graphs/__init__.py +13 -0
  188. v0/relationalai/early_access/lqp/__init__.py +12 -0
  189. v0/relationalai/early_access/lqp/compiler/__init__.py +12 -0
  190. v0/relationalai/early_access/lqp/constructors/__init__.py +18 -0
  191. v0/relationalai/early_access/lqp/executor/__init__.py +12 -0
  192. v0/relationalai/early_access/lqp/ir/__init__.py +12 -0
  193. v0/relationalai/early_access/lqp/passes/__init__.py +12 -0
  194. v0/relationalai/early_access/lqp/pragmas/__init__.py +12 -0
  195. v0/relationalai/early_access/lqp/primitives/__init__.py +12 -0
  196. v0/relationalai/early_access/lqp/types/__init__.py +12 -0
  197. v0/relationalai/early_access/lqp/utils/__init__.py +12 -0
  198. v0/relationalai/early_access/lqp/validators/__init__.py +12 -0
  199. v0/relationalai/early_access/metamodel/__init__.py +58 -0
  200. v0/relationalai/early_access/metamodel/builtins/__init__.py +12 -0
  201. v0/relationalai/early_access/metamodel/compiler/__init__.py +12 -0
  202. v0/relationalai/early_access/metamodel/dependency/__init__.py +12 -0
  203. v0/relationalai/early_access/metamodel/factory/__init__.py +17 -0
  204. v0/relationalai/early_access/metamodel/helpers/__init__.py +12 -0
  205. v0/relationalai/early_access/metamodel/ir/__init__.py +14 -0
  206. v0/relationalai/early_access/metamodel/rewrite/__init__.py +7 -0
  207. v0/relationalai/early_access/metamodel/typer/__init__.py +3 -0
  208. v0/relationalai/early_access/metamodel/typer/typer/__init__.py +12 -0
  209. v0/relationalai/early_access/metamodel/types/__init__.py +15 -0
  210. v0/relationalai/early_access/metamodel/util/__init__.py +15 -0
  211. v0/relationalai/early_access/metamodel/visitor/__init__.py +12 -0
  212. v0/relationalai/early_access/rel/__init__.py +12 -0
  213. v0/relationalai/early_access/rel/executor/__init__.py +12 -0
  214. v0/relationalai/early_access/rel/rel_utils/__init__.py +12 -0
  215. v0/relationalai/early_access/rel/rewrite/__init__.py +7 -0
  216. v0/relationalai/early_access/solvers/__init__.py +19 -0
  217. v0/relationalai/early_access/sql/__init__.py +11 -0
  218. v0/relationalai/early_access/sql/executor/__init__.py +3 -0
  219. v0/relationalai/early_access/sql/rewrite/__init__.py +3 -0
  220. v0/relationalai/early_access/tests/logging/__init__.py +12 -0
  221. v0/relationalai/early_access/tests/test_snapshot_base/__init__.py +12 -0
  222. v0/relationalai/early_access/tests/utils/__init__.py +12 -0
  223. v0/relationalai/environments/__init__.py +35 -0
  224. v0/relationalai/environments/base.py +381 -0
  225. v0/relationalai/environments/colab.py +14 -0
  226. v0/relationalai/environments/generic.py +71 -0
  227. v0/relationalai/environments/ipython.py +68 -0
  228. v0/relationalai/environments/jupyter.py +9 -0
  229. v0/relationalai/environments/snowbook.py +169 -0
  230. v0/relationalai/errors.py +2478 -0
  231. v0/relationalai/experimental/SF.py +38 -0
  232. v0/relationalai/experimental/inspect.py +47 -0
  233. v0/relationalai/experimental/pathfinder/__init__.py +158 -0
  234. v0/relationalai/experimental/pathfinder/api.py +160 -0
  235. v0/relationalai/experimental/pathfinder/automaton.py +584 -0
  236. v0/relationalai/experimental/pathfinder/bridge.py +226 -0
  237. v0/relationalai/experimental/pathfinder/compiler.py +416 -0
  238. v0/relationalai/experimental/pathfinder/datalog.py +214 -0
  239. v0/relationalai/experimental/pathfinder/diagnostics.py +56 -0
  240. v0/relationalai/experimental/pathfinder/filter.py +236 -0
  241. v0/relationalai/experimental/pathfinder/glushkov.py +439 -0
  242. v0/relationalai/experimental/pathfinder/options.py +265 -0
  243. v0/relationalai/experimental/pathfinder/rpq.py +344 -0
  244. v0/relationalai/experimental/pathfinder/transition.py +200 -0
  245. v0/relationalai/experimental/pathfinder/utils.py +26 -0
  246. v0/relationalai/experimental/paths/api.py +143 -0
  247. v0/relationalai/experimental/paths/benchmarks/grid_graph.py +37 -0
  248. v0/relationalai/experimental/paths/examples/basic_example.py +40 -0
  249. v0/relationalai/experimental/paths/examples/minimal_engine_warmup.py +3 -0
  250. v0/relationalai/experimental/paths/examples/movie_example.py +77 -0
  251. v0/relationalai/experimental/paths/examples/paths_benchmark.py +115 -0
  252. v0/relationalai/experimental/paths/examples/paths_example.py +116 -0
  253. v0/relationalai/experimental/paths/examples/pattern_to_automaton.py +28 -0
  254. v0/relationalai/experimental/paths/find_paths_via_automaton.py +85 -0
  255. v0/relationalai/experimental/paths/graph.py +185 -0
  256. v0/relationalai/experimental/paths/path_algorithms/find_paths.py +280 -0
  257. v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +26 -0
  258. v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +111 -0
  259. v0/relationalai/experimental/paths/path_algorithms/single.py +59 -0
  260. v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +39 -0
  261. v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +103 -0
  262. v0/relationalai/experimental/paths/path_algorithms/usp-old.py +130 -0
  263. v0/relationalai/experimental/paths/path_algorithms/usp-tuple.py +183 -0
  264. v0/relationalai/experimental/paths/path_algorithms/usp.py +150 -0
  265. v0/relationalai/experimental/paths/product_graph.py +93 -0
  266. v0/relationalai/experimental/paths/rpq/automaton.py +584 -0
  267. v0/relationalai/experimental/paths/rpq/diagnostics.py +56 -0
  268. v0/relationalai/experimental/paths/rpq/rpq.py +378 -0
  269. v0/relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +90 -0
  270. v0/relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +119 -0
  271. v0/relationalai/experimental/paths/tests/tests_limit_sp_single.py +104 -0
  272. v0/relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +113 -0
  273. v0/relationalai/experimental/paths/tests/tests_limit_walks_single.py +149 -0
  274. v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +70 -0
  275. v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +64 -0
  276. v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +115 -0
  277. v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +75 -0
  278. v0/relationalai/experimental/paths/tests/tests_single_paths.py +152 -0
  279. v0/relationalai/experimental/paths/tests/tests_single_walks.py +208 -0
  280. v0/relationalai/experimental/paths/tests/tests_single_walks_undirected.py +297 -0
  281. v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +107 -0
  282. v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +76 -0
  283. v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +76 -0
  284. v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +110 -0
  285. v0/relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +229 -0
  286. v0/relationalai/experimental/paths/tests/tests_usp_nsp_single.py +108 -0
  287. v0/relationalai/experimental/paths/tree_agg.py +168 -0
  288. v0/relationalai/experimental/paths/utilities/iterators.py +27 -0
  289. v0/relationalai/experimental/paths/utilities/prefix_sum.py +91 -0
  290. v0/relationalai/experimental/solvers.py +1087 -0
  291. v0/relationalai/loaders/csv.py +195 -0
  292. v0/relationalai/loaders/loader.py +177 -0
  293. v0/relationalai/loaders/types.py +23 -0
  294. v0/relationalai/rel_emitter.py +373 -0
  295. v0/relationalai/rel_utils.py +185 -0
  296. v0/relationalai/semantics/__init__.py +29 -0
  297. v0/relationalai/semantics/devtools/benchmark_lqp.py +536 -0
  298. v0/relationalai/semantics/devtools/compilation_manager.py +294 -0
  299. v0/relationalai/semantics/devtools/extract_lqp.py +110 -0
  300. v0/relationalai/semantics/internal/internal.py +3785 -0
  301. v0/relationalai/semantics/internal/snowflake.py +325 -0
  302. v0/relationalai/semantics/lqp/builtins.py +16 -0
  303. v0/relationalai/semantics/lqp/compiler.py +22 -0
  304. v0/relationalai/semantics/lqp/constructors.py +68 -0
  305. v0/relationalai/semantics/lqp/executor.py +474 -0
  306. v0/relationalai/semantics/lqp/intrinsics.py +24 -0
  307. v0/relationalai/semantics/lqp/ir.py +124 -0
  308. v0/relationalai/semantics/lqp/model2lqp.py +877 -0
  309. v0/relationalai/semantics/lqp/passes.py +680 -0
  310. v0/relationalai/semantics/lqp/primitives.py +252 -0
  311. v0/relationalai/semantics/lqp/result_helpers.py +202 -0
  312. v0/relationalai/semantics/lqp/rewrite/__init__.py +18 -0
  313. v0/relationalai/semantics/lqp/rewrite/annotate_constraints.py +57 -0
  314. v0/relationalai/semantics/lqp/rewrite/cdc.py +216 -0
  315. v0/relationalai/semantics/lqp/rewrite/extract_common.py +338 -0
  316. v0/relationalai/semantics/lqp/rewrite/extract_keys.py +490 -0
  317. v0/relationalai/semantics/lqp/rewrite/function_annotations.py +114 -0
  318. v0/relationalai/semantics/lqp/rewrite/functional_dependencies.py +314 -0
  319. v0/relationalai/semantics/lqp/rewrite/quantify_vars.py +296 -0
  320. v0/relationalai/semantics/lqp/rewrite/splinter.py +76 -0
  321. v0/relationalai/semantics/lqp/types.py +101 -0
  322. v0/relationalai/semantics/lqp/utils.py +160 -0
  323. v0/relationalai/semantics/lqp/validators.py +57 -0
  324. v0/relationalai/semantics/metamodel/__init__.py +40 -0
  325. v0/relationalai/semantics/metamodel/builtins.py +776 -0
  326. v0/relationalai/semantics/metamodel/compiler.py +133 -0
  327. v0/relationalai/semantics/metamodel/dependency.py +862 -0
  328. v0/relationalai/semantics/metamodel/executor.py +61 -0
  329. v0/relationalai/semantics/metamodel/factory.py +287 -0
  330. v0/relationalai/semantics/metamodel/helpers.py +361 -0
  331. v0/relationalai/semantics/metamodel/ir.py +923 -0
  332. v0/relationalai/semantics/metamodel/rewrite/__init__.py +7 -0
  333. v0/relationalai/semantics/metamodel/rewrite/discharge_constraints.py +39 -0
  334. v0/relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +210 -0
  335. v0/relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +78 -0
  336. v0/relationalai/semantics/metamodel/rewrite/flatten.py +554 -0
  337. v0/relationalai/semantics/metamodel/rewrite/format_outputs.py +165 -0
  338. v0/relationalai/semantics/metamodel/typer/checker.py +353 -0
  339. v0/relationalai/semantics/metamodel/typer/typer.py +1395 -0
  340. v0/relationalai/semantics/metamodel/util.py +505 -0
  341. v0/relationalai/semantics/metamodel/visitor.py +944 -0
  342. v0/relationalai/semantics/reasoners/__init__.py +10 -0
  343. v0/relationalai/semantics/reasoners/graph/__init__.py +37 -0
  344. v0/relationalai/semantics/reasoners/graph/core.py +9019 -0
  345. v0/relationalai/semantics/reasoners/optimization/__init__.py +68 -0
  346. v0/relationalai/semantics/reasoners/optimization/common.py +88 -0
  347. v0/relationalai/semantics/reasoners/optimization/solvers_dev.py +568 -0
  348. v0/relationalai/semantics/reasoners/optimization/solvers_pb.py +1163 -0
  349. v0/relationalai/semantics/rel/builtins.py +40 -0
  350. v0/relationalai/semantics/rel/compiler.py +989 -0
  351. v0/relationalai/semantics/rel/executor.py +359 -0
  352. v0/relationalai/semantics/rel/rel.py +482 -0
  353. v0/relationalai/semantics/rel/rel_utils.py +276 -0
  354. v0/relationalai/semantics/snowflake/__init__.py +3 -0
  355. v0/relationalai/semantics/sql/compiler.py +2503 -0
  356. v0/relationalai/semantics/sql/executor/duck_db.py +52 -0
  357. v0/relationalai/semantics/sql/executor/result_helpers.py +64 -0
  358. v0/relationalai/semantics/sql/executor/snowflake.py +145 -0
  359. v0/relationalai/semantics/sql/rewrite/denormalize.py +222 -0
  360. v0/relationalai/semantics/sql/rewrite/double_negation.py +49 -0
  361. v0/relationalai/semantics/sql/rewrite/recursive_union.py +127 -0
  362. v0/relationalai/semantics/sql/rewrite/sort_output_query.py +246 -0
  363. v0/relationalai/semantics/sql/sql.py +504 -0
  364. v0/relationalai/semantics/std/__init__.py +54 -0
  365. v0/relationalai/semantics/std/constraints.py +43 -0
  366. v0/relationalai/semantics/std/datetime.py +363 -0
  367. v0/relationalai/semantics/std/decimals.py +62 -0
  368. v0/relationalai/semantics/std/floats.py +7 -0
  369. v0/relationalai/semantics/std/integers.py +22 -0
  370. v0/relationalai/semantics/std/math.py +141 -0
  371. v0/relationalai/semantics/std/pragmas.py +11 -0
  372. v0/relationalai/semantics/std/re.py +83 -0
  373. v0/relationalai/semantics/std/std.py +14 -0
  374. v0/relationalai/semantics/std/strings.py +63 -0
  375. v0/relationalai/semantics/tests/__init__.py +0 -0
  376. v0/relationalai/semantics/tests/test_snapshot_abstract.py +143 -0
  377. v0/relationalai/semantics/tests/test_snapshot_base.py +9 -0
  378. v0/relationalai/semantics/tests/utils.py +46 -0
  379. v0/relationalai/std/__init__.py +70 -0
  380. v0/relationalai/tools/__init__.py +0 -0
  381. v0/relationalai/tools/cli.py +1940 -0
  382. v0/relationalai/tools/cli_controls.py +1826 -0
  383. v0/relationalai/tools/cli_helpers.py +390 -0
  384. v0/relationalai/tools/debugger.py +183 -0
  385. v0/relationalai/tools/debugger_client.py +109 -0
  386. v0/relationalai/tools/debugger_server.py +302 -0
  387. v0/relationalai/tools/dev.py +685 -0
  388. v0/relationalai/tools/qb_debugger.py +425 -0
  389. v0/relationalai/util/clean_up_databases.py +95 -0
  390. v0/relationalai/util/format.py +123 -0
  391. v0/relationalai/util/list_databases.py +9 -0
  392. v0/relationalai/util/otel_configuration.py +25 -0
  393. v0/relationalai/util/otel_handler.py +484 -0
  394. v0/relationalai/util/snowflake_handler.py +88 -0
  395. v0/relationalai/util/span_format_test.py +43 -0
  396. v0/relationalai/util/span_tracker.py +207 -0
  397. v0/relationalai/util/spans_file_handler.py +72 -0
  398. v0/relationalai/util/tracing_handler.py +34 -0
  399. frontend/debugger/dist/.gitignore +0 -2
  400. frontend/debugger/dist/assets/favicon-Dy0ZgA6N.png +0 -0
  401. frontend/debugger/dist/assets/index-Cssla-O7.js +0 -208
  402. frontend/debugger/dist/assets/index-DlHsYx1V.css +0 -9
  403. frontend/debugger/dist/index.html +0 -17
  404. relationalai/clients/__init__.py +0 -18
  405. relationalai/clients/client.py +0 -946
  406. relationalai/clients/config.py +0 -673
  407. relationalai/clients/direct_access_client.py +0 -118
  408. relationalai/clients/exec_txn_poller.py +0 -153
  409. relationalai/clients/hash_util.py +0 -31
  410. relationalai/clients/local.py +0 -594
  411. relationalai/clients/profile_polling.py +0 -73
  412. relationalai/clients/resources/__init__.py +0 -8
  413. relationalai/clients/resources/azure/azure.py +0 -502
  414. relationalai/clients/resources/snowflake/__init__.py +0 -20
  415. relationalai/clients/resources/snowflake/cli_resources.py +0 -98
  416. relationalai/clients/resources/snowflake/direct_access_resources.py +0 -739
  417. relationalai/clients/resources/snowflake/engine_service.py +0 -381
  418. relationalai/clients/resources/snowflake/engine_state_handlers.py +0 -315
  419. relationalai/clients/resources/snowflake/error_handlers.py +0 -240
  420. relationalai/clients/resources/snowflake/export_procedure.py.jinja +0 -249
  421. relationalai/clients/resources/snowflake/resources_factory.py +0 -99
  422. relationalai/clients/resources/snowflake/snowflake.py +0 -3193
  423. relationalai/clients/resources/snowflake/use_index_poller.py +0 -1019
  424. relationalai/clients/resources/snowflake/use_index_resources.py +0 -188
  425. relationalai/clients/resources/snowflake/util.py +0 -387
  426. relationalai/clients/result_helpers.py +0 -420
  427. relationalai/clients/types.py +0 -118
  428. relationalai/clients/util.py +0 -356
  429. relationalai/debugging.py +0 -389
  430. relationalai/dsl.py +0 -1749
  431. relationalai/early_access/builder/__init__.py +0 -30
  432. relationalai/early_access/builder/builder/__init__.py +0 -35
  433. relationalai/early_access/builder/snowflake/__init__.py +0 -12
  434. relationalai/early_access/builder/std/__init__.py +0 -25
  435. relationalai/early_access/builder/std/decimals/__init__.py +0 -12
  436. relationalai/early_access/builder/std/integers/__init__.py +0 -12
  437. relationalai/early_access/builder/std/math/__init__.py +0 -12
  438. relationalai/early_access/builder/std/strings/__init__.py +0 -14
  439. relationalai/early_access/devtools/__init__.py +0 -12
  440. relationalai/early_access/devtools/benchmark_lqp/__init__.py +0 -12
  441. relationalai/early_access/devtools/extract_lqp/__init__.py +0 -12
  442. relationalai/early_access/dsl/adapters/orm/adapter_qb.py +0 -427
  443. relationalai/early_access/dsl/adapters/orm/parser.py +0 -636
  444. relationalai/early_access/dsl/adapters/owl/adapter.py +0 -176
  445. relationalai/early_access/dsl/adapters/owl/parser.py +0 -160
  446. relationalai/early_access/dsl/bindings/common.py +0 -402
  447. relationalai/early_access/dsl/bindings/csv.py +0 -170
  448. relationalai/early_access/dsl/bindings/legacy/binding_models.py +0 -143
  449. relationalai/early_access/dsl/bindings/snowflake.py +0 -64
  450. relationalai/early_access/dsl/codegen/binder.py +0 -411
  451. relationalai/early_access/dsl/codegen/common.py +0 -79
  452. relationalai/early_access/dsl/codegen/helpers.py +0 -23
  453. relationalai/early_access/dsl/codegen/relations.py +0 -700
  454. relationalai/early_access/dsl/codegen/weaver.py +0 -417
  455. relationalai/early_access/dsl/core/builders/__init__.py +0 -47
  456. relationalai/early_access/dsl/core/builders/logic.py +0 -19
  457. relationalai/early_access/dsl/core/builders/scalar_constraint.py +0 -11
  458. relationalai/early_access/dsl/core/constraints/predicate/atomic.py +0 -455
  459. relationalai/early_access/dsl/core/constraints/predicate/universal.py +0 -73
  460. relationalai/early_access/dsl/core/constraints/scalar.py +0 -310
  461. relationalai/early_access/dsl/core/context.py +0 -13
  462. relationalai/early_access/dsl/core/cset.py +0 -132
  463. relationalai/early_access/dsl/core/exprs/__init__.py +0 -116
  464. relationalai/early_access/dsl/core/exprs/relational.py +0 -18
  465. relationalai/early_access/dsl/core/exprs/scalar.py +0 -412
  466. relationalai/early_access/dsl/core/instances.py +0 -44
  467. relationalai/early_access/dsl/core/logic/__init__.py +0 -193
  468. relationalai/early_access/dsl/core/logic/aggregation.py +0 -98
  469. relationalai/early_access/dsl/core/logic/exists.py +0 -223
  470. relationalai/early_access/dsl/core/logic/helper.py +0 -163
  471. relationalai/early_access/dsl/core/namespaces.py +0 -32
  472. relationalai/early_access/dsl/core/relations.py +0 -276
  473. relationalai/early_access/dsl/core/rules.py +0 -112
  474. relationalai/early_access/dsl/core/std/__init__.py +0 -45
  475. relationalai/early_access/dsl/core/temporal/recall.py +0 -6
  476. relationalai/early_access/dsl/core/types/__init__.py +0 -270
  477. relationalai/early_access/dsl/core/types/concepts.py +0 -128
  478. relationalai/early_access/dsl/core/types/constrained/__init__.py +0 -267
  479. relationalai/early_access/dsl/core/types/constrained/nominal.py +0 -143
  480. relationalai/early_access/dsl/core/types/constrained/subtype.py +0 -124
  481. relationalai/early_access/dsl/core/types/standard.py +0 -92
  482. relationalai/early_access/dsl/core/types/unconstrained.py +0 -50
  483. relationalai/early_access/dsl/core/types/variables.py +0 -203
  484. relationalai/early_access/dsl/ir/compiler.py +0 -318
  485. relationalai/early_access/dsl/ir/executor.py +0 -260
  486. relationalai/early_access/dsl/ontologies/constraints.py +0 -88
  487. relationalai/early_access/dsl/ontologies/export.py +0 -30
  488. relationalai/early_access/dsl/ontologies/models.py +0 -453
  489. relationalai/early_access/dsl/ontologies/python_printer.py +0 -303
  490. relationalai/early_access/dsl/ontologies/readings.py +0 -60
  491. relationalai/early_access/dsl/ontologies/relationships.py +0 -322
  492. relationalai/early_access/dsl/ontologies/roles.py +0 -87
  493. relationalai/early_access/dsl/ontologies/subtyping.py +0 -55
  494. relationalai/early_access/dsl/orm/constraints.py +0 -438
  495. relationalai/early_access/dsl/orm/measures/dimensions.py +0 -200
  496. relationalai/early_access/dsl/orm/measures/initializer.py +0 -16
  497. relationalai/early_access/dsl/orm/measures/measure_rules.py +0 -275
  498. relationalai/early_access/dsl/orm/measures/measures.py +0 -299
  499. relationalai/early_access/dsl/orm/measures/role_exprs.py +0 -268
  500. relationalai/early_access/dsl/orm/models.py +0 -256
  501. relationalai/early_access/dsl/orm/object_oriented_printer.py +0 -344
  502. relationalai/early_access/dsl/orm/printer.py +0 -469
  503. relationalai/early_access/dsl/orm/reasoners.py +0 -480
  504. relationalai/early_access/dsl/orm/relations.py +0 -19
  505. relationalai/early_access/dsl/orm/relationships.py +0 -251
  506. relationalai/early_access/dsl/orm/types.py +0 -42
  507. relationalai/early_access/dsl/orm/utils.py +0 -79
  508. relationalai/early_access/dsl/orm/verb.py +0 -204
  509. relationalai/early_access/dsl/physical_metadata/tables.py +0 -133
  510. relationalai/early_access/dsl/relations.py +0 -170
  511. relationalai/early_access/dsl/rulesets.py +0 -69
  512. relationalai/early_access/dsl/schemas/__init__.py +0 -450
  513. relationalai/early_access/dsl/schemas/builder.py +0 -48
  514. relationalai/early_access/dsl/schemas/comp_names.py +0 -51
  515. relationalai/early_access/dsl/schemas/components.py +0 -203
  516. relationalai/early_access/dsl/schemas/contexts.py +0 -156
  517. relationalai/early_access/dsl/schemas/exprs.py +0 -89
  518. relationalai/early_access/dsl/schemas/fragments.py +0 -464
  519. relationalai/early_access/dsl/serialization.py +0 -79
  520. relationalai/early_access/dsl/serialize/exporter.py +0 -163
  521. relationalai/early_access/dsl/snow/api.py +0 -105
  522. relationalai/early_access/dsl/snow/common.py +0 -76
  523. relationalai/early_access/dsl/state_mgmt/__init__.py +0 -129
  524. relationalai/early_access/dsl/state_mgmt/state_charts.py +0 -125
  525. relationalai/early_access/dsl/state_mgmt/transitions.py +0 -130
  526. relationalai/early_access/dsl/types/__init__.py +0 -40
  527. relationalai/early_access/dsl/types/concepts.py +0 -12
  528. relationalai/early_access/dsl/types/entities.py +0 -135
  529. relationalai/early_access/dsl/types/values.py +0 -17
  530. relationalai/early_access/dsl/utils.py +0 -102
  531. relationalai/early_access/graphs/__init__.py +0 -13
  532. relationalai/early_access/lqp/__init__.py +0 -12
  533. relationalai/early_access/lqp/compiler/__init__.py +0 -12
  534. relationalai/early_access/lqp/constructors/__init__.py +0 -18
  535. relationalai/early_access/lqp/executor/__init__.py +0 -12
  536. relationalai/early_access/lqp/ir/__init__.py +0 -12
  537. relationalai/early_access/lqp/passes/__init__.py +0 -12
  538. relationalai/early_access/lqp/pragmas/__init__.py +0 -12
  539. relationalai/early_access/lqp/primitives/__init__.py +0 -12
  540. relationalai/early_access/lqp/types/__init__.py +0 -12
  541. relationalai/early_access/lqp/utils/__init__.py +0 -12
  542. relationalai/early_access/lqp/validators/__init__.py +0 -12
  543. relationalai/early_access/metamodel/__init__.py +0 -58
  544. relationalai/early_access/metamodel/builtins/__init__.py +0 -12
  545. relationalai/early_access/metamodel/compiler/__init__.py +0 -12
  546. relationalai/early_access/metamodel/dependency/__init__.py +0 -12
  547. relationalai/early_access/metamodel/factory/__init__.py +0 -17
  548. relationalai/early_access/metamodel/helpers/__init__.py +0 -12
  549. relationalai/early_access/metamodel/ir/__init__.py +0 -14
  550. relationalai/early_access/metamodel/rewrite/__init__.py +0 -7
  551. relationalai/early_access/metamodel/typer/__init__.py +0 -3
  552. relationalai/early_access/metamodel/typer/typer/__init__.py +0 -12
  553. relationalai/early_access/metamodel/types/__init__.py +0 -15
  554. relationalai/early_access/metamodel/util/__init__.py +0 -15
  555. relationalai/early_access/metamodel/visitor/__init__.py +0 -12
  556. relationalai/early_access/rel/__init__.py +0 -12
  557. relationalai/early_access/rel/executor/__init__.py +0 -12
  558. relationalai/early_access/rel/rel_utils/__init__.py +0 -12
  559. relationalai/early_access/rel/rewrite/__init__.py +0 -7
  560. relationalai/early_access/solvers/__init__.py +0 -19
  561. relationalai/early_access/sql/__init__.py +0 -11
  562. relationalai/early_access/sql/executor/__init__.py +0 -3
  563. relationalai/early_access/sql/rewrite/__init__.py +0 -3
  564. relationalai/early_access/tests/logging/__init__.py +0 -12
  565. relationalai/early_access/tests/test_snapshot_base/__init__.py +0 -12
  566. relationalai/early_access/tests/utils/__init__.py +0 -12
  567. relationalai/environments/__init__.py +0 -35
  568. relationalai/environments/base.py +0 -381
  569. relationalai/environments/colab.py +0 -14
  570. relationalai/environments/generic.py +0 -71
  571. relationalai/environments/ipython.py +0 -68
  572. relationalai/environments/jupyter.py +0 -9
  573. relationalai/environments/snowbook.py +0 -169
  574. relationalai/errors.py +0 -2496
  575. relationalai/experimental/SF.py +0 -38
  576. relationalai/experimental/inspect.py +0 -47
  577. relationalai/experimental/pathfinder/__init__.py +0 -158
  578. relationalai/experimental/pathfinder/api.py +0 -160
  579. relationalai/experimental/pathfinder/automaton.py +0 -584
  580. relationalai/experimental/pathfinder/bridge.py +0 -226
  581. relationalai/experimental/pathfinder/compiler.py +0 -416
  582. relationalai/experimental/pathfinder/datalog.py +0 -214
  583. relationalai/experimental/pathfinder/diagnostics.py +0 -56
  584. relationalai/experimental/pathfinder/filter.py +0 -236
  585. relationalai/experimental/pathfinder/glushkov.py +0 -439
  586. relationalai/experimental/pathfinder/options.py +0 -265
  587. relationalai/experimental/pathfinder/pathfinder-v0.7.0.rel +0 -1951
  588. relationalai/experimental/pathfinder/rpq.py +0 -344
  589. relationalai/experimental/pathfinder/transition.py +0 -200
  590. relationalai/experimental/pathfinder/utils.py +0 -26
  591. relationalai/experimental/paths/README.md +0 -107
  592. relationalai/experimental/paths/api.py +0 -143
  593. relationalai/experimental/paths/benchmarks/grid_graph.py +0 -37
  594. relationalai/experimental/paths/code_organization.md +0 -2
  595. relationalai/experimental/paths/examples/Movies.ipynb +0 -16328
  596. relationalai/experimental/paths/examples/basic_example.py +0 -40
  597. relationalai/experimental/paths/examples/minimal_engine_warmup.py +0 -3
  598. relationalai/experimental/paths/examples/movie_example.py +0 -77
  599. relationalai/experimental/paths/examples/movies_data/actedin.csv +0 -193
  600. relationalai/experimental/paths/examples/movies_data/directed.csv +0 -45
  601. relationalai/experimental/paths/examples/movies_data/follows.csv +0 -7
  602. relationalai/experimental/paths/examples/movies_data/movies.csv +0 -39
  603. relationalai/experimental/paths/examples/movies_data/person.csv +0 -134
  604. relationalai/experimental/paths/examples/movies_data/produced.csv +0 -16
  605. relationalai/experimental/paths/examples/movies_data/ratings.csv +0 -10
  606. relationalai/experimental/paths/examples/movies_data/wrote.csv +0 -11
  607. relationalai/experimental/paths/examples/paths_benchmark.py +0 -115
  608. relationalai/experimental/paths/examples/paths_example.py +0 -116
  609. relationalai/experimental/paths/examples/pattern_to_automaton.py +0 -28
  610. relationalai/experimental/paths/find_paths_via_automaton.py +0 -85
  611. relationalai/experimental/paths/graph.py +0 -185
  612. relationalai/experimental/paths/path_algorithms/find_paths.py +0 -280
  613. relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +0 -26
  614. relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +0 -111
  615. relationalai/experimental/paths/path_algorithms/single.py +0 -59
  616. relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +0 -39
  617. relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +0 -103
  618. relationalai/experimental/paths/path_algorithms/usp-old.py +0 -130
  619. relationalai/experimental/paths/path_algorithms/usp-tuple.py +0 -183
  620. relationalai/experimental/paths/path_algorithms/usp.py +0 -150
  621. relationalai/experimental/paths/product_graph.py +0 -93
  622. relationalai/experimental/paths/rpq/automaton.py +0 -584
  623. relationalai/experimental/paths/rpq/diagnostics.py +0 -56
  624. relationalai/experimental/paths/rpq/rpq.py +0 -378
  625. relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +0 -90
  626. relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +0 -119
  627. relationalai/experimental/paths/tests/tests_limit_sp_single.py +0 -104
  628. relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +0 -113
  629. relationalai/experimental/paths/tests/tests_limit_walks_single.py +0 -149
  630. relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +0 -70
  631. relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +0 -64
  632. relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +0 -115
  633. relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +0 -75
  634. relationalai/experimental/paths/tests/tests_single_paths.py +0 -152
  635. relationalai/experimental/paths/tests/tests_single_walks.py +0 -208
  636. relationalai/experimental/paths/tests/tests_single_walks_undirected.py +0 -297
  637. relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +0 -107
  638. relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +0 -76
  639. relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +0 -76
  640. relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +0 -110
  641. relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +0 -229
  642. relationalai/experimental/paths/tests/tests_usp_nsp_single.py +0 -108
  643. relationalai/experimental/paths/tree_agg.py +0 -168
  644. relationalai/experimental/paths/utilities/iterators.py +0 -27
  645. relationalai/experimental/paths/utilities/prefix_sum.py +0 -91
  646. relationalai/experimental/solvers.py +0 -1095
  647. relationalai/loaders/csv.py +0 -195
  648. relationalai/loaders/loader.py +0 -177
  649. relationalai/loaders/types.py +0 -23
  650. relationalai/rel_emitter.py +0 -373
  651. relationalai/rel_utils.py +0 -185
  652. relationalai/semantics/designs/query_builder/identify_by.md +0 -106
  653. relationalai/semantics/devtools/benchmark_lqp.py +0 -535
  654. relationalai/semantics/devtools/compilation_manager.py +0 -294
  655. relationalai/semantics/devtools/extract_lqp.py +0 -110
  656. relationalai/semantics/internal/internal.py +0 -3785
  657. relationalai/semantics/internal/snowflake.py +0 -329
  658. relationalai/semantics/lqp/README.md +0 -34
  659. relationalai/semantics/lqp/algorithms.py +0 -173
  660. relationalai/semantics/lqp/builtins.py +0 -213
  661. relationalai/semantics/lqp/compiler.py +0 -22
  662. relationalai/semantics/lqp/constructors.py +0 -68
  663. relationalai/semantics/lqp/executor.py +0 -518
  664. relationalai/semantics/lqp/export_rewriter.py +0 -40
  665. relationalai/semantics/lqp/intrinsics.py +0 -24
  666. relationalai/semantics/lqp/ir.py +0 -150
  667. relationalai/semantics/lqp/model2lqp.py +0 -1056
  668. relationalai/semantics/lqp/passes.py +0 -38
  669. relationalai/semantics/lqp/primitives.py +0 -252
  670. relationalai/semantics/lqp/result_helpers.py +0 -266
  671. relationalai/semantics/lqp/rewrite/__init__.py +0 -32
  672. relationalai/semantics/lqp/rewrite/algorithm.py +0 -385
  673. relationalai/semantics/lqp/rewrite/annotate_constraints.py +0 -69
  674. relationalai/semantics/lqp/rewrite/cdc.py +0 -216
  675. relationalai/semantics/lqp/rewrite/constants_to_vars.py +0 -70
  676. relationalai/semantics/lqp/rewrite/deduplicate_vars.py +0 -104
  677. relationalai/semantics/lqp/rewrite/eliminate_data.py +0 -108
  678. relationalai/semantics/lqp/rewrite/extract_common.py +0 -340
  679. relationalai/semantics/lqp/rewrite/extract_keys.py +0 -577
  680. relationalai/semantics/lqp/rewrite/flatten_script.py +0 -301
  681. relationalai/semantics/lqp/rewrite/function_annotations.py +0 -114
  682. relationalai/semantics/lqp/rewrite/functional_dependencies.py +0 -348
  683. relationalai/semantics/lqp/rewrite/period_math.py +0 -77
  684. relationalai/semantics/lqp/rewrite/quantify_vars.py +0 -339
  685. relationalai/semantics/lqp/rewrite/splinter.py +0 -76
  686. relationalai/semantics/lqp/rewrite/unify_definitions.py +0 -323
  687. relationalai/semantics/lqp/types.py +0 -101
  688. relationalai/semantics/lqp/utils.py +0 -170
  689. relationalai/semantics/lqp/validators.py +0 -70
  690. relationalai/semantics/metamodel/compiler.py +0 -134
  691. relationalai/semantics/metamodel/dependency.py +0 -880
  692. relationalai/semantics/metamodel/executor.py +0 -78
  693. relationalai/semantics/metamodel/factory.py +0 -287
  694. relationalai/semantics/metamodel/helpers.py +0 -368
  695. relationalai/semantics/metamodel/ir.py +0 -924
  696. relationalai/semantics/metamodel/rewrite/__init__.py +0 -8
  697. relationalai/semantics/metamodel/rewrite/discharge_constraints.py +0 -39
  698. relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +0 -220
  699. relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +0 -78
  700. relationalai/semantics/metamodel/rewrite/flatten.py +0 -590
  701. relationalai/semantics/metamodel/rewrite/format_outputs.py +0 -256
  702. relationalai/semantics/metamodel/rewrite/handle_aggregations_and_ranks.py +0 -237
  703. relationalai/semantics/metamodel/typer/checker.py +0 -355
  704. relationalai/semantics/metamodel/typer/typer.py +0 -1396
  705. relationalai/semantics/metamodel/util.py +0 -506
  706. relationalai/semantics/metamodel/visitor.py +0 -945
  707. relationalai/semantics/reasoners/__init__.py +0 -10
  708. relationalai/semantics/reasoners/graph/README.md +0 -620
  709. relationalai/semantics/reasoners/graph/__init__.py +0 -37
  710. relationalai/semantics/reasoners/graph/core.py +0 -9019
  711. relationalai/semantics/reasoners/graph/design/beyond_demand_transform.md +0 -797
  712. relationalai/semantics/reasoners/graph/tests/README.md +0 -21
  713. relationalai/semantics/reasoners/optimization/__init__.py +0 -68
  714. relationalai/semantics/reasoners/optimization/common.py +0 -88
  715. relationalai/semantics/reasoners/optimization/solvers_dev.py +0 -568
  716. relationalai/semantics/reasoners/optimization/solvers_pb.py +0 -1407
  717. relationalai/semantics/rel/builtins.py +0 -40
  718. relationalai/semantics/rel/compiler.py +0 -994
  719. relationalai/semantics/rel/executor.py +0 -363
  720. relationalai/semantics/rel/rel.py +0 -482
  721. relationalai/semantics/rel/rel_utils.py +0 -276
  722. relationalai/semantics/snowflake/__init__.py +0 -3
  723. relationalai/semantics/sql/compiler.py +0 -2503
  724. relationalai/semantics/sql/executor/duck_db.py +0 -52
  725. relationalai/semantics/sql/executor/result_helpers.py +0 -64
  726. relationalai/semantics/sql/executor/snowflake.py +0 -149
  727. relationalai/semantics/sql/rewrite/denormalize.py +0 -222
  728. relationalai/semantics/sql/rewrite/double_negation.py +0 -49
  729. relationalai/semantics/sql/rewrite/recursive_union.py +0 -127
  730. relationalai/semantics/sql/rewrite/sort_output_query.py +0 -246
  731. relationalai/semantics/sql/sql.py +0 -504
  732. relationalai/semantics/std/pragmas.py +0 -11
  733. relationalai/semantics/std/std.py +0 -14
  734. relationalai/semantics/tests/lqp/algorithms.py +0 -345
  735. relationalai/semantics/tests/test_snapshot_abstract.py +0 -144
  736. relationalai/semantics/tests/test_snapshot_base.py +0 -9
  737. relationalai/semantics/tests/utils.py +0 -46
  738. relationalai/std/__init__.py +0 -70
  739. relationalai/tools/cli.py +0 -2089
  740. relationalai/tools/cli_controls.py +0 -1975
  741. relationalai/tools/cli_helpers.py +0 -802
  742. relationalai/tools/debugger_client.py +0 -109
  743. relationalai/tools/debugger_server.py +0 -302
  744. relationalai/tools/dev.py +0 -685
  745. relationalai/tools/notes +0 -7
  746. relationalai/tools/qb_debugger.py +0 -425
  747. relationalai/tools/txn_progress.py +0 -188
  748. relationalai/util/clean_up_databases.py +0 -95
  749. relationalai/util/list_databases.py +0 -9
  750. relationalai/util/otel_configuration.py +0 -26
  751. relationalai/util/otel_handler.py +0 -484
  752. relationalai/util/snowflake_handler.py +0 -88
  753. relationalai/util/span_format_test.py +0 -43
  754. relationalai/util/span_tracker.py +0 -207
  755. relationalai/util/spans_file_handler.py +0 -72
  756. relationalai/util/tracing_handler.py +0 -34
  757. relationalai-0.13.5.dist-info/METADATA +0 -74
  758. relationalai-0.13.5.dist-info/RECORD +0 -473
  759. relationalai-0.13.5.dist-info/WHEEL +0 -4
  760. relationalai-0.13.5.dist-info/entry_points.txt +0 -3
  761. relationalai-0.13.5.dist-info/licenses/LICENSE +0 -202
  762. relationalai_test_util/__init__.py +0 -4
  763. relationalai_test_util/fixtures.py +0 -233
  764. relationalai_test_util/snapshot.py +0 -252
  765. relationalai_test_util/traceback.py +0 -118
  766. /relationalai/{analysis → semantics/frontend}/__init__.py +0 -0
  767. /relationalai/{auth/__init__.py → semantics/metamodel/metamodel_compiler.py} +0 -0
  768. /relationalai/{early_access → shims}/__init__.py +0 -0
  769. {relationalai/early_access/dsl/adapters → v0/relationalai/analysis}/__init__.py +0 -0
  770. {relationalai → v0/relationalai}/analysis/mechanistic.py +0 -0
  771. {relationalai → v0/relationalai}/analysis/whynot.py +0 -0
  772. {relationalai/early_access/dsl/adapters/orm → v0/relationalai/auth}/__init__.py +0 -0
  773. {relationalai → v0/relationalai}/auth/jwt_generator.py +0 -0
  774. {relationalai → v0/relationalai}/auth/oauth_callback_server.py +0 -0
  775. {relationalai → v0/relationalai}/auth/token_handler.py +0 -0
  776. {relationalai → v0/relationalai}/auth/util.py +0 -0
  777. {relationalai/clients/resources/snowflake → v0/relationalai/clients}/cache_store.py +0 -0
  778. {relationalai → v0/relationalai}/compiler.py +0 -0
  779. {relationalai → v0/relationalai}/dependencies.py +0 -0
  780. {relationalai → v0/relationalai}/docutils.py +0 -0
  781. {relationalai/early_access/dsl/adapters/owl → v0/relationalai/early_access}/__init__.py +0 -0
  782. {relationalai → v0/relationalai}/early_access/dsl/__init__.py +0 -0
  783. {relationalai/early_access/dsl/bindings → v0/relationalai/early_access/dsl/adapters}/__init__.py +0 -0
  784. {relationalai/early_access/dsl/bindings/legacy → v0/relationalai/early_access/dsl/adapters/orm}/__init__.py +0 -0
  785. {relationalai → v0/relationalai}/early_access/dsl/adapters/orm/model.py +0 -0
  786. {relationalai/early_access/dsl/codegen → v0/relationalai/early_access/dsl/adapters/owl}/__init__.py +0 -0
  787. {relationalai → v0/relationalai}/early_access/dsl/adapters/owl/model.py +0 -0
  788. {relationalai/early_access/dsl/core/temporal → v0/relationalai/early_access/dsl/bindings}/__init__.py +0 -0
  789. {relationalai/early_access/dsl/ir → v0/relationalai/early_access/dsl/bindings/legacy}/__init__.py +0 -0
  790. {relationalai/early_access/dsl/ontologies → v0/relationalai/early_access/dsl/codegen}/__init__.py +0 -0
  791. {relationalai → v0/relationalai}/early_access/dsl/constants.py +0 -0
  792. {relationalai → v0/relationalai}/early_access/dsl/core/__init__.py +0 -0
  793. {relationalai → v0/relationalai}/early_access/dsl/core/constraints/__init__.py +0 -0
  794. {relationalai → v0/relationalai}/early_access/dsl/core/constraints/predicate/__init__.py +0 -0
  795. {relationalai → v0/relationalai}/early_access/dsl/core/stack.py +0 -0
  796. {relationalai/early_access/dsl/orm → v0/relationalai/early_access/dsl/core/temporal}/__init__.py +0 -0
  797. {relationalai → v0/relationalai}/early_access/dsl/core/utils.py +0 -0
  798. {relationalai/early_access/dsl/orm/measures → v0/relationalai/early_access/dsl/ir}/__init__.py +0 -0
  799. {relationalai/early_access/dsl/physical_metadata → v0/relationalai/early_access/dsl/ontologies}/__init__.py +0 -0
  800. {relationalai → v0/relationalai}/early_access/dsl/ontologies/raw_source.py +0 -0
  801. {relationalai/early_access/dsl/serialize → v0/relationalai/early_access/dsl/orm}/__init__.py +0 -0
  802. {relationalai/early_access/dsl/snow → v0/relationalai/early_access/dsl/orm/measures}/__init__.py +0 -0
  803. {relationalai → v0/relationalai}/early_access/dsl/orm/reasoner_errors.py +0 -0
  804. {relationalai/loaders → v0/relationalai/early_access/dsl/physical_metadata}/__init__.py +0 -0
  805. {relationalai/semantics/tests → v0/relationalai/early_access/dsl/serialize}/__init__.py +0 -0
  806. {relationalai → v0/relationalai}/early_access/dsl/serialize/binding_model.py +0 -0
  807. {relationalai → v0/relationalai}/early_access/dsl/serialize/model.py +0 -0
  808. {relationalai/semantics/tests/lqp → v0/relationalai/early_access/dsl/snow}/__init__.py +0 -0
  809. {relationalai → v0/relationalai}/early_access/tests/__init__.py +0 -0
  810. {relationalai → v0/relationalai}/environments/ci.py +0 -0
  811. {relationalai → v0/relationalai}/environments/hex.py +0 -0
  812. {relationalai → v0/relationalai}/environments/terminal.py +0 -0
  813. {relationalai → v0/relationalai}/experimental/__init__.py +0 -0
  814. {relationalai → v0/relationalai}/experimental/graphs.py +0 -0
  815. {relationalai → v0/relationalai}/experimental/paths/__init__.py +0 -0
  816. {relationalai → v0/relationalai}/experimental/paths/benchmarks/__init__.py +0 -0
  817. {relationalai → v0/relationalai}/experimental/paths/path_algorithms/__init__.py +0 -0
  818. {relationalai → v0/relationalai}/experimental/paths/rpq/__init__.py +0 -0
  819. {relationalai → v0/relationalai}/experimental/paths/rpq/filter.py +0 -0
  820. {relationalai → v0/relationalai}/experimental/paths/rpq/glushkov.py +0 -0
  821. {relationalai → v0/relationalai}/experimental/paths/rpq/transition.py +0 -0
  822. {relationalai → v0/relationalai}/experimental/paths/utilities/__init__.py +0 -0
  823. {relationalai → v0/relationalai}/experimental/paths/utilities/utilities.py +0 -0
  824. {relationalai/tools → v0/relationalai/loaders}/__init__.py +0 -0
  825. {relationalai → v0/relationalai}/metagen.py +0 -0
  826. {relationalai → v0/relationalai}/metamodel.py +0 -0
  827. {relationalai → v0/relationalai}/rel.py +0 -0
  828. {relationalai → v0/relationalai}/semantics/devtools/__init__.py +0 -0
  829. {relationalai → v0/relationalai}/semantics/internal/__init__.py +0 -0
  830. {relationalai → v0/relationalai}/semantics/internal/annotations.py +0 -0
  831. {relationalai → v0/relationalai}/semantics/lqp/__init__.py +0 -0
  832. {relationalai → v0/relationalai}/semantics/lqp/pragmas.py +0 -0
  833. {relationalai → v0/relationalai}/semantics/metamodel/dataflow.py +0 -0
  834. {relationalai → v0/relationalai}/semantics/metamodel/typer/__init__.py +0 -0
  835. {relationalai → v0/relationalai}/semantics/metamodel/types.py +0 -0
  836. {relationalai → v0/relationalai}/semantics/reasoners/experimental/__init__.py +0 -0
  837. {relationalai → v0/relationalai}/semantics/rel/__init__.py +0 -0
  838. {relationalai → v0/relationalai}/semantics/sql/__init__.py +0 -0
  839. {relationalai → v0/relationalai}/semantics/sql/executor/__init__.py +0 -0
  840. {relationalai → v0/relationalai}/semantics/sql/rewrite/__init__.py +0 -0
  841. {relationalai → v0/relationalai}/semantics/tests/logging.py +0 -0
  842. {relationalai → v0/relationalai}/std/aggregates.py +0 -0
  843. {relationalai → v0/relationalai}/std/dates.py +0 -0
  844. {relationalai → v0/relationalai}/std/graphs.py +0 -0
  845. {relationalai → v0/relationalai}/std/inspect.py +0 -0
  846. {relationalai → v0/relationalai}/std/math.py +0 -0
  847. {relationalai → v0/relationalai}/std/re.py +0 -0
  848. {relationalai → v0/relationalai}/std/strings.py +0 -0
  849. {relationalai → v0/relationalai}/tools/cleanup_snapshots.py +0 -0
  850. {relationalai → v0/relationalai}/tools/constants.py +0 -0
  851. {relationalai → v0/relationalai}/tools/query_utils.py +0 -0
  852. {relationalai → v0/relationalai}/tools/snapshot_viewer.py +0 -0
  853. {relationalai → v0/relationalai}/util/__init__.py +0 -0
  854. {relationalai → v0/relationalai}/util/constants.py +0 -0
  855. {relationalai → v0/relationalai}/util/graph.py +0 -0
  856. {relationalai → v0/relationalai}/util/timeout.py +0 -0
@@ -1,1396 +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 relationalai import debugging
9
- from relationalai.semantics.metamodel import builtins, helpers, ir, types, visitor, compiler, factory as f, executor
10
- from 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 node.reconstruct(name=node.name, type=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
- if not executor.SUPPRESS_TYPE_ERRORS:
1393
- for err in w.net.errors:
1394
- rich.print(str(err), file=sys.stderr)
1395
-
1396
- return final