analytic-workspace-client 1.29.1__tar.gz → 1.29.3__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.
Files changed (47) hide show
  1. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/PKG-INFO +4 -1
  2. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/setup.py +2 -2
  3. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/analytic_workspace_client.egg-info/PKG-INFO +4 -1
  4. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/analytic_workspace_client.egg-info/requires.txt +3 -3
  5. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/data_master/base.py +2 -2
  6. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/data_master/v2.py +1 -1
  7. analytic_workspace_client-1.29.3/src/aw_client/etl_blocks/__init__.py +9 -0
  8. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/etl_blocks/dto.py +1 -1
  9. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/etl_blocks/runtime.py +145 -11
  10. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/model_dev/runner.py +3 -2
  11. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/models/model_schema.py +11 -1
  12. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_etl/etl_blocks.py +8 -2
  13. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_etl/models.py +4 -0
  14. analytic_workspace_client-1.29.1/src/aw_client/etl_blocks/__init__.py +0 -4
  15. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/README.md +0 -0
  16. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/pyproject.toml +0 -0
  17. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/setup.cfg +0 -0
  18. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/analytic_workspace_client.egg-info/SOURCES.txt +0 -0
  19. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/analytic_workspace_client.egg-info/dependency_links.txt +0 -0
  20. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/analytic_workspace_client.egg-info/top_level.txt +0 -0
  21. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/__init__.py +0 -0
  22. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/cache.py +0 -0
  23. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/core/__init__.py +0 -0
  24. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/core/bundle.py +0 -0
  25. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/core/compiler.py +0 -0
  26. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/core/model_vault.py +0 -0
  27. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/core/spark.py +0 -0
  28. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/data_master/__init__.py +0 -0
  29. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/data_master/v0.py +0 -0
  30. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/data_master/v1.py +0 -0
  31. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/domain.py +0 -0
  32. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/etl_blocks/application.py +0 -0
  33. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/etl_blocks/services.py +0 -0
  34. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/etl_blocks/test_data.py +0 -0
  35. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/etl_blocks/tools.py +0 -0
  36. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/exceptions.py +0 -0
  37. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/ml/__init__.py +0 -0
  38. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/ml/mlflow_wrapper.py +0 -0
  39. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/model_dev/__init__.py +0 -0
  40. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/model_dev/application.py +0 -0
  41. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/model_dev/cache.py +0 -0
  42. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/model_dev/virtual_objects.py +0 -0
  43. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/models/__init__.py +0 -0
  44. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/session.py +0 -0
  45. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_client/tools.py +0 -0
  46. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_etl/__init__.py +0 -0
  47. {analytic_workspace_client-1.29.1 → analytic_workspace_client-1.29.3}/src/aw_etl/compiler.py +0 -0
@@ -1,10 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: analytic_workspace_client
3
- Version: 1.29.1
3
+ Version: 1.29.3
4
4
  Summary: Библиотека для подключения к Analytic Workspace
5
5
  Home-page: https://analyticworkspace.ru/
6
6
  Author: Analytic Workspace
7
7
  Author-email: aw_help@analyticworkspace.ru
8
+ License: UNKNOWN
9
+ Platform: UNKNOWN
8
10
  Classifier: Programming Language :: Python :: 3
9
11
  Classifier: License :: OSI Approved :: MIT License
10
12
  Classifier: Operating System :: OS Independent
@@ -39,3 +41,4 @@ df = session.load(model_id=123) # df: pandas.DataFrame
39
41
 
40
42
  display(df)
41
43
  ```
44
+
@@ -10,7 +10,7 @@ long_description = (here / "README.md").read_text(encoding="utf-8")
10
10
 
11
11
  setup(
12
12
  name='analytic_workspace_client',
13
- version='1.29.1',
13
+ version='1.29.3',
14
14
 
15
15
  description='Библиотека для подключения к Analytic Workspace',
16
16
  long_description=long_description,
@@ -36,7 +36,7 @@ setup(
36
36
  'python-dotenv>=1.0,<1.1',
37
37
  'httpx>=0.25,<1.0',
38
38
  'pandas',
39
- 'pydantic>=1.10,<2.0',
39
+ 'pydantic>=2.0',
40
40
  'colorama>=0.4,<0.5'
41
41
  ],
42
42
 
@@ -1,10 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: analytic-workspace-client
3
- Version: 1.29.1
3
+ Version: 1.29.3
4
4
  Summary: Библиотека для подключения к Analytic Workspace
5
5
  Home-page: https://analyticworkspace.ru/
6
6
  Author: Analytic Workspace
7
7
  Author-email: aw_help@analyticworkspace.ru
8
+ License: UNKNOWN
9
+ Platform: UNKNOWN
8
10
  Classifier: Programming Language :: Python :: 3
9
11
  Classifier: License :: OSI Approved :: MIT License
10
12
  Classifier: Operating System :: OS Independent
@@ -39,3 +41,4 @@ df = session.load(model_id=123) # df: pandas.DataFrame
39
41
 
40
42
  display(df)
41
43
  ```
44
+
@@ -1,8 +1,8 @@
1
- python-dotenv<1.1,>=1.0
1
+ colorama<0.5,>=0.4
2
2
  httpx<1.0,>=0.25
3
3
  pandas
4
- pydantic<2.0,>=1.10
5
- colorama<0.5,>=0.4
4
+ pydantic>=2.0
5
+ python-dotenv<1.1,>=1.0
6
6
 
7
7
  [dev]
8
8
  pyspark==3.5.0
@@ -1,4 +1,4 @@
1
- from typing import Optional
1
+ from typing import Optional, Iterator
2
2
 
3
3
  import abc
4
4
  from pathlib import Path
@@ -38,7 +38,7 @@ class DataMasterApi(metaclass=abc.ABCMeta):
38
38
  """ """
39
39
 
40
40
  @contextmanager
41
- def get_http_client(self) -> httpx.Client:
41
+ def get_http_client(self) -> Iterator[httpx.Client]:
42
42
  """ """
43
43
  if not self.api_config.aw_url:
44
44
  raise DataMasterApi.MisconfiguredError('Не указан URL к Analytic Workspace')
@@ -34,7 +34,7 @@ class DataMasterV2(DataMasterApi):
34
34
  raise AwModelForbidden(f'Доступ к модели {model_id} запрещен')
35
35
  raise Exception(f'Ошибка запроса схемы модели HTTP {r.status_code} GET {r.url}: {r.text}')
36
36
 
37
- return ModelSchema.parse_obj(r.json())
37
+ return ModelSchema.model_validate(r.json())
38
38
 
39
39
  def load_model_object_data(self, folder: Path, model_id: int, model_object_name: str, limit: Optional[int]):
40
40
  """ """
@@ -0,0 +1,9 @@
1
+ from .runtime import (
2
+ get_etl_block_schema,
3
+ get_etl_block_data,
4
+ get_etl_block_meta,
5
+ run_block_action
6
+ )
7
+ from .test_data import ModelObjectTestData
8
+
9
+
@@ -3,7 +3,7 @@ from typing import Optional, Any, List, Union
3
3
  import datetime
4
4
  from enum import Enum
5
5
 
6
- from pydantic import BaseModel
6
+ from pydantic import BaseModel, ConfigDict
7
7
 
8
8
 
9
9
  class ETLBlockParamType(str, Enum):
@@ -9,6 +9,7 @@ from aw_client.core.model_vault import Vault
9
9
  from aw_client.core.spark import build_spark_session
10
10
  from aw_client.core.bundle import NamedObjectsBundle
11
11
  from aw_client.models.model_schema import ModelObject, ModelObjectField
12
+ from aw_etl.etl_blocks import ETLBlockActionResult
12
13
  from .application import ETLBlockApplication
13
14
  from .test_data import ModelObjectTestData
14
15
  from .tools import build_dataframe, build_model_object, build_spark_schema
@@ -32,7 +33,7 @@ def get_etl_block_meta(block_path: Path) -> ETLBlockMeta:
32
33
  raise Exception(f'Файл с метаданным блока не найден: {block_meta_path}')
33
34
 
34
35
  with open(block_meta_path, 'rt') as f:
35
- return ETLBlockMeta.parse_raw(f.read())
36
+ return ETLBlockMeta.model_validate_json(f.read())
36
37
 
37
38
 
38
39
  def get_etl_block_schema(block_path: Path,
@@ -98,6 +99,8 @@ def get_etl_block_schema(block_path: Path,
98
99
  model_module=model_module
99
100
  )
100
101
 
102
+ child_objects_data = (test_data if isinstance(test_data, list) else [test_data]) if test_data is not None else None
103
+
101
104
  # Определение параметров для передачи
102
105
  block_schema_kwargs = {}
103
106
  if 'params' in block_schema_parameters:
@@ -105,7 +108,14 @@ def get_etl_block_schema(block_path: Path,
105
108
  if 'app' in block_schema_parameters:
106
109
  block_schema_kwargs['app'] = app
107
110
  if 'model_object' in block_schema_parameters:
108
- block_schema_kwargs['model_object'] = build_model_object(test_data[0] if isinstance(test_data, list) else test_data)
111
+ model_object = ModelObject(
112
+ name='obj',
113
+ model_name='obj',
114
+ type='etl_block',
115
+ fields=[],
116
+ childs=[build_model_object(o) for o in child_objects_data]
117
+ )
118
+ block_schema_kwargs['model_object'] = model_object
109
119
  if 'schema' in block_schema_parameters:
110
120
  block_schema_kwargs['schema'] = upstream_schemas.first()
111
121
  if 'schemas' in block_schema_parameters:
@@ -181,22 +191,146 @@ def get_etl_block_data(block_path: Path,
181
191
  model_module=model_module
182
192
  )
183
193
 
194
+ child_objects_data = (test_data if isinstance(test_data, list) else [test_data]) if test_data is not None else None
195
+
184
196
  # Определение параметров для передачи
185
- block_schema_kwargs = {}
197
+ block_data_kwargs = {}
186
198
  if 'params' in block_data_parameters:
187
- block_schema_kwargs['params'] = params
199
+ block_data_kwargs['params'] = params
188
200
  if 'app' in block_data_parameters:
189
- block_schema_kwargs['app'] = app
201
+ block_data_kwargs['app'] = app
190
202
  if 'model_object' in block_data_parameters:
191
- block_schema_kwargs['model_object'] = build_model_object(test_data[0] if isinstance(test_data, list) else test_data)
203
+ model_object = ModelObject(
204
+ name='obj',
205
+ model_name='obj',
206
+ type='etl_block',
207
+ fields=[],
208
+ childs=[build_model_object(o) for o in child_objects_data]
209
+ )
210
+ block_data_kwargs['model_object'] = model_object
192
211
  if 'df' in block_data_parameters:
193
- block_schema_kwargs['df'] = upstream_dataframes.first()
212
+ block_data_kwargs['df'] = upstream_dataframes.first()
194
213
  if 'dfs' in block_data_parameters:
195
- block_schema_kwargs['dfs'] = upstream_dataframes
214
+ block_data_kwargs['dfs'] = upstream_dataframes
196
215
  if 'upstream_dataframe' in block_data_parameters:
197
- block_schema_kwargs['upstream_dataframe'] = upstream_dataframes.first()
216
+ block_data_kwargs['upstream_dataframe'] = upstream_dataframes.first()
198
217
  if 'upstream_dataframes' in block_data_parameters:
199
- block_schema_kwargs['upstream_dataframes'] = upstream_dataframes
218
+ block_data_kwargs['upstream_dataframes'] = upstream_dataframes
219
+
220
+ return block_module['block_data'](**block_data_kwargs)
200
221
 
201
- return block_module['block_data'](**block_schema_kwargs)
222
+
223
+ def run_block_action(
224
+ block_path: Path,
225
+ action_name: str,
226
+ test_data: Union[ModelObjectTestData, List[ModelObjectTestData]],
227
+ params: Optional[Dict] = None,
228
+ run_mode: Optional[Literal['']] = None,
229
+ vault: Optional[Vault] = None,
230
+ model_script_code: Optional[str] = None
231
+ ) -> ETLBlockActionResult:
232
+ """
233
+ Выполняет действие etl-блока
234
+
235
+ Args:
236
+ -------------------------------------------------------
237
+ block_path : Path
238
+ Путь к исходным текстам блока
239
+ """
240
+ block_code_path = block_path / 'block_code.py' if block_path.is_dir() else block_path
241
+
242
+ if not block_code_path.exists():
243
+ raise Exception(f'Файл с исходным кодом блока не найден: {block_code_path}')
202
244
 
245
+ with open(block_code_path, 'rt') as f:
246
+ block_code = f.read()
247
+
248
+ # Компиляция кода блока
249
+ try:
250
+ block_module = ScriptCompiler().compile(source_code=block_code, mode=ScriptCompiler.MODE_ETL_BLOCK)
251
+ except ScriptCompiler.CannotCompile as e:
252
+ raise Exception(f'Ошибка компиляции исходного кода блока: {e}')
253
+
254
+ # Проверяем, что функция для запуска действия объявлена в модуле блока
255
+ block_action_function_name = f'block_action_{action_name}'
256
+ if not block_action_function_name in block_module:
257
+ raise Exception(f'Функция для обработки действия {block_action_function_name} '
258
+ 'не найдена в исходном коде блока')
259
+
260
+ # Компиляция кода модели
261
+ if model_script_code:
262
+ try:
263
+ model_module = ScriptCompiler().compile(source_code=model_script_code, mode=ScriptCompiler.MODE_ETL)
264
+ except ScriptCompiler.CannotCompile as e:
265
+ raise Exception(f'Ошибка компиляции исходного кода скрипта модели: {e}')
266
+ else:
267
+ model_module = None
268
+
269
+ spark = build_spark_session()
270
+
271
+ # Дочерние схемы
272
+ schemas = OrderedDict()
273
+ for td in (test_data if isinstance(test_data, list) else [test_data]):
274
+ schema = build_spark_schema(td)
275
+ if not schemas:
276
+ schemas['child'] = schema
277
+ schemas[td.model_name] = schema
278
+
279
+ upstream_schemas = NamedObjectsBundle(schemas)
280
+
281
+ # Дочерние датафреймы
282
+ dataframes = OrderedDict()
283
+ for td in (test_data if isinstance(test_data, list) else [test_data]):
284
+ df = build_dataframe(spark, td)
285
+ if not dataframes:
286
+ dataframes['child'] = df
287
+ dataframes[td.model_name] = df
288
+
289
+ upstream_dataframes = NamedObjectsBundle(dataframes)
290
+
291
+ block_action_parameters = inspect.signature(block_module[block_action_function_name]).parameters
292
+
293
+ app = ETLBlockApplication(
294
+ spark_builder=build_spark_session,
295
+ run_mode=run_mode or 'full',
296
+ vault=vault or Vault(),
297
+ model_module=model_module
298
+ )
299
+
300
+ child_objects_data = (test_data if isinstance(test_data, list) else [test_data]) if test_data is not None else None
301
+
302
+ block_action_kwargs = {}
303
+ if 'params' in block_action_parameters:
304
+ block_action_kwargs['params'] = params
305
+ if 'app' in block_action_parameters:
306
+ block_action_kwargs['app'] = app
307
+ if 'model_object' in block_action_parameters:
308
+ model_object = ModelObject(
309
+ name='obj',
310
+ model_name='obj',
311
+ type='etl_block',
312
+ fields=[],
313
+ childs=[build_model_object(o) for o in child_objects_data]
314
+ )
315
+ block_action_kwargs['model_object'] = model_object
316
+ if 'schema' in block_action_parameters:
317
+ block_action_kwargs['schema'] = upstream_schemas.first()
318
+ if 'schemas' in block_action_parameters:
319
+ block_action_kwargs['schemas'] = upstream_schemas
320
+ if 'upstream_schema' in block_action_parameters:
321
+ block_action_kwargs['upstream_schema'] = upstream_schemas.first()
322
+ if 'upstream_schemas' in block_action_parameters:
323
+ block_action_kwargs['upstream_schemas'] = upstream_schemas
324
+ if 'df' in block_action_parameters:
325
+ block_action_kwargs['df'] = upstream_dataframes.first()
326
+ if 'dfs' in block_action_parameters:
327
+ block_action_kwargs['dfs'] = upstream_dataframes
328
+ if 'upstream_dataframe' in block_action_parameters:
329
+ block_action_kwargs['upstream_dataframe'] = upstream_dataframes.first()
330
+ if 'upstream_dataframes' in block_action_parameters:
331
+ block_action_kwargs['upstream_dataframes'] = upstream_dataframes
332
+
333
+ return block_module[block_action_function_name](**block_action_kwargs)
334
+
335
+
336
+
@@ -150,7 +150,8 @@ if __name__ == '__main__':
150
150
  if cache.model_schema_path().exists() and not args.no_cache:
151
151
  print(Fore.YELLOW + f'Не удалось получить схему модели {model_id}: {e}. '
152
152
  f'Для запуска скрипта используется схема модели из кеша.' + Fore.RESET)
153
- model_schema = ModelSchema.parse_file(cache.model_schema_path())
153
+ with open(cache.model_schema_path(), 'rt') as f:
154
+ model_schema = ModelSchema.model_validate_json(f.read())
154
155
  else:
155
156
  print(Fore.RED + f'ОШИБКА: Не удалось получить схему модели {model_id}: {e}' + Fore.RESET)
156
157
  sys.exit(1)
@@ -162,7 +163,7 @@ if __name__ == '__main__':
162
163
  cache_folder = cache.get_model_folder()
163
164
  os.makedirs(cache_folder, exist_ok=True)
164
165
  with open(cache.model_schema_path(), 'wt') as f:
165
- f.write(model_schema.json(ensure_ascii=False, indent=2))
166
+ f.write(model_schema.model_dump_json(indent=2))
166
167
 
167
168
  # ------------------------------------------------------------------------------
168
169
  # Загрузка данных объектов модели
@@ -1,6 +1,6 @@
1
1
  from typing import Optional, List, Dict
2
2
 
3
- from pydantic import BaseModel
3
+ from pydantic import BaseModel, ConfigDict
4
4
 
5
5
 
6
6
  class ModelObjectField(BaseModel):
@@ -9,6 +9,10 @@ class ModelObjectField(BaseModel):
9
9
  model_name: str
10
10
  simple_type: str
11
11
 
12
+ model_config = ConfigDict(
13
+ protected_namespaces=()
14
+ )
15
+
12
16
 
13
17
  class ModelObject(BaseModel):
14
18
  """ """
@@ -18,6 +22,12 @@ class ModelObject(BaseModel):
18
22
  sql_text: Optional[str] = None
19
23
  fields: List[ModelObjectField] = []
20
24
 
25
+ childs: List['ModelObject'] = []
26
+
27
+ model_config = ConfigDict(
28
+ protected_namespaces=()
29
+ )
30
+
21
31
 
22
32
  class ModelSql(BaseModel):
23
33
  """
@@ -1,4 +1,6 @@
1
- from typing import Protocol, Optional
1
+ from typing import Protocol, Optional, Dict, Any
2
+
3
+ from pydantic import BaseModel
2
4
 
3
5
  try:
4
6
  from pyspark.sql import SparkSession
@@ -36,4 +38,8 @@ class ETLBlockApplication(Protocol):
36
38
  def run_mode(self) -> str:
37
39
  """ """
38
40
 
39
-
41
+ class ETLBlockActionResult(BaseModel):
42
+ """
43
+ Результат выполнения экшена блока
44
+ """
45
+ params_patch: Dict[str, Any]
@@ -14,6 +14,10 @@ class ModelObject(Protocol):
14
14
  def fields(self) -> List[ModelObjectField]:
15
15
  """ """
16
16
 
17
+ @property
18
+ def childs(self) -> List['ModelObject']:
19
+ """ """
20
+
17
21
 
18
22
  class Vault(Protocol):
19
23
  """ """
@@ -1,4 +0,0 @@
1
- from .runtime import get_etl_block_schema, get_etl_block_data, get_etl_block_meta
2
- from .test_data import ModelObjectTestData
3
-
4
-