relationalai 0.11.4__py3-none-any.whl → 0.12.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. relationalai/clients/config.py +7 -0
  2. relationalai/clients/direct_access_client.py +113 -0
  3. relationalai/clients/snowflake.py +263 -189
  4. relationalai/clients/types.py +4 -1
  5. relationalai/clients/use_index_poller.py +72 -48
  6. relationalai/clients/util.py +9 -0
  7. relationalai/dsl.py +1 -2
  8. relationalai/early_access/metamodel/rewrite/__init__.py +5 -3
  9. relationalai/early_access/rel/rewrite/__init__.py +1 -1
  10. relationalai/environments/snowbook.py +10 -1
  11. relationalai/errors.py +24 -3
  12. relationalai/semantics/internal/annotations.py +1 -0
  13. relationalai/semantics/internal/internal.py +22 -3
  14. relationalai/semantics/lqp/builtins.py +1 -0
  15. relationalai/semantics/lqp/executor.py +12 -4
  16. relationalai/semantics/lqp/model2lqp.py +1 -0
  17. relationalai/semantics/lqp/passes.py +3 -4
  18. relationalai/semantics/{rel → lqp}/rewrite/__init__.py +6 -0
  19. relationalai/semantics/metamodel/builtins.py +12 -1
  20. relationalai/semantics/metamodel/executor.py +2 -1
  21. relationalai/semantics/metamodel/rewrite/__init__.py +3 -9
  22. relationalai/semantics/metamodel/rewrite/flatten.py +8 -7
  23. relationalai/semantics/reasoners/graph/core.py +1356 -258
  24. relationalai/semantics/rel/builtins.py +5 -1
  25. relationalai/semantics/rel/compiler.py +3 -3
  26. relationalai/semantics/rel/executor.py +20 -11
  27. relationalai/semantics/sql/compiler.py +2 -3
  28. relationalai/semantics/sql/executor/duck_db.py +8 -4
  29. relationalai/semantics/sql/executor/snowflake.py +1 -1
  30. relationalai/tools/cli.py +17 -6
  31. relationalai/tools/cli_controls.py +334 -352
  32. relationalai/tools/constants.py +1 -0
  33. relationalai/tools/query_utils.py +27 -0
  34. relationalai/util/otel_configuration.py +1 -1
  35. {relationalai-0.11.4.dist-info → relationalai-0.12.1.dist-info}/METADATA +5 -4
  36. {relationalai-0.11.4.dist-info → relationalai-0.12.1.dist-info}/RECORD +45 -45
  37. relationalai/semantics/metamodel/rewrite/gc_nodes.py +0 -58
  38. relationalai/semantics/metamodel/rewrite/list_types.py +0 -109
  39. /relationalai/semantics/{rel → lqp}/rewrite/cdc.py +0 -0
  40. /relationalai/semantics/{rel → lqp}/rewrite/extract_common.py +0 -0
  41. /relationalai/semantics/{metamodel → lqp}/rewrite/extract_keys.py +0 -0
  42. /relationalai/semantics/{metamodel → lqp}/rewrite/fd_constraints.py +0 -0
  43. /relationalai/semantics/{rel → lqp}/rewrite/quantify_vars.py +0 -0
  44. /relationalai/semantics/{metamodel → lqp}/rewrite/splinter.py +0 -0
  45. {relationalai-0.11.4.dist-info → relationalai-0.12.1.dist-info}/WHEEL +0 -0
  46. {relationalai-0.11.4.dist-info → relationalai-0.12.1.dist-info}/entry_points.txt +0 -0
  47. {relationalai-0.11.4.dist-info → relationalai-0.12.1.dist-info}/licenses/LICENSE +0 -0
@@ -468,6 +468,13 @@ class Config():
468
468
  if not self.file_path:
469
469
  self.file_path = "__inline__"
470
470
  self._handle_snowflake_fallback_configurations()
471
+ # Check if Azure platform is being used without the legacy dependency
472
+ if self.get("platform", "") == "azure":
473
+ try:
474
+ import railib # noqa
475
+ except ImportError:
476
+ from relationalai.errors import AzureLegacyDependencyMissingException
477
+ raise AzureLegacyDependencyMissingException() from None
471
478
 
472
479
  def fetch(self, profile:str|None=None):
473
480
  from relationalai.environments import runtime_env, TerminalEnvironment
@@ -0,0 +1,113 @@
1
+ from __future__ import annotations
2
+
3
+ import requests
4
+ from dataclasses import dataclass
5
+ from urllib.parse import urlencode, quote
6
+ from requests.adapters import HTTPAdapter
7
+ from urllib3.util.retry import Retry
8
+ from typing import Any, Dict, Optional, Tuple
9
+
10
+ from relationalai.auth.token_handler import TokenHandler
11
+ from relationalai.clients.config import Config
12
+ from relationalai.clients.util import get_pyrel_version
13
+ from relationalai import debugging
14
+ from relationalai.tools.constants import Generation
15
+ from relationalai.environments import runtime_env, SnowbookEnvironment
16
+
17
+ @dataclass
18
+ class Endpoint:
19
+ method: str
20
+ endpoint: str
21
+
22
+ class DirectAccessClient:
23
+ """
24
+ DirectAccessClient is a client for direct service access without service function calls.
25
+ """
26
+
27
+ def __init__(self, config: Config, token_handler: TokenHandler, service_endpoint: str, generation: Optional[Generation] = None):
28
+ self._config: Config = config
29
+ self._token_handler: TokenHandler = token_handler
30
+ self.service_endpoint: str = service_endpoint
31
+ self.generation: Optional[Generation] = generation
32
+ self._is_snowflake_notebook = isinstance(runtime_env, SnowbookEnvironment)
33
+ self.endpoints: Dict[str, Endpoint] = {
34
+ "create_txn": Endpoint(method="POST", endpoint="/v1alpha1/transactions"),
35
+ "get_txn": Endpoint(method="GET", endpoint="/v1alpha1/transactions/{txn_id}"),
36
+ "get_txn_artifacts": Endpoint(method="GET", endpoint="/v1alpha1/transactions/{txn_id}/artifacts"),
37
+ "get_txn_problems": Endpoint(method="GET", endpoint="/v1alpha1/transactions/{txn_id}/problems"),
38
+ "get_txn_events": Endpoint(method="GET", endpoint="/v1alpha1/transactions/{txn_id}/events/{stream_name}"),
39
+ "get_package_versions": Endpoint(method="GET", endpoint="/v1alpha1/databases/{db_name}/package_versions"),
40
+ "get_model_package_versions": Endpoint(method="POST", endpoint="/v1alpha1/models/get_package_versions"),
41
+ "create_db": Endpoint(method="POST", endpoint="/v1alpha1/databases"),
42
+ "get_db": Endpoint(method="GET", endpoint="/v1alpha1/databases"),
43
+ "delete_db": Endpoint(method="DELETE", endpoint="/v1alpha1/databases/{db_name}"),
44
+ "release_index": Endpoint(method="POST", endpoint="/v1alpha1/index/release"),
45
+ "list_engines": Endpoint(method="GET", endpoint="/v1alpha1/engines"),
46
+ "get_engine": Endpoint(method="GET", endpoint="/v1alpha1/engines/{engine_type}/{engine_name}"),
47
+ "create_engine": Endpoint(method="POST", endpoint="/v1alpha1/engines/{engine_type}"),
48
+ "delete_engine": Endpoint(method="DELETE", endpoint="/v1alpha1/engines/{engine_type}/{engine_name}"),
49
+ "suspend_engine": Endpoint(method="POST", endpoint="/v1alpha1/engines/{engine_type}/{engine_name}/suspend"),
50
+ "resume_engine": Endpoint(method="POST", endpoint="/v1alpha1/engines/{engine_type}/{engine_name}/resume_async"),
51
+ "prepare_index": Endpoint(method="POST", endpoint="/v1alpha1/index/prepare"),
52
+ }
53
+ self.http_session = self._create_retry_session()
54
+
55
+ def _create_retry_session(self) -> requests.Session:
56
+ http_session = requests.Session()
57
+ retries = Retry(
58
+ total=3,
59
+ backoff_factor=0.3,
60
+ status_forcelist=[500, 502, 503, 504],
61
+ allowed_methods=frozenset({"GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"}),
62
+ raise_on_status=False
63
+ )
64
+ adapter = HTTPAdapter(max_retries=retries)
65
+ http_session.mount("http://", adapter)
66
+ http_session.mount("https://", adapter)
67
+ http_session.headers.update({"Connection": "keep-alive"})
68
+ return http_session
69
+
70
+ def request(
71
+ self,
72
+ endpoint: str,
73
+ payload: Dict[str, Any] | None = None,
74
+ headers: Dict[str, str] | None = None,
75
+ path_params: Dict[str, str] | None = None,
76
+ query_params: Dict[str, str] | None = None,
77
+ ) -> requests.Response:
78
+ """
79
+ Send a request to the service endpoint.
80
+ """
81
+ url, method = self._prepare_url(endpoint, path_params, query_params)
82
+ request_headers = self._prepare_headers(headers)
83
+ return self.http_session.request(method, url, json=payload, headers=request_headers)
84
+
85
+ def _prepare_url(self, endpoint: str, path_params: Dict[str, str] | None = None, query_params: Dict[str, str] | None = None) -> Tuple[str, str]:
86
+ try:
87
+ ep = self.endpoints[endpoint]
88
+ except KeyError:
89
+ raise ValueError(f"Invalid endpoint: {endpoint}. Available endpoints: {list(self.endpoints.keys())}")
90
+ url = f"{self.service_endpoint}{ep.endpoint}"
91
+ if path_params:
92
+ escaped_path_params = {k: quote(v, safe='') for k, v in path_params.items()}
93
+ url = url.format(**escaped_path_params)
94
+ if query_params:
95
+ url += '?' + urlencode(query_params)
96
+ return url, ep.method
97
+
98
+ def _prepare_headers(self, headers: Dict[str, str] | None) -> Dict[str, str]:
99
+ request_headers = {}
100
+ if headers:
101
+ request_headers.update(headers)
102
+ # Authorization tokens are not needed in a snowflake notebook environment
103
+ if not self._is_snowflake_notebook:
104
+ request_headers["Authorization"] = f'Snowflake Token="{self._token_handler.get_ingress_token(self.service_endpoint)}"'
105
+ # needed for oauth, does no harm for other authentication methods
106
+ request_headers["X-SF-SPCS-Authentication-Method"] = 'OAUTH'
107
+ request_headers["Content-Type"] = 'application/x-www-form-urlencoded'
108
+ request_headers["Accept"] = "application/json"
109
+
110
+ request_headers["user-agent"] = get_pyrel_version(self.generation)
111
+ request_headers["pyrel_program_id"] = debugging.get_program_span_id() or ""
112
+
113
+ return debugging.add_current_propagation_headers(request_headers)