moose-lib 0.6.6__tar.gz → 0.6.8__tar.gz
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.
Potentially problematic release.
This version of moose-lib might be problematic. Click here for more details.
- {moose_lib-0.6.6 → moose_lib-0.6.8}/PKG-INFO +1 -1
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2/__init__.py +8 -8
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2/_registry.py +2 -2
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2/consumption.py +27 -27
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2/registry.py +9 -9
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/internal.py +10 -10
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/main.py +1 -1
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/query_param.py +1 -1
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib.egg-info/PKG-INFO +1 -1
- {moose_lib-0.6.6 → moose_lib-0.6.8}/README.md +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/__init__.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/blocks.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/clients/__init__.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/clients/redis_client.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/commons.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/config/__init__.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/config/config_file.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/config/runtime.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/data_models.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2/ingest_api.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2/ingest_pipeline.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2/life_cycle.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2/materialized_view.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2/olap_table.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2/sql_resource.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2/stream.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2/types.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2/view.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2/workflow.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/dmv2-serializer.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/streaming/__init__.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/streaming/streaming_function_runner.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib/tasks.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib.egg-info/SOURCES.txt +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib.egg-info/dependency_links.txt +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib.egg-info/requires.txt +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/moose_lib.egg-info/top_level.txt +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/setup.cfg +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/setup.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/tests/__init__.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/tests/conftest.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/tests/test_moose.py +0 -0
- {moose_lib-0.6.6 → moose_lib-0.6.8}/tests/test_redis_client.py +0 -0
|
@@ -42,8 +42,8 @@ from .ingest_pipeline import (
|
|
|
42
42
|
)
|
|
43
43
|
|
|
44
44
|
from .consumption import (
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
ApiConfig,
|
|
46
|
+
Api,
|
|
47
47
|
get_moose_base_url,
|
|
48
48
|
set_moose_base_url,
|
|
49
49
|
)
|
|
@@ -79,8 +79,8 @@ from .registry import (
|
|
|
79
79
|
get_stream,
|
|
80
80
|
get_ingest_apis,
|
|
81
81
|
get_ingest_api,
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
get_apis,
|
|
83
|
+
get_api,
|
|
84
84
|
get_sql_resources,
|
|
85
85
|
get_sql_resource,
|
|
86
86
|
get_workflows,
|
|
@@ -119,8 +119,8 @@ __all__ = [
|
|
|
119
119
|
'IngestPipeline',
|
|
120
120
|
|
|
121
121
|
# Consumption
|
|
122
|
-
'
|
|
123
|
-
'
|
|
122
|
+
'ApiConfig',
|
|
123
|
+
'Api',
|
|
124
124
|
'get_moose_base_url',
|
|
125
125
|
'set_moose_base_url',
|
|
126
126
|
|
|
@@ -146,8 +146,8 @@ __all__ = [
|
|
|
146
146
|
'get_stream',
|
|
147
147
|
'get_ingest_apis',
|
|
148
148
|
'get_ingest_api',
|
|
149
|
-
'
|
|
150
|
-
'
|
|
149
|
+
'get_apis',
|
|
150
|
+
'get_api',
|
|
151
151
|
'get_sql_resources',
|
|
152
152
|
'get_sql_resource',
|
|
153
153
|
'get_workflows',
|
|
@@ -10,8 +10,8 @@ from typing import Dict, Any
|
|
|
10
10
|
_tables: Dict[str, Any] = {}
|
|
11
11
|
_streams: Dict[str, Any] = {}
|
|
12
12
|
_ingest_apis: Dict[str, Any] = {}
|
|
13
|
-
|
|
13
|
+
_apis: Dict[str, Any] = {}
|
|
14
14
|
# Alias map for O(1) fallback of sole versioned APIs: base name -> handler
|
|
15
|
-
|
|
15
|
+
_api_name_aliases: Dict[str, Any] = {}
|
|
16
16
|
_sql_resources: Dict[str, Any] = {}
|
|
17
17
|
_workflows: Dict[str, Any] = {}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
API definitions for Moose Data Model v2 (dmv2).
|
|
3
3
|
|
|
4
|
-
This module provides classes for defining and configuring
|
|
4
|
+
This module provides classes for defining and configuring APIs
|
|
5
5
|
that allow querying data through user-defined functions.
|
|
6
6
|
"""
|
|
7
7
|
import os
|
|
@@ -12,7 +12,7 @@ from pydantic import BaseModel
|
|
|
12
12
|
from pydantic.json_schema import JsonSchemaValue
|
|
13
13
|
|
|
14
14
|
from .types import BaseTypedResource, T, U
|
|
15
|
-
from ._registry import
|
|
15
|
+
from ._registry import _apis, _api_name_aliases
|
|
16
16
|
|
|
17
17
|
# Global base URL configuration
|
|
18
18
|
_global_base_url: Optional[str] = None
|
|
@@ -22,7 +22,7 @@ def _generate_api_key(name: str, version: Optional[str] = None) -> str:
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def set_moose_base_url(url: str) -> None:
|
|
25
|
-
"""Set the global base URL for
|
|
25
|
+
"""Set the global base URL for API calls.
|
|
26
26
|
|
|
27
27
|
Args:
|
|
28
28
|
url: The base URL to use for API calls
|
|
@@ -43,40 +43,40 @@ def get_moose_base_url() -> Optional[str]:
|
|
|
43
43
|
return os.getenv('MOOSE_BASE_URL')
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
class
|
|
47
|
-
"""Configuration for
|
|
46
|
+
class ApiConfig(BaseModel):
|
|
47
|
+
"""Configuration for APIs.
|
|
48
48
|
|
|
49
49
|
Attributes:
|
|
50
50
|
version: Optional version string.
|
|
51
|
-
metadata: Optional metadata for the
|
|
51
|
+
metadata: Optional metadata for the API.
|
|
52
52
|
"""
|
|
53
53
|
version: Optional[str] = None
|
|
54
54
|
metadata: Optional[dict] = None
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
class
|
|
58
|
-
"""Represents a
|
|
57
|
+
class Api(BaseTypedResource, Generic[U]):
|
|
58
|
+
"""Represents a API endpoint.
|
|
59
59
|
|
|
60
60
|
Allows querying data, typically powered by a user-defined function.
|
|
61
61
|
Requires two Pydantic models: `T` for query parameters and `U` for the response body.
|
|
62
62
|
|
|
63
63
|
Args:
|
|
64
|
-
name: The name of the
|
|
64
|
+
name: The name of the API endpoint.
|
|
65
65
|
query_function: The callable that executes the query logic.
|
|
66
66
|
It receives parameters matching model `T` (and potentially
|
|
67
67
|
other runtime utilities) and should return data matching model `U`.
|
|
68
68
|
config: Optional configuration (currently only `version`).
|
|
69
69
|
t: A tuple containing the input (`T`) and output (`U`) Pydantic models
|
|
70
|
-
(passed via `
|
|
70
|
+
(passed via `Api[InputModel, OutputModel](...)`).
|
|
71
71
|
|
|
72
72
|
Attributes:
|
|
73
|
-
config (
|
|
73
|
+
config (ApiConfig): Configuration for the API.
|
|
74
74
|
query_function (Callable[..., U]): The handler function for the API.
|
|
75
75
|
name (str): The name of the API.
|
|
76
76
|
model_type (type[T]): The Pydantic model for the input/query parameters.
|
|
77
77
|
return_type (type[U]): The Pydantic model for the response body.
|
|
78
78
|
"""
|
|
79
|
-
config:
|
|
79
|
+
config: ApiConfig
|
|
80
80
|
query_function: Callable[..., U]
|
|
81
81
|
_u: type[U]
|
|
82
82
|
|
|
@@ -91,7 +91,7 @@ class ConsumptionApi(BaseTypedResource, Generic[U]):
|
|
|
91
91
|
|
|
92
92
|
return curried_constructor
|
|
93
93
|
|
|
94
|
-
def __init__(self, name: str, query_function: Callable[..., U], config:
|
|
94
|
+
def __init__(self, name: str, query_function: Callable[..., U], config: ApiConfig = None, version: str = None, **kwargs):
|
|
95
95
|
super().__init__()
|
|
96
96
|
self._set_type(name, self._get_type(kwargs))
|
|
97
97
|
|
|
@@ -100,7 +100,7 @@ class ConsumptionApi(BaseTypedResource, Generic[U]):
|
|
|
100
100
|
# If config is provided, use it as base
|
|
101
101
|
if version is not None:
|
|
102
102
|
# If version is also provided, update the config's version
|
|
103
|
-
self.config =
|
|
103
|
+
self.config = ApiConfig(
|
|
104
104
|
version=version,
|
|
105
105
|
metadata=config.metadata
|
|
106
106
|
)
|
|
@@ -109,28 +109,28 @@ class ConsumptionApi(BaseTypedResource, Generic[U]):
|
|
|
109
109
|
self.config = config
|
|
110
110
|
elif version is not None:
|
|
111
111
|
# Only version provided, create new config with version
|
|
112
|
-
self.config =
|
|
112
|
+
self.config = ApiConfig(version=version)
|
|
113
113
|
else:
|
|
114
114
|
# Neither provided, use default config
|
|
115
|
-
self.config =
|
|
115
|
+
self.config = ApiConfig()
|
|
116
116
|
|
|
117
117
|
self.query_function = query_function
|
|
118
118
|
self.metadata = getattr(self.config, 'metadata', {}) or {}
|
|
119
119
|
key = _generate_api_key(name, self.config.version)
|
|
120
|
-
|
|
120
|
+
_apis[key] = self
|
|
121
121
|
|
|
122
122
|
# Maintain alias for base name:
|
|
123
123
|
# - If explicit unversioned registered, alias -> that
|
|
124
124
|
# - Else, if exactly one versioned exists, alias -> that
|
|
125
125
|
base = name
|
|
126
126
|
if self.config.version is None:
|
|
127
|
-
|
|
127
|
+
_api_name_aliases[base] = self
|
|
128
128
|
return
|
|
129
129
|
|
|
130
130
|
# Versioned registration: only adjust alias if no explicit unversioned exists
|
|
131
|
-
if base in
|
|
131
|
+
if base in _apis:
|
|
132
132
|
# Explicit unversioned present, ensure alias points to it
|
|
133
|
-
|
|
133
|
+
_api_name_aliases[base] = _apis[base]
|
|
134
134
|
return
|
|
135
135
|
|
|
136
136
|
# Determine if there is exactly one versioned API
|
|
@@ -138,16 +138,16 @@ class ConsumptionApi(BaseTypedResource, Generic[U]):
|
|
|
138
138
|
# Early exit on 2 matches to avoid O(n) counting
|
|
139
139
|
match_count = 0
|
|
140
140
|
sole = None
|
|
141
|
-
for k in
|
|
141
|
+
for k in _apis.keys():
|
|
142
142
|
if k.startswith(prefix):
|
|
143
143
|
match_count += 1
|
|
144
|
-
sole =
|
|
144
|
+
sole = _apis[k]
|
|
145
145
|
if match_count > 1:
|
|
146
146
|
break
|
|
147
147
|
if match_count == 1 and sole is not None:
|
|
148
|
-
|
|
148
|
+
_api_name_aliases[base] = sole
|
|
149
149
|
else:
|
|
150
|
-
|
|
150
|
+
_api_name_aliases.pop(base, None)
|
|
151
151
|
|
|
152
152
|
@classmethod
|
|
153
153
|
def _get_type(cls, keyword_args: dict):
|
|
@@ -184,7 +184,7 @@ class ConsumptionApi(BaseTypedResource, Generic[U]):
|
|
|
184
184
|
)
|
|
185
185
|
|
|
186
186
|
def call(self, params: T, base_url: Optional[str] = None) -> U:
|
|
187
|
-
"""Call the
|
|
187
|
+
"""Call the API with the given parameters.
|
|
188
188
|
|
|
189
189
|
Args:
|
|
190
190
|
params: Parameters matching the input model T
|
|
@@ -206,7 +206,7 @@ class ConsumptionApi(BaseTypedResource, Generic[U]):
|
|
|
206
206
|
)
|
|
207
207
|
|
|
208
208
|
# Construct the API endpoint URL
|
|
209
|
-
url = f"{effective_base_url.rstrip('/')}/
|
|
209
|
+
url = f"{effective_base_url.rstrip('/')}/api/{self.name}"
|
|
210
210
|
|
|
211
211
|
# Convert Pydantic model to dictionary
|
|
212
212
|
params_dict = params.model_dump()
|
|
@@ -8,17 +8,17 @@ from typing import Optional, Dict
|
|
|
8
8
|
from .olap_table import OlapTable
|
|
9
9
|
from .stream import Stream
|
|
10
10
|
from .ingest_api import IngestApi
|
|
11
|
-
from .consumption import
|
|
11
|
+
from .consumption import Api
|
|
12
12
|
from .sql_resource import SqlResource
|
|
13
13
|
from .workflow import Workflow
|
|
14
14
|
from ._registry import (
|
|
15
15
|
_tables,
|
|
16
16
|
_streams,
|
|
17
17
|
_ingest_apis,
|
|
18
|
-
|
|
18
|
+
_apis,
|
|
19
19
|
_sql_resources,
|
|
20
20
|
_workflows,
|
|
21
|
-
|
|
21
|
+
_api_name_aliases,
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
def get_tables() -> Dict[str, OlapTable]:
|
|
@@ -45,16 +45,16 @@ def get_ingest_api(name: str) -> Optional[IngestApi]:
|
|
|
45
45
|
"""Get a registered ingestion API by name."""
|
|
46
46
|
return _ingest_apis.get(name)
|
|
47
47
|
|
|
48
|
-
def
|
|
49
|
-
"""Get all registered
|
|
50
|
-
return
|
|
48
|
+
def get_apis() -> Dict[str, Api]:
|
|
49
|
+
"""Get all registered APIs."""
|
|
50
|
+
return _apis
|
|
51
51
|
|
|
52
|
-
def
|
|
53
|
-
"""Get a registered
|
|
52
|
+
def get_api(name: str) -> Optional[Api]:
|
|
53
|
+
"""Get a registered API by name.
|
|
54
54
|
|
|
55
55
|
Supports unversioned lookup by name via alias map when only a single versioned API exists.
|
|
56
56
|
"""
|
|
57
|
-
return
|
|
57
|
+
return _apis.get(name) or _api_name_aliases.get(name)
|
|
58
58
|
|
|
59
59
|
def get_sql_resources() -> Dict[str, SqlResource]:
|
|
60
60
|
"""Get all registered SQL resources."""
|
|
@@ -15,7 +15,7 @@ from moose_lib.dmv2 import (
|
|
|
15
15
|
get_tables,
|
|
16
16
|
get_streams,
|
|
17
17
|
get_ingest_apis,
|
|
18
|
-
|
|
18
|
+
get_apis,
|
|
19
19
|
get_sql_resources,
|
|
20
20
|
get_workflows,
|
|
21
21
|
OlapTable,
|
|
@@ -126,11 +126,11 @@ class IngestApiConfig(BaseModel):
|
|
|
126
126
|
version: Optional[str] = None
|
|
127
127
|
metadata: Optional[dict] = None
|
|
128
128
|
|
|
129
|
-
class
|
|
130
|
-
"""Internal representation of a
|
|
129
|
+
class InternalApiConfig(BaseModel):
|
|
130
|
+
"""Internal representation of a API configuration for serialization.
|
|
131
131
|
|
|
132
132
|
Attributes:
|
|
133
|
-
name: Name of the
|
|
133
|
+
name: Name of the API.
|
|
134
134
|
query_params: List of columns representing the expected query parameters.
|
|
135
135
|
response_schema: JSON schema definition of the API's response body.
|
|
136
136
|
version: Optional version string of the API configuration.
|
|
@@ -202,7 +202,7 @@ class InfrastructureMap(BaseModel):
|
|
|
202
202
|
tables: Dictionary mapping table names to their configurations.
|
|
203
203
|
topics: Dictionary mapping topic/stream names to their configurations.
|
|
204
204
|
ingest_apis: Dictionary mapping ingest API names to their configurations.
|
|
205
|
-
|
|
205
|
+
apis: Dictionary mapping API names to their configurations.
|
|
206
206
|
sql_resources: Dictionary mapping SQL resource names to their configurations.
|
|
207
207
|
workflows: Dictionary mapping workflow names to their configurations.
|
|
208
208
|
"""
|
|
@@ -211,7 +211,7 @@ class InfrastructureMap(BaseModel):
|
|
|
211
211
|
tables: dict[str, TableConfig]
|
|
212
212
|
topics: dict[str, TopicConfig]
|
|
213
213
|
ingest_apis: dict[str, IngestApiConfig]
|
|
214
|
-
|
|
214
|
+
apis: dict[str, InternalApiConfig]
|
|
215
215
|
sql_resources: dict[str, SqlResourceConfig]
|
|
216
216
|
workflows: dict[str, WorkflowJson]
|
|
217
217
|
|
|
@@ -262,7 +262,7 @@ def to_infra_map() -> dict:
|
|
|
262
262
|
tables = {}
|
|
263
263
|
topics = {}
|
|
264
264
|
ingest_apis = {}
|
|
265
|
-
|
|
265
|
+
apis = {}
|
|
266
266
|
sql_resources = {}
|
|
267
267
|
workflows = {}
|
|
268
268
|
|
|
@@ -323,8 +323,8 @@ def to_infra_map() -> dict:
|
|
|
323
323
|
dead_letter_queue=api.config.dead_letter_queue.name
|
|
324
324
|
)
|
|
325
325
|
|
|
326
|
-
for name, api in
|
|
327
|
-
|
|
326
|
+
for name, api in get_apis().items():
|
|
327
|
+
apis[name] = InternalApiConfig(
|
|
328
328
|
name=api.name,
|
|
329
329
|
query_params=_to_columns(api.model_type),
|
|
330
330
|
response_schema=api.get_response_schema(),
|
|
@@ -354,7 +354,7 @@ def to_infra_map() -> dict:
|
|
|
354
354
|
tables=tables,
|
|
355
355
|
topics=topics,
|
|
356
356
|
ingest_apis=ingest_apis,
|
|
357
|
-
|
|
357
|
+
apis=apis,
|
|
358
358
|
sql_resources=sql_resources,
|
|
359
359
|
workflows=workflows
|
|
360
360
|
)
|
|
@@ -118,7 +118,7 @@ def convert_dataclass_definition(cls: type) -> list[QueryField]:
|
|
|
118
118
|
return fields_list
|
|
119
119
|
|
|
120
120
|
|
|
121
|
-
def
|
|
121
|
+
def convert_api_param(module) -> Optional[tuple[type, list[QueryField]]]:
|
|
122
122
|
run_func = module.run
|
|
123
123
|
params_arg = inspect.getfullargspec(run_func).args[1]
|
|
124
124
|
param_class: type = run_func.__annotations__.get(params_arg)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|