ray-hive 1.0__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.
- ray_hive/__init__.py +64 -0
- ray_hive/_api.py +40 -0
- ray_hive/_capabilities.py +70 -0
- ray_hive/_compat.py +120 -0
- ray_hive/_credentials.py +140 -0
- ray_hive/_errors.py +157 -0
- ray_hive/_hs2/__init__.py +15 -0
- ray_hive/_hs2/client.py +447 -0
- ray_hive/_hs2/decoder.py +119 -0
- ray_hive/_hs2/generated/README.md +19 -0
- ray_hive/_hs2/generated/TCLIService/TCLIService-remote +285 -0
- ray_hive/_hs2/generated/TCLIService/TCLIService.py +5334 -0
- ray_hive/_hs2/generated/TCLIService/__init__.py +1 -0
- ray_hive/_hs2/generated/TCLIService/constants.py +72 -0
- ray_hive/_hs2/generated/TCLIService/ttypes.py +9014 -0
- ray_hive/_hs2/generated/__init__.py +15 -0
- ray_hive/_hs2/generated/idl/TCLIService.thrift +1350 -0
- ray_hive/_hs2/operation.py +120 -0
- ray_hive/_hs2/protocol.py +227 -0
- ray_hive/_hs2/session.py +108 -0
- ray_hive/_hs2/transport.py +275 -0
- ray_hive/_models.py +356 -0
- ray_hive/_planner.py +172 -0
- ray_hive/_schema.py +121 -0
- ray_hive/_sql.py +218 -0
- ray_hive/_task_spec.py +48 -0
- ray_hive/_telemetry.py +25 -0
- ray_hive/_worker.py +323 -0
- ray_hive/datasource.py +90 -0
- ray_hive/py.typed +1 -0
- ray_hive/sql.py +19 -0
- ray_hive-1.0.dist-info/METADATA +163 -0
- ray_hive-1.0.dist-info/RECORD +36 -0
- ray_hive-1.0.dist-info/WHEEL +4 -0
- ray_hive-1.0.dist-info/licenses/LICENSE +201 -0
- ray_hive-1.0.dist-info/licenses/NOTICE +5 -0
ray_hive/__init__.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Copyright 2026 ray-hive contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Public API for the ray-hive HiveServer2 datasource."""
|
|
16
|
+
|
|
17
|
+
from ray_hive._api import read_hive
|
|
18
|
+
from ray_hive._credentials import CredentialProvider, SecretRef
|
|
19
|
+
from ray_hive._errors import (
|
|
20
|
+
HiveAuthenticationError,
|
|
21
|
+
HiveCancellationError,
|
|
22
|
+
HiveCleanupError,
|
|
23
|
+
HiveCompatibilityError,
|
|
24
|
+
HiveConfigurationError,
|
|
25
|
+
HiveDependencyError,
|
|
26
|
+
HiveError,
|
|
27
|
+
HiveErrorCode,
|
|
28
|
+
HivePermissionError,
|
|
29
|
+
HivePlanningError,
|
|
30
|
+
HiveProtocolError,
|
|
31
|
+
HiveQueryError,
|
|
32
|
+
HiveSchemaError,
|
|
33
|
+
HiveTransportError,
|
|
34
|
+
)
|
|
35
|
+
from ray_hive._models import (
|
|
36
|
+
HiveConnectionOptions,
|
|
37
|
+
HiveReadOptions,
|
|
38
|
+
HiveTableIdentifier,
|
|
39
|
+
HiveTLSOptions,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"CredentialProvider",
|
|
44
|
+
"HiveAuthenticationError",
|
|
45
|
+
"HiveCancellationError",
|
|
46
|
+
"HiveCleanupError",
|
|
47
|
+
"HiveCompatibilityError",
|
|
48
|
+
"HiveConfigurationError",
|
|
49
|
+
"HiveConnectionOptions",
|
|
50
|
+
"HiveDependencyError",
|
|
51
|
+
"HiveError",
|
|
52
|
+
"HiveErrorCode",
|
|
53
|
+
"HivePermissionError",
|
|
54
|
+
"HivePlanningError",
|
|
55
|
+
"HiveProtocolError",
|
|
56
|
+
"HiveQueryError",
|
|
57
|
+
"HiveReadOptions",
|
|
58
|
+
"HiveSchemaError",
|
|
59
|
+
"HiveTLSOptions",
|
|
60
|
+
"HiveTableIdentifier",
|
|
61
|
+
"HiveTransportError",
|
|
62
|
+
"SecretRef",
|
|
63
|
+
"read_hive",
|
|
64
|
+
]
|
ray_hive/_api.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Copyright 2026 ray-hive contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Stable public read facade."""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from collections.abc import Mapping
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
from ray_hive._compat import read_datasource_strict
|
|
23
|
+
from ray_hive._models import HiveConnectionOptions, HiveReadOptions
|
|
24
|
+
from ray_hive.datasource import HiveServer2Datasource
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def read_hive(
|
|
28
|
+
*,
|
|
29
|
+
connection: HiveConnectionOptions,
|
|
30
|
+
read: HiveReadOptions,
|
|
31
|
+
ray_remote_args: Mapping[str, Any] | None = None,
|
|
32
|
+
) -> Any:
|
|
33
|
+
"""Plan an HS2-only read and return a lazy Ray Dataset with task retries disabled."""
|
|
34
|
+
|
|
35
|
+
datasource = HiveServer2Datasource.from_options(connection, read)
|
|
36
|
+
return read_datasource_strict(
|
|
37
|
+
datasource,
|
|
38
|
+
num_tasks=len(datasource.task_specs),
|
|
39
|
+
ray_remote_args=ray_remote_args,
|
|
40
|
+
)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Copyright 2026 ray-hive contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Fail-closed HiveServer2 capability negotiation."""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from enum import StrEnum
|
|
21
|
+
|
|
22
|
+
from ray_hive._errors import HiveCompatibilityError
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class CapabilityState(StrEnum):
|
|
26
|
+
"""Tri-state support result; unknown is never treated as supported."""
|
|
27
|
+
|
|
28
|
+
SUPPORTED = "supported"
|
|
29
|
+
UNSUPPORTED = "unsupported"
|
|
30
|
+
UNKNOWN = "unknown"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True, slots=True)
|
|
34
|
+
class CapabilityEvidence:
|
|
35
|
+
"""The origin of one capability conclusion."""
|
|
36
|
+
|
|
37
|
+
capability: str
|
|
38
|
+
state: CapabilityState
|
|
39
|
+
source: str
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass(frozen=True, slots=True)
|
|
43
|
+
class HiveCapabilities:
|
|
44
|
+
"""Immutable capabilities negotiated immediately after OpenSession."""
|
|
45
|
+
|
|
46
|
+
protocol_version: int
|
|
47
|
+
columnar_rowsets: CapabilityState
|
|
48
|
+
binary_columns: CapabilityState
|
|
49
|
+
cancel_operation: CapabilityState
|
|
50
|
+
operation_log: CapabilityState
|
|
51
|
+
evidence: tuple[CapabilityEvidence, ...] = ()
|
|
52
|
+
|
|
53
|
+
def require_core(self) -> None:
|
|
54
|
+
"""Reject a connection that cannot satisfy the Core read profile."""
|
|
55
|
+
|
|
56
|
+
if self.protocol_version < 6:
|
|
57
|
+
raise HiveCompatibilityError("HS2 protocol V6 or newer is required")
|
|
58
|
+
if self.columnar_rowsets is not CapabilityState.SUPPORTED:
|
|
59
|
+
raise HiveCompatibilityError("Native V6 columnar result sets are required")
|
|
60
|
+
if self.cancel_operation is not CapabilityState.SUPPORTED:
|
|
61
|
+
raise HiveCompatibilityError("CancelOperation capability is required")
|
|
62
|
+
|
|
63
|
+
def require(self, capability: str, state: CapabilityState) -> None:
|
|
64
|
+
"""Require an explicitly supported capability by attribute name."""
|
|
65
|
+
|
|
66
|
+
actual = getattr(self, capability, None)
|
|
67
|
+
if actual is not state:
|
|
68
|
+
raise HiveCompatibilityError(
|
|
69
|
+
f"Required capability {capability!r} is not explicitly {state.value}"
|
|
70
|
+
)
|
ray_hive/_compat.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Copyright 2026 ray-hive contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""The only module allowed to adapt Ray DeveloperAPI version differences."""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import inspect
|
|
20
|
+
from collections.abc import Callable, Iterable, Mapping
|
|
21
|
+
from importlib.metadata import version
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
import pyarrow as pa
|
|
25
|
+
|
|
26
|
+
from ray_hive._errors import HiveCompatibilityError
|
|
27
|
+
|
|
28
|
+
SUPPORTED_RAY_VERSION = "2.55.1"
|
|
29
|
+
SUPPORTED_PYARROW_VERSION = "19.0.1"
|
|
30
|
+
_READ_TASK_PARAMETERS = ("self", "read_fn", "metadata", "schema", "per_task_row_limit")
|
|
31
|
+
_GET_READ_TASKS_PARAMETERS = (
|
|
32
|
+
"self",
|
|
33
|
+
"parallelism",
|
|
34
|
+
"per_task_row_limit",
|
|
35
|
+
"data_context",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def validate_runtime() -> None:
|
|
40
|
+
"""Fail closed unless the exact tested Ray/PyArrow contracts are installed."""
|
|
41
|
+
|
|
42
|
+
if version("ray") != SUPPORTED_RAY_VERSION:
|
|
43
|
+
raise HiveCompatibilityError(
|
|
44
|
+
f"ray-hive requires Ray {SUPPORTED_RAY_VERSION} in the initial release"
|
|
45
|
+
)
|
|
46
|
+
if pa.__version__ != SUPPORTED_PYARROW_VERSION:
|
|
47
|
+
raise HiveCompatibilityError(
|
|
48
|
+
f"ray-hive requires PyArrow {SUPPORTED_PYARROW_VERSION} in the initial release"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
from ray.data import Datasource, ReadTask
|
|
52
|
+
|
|
53
|
+
read_task_parameters = tuple(inspect.signature(ReadTask.__init__).parameters)
|
|
54
|
+
if read_task_parameters != _READ_TASK_PARAMETERS:
|
|
55
|
+
raise HiveCompatibilityError("Unsupported Ray ReadTask constructor signature")
|
|
56
|
+
get_tasks_parameters = tuple(inspect.signature(Datasource.get_read_tasks).parameters)
|
|
57
|
+
if get_tasks_parameters != _GET_READ_TASKS_PARAMETERS:
|
|
58
|
+
raise HiveCompatibilityError("Unsupported Ray Datasource.get_read_tasks signature")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def initialize_datasource(instance: Any) -> None:
|
|
62
|
+
"""Invoke the exact pinned Ray Datasource initializer through the adapter boundary."""
|
|
63
|
+
|
|
64
|
+
from ray.data import Datasource
|
|
65
|
+
|
|
66
|
+
initializer: Any = Datasource.__init__
|
|
67
|
+
initializer(instance)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def create_read_task(
|
|
71
|
+
read_fn: Callable[[], Iterable[pa.Table]],
|
|
72
|
+
schema: pa.Schema,
|
|
73
|
+
*,
|
|
74
|
+
per_task_row_limit: int | None,
|
|
75
|
+
) -> Any:
|
|
76
|
+
"""Construct the exact supported DeveloperAPI ReadTask shape."""
|
|
77
|
+
|
|
78
|
+
validate_runtime()
|
|
79
|
+
from ray.data import ReadTask
|
|
80
|
+
from ray.data.block import BlockMetadata
|
|
81
|
+
|
|
82
|
+
metadata = BlockMetadata(
|
|
83
|
+
num_rows=None,
|
|
84
|
+
size_bytes=None,
|
|
85
|
+
exec_stats=None,
|
|
86
|
+
input_files=None,
|
|
87
|
+
)
|
|
88
|
+
return ReadTask(
|
|
89
|
+
read_fn,
|
|
90
|
+
metadata,
|
|
91
|
+
schema=schema,
|
|
92
|
+
per_task_row_limit=per_task_row_limit,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def read_datasource_strict(
|
|
97
|
+
datasource: Any,
|
|
98
|
+
*,
|
|
99
|
+
num_tasks: int,
|
|
100
|
+
ray_remote_args: Mapping[str, Any] | None,
|
|
101
|
+
) -> Any:
|
|
102
|
+
"""Call the public Ray facade with no retry or lineage replay of a query task."""
|
|
103
|
+
|
|
104
|
+
validate_runtime()
|
|
105
|
+
from ray.data import read_datasource
|
|
106
|
+
|
|
107
|
+
parameters = inspect.signature(read_datasource).parameters
|
|
108
|
+
required = {"datasource", "ray_remote_args", "concurrency", "override_num_blocks"}
|
|
109
|
+
if not required.issubset(parameters):
|
|
110
|
+
raise HiveCompatibilityError("Unsupported Ray read_datasource signature")
|
|
111
|
+
remote_args = dict(ray_remote_args or {})
|
|
112
|
+
if remote_args.get("max_retries", 0) != 0:
|
|
113
|
+
raise HiveCompatibilityError("Strict Hive reads require Ray max_retries=0")
|
|
114
|
+
remote_args["max_retries"] = 0
|
|
115
|
+
return read_datasource(
|
|
116
|
+
datasource,
|
|
117
|
+
ray_remote_args=remote_args,
|
|
118
|
+
concurrency=num_tasks,
|
|
119
|
+
override_num_blocks=num_tasks,
|
|
120
|
+
)
|
ray_hive/_credentials.py
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Copyright 2026 ray-hive contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Serializable secret references resolved only by trusted HS2-connecting nodes."""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import os
|
|
20
|
+
from dataclasses import dataclass, field, replace
|
|
21
|
+
from typing import Protocol, runtime_checkable
|
|
22
|
+
|
|
23
|
+
from ray_hive._errors import HiveAuthenticationError, HiveConfigurationError
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass(frozen=True, slots=True)
|
|
27
|
+
class CredentialContext:
|
|
28
|
+
"""Security boundary to which resolved credentials must be bound."""
|
|
29
|
+
|
|
30
|
+
endpoint: str
|
|
31
|
+
driver: str
|
|
32
|
+
auth: str
|
|
33
|
+
tls_server_name: str | None
|
|
34
|
+
audience: str | None = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass(frozen=True, slots=True)
|
|
38
|
+
class HiveCredentials:
|
|
39
|
+
"""Ephemeral authentication material that must never enter a task spec."""
|
|
40
|
+
|
|
41
|
+
username: str | None = None
|
|
42
|
+
password: str | None = field(default=None, repr=False)
|
|
43
|
+
token: str | None = field(default=None, repr=False)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@runtime_checkable
|
|
47
|
+
class CredentialProvider(Protocol):
|
|
48
|
+
"""A serializable strategy resolved only by a trusted HS2-connecting node."""
|
|
49
|
+
|
|
50
|
+
def bind(self, context: CredentialContext) -> CredentialProvider:
|
|
51
|
+
"""Return a provider restricted to the supplied connection context."""
|
|
52
|
+
|
|
53
|
+
def resolve(self, context: CredentialContext) -> HiveCredentials:
|
|
54
|
+
"""Resolve ephemeral authentication material for the supplied context."""
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass(frozen=True, slots=True)
|
|
58
|
+
class SecretRef:
|
|
59
|
+
"""An immutable reference to one secret value, never the value itself."""
|
|
60
|
+
|
|
61
|
+
provider: str
|
|
62
|
+
key: str
|
|
63
|
+
allowed_context: CredentialContext | None = field(default=None, repr=False)
|
|
64
|
+
|
|
65
|
+
def __post_init__(self) -> None:
|
|
66
|
+
if self.provider != "env":
|
|
67
|
+
raise HiveConfigurationError(f"Unsupported secret provider: {self.provider!r}")
|
|
68
|
+
if not self.key or "\x00" in self.key:
|
|
69
|
+
raise HiveConfigurationError(
|
|
70
|
+
"Secret reference key must be non-empty and contain no NUL"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
@classmethod
|
|
74
|
+
def env(cls, variable: str) -> SecretRef:
|
|
75
|
+
"""Create a reference resolved from the local HS2 client's environment."""
|
|
76
|
+
|
|
77
|
+
return cls(provider="env", key=variable)
|
|
78
|
+
|
|
79
|
+
def bind(self, context: CredentialContext) -> SecretRef:
|
|
80
|
+
"""Bind this reference to exactly one endpoint and authentication context."""
|
|
81
|
+
|
|
82
|
+
if self.allowed_context is not None and self.allowed_context != context:
|
|
83
|
+
raise HiveConfigurationError("Secret reference is already bound to another endpoint")
|
|
84
|
+
return replace(self, allowed_context=context)
|
|
85
|
+
|
|
86
|
+
def resolve_value(self, context: CredentialContext) -> str:
|
|
87
|
+
"""Resolve the referenced value after validating its endpoint binding."""
|
|
88
|
+
|
|
89
|
+
if self.allowed_context is None or self.allowed_context != context:
|
|
90
|
+
raise HiveAuthenticationError("Secret reference is not bound to this endpoint")
|
|
91
|
+
try:
|
|
92
|
+
return os.environ[self.key]
|
|
93
|
+
except KeyError as exc:
|
|
94
|
+
raise HiveAuthenticationError(
|
|
95
|
+
f"Required environment credential {self.key!r} is unavailable"
|
|
96
|
+
) from exc
|
|
97
|
+
|
|
98
|
+
def resolve(self, context: CredentialContext) -> HiveCredentials:
|
|
99
|
+
"""Resolve a direct secret reference as a password credential."""
|
|
100
|
+
|
|
101
|
+
return HiveCredentials(password=self.resolve_value(context))
|
|
102
|
+
|
|
103
|
+
def __repr__(self) -> str:
|
|
104
|
+
return (
|
|
105
|
+
f"SecretRef(provider={self.provider!r}, key={self.key!r}, "
|
|
106
|
+
f"bound={self.allowed_context is not None})"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@dataclass(frozen=True, slots=True)
|
|
111
|
+
class EnvironmentCredentialProvider:
|
|
112
|
+
"""Resolve optional username, password, and token environment references."""
|
|
113
|
+
|
|
114
|
+
username: str | None = None
|
|
115
|
+
password: SecretRef | None = None
|
|
116
|
+
token: SecretRef | None = None
|
|
117
|
+
allowed_context: CredentialContext | None = field(default=None, repr=False)
|
|
118
|
+
|
|
119
|
+
def bind(self, context: CredentialContext) -> EnvironmentCredentialProvider:
|
|
120
|
+
"""Bind every contained reference to one connection context."""
|
|
121
|
+
|
|
122
|
+
if self.allowed_context is not None and self.allowed_context != context:
|
|
123
|
+
raise HiveConfigurationError("Credential provider is already bound to another endpoint")
|
|
124
|
+
return replace(
|
|
125
|
+
self,
|
|
126
|
+
password=self.password.bind(context) if self.password else None,
|
|
127
|
+
token=self.token.bind(context) if self.token else None,
|
|
128
|
+
allowed_context=context,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
def resolve(self, context: CredentialContext) -> HiveCredentials:
|
|
132
|
+
"""Resolve authentication material only when the binding is exact."""
|
|
133
|
+
|
|
134
|
+
if self.allowed_context != context:
|
|
135
|
+
raise HiveAuthenticationError("Credential provider is not bound to this endpoint")
|
|
136
|
+
return HiveCredentials(
|
|
137
|
+
username=self.username,
|
|
138
|
+
password=self.password.resolve_value(context) if self.password else None,
|
|
139
|
+
token=self.token.resolve_value(context) if self.token else None,
|
|
140
|
+
)
|
ray_hive/_errors.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Copyright 2026 ray-hive contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Public, stable error contracts for ray-hive."""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from enum import StrEnum
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class HiveErrorCode(StrEnum):
|
|
23
|
+
"""Stable conformance error codes."""
|
|
24
|
+
|
|
25
|
+
CONFIG = "CONFIG"
|
|
26
|
+
AUTH = "AUTH"
|
|
27
|
+
PERMISSION = "PERMISSION"
|
|
28
|
+
QUERY_COMPILE = "QUERY_COMPILE"
|
|
29
|
+
QUERY_EXECUTION = "QUERY_EXECUTION"
|
|
30
|
+
SCHEMA = "SCHEMA"
|
|
31
|
+
PROTOCOL = "PROTOCOL"
|
|
32
|
+
TRANSPORT_BEFORE_OUTPUT = "TRANSPORT_BEFORE_OUTPUT"
|
|
33
|
+
TRANSPORT_AFTER_OUTPUT = "TRANSPORT_AFTER_OUTPUT"
|
|
34
|
+
CANCELLED = "CANCELLED"
|
|
35
|
+
CLEANUP = "CLEANUP"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class HiveError(Exception):
|
|
39
|
+
"""Base exception with stable, sanitized machine-readable attributes."""
|
|
40
|
+
|
|
41
|
+
default_error_code = HiveErrorCode.CONFIG
|
|
42
|
+
default_retryable = False
|
|
43
|
+
default_partial_output = False
|
|
44
|
+
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
safe_message: str,
|
|
48
|
+
*,
|
|
49
|
+
error_code: HiveErrorCode | None = None,
|
|
50
|
+
retryable: bool | None = None,
|
|
51
|
+
partial_output: bool | None = None,
|
|
52
|
+
operation_state: str | None = None,
|
|
53
|
+
) -> None:
|
|
54
|
+
super().__init__(safe_message)
|
|
55
|
+
self.error_code = error_code or self.default_error_code
|
|
56
|
+
self.retryable = self.default_retryable if retryable is None else retryable
|
|
57
|
+
self.partial_output = (
|
|
58
|
+
self.default_partial_output if partial_output is None else partial_output
|
|
59
|
+
)
|
|
60
|
+
self.operation_state = operation_state
|
|
61
|
+
|
|
62
|
+
def __repr__(self) -> str:
|
|
63
|
+
return (
|
|
64
|
+
f"{type(self).__name__}(error_code={self.error_code.value!r}, "
|
|
65
|
+
f"retryable={self.retryable!r}, partial_output={self.partial_output!r}, "
|
|
66
|
+
f"operation_state={self.operation_state!r})"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def mark_partial_output(self) -> HiveError:
|
|
70
|
+
"""Preserve the concrete error while recording that output was published."""
|
|
71
|
+
|
|
72
|
+
self.partial_output = True
|
|
73
|
+
self.retryable = False
|
|
74
|
+
if self.error_code is HiveErrorCode.TRANSPORT_BEFORE_OUTPUT:
|
|
75
|
+
self.error_code = HiveErrorCode.TRANSPORT_AFTER_OUTPUT
|
|
76
|
+
return self
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class HiveConfigurationError(HiveError):
|
|
80
|
+
"""Raised for invalid or insecure configuration."""
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class HiveDependencyError(HiveConfigurationError):
|
|
84
|
+
"""Raised when an explicitly selected optional dependency is unavailable."""
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class HiveAuthenticationError(HiveError):
|
|
88
|
+
"""Raised when HiveServer2 authentication fails."""
|
|
89
|
+
|
|
90
|
+
default_error_code = HiveErrorCode.AUTH
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class HivePermissionError(HiveError):
|
|
94
|
+
"""Raised when HiveServer2 rejects an authorized operation."""
|
|
95
|
+
|
|
96
|
+
default_error_code = HiveErrorCode.PERMISSION
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class HivePlanningError(HiveError):
|
|
100
|
+
"""Raised when a logical read cannot be compiled safely."""
|
|
101
|
+
|
|
102
|
+
default_error_code = HiveErrorCode.QUERY_COMPILE
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class HiveSchemaError(HiveError):
|
|
106
|
+
"""Raised for unsupported types or schema drift."""
|
|
107
|
+
|
|
108
|
+
default_error_code = HiveErrorCode.SCHEMA
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class HiveQueryError(HiveError):
|
|
112
|
+
"""Raised when an accepted Hive query fails during execution."""
|
|
113
|
+
|
|
114
|
+
default_error_code = HiveErrorCode.QUERY_EXECUTION
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class HiveProtocolError(HiveError):
|
|
118
|
+
"""Raised when the server violates the negotiated HS2 protocol."""
|
|
119
|
+
|
|
120
|
+
default_error_code = HiveErrorCode.PROTOCOL
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class HiveCompatibilityError(HiveProtocolError):
|
|
124
|
+
"""Raised when a runtime version or capability is unsupported."""
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class HiveTransportError(HiveError):
|
|
128
|
+
"""Raised when the HS2 transport fails."""
|
|
129
|
+
|
|
130
|
+
default_error_code = HiveErrorCode.TRANSPORT_BEFORE_OUTPUT
|
|
131
|
+
default_retryable = True
|
|
132
|
+
|
|
133
|
+
@classmethod
|
|
134
|
+
def after_output(
|
|
135
|
+
cls, safe_message: str, *, operation_state: str | None = None
|
|
136
|
+
) -> HiveTransportError:
|
|
137
|
+
"""Construct a non-retryable transport error after a block was published."""
|
|
138
|
+
|
|
139
|
+
return cls(
|
|
140
|
+
safe_message,
|
|
141
|
+
error_code=HiveErrorCode.TRANSPORT_AFTER_OUTPUT,
|
|
142
|
+
retryable=False,
|
|
143
|
+
partial_output=True,
|
|
144
|
+
operation_state=operation_state,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class HiveCancellationError(HiveError):
|
|
149
|
+
"""Raised when a read is cancelled."""
|
|
150
|
+
|
|
151
|
+
default_error_code = HiveErrorCode.CANCELLED
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class HiveCleanupError(HiveError):
|
|
155
|
+
"""Raised when required resource cleanup fails."""
|
|
156
|
+
|
|
157
|
+
default_error_code = HiveErrorCode.CLEANUP
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright 2026 ray-hive contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Internal HiveServer2 protocol implementation."""
|