Общие сведения

Python-скрипт (далее – скрипт) обеспечивает детализацию Drill-through, выполняя её по условиям, описанным в файле конфигурации config.json (см. Детализация Drill-through). Скрипт необходимо зарегистрировать для приложения при помощи утилиты plm-util, чтобы приложение могло с ним работать.

При регистрации скрипта необходимо указывать его название, которое в приложении отображается в выпадающем списке варианта «Связанный сценарий» контекстного меню факта (см. Детализация Drill-through).

В приложении может быть зарегистрировано сколько угодно много скриптов. Для каждого зарегистрированного скрипта обязательно должен быть предоставлен файл конфигурации config.json (далее – файл конфигурации). Если для какого-либо зарегистрированного скрипта файл конфигурации отсутствует или имеет недопустимую структуру и детализация включена параметром конфигурации приложения plm.user_interface.scenario_hyperlink_enabled, то в ЛЮБОМ воспроизведенном сценарии, для ЛЮБОЙ его мультисферы контекстное меню факта НЕ ОТКРЫВАЕТСЯ, а в лог приложения записывается ошибка вида, соответственно:

Failed to get list of registered python scripts: linked scenario script 'Имя сценария' config file not exists
Failed to get list of registered python scripts: Rapidjson assertion error

Конфигурация зарегистрированного скрипта записывается в директорию /var/plmrepo/linkedscenarioscripts/идентификатор_конфигурации_зарегистрированного_скрипта.

Регистрировать, обновлять и удалять можно только по одному скрипту за раз.

Подготовка к регистрации

  1. Остановить работу приложения:

    service polymatica stop
  2. Убедиться, что в файле конфигурации утилиты plm-util.conf указан параметр, определяющий путь до репозитория Polymatica Analytics, обычно это /var/plmrepo:

    plm.manager.repo_directory = /var/plmrepo
  3. Создать в системе хоста приложения директорию /var/plmrepo/pyscripts/директория_python-скрипта, создать в ней файл с расширением .py, и вставить в него код скрипта. Например:

    /var/plmrepo/pyscripts/drill_through_on_population_ms/script.py
    Разверните блок и скопируйте код
    import argparse
    import json
    import os
    import sys
    from typing import List
    from polymatica import business_scenarios
    from polymatica.exceptions import PolymaticaException, RightsError, ScenarioError
     
    sys.stdout = open(1, "w", encoding='utf-8', closefd=False)
     
    ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
     
    print("script args: ", sys.argv[1:])
     
     
    class KeyValue(argparse.Action):
        def __call__(self, parser, namespace,
                     values, option_string=None):
            setattr(namespace, self.dest, dict())
     
            for value in values:
                key, value = value.split('=')
     
                getattr(namespace, self.dest)[key] = value
     
     
    parser = argparse.ArgumentParser()
     
    parser.add_argument('--dimension-elements',
                        nargs='*',
                        action=KeyValue)
     
    parser.add_argument('--connection_session', nargs=3)
    parser.add_argument('--url')
    parser.add_argument('--layer_id')
    parser.add_argument('--scenario_id')
    parser.add_argument('--cube_id')
    parser.add_argument('--config_path', default=os.path.join(ROOT_PATH, 'config.json'))
     
    args = parser.parse_args()
     
    print("dim args: ", args.dimension_elements)
     
     
    class DimFilter:
        def __init__(self, dim_id: str, filter_val: str):
            self.dim_id = dim_id
            self.filter_val = filter_val
     
     
    class MapInfo:
        def __init__(self, scenario_id: str, cube_id: str, filters: List[DimFilter]):
            self.scenario_id = scenario_id  # 1. запустить
            self.cube_id = cube_id  # 2. найти на слое мультисферы этого куба
            self.filters = filters  # 3. применить к мультисферам
     
     
    def err(msg):
        print(msg, file=sys.stderr)
        sys.exit(1)
     
     
    def extract_map_info(cfg) -> MapInfo:
        for scenario_pair in cfg['scenarios']:
            from_sc_id = scenario_pair['from_scenario_id']
            to_sc_id = scenario_pair['to_scenario_id']
     
            if args.scenario_id == from_sc_id:
                dims_to_filter = []
                to_cube_id = 0
     
                for cube_pair in scenario_pair['cubes']:
                    if cube_pair['from_cube_id'] == args.cube_id:
                        to_cube_id = cube_pair['to_cube_id']
     
                        for dim in cube_pair['dimensions']:
                            from_dim_id = dim['from_dimension_id']
                            to_dim_id = dim['to_dimension_id']
     
                            if from_dim_id in args.dimension_elements.keys():
                                dim_filter = DimFilter(dim_id=to_dim_id,
                                                       filter_val=args.dimension_elements[from_dim_id].encode('utf8',
                                                                                                              'surrogateescape').decode(
                                                           'utf8'))
     
                                dims_to_filter.append(dim_filter)
     
                        break
     
                return MapInfo(filters=dims_to_filter, cube_id=to_cube_id, scenario_id=to_sc_id)
     
        raise Exception("scenario pair not found")
     
     
    try:
        with open(args.config_path) as f:
            json_config = json.load(f)
    except OSError:
        err("cannot open {}".format(args.config_path))
     
    try:
        map_info = extract_map_info(json_config)
    except KeyError as e:
        err("bad config: {}".format(e))
     
    except Exception as e:
        err(e)
     
    if len(map_info.filters) != len(args.dimension_elements):
        err("some pairs for dimensions \"{}\" not specified in config".format(args.dimension_elements.keys()))
     
    try:
        session_params = {"session_id": args.connection_session[0],
                          "manager_uuid": args.connection_session[1],
                          "full_polymatica_version": args.connection_session[2]}
     
        bs = business_scenarios.BusinessLogic("", session_auth=session_params, url=json_config['connection']['url'])
    except Exception as e:
        err(e)
     
    print("starting scenario \"{}\" on layer \"{}\"".format(map_info.scenario_id, args.layer_id))
     
    try:
        bs.run_scenario_on_layer(scenario_id=map_info.scenario_id, layer_id=args.layer_id)
    except RightsError as e:
        err("Не удалось запустить связанный сценарий: " + e.user_msg)
    except ScenarioError as e:
        err("Не удалось запустить связанный сценарий: " + e.user_msg)
    except Exception as e:
        err("Не удалось запустить связанный сценарий")
     
    print("scenario \"{}\" successfully finished on layer \"{}\"".format(map_info.scenario_id, args.layer_id))
     
    modules_to_filter = []
    for module_info in bs.get_module_list():
        if module_info[3] == map_info.cube_id:
            modules_to_filter.append(module_info[0])
     
    if len(modules_to_filter) == 0:
        err("cannot find multispheres created from cube with id \"{}\" on scenario \"{}\"".format(map_info.cube_id,
                                                                                                  map_info.scenario_id))
     
    for module_id in modules_to_filter:
        bs.set_multisphere_module_id(module_id)
     
        for filter_to_put in map_info.filters:
            try:
                bs.put_dim_filter_by_value(dim_id=filter_to_put.dim_id, value=filter_to_put.filter_val)
                print(
                    "putted filter with value - \"{}\" on dim with id - \"{}\"".format(filter_to_put.filter_val,
                                                                                       filter_to_put.dim_id))
     
            except PolymaticaException as e:  # если фильтр исключен другим фильтром то игнорим его
                print(
                    "skipped filter with value - \"{}\" on dim with id - \"{}\"".format(filter_to_put.filter_val,
                                                                                        filter_to_put.dim_id))

Регистрация скрипта через конфигурационный файл plm-util

Регистрация скрипта

  1.  Открыть на редактирование файл plm-util.config:

    nano /etc/polymatica/plm-util.conf
  2. Добавить в него строки:

    # Команда регистрации скрипта
    create-pyscript
    # Название регистрируемого скрипта Python
    pyscripts.create.name = Python Linked Scenario
    # Вид регистрируемого скрипта Python [formatted_export, linked_scenario]
    pyscripts.create.type = linked_scenario
    # Путь до регистрируемого скрипта Python на диске
    pyscripts.create.script = /var/plmscripts/linked_scenario/first/script.py
    # Идентификатор размерности, в которой начинается переход в связанный сценарий для вида "linked_scenario"
    pyscripts.create.measure_id = 07141982
  3. Сохранить изменения в plm-util.config и выполнить команду:

    plm-util

Обновление скрипта 

  1. Открыть на редактирование файл plm-util.config:

    nano /etc/polymatica/plm-util.conf
  2. Добавить (раскомментировать) строки:

    # Команда обновления скрипта
    update-pyscript
    # Внесение изменений в зарегистрированный скрипт Python по имени
    # pyscripts.update.by_name = Python Linked Scenario
    # либо
    # Внесение изменений в зарегистрированный скрипт Python по идентификатору
    # pyscripts.update.by_id = 1a71ec1d
    # Новое наименование для скрипта Python
    pyscripts.update.new_name = New PlmUtil Script
    # Новый тип скрипта Python
    pyscripts.update.new_type = formatted_export
    # Путь до нового скрипта Python.
    pyscripts.update.new_script = /var/plmscripts/formatted_export/test_python_script_2.py
  3. Сохранить изменения в plm-util.config и выполнить команду:

    plm-util

Удаление скрипта

  1. Открыть на редактирование файл plm-util.config:

    nano /etc/polymatica/plm-util.conf
  2. Добавить в него строки:

    delete-pyscript 
    # Удаление зарегистрированного скрипта Python по имени
    # pyscripts.delete.by_name = Python Linked Scenario
    либо
    # Удаление зарегистрированного скрипта Python по идентификатору
    # pyscripts.delete.by_id = e654a03f
  3. Выполните команду:

    plm-util

    После успешного завершения процедуры можно запустить сервисы Polymatica командой:

    systemctl start polymatica.service

  • Нет меток