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.
- relationalai/__init__.py +1 -256
- relationalai/config/__init__.py +56 -0
- relationalai/config/config.py +289 -0
- relationalai/config/config_fields.py +86 -0
- relationalai/config/connections/__init__.py +46 -0
- relationalai/config/connections/base.py +23 -0
- relationalai/config/connections/duckdb.py +29 -0
- relationalai/config/connections/snowflake.py +243 -0
- relationalai/config/external/__init__.py +17 -0
- relationalai/config/external/dbt_converter.py +101 -0
- relationalai/config/external/dbt_models.py +93 -0
- relationalai/config/external/snowflake_converter.py +41 -0
- relationalai/config/external/snowflake_models.py +85 -0
- relationalai/config/external/utils.py +19 -0
- relationalai/config/shims.py +1 -0
- relationalai/semantics/__init__.py +146 -22
- relationalai/semantics/backends/lqp/annotations.py +11 -0
- relationalai/semantics/backends/sql/sql_compiler.py +327 -0
- relationalai/semantics/frontend/base.py +1719 -0
- relationalai/semantics/frontend/core.py +179 -0
- relationalai/semantics/frontend/front_compiler.py +1316 -0
- relationalai/semantics/frontend/pprint.py +408 -0
- relationalai/semantics/metamodel/__init__.py +6 -40
- relationalai/semantics/metamodel/builtins.py +206 -772
- relationalai/semantics/metamodel/metamodel.py +465 -0
- relationalai/semantics/metamodel/metamodel_analyzer.py +519 -0
- relationalai/semantics/metamodel/pprint.py +414 -0
- relationalai/semantics/metamodel/rewriter.py +266 -0
- relationalai/semantics/metamodel/typer.py +1213 -0
- relationalai/semantics/std/__init__.py +60 -40
- relationalai/semantics/std/aggregates.py +148 -0
- relationalai/semantics/std/common.py +44 -0
- relationalai/semantics/std/constraints.py +37 -43
- relationalai/semantics/std/datetime.py +249 -135
- relationalai/semantics/std/decimals.py +45 -52
- relationalai/semantics/std/floats.py +13 -5
- relationalai/semantics/std/integers.py +26 -11
- relationalai/semantics/std/math.py +183 -112
- relationalai/semantics/std/numbers.py +86 -0
- relationalai/semantics/std/re.py +80 -62
- relationalai/semantics/std/strings.py +101 -46
- relationalai/shims/executor.py +179 -0
- relationalai/shims/helpers.py +126 -0
- relationalai/shims/hoister.py +221 -0
- relationalai/shims/mm2v0.py +1394 -0
- relationalai/tools/cli/__init__.py +6 -0
- relationalai/tools/cli/cli.py +90 -0
- relationalai/tools/cli/components/__init__.py +5 -0
- relationalai/tools/cli/components/progress_reader.py +1524 -0
- relationalai/tools/cli/components/utils.py +58 -0
- relationalai/tools/cli/config_template.py +45 -0
- relationalai/tools/cli/dev.py +19 -0
- relationalai/tools/debugger.py +289 -183
- relationalai/tools/typer_debugger.py +93 -0
- relationalai/util/dataclasses.py +43 -0
- relationalai/util/docutils.py +40 -0
- relationalai/util/error.py +199 -0
- relationalai/util/format.py +48 -109
- relationalai/util/naming.py +145 -0
- relationalai/util/python.py +35 -0
- relationalai/util/runtime.py +156 -0
- relationalai/util/schema.py +197 -0
- relationalai/util/source.py +185 -0
- relationalai/util/structures.py +163 -0
- relationalai/util/tracing.py +261 -0
- relationalai-1.0.0a2.dist-info/METADATA +44 -0
- relationalai-1.0.0a2.dist-info/RECORD +489 -0
- relationalai-1.0.0a2.dist-info/WHEEL +5 -0
- relationalai-1.0.0a2.dist-info/entry_points.txt +3 -0
- relationalai-1.0.0a2.dist-info/top_level.txt +2 -0
- v0/relationalai/__init__.py +216 -0
- v0/relationalai/clients/__init__.py +5 -0
- v0/relationalai/clients/azure.py +477 -0
- v0/relationalai/clients/client.py +912 -0
- v0/relationalai/clients/config.py +673 -0
- v0/relationalai/clients/direct_access_client.py +118 -0
- v0/relationalai/clients/hash_util.py +31 -0
- v0/relationalai/clients/local.py +571 -0
- v0/relationalai/clients/profile_polling.py +73 -0
- v0/relationalai/clients/result_helpers.py +420 -0
- v0/relationalai/clients/snowflake.py +3869 -0
- v0/relationalai/clients/types.py +113 -0
- v0/relationalai/clients/use_index_poller.py +980 -0
- v0/relationalai/clients/util.py +356 -0
- v0/relationalai/debugging.py +389 -0
- v0/relationalai/dsl.py +1749 -0
- v0/relationalai/early_access/builder/__init__.py +30 -0
- v0/relationalai/early_access/builder/builder/__init__.py +35 -0
- v0/relationalai/early_access/builder/snowflake/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/__init__.py +25 -0
- v0/relationalai/early_access/builder/std/decimals/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/integers/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/math/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/strings/__init__.py +14 -0
- v0/relationalai/early_access/devtools/__init__.py +12 -0
- v0/relationalai/early_access/devtools/benchmark_lqp/__init__.py +12 -0
- v0/relationalai/early_access/devtools/extract_lqp/__init__.py +12 -0
- v0/relationalai/early_access/dsl/adapters/orm/adapter_qb.py +427 -0
- v0/relationalai/early_access/dsl/adapters/orm/parser.py +636 -0
- v0/relationalai/early_access/dsl/adapters/owl/adapter.py +176 -0
- v0/relationalai/early_access/dsl/adapters/owl/parser.py +160 -0
- v0/relationalai/early_access/dsl/bindings/common.py +402 -0
- v0/relationalai/early_access/dsl/bindings/csv.py +170 -0
- v0/relationalai/early_access/dsl/bindings/legacy/binding_models.py +143 -0
- v0/relationalai/early_access/dsl/bindings/snowflake.py +64 -0
- v0/relationalai/early_access/dsl/codegen/binder.py +411 -0
- v0/relationalai/early_access/dsl/codegen/common.py +79 -0
- v0/relationalai/early_access/dsl/codegen/helpers.py +23 -0
- v0/relationalai/early_access/dsl/codegen/relations.py +700 -0
- v0/relationalai/early_access/dsl/codegen/weaver.py +417 -0
- v0/relationalai/early_access/dsl/core/builders/__init__.py +47 -0
- v0/relationalai/early_access/dsl/core/builders/logic.py +19 -0
- v0/relationalai/early_access/dsl/core/builders/scalar_constraint.py +11 -0
- v0/relationalai/early_access/dsl/core/constraints/predicate/atomic.py +455 -0
- v0/relationalai/early_access/dsl/core/constraints/predicate/universal.py +73 -0
- v0/relationalai/early_access/dsl/core/constraints/scalar.py +310 -0
- v0/relationalai/early_access/dsl/core/context.py +13 -0
- v0/relationalai/early_access/dsl/core/cset.py +132 -0
- v0/relationalai/early_access/dsl/core/exprs/__init__.py +116 -0
- v0/relationalai/early_access/dsl/core/exprs/relational.py +18 -0
- v0/relationalai/early_access/dsl/core/exprs/scalar.py +412 -0
- v0/relationalai/early_access/dsl/core/instances.py +44 -0
- v0/relationalai/early_access/dsl/core/logic/__init__.py +193 -0
- v0/relationalai/early_access/dsl/core/logic/aggregation.py +98 -0
- v0/relationalai/early_access/dsl/core/logic/exists.py +223 -0
- v0/relationalai/early_access/dsl/core/logic/helper.py +163 -0
- v0/relationalai/early_access/dsl/core/namespaces.py +32 -0
- v0/relationalai/early_access/dsl/core/relations.py +276 -0
- v0/relationalai/early_access/dsl/core/rules.py +112 -0
- v0/relationalai/early_access/dsl/core/std/__init__.py +45 -0
- v0/relationalai/early_access/dsl/core/temporal/recall.py +6 -0
- v0/relationalai/early_access/dsl/core/types/__init__.py +270 -0
- v0/relationalai/early_access/dsl/core/types/concepts.py +128 -0
- v0/relationalai/early_access/dsl/core/types/constrained/__init__.py +267 -0
- v0/relationalai/early_access/dsl/core/types/constrained/nominal.py +143 -0
- v0/relationalai/early_access/dsl/core/types/constrained/subtype.py +124 -0
- v0/relationalai/early_access/dsl/core/types/standard.py +92 -0
- v0/relationalai/early_access/dsl/core/types/unconstrained.py +50 -0
- v0/relationalai/early_access/dsl/core/types/variables.py +203 -0
- v0/relationalai/early_access/dsl/ir/compiler.py +318 -0
- v0/relationalai/early_access/dsl/ir/executor.py +260 -0
- v0/relationalai/early_access/dsl/ontologies/constraints.py +88 -0
- v0/relationalai/early_access/dsl/ontologies/export.py +30 -0
- v0/relationalai/early_access/dsl/ontologies/models.py +453 -0
- v0/relationalai/early_access/dsl/ontologies/python_printer.py +303 -0
- v0/relationalai/early_access/dsl/ontologies/readings.py +60 -0
- v0/relationalai/early_access/dsl/ontologies/relationships.py +322 -0
- v0/relationalai/early_access/dsl/ontologies/roles.py +87 -0
- v0/relationalai/early_access/dsl/ontologies/subtyping.py +55 -0
- v0/relationalai/early_access/dsl/orm/constraints.py +438 -0
- v0/relationalai/early_access/dsl/orm/measures/dimensions.py +200 -0
- v0/relationalai/early_access/dsl/orm/measures/initializer.py +16 -0
- v0/relationalai/early_access/dsl/orm/measures/measure_rules.py +275 -0
- v0/relationalai/early_access/dsl/orm/measures/measures.py +299 -0
- v0/relationalai/early_access/dsl/orm/measures/role_exprs.py +268 -0
- v0/relationalai/early_access/dsl/orm/models.py +256 -0
- v0/relationalai/early_access/dsl/orm/object_oriented_printer.py +344 -0
- v0/relationalai/early_access/dsl/orm/printer.py +469 -0
- v0/relationalai/early_access/dsl/orm/reasoners.py +480 -0
- v0/relationalai/early_access/dsl/orm/relations.py +19 -0
- v0/relationalai/early_access/dsl/orm/relationships.py +251 -0
- v0/relationalai/early_access/dsl/orm/types.py +42 -0
- v0/relationalai/early_access/dsl/orm/utils.py +79 -0
- v0/relationalai/early_access/dsl/orm/verb.py +204 -0
- v0/relationalai/early_access/dsl/physical_metadata/tables.py +133 -0
- v0/relationalai/early_access/dsl/relations.py +170 -0
- v0/relationalai/early_access/dsl/rulesets.py +69 -0
- v0/relationalai/early_access/dsl/schemas/__init__.py +450 -0
- v0/relationalai/early_access/dsl/schemas/builder.py +48 -0
- v0/relationalai/early_access/dsl/schemas/comp_names.py +51 -0
- v0/relationalai/early_access/dsl/schemas/components.py +203 -0
- v0/relationalai/early_access/dsl/schemas/contexts.py +156 -0
- v0/relationalai/early_access/dsl/schemas/exprs.py +89 -0
- v0/relationalai/early_access/dsl/schemas/fragments.py +464 -0
- v0/relationalai/early_access/dsl/serialization.py +79 -0
- v0/relationalai/early_access/dsl/serialize/exporter.py +163 -0
- v0/relationalai/early_access/dsl/snow/api.py +104 -0
- v0/relationalai/early_access/dsl/snow/common.py +76 -0
- v0/relationalai/early_access/dsl/state_mgmt/__init__.py +129 -0
- v0/relationalai/early_access/dsl/state_mgmt/state_charts.py +125 -0
- v0/relationalai/early_access/dsl/state_mgmt/transitions.py +130 -0
- v0/relationalai/early_access/dsl/types/__init__.py +40 -0
- v0/relationalai/early_access/dsl/types/concepts.py +12 -0
- v0/relationalai/early_access/dsl/types/entities.py +135 -0
- v0/relationalai/early_access/dsl/types/values.py +17 -0
- v0/relationalai/early_access/dsl/utils.py +102 -0
- v0/relationalai/early_access/graphs/__init__.py +13 -0
- v0/relationalai/early_access/lqp/__init__.py +12 -0
- v0/relationalai/early_access/lqp/compiler/__init__.py +12 -0
- v0/relationalai/early_access/lqp/constructors/__init__.py +18 -0
- v0/relationalai/early_access/lqp/executor/__init__.py +12 -0
- v0/relationalai/early_access/lqp/ir/__init__.py +12 -0
- v0/relationalai/early_access/lqp/passes/__init__.py +12 -0
- v0/relationalai/early_access/lqp/pragmas/__init__.py +12 -0
- v0/relationalai/early_access/lqp/primitives/__init__.py +12 -0
- v0/relationalai/early_access/lqp/types/__init__.py +12 -0
- v0/relationalai/early_access/lqp/utils/__init__.py +12 -0
- v0/relationalai/early_access/lqp/validators/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/__init__.py +58 -0
- v0/relationalai/early_access/metamodel/builtins/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/compiler/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/dependency/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/factory/__init__.py +17 -0
- v0/relationalai/early_access/metamodel/helpers/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/ir/__init__.py +14 -0
- v0/relationalai/early_access/metamodel/rewrite/__init__.py +7 -0
- v0/relationalai/early_access/metamodel/typer/__init__.py +3 -0
- v0/relationalai/early_access/metamodel/typer/typer/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/types/__init__.py +15 -0
- v0/relationalai/early_access/metamodel/util/__init__.py +15 -0
- v0/relationalai/early_access/metamodel/visitor/__init__.py +12 -0
- v0/relationalai/early_access/rel/__init__.py +12 -0
- v0/relationalai/early_access/rel/executor/__init__.py +12 -0
- v0/relationalai/early_access/rel/rel_utils/__init__.py +12 -0
- v0/relationalai/early_access/rel/rewrite/__init__.py +7 -0
- v0/relationalai/early_access/solvers/__init__.py +19 -0
- v0/relationalai/early_access/sql/__init__.py +11 -0
- v0/relationalai/early_access/sql/executor/__init__.py +3 -0
- v0/relationalai/early_access/sql/rewrite/__init__.py +3 -0
- v0/relationalai/early_access/tests/logging/__init__.py +12 -0
- v0/relationalai/early_access/tests/test_snapshot_base/__init__.py +12 -0
- v0/relationalai/early_access/tests/utils/__init__.py +12 -0
- v0/relationalai/environments/__init__.py +35 -0
- v0/relationalai/environments/base.py +381 -0
- v0/relationalai/environments/colab.py +14 -0
- v0/relationalai/environments/generic.py +71 -0
- v0/relationalai/environments/ipython.py +68 -0
- v0/relationalai/environments/jupyter.py +9 -0
- v0/relationalai/environments/snowbook.py +169 -0
- v0/relationalai/errors.py +2478 -0
- v0/relationalai/experimental/SF.py +38 -0
- v0/relationalai/experimental/inspect.py +47 -0
- v0/relationalai/experimental/pathfinder/__init__.py +158 -0
- v0/relationalai/experimental/pathfinder/api.py +160 -0
- v0/relationalai/experimental/pathfinder/automaton.py +584 -0
- v0/relationalai/experimental/pathfinder/bridge.py +226 -0
- v0/relationalai/experimental/pathfinder/compiler.py +416 -0
- v0/relationalai/experimental/pathfinder/datalog.py +214 -0
- v0/relationalai/experimental/pathfinder/diagnostics.py +56 -0
- v0/relationalai/experimental/pathfinder/filter.py +236 -0
- v0/relationalai/experimental/pathfinder/glushkov.py +439 -0
- v0/relationalai/experimental/pathfinder/options.py +265 -0
- v0/relationalai/experimental/pathfinder/rpq.py +344 -0
- v0/relationalai/experimental/pathfinder/transition.py +200 -0
- v0/relationalai/experimental/pathfinder/utils.py +26 -0
- v0/relationalai/experimental/paths/api.py +143 -0
- v0/relationalai/experimental/paths/benchmarks/grid_graph.py +37 -0
- v0/relationalai/experimental/paths/examples/basic_example.py +40 -0
- v0/relationalai/experimental/paths/examples/minimal_engine_warmup.py +3 -0
- v0/relationalai/experimental/paths/examples/movie_example.py +77 -0
- v0/relationalai/experimental/paths/examples/paths_benchmark.py +115 -0
- v0/relationalai/experimental/paths/examples/paths_example.py +116 -0
- v0/relationalai/experimental/paths/examples/pattern_to_automaton.py +28 -0
- v0/relationalai/experimental/paths/find_paths_via_automaton.py +85 -0
- v0/relationalai/experimental/paths/graph.py +185 -0
- v0/relationalai/experimental/paths/path_algorithms/find_paths.py +280 -0
- v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +26 -0
- v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +111 -0
- v0/relationalai/experimental/paths/path_algorithms/single.py +59 -0
- v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +39 -0
- v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +103 -0
- v0/relationalai/experimental/paths/path_algorithms/usp-old.py +130 -0
- v0/relationalai/experimental/paths/path_algorithms/usp-tuple.py +183 -0
- v0/relationalai/experimental/paths/path_algorithms/usp.py +150 -0
- v0/relationalai/experimental/paths/product_graph.py +93 -0
- v0/relationalai/experimental/paths/rpq/automaton.py +584 -0
- v0/relationalai/experimental/paths/rpq/diagnostics.py +56 -0
- v0/relationalai/experimental/paths/rpq/rpq.py +378 -0
- v0/relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +90 -0
- v0/relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +119 -0
- v0/relationalai/experimental/paths/tests/tests_limit_sp_single.py +104 -0
- v0/relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +113 -0
- v0/relationalai/experimental/paths/tests/tests_limit_walks_single.py +149 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +70 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +64 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +115 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +75 -0
- v0/relationalai/experimental/paths/tests/tests_single_paths.py +152 -0
- v0/relationalai/experimental/paths/tests/tests_single_walks.py +208 -0
- v0/relationalai/experimental/paths/tests/tests_single_walks_undirected.py +297 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +107 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +76 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +76 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +110 -0
- v0/relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +229 -0
- v0/relationalai/experimental/paths/tests/tests_usp_nsp_single.py +108 -0
- v0/relationalai/experimental/paths/tree_agg.py +168 -0
- v0/relationalai/experimental/paths/utilities/iterators.py +27 -0
- v0/relationalai/experimental/paths/utilities/prefix_sum.py +91 -0
- v0/relationalai/experimental/solvers.py +1087 -0
- v0/relationalai/loaders/csv.py +195 -0
- v0/relationalai/loaders/loader.py +177 -0
- v0/relationalai/loaders/types.py +23 -0
- v0/relationalai/rel_emitter.py +373 -0
- v0/relationalai/rel_utils.py +185 -0
- v0/relationalai/semantics/__init__.py +29 -0
- v0/relationalai/semantics/devtools/benchmark_lqp.py +536 -0
- v0/relationalai/semantics/devtools/compilation_manager.py +294 -0
- v0/relationalai/semantics/devtools/extract_lqp.py +110 -0
- v0/relationalai/semantics/internal/internal.py +3785 -0
- v0/relationalai/semantics/internal/snowflake.py +325 -0
- v0/relationalai/semantics/lqp/builtins.py +16 -0
- v0/relationalai/semantics/lqp/compiler.py +22 -0
- v0/relationalai/semantics/lqp/constructors.py +68 -0
- v0/relationalai/semantics/lqp/executor.py +474 -0
- v0/relationalai/semantics/lqp/intrinsics.py +24 -0
- v0/relationalai/semantics/lqp/ir.py +124 -0
- v0/relationalai/semantics/lqp/model2lqp.py +877 -0
- v0/relationalai/semantics/lqp/passes.py +680 -0
- v0/relationalai/semantics/lqp/primitives.py +252 -0
- v0/relationalai/semantics/lqp/result_helpers.py +202 -0
- v0/relationalai/semantics/lqp/rewrite/__init__.py +18 -0
- v0/relationalai/semantics/lqp/rewrite/annotate_constraints.py +57 -0
- v0/relationalai/semantics/lqp/rewrite/cdc.py +216 -0
- v0/relationalai/semantics/lqp/rewrite/extract_common.py +338 -0
- v0/relationalai/semantics/lqp/rewrite/extract_keys.py +490 -0
- v0/relationalai/semantics/lqp/rewrite/function_annotations.py +114 -0
- v0/relationalai/semantics/lqp/rewrite/functional_dependencies.py +314 -0
- v0/relationalai/semantics/lqp/rewrite/quantify_vars.py +296 -0
- v0/relationalai/semantics/lqp/rewrite/splinter.py +76 -0
- v0/relationalai/semantics/lqp/types.py +101 -0
- v0/relationalai/semantics/lqp/utils.py +160 -0
- v0/relationalai/semantics/lqp/validators.py +57 -0
- v0/relationalai/semantics/metamodel/__init__.py +40 -0
- v0/relationalai/semantics/metamodel/builtins.py +776 -0
- v0/relationalai/semantics/metamodel/compiler.py +133 -0
- v0/relationalai/semantics/metamodel/dependency.py +862 -0
- v0/relationalai/semantics/metamodel/executor.py +61 -0
- v0/relationalai/semantics/metamodel/factory.py +287 -0
- v0/relationalai/semantics/metamodel/helpers.py +361 -0
- v0/relationalai/semantics/metamodel/ir.py +923 -0
- v0/relationalai/semantics/metamodel/rewrite/__init__.py +7 -0
- v0/relationalai/semantics/metamodel/rewrite/discharge_constraints.py +39 -0
- v0/relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +210 -0
- v0/relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +78 -0
- v0/relationalai/semantics/metamodel/rewrite/flatten.py +554 -0
- v0/relationalai/semantics/metamodel/rewrite/format_outputs.py +165 -0
- v0/relationalai/semantics/metamodel/typer/checker.py +353 -0
- v0/relationalai/semantics/metamodel/typer/typer.py +1395 -0
- v0/relationalai/semantics/metamodel/util.py +505 -0
- v0/relationalai/semantics/metamodel/visitor.py +944 -0
- v0/relationalai/semantics/reasoners/__init__.py +10 -0
- v0/relationalai/semantics/reasoners/graph/__init__.py +37 -0
- v0/relationalai/semantics/reasoners/graph/core.py +9019 -0
- v0/relationalai/semantics/reasoners/optimization/__init__.py +68 -0
- v0/relationalai/semantics/reasoners/optimization/common.py +88 -0
- v0/relationalai/semantics/reasoners/optimization/solvers_dev.py +568 -0
- v0/relationalai/semantics/reasoners/optimization/solvers_pb.py +1163 -0
- v0/relationalai/semantics/rel/builtins.py +40 -0
- v0/relationalai/semantics/rel/compiler.py +989 -0
- v0/relationalai/semantics/rel/executor.py +359 -0
- v0/relationalai/semantics/rel/rel.py +482 -0
- v0/relationalai/semantics/rel/rel_utils.py +276 -0
- v0/relationalai/semantics/snowflake/__init__.py +3 -0
- v0/relationalai/semantics/sql/compiler.py +2503 -0
- v0/relationalai/semantics/sql/executor/duck_db.py +52 -0
- v0/relationalai/semantics/sql/executor/result_helpers.py +64 -0
- v0/relationalai/semantics/sql/executor/snowflake.py +145 -0
- v0/relationalai/semantics/sql/rewrite/denormalize.py +222 -0
- v0/relationalai/semantics/sql/rewrite/double_negation.py +49 -0
- v0/relationalai/semantics/sql/rewrite/recursive_union.py +127 -0
- v0/relationalai/semantics/sql/rewrite/sort_output_query.py +246 -0
- v0/relationalai/semantics/sql/sql.py +504 -0
- v0/relationalai/semantics/std/__init__.py +54 -0
- v0/relationalai/semantics/std/constraints.py +43 -0
- v0/relationalai/semantics/std/datetime.py +363 -0
- v0/relationalai/semantics/std/decimals.py +62 -0
- v0/relationalai/semantics/std/floats.py +7 -0
- v0/relationalai/semantics/std/integers.py +22 -0
- v0/relationalai/semantics/std/math.py +141 -0
- v0/relationalai/semantics/std/pragmas.py +11 -0
- v0/relationalai/semantics/std/re.py +83 -0
- v0/relationalai/semantics/std/std.py +14 -0
- v0/relationalai/semantics/std/strings.py +63 -0
- v0/relationalai/semantics/tests/__init__.py +0 -0
- v0/relationalai/semantics/tests/test_snapshot_abstract.py +143 -0
- v0/relationalai/semantics/tests/test_snapshot_base.py +9 -0
- v0/relationalai/semantics/tests/utils.py +46 -0
- v0/relationalai/std/__init__.py +70 -0
- v0/relationalai/tools/__init__.py +0 -0
- v0/relationalai/tools/cli.py +1940 -0
- v0/relationalai/tools/cli_controls.py +1826 -0
- v0/relationalai/tools/cli_helpers.py +390 -0
- v0/relationalai/tools/debugger.py +183 -0
- v0/relationalai/tools/debugger_client.py +109 -0
- v0/relationalai/tools/debugger_server.py +302 -0
- v0/relationalai/tools/dev.py +685 -0
- v0/relationalai/tools/qb_debugger.py +425 -0
- v0/relationalai/util/clean_up_databases.py +95 -0
- v0/relationalai/util/format.py +123 -0
- v0/relationalai/util/list_databases.py +9 -0
- v0/relationalai/util/otel_configuration.py +25 -0
- v0/relationalai/util/otel_handler.py +484 -0
- v0/relationalai/util/snowflake_handler.py +88 -0
- v0/relationalai/util/span_format_test.py +43 -0
- v0/relationalai/util/span_tracker.py +207 -0
- v0/relationalai/util/spans_file_handler.py +72 -0
- v0/relationalai/util/tracing_handler.py +34 -0
- frontend/debugger/dist/.gitignore +0 -2
- frontend/debugger/dist/assets/favicon-Dy0ZgA6N.png +0 -0
- frontend/debugger/dist/assets/index-Cssla-O7.js +0 -208
- frontend/debugger/dist/assets/index-DlHsYx1V.css +0 -9
- frontend/debugger/dist/index.html +0 -17
- relationalai/clients/__init__.py +0 -18
- relationalai/clients/client.py +0 -946
- relationalai/clients/config.py +0 -673
- relationalai/clients/direct_access_client.py +0 -118
- relationalai/clients/exec_txn_poller.py +0 -153
- relationalai/clients/hash_util.py +0 -31
- relationalai/clients/local.py +0 -594
- relationalai/clients/profile_polling.py +0 -73
- relationalai/clients/resources/__init__.py +0 -8
- relationalai/clients/resources/azure/azure.py +0 -502
- relationalai/clients/resources/snowflake/__init__.py +0 -20
- relationalai/clients/resources/snowflake/cli_resources.py +0 -98
- relationalai/clients/resources/snowflake/direct_access_resources.py +0 -739
- relationalai/clients/resources/snowflake/engine_service.py +0 -381
- relationalai/clients/resources/snowflake/engine_state_handlers.py +0 -315
- relationalai/clients/resources/snowflake/error_handlers.py +0 -240
- relationalai/clients/resources/snowflake/export_procedure.py.jinja +0 -249
- relationalai/clients/resources/snowflake/resources_factory.py +0 -99
- relationalai/clients/resources/snowflake/snowflake.py +0 -3193
- relationalai/clients/resources/snowflake/use_index_poller.py +0 -1019
- relationalai/clients/resources/snowflake/use_index_resources.py +0 -188
- relationalai/clients/resources/snowflake/util.py +0 -387
- relationalai/clients/result_helpers.py +0 -420
- relationalai/clients/types.py +0 -118
- relationalai/clients/util.py +0 -356
- relationalai/debugging.py +0 -389
- relationalai/dsl.py +0 -1749
- relationalai/early_access/builder/__init__.py +0 -30
- relationalai/early_access/builder/builder/__init__.py +0 -35
- relationalai/early_access/builder/snowflake/__init__.py +0 -12
- relationalai/early_access/builder/std/__init__.py +0 -25
- relationalai/early_access/builder/std/decimals/__init__.py +0 -12
- relationalai/early_access/builder/std/integers/__init__.py +0 -12
- relationalai/early_access/builder/std/math/__init__.py +0 -12
- relationalai/early_access/builder/std/strings/__init__.py +0 -14
- relationalai/early_access/devtools/__init__.py +0 -12
- relationalai/early_access/devtools/benchmark_lqp/__init__.py +0 -12
- relationalai/early_access/devtools/extract_lqp/__init__.py +0 -12
- relationalai/early_access/dsl/adapters/orm/adapter_qb.py +0 -427
- relationalai/early_access/dsl/adapters/orm/parser.py +0 -636
- relationalai/early_access/dsl/adapters/owl/adapter.py +0 -176
- relationalai/early_access/dsl/adapters/owl/parser.py +0 -160
- relationalai/early_access/dsl/bindings/common.py +0 -402
- relationalai/early_access/dsl/bindings/csv.py +0 -170
- relationalai/early_access/dsl/bindings/legacy/binding_models.py +0 -143
- relationalai/early_access/dsl/bindings/snowflake.py +0 -64
- relationalai/early_access/dsl/codegen/binder.py +0 -411
- relationalai/early_access/dsl/codegen/common.py +0 -79
- relationalai/early_access/dsl/codegen/helpers.py +0 -23
- relationalai/early_access/dsl/codegen/relations.py +0 -700
- relationalai/early_access/dsl/codegen/weaver.py +0 -417
- relationalai/early_access/dsl/core/builders/__init__.py +0 -47
- relationalai/early_access/dsl/core/builders/logic.py +0 -19
- relationalai/early_access/dsl/core/builders/scalar_constraint.py +0 -11
- relationalai/early_access/dsl/core/constraints/predicate/atomic.py +0 -455
- relationalai/early_access/dsl/core/constraints/predicate/universal.py +0 -73
- relationalai/early_access/dsl/core/constraints/scalar.py +0 -310
- relationalai/early_access/dsl/core/context.py +0 -13
- relationalai/early_access/dsl/core/cset.py +0 -132
- relationalai/early_access/dsl/core/exprs/__init__.py +0 -116
- relationalai/early_access/dsl/core/exprs/relational.py +0 -18
- relationalai/early_access/dsl/core/exprs/scalar.py +0 -412
- relationalai/early_access/dsl/core/instances.py +0 -44
- relationalai/early_access/dsl/core/logic/__init__.py +0 -193
- relationalai/early_access/dsl/core/logic/aggregation.py +0 -98
- relationalai/early_access/dsl/core/logic/exists.py +0 -223
- relationalai/early_access/dsl/core/logic/helper.py +0 -163
- relationalai/early_access/dsl/core/namespaces.py +0 -32
- relationalai/early_access/dsl/core/relations.py +0 -276
- relationalai/early_access/dsl/core/rules.py +0 -112
- relationalai/early_access/dsl/core/std/__init__.py +0 -45
- relationalai/early_access/dsl/core/temporal/recall.py +0 -6
- relationalai/early_access/dsl/core/types/__init__.py +0 -270
- relationalai/early_access/dsl/core/types/concepts.py +0 -128
- relationalai/early_access/dsl/core/types/constrained/__init__.py +0 -267
- relationalai/early_access/dsl/core/types/constrained/nominal.py +0 -143
- relationalai/early_access/dsl/core/types/constrained/subtype.py +0 -124
- relationalai/early_access/dsl/core/types/standard.py +0 -92
- relationalai/early_access/dsl/core/types/unconstrained.py +0 -50
- relationalai/early_access/dsl/core/types/variables.py +0 -203
- relationalai/early_access/dsl/ir/compiler.py +0 -318
- relationalai/early_access/dsl/ir/executor.py +0 -260
- relationalai/early_access/dsl/ontologies/constraints.py +0 -88
- relationalai/early_access/dsl/ontologies/export.py +0 -30
- relationalai/early_access/dsl/ontologies/models.py +0 -453
- relationalai/early_access/dsl/ontologies/python_printer.py +0 -303
- relationalai/early_access/dsl/ontologies/readings.py +0 -60
- relationalai/early_access/dsl/ontologies/relationships.py +0 -322
- relationalai/early_access/dsl/ontologies/roles.py +0 -87
- relationalai/early_access/dsl/ontologies/subtyping.py +0 -55
- relationalai/early_access/dsl/orm/constraints.py +0 -438
- relationalai/early_access/dsl/orm/measures/dimensions.py +0 -200
- relationalai/early_access/dsl/orm/measures/initializer.py +0 -16
- relationalai/early_access/dsl/orm/measures/measure_rules.py +0 -275
- relationalai/early_access/dsl/orm/measures/measures.py +0 -299
- relationalai/early_access/dsl/orm/measures/role_exprs.py +0 -268
- relationalai/early_access/dsl/orm/models.py +0 -256
- relationalai/early_access/dsl/orm/object_oriented_printer.py +0 -344
- relationalai/early_access/dsl/orm/printer.py +0 -469
- relationalai/early_access/dsl/orm/reasoners.py +0 -480
- relationalai/early_access/dsl/orm/relations.py +0 -19
- relationalai/early_access/dsl/orm/relationships.py +0 -251
- relationalai/early_access/dsl/orm/types.py +0 -42
- relationalai/early_access/dsl/orm/utils.py +0 -79
- relationalai/early_access/dsl/orm/verb.py +0 -204
- relationalai/early_access/dsl/physical_metadata/tables.py +0 -133
- relationalai/early_access/dsl/relations.py +0 -170
- relationalai/early_access/dsl/rulesets.py +0 -69
- relationalai/early_access/dsl/schemas/__init__.py +0 -450
- relationalai/early_access/dsl/schemas/builder.py +0 -48
- relationalai/early_access/dsl/schemas/comp_names.py +0 -51
- relationalai/early_access/dsl/schemas/components.py +0 -203
- relationalai/early_access/dsl/schemas/contexts.py +0 -156
- relationalai/early_access/dsl/schemas/exprs.py +0 -89
- relationalai/early_access/dsl/schemas/fragments.py +0 -464
- relationalai/early_access/dsl/serialization.py +0 -79
- relationalai/early_access/dsl/serialize/exporter.py +0 -163
- relationalai/early_access/dsl/snow/api.py +0 -105
- relationalai/early_access/dsl/snow/common.py +0 -76
- relationalai/early_access/dsl/state_mgmt/__init__.py +0 -129
- relationalai/early_access/dsl/state_mgmt/state_charts.py +0 -125
- relationalai/early_access/dsl/state_mgmt/transitions.py +0 -130
- relationalai/early_access/dsl/types/__init__.py +0 -40
- relationalai/early_access/dsl/types/concepts.py +0 -12
- relationalai/early_access/dsl/types/entities.py +0 -135
- relationalai/early_access/dsl/types/values.py +0 -17
- relationalai/early_access/dsl/utils.py +0 -102
- relationalai/early_access/graphs/__init__.py +0 -13
- relationalai/early_access/lqp/__init__.py +0 -12
- relationalai/early_access/lqp/compiler/__init__.py +0 -12
- relationalai/early_access/lqp/constructors/__init__.py +0 -18
- relationalai/early_access/lqp/executor/__init__.py +0 -12
- relationalai/early_access/lqp/ir/__init__.py +0 -12
- relationalai/early_access/lqp/passes/__init__.py +0 -12
- relationalai/early_access/lqp/pragmas/__init__.py +0 -12
- relationalai/early_access/lqp/primitives/__init__.py +0 -12
- relationalai/early_access/lqp/types/__init__.py +0 -12
- relationalai/early_access/lqp/utils/__init__.py +0 -12
- relationalai/early_access/lqp/validators/__init__.py +0 -12
- relationalai/early_access/metamodel/__init__.py +0 -58
- relationalai/early_access/metamodel/builtins/__init__.py +0 -12
- relationalai/early_access/metamodel/compiler/__init__.py +0 -12
- relationalai/early_access/metamodel/dependency/__init__.py +0 -12
- relationalai/early_access/metamodel/factory/__init__.py +0 -17
- relationalai/early_access/metamodel/helpers/__init__.py +0 -12
- relationalai/early_access/metamodel/ir/__init__.py +0 -14
- relationalai/early_access/metamodel/rewrite/__init__.py +0 -7
- relationalai/early_access/metamodel/typer/__init__.py +0 -3
- relationalai/early_access/metamodel/typer/typer/__init__.py +0 -12
- relationalai/early_access/metamodel/types/__init__.py +0 -15
- relationalai/early_access/metamodel/util/__init__.py +0 -15
- relationalai/early_access/metamodel/visitor/__init__.py +0 -12
- relationalai/early_access/rel/__init__.py +0 -12
- relationalai/early_access/rel/executor/__init__.py +0 -12
- relationalai/early_access/rel/rel_utils/__init__.py +0 -12
- relationalai/early_access/rel/rewrite/__init__.py +0 -7
- relationalai/early_access/solvers/__init__.py +0 -19
- relationalai/early_access/sql/__init__.py +0 -11
- relationalai/early_access/sql/executor/__init__.py +0 -3
- relationalai/early_access/sql/rewrite/__init__.py +0 -3
- relationalai/early_access/tests/logging/__init__.py +0 -12
- relationalai/early_access/tests/test_snapshot_base/__init__.py +0 -12
- relationalai/early_access/tests/utils/__init__.py +0 -12
- relationalai/environments/__init__.py +0 -35
- relationalai/environments/base.py +0 -381
- relationalai/environments/colab.py +0 -14
- relationalai/environments/generic.py +0 -71
- relationalai/environments/ipython.py +0 -68
- relationalai/environments/jupyter.py +0 -9
- relationalai/environments/snowbook.py +0 -169
- relationalai/errors.py +0 -2496
- relationalai/experimental/SF.py +0 -38
- relationalai/experimental/inspect.py +0 -47
- relationalai/experimental/pathfinder/__init__.py +0 -158
- relationalai/experimental/pathfinder/api.py +0 -160
- relationalai/experimental/pathfinder/automaton.py +0 -584
- relationalai/experimental/pathfinder/bridge.py +0 -226
- relationalai/experimental/pathfinder/compiler.py +0 -416
- relationalai/experimental/pathfinder/datalog.py +0 -214
- relationalai/experimental/pathfinder/diagnostics.py +0 -56
- relationalai/experimental/pathfinder/filter.py +0 -236
- relationalai/experimental/pathfinder/glushkov.py +0 -439
- relationalai/experimental/pathfinder/options.py +0 -265
- relationalai/experimental/pathfinder/pathfinder-v0.7.0.rel +0 -1951
- relationalai/experimental/pathfinder/rpq.py +0 -344
- relationalai/experimental/pathfinder/transition.py +0 -200
- relationalai/experimental/pathfinder/utils.py +0 -26
- relationalai/experimental/paths/README.md +0 -107
- relationalai/experimental/paths/api.py +0 -143
- relationalai/experimental/paths/benchmarks/grid_graph.py +0 -37
- relationalai/experimental/paths/code_organization.md +0 -2
- relationalai/experimental/paths/examples/Movies.ipynb +0 -16328
- relationalai/experimental/paths/examples/basic_example.py +0 -40
- relationalai/experimental/paths/examples/minimal_engine_warmup.py +0 -3
- relationalai/experimental/paths/examples/movie_example.py +0 -77
- relationalai/experimental/paths/examples/movies_data/actedin.csv +0 -193
- relationalai/experimental/paths/examples/movies_data/directed.csv +0 -45
- relationalai/experimental/paths/examples/movies_data/follows.csv +0 -7
- relationalai/experimental/paths/examples/movies_data/movies.csv +0 -39
- relationalai/experimental/paths/examples/movies_data/person.csv +0 -134
- relationalai/experimental/paths/examples/movies_data/produced.csv +0 -16
- relationalai/experimental/paths/examples/movies_data/ratings.csv +0 -10
- relationalai/experimental/paths/examples/movies_data/wrote.csv +0 -11
- relationalai/experimental/paths/examples/paths_benchmark.py +0 -115
- relationalai/experimental/paths/examples/paths_example.py +0 -116
- relationalai/experimental/paths/examples/pattern_to_automaton.py +0 -28
- relationalai/experimental/paths/find_paths_via_automaton.py +0 -85
- relationalai/experimental/paths/graph.py +0 -185
- relationalai/experimental/paths/path_algorithms/find_paths.py +0 -280
- relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +0 -26
- relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +0 -111
- relationalai/experimental/paths/path_algorithms/single.py +0 -59
- relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +0 -39
- relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +0 -103
- relationalai/experimental/paths/path_algorithms/usp-old.py +0 -130
- relationalai/experimental/paths/path_algorithms/usp-tuple.py +0 -183
- relationalai/experimental/paths/path_algorithms/usp.py +0 -150
- relationalai/experimental/paths/product_graph.py +0 -93
- relationalai/experimental/paths/rpq/automaton.py +0 -584
- relationalai/experimental/paths/rpq/diagnostics.py +0 -56
- relationalai/experimental/paths/rpq/rpq.py +0 -378
- relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +0 -90
- relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +0 -119
- relationalai/experimental/paths/tests/tests_limit_sp_single.py +0 -104
- relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +0 -113
- relationalai/experimental/paths/tests/tests_limit_walks_single.py +0 -149
- relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +0 -70
- relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +0 -64
- relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +0 -115
- relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +0 -75
- relationalai/experimental/paths/tests/tests_single_paths.py +0 -152
- relationalai/experimental/paths/tests/tests_single_walks.py +0 -208
- relationalai/experimental/paths/tests/tests_single_walks_undirected.py +0 -297
- relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +0 -107
- relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +0 -76
- relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +0 -76
- relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +0 -110
- relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +0 -229
- relationalai/experimental/paths/tests/tests_usp_nsp_single.py +0 -108
- relationalai/experimental/paths/tree_agg.py +0 -168
- relationalai/experimental/paths/utilities/iterators.py +0 -27
- relationalai/experimental/paths/utilities/prefix_sum.py +0 -91
- relationalai/experimental/solvers.py +0 -1095
- relationalai/loaders/csv.py +0 -195
- relationalai/loaders/loader.py +0 -177
- relationalai/loaders/types.py +0 -23
- relationalai/rel_emitter.py +0 -373
- relationalai/rel_utils.py +0 -185
- relationalai/semantics/designs/query_builder/identify_by.md +0 -106
- relationalai/semantics/devtools/benchmark_lqp.py +0 -535
- relationalai/semantics/devtools/compilation_manager.py +0 -294
- relationalai/semantics/devtools/extract_lqp.py +0 -110
- relationalai/semantics/internal/internal.py +0 -3785
- relationalai/semantics/internal/snowflake.py +0 -329
- relationalai/semantics/lqp/README.md +0 -34
- relationalai/semantics/lqp/algorithms.py +0 -173
- relationalai/semantics/lqp/builtins.py +0 -213
- relationalai/semantics/lqp/compiler.py +0 -22
- relationalai/semantics/lqp/constructors.py +0 -68
- relationalai/semantics/lqp/executor.py +0 -518
- relationalai/semantics/lqp/export_rewriter.py +0 -40
- relationalai/semantics/lqp/intrinsics.py +0 -24
- relationalai/semantics/lqp/ir.py +0 -150
- relationalai/semantics/lqp/model2lqp.py +0 -1056
- relationalai/semantics/lqp/passes.py +0 -38
- relationalai/semantics/lqp/primitives.py +0 -252
- relationalai/semantics/lqp/result_helpers.py +0 -266
- relationalai/semantics/lqp/rewrite/__init__.py +0 -32
- relationalai/semantics/lqp/rewrite/algorithm.py +0 -385
- relationalai/semantics/lqp/rewrite/annotate_constraints.py +0 -69
- relationalai/semantics/lqp/rewrite/cdc.py +0 -216
- relationalai/semantics/lqp/rewrite/constants_to_vars.py +0 -70
- relationalai/semantics/lqp/rewrite/deduplicate_vars.py +0 -104
- relationalai/semantics/lqp/rewrite/eliminate_data.py +0 -108
- relationalai/semantics/lqp/rewrite/extract_common.py +0 -340
- relationalai/semantics/lqp/rewrite/extract_keys.py +0 -577
- relationalai/semantics/lqp/rewrite/flatten_script.py +0 -301
- relationalai/semantics/lqp/rewrite/function_annotations.py +0 -114
- relationalai/semantics/lqp/rewrite/functional_dependencies.py +0 -348
- relationalai/semantics/lqp/rewrite/period_math.py +0 -77
- relationalai/semantics/lqp/rewrite/quantify_vars.py +0 -339
- relationalai/semantics/lqp/rewrite/splinter.py +0 -76
- relationalai/semantics/lqp/rewrite/unify_definitions.py +0 -323
- relationalai/semantics/lqp/types.py +0 -101
- relationalai/semantics/lqp/utils.py +0 -170
- relationalai/semantics/lqp/validators.py +0 -70
- relationalai/semantics/metamodel/compiler.py +0 -134
- relationalai/semantics/metamodel/dependency.py +0 -880
- relationalai/semantics/metamodel/executor.py +0 -78
- relationalai/semantics/metamodel/factory.py +0 -287
- relationalai/semantics/metamodel/helpers.py +0 -368
- relationalai/semantics/metamodel/ir.py +0 -924
- relationalai/semantics/metamodel/rewrite/__init__.py +0 -8
- relationalai/semantics/metamodel/rewrite/discharge_constraints.py +0 -39
- relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +0 -220
- relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +0 -78
- relationalai/semantics/metamodel/rewrite/flatten.py +0 -590
- relationalai/semantics/metamodel/rewrite/format_outputs.py +0 -256
- relationalai/semantics/metamodel/rewrite/handle_aggregations_and_ranks.py +0 -237
- relationalai/semantics/metamodel/typer/checker.py +0 -355
- relationalai/semantics/metamodel/typer/typer.py +0 -1396
- relationalai/semantics/metamodel/util.py +0 -506
- relationalai/semantics/metamodel/visitor.py +0 -945
- relationalai/semantics/reasoners/__init__.py +0 -10
- relationalai/semantics/reasoners/graph/README.md +0 -620
- relationalai/semantics/reasoners/graph/__init__.py +0 -37
- relationalai/semantics/reasoners/graph/core.py +0 -9019
- relationalai/semantics/reasoners/graph/design/beyond_demand_transform.md +0 -797
- relationalai/semantics/reasoners/graph/tests/README.md +0 -21
- relationalai/semantics/reasoners/optimization/__init__.py +0 -68
- relationalai/semantics/reasoners/optimization/common.py +0 -88
- relationalai/semantics/reasoners/optimization/solvers_dev.py +0 -568
- relationalai/semantics/reasoners/optimization/solvers_pb.py +0 -1407
- relationalai/semantics/rel/builtins.py +0 -40
- relationalai/semantics/rel/compiler.py +0 -994
- relationalai/semantics/rel/executor.py +0 -363
- relationalai/semantics/rel/rel.py +0 -482
- relationalai/semantics/rel/rel_utils.py +0 -276
- relationalai/semantics/snowflake/__init__.py +0 -3
- relationalai/semantics/sql/compiler.py +0 -2503
- relationalai/semantics/sql/executor/duck_db.py +0 -52
- relationalai/semantics/sql/executor/result_helpers.py +0 -64
- relationalai/semantics/sql/executor/snowflake.py +0 -149
- relationalai/semantics/sql/rewrite/denormalize.py +0 -222
- relationalai/semantics/sql/rewrite/double_negation.py +0 -49
- relationalai/semantics/sql/rewrite/recursive_union.py +0 -127
- relationalai/semantics/sql/rewrite/sort_output_query.py +0 -246
- relationalai/semantics/sql/sql.py +0 -504
- relationalai/semantics/std/pragmas.py +0 -11
- relationalai/semantics/std/std.py +0 -14
- relationalai/semantics/tests/lqp/algorithms.py +0 -345
- relationalai/semantics/tests/test_snapshot_abstract.py +0 -144
- relationalai/semantics/tests/test_snapshot_base.py +0 -9
- relationalai/semantics/tests/utils.py +0 -46
- relationalai/std/__init__.py +0 -70
- relationalai/tools/cli.py +0 -2089
- relationalai/tools/cli_controls.py +0 -1975
- relationalai/tools/cli_helpers.py +0 -802
- relationalai/tools/debugger_client.py +0 -109
- relationalai/tools/debugger_server.py +0 -302
- relationalai/tools/dev.py +0 -685
- relationalai/tools/notes +0 -7
- relationalai/tools/qb_debugger.py +0 -425
- relationalai/tools/txn_progress.py +0 -188
- relationalai/util/clean_up_databases.py +0 -95
- relationalai/util/list_databases.py +0 -9
- relationalai/util/otel_configuration.py +0 -26
- relationalai/util/otel_handler.py +0 -484
- relationalai/util/snowflake_handler.py +0 -88
- relationalai/util/span_format_test.py +0 -43
- relationalai/util/span_tracker.py +0 -207
- relationalai/util/spans_file_handler.py +0 -72
- relationalai/util/tracing_handler.py +0 -34
- relationalai-0.13.5.dist-info/METADATA +0 -74
- relationalai-0.13.5.dist-info/RECORD +0 -473
- relationalai-0.13.5.dist-info/WHEEL +0 -4
- relationalai-0.13.5.dist-info/entry_points.txt +0 -3
- relationalai-0.13.5.dist-info/licenses/LICENSE +0 -202
- relationalai_test_util/__init__.py +0 -4
- relationalai_test_util/fixtures.py +0 -233
- relationalai_test_util/snapshot.py +0 -252
- relationalai_test_util/traceback.py +0 -118
- /relationalai/{analysis → semantics/frontend}/__init__.py +0 -0
- /relationalai/{auth/__init__.py → semantics/metamodel/metamodel_compiler.py} +0 -0
- /relationalai/{early_access → shims}/__init__.py +0 -0
- {relationalai/early_access/dsl/adapters → v0/relationalai/analysis}/__init__.py +0 -0
- {relationalai → v0/relationalai}/analysis/mechanistic.py +0 -0
- {relationalai → v0/relationalai}/analysis/whynot.py +0 -0
- {relationalai/early_access/dsl/adapters/orm → v0/relationalai/auth}/__init__.py +0 -0
- {relationalai → v0/relationalai}/auth/jwt_generator.py +0 -0
- {relationalai → v0/relationalai}/auth/oauth_callback_server.py +0 -0
- {relationalai → v0/relationalai}/auth/token_handler.py +0 -0
- {relationalai → v0/relationalai}/auth/util.py +0 -0
- {relationalai/clients/resources/snowflake → v0/relationalai/clients}/cache_store.py +0 -0
- {relationalai → v0/relationalai}/compiler.py +0 -0
- {relationalai → v0/relationalai}/dependencies.py +0 -0
- {relationalai → v0/relationalai}/docutils.py +0 -0
- {relationalai/early_access/dsl/adapters/owl → v0/relationalai/early_access}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/__init__.py +0 -0
- {relationalai/early_access/dsl/bindings → v0/relationalai/early_access/dsl/adapters}/__init__.py +0 -0
- {relationalai/early_access/dsl/bindings/legacy → v0/relationalai/early_access/dsl/adapters/orm}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/adapters/orm/model.py +0 -0
- {relationalai/early_access/dsl/codegen → v0/relationalai/early_access/dsl/adapters/owl}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/adapters/owl/model.py +0 -0
- {relationalai/early_access/dsl/core/temporal → v0/relationalai/early_access/dsl/bindings}/__init__.py +0 -0
- {relationalai/early_access/dsl/ir → v0/relationalai/early_access/dsl/bindings/legacy}/__init__.py +0 -0
- {relationalai/early_access/dsl/ontologies → v0/relationalai/early_access/dsl/codegen}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/constants.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/constraints/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/constraints/predicate/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/stack.py +0 -0
- {relationalai/early_access/dsl/orm → v0/relationalai/early_access/dsl/core/temporal}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/utils.py +0 -0
- {relationalai/early_access/dsl/orm/measures → v0/relationalai/early_access/dsl/ir}/__init__.py +0 -0
- {relationalai/early_access/dsl/physical_metadata → v0/relationalai/early_access/dsl/ontologies}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/ontologies/raw_source.py +0 -0
- {relationalai/early_access/dsl/serialize → v0/relationalai/early_access/dsl/orm}/__init__.py +0 -0
- {relationalai/early_access/dsl/snow → v0/relationalai/early_access/dsl/orm/measures}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/orm/reasoner_errors.py +0 -0
- {relationalai/loaders → v0/relationalai/early_access/dsl/physical_metadata}/__init__.py +0 -0
- {relationalai/semantics/tests → v0/relationalai/early_access/dsl/serialize}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/serialize/binding_model.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/serialize/model.py +0 -0
- {relationalai/semantics/tests/lqp → v0/relationalai/early_access/dsl/snow}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/tests/__init__.py +0 -0
- {relationalai → v0/relationalai}/environments/ci.py +0 -0
- {relationalai → v0/relationalai}/environments/hex.py +0 -0
- {relationalai → v0/relationalai}/environments/terminal.py +0 -0
- {relationalai → v0/relationalai}/experimental/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/graphs.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/benchmarks/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/path_algorithms/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/filter.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/glushkov.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/transition.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/utilities/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/utilities/utilities.py +0 -0
- {relationalai/tools → v0/relationalai/loaders}/__init__.py +0 -0
- {relationalai → v0/relationalai}/metagen.py +0 -0
- {relationalai → v0/relationalai}/metamodel.py +0 -0
- {relationalai → v0/relationalai}/rel.py +0 -0
- {relationalai → v0/relationalai}/semantics/devtools/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/internal/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/internal/annotations.py +0 -0
- {relationalai → v0/relationalai}/semantics/lqp/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/lqp/pragmas.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/dataflow.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/typer/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/types.py +0 -0
- {relationalai → v0/relationalai}/semantics/reasoners/experimental/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/rel/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/sql/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/sql/executor/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/sql/rewrite/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/tests/logging.py +0 -0
- {relationalai → v0/relationalai}/std/aggregates.py +0 -0
- {relationalai → v0/relationalai}/std/dates.py +0 -0
- {relationalai → v0/relationalai}/std/graphs.py +0 -0
- {relationalai → v0/relationalai}/std/inspect.py +0 -0
- {relationalai → v0/relationalai}/std/math.py +0 -0
- {relationalai → v0/relationalai}/std/re.py +0 -0
- {relationalai → v0/relationalai}/std/strings.py +0 -0
- {relationalai → v0/relationalai}/tools/cleanup_snapshots.py +0 -0
- {relationalai → v0/relationalai}/tools/constants.py +0 -0
- {relationalai → v0/relationalai}/tools/query_utils.py +0 -0
- {relationalai → v0/relationalai}/tools/snapshot_viewer.py +0 -0
- {relationalai → v0/relationalai}/util/__init__.py +0 -0
- {relationalai → v0/relationalai}/util/constants.py +0 -0
- {relationalai → v0/relationalai}/util/graph.py +0 -0
- {relationalai → v0/relationalai}/util/timeout.py +0 -0
v0/relationalai/dsl.py
ADDED
|
@@ -0,0 +1,1749 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import base64
|
|
3
|
+
from enum import Enum
|
|
4
|
+
import inspect
|
|
5
|
+
from itertools import zip_longest
|
|
6
|
+
import re
|
|
7
|
+
import struct
|
|
8
|
+
import threading
|
|
9
|
+
import typing
|
|
10
|
+
from typing import Any, Dict, List, Optional, Set, Tuple, Union, get_type_hints
|
|
11
|
+
from v0.relationalai.clients.util import IdentityParser, ParseError
|
|
12
|
+
from typing_extensions import TypeGuard
|
|
13
|
+
import numbers
|
|
14
|
+
import os
|
|
15
|
+
import datetime
|
|
16
|
+
import hashlib
|
|
17
|
+
import traceback
|
|
18
|
+
import rich
|
|
19
|
+
import json
|
|
20
|
+
import sys
|
|
21
|
+
|
|
22
|
+
from pandas import DataFrame
|
|
23
|
+
|
|
24
|
+
from v0.relationalai.environments import runtime_env, SnowbookEnvironment
|
|
25
|
+
from v0.relationalai.tools.constants import QUERY_ATTRIBUTES_HEADER
|
|
26
|
+
|
|
27
|
+
from .clients.client import Client
|
|
28
|
+
|
|
29
|
+
from .metamodel import Behavior, Builtins, ActionType, Var, Task, Action, Builder, Type as mType, Property as mProperty
|
|
30
|
+
from . import debugging, errors
|
|
31
|
+
from .errors import FilterAsValue, Errors, InvalidPropertySetException, MultipleIdentities, NonCallablePropertyException, OutOfContextException, RAIException, ReservedPropertyException, VariableOutOfContextException, handle_missing_integration
|
|
32
|
+
|
|
33
|
+
#--------------------------------------------------
|
|
34
|
+
# Constants
|
|
35
|
+
#--------------------------------------------------
|
|
36
|
+
|
|
37
|
+
RESERVED_PROPS = ["add", "set", "persist", "unpersist"]
|
|
38
|
+
MAX_QUERY_ATTRIBUTE_LENGTH = 255
|
|
39
|
+
|
|
40
|
+
Value = Union[
|
|
41
|
+
"Expression",
|
|
42
|
+
"ContextSelect", # because of union/match
|
|
43
|
+
int,
|
|
44
|
+
float,
|
|
45
|
+
str,
|
|
46
|
+
bool,
|
|
47
|
+
datetime.datetime,
|
|
48
|
+
datetime.date,
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
#--------------------------------------------------
|
|
52
|
+
# Helpers
|
|
53
|
+
#--------------------------------------------------
|
|
54
|
+
|
|
55
|
+
# @FIXME: This should only return a Var or None but that's gonna take some doing.
|
|
56
|
+
def to_var(x:Any) -> Any:
|
|
57
|
+
if isinstance(x, Var):
|
|
58
|
+
return x
|
|
59
|
+
if getattr(x, "_to_var", None):
|
|
60
|
+
return to_var(x._to_var())
|
|
61
|
+
if isinstance(x, ContextSelect):
|
|
62
|
+
return x._vars[0]
|
|
63
|
+
if isinstance(x, mProperty):
|
|
64
|
+
return Var(value=x)
|
|
65
|
+
if isinstance(x, mType):
|
|
66
|
+
return Var(value=x)
|
|
67
|
+
if isinstance(x, Producer):
|
|
68
|
+
x._use_var()
|
|
69
|
+
return x._var
|
|
70
|
+
if isinstance(x, list) or isinstance(x, tuple):
|
|
71
|
+
return Var(Builtins.Any, value=[v for i in x if (v := to_var(i))])
|
|
72
|
+
if isinstance(x, str):
|
|
73
|
+
return Var(Builtins.String, None, x)
|
|
74
|
+
if isinstance(x, numbers.Number):
|
|
75
|
+
return Var(Builtins.Number, None, x)
|
|
76
|
+
if isinstance(x, datetime.datetime) or isinstance(x, datetime.date):
|
|
77
|
+
return Var(value=x)
|
|
78
|
+
raise Exception(f"Unknown type: {type(x)}\n{x}")
|
|
79
|
+
|
|
80
|
+
build = Builder(to_var)
|
|
81
|
+
|
|
82
|
+
def to_list(x:Any):
|
|
83
|
+
if isinstance(x, list):
|
|
84
|
+
return x
|
|
85
|
+
if isinstance(x, tuple):
|
|
86
|
+
return list(x)
|
|
87
|
+
return [x]
|
|
88
|
+
|
|
89
|
+
def is_static(x:Any):
|
|
90
|
+
if isinstance(x, Var):
|
|
91
|
+
return x.value is not None
|
|
92
|
+
if isinstance(x, Type):
|
|
93
|
+
return True
|
|
94
|
+
if isinstance(x, str):
|
|
95
|
+
return True
|
|
96
|
+
if isinstance(x, Producer):
|
|
97
|
+
return is_static(to_var(x))
|
|
98
|
+
if isinstance(x, numbers.Number):
|
|
99
|
+
return True
|
|
100
|
+
if isinstance(x, list):
|
|
101
|
+
return all(is_static(i) for i in x)
|
|
102
|
+
if isinstance(x, tuple):
|
|
103
|
+
return all(is_static(i) for i in x)
|
|
104
|
+
if isinstance(x, dict):
|
|
105
|
+
return all(is_static(i) for i in x.values())
|
|
106
|
+
return False
|
|
107
|
+
|
|
108
|
+
def is_collection(x:Any) -> TypeGuard[Union[List, Tuple, Set]]:
|
|
109
|
+
return isinstance(x, list) or isinstance(x, tuple) or isinstance(x, set)
|
|
110
|
+
|
|
111
|
+
def rel_dict(**kwargs):
|
|
112
|
+
return InlineRelation(get_graph(), [
|
|
113
|
+
(Symbol(k), v) for k, v in kwargs.items()
|
|
114
|
+
])
|
|
115
|
+
|
|
116
|
+
#--------------------------------------------------
|
|
117
|
+
# Base
|
|
118
|
+
#--------------------------------------------------
|
|
119
|
+
|
|
120
|
+
id = 0
|
|
121
|
+
def next_id():
|
|
122
|
+
global id
|
|
123
|
+
id += 1
|
|
124
|
+
return id
|
|
125
|
+
|
|
126
|
+
#--------------------------------------------------
|
|
127
|
+
# Producer
|
|
128
|
+
#--------------------------------------------------
|
|
129
|
+
|
|
130
|
+
attributes_to_skip = {
|
|
131
|
+
"_to_var",
|
|
132
|
+
"__name__",
|
|
133
|
+
"__qualname__",
|
|
134
|
+
"_repr_html_",
|
|
135
|
+
"_supports_binary_op",
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
def is_streamlit_running():
|
|
139
|
+
# First check: Is streamlit imported?
|
|
140
|
+
if 'streamlit' not in sys.modules:
|
|
141
|
+
return False
|
|
142
|
+
|
|
143
|
+
# Second check: Try to access session_state
|
|
144
|
+
try:
|
|
145
|
+
import streamlit as st #type: ignore
|
|
146
|
+
_ = st.session_state
|
|
147
|
+
return True
|
|
148
|
+
except RuntimeError:
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
def is_called_by_streamlit_write():
|
|
152
|
+
if not is_streamlit_running():
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
stack_frames = inspect.stack()
|
|
156
|
+
|
|
157
|
+
for frame in stack_frames[1:]:
|
|
158
|
+
if ("streamlit" in frame.filename and "write" in frame.function):
|
|
159
|
+
return True
|
|
160
|
+
|
|
161
|
+
return False
|
|
162
|
+
|
|
163
|
+
class Producer():
|
|
164
|
+
def __init__(self, graph:'Graph'):
|
|
165
|
+
self._id = next_id()
|
|
166
|
+
self._graph = graph
|
|
167
|
+
self._subs = {}
|
|
168
|
+
self._var = None
|
|
169
|
+
|
|
170
|
+
def __iter__(self):
|
|
171
|
+
if is_called_by_streamlit_write():
|
|
172
|
+
return iter([])
|
|
173
|
+
raise Exception("Can't iterate over a producer")
|
|
174
|
+
|
|
175
|
+
def __repr__(self):
|
|
176
|
+
if isinstance(runtime_env, SnowbookEnvironment):
|
|
177
|
+
# suppress spurious output in Snowflake notebooks
|
|
178
|
+
# for expressions like p.age > 18
|
|
179
|
+
return ""
|
|
180
|
+
else:
|
|
181
|
+
return super().__repr__()
|
|
182
|
+
|
|
183
|
+
def __getattr__(self, name: str) -> Any:
|
|
184
|
+
if is_called_by_streamlit_write():
|
|
185
|
+
return None
|
|
186
|
+
if name in attributes_to_skip:
|
|
187
|
+
return None
|
|
188
|
+
self._subs[name] = self._make_sub(name, self._subs.get(name))
|
|
189
|
+
return self._subs[name]
|
|
190
|
+
|
|
191
|
+
def _make_sub(self, name:str, existing:Optional['Producer']=None) -> Any:
|
|
192
|
+
raise Exception("Implement Producer._make_sub")
|
|
193
|
+
|
|
194
|
+
def _use_var(self):
|
|
195
|
+
pass
|
|
196
|
+
|
|
197
|
+
#--------------------------------------------------
|
|
198
|
+
# Boolean overloads
|
|
199
|
+
#--------------------------------------------------
|
|
200
|
+
|
|
201
|
+
def __bool__(self):
|
|
202
|
+
# This doesn't seem to be safe as Python can call bool on Producers in lots of random cases
|
|
203
|
+
# InvalidBoolWarning(Errors.call_source())
|
|
204
|
+
# class_name = self.__class__.__name__
|
|
205
|
+
# TODO: Refactor this to be Exception instead of warning, so we could directly raise it if we bring back this
|
|
206
|
+
# raise TypeError(f"Can't convert an {class_name} to a boolean.")
|
|
207
|
+
return True
|
|
208
|
+
|
|
209
|
+
#--------------------------------------------------
|
|
210
|
+
# Math overloads
|
|
211
|
+
#--------------------------------------------------
|
|
212
|
+
|
|
213
|
+
def _wrapped_op(self, op, left, right):
|
|
214
|
+
# Check if an active context redefines this binary operator (e.g. for the solvers library).
|
|
215
|
+
for s in self._graph._stack.stack:
|
|
216
|
+
f = getattr(s, "_supports_binary_op", None)
|
|
217
|
+
if f and f(op):
|
|
218
|
+
return s._make_binary_op(op, left, right)
|
|
219
|
+
return Expression(self._graph, op, [left, right])
|
|
220
|
+
|
|
221
|
+
def __add__(self, other):
|
|
222
|
+
return self._wrapped_op(Builtins.plus, self, other)
|
|
223
|
+
def __radd__(self, other):
|
|
224
|
+
return self._wrapped_op(Builtins.plus, other, self)
|
|
225
|
+
|
|
226
|
+
def __mul__(self, other):
|
|
227
|
+
return self._wrapped_op(Builtins.mult, self, other)
|
|
228
|
+
def __rmul__(self, other):
|
|
229
|
+
return self._wrapped_op(Builtins.mult, other, self)
|
|
230
|
+
|
|
231
|
+
def __sub__(self, other):
|
|
232
|
+
return self._wrapped_op(Builtins.minus, self, other)
|
|
233
|
+
def __rsub__(self, other):
|
|
234
|
+
return self._wrapped_op(Builtins.minus, other, self)
|
|
235
|
+
|
|
236
|
+
def __truediv__(self, other):
|
|
237
|
+
return self._wrapped_op(Builtins.div, self, other)
|
|
238
|
+
def __rtruediv__(self, other):
|
|
239
|
+
return self._wrapped_op(Builtins.div, other, self)
|
|
240
|
+
|
|
241
|
+
def __floordiv__(self, other):
|
|
242
|
+
return self._wrapped_op(Builtins.floor_div, self, other)
|
|
243
|
+
def __rfloordiv__(self, other):
|
|
244
|
+
return self._wrapped_op(Builtins.floor_div, other, self)
|
|
245
|
+
|
|
246
|
+
def __pow__(self, other):
|
|
247
|
+
return self._wrapped_op(Builtins.pow, self, other)
|
|
248
|
+
def __rpow__(self, other):
|
|
249
|
+
return self._wrapped_op(Builtins.pow, other, self)
|
|
250
|
+
|
|
251
|
+
def __mod__(self, other):
|
|
252
|
+
return self._wrapped_op(Builtins.mod, self, other)
|
|
253
|
+
def __rmod__(self, other):
|
|
254
|
+
return self._wrapped_op(Builtins.mod, other, self)
|
|
255
|
+
|
|
256
|
+
def __neg__(self):
|
|
257
|
+
return self._wrapped_op(Builtins.mult, self, -1)
|
|
258
|
+
|
|
259
|
+
#--------------------------------------------------
|
|
260
|
+
# Filter overloads
|
|
261
|
+
#--------------------------------------------------
|
|
262
|
+
|
|
263
|
+
def __gt__(self, other):
|
|
264
|
+
return self._wrapped_op(Builtins.gt, self, other)
|
|
265
|
+
def __ge__(self, other):
|
|
266
|
+
return self._wrapped_op(Builtins.gte, self, other)
|
|
267
|
+
def __lt__(self, other):
|
|
268
|
+
return self._wrapped_op(Builtins.lt, self, other)
|
|
269
|
+
def __le__(self, other):
|
|
270
|
+
return self._wrapped_op(Builtins.lte, self, other)
|
|
271
|
+
def __eq__(self, other) -> Any:
|
|
272
|
+
return self._wrapped_op(Builtins.approx_eq, self, other)
|
|
273
|
+
def __ne__(self, other) -> Any:
|
|
274
|
+
return self._wrapped_op(Builtins.neq, self, other)
|
|
275
|
+
|
|
276
|
+
#--------------------------------------------------
|
|
277
|
+
# Context management
|
|
278
|
+
#--------------------------------------------------
|
|
279
|
+
|
|
280
|
+
def __enter__(self):
|
|
281
|
+
self._graph._push(self)
|
|
282
|
+
|
|
283
|
+
def __exit__(self, *args):
|
|
284
|
+
self._graph._pop(self)
|
|
285
|
+
|
|
286
|
+
#--------------------------------------------------
|
|
287
|
+
# Context
|
|
288
|
+
#--------------------------------------------------
|
|
289
|
+
|
|
290
|
+
class TaskExecType(Enum):
|
|
291
|
+
Query = 1
|
|
292
|
+
Rule = 2
|
|
293
|
+
Procedure = 3
|
|
294
|
+
Export = 4
|
|
295
|
+
|
|
296
|
+
class ContextSelect(Producer):
|
|
297
|
+
def __init__(self, context:'Context'):
|
|
298
|
+
super().__init__(context.graph)
|
|
299
|
+
self._context = context
|
|
300
|
+
self._select_len = None
|
|
301
|
+
self._insts = []
|
|
302
|
+
self._vars = []
|
|
303
|
+
self._props = {}
|
|
304
|
+
|
|
305
|
+
def _assign_vars(self):
|
|
306
|
+
task = self._context._task
|
|
307
|
+
if not len(self._vars) and self._select_len:
|
|
308
|
+
self._insts = to_list(Vars(self._select_len))
|
|
309
|
+
self._vars = [to_var(v) for v in self._insts]
|
|
310
|
+
task.properties = [Builtins.Relation.properties[i] for i in range(self._select_len)]
|
|
311
|
+
task.bindings.update({Builtins.Relation.properties[i]: v for i, v in enumerate(self._vars)})
|
|
312
|
+
|
|
313
|
+
def __getattr__(self, name: str) -> Any:
|
|
314
|
+
if name.startswith("_"):
|
|
315
|
+
return None
|
|
316
|
+
if name in self._props:
|
|
317
|
+
return Instance(self._context.graph, ActionType.Get, [], {}, var=to_var(self._props[name]))
|
|
318
|
+
else:
|
|
319
|
+
return getattr(Instance(self._context.graph, ActionType.Get, [], {}, var=to_var(self._vars[0])), name)
|
|
320
|
+
|
|
321
|
+
#--------------------------------------------------
|
|
322
|
+
# Return handling
|
|
323
|
+
#--------------------------------------------------
|
|
324
|
+
|
|
325
|
+
def _do_return(self, args, distinct=False):
|
|
326
|
+
graph = self._context.graph
|
|
327
|
+
task = self._context._task
|
|
328
|
+
if task.behavior == Behavior.Query \
|
|
329
|
+
and self._context._exec_type in [TaskExecType.Query, TaskExecType.Procedure]:
|
|
330
|
+
if isinstance(args[0], tuple):
|
|
331
|
+
args = args[0]
|
|
332
|
+
export = self._context._format == "snowpark"
|
|
333
|
+
graph._action(build.return_(list(args), export=export, distinct=distinct))
|
|
334
|
+
else:
|
|
335
|
+
#TODO: good error message depending on the type of task we're dealing with
|
|
336
|
+
raise Exception("Can't select in a non-query")
|
|
337
|
+
return self._context
|
|
338
|
+
|
|
339
|
+
def __call__(self, *args: Any) -> Any:
|
|
340
|
+
if self._context._done:
|
|
341
|
+
raise errors.SelectOutOfContext()
|
|
342
|
+
return self._do_return(args)
|
|
343
|
+
|
|
344
|
+
def distinct(self, *args:Any) -> Any:
|
|
345
|
+
if self._context._done:
|
|
346
|
+
raise errors.SelectOutOfContext()
|
|
347
|
+
return self._do_return(args, distinct=True)
|
|
348
|
+
|
|
349
|
+
#--------------------------------------------------
|
|
350
|
+
# Add for `model.match() as m`
|
|
351
|
+
#--------------------------------------------------
|
|
352
|
+
|
|
353
|
+
def add(self, item, **kwargs):
|
|
354
|
+
arg_len = len(kwargs) + 1
|
|
355
|
+
if self._select_len is not None and arg_len != self._select_len:
|
|
356
|
+
raise Exception("Add must be provided the same arguments in each branch")
|
|
357
|
+
self._select_len = arg_len
|
|
358
|
+
self._assign_vars()
|
|
359
|
+
if len(self._props) and set(self._props.keys()) != set(kwargs.keys()):
|
|
360
|
+
raise Exception("Add must be provided the same properties in each branch")
|
|
361
|
+
elif len(self._props) == 0:
|
|
362
|
+
for k, v in zip(kwargs.keys(), self._vars[1:]):
|
|
363
|
+
v.name = k
|
|
364
|
+
self._props[k] = v
|
|
365
|
+
|
|
366
|
+
graph = self._context.graph
|
|
367
|
+
graph._action(build.relation_action(ActionType.Bind, self._context._task, [item, *[kwargs[k] for k in self._props.keys()]]))
|
|
368
|
+
|
|
369
|
+
class Context():
|
|
370
|
+
def __init__(self, graph:'Graph', *args, behavior=Behavior.Query, op=None,
|
|
371
|
+
exec_type=TaskExecType.Rule, dynamic=False, format="default",
|
|
372
|
+
props=None, engine=None, tag=None, globalize=False, source=None,
|
|
373
|
+
attributes=None, read_only=False, skip_invalid_data=False):
|
|
374
|
+
self._id = next_id()
|
|
375
|
+
self.results = DataFrame()
|
|
376
|
+
self.graph = graph
|
|
377
|
+
self._task = Task(behavior=behavior)
|
|
378
|
+
self._globalize = globalize
|
|
379
|
+
self._op = op
|
|
380
|
+
self._args = list(args)
|
|
381
|
+
self._exec_type = exec_type
|
|
382
|
+
self._select_len = None
|
|
383
|
+
self._dynamic = dynamic or any([item._dynamic for item in self.graph._stack.stack if isinstance(item, Context)])
|
|
384
|
+
self._props = props or {}
|
|
385
|
+
self._engine= engine
|
|
386
|
+
self._tag = tag # for benchmark reporting
|
|
387
|
+
self._format = self._resolve_format(format)
|
|
388
|
+
self._done = False
|
|
389
|
+
self._source = source
|
|
390
|
+
self._read_only:bool = read_only
|
|
391
|
+
self._skip_invalid_data:bool = skip_invalid_data
|
|
392
|
+
|
|
393
|
+
self._validate_attributes(attributes)
|
|
394
|
+
self._attributes = attributes
|
|
395
|
+
|
|
396
|
+
def _validate_attributes(self, attributes):
|
|
397
|
+
if attributes is None:
|
|
398
|
+
return True
|
|
399
|
+
|
|
400
|
+
for key, value in attributes.items():
|
|
401
|
+
self._validate_attribute_item(key)
|
|
402
|
+
self._validate_attribute_item(value)
|
|
403
|
+
|
|
404
|
+
def _validate_attribute_item(self, item):
|
|
405
|
+
assert isinstance(item, str), f"'{item}' must be a string"
|
|
406
|
+
assert len(item) <= MAX_QUERY_ATTRIBUTE_LENGTH, f"'{item}' exceeds the maximum length of {MAX_QUERY_ATTRIBUTE_LENGTH} characters."
|
|
407
|
+
assert re.match(r'^[a-zA-Z0-9_-]+$', item), f"'{item}' must contain only alphanumeric characters, underscores, or hyphens."
|
|
408
|
+
|
|
409
|
+
def _resolve_format(self, format):
|
|
410
|
+
if format == "default":
|
|
411
|
+
if self.graph._format != "default":
|
|
412
|
+
return self.graph._format
|
|
413
|
+
if self.graph._config.get("platform") == "snowflake":
|
|
414
|
+
# In the future we may want to default to snowpark
|
|
415
|
+
return "pandas"
|
|
416
|
+
return "pandas"
|
|
417
|
+
return format
|
|
418
|
+
|
|
419
|
+
def __enter__(self):
|
|
420
|
+
debugging.set_source(self._task, self._source)
|
|
421
|
+
self.graph._push(self)
|
|
422
|
+
return ContextSelect(self)
|
|
423
|
+
|
|
424
|
+
def __exit__(self, *args):
|
|
425
|
+
self._done = True
|
|
426
|
+
# If no exception info has been passed to args,
|
|
427
|
+
# then proceed with the normal exit process.
|
|
428
|
+
# Otherwise, return False to propagate the exception.
|
|
429
|
+
if args[0] is None:
|
|
430
|
+
if not self._dynamic:
|
|
431
|
+
debugging.check_errors(self._task)
|
|
432
|
+
try:
|
|
433
|
+
self.graph._pop(self, globalize=self._globalize)
|
|
434
|
+
except KeyboardInterrupt as e:
|
|
435
|
+
print("Canceling transactions...")
|
|
436
|
+
self.graph.resources.cancel_pending_transactions()
|
|
437
|
+
raise e
|
|
438
|
+
except RAIException as e:
|
|
439
|
+
handle_missing_integration(e)
|
|
440
|
+
raise e.clone(self.graph._config) from None
|
|
441
|
+
else:
|
|
442
|
+
self.graph._pop(self, exec=False)
|
|
443
|
+
if isinstance(args[1], RAIException):
|
|
444
|
+
raise args[1].clone(self.graph._config) from None
|
|
445
|
+
return False
|
|
446
|
+
|
|
447
|
+
def __iter__(self):
|
|
448
|
+
if self._exec_type != TaskExecType.Query:
|
|
449
|
+
raise Exception("Can't iterate over a non-query task")
|
|
450
|
+
else:
|
|
451
|
+
return self.results.itertuples(index=False)
|
|
452
|
+
|
|
453
|
+
def _repr_html_(self):
|
|
454
|
+
if self._exec_type == TaskExecType.Query:
|
|
455
|
+
if isinstance(self.results, DataFrame):
|
|
456
|
+
return self.results.to_html(index=False)
|
|
457
|
+
elif getattr(self.results, "_repr_html_", None):
|
|
458
|
+
return self.results._repr_html_()
|
|
459
|
+
elif getattr(self.results, "show"):
|
|
460
|
+
self.results.show()
|
|
461
|
+
return ""
|
|
462
|
+
else:
|
|
463
|
+
return str(self.results)
|
|
464
|
+
|
|
465
|
+
def __str__(self):
|
|
466
|
+
if self._exec_type == TaskExecType.Query:
|
|
467
|
+
if isinstance(self.results, DataFrame):
|
|
468
|
+
return self.results.to_string(index=False)
|
|
469
|
+
else:
|
|
470
|
+
return str(self.results)
|
|
471
|
+
return super().__str__()
|
|
472
|
+
|
|
473
|
+
#--------------------------------------------------
|
|
474
|
+
# Type
|
|
475
|
+
#--------------------------------------------------
|
|
476
|
+
|
|
477
|
+
def hash_values_sha256_truncated(args):
|
|
478
|
+
combined = ''.join(map(str, args))
|
|
479
|
+
combined_bytes = combined.encode('utf-8')
|
|
480
|
+
hasher = hashlib.sha256()
|
|
481
|
+
hasher.update(combined_bytes)
|
|
482
|
+
hash_128_bit = hasher.digest()[:16]
|
|
483
|
+
return hash_128_bit
|
|
484
|
+
|
|
485
|
+
# @NOTE: `omit_intrinsic_type_in_hash` exists to keep node hashes (which are namespaced by their graph) stable
|
|
486
|
+
# when new nodes are directly created via `Node.add(x = ..)` instead of marking existing entities as
|
|
487
|
+
# nodes. Possible hash collisions between types happen to be okay in this case because of the access
|
|
488
|
+
# paths, but it's _not_ generally safe to use it otherwise.
|
|
489
|
+
class Type(Producer):
|
|
490
|
+
def __init__(self, graph:'Graph', name:str, builtins:List[str] = [], scope:str="", omit_intrinsic_type_in_hash = False):
|
|
491
|
+
super().__init__(graph)
|
|
492
|
+
self._type = mType(scope+name)
|
|
493
|
+
self._scope = scope
|
|
494
|
+
self._omit_intrinsic_type_in_hash = omit_intrinsic_type_in_hash
|
|
495
|
+
if graph._config.get("compiler.use_value_types", False):
|
|
496
|
+
self._type.parents.append(Builtins.ValueType)
|
|
497
|
+
install = build.install(self._type)
|
|
498
|
+
self._graph._action(install)
|
|
499
|
+
debugging.set_source(install)
|
|
500
|
+
|
|
501
|
+
def __call__(self, *args, **kwargs):
|
|
502
|
+
return Instance(self._graph, ActionType.Get, [self, *args], kwargs, name=self._type.name.lower(), scope=self._scope)
|
|
503
|
+
|
|
504
|
+
def add(self, *args, **kwargs):
|
|
505
|
+
inst = Instance(self._graph, ActionType.Bind, [self, *args], kwargs, name=self._type.name.lower(), is_add=True, scope=self._scope)
|
|
506
|
+
if inst._action.entity.value is not None:
|
|
507
|
+
pass
|
|
508
|
+
elif is_static(args) and is_static(kwargs):
|
|
509
|
+
params = [Var(value=t.name) for t in inst._action.types]
|
|
510
|
+
if self._omit_intrinsic_type_in_hash:
|
|
511
|
+
params.pop(0)
|
|
512
|
+
params.extend(inst._action.bindings.values())
|
|
513
|
+
inst._action.entity.value = hash_values_sha256_truncated(params)
|
|
514
|
+
elif all([isinstance(a, Type) for a in args]):
|
|
515
|
+
self._graph._action(build.ident(inst._action, self._omit_intrinsic_type_in_hash))
|
|
516
|
+
inst._add_to_graph()
|
|
517
|
+
return inst
|
|
518
|
+
|
|
519
|
+
def persist(self, *args, **kwargs):
|
|
520
|
+
inst = Instance(self._graph, ActionType.Persist, [self, *args], kwargs, name=self._type.name.lower(), is_add=True, scope=self._scope)
|
|
521
|
+
if inst._action.entity.value is not None:
|
|
522
|
+
pass
|
|
523
|
+
elif is_static(args) and is_static(kwargs):
|
|
524
|
+
params = [Var(value=t.name) for t in inst._action.types]
|
|
525
|
+
params.extend(inst._action.bindings.values())
|
|
526
|
+
inst._action.entity.value = hash_values_sha256_truncated(params)
|
|
527
|
+
elif all([isinstance(a, Type) for a in args]):
|
|
528
|
+
self._graph._action(build.ident(inst._action, self._omit_intrinsic_type_in_hash))
|
|
529
|
+
inst._add_to_graph()
|
|
530
|
+
return inst
|
|
531
|
+
|
|
532
|
+
def extend(self, *args, **kwargs):
|
|
533
|
+
for arg in args:
|
|
534
|
+
if not isinstance(arg, Type):
|
|
535
|
+
raise Exception("Can only extend a type with another type")
|
|
536
|
+
with self._graph.rule(dynamic=True):
|
|
537
|
+
a = arg()
|
|
538
|
+
a.set(self)
|
|
539
|
+
with self._graph.rule(dynamic=True):
|
|
540
|
+
a = arg()
|
|
541
|
+
neue = self(a)
|
|
542
|
+
for k, v in kwargs.items():
|
|
543
|
+
if isinstance(v, Property):
|
|
544
|
+
v = getattr(a, v._prop.name)
|
|
545
|
+
neue.set(**{k:v})
|
|
546
|
+
|
|
547
|
+
def define(self, **kwargs):
|
|
548
|
+
for k, v in kwargs.items():
|
|
549
|
+
if isinstance(v, tuple):
|
|
550
|
+
(other_type, left, right) = v
|
|
551
|
+
with self._graph.rule():
|
|
552
|
+
inst = other_type()
|
|
553
|
+
me = self()
|
|
554
|
+
getattr(inst, right) == getattr(me, left) # type: ignore
|
|
555
|
+
if getattr(self, k).is_multi_valued:
|
|
556
|
+
getattr(me, k).add(inst)
|
|
557
|
+
else:
|
|
558
|
+
me.set(**{k: inst})
|
|
559
|
+
else:
|
|
560
|
+
raise Exception("Define requires a tuple of (Type, left, right)")
|
|
561
|
+
return self
|
|
562
|
+
|
|
563
|
+
def keyed(self, **kwargs):
|
|
564
|
+
return KeyedType(self, kwargs)
|
|
565
|
+
|
|
566
|
+
def __or__(self, __value: Any) -> TypeUnion:
|
|
567
|
+
if isinstance(__value, Type) or isinstance(__value, TypeIntersection):
|
|
568
|
+
return TypeUnion(self._graph, [self, __value])
|
|
569
|
+
if isinstance(__value, TypeUnion):
|
|
570
|
+
return TypeUnion(self._graph, [self, *__value._types])
|
|
571
|
+
raise Exception("Can't or a type with a non-type")
|
|
572
|
+
|
|
573
|
+
def __and__(self, __value: Any) -> TypeIntersection:
|
|
574
|
+
if isinstance(__value, Type) or isinstance(__value, TypeUnion):
|
|
575
|
+
return TypeIntersection(self._graph, [self, __value])
|
|
576
|
+
if isinstance(__value, TypeIntersection):
|
|
577
|
+
return TypeIntersection(self._graph, [self, *__value._types])
|
|
578
|
+
raise Exception("Can't & a type with a non-type")
|
|
579
|
+
|
|
580
|
+
def _make_sub(self, name: str, existing=None):
|
|
581
|
+
if existing is not None:
|
|
582
|
+
return existing
|
|
583
|
+
return Property(self._graph, name, [self._type], self, scope=self._scope)
|
|
584
|
+
|
|
585
|
+
def known_properties(self):
|
|
586
|
+
return [p.name.removeprefix(self._scope) for p in self._type.properties]
|
|
587
|
+
|
|
588
|
+
#--------------------------------------------------
|
|
589
|
+
# KeyedType
|
|
590
|
+
#--------------------------------------------------
|
|
591
|
+
|
|
592
|
+
class KeyedType(Producer):
|
|
593
|
+
def __init__(self, type:Type, keys:Dict[str,Type]):
|
|
594
|
+
super().__init__(type._graph)
|
|
595
|
+
self._type = type
|
|
596
|
+
self._relation = RawRelation(self._graph, type._type.name, len(keys))
|
|
597
|
+
self._key_info = keys
|
|
598
|
+
self._key_order = list(keys.keys())
|
|
599
|
+
self._props = {}
|
|
600
|
+
|
|
601
|
+
# declare the relation
|
|
602
|
+
install = build.install(self._relation._type)
|
|
603
|
+
self._graph._action(install)
|
|
604
|
+
debugging.set_source(install)
|
|
605
|
+
|
|
606
|
+
def _prop(self, name:str):
|
|
607
|
+
if name not in self._props:
|
|
608
|
+
self._props[name] = RawRelation(self._graph, f"{self._relation._name}_{name}", len(self._key_info)+1)
|
|
609
|
+
return self._props[name]
|
|
610
|
+
|
|
611
|
+
def extend(self, *args, **kwargs):
|
|
612
|
+
raise errors.KeyedCantBeExtended()
|
|
613
|
+
|
|
614
|
+
def _collect_keys(self, args:List[Any], kwargs:Dict[str,Any]):
|
|
615
|
+
ks = self._key_info.keys()
|
|
616
|
+
all_args = dict(zip(ks, args))
|
|
617
|
+
all_args.update(kwargs)
|
|
618
|
+
props = set(all_args.keys()) - set(ks)
|
|
619
|
+
return all_args, {k: all_args.get(k) for k in ks if k in all_args}, {k: all_args[k] for k in props}
|
|
620
|
+
|
|
621
|
+
def add(self, *args:Any, **kwargs):
|
|
622
|
+
all_args, keys, props = self._collect_keys(list(args), kwargs)
|
|
623
|
+
if len(keys) != len(self._key_info):
|
|
624
|
+
raise errors.KeyedWrongArity(self._type._type.name, list(self._key_info.keys()), len(keys))
|
|
625
|
+
self._relation.add(*keys.values())
|
|
626
|
+
for k, v in props.items():
|
|
627
|
+
self._prop(k).add(*keys, v)
|
|
628
|
+
return KeyedInstance(self, list(keys), {})
|
|
629
|
+
|
|
630
|
+
def __call__(self, *args, **kwargs):
|
|
631
|
+
all_args, keys, props = self._collect_keys(list(args), kwargs)
|
|
632
|
+
ks = self._key_info.keys()
|
|
633
|
+
keys = [all_args.get(k, Vars(1)) for k in ks]
|
|
634
|
+
self._relation(*keys)
|
|
635
|
+
return KeyedInstance(self, keys, props)
|
|
636
|
+
|
|
637
|
+
def __getattr__(self, name: str) -> Any:
|
|
638
|
+
return self._props[name]
|
|
639
|
+
|
|
640
|
+
class KeyedInstance(Producer):
|
|
641
|
+
def __init__(self, keyed_type:KeyedType, keys:List[Any], kwargs:dict={}):
|
|
642
|
+
self._keys = keys
|
|
643
|
+
self._type = keyed_type
|
|
644
|
+
for k, v in kwargs.items():
|
|
645
|
+
self._type._prop(k)(*keys, v)
|
|
646
|
+
|
|
647
|
+
def __getattr__(self, name:str):
|
|
648
|
+
if name in self._type._key_order:
|
|
649
|
+
return self._keys[self._type._key_order.index(name)]
|
|
650
|
+
v = Vars(1)
|
|
651
|
+
self._type._prop(name)(*self._keys, v)
|
|
652
|
+
return v
|
|
653
|
+
|
|
654
|
+
def set(self, **kwargs):
|
|
655
|
+
for k, v in kwargs.items():
|
|
656
|
+
self._type._prop(k).add(*self._keys, v)
|
|
657
|
+
return self
|
|
658
|
+
|
|
659
|
+
def __iter__(self):
|
|
660
|
+
return iter(self._keys)
|
|
661
|
+
|
|
662
|
+
def _to_var(self):
|
|
663
|
+
raise Exception("KeyedTypes can't be returned directly, you can only reference properties")
|
|
664
|
+
|
|
665
|
+
#--------------------------------------------------
|
|
666
|
+
# TypeUnion
|
|
667
|
+
#--------------------------------------------------
|
|
668
|
+
|
|
669
|
+
class TypeUnion(Producer):
|
|
670
|
+
def __init__(self, graph:'Graph', types:List[Type|TypeIntersection]):
|
|
671
|
+
super().__init__(graph)
|
|
672
|
+
self._types = types
|
|
673
|
+
|
|
674
|
+
def __call__(self, *args, **kwargs) -> 'ContextSelect':
|
|
675
|
+
if not len(self._graph._stack.stack):
|
|
676
|
+
raise Exception("Can't create an instance outside of a context")
|
|
677
|
+
graph = self._graph
|
|
678
|
+
with graph.union(dynamic=True) as union:
|
|
679
|
+
for t in self._types:
|
|
680
|
+
with graph.scope():
|
|
681
|
+
union.add(t(*args, **kwargs))
|
|
682
|
+
return union
|
|
683
|
+
|
|
684
|
+
def known_properties(self):
|
|
685
|
+
props = []
|
|
686
|
+
for t in self._types:
|
|
687
|
+
for prop in t.known_properties():
|
|
688
|
+
if prop not in props:
|
|
689
|
+
props.append(prop)
|
|
690
|
+
return props
|
|
691
|
+
|
|
692
|
+
def __or__(self, __value: Any) -> 'TypeUnion':
|
|
693
|
+
if isinstance(__value, Type):
|
|
694
|
+
return TypeUnion(self._graph, [*self._types, __value])
|
|
695
|
+
if isinstance(__value, TypeUnion):
|
|
696
|
+
return TypeUnion(self._graph, [*self._types, *__value._types])
|
|
697
|
+
raise Exception("Can't or a type with a non-type")
|
|
698
|
+
|
|
699
|
+
def _make_sub(self, name: str, existing=None):
|
|
700
|
+
if existing is not None:
|
|
701
|
+
return existing
|
|
702
|
+
return Property(self._graph, name, [t._type for t in self._types], self)
|
|
703
|
+
|
|
704
|
+
#--------------------------------------------------
|
|
705
|
+
# TypeIntersection
|
|
706
|
+
#--------------------------------------------------
|
|
707
|
+
|
|
708
|
+
class TypeIntersection(Producer):
|
|
709
|
+
def __init__(self, graph:'Graph', types:List[Type|TypeUnion]):
|
|
710
|
+
super().__init__(graph)
|
|
711
|
+
self._types = types
|
|
712
|
+
|
|
713
|
+
def __call__(self, *args, **kwargs) -> Producer:
|
|
714
|
+
if not len(self._graph._stack.stack):
|
|
715
|
+
raise Exception("Can't create an instance outside of a context")
|
|
716
|
+
return self._types[0](*self._types[1:], *args, **kwargs)
|
|
717
|
+
|
|
718
|
+
def known_properties(self):
|
|
719
|
+
props = []
|
|
720
|
+
for t in self._types:
|
|
721
|
+
for prop in t.known_properties():
|
|
722
|
+
if prop not in props:
|
|
723
|
+
props.append(prop)
|
|
724
|
+
return props
|
|
725
|
+
|
|
726
|
+
def __and__(self, __value: Any) -> TypeIntersection:
|
|
727
|
+
if isinstance(__value, Type):
|
|
728
|
+
return TypeIntersection(self._graph, [*self._types, __value])
|
|
729
|
+
if isinstance(__value, TypeIntersection):
|
|
730
|
+
return TypeIntersection(self._graph, [*self._types, *__value._types])
|
|
731
|
+
raise Exception("Can't & a type with a non-type")
|
|
732
|
+
|
|
733
|
+
def _make_sub(self, name: str, existing=None):
|
|
734
|
+
if existing is not None:
|
|
735
|
+
return existing
|
|
736
|
+
return Property(self._graph, name, [t._type for t in self._types], self)
|
|
737
|
+
|
|
738
|
+
#--------------------------------------------------
|
|
739
|
+
# Property
|
|
740
|
+
#--------------------------------------------------
|
|
741
|
+
|
|
742
|
+
class Property(Producer):
|
|
743
|
+
def __init__(self, graph:'Graph', name:str, types:List[mType], provider:Type|TypeUnion|TypeIntersection, scope:str=""):
|
|
744
|
+
super().__init__(graph)
|
|
745
|
+
self._name = name
|
|
746
|
+
self._type = types[0]
|
|
747
|
+
self._scope = scope
|
|
748
|
+
self._provider = provider
|
|
749
|
+
self._prop = build.property_named(scope+name, types)
|
|
750
|
+
|
|
751
|
+
def __call__(self, key:Any, value:Any):
|
|
752
|
+
action = build.relation_action(ActionType.Get, self._prop, [key, value])
|
|
753
|
+
self._graph._action(action)
|
|
754
|
+
|
|
755
|
+
def _use_var(self):
|
|
756
|
+
raise Exception("Support properties being used as vars")
|
|
757
|
+
|
|
758
|
+
def _make_sub(self, name: str, existing=None):
|
|
759
|
+
raise Exception("Support properties on properties?")
|
|
760
|
+
|
|
761
|
+
def to_property(self):
|
|
762
|
+
return self._prop
|
|
763
|
+
|
|
764
|
+
def declare(self):
|
|
765
|
+
self._graph._action(build.install(self._prop))
|
|
766
|
+
|
|
767
|
+
def has_many(self):
|
|
768
|
+
self.declare()
|
|
769
|
+
self._graph._check_property(self._prop, multi_valued=True)
|
|
770
|
+
|
|
771
|
+
@property
|
|
772
|
+
def is_multi_valued(self):
|
|
773
|
+
return self._graph._prop_is_multi.get(self._name)
|
|
774
|
+
|
|
775
|
+
#--------------------------------------------------
|
|
776
|
+
# Instance
|
|
777
|
+
#--------------------------------------------------
|
|
778
|
+
|
|
779
|
+
class Instance(Producer):
|
|
780
|
+
def __init__(self, graph:'Graph', action_type:ActionType, positionals:List[Any], named:Dict[str,Any], var:Var|None=None, name=None, is_add=False, scope:str=""):
|
|
781
|
+
super().__init__(graph)
|
|
782
|
+
self._action = Action(action_type, to_var(var) if var else Var(name=name))
|
|
783
|
+
self._actions = [self._action]
|
|
784
|
+
self._sets = {}
|
|
785
|
+
self._context = graph._stack.active()
|
|
786
|
+
self._scope = scope
|
|
787
|
+
available_types = []
|
|
788
|
+
last_pos_var = None
|
|
789
|
+
|
|
790
|
+
#--------------------------------------------------
|
|
791
|
+
# Positionals
|
|
792
|
+
#--------------------------------------------------
|
|
793
|
+
has_ident = False
|
|
794
|
+
for pos in positionals:
|
|
795
|
+
if isinstance(pos, Type):
|
|
796
|
+
self._action.append(pos._type)
|
|
797
|
+
elif isinstance(pos, Instance):
|
|
798
|
+
if has_ident:
|
|
799
|
+
raise MultipleIdentities()
|
|
800
|
+
has_ident = True
|
|
801
|
+
self._action.append(to_var(pos))
|
|
802
|
+
available_types.extend(pos._action.types)
|
|
803
|
+
if last_pos_var:
|
|
804
|
+
self._graph._action(build.eq(last_pos_var, self._action.entity))
|
|
805
|
+
last_pos_var = self._action.entity
|
|
806
|
+
elif isinstance(pos, TypeUnion) or isinstance(pos, TypeIntersection):
|
|
807
|
+
self._action.append(to_var(pos()))
|
|
808
|
+
available_types.extend([t._type for t in pos._types])
|
|
809
|
+
if last_pos_var:
|
|
810
|
+
self._graph._action(build.eq(last_pos_var, self._action.entity))
|
|
811
|
+
last_pos_var = self._action.entity
|
|
812
|
+
elif isinstance(pos, Producer):
|
|
813
|
+
if has_ident:
|
|
814
|
+
raise MultipleIdentities()
|
|
815
|
+
has_ident = True
|
|
816
|
+
self._action.append(to_var(pos))
|
|
817
|
+
if last_pos_var:
|
|
818
|
+
self._graph._action(build.eq(last_pos_var, self._action.entity))
|
|
819
|
+
last_pos_var = self._action.entity
|
|
820
|
+
elif isinstance(pos, (str, int)):
|
|
821
|
+
if has_ident:
|
|
822
|
+
raise MultipleIdentities()
|
|
823
|
+
has_ident = True
|
|
824
|
+
if isinstance(pos, str):
|
|
825
|
+
try:
|
|
826
|
+
decoded = base64.b64decode(pos + "==")
|
|
827
|
+
if len(decoded) == 16:
|
|
828
|
+
first_int = decoded[:8]
|
|
829
|
+
second_int = decoded[8:]
|
|
830
|
+
pos = struct.pack('<Q', struct.unpack('>Q', second_int)[0]) + \
|
|
831
|
+
struct.pack('<Q', struct.unpack('>Q', first_int)[0])
|
|
832
|
+
except Exception:
|
|
833
|
+
pass
|
|
834
|
+
self._action.append(Var(value=pos))
|
|
835
|
+
last_pos_var = self._action.entity
|
|
836
|
+
else:
|
|
837
|
+
raise Exception(f"Unknown input type: {pos}")
|
|
838
|
+
available_types.extend(self._action.types)
|
|
839
|
+
if scope:
|
|
840
|
+
available_types = [t for t in available_types if t.name.startswith(scope)]
|
|
841
|
+
|
|
842
|
+
#--------------------------------------------------
|
|
843
|
+
# Handle properties
|
|
844
|
+
#--------------------------------------------------
|
|
845
|
+
for name, val in named.items():
|
|
846
|
+
prop = build.property_named(scope+name, available_types)
|
|
847
|
+
|
|
848
|
+
if val is None:
|
|
849
|
+
raise Exception(f"{prop}'s value is None, please provide a value for the property")
|
|
850
|
+
|
|
851
|
+
if isinstance(val, int) and action_type == ActionType.Get:
|
|
852
|
+
orig = val
|
|
853
|
+
val = Vars(1)
|
|
854
|
+
self._actions.append(build.eq(val, orig, approx=True))
|
|
855
|
+
|
|
856
|
+
prop_var = to_var(val)
|
|
857
|
+
|
|
858
|
+
if prop_var.isa(Builtins.ExternalInput):
|
|
859
|
+
orig = prop_var
|
|
860
|
+
prop_var = to_var(Vars(1))
|
|
861
|
+
self._actions.append(build.eq(prop_var, orig, approx=True))
|
|
862
|
+
|
|
863
|
+
if is_collection(prop_var.value):
|
|
864
|
+
raise Exception("Can't set a property to a collection")
|
|
865
|
+
|
|
866
|
+
if not prop_var.name:
|
|
867
|
+
prop_var.name = prop.name
|
|
868
|
+
if action_type.is_effect():
|
|
869
|
+
self._graph._check_property(prop)
|
|
870
|
+
else:
|
|
871
|
+
self._graph._check_property(prop, unknown_cardinality=True)
|
|
872
|
+
self._action.append(prop, prop_var)
|
|
873
|
+
|
|
874
|
+
#--------------------------------------------------
|
|
875
|
+
# Entities
|
|
876
|
+
#--------------------------------------------------
|
|
877
|
+
self._var = self._action.entity
|
|
878
|
+
if self._var.type == Builtins.Unknown and len(self._action.types):
|
|
879
|
+
self._var.type = self._action.types[0]
|
|
880
|
+
if not is_add and (self._action.types or self._action.bindings):
|
|
881
|
+
self._add_to_graph()
|
|
882
|
+
|
|
883
|
+
def _to_var(self):
|
|
884
|
+
if not self._graph._stack.contains(self._context):
|
|
885
|
+
exception = VariableOutOfContextException(Errors.call_source(), self._var.name)
|
|
886
|
+
raise exception from None
|
|
887
|
+
return self._var
|
|
888
|
+
|
|
889
|
+
def _add_to_graph(self):
|
|
890
|
+
for action in self._actions:
|
|
891
|
+
self._graph._action(action)
|
|
892
|
+
|
|
893
|
+
def __call__(self, *args, **kwargs):
|
|
894
|
+
pass
|
|
895
|
+
|
|
896
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
|
897
|
+
if name.startswith("_"):
|
|
898
|
+
return super().__setattr__(name, value)
|
|
899
|
+
exception = InvalidPropertySetException(Errors.call_source(3))
|
|
900
|
+
raise exception from None
|
|
901
|
+
|
|
902
|
+
def _make_sub(self, name: str, existing=None):
|
|
903
|
+
if self._sets.get(name) is not None:
|
|
904
|
+
return self._sets[name]
|
|
905
|
+
if existing is not None:
|
|
906
|
+
inst = InstanceProperty(self._graph, self, name, var=existing._var, scope=self._scope)
|
|
907
|
+
inst._subs = existing._subs
|
|
908
|
+
return inst
|
|
909
|
+
prop = build.property_named(self._scope+name, self._action.types)
|
|
910
|
+
if self._action.bindings.get(prop):
|
|
911
|
+
return InstanceProperty(self._graph, self, name, var=self._action.bindings[prop], scope=self._scope)
|
|
912
|
+
return InstanceProperty(self._graph, self, name, scope=self._scope)
|
|
913
|
+
|
|
914
|
+
def set(self, *args, **kwargs):
|
|
915
|
+
if self._graph._stack.active() is self._context:
|
|
916
|
+
self._sets.update(kwargs)
|
|
917
|
+
Instance(self._graph, ActionType.Bind, [self, *args], kwargs, var=self._var, scope=self._scope)
|
|
918
|
+
return self
|
|
919
|
+
|
|
920
|
+
def persist(self, *args, **kwargs):
|
|
921
|
+
Instance(self._graph, ActionType.Persist, [self, *args], kwargs, var=self._var, scope=self._scope)
|
|
922
|
+
return self
|
|
923
|
+
|
|
924
|
+
def unpersist(self, *args, **kwargs):
|
|
925
|
+
Instance(self._graph, ActionType.Unpersist, [self, *args], kwargs, var=self._var, scope=self._scope)
|
|
926
|
+
return self
|
|
927
|
+
|
|
928
|
+
def has_value(self):
|
|
929
|
+
return self != rel.Missing # type:ignore
|
|
930
|
+
|
|
931
|
+
#--------------------------------------------------
|
|
932
|
+
# InstanceProperty
|
|
933
|
+
#--------------------------------------------------
|
|
934
|
+
|
|
935
|
+
class InstanceProperty(Producer):
|
|
936
|
+
def __init__(self, graph:'Graph', instance:Instance, name:str, var=None, scope:str=""):
|
|
937
|
+
super().__init__(graph)
|
|
938
|
+
self._instance = instance
|
|
939
|
+
|
|
940
|
+
self._prop = build.property_named(scope+name, instance._action.types)
|
|
941
|
+
self._var = var or Var(self._prop.type, name=name)
|
|
942
|
+
self._check_context()
|
|
943
|
+
self._scope = scope
|
|
944
|
+
new = Instance(self._graph, ActionType.Get, [instance], {name: self._var}, scope=self._scope)
|
|
945
|
+
self._action = new._action
|
|
946
|
+
|
|
947
|
+
def _check_context(self):
|
|
948
|
+
if not self._graph._stack.contains(self._instance._context):
|
|
949
|
+
name = f"{self._instance._var.name}.{self._var.name}"
|
|
950
|
+
exception = VariableOutOfContextException(Errors.call_source(), name, is_property=True)
|
|
951
|
+
raise exception from None
|
|
952
|
+
|
|
953
|
+
def __call__(self, *args, **kwargs):
|
|
954
|
+
name = f"{self._instance._var.name}.{self._var.name}"
|
|
955
|
+
exception = NonCallablePropertyException(Errors.call_source(), name)
|
|
956
|
+
raise exception from None
|
|
957
|
+
|
|
958
|
+
def _make_sub(self, name: str, existing=None):
|
|
959
|
+
if existing is not None and self._graph._stack.is_active(existing._instance._context):
|
|
960
|
+
return existing
|
|
961
|
+
return getattr(Instance(self._graph, ActionType.Get, [self], {}), name)
|
|
962
|
+
|
|
963
|
+
def _to_var(self):
|
|
964
|
+
self._check_context()
|
|
965
|
+
return self._var
|
|
966
|
+
|
|
967
|
+
def or_(self, other):
|
|
968
|
+
self._graph._remove_action(self._action)
|
|
969
|
+
default = build.call(Builtins.Default, [self._prop, other, self._instance, self])
|
|
970
|
+
self._graph._action(default)
|
|
971
|
+
return self
|
|
972
|
+
|
|
973
|
+
def in_(self, others):
|
|
974
|
+
other_rel = InlineRelation(self._graph, [(x,) for x in others])
|
|
975
|
+
return self == other_rel
|
|
976
|
+
|
|
977
|
+
def has_value(self):
|
|
978
|
+
return self != rel.Missing # type:ignore
|
|
979
|
+
|
|
980
|
+
def _remove_if_unused(self):
|
|
981
|
+
# When calling append/extend we aren't necessarily doing a get on the property,
|
|
982
|
+
# but we will already have added one. If we're the only thing using this get,
|
|
983
|
+
# we remove it so that it doesn't unnecessarily constrain the query.
|
|
984
|
+
remove = False
|
|
985
|
+
for item in reversed(self._graph._stack.items):
|
|
986
|
+
if item is self._action:
|
|
987
|
+
remove = True
|
|
988
|
+
break
|
|
989
|
+
elif isinstance(item, Action):
|
|
990
|
+
if self._var in item.vars():
|
|
991
|
+
remove = False
|
|
992
|
+
break
|
|
993
|
+
if remove:
|
|
994
|
+
self._graph._remove_action(self._action)
|
|
995
|
+
|
|
996
|
+
def set(self, *args, **kwargs):
|
|
997
|
+
return Instance(self._graph, ActionType.Get, [self], {}).set(*args, **kwargs)
|
|
998
|
+
|
|
999
|
+
def add(self, other):
|
|
1000
|
+
self._remove_if_unused()
|
|
1001
|
+
self._graph._check_property(self._prop, multi_valued=True)
|
|
1002
|
+
rel = Action(ActionType.Bind, to_var(self._instance), [], {self._prop: to_var(other)})
|
|
1003
|
+
self._graph._action(rel)
|
|
1004
|
+
|
|
1005
|
+
def extend(self, others):
|
|
1006
|
+
self._remove_if_unused()
|
|
1007
|
+
self._graph._check_property(self._prop, True)
|
|
1008
|
+
for other in others:
|
|
1009
|
+
rel = Action(ActionType.Bind, to_var(self._instance), [], {self._prop: to_var(other)})
|
|
1010
|
+
self._graph._action(rel)
|
|
1011
|
+
|
|
1012
|
+
def choose(self, num, unique=True):
|
|
1013
|
+
if num < 1:
|
|
1014
|
+
raise ValueError("Must choose a positive number of items")
|
|
1015
|
+
self._remove_if_unused()
|
|
1016
|
+
items = [getattr(Instance(self._graph, ActionType.Get, [self._instance], {}), self._prop.name) for ix in range(num)]
|
|
1017
|
+
if unique:
|
|
1018
|
+
for ix in range(num-1):
|
|
1019
|
+
items[ix] < items[ix+1]
|
|
1020
|
+
return items
|
|
1021
|
+
|
|
1022
|
+
#--------------------------------------------------
|
|
1023
|
+
# Expression
|
|
1024
|
+
#--------------------------------------------------
|
|
1025
|
+
|
|
1026
|
+
class Expression(Producer):
|
|
1027
|
+
def __init__(self, graph:'Graph', op:mType|Task, args:List[Any]):
|
|
1028
|
+
|
|
1029
|
+
super().__init__(graph)
|
|
1030
|
+
self._var = None
|
|
1031
|
+
self._context = graph._stack.active()
|
|
1032
|
+
|
|
1033
|
+
# For calls to tasks with known signatures, normalize their arguments by
|
|
1034
|
+
# throwing on missing inputs or constructing vars for missing outputs
|
|
1035
|
+
if op.properties and not op.isa(Builtins.Anonymous):
|
|
1036
|
+
for prop, arg in zip_longest(op.properties, args):
|
|
1037
|
+
if arg is None:
|
|
1038
|
+
if prop.is_input:
|
|
1039
|
+
raise TypeError(f"{op.name} is missing a required argument: '{prop.name}'")
|
|
1040
|
+
else:
|
|
1041
|
+
args.append(Var(prop.type, name=prop.name))
|
|
1042
|
+
|
|
1043
|
+
# Expose the last output as the result, to ensure we don't double-create it in _use_var.
|
|
1044
|
+
# @NOTE: Literal values like 1 show up here from calls like `rel.range(0, len(df), 1)`
|
|
1045
|
+
if not op.properties[-1].is_input and isinstance(args[-1], Var):
|
|
1046
|
+
self._var = args[-1]
|
|
1047
|
+
|
|
1048
|
+
self._expr = build.call(op, args)
|
|
1049
|
+
self._graph._action(self._expr)
|
|
1050
|
+
|
|
1051
|
+
def __call__(self, *args, **kwargs):
|
|
1052
|
+
raise Exception("Expressions can't be called")
|
|
1053
|
+
|
|
1054
|
+
def _use_var(self):
|
|
1055
|
+
if self._expr.entity.isa(Builtins.Filter):
|
|
1056
|
+
if isinstance(runtime_env, SnowbookEnvironment):
|
|
1057
|
+
return
|
|
1058
|
+
raise FilterAsValue(Errors.call_source())
|
|
1059
|
+
elif not self._var:
|
|
1060
|
+
self._var = Var(Builtins.Unknown)
|
|
1061
|
+
prop = build.property_named("result", self._expr.types)
|
|
1062
|
+
self._expr.append(prop, self._var)
|
|
1063
|
+
|
|
1064
|
+
if not self._graph._stack.contains(self._context):
|
|
1065
|
+
exception = VariableOutOfContextException(Errors.call_source(), self._var.name or "a result")
|
|
1066
|
+
raise exception from None
|
|
1067
|
+
|
|
1068
|
+
def _make_sub(self, name: str, existing=None):
|
|
1069
|
+
if existing is not None and existing._instance._context is self._graph._stack.active():
|
|
1070
|
+
return existing
|
|
1071
|
+
return getattr(Instance(self._graph, ActionType.Get, [self], {}), name)
|
|
1072
|
+
|
|
1073
|
+
def has_value(self):
|
|
1074
|
+
return self != rel.Missing # type:ignore
|
|
1075
|
+
|
|
1076
|
+
#--------------------------------------------------
|
|
1077
|
+
# RelationNS
|
|
1078
|
+
#--------------------------------------------------
|
|
1079
|
+
|
|
1080
|
+
unsafe_symbol_pattern = re.compile(r"[^a-zA-Z0-9_]", re.UNICODE)
|
|
1081
|
+
def safe_symbol(name: str):
|
|
1082
|
+
return f':"{name}"' if unsafe_symbol_pattern.search(name) else f":{name}"
|
|
1083
|
+
|
|
1084
|
+
class RelationNS():
|
|
1085
|
+
def __init__(self, ns:List[str], name:str, use_rel_namespaces=False, tags:List[mType]=[]):
|
|
1086
|
+
if name == "getdoc":
|
|
1087
|
+
rich.print("[red bold]GETDOC CALLED")
|
|
1088
|
+
traceback.print_stack()
|
|
1089
|
+
return
|
|
1090
|
+
self._name = name
|
|
1091
|
+
self._ns = ns
|
|
1092
|
+
self._subs = {}
|
|
1093
|
+
self._use_rel_namespaces = use_rel_namespaces
|
|
1094
|
+
self._rel = self._build_rel()
|
|
1095
|
+
self._tags = tags
|
|
1096
|
+
|
|
1097
|
+
def __call__(self, *args: Any, **kwds: Any) -> Any:
|
|
1098
|
+
op = self._rel
|
|
1099
|
+
for t in self._tags:
|
|
1100
|
+
tag(self, t)
|
|
1101
|
+
self._ensure_args(len(args))
|
|
1102
|
+
return Expression(get_graph(), op, list(args))
|
|
1103
|
+
|
|
1104
|
+
def __getattr__(self, name: str) -> RelationNS:
|
|
1105
|
+
self._subs[name] = self._make_sub(name, self._subs.get(name))
|
|
1106
|
+
return self._subs[name]
|
|
1107
|
+
|
|
1108
|
+
def _make_sub(self, name: str, existing=None):
|
|
1109
|
+
if existing is not None:
|
|
1110
|
+
return existing
|
|
1111
|
+
ns = self._ns[:]
|
|
1112
|
+
if self._name:
|
|
1113
|
+
ns.append(self._name)
|
|
1114
|
+
return self.__class__(ns, name, use_rel_namespaces=self._use_rel_namespaces, tags=self._tags)
|
|
1115
|
+
|
|
1116
|
+
def _build_rel(self, arg_count = 0):
|
|
1117
|
+
fqn_parts = self._ns + [self._name]
|
|
1118
|
+
if self._use_rel_namespaces:
|
|
1119
|
+
return build.relation('::'+'::'.join(fqn_parts), arg_count)
|
|
1120
|
+
if len(fqn_parts) == 1:
|
|
1121
|
+
return build.relation(fqn_parts[0], arg_count)
|
|
1122
|
+
else:
|
|
1123
|
+
return build.relation(f"{fqn_parts[0]}[{', '.join(safe_symbol(part) for part in fqn_parts[1:])}]", arg_count)
|
|
1124
|
+
|
|
1125
|
+
def _ensure_args(self, arg_count):
|
|
1126
|
+
if len(self._rel.properties) <= arg_count:
|
|
1127
|
+
self._rel.properties = [Builtins.Relation.properties[i] for i in range(arg_count)]
|
|
1128
|
+
|
|
1129
|
+
def add(self, *args):
|
|
1130
|
+
op = self._rel
|
|
1131
|
+
self._ensure_args(len(args))
|
|
1132
|
+
get_graph()._action(build.relation_action(ActionType.Bind, op, list(args)))
|
|
1133
|
+
|
|
1134
|
+
def _to_var(self):
|
|
1135
|
+
return Var(Builtins.Relation, value=self._build_rel())
|
|
1136
|
+
|
|
1137
|
+
def _tagged(self, *tags: mType):
|
|
1138
|
+
return self.__class__(self._ns, self._name, use_rel_namespaces=self._use_rel_namespaces, tags=list(tags))
|
|
1139
|
+
|
|
1140
|
+
#--------------------------------------------------
|
|
1141
|
+
# RawRelation
|
|
1142
|
+
#--------------------------------------------------
|
|
1143
|
+
|
|
1144
|
+
class RawRelation(Producer):
|
|
1145
|
+
def __init__(self, graph:'Graph', name:str, arity:int):
|
|
1146
|
+
super().__init__(graph)
|
|
1147
|
+
self._name = name
|
|
1148
|
+
self._arity = arity
|
|
1149
|
+
self._type = build.relation(self._name, self._arity)
|
|
1150
|
+
|
|
1151
|
+
def __call__(self, *args: Any, **kwds: Any) -> Any:
|
|
1152
|
+
return Expression(self._graph, self._type, list(args))
|
|
1153
|
+
|
|
1154
|
+
def add(self, *args):
|
|
1155
|
+
self._graph._action(build.relation_action(ActionType.Bind, self._type, list(args)))
|
|
1156
|
+
|
|
1157
|
+
def _make_sub(self, name: str, existing=None):
|
|
1158
|
+
return existing
|
|
1159
|
+
|
|
1160
|
+
def _to_var(self):
|
|
1161
|
+
return Var(Builtins.Relation, value=self._type)
|
|
1162
|
+
|
|
1163
|
+
#--------------------------------------------------
|
|
1164
|
+
# InlineRelation
|
|
1165
|
+
#--------------------------------------------------
|
|
1166
|
+
|
|
1167
|
+
class InlineRelation():
|
|
1168
|
+
def __init__(self, graph:'Graph', data:List[Tuple]):
|
|
1169
|
+
self._var = Var(type=Builtins.InlineRawData)
|
|
1170
|
+
self._graph = graph
|
|
1171
|
+
cols = [[] for _ in range(len(data[0]))]
|
|
1172
|
+
for row in data:
|
|
1173
|
+
for i, val in enumerate(row):
|
|
1174
|
+
cols[i].append(to_var(val))
|
|
1175
|
+
|
|
1176
|
+
params = [Var(value=col) for col in cols]
|
|
1177
|
+
params.append(self._var)
|
|
1178
|
+
q = build.relation_action(ActionType.Get, Builtins.InlineRawData, params)
|
|
1179
|
+
self._graph._action(q)
|
|
1180
|
+
|
|
1181
|
+
def _to_var(self):
|
|
1182
|
+
return self._var
|
|
1183
|
+
|
|
1184
|
+
#--------------------------------------------------
|
|
1185
|
+
# Rows
|
|
1186
|
+
#--------------------------------------------------
|
|
1187
|
+
|
|
1188
|
+
class Rows():
|
|
1189
|
+
def __init__(self, graph:'Graph', data:List[Any]):
|
|
1190
|
+
self._graph = graph
|
|
1191
|
+
|
|
1192
|
+
col_names = []
|
|
1193
|
+
data_cols = []
|
|
1194
|
+
|
|
1195
|
+
size = len(data)
|
|
1196
|
+
warning_size = 1000
|
|
1197
|
+
error_size = 10000
|
|
1198
|
+
if size > error_size:
|
|
1199
|
+
raise errors.RowLiteralTooLarge(size, max_size=error_size)
|
|
1200
|
+
elif size > warning_size:
|
|
1201
|
+
errors.RowLiteralTooLargeWarning(size, max_size=warning_size)
|
|
1202
|
+
|
|
1203
|
+
first = data[0]
|
|
1204
|
+
if isinstance(first, dict):
|
|
1205
|
+
col_names = list(first.keys())
|
|
1206
|
+
data_cols = [[] for _ in range(len(col_names))]
|
|
1207
|
+
for row in data:
|
|
1208
|
+
for ix, col in enumerate(col_names):
|
|
1209
|
+
if col not in row:
|
|
1210
|
+
raise errors.RowLiteralMismatch("keys")
|
|
1211
|
+
data_cols[ix].append(row[col])
|
|
1212
|
+
elif isinstance(first, tuple):
|
|
1213
|
+
data_cols = [[] for _ in range(len(first))]
|
|
1214
|
+
for row in data:
|
|
1215
|
+
if len(row) != len(first):
|
|
1216
|
+
raise errors.RowLiteralMismatch("length")
|
|
1217
|
+
for ix, col in enumerate(row):
|
|
1218
|
+
data_cols[ix].append(col)
|
|
1219
|
+
elif isinstance(first, list):
|
|
1220
|
+
data_cols = [data]
|
|
1221
|
+
else:
|
|
1222
|
+
raise Exception("Unsupported data type: must be a list")
|
|
1223
|
+
|
|
1224
|
+
data_vars = [Var(value=col) for col in data_cols]
|
|
1225
|
+
if col_names:
|
|
1226
|
+
vars = [Var(name=name) for name in col_names]
|
|
1227
|
+
else:
|
|
1228
|
+
vars = [Var() for _ in range(len(data_vars))]
|
|
1229
|
+
|
|
1230
|
+
self._fetch = build.relation_action(ActionType.Get, Builtins.RawData, [*data_vars, *vars])
|
|
1231
|
+
self._var = vars[-1]
|
|
1232
|
+
self._vars = vars
|
|
1233
|
+
self._columns = col_names
|
|
1234
|
+
|
|
1235
|
+
def _add_to_graph(self):
|
|
1236
|
+
if not self._graph._in_rule():
|
|
1237
|
+
raise errors.OutOfContextException()
|
|
1238
|
+
self._graph._action(self._fetch, dedupe=True)
|
|
1239
|
+
|
|
1240
|
+
def _to_var(self):
|
|
1241
|
+
self._add_to_graph()
|
|
1242
|
+
return self._var
|
|
1243
|
+
|
|
1244
|
+
def __getitem__(self, index):
|
|
1245
|
+
self._add_to_graph()
|
|
1246
|
+
if isinstance(index, str):
|
|
1247
|
+
return getattr(self, index)
|
|
1248
|
+
return self._vars[index]
|
|
1249
|
+
|
|
1250
|
+
def __getattr__(self, name):
|
|
1251
|
+
if name in self._columns:
|
|
1252
|
+
self._add_to_graph()
|
|
1253
|
+
return self._vars[self._columns.index(name)]
|
|
1254
|
+
raise AttributeError(f"Set has no attribute '{name}'")
|
|
1255
|
+
|
|
1256
|
+
#--------------------------------------------------
|
|
1257
|
+
# Symbol
|
|
1258
|
+
#--------------------------------------------------
|
|
1259
|
+
|
|
1260
|
+
class Symbol():
|
|
1261
|
+
def __init__(self, name:str):
|
|
1262
|
+
self._var = Var(Builtins.Symbol, value=name)
|
|
1263
|
+
|
|
1264
|
+
def _to_var(self):
|
|
1265
|
+
return self._var
|
|
1266
|
+
|
|
1267
|
+
#--------------------------------------------------
|
|
1268
|
+
# RelationRef
|
|
1269
|
+
#--------------------------------------------------
|
|
1270
|
+
|
|
1271
|
+
class RelationRef(Producer):
|
|
1272
|
+
def __init__(self, graph:'Graph', rel:Task|mType, args:List[Var]):
|
|
1273
|
+
super().__init__(graph)
|
|
1274
|
+
self._rel = rel
|
|
1275
|
+
self._args = args
|
|
1276
|
+
self._var = args[-1]
|
|
1277
|
+
self._action = build.relation_action(ActionType.Get, self._rel, self._args)
|
|
1278
|
+
|
|
1279
|
+
def _use_var(self):
|
|
1280
|
+
self._graph._action(self._action)
|
|
1281
|
+
|
|
1282
|
+
def _make_sub(self, name: str, existing=None):
|
|
1283
|
+
return getattr(Instance(self._graph, ActionType.Get, [self], {}), name)
|
|
1284
|
+
|
|
1285
|
+
def __enter__(self):
|
|
1286
|
+
super().__enter__()
|
|
1287
|
+
self._use_var()
|
|
1288
|
+
Instance(self._graph, ActionType.Get, [self], {}).has_value()
|
|
1289
|
+
|
|
1290
|
+
#--------------------------------------------------
|
|
1291
|
+
# Export
|
|
1292
|
+
#--------------------------------------------------
|
|
1293
|
+
|
|
1294
|
+
allowed_export_types = [Type, str, numbers.Number, datetime.datetime, datetime.date, bool]
|
|
1295
|
+
|
|
1296
|
+
def check_type(name, type):
|
|
1297
|
+
if not any(isinstance(type, t) or (inspect.isclass(type) and issubclass(type, t))
|
|
1298
|
+
for t in allowed_export_types):
|
|
1299
|
+
raise TypeError(f"Argument '{name}' is an unsupported type: {type}")
|
|
1300
|
+
|
|
1301
|
+
def export(model, schema, kwargs):
|
|
1302
|
+
try:
|
|
1303
|
+
parser = IdentityParser(schema)
|
|
1304
|
+
except ParseError as e:
|
|
1305
|
+
raise Exception(f"Not able to parse provided schema '{schema}'. {e}")
|
|
1306
|
+
|
|
1307
|
+
def decorator(func):
|
|
1308
|
+
# Get type hints of the function
|
|
1309
|
+
hints = get_type_hints(func)
|
|
1310
|
+
input_types = [hints[name] for name in hints if name != 'return']
|
|
1311
|
+
arg_names = func.__code__.co_varnames[:func.__code__.co_argcount]
|
|
1312
|
+
for name in arg_names:
|
|
1313
|
+
if name not in hints:
|
|
1314
|
+
raise TypeError(f"Argument '{name}' must have a type hint")
|
|
1315
|
+
check_type(name, hints[name])
|
|
1316
|
+
|
|
1317
|
+
output_types = []
|
|
1318
|
+
has_return_hint = 'return' in hints
|
|
1319
|
+
if has_return_hint:
|
|
1320
|
+
ret = hints.get('return')
|
|
1321
|
+
if typing.get_origin(ret) is tuple:
|
|
1322
|
+
for t in typing.get_args(ret):
|
|
1323
|
+
check_type("return", t)
|
|
1324
|
+
output_types.append(t)
|
|
1325
|
+
else:
|
|
1326
|
+
check_type("return", ret)
|
|
1327
|
+
output_types.append(ret)
|
|
1328
|
+
name = f"{schema}.{func.__name__}" if schema else func.__name__
|
|
1329
|
+
props = {
|
|
1330
|
+
"name": name if parser.entity is None else parser.identity,
|
|
1331
|
+
"outputs": output_types if has_return_hint else None,
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
ctx = Context(model, exec_type=TaskExecType.Procedure, props=props, format="snowpark", **kwargs)
|
|
1335
|
+
with ctx as ret:
|
|
1336
|
+
inputs = to_list(Vars(len(arg_names)))
|
|
1337
|
+
for i in inputs:
|
|
1338
|
+
i._var.type = Builtins.ExternalInput
|
|
1339
|
+
props["inputs"] = list(zip(arg_names, [to_var(i) for i in inputs], input_types))
|
|
1340
|
+
outs = to_list(func(*inputs))
|
|
1341
|
+
if has_return_hint and len(outs) != len(output_types):
|
|
1342
|
+
raise TypeError(f"Function '{func.__name__}' must return {len(output_types)} values according to the type hints")
|
|
1343
|
+
ret(*outs)
|
|
1344
|
+
|
|
1345
|
+
def wrapper():
|
|
1346
|
+
raise Exception("Exports can't be called directly. They are exported to the underlying platform")
|
|
1347
|
+
|
|
1348
|
+
return wrapper
|
|
1349
|
+
return decorator
|
|
1350
|
+
|
|
1351
|
+
#--------------------------------------------------
|
|
1352
|
+
# RuleStack
|
|
1353
|
+
#--------------------------------------------------
|
|
1354
|
+
|
|
1355
|
+
class RuleStack():
|
|
1356
|
+
def __init__(self, graph:'Graph'):
|
|
1357
|
+
self.items = []
|
|
1358
|
+
self.stack = []
|
|
1359
|
+
self._graph = graph
|
|
1360
|
+
|
|
1361
|
+
def push(self, item):
|
|
1362
|
+
self.stack.append(item)
|
|
1363
|
+
self.items.append(("push", item))
|
|
1364
|
+
|
|
1365
|
+
def pop(self, item, globalize=False):
|
|
1366
|
+
self.stack.pop()
|
|
1367
|
+
self.items.append(("pop", item))
|
|
1368
|
+
if len(self.stack) == 0:
|
|
1369
|
+
compacted = self.compact()
|
|
1370
|
+
self.items.clear()
|
|
1371
|
+
if len(compacted.items):
|
|
1372
|
+
return compacted
|
|
1373
|
+
elif globalize:
|
|
1374
|
+
ix = self.items.index(("push", item))
|
|
1375
|
+
temp_items = self.items[0:ix]
|
|
1376
|
+
self.items = self.items[ix:]
|
|
1377
|
+
compacted = self.compact()
|
|
1378
|
+
self.items = temp_items
|
|
1379
|
+
if len(compacted.items):
|
|
1380
|
+
return compacted
|
|
1381
|
+
|
|
1382
|
+
def push_item(self, item):
|
|
1383
|
+
if not len(self.stack):
|
|
1384
|
+
raise Exception("Can't push a non-context item onto an empty stack")
|
|
1385
|
+
self.items.append(item)
|
|
1386
|
+
|
|
1387
|
+
def contains(self, item):
|
|
1388
|
+
for i in self.stack:
|
|
1389
|
+
if i is item:
|
|
1390
|
+
return True
|
|
1391
|
+
|
|
1392
|
+
def is_active(self, item):
|
|
1393
|
+
if isinstance(item, Context) and item._task.behavior != Behavior.Query:
|
|
1394
|
+
return False
|
|
1395
|
+
return item is self.active()
|
|
1396
|
+
|
|
1397
|
+
def in_context(self, item):
|
|
1398
|
+
if isinstance(item, Context) and item._task.behavior != Behavior.Query:
|
|
1399
|
+
return False
|
|
1400
|
+
return self.contains(item)
|
|
1401
|
+
|
|
1402
|
+
def active(self):
|
|
1403
|
+
try:
|
|
1404
|
+
cur = self.stack[-1]
|
|
1405
|
+
if cur is self._graph._temp_rule:
|
|
1406
|
+
exception = OutOfContextException(Errors.call_source())
|
|
1407
|
+
raise exception from None
|
|
1408
|
+
return cur
|
|
1409
|
+
except IndexError:
|
|
1410
|
+
exception = OutOfContextException(Errors.call_source())
|
|
1411
|
+
raise exception from None
|
|
1412
|
+
|
|
1413
|
+
def _expression_start(self, buffer, single_use_vars):
|
|
1414
|
+
consume_from = -1
|
|
1415
|
+
if not len(buffer):
|
|
1416
|
+
return consume_from
|
|
1417
|
+
# we can only pull vars if their only use is for this condition
|
|
1418
|
+
used_vars = set(buffer[-1].requires_provides()[0] & single_use_vars)
|
|
1419
|
+
# walk buffer in reverse collecting vars in the action until we get one
|
|
1420
|
+
# that doesn't provide a var we care about
|
|
1421
|
+
for action in reversed(buffer[:-1]):
|
|
1422
|
+
if not isinstance(action, Action):
|
|
1423
|
+
break
|
|
1424
|
+
req, provs, _ = action.requires_provides()
|
|
1425
|
+
# don't pull in vars the represent root entities even though they're provided
|
|
1426
|
+
# by gets. This prevents scenarios where p = Person() would get pulled in if you
|
|
1427
|
+
# did with p.age > 10:
|
|
1428
|
+
provs = provs - {action.entity}
|
|
1429
|
+
if len(used_vars.intersection(provs)):
|
|
1430
|
+
used_vars.update(req & single_use_vars)
|
|
1431
|
+
consume_from -= 1
|
|
1432
|
+
else:
|
|
1433
|
+
break
|
|
1434
|
+
return consume_from
|
|
1435
|
+
|
|
1436
|
+
def compact(self) -> Task:
|
|
1437
|
+
stack:List[Task] = []
|
|
1438
|
+
buffer = []
|
|
1439
|
+
|
|
1440
|
+
var_uses = {}
|
|
1441
|
+
for item in self.items:
|
|
1442
|
+
if isinstance(item, Action):
|
|
1443
|
+
if item.action == ActionType.Get:
|
|
1444
|
+
for var in item.vars():
|
|
1445
|
+
var_uses[var] = var_uses.get(var, 0) + 1
|
|
1446
|
+
else:
|
|
1447
|
+
for var in item.vars():
|
|
1448
|
+
var_uses[var] = var_uses.get(var, 0) - 1
|
|
1449
|
+
|
|
1450
|
+
# check for 2 refs - one create and one use
|
|
1451
|
+
single_use_vars = set([var for var, uses in var_uses.items() if uses >= 0])
|
|
1452
|
+
|
|
1453
|
+
for item in self.items:
|
|
1454
|
+
if not isinstance(item, tuple):
|
|
1455
|
+
buffer.append(item)
|
|
1456
|
+
continue
|
|
1457
|
+
|
|
1458
|
+
op, value = item
|
|
1459
|
+
if op == "push":
|
|
1460
|
+
if isinstance(value, Context):
|
|
1461
|
+
if len(buffer):
|
|
1462
|
+
stack[-1].items.extend(buffer)
|
|
1463
|
+
buffer.clear()
|
|
1464
|
+
task = value._task
|
|
1465
|
+
elif isinstance(value, RelationRef):
|
|
1466
|
+
if len(buffer):
|
|
1467
|
+
stack[-1].items.extend(buffer)
|
|
1468
|
+
buffer.clear()
|
|
1469
|
+
task = Task()
|
|
1470
|
+
|
|
1471
|
+
elif isinstance(value, Producer):
|
|
1472
|
+
consume_from = self._expression_start(buffer, single_use_vars)
|
|
1473
|
+
stack[-1].items.extend(buffer[:consume_from])
|
|
1474
|
+
buffer = buffer[consume_from:]
|
|
1475
|
+
task = Task()
|
|
1476
|
+
else:
|
|
1477
|
+
raise Exception(f"Unknown push type: {type(value)}")
|
|
1478
|
+
|
|
1479
|
+
stack.append(task)
|
|
1480
|
+
|
|
1481
|
+
elif op == "pop":
|
|
1482
|
+
cur = stack.pop()
|
|
1483
|
+
cur.items.extend(buffer)
|
|
1484
|
+
buffer.clear()
|
|
1485
|
+
if not len(stack):
|
|
1486
|
+
return cur
|
|
1487
|
+
if isinstance(value, Context) and value._op:
|
|
1488
|
+
stack[-1].items.append(build.call(value._op, [Var(value=value._args), Var(Builtins.Task, value=cur)]))
|
|
1489
|
+
else:
|
|
1490
|
+
stack[-1].items.append(build.call(cur, list(cur.bindings.values())))
|
|
1491
|
+
|
|
1492
|
+
raise Exception("No task found")
|
|
1493
|
+
|
|
1494
|
+
#--------------------------------------------------
|
|
1495
|
+
# Graph
|
|
1496
|
+
#--------------------------------------------------
|
|
1497
|
+
|
|
1498
|
+
locals = threading.local()
|
|
1499
|
+
locals.graph_stack = []
|
|
1500
|
+
|
|
1501
|
+
def get_graph() -> 'Graph':
|
|
1502
|
+
_ensure_stack()
|
|
1503
|
+
if not len(locals.graph_stack):
|
|
1504
|
+
raise Exception("Outside of a model context")
|
|
1505
|
+
return locals.graph_stack[-1]
|
|
1506
|
+
|
|
1507
|
+
def _ensure_stack():
|
|
1508
|
+
if not hasattr(locals, "graph_stack"):
|
|
1509
|
+
locals.graph_stack = []
|
|
1510
|
+
return locals.graph_stack
|
|
1511
|
+
|
|
1512
|
+
rel = RelationNS([], "")
|
|
1513
|
+
global_ns = RelationNS([], "", use_rel_namespaces=True)
|
|
1514
|
+
|
|
1515
|
+
def alias(ref:Any, name:str):
|
|
1516
|
+
var = to_var(ref)
|
|
1517
|
+
var.name = name
|
|
1518
|
+
return var
|
|
1519
|
+
|
|
1520
|
+
def tag(ref:Any, tag:mType):
|
|
1521
|
+
if isinstance(ref, RelationNS):
|
|
1522
|
+
parents = ref._rel.parents
|
|
1523
|
+
elif isinstance(ref, Type):
|
|
1524
|
+
parents = ref._type.parents
|
|
1525
|
+
elif isinstance(ref, Property):
|
|
1526
|
+
parents = ref._type.parents
|
|
1527
|
+
else:
|
|
1528
|
+
return
|
|
1529
|
+
if tag not in parents:
|
|
1530
|
+
parents.append(tag)
|
|
1531
|
+
|
|
1532
|
+
def create_var() -> Instance:
|
|
1533
|
+
return Instance(get_graph(), ActionType.Get, [], {}, Var(Builtins.Unknown))
|
|
1534
|
+
|
|
1535
|
+
def create_vars(count: int) -> List[Instance]:
|
|
1536
|
+
return [create_var() for _ in range(count)]
|
|
1537
|
+
|
|
1538
|
+
def Vars(count: int):
|
|
1539
|
+
if count == 1:
|
|
1540
|
+
return create_var()
|
|
1541
|
+
return create_vars(count)
|
|
1542
|
+
|
|
1543
|
+
class Graph:
|
|
1544
|
+
def __init__(self, client:Client, name:str, format:str="default"):
|
|
1545
|
+
self.name = name
|
|
1546
|
+
self._executed = []
|
|
1547
|
+
self._client = client
|
|
1548
|
+
self._config = client.resources.config
|
|
1549
|
+
self.resources = client.resources
|
|
1550
|
+
self._prop_is_multi:Dict[str, bool] = {}
|
|
1551
|
+
self._format = format
|
|
1552
|
+
self._stack = RuleStack(self)
|
|
1553
|
+
self._restore_temp()
|
|
1554
|
+
|
|
1555
|
+
self._Error = Type(self, "Error", scope="pyrel_error_")
|
|
1556
|
+
self._error_props = set()
|
|
1557
|
+
|
|
1558
|
+
|
|
1559
|
+
#--------------------------------------------------
|
|
1560
|
+
# Rule stack
|
|
1561
|
+
#--------------------------------------------------
|
|
1562
|
+
|
|
1563
|
+
def _flush_temp(self):
|
|
1564
|
+
if self._temp_rule:
|
|
1565
|
+
self._pop(self._temp_rule, is_temp=True)
|
|
1566
|
+
if not len(_ensure_stack()):
|
|
1567
|
+
_ensure_stack().append(self)
|
|
1568
|
+
self._temp_rule = None
|
|
1569
|
+
|
|
1570
|
+
def _restore_temp(self):
|
|
1571
|
+
self._temp_rule = Context(self)
|
|
1572
|
+
_ensure_stack().append(self)
|
|
1573
|
+
self._stack.push(self._temp_rule)
|
|
1574
|
+
|
|
1575
|
+
def _temp_is_active(self):
|
|
1576
|
+
return self._temp_rule and len(self._stack.items) > 1
|
|
1577
|
+
|
|
1578
|
+
def _in_rule(self):
|
|
1579
|
+
return not self._temp_rule
|
|
1580
|
+
|
|
1581
|
+
def _push(self, item):
|
|
1582
|
+
_ensure_stack().append(self)
|
|
1583
|
+
self._flush_temp()
|
|
1584
|
+
self._stack.push(item)
|
|
1585
|
+
|
|
1586
|
+
def _pop(self, item, exec=True, is_temp=False, globalize=False):
|
|
1587
|
+
_ensure_stack().pop()
|
|
1588
|
+
task = self._stack.pop(item, globalize=globalize)
|
|
1589
|
+
try:
|
|
1590
|
+
if exec and task:
|
|
1591
|
+
self._exec(item, task)
|
|
1592
|
+
finally:
|
|
1593
|
+
if not is_temp and not len(self._stack.stack):
|
|
1594
|
+
self._restore_temp()
|
|
1595
|
+
|
|
1596
|
+
def _action(self, action:Action|List[Action], dedupe=False):
|
|
1597
|
+
if isinstance(action, list):
|
|
1598
|
+
for a in action:
|
|
1599
|
+
self._action(a, dedupe=dedupe)
|
|
1600
|
+
return
|
|
1601
|
+
if dedupe and self._stack.contains(action):
|
|
1602
|
+
return
|
|
1603
|
+
self._stack.push_item(action)
|
|
1604
|
+
|
|
1605
|
+
def _remove_action(self, action):
|
|
1606
|
+
self._stack.items.remove(action)
|
|
1607
|
+
|
|
1608
|
+
def _exec(self, context:Context, task):
|
|
1609
|
+
props = context._props
|
|
1610
|
+
if context._exec_type == TaskExecType.Rule:
|
|
1611
|
+
self._client.install(f"rule{len(self._executed)}", context._task)
|
|
1612
|
+
elif context._exec_type == TaskExecType.Query:
|
|
1613
|
+
headers = {QUERY_ATTRIBUTES_HEADER: json.dumps(context._attributes)} if context._attributes else {}
|
|
1614
|
+
context.results = self._client.query(context._task, tag=context._tag, format=context._format, headers=headers, read_only=context._read_only, skip_invalid_data=context._skip_invalid_data)
|
|
1615
|
+
elif context._exec_type == TaskExecType.Procedure:
|
|
1616
|
+
self._client.export_udf(props["name"], props["inputs"], props["outputs"], context._task, props.get("engine"), skip_invalid_data=context._skip_invalid_data)
|
|
1617
|
+
elif context._exec_type == TaskExecType.Export:
|
|
1618
|
+
self._client.export_table(props["name"], props["rel"], props["columns"], context._task, engine=props.get("engine"), refresh=props.get("refresh"))
|
|
1619
|
+
self._executed.append(context)
|
|
1620
|
+
|
|
1621
|
+
#--------------------------------------------------
|
|
1622
|
+
# Property handling
|
|
1623
|
+
#--------------------------------------------------
|
|
1624
|
+
|
|
1625
|
+
def _check_property(self, prop:mProperty, multi_valued=False, unknown_cardinality=False):
|
|
1626
|
+
name = prop.name
|
|
1627
|
+
if name in RESERVED_PROPS:
|
|
1628
|
+
exception = ReservedPropertyException(Errors.call_source(), name)
|
|
1629
|
+
raise exception from None
|
|
1630
|
+
|
|
1631
|
+
if unknown_cardinality:
|
|
1632
|
+
if name in self._prop_is_multi and self._prop_is_multi[name] and Builtins.MultiValued not in prop.parents:
|
|
1633
|
+
prop.parents.append(Builtins.MultiValued)
|
|
1634
|
+
return
|
|
1635
|
+
|
|
1636
|
+
if name in self._prop_is_multi:
|
|
1637
|
+
if self._prop_is_multi[name] != multi_valued:
|
|
1638
|
+
raise Exception(
|
|
1639
|
+
f"Trying to use a property `{name}` as both singular and multi-valued. "
|
|
1640
|
+
"This often happens when multiple types have a property with the same name, but one is single-valued and the other is multi-valued. "
|
|
1641
|
+
"Consider using a plural name for the multi-valued property. "
|
|
1642
|
+
"See https://relational.ai/docs/develop/core-concepts#setting-object-properties for more information."
|
|
1643
|
+
)
|
|
1644
|
+
elif self._prop_is_multi[name] and Builtins.MultiValued not in prop.parents:
|
|
1645
|
+
prop.parents.append(Builtins.MultiValued)
|
|
1646
|
+
else:
|
|
1647
|
+
self._prop_is_multi[name] = multi_valued
|
|
1648
|
+
|
|
1649
|
+
if not multi_valued and Builtins.FunctionAnnotation not in prop.parents:
|
|
1650
|
+
prop.parents.append(Builtins.FunctionAnnotation)
|
|
1651
|
+
elif multi_valued and Builtins.MultiValued not in prop.parents:
|
|
1652
|
+
prop.parents.append(Builtins.MultiValued)
|
|
1653
|
+
|
|
1654
|
+
#--------------------------------------------------
|
|
1655
|
+
# Public API
|
|
1656
|
+
#--------------------------------------------------
|
|
1657
|
+
|
|
1658
|
+
def Type(self, name:str, source=None):
|
|
1659
|
+
if source:
|
|
1660
|
+
return self.resources.to_model_type(self, name, source)
|
|
1661
|
+
return Type(self, name)
|
|
1662
|
+
|
|
1663
|
+
def _error_like(self, message:str, kwargs:Dict[str, Any], is_error:bool):
|
|
1664
|
+
kwargs["message"] = message
|
|
1665
|
+
kwargs["severity"] = "error" if is_error else "warning"
|
|
1666
|
+
source = Errors.call_source()
|
|
1667
|
+
id = 0
|
|
1668
|
+
if source:
|
|
1669
|
+
id = len(errors.ModelError.error_locations)
|
|
1670
|
+
errors.ModelError.error_locations[id] = source
|
|
1671
|
+
kwargs["pyrel_id"] = id
|
|
1672
|
+
for k, v in kwargs.items():
|
|
1673
|
+
if k not in self._error_props:
|
|
1674
|
+
self._error_props.add(k)
|
|
1675
|
+
with self.rule():
|
|
1676
|
+
e = self._Error()
|
|
1677
|
+
rel.output.pyrel_error.add(e, k, getattr(e, k))
|
|
1678
|
+
if is_error:
|
|
1679
|
+
with self.case():
|
|
1680
|
+
self._Error(pyrel_id=id)
|
|
1681
|
+
rel.abort.add()
|
|
1682
|
+
return self._Error.add(**kwargs)
|
|
1683
|
+
|
|
1684
|
+
def error(self, message:str, **kwargs):
|
|
1685
|
+
return self._error_like(message, kwargs, is_error=True)
|
|
1686
|
+
|
|
1687
|
+
def warn(self, message:str, **kwargs):
|
|
1688
|
+
return self._error_like(message, kwargs, is_error=False)
|
|
1689
|
+
|
|
1690
|
+
def rule(self, **kwargs):
|
|
1691
|
+
return Context(self, **kwargs)
|
|
1692
|
+
|
|
1693
|
+
def scope(self, **kwargs):
|
|
1694
|
+
return Context(self, **kwargs)
|
|
1695
|
+
|
|
1696
|
+
def case(self, **kwargs):
|
|
1697
|
+
return Context(self, **kwargs)
|
|
1698
|
+
|
|
1699
|
+
def match(self, multiple=False, **kwargs):
|
|
1700
|
+
if not multiple:
|
|
1701
|
+
return Context(self, behavior=Behavior.OrderedChoice, **kwargs)
|
|
1702
|
+
else:
|
|
1703
|
+
return Context(self, behavior=Behavior.Union, **kwargs)
|
|
1704
|
+
|
|
1705
|
+
def query(self, **kwargs):
|
|
1706
|
+
return Context(self, exec_type=TaskExecType.Query, **kwargs)
|
|
1707
|
+
|
|
1708
|
+
def export(self, object:str = "", **kwargs):
|
|
1709
|
+
return export(self, object, kwargs)
|
|
1710
|
+
|
|
1711
|
+
def found(self, **kwargs):
|
|
1712
|
+
return Context(self, op=Builtins.Exists, **kwargs)
|
|
1713
|
+
|
|
1714
|
+
def not_found(self, **kwargs):
|
|
1715
|
+
return Context(self, op=Builtins.Not, **kwargs)
|
|
1716
|
+
|
|
1717
|
+
def union(self, **kwargs):
|
|
1718
|
+
return Context(self, behavior=Behavior.Union, **kwargs)
|
|
1719
|
+
|
|
1720
|
+
def ordered_choice(self, **kwargs):
|
|
1721
|
+
return Context(self, behavior=Behavior.OrderedChoice, **kwargs)
|
|
1722
|
+
|
|
1723
|
+
def read(self, name:str, **kwargs):
|
|
1724
|
+
from v0.relationalai.loaders.loader import read_resource_context # We do the late import to break an dependency cycle
|
|
1725
|
+
return read_resource_context(self, name, **kwargs)
|
|
1726
|
+
|
|
1727
|
+
def load_raw(self, path:str):
|
|
1728
|
+
if os.path.isfile(path):
|
|
1729
|
+
if path.endswith('.rel'):
|
|
1730
|
+
self._client.load_raw_file(path)
|
|
1731
|
+
elif os.path.isdir(path):
|
|
1732
|
+
for root, _, files in os.walk(path):
|
|
1733
|
+
for file in files:
|
|
1734
|
+
if file.endswith('.rel'):
|
|
1735
|
+
file_path = os.path.join(root, file)
|
|
1736
|
+
self._client.load_raw_file(file_path)
|
|
1737
|
+
|
|
1738
|
+
def exec_raw(self, code:str, readonly=False, raw_results=True, abort_on_error=True, inputs={}, query_timeout_mins: Optional[int]=None):
|
|
1739
|
+
try:
|
|
1740
|
+
return self._client.exec_raw(code, readonly=readonly, raw_results=raw_results, inputs=inputs, abort_on_error=abort_on_error, query_timeout_mins=query_timeout_mins)
|
|
1741
|
+
except KeyboardInterrupt as e:
|
|
1742
|
+
print("Canceling transactions...")
|
|
1743
|
+
self.resources.cancel_pending_transactions()
|
|
1744
|
+
raise e
|
|
1745
|
+
except RAIException as e:
|
|
1746
|
+
raise e.clone(self._config) from None
|
|
1747
|
+
|
|
1748
|
+
def install_raw(self, code:str, name:str|None = None, overwrite=False):
|
|
1749
|
+
self._client.install_raw(code, name, overwrite)
|