polyapi 5.9.17__tar.gz → 5.9.18__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 (55) hide show
  1. {polyapi-5.9.17 → polyapi-5.9.18}/PKG-INFO +1 -1
  2. {polyapi-5.9.17 → polyapi-5.9.18}/polyapi.egg-info/PKG-INFO +1 -1
  3. {polyapi-5.9.17 → polyapi-5.9.18}/polyapi.egg-info/SOURCES.txt +0 -3
  4. {polyapi-5.9.17 → polyapi-5.9.18}/polyapi.egg-info/top_level.txt +0 -1
  5. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/business_scenarios.py +280 -79
  6. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/common/consts.py +3 -1
  7. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/common/params_models.py +9 -7
  8. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/error_handler.py +128 -31
  9. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/helper.py +95 -5
  10. {polyapi-5.9.17 → polyapi-5.9.18}/pyproject.toml +1 -1
  11. {polyapi-5.9.17 → polyapi-5.9.18}/setup.py +2 -2
  12. polyapi-5.9.17/tests/__init__.py +0 -1
  13. polyapi-5.9.17/tests/conftest.py +0 -65
  14. polyapi-5.9.17/tests/const.py +0 -312
  15. {polyapi-5.9.17 → polyapi-5.9.18}/LICENSE.txt +0 -0
  16. {polyapi-5.9.17 → polyapi-5.9.18}/README.md +0 -0
  17. {polyapi-5.9.17 → polyapi-5.9.18}/polyapi.egg-info/dependency_links.txt +0 -0
  18. {polyapi-5.9.17 → polyapi-5.9.18}/polyapi.egg-info/requires.txt +0 -0
  19. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/__init__.py +0 -0
  20. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/authorization.py +0 -0
  21. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/business_logic_doc.py +0 -0
  22. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/commands/__init__.py +0 -0
  23. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/commands/base_command.py +0 -0
  24. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/commands/olap_module.py +0 -0
  25. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/commands/other_modules.py +0 -0
  26. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/common/__init__.py +0 -0
  27. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/common/helper_funcs.py +0 -0
  28. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/exceptions.py +0 -0
  29. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/executor.py +0 -0
  30. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/__init__.py +0 -0
  31. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/base_graph.py +0 -0
  32. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/graph_interface.py +0 -0
  33. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/__init__.py +0 -0
  34. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/areas.py +0 -0
  35. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/balls.py +0 -0
  36. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/chord.py +0 -0
  37. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/circles.py +0 -0
  38. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/circles_series.py +0 -0
  39. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/corridors.py +0 -0
  40. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/cumulative_areas.py +0 -0
  41. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/cumulative_cylinders.py +0 -0
  42. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/cylinders.py +0 -0
  43. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/graph.py +0 -0
  44. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/lines.py +0 -0
  45. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/pies.py +0 -0
  46. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/point.py +0 -0
  47. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/point_series.py +0 -0
  48. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/pools.py +0 -0
  49. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/pools_3d.py +0 -0
  50. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/radar.py +0 -0
  51. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/sankey.py +0 -0
  52. {polyapi-5.9.17 → polyapi-5.9.18}/polymatica/graph/types/surface.py +0 -0
  53. {polyapi-5.9.17 → polyapi-5.9.18}/setup.cfg +0 -0
  54. {polyapi-5.9.17 → polyapi-5.9.18}/tests/test_create_sphere.py +0 -0
  55. {polyapi-5.9.17 → polyapi-5.9.18}/tests/test_update_cube.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polyapi
3
- Version: 5.9.17
3
+ Version: 5.9.18
4
4
  Summary: Wrapper for Polymatica API
5
5
  Home-page: https://slsoft.ru/products/polymatica/
6
6
  Author: Polymatica Rus LLC
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polyapi
3
- Version: 5.9.17
3
+ Version: 5.9.18
4
4
  Summary: Wrapper for Polymatica API
5
5
  Home-page: https://slsoft.ru/products/polymatica/
6
6
  Author: Polymatica Rus LLC
@@ -47,8 +47,5 @@ polymatica/graph/types/pools_3d.py
47
47
  polymatica/graph/types/radar.py
48
48
  polymatica/graph/types/sankey.py
49
49
  polymatica/graph/types/surface.py
50
- tests/__init__.py
51
- tests/conftest.py
52
- tests/const.py
53
50
  tests/test_create_sphere.py
54
51
  tests/test_update_cube.py
@@ -1,2 +1 @@
1
1
  polymatica
2
- tests
@@ -37,6 +37,7 @@ from polymatica.common import (
37
37
  LOGIC_FUNCS,
38
38
  MEASURE_INT_STR_TYPES_MAP,
39
39
  MIN_MEASURE_CELL_WIDTH,
40
+ MIN_OLAP_HEIGHT,
40
41
  MIN_OLAP_WIDTH,
41
42
  MULTISPHERE_ID,
42
43
  OPERANDS,
@@ -3825,24 +3826,33 @@ class BusinessLogic:
3825
3826
 
3826
3827
  @timing
3827
3828
  def set_width_columns(
3828
- self, measures: List, left_dims: List, width: int = 890, height: int = 540
3829
+ self, measures: List[int], left_dims: List[int], width: int = 890, height: int = 540
3829
3830
  ) -> dict:
3830
3831
  """
3831
- Установить ширину колонок в текущем (активном) модуле. Под колонками подразумеваются как левые размерности,
3832
- так и факты.
3833
- :param measures: (List) список новых значений ширины фактов.
3834
- ВАЖНО! Длина списка должна совпадать с количеством нескрытых фактов в мультисфере без учёта верхних
3832
+ Установить ширину колонок левых размерностей и фактов в текущем (активном) модуле.
3833
+ Установить ширину окна мультисферы.
3834
+ :param measures: (List[int]) список новых значений ширины фактов в формате int.
3835
+ Длина списка должна совпадать с количеством видимых фактов в мультисфере без учёта верхних
3835
3836
  размерностей. То есть:
3836
3837
  1. Если в мультисфере нет вынесенных вверх размерностей, то длина списка должна совпадать с
3837
- количеством нескрытых фактов в мультисфере.
3838
+ количеством видимых фактов в мультисфере.
3838
3839
  2. Если в мультисфере есть вынесенные вверх размерности, то длина списка должна совпадать с
3839
- количеством уникальных (не дублирующихся из-за верхних размерностей) нескрытых фактов в мультисфере.
3840
- :param left_dims: (List) список новых значений ширины вынесенных влево размерностей.
3841
- ВАЖНО! Длина списка должна совпадать с количеством реально вынесенных влево размерностей мультисферы!
3842
- :param width: (int) ширина мультисферы.
3843
- :param height: (int) высота мультисферы.
3840
+ количеством уникальных (не дублирующихся из-за верхних размерностей) видимых фактов в мультисфере.
3841
+ Минимально допустимое значение ширины для каждого факта - 60, если будет задано меньшее значение,
3842
+ то будет передано 60.
3843
+ :param left_dims: (List[int]) список новых значений ширины вынесенных влево размерностей в формате int.
3844
+ Длина списка должна совпадать с количеством вынесенных влево размерностей мультисферы!
3845
+ Минимально допустимое значение ширины для каждой вынесенной влево размерности - 110,
3846
+ если будет задано меньшее значение, то будет передано 110.
3847
+ :param width: (int) ширина окна мультисферы. Необязательный параметр, по умолчанию - 890,
3848
+ минимальное значение - 640.
3849
+ :param height: (int) высота окна мультисферы. Необязательный параметр, по умолчанию - 540,
3850
+ минимальное значение - 440.
3851
+ :call_example:
3852
+ session.set_width_columns(measures=[100, 150, 120], left_dims=[120, 120], width=700, height=600)
3844
3853
  :return: Команда ("user_iface", "save_settings").
3845
3854
  """
3855
+ # TODO: убрать num_row=20, num_col=20, загружать чанками
3846
3856
  result = self.execute_olap_command(
3847
3857
  command_name="view",
3848
3858
  state="get",
@@ -3865,16 +3875,27 @@ class BusinessLogic:
3865
3875
 
3866
3876
  # проверки
3867
3877
  try:
3868
- self.checks(
3869
- self.func_name, measures, measures_ids, left_dims, left_dims_data
3878
+ measures, left_dims = self.checks(
3879
+ self.func_name, measures, measures_ids, left_dims, left_dims_data, width, height
3870
3880
  )
3871
3881
  except Exception as e:
3872
3882
  return self._raise_exception(
3873
3883
  PolymaticaException, str(e), with_traceback=False
3874
3884
  )
3875
3885
 
3886
+ # ограничиваем ширину окна мультисферы минимально допустимой
3887
+ width = max(width, MIN_OLAP_WIDTH)
3888
+ height = max(height, MIN_OLAP_HEIGHT)
3889
+
3890
+ # извлекаем текущее имя модуля
3891
+ current_settings = self.execute_manager_command(
3892
+ command_name="user_iface", state="load_settings", module_id=self.multisphere_module_id
3893
+ )
3894
+ title = self.h.parse_result(result=current_settings, key="settings", nested_key="title")
3895
+
3876
3896
  # сохраняем новые настройки
3877
3897
  settings = {
3898
+ "title": title,
3878
3899
  "dimAndFactShow": True,
3879
3900
  "itemWidth": measures,
3880
3901
  "geometry": {"width": width, "height": height},
@@ -4045,15 +4066,17 @@ class BusinessLogic:
4045
4066
  sql_params: dict = None,
4046
4067
  user_interval: str = "с текущего дня",
4047
4068
  filepath: str = "",
4048
- separator: str = "",
4069
+ separator: str = ",",
4049
4070
  increment_dim: str = "",
4050
4071
  interval_dim: str = "",
4051
4072
  interval_borders: list = None,
4052
- encoding: str = "",
4073
+ encoding: str = "UTF-8",
4053
4074
  delayed: bool = False,
4054
4075
  modified_records_params: dict = None,
4055
4076
  relevance_date: dict = None,
4056
4077
  indirect_cpu_load_parameter: dict = None,
4078
+ measures: dict = None,
4079
+ sources: list = None,
4057
4080
  ) -> dict:
4058
4081
  """
4059
4082
  Создать новую мультисферу (куб).
@@ -4063,8 +4086,8 @@ class BusinessLogic:
4063
4086
  начиная с единицы, например "cube(1)", "cube(2)".
4064
4087
  :param source_name: (str) название источника данных, оно должно содержать от 5 до 100 символов, допустимы
4065
4088
  русские и английские буквы, цифры, пробел, '_' , '-').
4066
- :param file_type: (str) тип источника данных (см. значения в "server-codes.json" в поле "data_source_type").
4067
- Примеры основных источников данных: "excel", "csv", "mssql", "mysql", "psql", "jdbc", "odbc".
4089
+ :param file_type: (str) тип источника данных. Допустимые типы источников данных:
4090
+ "excel", "csv", "mssql", "mysql", "psql", "jdbc", "odbc".
4068
4091
  :param update_params: (dict) параметры обновления мультисферы. Не используется для мультисфер,
4069
4092
  созданных из файловых источников ("excel", "csv").
4070
4093
  Имеет структуру:
@@ -4135,7 +4158,9 @@ class BusinessLogic:
4135
4158
  "с предыдущего года", "с указанной даты", "с и по указанную дату"];
4136
4159
  актуально только для интервального обновления.
4137
4160
  :param filepath: (str) путь к файлу, либо название файла, если он лежит в той же директории.
4138
- :param separator: (str) разделитель столбцов; обязателен для csv-источника.
4161
+ :param separator: (str) разделитель столбцов; обязателен для csv-источника. По умолчанию запятая - ",".
4162
+ Если значение separator не совпадает с разделителем в источнике, возможна ошибка "Error in response: Facts
4163
+ list is empty". В этом случае необходимо поменять значение separator.
4139
4164
  :param increment_dim: (str) название размерности для инкрементального обновления; размерность должна иметь
4140
4165
  один из следующих типов: uint8, uint16, uint32, uint64, double, date, time, datetime.
4141
4166
  :param interval_dim: (str) название размерности для интервального обновления; размерность должна иметь
@@ -4145,7 +4170,7 @@ class BusinessLogic:
4145
4170
  в список только одно значение времени, а для обновления "с и по указанную дату" - два значения времени,
4146
4171
  при этом второе значение должно быть больше первого. Формат значений времени: "DD.MM.YYYY". Все остальные
4147
4172
  значения, если они будут переданы, будут игнорироваться. Актуально только для интервального обновления.
4148
- :param encoding: (str) кодировка, например UTF-8; обязательна для csv-источника.
4173
+ :param encoding: (str) кодировка; обязательна для csv-источника. По умолчанию - "UTF-8".
4149
4174
  :param delayed: (bool) параметр, определяющий, будет ли отложено создание мультисферы.
4150
4175
  Если False, то не будет, и мультисфера будет автоматически создана.
4151
4176
  Если True: если настроено расписание обновлений (schedule в update_params),
@@ -4206,6 +4231,36 @@ class BusinessLogic:
4206
4231
  "use_default_value": False,
4207
4232
  "percent": 70,
4208
4233
  }
4234
+ :param measures: (dict) словарь, в который передаются факты, которые требуется удалить из создаваемой
4235
+ мультисферы, либо факты, которые требуется добавить в создаваемую мультисферу, исключив все остальные,
4236
+ а также список фактов, которые требуется добавить в создаваемую мультисферу с определенными настройками.
4237
+ Необязательный аргумент.
4238
+ Поля, передаваемые в словарь measures:
4239
+ "measures_list_mode": (str) - Режим работы списка фактов measures_list.
4240
+ Допустимые значения: "blacklist", "whitelist". Значение по умолчанию — "whitelist".
4241
+ "measures_list": (List[str]) - Если measures_list_mode = "blacklist", то measures_list — это
4242
+ список наименований полей источника, которые требуется удалить из списка фактов создаваемой
4243
+ мультисферы.
4244
+ Если measures_list_mode = "whitelist", то measures_list — это список наименований полей источника,
4245
+ которые требуется добавить в список фактов создаваемой мультисферы, исключив при этом
4246
+ все остальные.
4247
+ Необязательный аргумент. Если не заполнен, мультисфера создается со списком фактов по умолчанию.
4248
+ "measures_custom_list": (List[dict]) - Список словарей, каждый из которых содержит информацию
4249
+ по одному факту, который требуется добавить в мультисферу с настройками, отличными от настроек
4250
+ по умолчанию.
4251
+ Необязательный аргумент. Если не заполнен, мультисфера создается с настройками фактов по умолчанию.
4252
+ Поля, передаваемые в словарь measures_custom_list:
4253
+ "source_column": (str) - Название колонки источника. Допустимо передавать несколько словарей
4254
+ с одинаковым значением source_column и разным значением measure_name — будет создано
4255
+ несколько фактов с разными названиями на основе одной колонки источника.
4256
+ "measure_name": (str) - Имя факта. Если значение не заполнено, имя факта совпадает с
4257
+ названием колонки источника.
4258
+ "nullable": (bool) - Параметр, определяющий допустимость пропусков. Если True — пропуски
4259
+ допустимы, если False — пропуски заменяются нулями. Значение по умолчанию — False.
4260
+ :param sources: (list) Параметр, содержащий несколько источников данных.
4261
+ Задается в методе create_sphere_multisource, в текущем методе create_sphere не применим.
4262
+ Метод create_sphere поддерживает только один источник данных через параметры
4263
+ source_name, file_type, sql_params, filepath, separator, encoding.
4209
4264
 
4210
4265
  :return: (dict) Результат команды ("user_cube", "save_ext_info_several_sources_request").
4211
4266
  """
@@ -4239,7 +4294,7 @@ class BusinessLogic:
4239
4294
  modified_records_params["version"] = 1
4240
4295
  elif algo_version not in (0, 1):
4241
4296
  self.logger.warning(f"Param 'modified_records_algo_version' must be 0 or 1, "
4242
- f"not {algo_version}. Changed to 1")
4297
+ f"not {algo_version}. Changed to 1")
4243
4298
  modified_records_params["version"] = 1
4244
4299
 
4245
4300
  # проверки
@@ -4262,6 +4317,8 @@ class BusinessLogic:
4262
4317
  modified_records_params=modified_records_params,
4263
4318
  relevance_date=relevance_date,
4264
4319
  indirect_cpu_load_parameter=indirect_cpu_load_parameter,
4320
+ measures=measures,
4321
+ sources=sources,
4265
4322
  )
4266
4323
  (
4267
4324
  cube_name,
@@ -4280,6 +4337,8 @@ class BusinessLogic:
4280
4337
  modified_records_params,
4281
4338
  relevance_date,
4282
4339
  indirect_cpu_load_parameter,
4340
+ measures,
4341
+ sources,
4283
4342
  ) = (
4284
4343
  params.cube_name,
4285
4344
  params.source_name,
@@ -4297,6 +4356,8 @@ class BusinessLogic:
4297
4356
  params.modified_records_params,
4298
4357
  params.relevance_date,
4299
4358
  params.indirect_cpu_load_parameter,
4359
+ params.measures,
4360
+ params.sources,
4300
4361
  )
4301
4362
 
4302
4363
  try:
@@ -4315,6 +4376,8 @@ class BusinessLogic:
4315
4376
  encoding,
4316
4377
  relevance_date,
4317
4378
  indirect_cpu_load_parameter,
4379
+ measures,
4380
+ sources,
4318
4381
  )
4319
4382
  except Exception as e:
4320
4383
  return self._raise_exception(ValueError, str(e), with_traceback=False)
@@ -4330,65 +4393,91 @@ class BusinessLogic:
4330
4393
  self._convert_schedule_item(time_zones, schedule_item)
4331
4394
  schedule_items = [item for item in schedule_items_tmp if item]
4332
4395
 
4333
- # параметр source_type для различных форматов данных
4334
- source_type = self.h.get_source_type(file_type)
4335
-
4336
4396
  # создать мультисферу, получить id куба
4337
4397
  res = self.execute_manager_command(
4338
4398
  command_name="user_cube", state="create_cube_request", cube_name=cube_name
4339
4399
  )
4340
4400
  self.cube_id = self.h.parse_result(result=res, key="cube_id")
4341
-
4342
- # загрузка csv/excel файла
4343
- encoded_file_name = ""
4344
- if (file_type == "excel") or (file_type == "csv"):
4345
- encoded_file_name = self.h.upload_file_to_server(filepath)
4346
-
4347
- # превью-данные
4348
- preview_data = {
4349
- "name": source_name,
4350
- "server": "",
4351
- "server_type": source_type,
4352
- "login": "",
4353
- "passwd": "",
4354
- "database": "",
4355
- "sql_query": separator,
4356
- "skip": -1,
4357
- }
4358
-
4359
- # для бд выставить параметры server, login, passwd и sql_query
4360
- if (file_type != "csv") and (file_type != "excel"):
4361
- preview_data.update(sql_params)
4362
-
4363
- # для формата данных csv выставить кодировку
4364
- if file_type == "csv":
4365
- preview_data.update({"encoding": encoding, "server": encoded_file_name})
4366
-
4367
- # для формата данных excel указать параметр server
4368
- if file_type == "excel":
4369
- preview_data.update({"server": encoded_file_name})
4370
-
4371
- # соединиться с бд в тестовом режиме, проверить соединение
4372
- conn_result = self.execute_manager_command(
4373
- command_name="user_cube",
4374
- state="test_source_connection_request",
4375
- datasource=preview_data,
4376
- )
4377
- conn_status = self.h.parse_result(conn_result, "status")
4378
- if conn_status.get("code") != 0:
4379
- error_msg = "Unable to connect to database: {}".format(
4380
- conn_status.get("message", "description not found!")
4381
- )
4382
- return self._raise_exception(
4383
- DBConnectionError, error_msg, with_traceback=False
4384
- )
4401
+
4402
+ if sources:
4403
+ # режим нескольких источников (создание через create_sphere_multisource)
4404
+ all_sources = sources
4405
+ else:
4406
+ # режим одного источника - создаем источник из параметров метода
4407
+ all_sources = [{
4408
+ "source_name": source_name,
4409
+ "file_type": file_type,
4410
+ "sql_params": sql_params or {},
4411
+ "filepath": filepath,
4412
+ "separator": separator,
4413
+ "encoding": encoding,
4414
+ }]
4415
+
4416
+ # обрабатываем каждый источник
4417
+ datasources = []
4418
+ for source in all_sources:
4419
+ source_name = source.get("source_name")
4420
+ file_type = source.get("file_type")
4421
+ sql_params = source.get("sql_params", {})
4422
+ filepath = source.get("filepath", "")
4423
+ separator = source.get("separator", ",")
4424
+ encoding = source.get("encoding", "UTF-8")
4425
+
4426
+ # параметр source_type для различных форматов данных
4427
+ source_type = self.h.get_source_type(file_type)
4428
+
4429
+ # загрузка csv/excel файла
4430
+ encoded_file_name = ""
4431
+ if (file_type == "excel") or (file_type == "csv"):
4432
+ encoded_file_name = self.h.upload_file_to_server(filepath)
4433
+
4434
+ # превью-данные
4435
+ preview_data = {
4436
+ "name": source_name,
4437
+ "server": "",
4438
+ "server_type": source_type,
4439
+ "login": "",
4440
+ "passwd": "",
4441
+ "database": "",
4442
+ "sql_query": separator,
4443
+ "skip": -1,
4444
+ }
4445
+
4446
+ # для бд выставить параметры server, login, passwd и sql_query
4447
+ if (file_type != "csv") and (file_type != "excel"):
4448
+ preview_data.update(sql_params)
4449
+
4450
+ # для формата данных csv выставить кодировку
4451
+ if file_type == "csv":
4452
+ preview_data.update({"encoding": encoding, "server": encoded_file_name})
4453
+
4454
+ # для формата данных excel указать параметр server
4455
+ if file_type == "excel":
4456
+ preview_data.update({"server": encoded_file_name})
4457
+
4458
+ # соединиться с бд в тестовом режиме, проверить соединение
4459
+ conn_result = self.execute_manager_command(
4460
+ command_name="user_cube",
4461
+ state="test_source_connection_request",
4462
+ datasource=preview_data,
4463
+ )
4464
+ conn_status = self.h.parse_result(conn_result, "status")
4465
+ if conn_status.get("code") != 0:
4466
+ error_msg = "Unable to connect to database: {}".format(
4467
+ conn_status.get("message", "description not found!")
4468
+ )
4469
+ return self._raise_exception(
4470
+ DBConnectionError, error_msg, with_traceback=False
4471
+ )
4472
+
4473
+ datasources.append(preview_data)
4385
4474
 
4386
4475
  # из структуры данных получаем словари с данными о размерностях и фактах
4387
4476
  self.execute_manager_command(
4388
4477
  command_name="user_cube",
4389
4478
  state="get_fields_request",
4390
4479
  cube_id=self.cube_id,
4391
- datasources=[preview_data],
4480
+ datasources=datasources,
4392
4481
  )
4393
4482
  result = self.execute_manager_command(
4394
4483
  command_name="user_cube",
@@ -4398,8 +4487,16 @@ class BusinessLogic:
4398
4487
  )
4399
4488
 
4400
4489
  try:
4490
+ # определяем file_type для обработки
4491
+ effective_file_type = "csv" if sources and any(s.get("file_type") == "csv" for s in sources) \
4492
+ else (file_type if not sources else None)
4493
+
4401
4494
  # получаем и обрабатываем информацию о фактах и размерностях куба
4402
- dims, measures = self.h.get_and_process_dims_and_measures(result, file_type)
4495
+ processed_dims, processed_measures = self.h.get_and_process_dims_and_measures(
4496
+ result,
4497
+ effective_file_type,
4498
+ measures,
4499
+ )
4403
4500
  except Exception as e:
4404
4501
  return self._raise_exception(
4405
4502
  PolymaticaException, str(e), with_traceback=False
@@ -4409,8 +4506,8 @@ class BusinessLogic:
4409
4506
  command_params = {
4410
4507
  "cube_id": self.cube_id,
4411
4508
  "cube_name": cube_name,
4412
- "dims": dims,
4413
- "facts": measures,
4509
+ "dims": processed_dims,
4510
+ "facts": processed_measures,
4414
4511
  "schedule": {"delayed": delayed, "items": schedule_items},
4415
4512
  }
4416
4513
  if update_type == "ручное":
@@ -4420,7 +4517,7 @@ class BusinessLogic:
4420
4517
  elif update_type == "инкрементальное":
4421
4518
  # получаем идентификатор размерности инкремента
4422
4519
  increment_dim_id = ""
4423
- for dim in dims:
4520
+ for dim in processed_dims:
4424
4521
  if dim.get("name") == increment_dim:
4425
4522
  current_type = POLYMATICA_INT_TYPES_MAP.get(dim.get("type"))
4426
4523
  if current_type not in (
@@ -4452,7 +4549,7 @@ class BusinessLogic:
4452
4549
  elif update_type == "интервальное":
4453
4550
  # получаем идентификатор размерности
4454
4551
  interval_dim_id = ""
4455
- for dim in dims:
4552
+ for dim in processed_dims:
4456
4553
  if dim.get("name") == interval_dim:
4457
4554
  current_type = POLYMATICA_INT_TYPES_MAP.get(dim.get("type"))
4458
4555
  if current_type not in ("date", "datetime"):
@@ -4497,7 +4594,7 @@ class BusinessLogic:
4497
4594
  modified_records_algo_version = modified_records_params.get("version")
4498
4595
  modified_records_key_id = ""
4499
4596
  modified_records_date_id = ""
4500
- for dim in dims:
4597
+ for dim in processed_dims:
4501
4598
  if dim.get("name") == modified_records_key:
4502
4599
  modified_records_key_id = dim.get("id")
4503
4600
  if dim.get("name") == modified_records_date:
@@ -4535,7 +4632,7 @@ class BusinessLogic:
4535
4632
  )
4536
4633
 
4537
4634
  # обрабатываем и добавляем параметры даты актуальности данных
4538
- relevance_date_dict = self._process_relevance_date(relevance_date, dims)
4635
+ relevance_date_dict = self._process_relevance_date(relevance_date, processed_dims)
4539
4636
 
4540
4637
  command_params.update({"relevance_date": relevance_date_dict})
4541
4638
 
@@ -4551,6 +4648,108 @@ class BusinessLogic:
4551
4648
  **command_params,
4552
4649
  )
4553
4650
 
4651
+ @timing
4652
+ def create_sphere_multisource(
4653
+ self,
4654
+ cube_name: str,
4655
+ sources: list,
4656
+ update_params: dict = None,
4657
+ user_interval: str = "с текущего дня",
4658
+ increment_dim: str = "",
4659
+ interval_dim: str = "",
4660
+ interval_borders: list = None,
4661
+ delayed: bool = False,
4662
+ modified_records_params: dict = None,
4663
+ relevance_date: dict = None,
4664
+ indirect_cpu_load_parameter: dict = None,
4665
+ measures: dict = None,
4666
+ ) -> dict:
4667
+ """
4668
+ Создать новую мультисферу (куб) из нескольких источников.
4669
+ Описание остальных параметров см. в методе create_sphere.
4670
+
4671
+ :param cube_name: (str) название создаваемой мультисферы (куба), оно должно состоять из 5 и более символов,
4672
+ допустимы буквы, цифры, специальные символы (кроме: % ^ & = ; ± § ` ~ ] [ } { < >).
4673
+ Если мультисфера с таким названием присутствует на сервере, то к названию будет добавлено число в скобках,
4674
+ начиная с единицы, например "cube(1)", "cube(2)".
4675
+ :param sources: (list) Источники. Представляет собой список, элементами которого являются
4676
+ однотипные словари, описывающие источники.
4677
+
4678
+ Словарь, описывающий источник (из списка sources), должен содержать следующие поля:
4679
+ - source_name: (str) название источника данных, оно должно содержать от 5 до 100 символов, допустимы
4680
+ русские и английские буквы, цифры, пробел, '_' , '-').
4681
+ - file_type: (str) тип источника данных. Допустимые типы источников данных:
4682
+ Примеры основных источников данных: "excel", "csv", "mssql", "mysql", "psql", "jdbc", "odbc".
4683
+ - sql_params: (dict) параметры для источника данных SQL.
4684
+ Поля, передаваемые в словарь:
4685
+ "server" - хост, который может быть задан в виде IP-адреса сервера (например, "10.18.0.132"),
4686
+ либо в виде имени сервера (например, "polymatica.database1.ru");
4687
+ опционально также может быть задан порт подключения, в таком случае он должен идти после указания
4688
+ хоста через двоеточие (например, "10.18.0.132:5433", "polymatica.database1.ru:5433");
4689
+ в случае, если порт явно не указан, подразумевается порт по-умолчанию 5432.
4690
+ Для источника данных JDBC в этом поле необходимо указать DSN в формате,
4691
+ например, jdbc:mysql://192.111.11.11:3306/database. Если database стандартный, то возможно
4692
+ подключение и без указания его в DSN.
4693
+ "login" - логин пользователя.
4694
+ "passwd" - пароль пользователя.
4695
+ "database" - имя базы данных. Для источника данных JDBC указывать "database" не надо, оно указывается
4696
+ после хоста в строке DSN (см. описание поля "server")
4697
+ "sql_query" - запрос, который необходимо выполнить на сервере.
4698
+ Пример задания параметра:
4699
+ {
4700
+ "server": "10.8.0.115:5433",
4701
+ "login": "your_user",
4702
+ "passwd": "your_password",
4703
+ "database": "database_name",
4704
+ "sql_query": "SELECT * FROM table"
4705
+ }
4706
+ - filepath: (str) путь к файлу, либо название файла, если он лежит в той же директории.
4707
+ - separator: (str) разделитель столбцов; обязателен для csv-источника, по умолчанию ",". Если значение
4708
+ separator не совпадает с разделителем в источнике, возможна ошибка "Error in response: Facts list
4709
+ is empty". В этом случае необходимо поменять значение separator.
4710
+ - encoding: (str) кодировка, например UTF-8; обязательна для csv-источника, по умолчанию "UTF-8".
4711
+
4712
+ :param update_params: (dict) параметры обновления мультисферы. См. описание в create_sphere.
4713
+ :param user_interval: (str) интервал обновлений. См. описание в create_sphere.
4714
+ :param increment_dim: (str) название размерности для инкрементального обновления. См. описание в create_sphere.
4715
+ :param interval_dim: (str) название размерности для интервального обновления. См. описание в create_sphere.
4716
+ :param interval_borders: (list) временные границы для интервалов обновлений. См. описание в create_sphere.
4717
+ :param delayed: (bool) параметр, определяющий, будет ли отложено создание мультисферы.
4718
+ См. описание в create_sphere.
4719
+ :param modified_records_params: (dict) параметры обновления для типа "обновление измененных записей".
4720
+ См. описание в create_sphere.
4721
+ :param relevance_date: (dict) словарь, содержащий параметры отображения даты актуальности данных.
4722
+ См. описание в create_sphere.
4723
+ :param indirect_cpu_load_parameter: (dict) словарь, содержащий параметры предельного процента использования CPU.
4724
+ См. описание в create_sphere.
4725
+ :param measures: (dict) словарь, в который передаются факты. См. описание в create_sphere.
4726
+
4727
+ :return: (dict) Результат команды ("user_cube", "save_ext_info_several_sources_request").
4728
+ """
4729
+ if len(sources) <= 1:
4730
+ return self._raise_exception(ValueError, "For one source use create_sphere method", with_traceback=False)
4731
+
4732
+ return self.create_sphere(
4733
+ cube_name=cube_name,
4734
+ source_name=None, # не используется в режиме нескольких источников
4735
+ file_type=None, # не используется в режиме нескольких источников
4736
+ update_params=update_params,
4737
+ sql_params=None, # не используется в режиме нескольких источников
4738
+ user_interval=user_interval,
4739
+ filepath=None, # не используется в режиме нескольких источников
4740
+ separator=None, # не используется в режиме нескольких источников
4741
+ increment_dim=increment_dim,
4742
+ interval_dim=interval_dim,
4743
+ interval_borders=interval_borders,
4744
+ encoding=None, # не используется в режиме нескольких источников
4745
+ delayed=delayed,
4746
+ modified_records_params=modified_records_params,
4747
+ relevance_date=relevance_date,
4748
+ indirect_cpu_load_parameter=indirect_cpu_load_parameter,
4749
+ measures=measures,
4750
+ sources=sources,
4751
+ )
4752
+
4554
4753
  @timing
4555
4754
  def update_cube(
4556
4755
  self,
@@ -4559,12 +4758,12 @@ class BusinessLogic:
4559
4758
  update_params: dict = None,
4560
4759
  user_interval: str = "с текущего дня",
4561
4760
  filepath: str = "",
4562
- separator: str = "",
4761
+ separator: str = ",",
4563
4762
  delayed: bool = False,
4564
4763
  increment_dim: str = "",
4565
4764
  interval_dim: str = "",
4566
4765
  interval_borders: list = None,
4567
- encoding: str = "",
4766
+ encoding: str = "UTF-8",
4568
4767
  modified_records_params: dict = None,
4569
4768
  relevance_date: dict = None,
4570
4769
  indirect_cpu_load_parameter: dict = None,
@@ -4626,6 +4825,8 @@ class BusinessLogic:
4626
4825
  используется для замены файла в источнике. Можно заменять на файл того же типа, что и был,
4627
4826
  например "csv" на "csv". В пути файла обязательно должно быть расширение, например, ".csv".
4628
4827
  :param separator: (str) разделитель столбцов. Обязателен для csv-источника (при замене источника).
4828
+ По умолчанию запятая - ",". Если значение separator не совпадает с разделителем в источнике, возможна
4829
+ ошибка "Error in response: Facts list is empty". В этом случае необходимо поменять значение separator.
4629
4830
  :param delayed: (bool) параметр, определяющий, будет ли отложено обновление мультисферы.
4630
4831
  Если False, то не будет, и мультисфера будет автоматически обновлена.
4631
4832
  Если True: если настроено расписание обновлений (schedule в update_params),
@@ -4641,7 +4842,7 @@ class BusinessLogic:
4641
4842
  в список только одно значение времени, а для обновления "с и по указанную дату" - два значения времени,
4642
4843
  при этом второе значение должно быть больше первого. Формат значений времени: "DD.MM.YYYY". Все остальные
4643
4844
  значения, если они будут переданы, будут игнорироваться. Актуально только для интервального обновления.
4644
- :param encoding: (str) кодировка, например UTF-8; обязательна для csv-источника (при замене источника).
4845
+ :param encoding: (str) кодировка; обязательна для csv-источника (при замене источника). По умолчанию - "UTF-8".
4645
4846
  :param modified_records_params: (dict) параметры обновления для типа "обновление измененных записей".
4646
4847
  Поля, передаваемые в словарь:
4647
4848
  "modified_records_key" - поле, которому осуществляется сопоставление данных (имя размерности).
@@ -4726,7 +4927,7 @@ class BusinessLogic:
4726
4927
  modified_records_params["version"] = 1
4727
4928
  elif algo_version not in (0, 1):
4728
4929
  self.logger.warning(f"Param 'modified_records_algo_version' must be 0 or 1, "
4729
- f"not {algo_version}. Changed to 1")
4930
+ f"not {algo_version}. Changed to 1")
4730
4931
  modified_records_params["version"] = 1
4731
4932
  cubes_list = self.get_cubes_list()
4732
4933
  self.func_name = "update_cube"
@@ -196,5 +196,7 @@ ROOT_PARENT = "00000000"
196
196
  EMPTY_ID = "00000000"
197
197
  UNITS_LOAD_DATA_CHUNK = 1000
198
198
  BASE_LAYER_NAME = "Слой"
199
+ MIN_LEFT_DIM_CELL_WIDTH = 110
199
200
  MIN_MEASURE_CELL_WIDTH = 60
200
- MIN_OLAP_WIDTH = 790
201
+ MIN_OLAP_WIDTH = 640
202
+ MIN_OLAP_HEIGHT = 440