From 663e218fce7754f778c4cd80fed55f1989eee84f Mon Sep 17 00:00:00 2001 From: Mark <47815760+chilo-m@users.noreply.github.com> Date: Tue, 19 Mar 2024 12:51:20 +0300 Subject: [PATCH] DPNLPF-1924 add read jinja2 file templates (#188) * DPNLPF-1924 add read jinja2 file templates DPNLPF-1924 add tests for UnifiedTemplateMultiLoader action and requirement remove support for 3.8 --------- Co-authored-by: Mark Chilingaryan Co-authored-by: Makar Shevchenko --- .github/workflows/release.yml | 2 +- .github/workflows/tests.yml | 6 +- README.md | 2 +- core/basic_models/actions/string_actions.py | 72 ++++++++++++++++++- .../requirement/basic_requirements.py | 4 +- core/unified_template/unified_template.py | 25 +++++++ poetry.lock | 29 +++++++- pyproject.toml | 1 + smart_kit/resources/__init__.py | 4 +- .../static/references/forms/hello_form.json | 12 ++-- .../experience_items_template.jinja2 | 9 +++ .../action_test/test_action.py | 52 +++++++++++++- .../requirements_test/test_requirements.py | 27 ++++++- ...string_file_unified_template_action.jinja2 | 4 ++ .../test_unified_template_requirement.jinja2 | 3 + 15 files changed, 229 insertions(+), 23 deletions(-) create mode 100644 smart_kit/template/static/references/templates/experience_items_template.jinja2 create mode 100644 tests/static/references/templates/test_string_file_unified_template_action.jinja2 create mode 100644 tests/static/references/templates/test_unified_template_requirement.jinja2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 38391cab..93d7dfed 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v2 with: - python-version: '3.8.x' + python-version: '3.11.x' - name: Install Poetry uses: snok/install-poetry@v1 - name: Install Poetry plugins diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c73f467f..55085c4e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: "3.8" + python-version: "3.11" cache: 'poetry' - name: Install dependencies run: poetry install --no-interaction --no-root --all-extras @@ -27,7 +27,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ['3.9', '3.10', '3.11'] runs-on: ubuntu-20.04 name: unittests with py-${{ matrix.python-version }} @@ -61,7 +61,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: "3.8" + python-version: "3.11" cache: 'poetry' - name: Install Poetry plugins run: poetry self add "poetry-dynamic-versioning[plugin]" diff --git a/README.md b/README.md index 120d5dc3..635861b1 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ ____ * Linux, Mac OS или Windows (необходима установка [Conda](https://docs.conda.io/en/latest/)). * 512 МБ свободной памяти. -* Python 3.8.0 - 3.9.6. +* Python 3.9 - 3.11. ____ diff --git a/core/basic_models/actions/string_actions.py b/core/basic_models/actions/string_actions.py index 52d93c22..4986a2bd 100644 --- a/core/basic_models/actions/string_actions.py +++ b/core/basic_models/actions/string_actions.py @@ -4,6 +4,8 @@ from functools import cached_property from itertools import chain from typing import Union, Dict, List, Any, Optional, Tuple, TypeVar, Type, AsyncGenerator +from lazy import lazy +from scenarios.user.user_model import User from core.basic_models.actions.basic_actions import CommandAction from core.basic_models.actions.command import Command @@ -11,7 +13,8 @@ from core.model.base_user import BaseUser from core.model.factory import list_factory from core.text_preprocessing.base import BaseTextPreprocessingResult -from core.unified_template.unified_template import UnifiedTemplate, UNIFIED_TEMPLATE_TYPE_NAME +from core.unified_template.unified_template import UnifiedTemplate, UNIFIED_TEMPLATE_TYPE_NAME, \ + UnifiedTemplateMultiLoader T = TypeVar("T") @@ -112,6 +115,7 @@ class StringAction(NodeAction): } } """ + def __init__(self, items: Dict[str, Any], id: Optional[str] = None): super(StringAction, self).__init__(items, id) @@ -130,7 +134,7 @@ def _generate_command_context(self, user: BaseUser, text_preprocessing_result: B async def run(self, user: BaseUser, text_preprocessing_result: BaseTextPreprocessingResult, params: Optional[Dict[str, Union[str, float, int]]] = None) -> AsyncGenerator[Command, None]: - # Example: Command("ANSWER_TO_USER", {"answer": {"key1": "string1", "keyN": "stringN"}}) + # Result command format: Command("ANSWER_TO_USER", {"answer": {"key1": "string1", "keyN": "stringN"}}) params = params or {} command_params = self._generate_command_context(user, text_preprocessing_result, params) @@ -146,6 +150,69 @@ async def run(self, user: BaseUser, text_preprocessing_result: BaseTextPreproces request_data=self.request_data) +class StringFileUnifiedTemplateAction(StringAction): + @lazy + def nodes(self): + if self._nodes.get("type", "") == UNIFIED_TEMPLATE_TYPE_NAME: + return self._get_template_tree(self._nodes) + else: + return {k: self._get_template_tree(t) for k, t in self._nodes.items()} + + async def run(self, user: User, text_preprocessing_result: BaseTextPreprocessingResult, + params: Optional[Dict[str, Union[str, float, int]]] = None) -> List[Command]: + command_params = dict() + params = copy(params) or {} + collected = user.parametrizer.collect(text_preprocessing_result, filter_params={"command": self.command}) + params.update(collected) + if type(self.nodes) == UnifiedTemplateMultiLoader: + command_params = self._get_rendered_tree(self.nodes, params, self.no_empty_nodes) + else: + for key, value in self.nodes.items(): + rendered = self._get_rendered_tree(value, params, self.no_empty_nodes) + if rendered != "" or not self.no_empty_nodes: + command_params[key] = rendered + + yield Command(self.command, command_params, self.id, request_type=self.request_type, + request_data=self.request_data) + + def _get_template_tree(self, value): + is_dict_unified_template = isinstance(value, dict) and value.get("type") == UNIFIED_TEMPLATE_TYPE_NAME + if isinstance(value, str) or is_dict_unified_template: + result = UnifiedTemplateMultiLoader(value) + elif isinstance(value, dict): + result = {} + for inner_key, inner_value in value.items(): + result[inner_key] = self._get_template_tree(inner_value) + elif isinstance(value, list): + result = [] + for inner_value in value: + result.append(self._get_template_tree(inner_value)) + else: + result = value + return result + + def _get_rendered_tree_recursive(self, value, params, no_empty=False): + value_type = type(value) + if value_type is dict: + result = {} + for inner_key, inner_value in value.items(): + rendered = self._get_rendered_tree_recursive(inner_value, params, no_empty=no_empty) + if rendered != "" or not no_empty: + result[inner_key] = rendered + elif value_type is list: + result = [] + for inner_value in value: + rendered = self._get_rendered_tree_recursive(inner_value, params, no_empty=no_empty) + if rendered != "" or not no_empty: + result.append(rendered) + + elif value_type is UnifiedTemplateMultiLoader: + result = value.render(params) + else: + result = value + return result + + class AfinaAnswerAction(NodeAction): """ Example: @@ -160,6 +227,7 @@ class AfinaAnswerAction(NodeAction): Output: [command1(pronounceText)] """ + def __init__(self, items: Dict[str, Any], id: Optional[str] = None): super(AfinaAnswerAction, self).__init__(items, id) self.command: str = ANSWER_TO_USER diff --git a/core/basic_models/requirement/basic_requirements.py b/core/basic_models/requirement/basic_requirements.py index 62efb842..b9dac387 100644 --- a/core/basic_models/requirement/basic_requirements.py +++ b/core/basic_models/requirement/basic_requirements.py @@ -16,7 +16,7 @@ from core.model.registered import Registered from core.text_preprocessing.base import BaseTextPreprocessingResult from core.text_preprocessing.preprocessing_result import TextPreprocessingResult -from core.unified_template.unified_template import UnifiedTemplate +from core.unified_template.unified_template import UnifiedTemplate, UnifiedTemplateMultiLoader from core.utils.stats_timer import StatsTimer from scenarios.scenario_models.field.field_filler_description import IntersectionFieldFiller from scenarios.user.user_model import User @@ -208,7 +208,7 @@ def _check(self, text_preprocessing_result: BaseTextPreprocessingResult, user: B class TemplateRequirement(Requirement): def __init__(self, items: Dict[str, Any], id: Optional[str] = None) -> None: super().__init__(items, id) - self._template = UnifiedTemplate(items["template"]) + self._template = UnifiedTemplateMultiLoader(items["template"]) def _check(self, text_preprocessing_result: BaseTextPreprocessingResult, user: BaseUser, params: Dict[str, Any] = None) -> bool: diff --git a/core/unified_template/unified_template.py b/core/unified_template/unified_template.py index 798189a4..f9f1b19e 100644 --- a/core/unified_template/unified_template.py +++ b/core/unified_template/unified_template.py @@ -3,6 +3,7 @@ from copy import copy import jinja2 from distutils.util import strtobool +import os import core.logging.logger_constants as log_const from core.logging.logger_utils import log @@ -84,3 +85,27 @@ def silent_render(self, params_dict): def __str__(self): return str(self.input) + + +class UnifiedTemplateMultiLoader(UnifiedTemplate): + """ + Загружает шаблон jinja из файла или строки + Файлы шаблонов jinja должны находиться в директории some-app.static.templates + """ + + def __init__(self, input): + if isinstance(input, dict) and input.get("file"): + file_name = input["file"] + from smart_kit.configs import get_app_config + app_config = get_app_config() + templates_dir = os.path.join(app_config.STATIC_PATH, "references/templates") + for root, dirs, files in os.walk(templates_dir): + if file_name in files: + with open(os.path.join(root, file_name)) as f: + input["template"] = f.read() + super().__init__(input) + return + raise Exception(f"Template {file_name} does not exist in templates directory {templates_dir}") + + else: + super().__init__(input) diff --git a/poetry.lock b/poetry.lock index fe17c890..89cf9ad9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1004,6 +1004,21 @@ files = [ {file = "keras-2.12.0-py2.py3-none-any.whl", hash = "sha256:35c39534011e909645fb93515452e98e1a0ce23727b55d4918b9c58b2308c15e"}, ] +[[package]] +name = "lazy" +version = "1.6" +description = "Lazy attributes for Python objects" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +files = [ + {file = "lazy-1.6-py2.py3-none-any.whl", hash = "sha256:449375c125c7acac6b7a93f71b8e7ccb06546c37b161613f92d2d3981f793244"}, + {file = "lazy-1.6.tar.gz", hash = "sha256:7127324ec709e8324f08cb4611c1abe01776bda53bb9ce68dc5dfa46ca0ed3e9"}, +] + +[package.extras] +docs = ["sphinx (==5.3.0)", "sphinx-rtd-theme (==1.0.0)"] +mypy = ["mypy"] + [[package]] name = "libclang" version = "16.0.6" @@ -1011,6 +1026,8 @@ description = "Clang Python Bindings, mirrored from the official LLVM repo: http optional = true python-versions = "*" files = [ + {file = "libclang-16.0.6-1-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:88bc7e7b393c32e41e03ba77ef02fdd647da1f764c2cd028e69e0837080b79f6"}, + {file = "libclang-16.0.6-1-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:d80ed5827736ed5ec2bcedf536720476fd9d4fa4c79ef0cb24aea4c59332f361"}, {file = "libclang-16.0.6-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:da9e47ebc3f0a6d90fb169ef25f9fbcd29b4a4ef97a8b0e3e3a17800af1423f4"}, {file = "libclang-16.0.6-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:e1a5ad1e895e5443e205568c85c04b4608e4e973dae42f4dfd9cb46c81d1486b"}, {file = "libclang-16.0.6-py2.py3-none-manylinux2010_x86_64.whl", hash = "sha256:9dcdc730939788b8b69ffd6d5d75fe5366e3ee007f1e36a99799ec0b0c001492"}, @@ -2544,6 +2561,16 @@ files = [ {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, + {file = "wrapt-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ecee4132c6cd2ce5308e21672015ddfed1ff975ad0ac8d27168ea82e71413f55"}, + {file = "wrapt-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2020f391008ef874c6d9e208b24f28e31bcb85ccff4f335f15a3251d222b92d9"}, + {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2feecf86e1f7a86517cab34ae6c2f081fd2d0dac860cb0c0ded96d799d20b335"}, + {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:240b1686f38ae665d1b15475966fe0472f78e71b1b4903c143a842659c8e4cb9"}, + {file = "wrapt-1.14.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9008dad07d71f68487c91e96579c8567c98ca4c3881b9b113bc7b33e9fd78b8"}, + {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6447e9f3ba72f8e2b985a1da758767698efa72723d5b59accefd716e9e8272bf"}, + {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:acae32e13a4153809db37405f5eba5bac5fbe2e2ba61ab227926a22901051c0a"}, + {file = "wrapt-1.14.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49ef582b7a1152ae2766557f0550a9fcbf7bbd76f43fbdc94dd3bf07cc7168be"}, + {file = "wrapt-1.14.1-cp311-cp311-win32.whl", hash = "sha256:358fe87cc899c6bb0ddc185bf3dbfa4ba646f05b1b0b9b5a27c2cb92c2cea204"}, + {file = "wrapt-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:26046cd03936ae745a502abf44dac702a5e6880b2b01c29aea8ddf3353b68224"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, @@ -2768,4 +2795,4 @@ ml = ["keras", "scikit-learn", "scikit-learn", "tensorflow", "tensorflow", "tens [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<3.12" -content-hash = "d63f8fdabcf8d823a172aa7025a4b93bfea6d1f28b713a1459dd51220913e7e2" +content-hash = "81a54d8bd4bd4c0d72cab068e7c7d32859bd98844e326f39ba47b6b1c0e97abb" diff --git a/pyproject.toml b/pyproject.toml index e71b465c..83a3609e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,6 +63,7 @@ lxml = "4.9.2" twisted = "22.10.0" urllib3 = "1.26.16" certifi = "2023.07.22" +lazy = "^1.6" [tool.poetry.extras] ml = ["keras", "scikit-learn", "tensorflow", "tensorflow-macos", "tensorflow-aarch64"] diff --git a/smart_kit/resources/__init__.py b/smart_kit/resources/__init__.py index b32f8fc0..64b657df 100644 --- a/smart_kit/resources/__init__.py +++ b/smart_kit/resources/__init__.py @@ -21,7 +21,7 @@ from core.basic_models.actions.smartpay import SmartPayCreateAction, SmartPayPerformAction, SmartPayGetStatusAction, \ SmartPayConfirmAction, SmartPayDeleteAction, SmartPayRefundAction from core.basic_models.actions.string_actions import StringAction, AfinaAnswerAction, SDKAnswer, \ - SDKAnswerToUser + SDKAnswerToUser, StringFileUnifiedTemplateAction from core.basic_models.actions.variable_actions import ClearVariablesAction, DeleteVariableAction, \ SetLocalVariableAction, SetVariableAction from core.basic_models.answer_items.answer_items import items_factory, SdkAnswerItem, answer_items, BubbleText, \ @@ -311,7 +311,7 @@ def init_actions(self): actions["self_service_with_state"] = SelfServiceActionWithState actions["set_local_variable"] = SetLocalVariableAction actions["set_variable"] = SetVariableAction - actions["string"] = StringAction + actions["string"] = StringFileUnifiedTemplateAction actions["push"] = PushAction actions["push_authentication"] = PushAuthenticationActionHttp actions["push_http"] = PushActionHttp diff --git a/smart_kit/template/static/references/forms/hello_form.json b/smart_kit/template/static/references/forms/hello_form.json index 8f6a8b1f..5c9d765c 100644 --- a/smart_kit/template/static/references/forms/hello_form.json +++ b/smart_kit/template/static/references/forms/hello_form.json @@ -61,13 +61,11 @@ "command": "ANSWER_TO_USER", "nodes": { "pronounceText": "Сколько лет ты программируешь на Python?", - "items": [ - { - "bubble": { - "text": "Сколько лет ты программируешь на Python?" - } - } - ] + "items": { + "type": "unified_template", + "file": "experience_items_template.jinja2", + "loader": "json" + } } } ], diff --git a/smart_kit/template/static/references/templates/experience_items_template.jinja2 b/smart_kit/template/static/references/templates/experience_items_template.jinja2 new file mode 100644 index 00000000..22322837 --- /dev/null +++ b/smart_kit/template/static/references/templates/experience_items_template.jinja2 @@ -0,0 +1,9 @@ +{{ + [ + { + "bubble": { + "text": "Сколько лет ты программируешь на Python?" + } + } + ] |tojson +}} \ No newline at end of file diff --git a/tests/core_tests/basic_scenario_models_test/action_test/test_action.py b/tests/core_tests/basic_scenario_models_test/action_test/test_action.py index dc0ee189..18ff96ee 100644 --- a/tests/core_tests/basic_scenario_models_test/action_test/test_action.py +++ b/tests/core_tests/basic_scenario_models_test/action_test/test_action.py @@ -1,6 +1,7 @@ # coding: utf-8 import inspect import json +import os import unittest import uuid from unittest.mock import Mock, MagicMock, patch, AsyncMock @@ -30,8 +31,8 @@ from core.basic_models.actions.external_actions import ExternalAction from core.basic_models.actions.push_action import PushAction, PushAuthenticationActionHttp, PushActionHttp, \ GetRuntimePermissionsAction -from core.basic_models.actions.string_actions import StringAction, AfinaAnswerAction, SDKAnswer, \ - SDKAnswerToUser, NodeAction +from core.basic_models.actions.string_actions import StringAction, StringFileUnifiedTemplateAction, \ + AfinaAnswerAction, SDKAnswer, SDKAnswerToUser, NodeAction from core.basic_models.answer_items.answer_items import SdkAnswerItem, items_factory, answer_items, BubbleText, \ ItemCard, PronounceText, SuggestText, SuggestDeepLink from core.basic_models.requirement.basic_requirements import requirement_factory, Requirement, requirements @@ -39,6 +40,7 @@ from core.text_preprocessing.base import BaseTextPreprocessingResult from core.unified_template.unified_template import UnifiedTemplate, UNIFIED_TEMPLATE_TYPE_NAME from smart_kit.action.http import HTTPRequestAction +from smart_kit import configs from smart_kit.request.kafka_request import SmartKitKafkaRequest from smart_kit.utils.picklable_mock import PicklableMock, PicklableMagicMock @@ -232,6 +234,48 @@ async def test_string_action(self): self.assertEqual(expected[0].name, result[0].name) self.assertEqual(expected[0].payload, result[0].payload) + async def test_string_file_unified_template_action_inline(self): + expected = [Command("cmd_id", {"item": "template", "params": "params"})] + user = PicklableMagicMock() + template = PicklableMock() + template.get_template = Mock(return_value=["nlpp.payload.personInfo.identityCard"]) + user.descriptions = {"render_templates": template} + params = {"params": "params"} + user.parametrizer = MockSimpleParametrizer(user, {"data": params}) + items = {"command": "cmd_id", "nodes": {"item": "template", "params": "{{params}}"}} + action = StringFileUnifiedTemplateAction(items) + result = [] + async for command in action.run(user, None): + result.append(command) + self.assertEqual(expected[0].name, result[0].name) + self.assertEqual(expected[0].payload, result[0].payload) + + async def test_string_file_unified_template_action_from_file(self): + expected = [Command("cmd_id", {"item": "template", "params": "params"})] + user = PicklableMagicMock() + template = PicklableMock() + template.get_template = Mock(return_value=["nlpp.payload.personInfo.identityCard"]) + user.descriptions = {"render_templates": template} + params = {"params": "params"} + user.parametrizer = MockSimpleParametrizer(user, {"data": params}) + items = { + "command": "cmd_id", + "nodes": { + "type": "unified_template", + "file": "test_string_file_unified_template_action.jinja2", + "loader": "json" + } + } + static_path = os.path.join(os.path.dirname(configs.__file__), os.pardir, os.pardir, "tests", "static") + cfg = MagicMock(STATIC_PATH=static_path) + configs.get_app_config = PicklableMagicMock(return_value=cfg) + action = StringFileUnifiedTemplateAction(items) + result = [] + async for command in action.run(user, None): + result.append(command) + self.assertEqual(expected[0].name, result[0].name) + self.assertEqual(expected[0].payload, result[0].payload) + async def test_else_action_if(self): registered_factories[Requirement] = requirement_factory requirements["test"] = MockRequirement @@ -632,7 +676,9 @@ async def test_push_authentication_action_http_call(self, request_mock: Mock): 'headers': { 'RqUID': '3f68e69e-351b-4e6f-b251-480f0cb08a5d', - 'Authorization': 'Basic QCE4OUZCLjRENjIuM0E1MS5BOUVCITAwMDEhOTZFNS5BRTg5ITAwMDghQjFBRi5EQjdELjE1ODYuODRGMzpzZWNyZXQ=' # noqa + 'Authorization': 'Basic QCE4OUZCLjRENjIuM0E1MS5BOUVCITAwMDEhOTZFNS5' + 'BRTg5ITAwMDghQjFBRi5EQjdELjE1ODYuODRGMzpzZWNyZXQ=' + # noqa } } } diff --git a/tests/core_tests/requirements_test/test_requirements.py b/tests/core_tests/requirements_test/test_requirements.py index d2686a05..0a8c61a9 100644 --- a/tests/core_tests/requirements_test/test_requirements.py +++ b/tests/core_tests/requirements_test/test_requirements.py @@ -2,7 +2,7 @@ import os import unittest from time import time -from unittest.mock import Mock, patch +from unittest.mock import Mock, patch, MagicMock import smart_kit from core.basic_models.classifiers.basic_classifiers import ExternalClassifier @@ -18,6 +18,7 @@ NormalizedTextInSetRequirement from core.basic_models.variables.variables import Variables from core.model.registered import registered_factories +from smart_kit import configs from smart_kit.text_preprocessing.local_text_normalizer import LocalTextNormalizer from smart_kit.utils.picklable_mock import PicklableMock @@ -244,6 +245,30 @@ def test_template_req_raise(self): with self.assertRaises(TypeError): _ = requirement.check(None, user) + def test_template_req_from_file(self): + items = { + "template": { + "type": "unified_template", + "file": "test_unified_template_requirement.jinja2", + "loader": "json" + } + } + static_path = os.path.join(os.path.dirname(configs.__file__), os.pardir, os.pardir, "tests", "static") + cfg = MagicMock(STATIC_PATH=static_path) + configs.get_app_config = MagicMock(return_value=cfg) + requirement = TemplateRequirement(items) + params = { + "payload": { + "groupCode": "BROKER", + "murexIds": ["AAA", "BBB"], + "message": " BBB " + } + } + user = PicklableMock() + user.parametrizer = PicklableMock() + user.parametrizer.collect = Mock(return_value=params) + self.assertTrue(requirement.check(None, user)) + def test_rolling_requirement_true(self): user = PicklableMock() user.id = "353454" diff --git a/tests/static/references/templates/test_string_file_unified_template_action.jinja2 b/tests/static/references/templates/test_string_file_unified_template_action.jinja2 new file mode 100644 index 00000000..3f4fc9ed --- /dev/null +++ b/tests/static/references/templates/test_string_file_unified_template_action.jinja2 @@ -0,0 +1,4 @@ +{ + "item": "template", + "params": "{{params}}" +} diff --git a/tests/static/references/templates/test_unified_template_requirement.jinja2 b/tests/static/references/templates/test_unified_template_requirement.jinja2 new file mode 100644 index 00000000..63d4ff41 --- /dev/null +++ b/tests/static/references/templates/test_unified_template_requirement.jinja2 @@ -0,0 +1,3 @@ +"{{ + payload.message.strip() in payload.murexIds +}}"