polyapi 5.9.12__tar.gz → 5.9.13__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.
- {polyapi-5.9.12 → polyapi-5.9.13}/PKG-INFO +2 -1
- {polyapi-5.9.12 → polyapi-5.9.13}/polyapi.egg-info/PKG-INFO +2 -1
- {polyapi-5.9.12 → polyapi-5.9.13}/polyapi.egg-info/requires.txt +1 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/business_scenarios.py +65 -21
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/common/helper_funcs.py +6 -0
- polyapi-5.9.13/polymatica/common/params_models.py +76 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/error_handler.py +41 -8
- {polyapi-5.9.12 → polyapi-5.9.13}/pyproject.toml +2 -1
- {polyapi-5.9.12 → polyapi-5.9.13}/setup.py +2 -2
- polyapi-5.9.12/polymatica/common/params_models.py +0 -86
- {polyapi-5.9.12 → polyapi-5.9.13}/LICENSE.txt +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/README.txt +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polyapi.egg-info/SOURCES.txt +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polyapi.egg-info/dependency_links.txt +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polyapi.egg-info/top_level.txt +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/__init__.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/authorization.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/business_logic_doc.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/commands/__init__.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/commands/base_command.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/commands/olap_module.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/commands/other_modules.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/common/__init__.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/common/consts.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/exceptions.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/executor.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/__init__.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/base_graph.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/graph_interface.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/__init__.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/areas.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/balls.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/chord.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/circles.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/circles_series.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/corridors.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/cumulative_areas.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/cumulative_cylinders.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/cylinders.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/graph.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/lines.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/pies.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/point.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/point_series.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/pools.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/pools_3d.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/radar.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/sankey.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/graph/types/surface.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/polymatica/helper.py +0 -0
- {polyapi-5.9.12 → polyapi-5.9.13}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: polyapi
|
|
3
|
-
Version: 5.9.
|
|
3
|
+
Version: 5.9.13
|
|
4
4
|
Summary: Wrapper for Polymatica API
|
|
5
5
|
Home-page: https://www.polymatica.ru
|
|
6
6
|
Author: Polymatica Rus LLC
|
|
@@ -17,6 +17,7 @@ Requires-Dist: setuptools
|
|
|
17
17
|
Requires-Dist: pandas
|
|
18
18
|
Requires-Dist: requests
|
|
19
19
|
Requires-Dist: pydantic
|
|
20
|
+
Requires-Dist: packaging
|
|
20
21
|
|
|
21
22
|
Библиотека предназначенна для работы с Polymatica API.
|
|
22
23
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: polyapi
|
|
3
|
-
Version: 5.9.
|
|
3
|
+
Version: 5.9.13
|
|
4
4
|
Summary: Wrapper for Polymatica API
|
|
5
5
|
Home-page: https://www.polymatica.ru
|
|
6
6
|
Author: Polymatica Rus LLC
|
|
@@ -17,6 +17,7 @@ Requires-Dist: setuptools
|
|
|
17
17
|
Requires-Dist: pandas
|
|
18
18
|
Requires-Dist: requests
|
|
19
19
|
Requires-Dist: pydantic
|
|
20
|
+
Requires-Dist: packaging
|
|
20
21
|
|
|
21
22
|
Библиотека предназначенна для работы с Polymatica API.
|
|
22
23
|
|
|
@@ -1286,9 +1286,9 @@ class BusinessLogic:
|
|
|
1286
1286
|
также будет сгенерирована ошибка
|
|
1287
1287
|
5. В противном случае, если указано что-то иное - будет сгенерирована ошибка.
|
|
1288
1288
|
:filter_field_format (Union[str, None]): формат даты-времени, в котором фильтруемая размерность
|
|
1289
|
-
представлена в Полиматике.
|
|
1290
|
-
Если в актуальном случае этот параметр не указан, то будет получено системное значение из Полиматики.
|
|
1289
|
+
представлена в Полиматике. Обязателен, если в параметрах start_date и end_date указаны строки-даты.
|
|
1291
1290
|
Параметр необходим для корректной фильтрации даты-времени.
|
|
1291
|
+
Пример: filter_field_format='%d.%m.%Y %H:%M:%S.%f' или '%Y-%m-%d'.
|
|
1292
1292
|
:return: (dict) результат команды ("filter", "apply_data").
|
|
1293
1293
|
"""
|
|
1294
1294
|
# заполнение списка dates_list в зависимости от содержания параметров filter_name, start_date, end_date
|
|
@@ -3515,22 +3515,25 @@ class BusinessLogic:
|
|
|
3515
3515
|
return ids
|
|
3516
3516
|
|
|
3517
3517
|
@timing
|
|
3518
|
-
def sort_measure(self, measure_name: str, sort_type: str) -> dict:
|
|
3518
|
+
def sort_measure(self, measure_name: str, sort_type: str, path: List[str] = None) -> dict:
|
|
3519
3519
|
"""
|
|
3520
|
-
Сортировка значений указанного факта по
|
|
3521
|
-
(даже если есть верхние размерности).
|
|
3520
|
+
Сортировка значений указанного факта по возрастанию/убыванию.
|
|
3522
3521
|
Необходимым условием сортировки является наличие хотя бы одной вынесенной влево размерности.
|
|
3523
|
-
Если
|
|
3522
|
+
Если задан параметр path, то сортировка будет производиться по столбцу,
|
|
3523
|
+
путь до которого указан в этом параметре. Верхние размерности должны быть развернуты,
|
|
3524
|
+
это можно сделать командой "expand_all_up_dims".
|
|
3525
|
+
Если параметр path не задан, то сортировка будет производиться по столбцу "Всего", и вынесенные
|
|
3526
|
+
вверх размерности необходимо свернуть перед вызовом метода.
|
|
3524
3527
|
Это можно сделать командой "collap_all_up_dims".
|
|
3525
3528
|
:param measure_name: название факта.
|
|
3526
3529
|
:param sort_type: "ascending"/"descending"/"off" (по возрастанию/по убыванию/выключить сортировку).
|
|
3530
|
+
:param path: путь до столбца, содержит имена элементов верхних размерностей,
|
|
3531
|
+
пример ['Простуда и грипп', 'Гастрацид'] - для двух верхних размерностей, также возможно указать
|
|
3532
|
+
колонку "Всего" в пути, то есть ["Простуда и грипп", "Всего"]
|
|
3527
3533
|
:return: (dict) результат команды ("view", "set_sort").
|
|
3528
3534
|
"""
|
|
3529
3535
|
# проверки
|
|
3530
|
-
|
|
3531
|
-
int_sort_type = self.checks(self.func_name, sort_type)
|
|
3532
|
-
except Exception as e:
|
|
3533
|
-
return self._raise_exception(ValueError, str(e), with_traceback=False)
|
|
3536
|
+
int_sort_type = self.checks(self.func_name, sort_type)
|
|
3534
3537
|
|
|
3535
3538
|
# получаем данные о расположении колонки "Всего". Если top_total_transfer = False - то в конце таблицы,
|
|
3536
3539
|
# если True, то первым столбцом
|
|
@@ -3553,31 +3556,71 @@ class BusinessLogic:
|
|
|
3553
3556
|
|
|
3554
3557
|
# извлекаем все колонки с фактами
|
|
3555
3558
|
top = self.h.parse_result(result, "top")
|
|
3556
|
-
measures = []
|
|
3557
|
-
for i in top:
|
|
3558
|
-
for elem in i:
|
|
3559
|
-
if "fact_id" in elem:
|
|
3560
|
-
measures.append(elem["fact_id"])
|
|
3561
3559
|
|
|
3562
3560
|
measure_id = self.get_measure_id(measure_name)
|
|
3563
3561
|
|
|
3564
3562
|
# находим номер колонки
|
|
3565
3563
|
try:
|
|
3566
|
-
|
|
3567
|
-
measures
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3564
|
+
if not path:
|
|
3565
|
+
measures = []
|
|
3566
|
+
for i in top:
|
|
3567
|
+
for elem in i:
|
|
3568
|
+
if "fact_id" in elem:
|
|
3569
|
+
measures.append(elem["fact_id"])
|
|
3570
|
+
line = (
|
|
3571
|
+
measures.index(measure_id)
|
|
3572
|
+
if top_total_transfer
|
|
3573
|
+
else len(measures) - 1 - measures[::-1].index(measure_id)
|
|
3574
|
+
)
|
|
3575
|
+
else:
|
|
3576
|
+
line = self._find_column_index(top, path, measure_id)
|
|
3571
3577
|
except ValueError:
|
|
3572
3578
|
return self._raise_exception(
|
|
3573
3579
|
ValueError, f'Measure "{measure_name}" must be visible!'
|
|
3574
3580
|
)
|
|
3575
3581
|
|
|
3582
|
+
if path and line is None:
|
|
3583
|
+
return self._raise_exception(
|
|
3584
|
+
ValueError, f'Path {path} is invalid! All top dims must be expanded!'
|
|
3585
|
+
)
|
|
3586
|
+
|
|
3576
3587
|
self.func_name = "sort_measure"
|
|
3577
3588
|
return self.execute_olap_command(
|
|
3578
3589
|
command_name="view", state="set_sort", line=line, sort_type=int_sort_type
|
|
3579
3590
|
)
|
|
3580
3591
|
|
|
3592
|
+
@staticmethod
|
|
3593
|
+
def _find_column_index(top: Dict, path: List[str], measure_id: str) -> Optional[int]:
|
|
3594
|
+
|
|
3595
|
+
acceptable_indieces = set(range(len(top[0])))
|
|
3596
|
+
value_index = len(top[0]) + 1
|
|
3597
|
+
for depth, expected_value in enumerate(path):
|
|
3598
|
+
row = top[depth]
|
|
3599
|
+
acceptable_indieces_row = set()
|
|
3600
|
+
|
|
3601
|
+
for index_cell, cell in enumerate(row):
|
|
3602
|
+
if expected_value == 'Всего' and cell.get("type") == 5 and index_cell in acceptable_indieces:
|
|
3603
|
+
acceptable_indieces_row.add(index_cell)
|
|
3604
|
+
break
|
|
3605
|
+
elif cell.get("value") == expected_value:
|
|
3606
|
+
if index_cell in acceptable_indieces:
|
|
3607
|
+
value_index = index_cell
|
|
3608
|
+
acceptable_indieces_row.add(index_cell)
|
|
3609
|
+
elif cell.get("type") in (1, 5) and index_cell >= value_index:
|
|
3610
|
+
if index_cell in acceptable_indieces:
|
|
3611
|
+
acceptable_indieces_row.add(index_cell)
|
|
3612
|
+
elif cell.get("value") != expected_value and cell.get("type") in (2, 3) and acceptable_indieces_row:
|
|
3613
|
+
break
|
|
3614
|
+
acceptable_indieces = acceptable_indieces_row
|
|
3615
|
+
value_index = len(top[0]) + 1
|
|
3616
|
+
|
|
3617
|
+
# находим факт в ряду фактов и возвращаем его индекс
|
|
3618
|
+
for index in sorted(acceptable_indieces):
|
|
3619
|
+
measure_cell = top[-1][index]
|
|
3620
|
+
if measure_cell.get("type") == 4 and measure_cell.get("fact_id") == measure_id:
|
|
3621
|
+
return index
|
|
3622
|
+
return None
|
|
3623
|
+
|
|
3581
3624
|
def _get_left_and_top_dims_count(
|
|
3582
3625
|
self, level: int = None, position: int = None
|
|
3583
3626
|
) -> Tuple[int, int]:
|
|
@@ -4147,6 +4190,7 @@ class BusinessLogic:
|
|
|
4147
4190
|
increment_dim,
|
|
4148
4191
|
interval_dim,
|
|
4149
4192
|
interval_borders,
|
|
4193
|
+
encoding
|
|
4150
4194
|
)
|
|
4151
4195
|
except Exception as e:
|
|
4152
4196
|
return self._raise_exception(ValueError, str(e), with_traceback=False)
|
|
@@ -8695,7 +8739,7 @@ class GetDataChunk:
|
|
|
8695
8739
|
)
|
|
8696
8740
|
|
|
8697
8741
|
# проверка на количество подгружаемых строк
|
|
8698
|
-
self.checks("load_sphere_chunk", units, convert_type, convert_empty_values)
|
|
8742
|
+
self.sc.checks("load_sphere_chunk", units, convert_type, convert_empty_values)
|
|
8699
8743
|
|
|
8700
8744
|
# если был передан параметр convert_type, то нужно инициализировать класс преобразования типов
|
|
8701
8745
|
if convert_type:
|
|
@@ -322,11 +322,17 @@ def request_with_undefined_suffix_url(
|
|
|
322
322
|
def validate_params(model, raise_exception_func, **kwargs):
|
|
323
323
|
type_name_map = {
|
|
324
324
|
"string_type": "str",
|
|
325
|
+
"type_error.str": "str",
|
|
325
326
|
"bool_type": "bool",
|
|
327
|
+
"value_error.strictbool": "bool",
|
|
326
328
|
"int_type": "int",
|
|
329
|
+
"type_error.integer": "int",
|
|
327
330
|
"float_type": "float",
|
|
331
|
+
"type_error.float": "float",
|
|
328
332
|
"list_type": "list",
|
|
333
|
+
"type_error.list": "list",
|
|
329
334
|
"dict_type": "dict",
|
|
335
|
+
"type_error.dict": "dict",
|
|
330
336
|
}
|
|
331
337
|
|
|
332
338
|
try:
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from typing import List, Optional, Union
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, StrictBool, StrictInt, StrictStr
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SetMeasuresParams(BaseModel):
|
|
7
|
+
measure_names: List[StrictStr]
|
|
8
|
+
measure_formats: List[dict]
|
|
9
|
+
set_to_default: StrictBool = False
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class GetMeasuresParams(BaseModel):
|
|
13
|
+
measure_names: Optional[List[StrictStr]] = None
|
|
14
|
+
return_id: Optional[StrictBool] = False
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CreateSphereParams(BaseModel):
|
|
18
|
+
cube_name: StrictStr
|
|
19
|
+
source_name: StrictStr
|
|
20
|
+
file_type: StrictStr
|
|
21
|
+
update_params: Optional[dict] = None
|
|
22
|
+
sql_params: Optional[dict] = None
|
|
23
|
+
user_interval: StrictStr = "с текущего дня"
|
|
24
|
+
filepath: StrictStr = ""
|
|
25
|
+
separator: StrictStr = ""
|
|
26
|
+
increment_dim: StrictStr = ""
|
|
27
|
+
interval_dim: StrictStr = ""
|
|
28
|
+
interval_borders: Optional[list] = None
|
|
29
|
+
encoding: StrictStr = ""
|
|
30
|
+
delayed: StrictBool = False
|
|
31
|
+
modified_records_params: Optional[dict] = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class UpdateCubeParams(BaseModel):
|
|
35
|
+
cube_name: StrictStr
|
|
36
|
+
new_cube_name: Optional[StrictStr] = None
|
|
37
|
+
update_params: Optional[dict] = None
|
|
38
|
+
user_interval: StrictStr = "с текущего дня"
|
|
39
|
+
delayed: StrictBool = False
|
|
40
|
+
increment_dim: StrictStr = ""
|
|
41
|
+
interval_dim: StrictStr = ""
|
|
42
|
+
interval_borders: Optional[list] = None
|
|
43
|
+
modified_records_params: Optional[dict] = None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class CleanUpParams(BaseModel):
|
|
47
|
+
cube_name: StrictStr
|
|
48
|
+
dimension_name: StrictStr
|
|
49
|
+
sql_params: dict
|
|
50
|
+
is_update: StrictBool = True
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class RenameDimsParams(BaseModel):
|
|
54
|
+
dim_name: StrictStr
|
|
55
|
+
new_name: StrictStr
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class SetMeasureVisibilityParams(BaseModel):
|
|
59
|
+
measure_names: Union[StrictStr, List[StrictStr]]
|
|
60
|
+
is_visible: StrictBool = False
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class DeleteDimFilterParams(BaseModel):
|
|
64
|
+
dim_name: StrictStr
|
|
65
|
+
filter_name: Union[StrictStr, list, set, tuple]
|
|
66
|
+
num_row: StrictInt = 100
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class CreateLayerParams(BaseModel):
|
|
70
|
+
set_active: StrictBool = True
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class CreateConsistentDimParams(BaseModel):
|
|
74
|
+
formula: StrictStr
|
|
75
|
+
separator: StrictStr
|
|
76
|
+
dimension_list: List[StrictStr]
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
""" Модуль обработки ошибок из ответа """
|
|
3
3
|
|
|
4
4
|
import datetime
|
|
5
|
+
from datetime import datetime as dt
|
|
5
6
|
import re
|
|
6
7
|
|
|
7
8
|
import requests
|
|
8
|
-
from
|
|
9
|
+
from packaging.version import Version
|
|
9
10
|
|
|
10
11
|
from polymatica.common.consts import (
|
|
11
12
|
CUBE_NAME_FORBIDDEN_CHARS,
|
|
@@ -429,9 +430,15 @@ class Validator:
|
|
|
429
430
|
:param filter_field_format: формат поля фильтра
|
|
430
431
|
:return: список дат
|
|
431
432
|
"""
|
|
433
|
+
if not filter_field_format:
|
|
434
|
+
raise ValueError(
|
|
435
|
+
f"filter_field_format must be specified!"
|
|
436
|
+
)
|
|
432
437
|
try:
|
|
433
|
-
|
|
434
|
-
|
|
438
|
+
start_dt = dt.strptime(start_date, filter_field_format)
|
|
439
|
+
end_dt = dt.strptime(end_date, filter_field_format)
|
|
440
|
+
start = start_dt if "%S" in filter_field_format else start_dt.date()
|
|
441
|
+
end = end_dt if "%S" in filter_field_format else end_dt.date()
|
|
435
442
|
except ValueError:
|
|
436
443
|
raise ValueError(
|
|
437
444
|
f"Unknown date format! start_date: {start_date}, end_date: {end_date}"
|
|
@@ -440,20 +447,36 @@ class Validator:
|
|
|
440
447
|
if start > end:
|
|
441
448
|
raise ValueError("Start date can not be more than the end date!")
|
|
442
449
|
|
|
443
|
-
# Получаем формат хранения дат в Полиматике, если он не задан пользователем
|
|
444
|
-
date_format_pattern = (
|
|
445
|
-
filter_field_format or self.bl.get_current_datetime_format()
|
|
446
|
-
)
|
|
447
450
|
|
|
448
451
|
# Заполняем dates_list
|
|
449
452
|
dates_list = []
|
|
450
453
|
step = datetime.timedelta(days=1)
|
|
454
|
+
|
|
455
|
+
# если версия аналитикс 5.9.12 или выше, то добавляем миллисекунды к датам
|
|
456
|
+
current_polymatica_version = self.bl.full_polymatica_version.split("-")[0]
|
|
457
|
+
current_polymatica_version = Version(current_polymatica_version)
|
|
458
|
+
edge_version = Version("5.9.12")
|
|
451
459
|
while start <= end:
|
|
452
|
-
|
|
460
|
+
if current_polymatica_version >= edge_version and "%S" in filter_field_format:
|
|
461
|
+
dates_list.append(self._format_datetime_with_millis(start, filter_field_format))
|
|
462
|
+
else:
|
|
463
|
+
dates_list.append(start.strftime(filter_field_format))
|
|
453
464
|
start += step
|
|
454
465
|
|
|
455
466
|
return dates_list
|
|
456
467
|
|
|
468
|
+
@staticmethod
|
|
469
|
+
def _format_datetime_with_millis(dt: datetime.datetime, pattern: str) -> str:
|
|
470
|
+
base = dt.strftime(pattern)
|
|
471
|
+
millis = f"{dt.microsecond // 1000:03d}"
|
|
472
|
+
if "%f" in pattern:
|
|
473
|
+
# Если %f есть, то заменим его на миллисекунды
|
|
474
|
+
base = base.replace(dt.strftime("%f"), millis)
|
|
475
|
+
else:
|
|
476
|
+
# Иначе просто добавим миллисекунды в конце через точку
|
|
477
|
+
base = f"{base}.{millis}"
|
|
478
|
+
return base
|
|
479
|
+
|
|
457
480
|
@staticmethod
|
|
458
481
|
def check_export(file_format, file_path):
|
|
459
482
|
"""
|
|
@@ -609,6 +632,7 @@ class Validator:
|
|
|
609
632
|
increment_dim,
|
|
610
633
|
interval_dim,
|
|
611
634
|
interval_borders,
|
|
635
|
+
encoding
|
|
612
636
|
):
|
|
613
637
|
"""
|
|
614
638
|
Проверка множества аргументов функции create_sphere.
|
|
@@ -647,9 +671,18 @@ class Validator:
|
|
|
647
671
|
# проверка длины и отсутствия пробелов в имени источника
|
|
648
672
|
self._validate_source_name(source_name)
|
|
649
673
|
|
|
674
|
+
self._validate_encoding(file_type, encoding)
|
|
675
|
+
|
|
650
676
|
self.bl.func_name = "create_sphere"
|
|
651
677
|
return cube_name
|
|
652
678
|
|
|
679
|
+
def _validate_encoding(self, file_type, encoding):
|
|
680
|
+
"""
|
|
681
|
+
Проверка кодировки. Для источника формата csv она должна быть обязательно задана.
|
|
682
|
+
"""
|
|
683
|
+
if file_type == 'csv' and encoding == "":
|
|
684
|
+
raise ValueError(f"For csv source encoding must be specified!")
|
|
685
|
+
|
|
653
686
|
def _validate_update_params(self, update_params, file_type, time_zones):
|
|
654
687
|
"""
|
|
655
688
|
Проверка параметров обновления.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "polyapi"
|
|
3
|
-
version = "5.9.
|
|
3
|
+
version = "5.9.13"
|
|
4
4
|
description = "Wrapper for Polymatica API"
|
|
5
5
|
license = "MIT"
|
|
6
6
|
keywords = ["polymatica"]
|
|
@@ -15,6 +15,7 @@ requests = ">=2.31.0"
|
|
|
15
15
|
setuptools = ">=68.0.0"
|
|
16
16
|
pandas = "^1.5.3"
|
|
17
17
|
pydantic = ">=2.0"
|
|
18
|
+
packaging = "^25.0"
|
|
18
19
|
|
|
19
20
|
[tool.poetry.group.dev.dependencies]
|
|
20
21
|
ruff = "^0.11.2"
|
|
@@ -10,7 +10,7 @@ classifiers = [
|
|
|
10
10
|
|
|
11
11
|
setup(
|
|
12
12
|
name='polyapi',
|
|
13
|
-
version='5.9.
|
|
13
|
+
version='5.9.13',
|
|
14
14
|
description='Wrapper for Polymatica API',
|
|
15
15
|
long_description=open('README.txt', encoding='utf-8').read(),
|
|
16
16
|
url='https://www.polymatica.ru',
|
|
@@ -20,5 +20,5 @@ setup(
|
|
|
20
20
|
classifiers=classifiers,
|
|
21
21
|
keywords="polymatica",
|
|
22
22
|
packages=find_packages(),
|
|
23
|
-
install_requires=["setuptools", "pandas", "requests", "pydantic"],
|
|
23
|
+
install_requires=["setuptools", "pandas", "requests", "pydantic", "packaging"],
|
|
24
24
|
)
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
from typing import List, Optional, Union
|
|
2
|
-
|
|
3
|
-
from pydantic import BaseModel, ConfigDict
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class SetMeasuresParams(BaseModel):
|
|
7
|
-
model_config = ConfigDict(strict=True)
|
|
8
|
-
measure_names: List[str]
|
|
9
|
-
measure_formats: List[dict]
|
|
10
|
-
set_to_default: bool = False
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class GetMeasuresParams(BaseModel):
|
|
14
|
-
model_config = ConfigDict(strict=True)
|
|
15
|
-
measure_names: Optional[List[str]] = None
|
|
16
|
-
return_id: Optional[bool] = False
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class CreateSphereParams(BaseModel):
|
|
20
|
-
model_config = ConfigDict(strict=True)
|
|
21
|
-
cube_name: str
|
|
22
|
-
source_name: str
|
|
23
|
-
file_type: str
|
|
24
|
-
update_params: Optional[dict] = None
|
|
25
|
-
sql_params: Optional[dict] = None
|
|
26
|
-
user_interval: str = "с текущего дня"
|
|
27
|
-
filepath: str = ""
|
|
28
|
-
separator: str = ""
|
|
29
|
-
increment_dim: str = ""
|
|
30
|
-
interval_dim: str = ""
|
|
31
|
-
interval_borders: Optional[list] = None
|
|
32
|
-
encoding: str = ""
|
|
33
|
-
delayed: bool = False
|
|
34
|
-
modified_records_params: Optional[dict] = None
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class UpdateCubeParams(BaseModel):
|
|
38
|
-
model_config = ConfigDict(strict=True)
|
|
39
|
-
cube_name: str
|
|
40
|
-
new_cube_name: Optional[str] = None
|
|
41
|
-
update_params: Optional[dict] = None
|
|
42
|
-
user_interval: str = "с текущего дня"
|
|
43
|
-
delayed: bool = False
|
|
44
|
-
increment_dim: str = ""
|
|
45
|
-
interval_dim: str = ""
|
|
46
|
-
interval_borders: Optional[list] = None
|
|
47
|
-
modified_records_params: Optional[dict] = None
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
class CleanUpParams(BaseModel):
|
|
51
|
-
model_config = ConfigDict(strict=True)
|
|
52
|
-
cube_name: str
|
|
53
|
-
dimension_name: str
|
|
54
|
-
sql_params: dict
|
|
55
|
-
is_update: bool = True
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class RenameDimsParams(BaseModel):
|
|
59
|
-
model_config = ConfigDict(strict=True)
|
|
60
|
-
dim_name: str
|
|
61
|
-
new_name: str
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class SetMeasureVisibilityParams(BaseModel):
|
|
65
|
-
model_config = ConfigDict(strict=True)
|
|
66
|
-
measure_names: Union[str, List[str]]
|
|
67
|
-
is_visible: bool = False
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
class DeleteDimFilterParams(BaseModel):
|
|
71
|
-
model_config = ConfigDict(strict=True)
|
|
72
|
-
dim_name: str
|
|
73
|
-
filter_name: Union[str, list, set, tuple]
|
|
74
|
-
num_row: int = 100
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
class CreateLayerParams(BaseModel):
|
|
78
|
-
model_config = ConfigDict(strict=True)
|
|
79
|
-
set_active: bool = True
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
class CreateConsistentDimParams(BaseModel):
|
|
83
|
-
model_config = ConfigDict(strict=True)
|
|
84
|
-
formula: str
|
|
85
|
-
separator: str
|
|
86
|
-
dimension_list: List[str]
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|