1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3 4# Copyright (c) 2021-2024 Huawei Device Co., Ltd. 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18import os 19from pathlib import Path 20from dataclasses import dataclass 21from typing import Dict, Any, List, Tuple 22import yaml 23 24from jinja2 import Environment, select_autoescape, TemplateSyntaxError 25 26from runner.utils import read_file 27from runner.plugins.ets.utils.exceptions import \ 28 InvalidFileFormatException, UnknownTemplateException, InvalidMetaException 29from runner.plugins.ets.utils.constants import META_COPYRIGHT, META_START_STRING, \ 30 META_END_STRING, META_START_COMMENT, META_END_COMMENT 31 32 33ROOT_PATH = Path(os.path.realpath(os.path.dirname(__file__))) 34BENCH_PATH = ROOT_PATH / "test_template.tpl" 35COPYRIGHT_PATH = ROOT_PATH / "copyright.txt" 36 37 38@dataclass 39class Meta: 40 config: Dict[str, Any] 41 code: str 42 43 44class Template: 45 def __init__(self, test_path: Path, params: Dict[str, Any]) -> None: 46 self.test_path = str(test_path) 47 self.text = read_file(test_path) 48 self.__params = params 49 self.__jinja_env = Environment(autoescape=select_autoescape()) 50 51 if self.is_copyright: 52 self.__copyright = read_file(COPYRIGHT_PATH) 53 else: 54 self.__copyright, out_content = self.__get_in_out_content(self.text, META_START_COMMENT, META_END_COMMENT) 55 self.text = out_content.strip() 56 57 @property 58 def is_copyright(self) -> bool: 59 return META_COPYRIGHT not in self.text 60 61 def render_template(self) -> List[str]: 62 try: 63 template = self.__jinja_env.from_string(self.text) 64 rendered = template.render(**self.__params).strip() 65 except TemplateSyntaxError as exc: 66 raise InvalidFileFormatException(message=f"Template Syntax Error: {exc.message}", 67 filepath=self.test_path) from exc 68 except Exception as exc: 69 raise UnknownTemplateException(filepath=self.test_path, exception=exc) from exc 70 71 meta_start = META_START_STRING if self.is_copyright else META_START_COMMENT 72 return [meta_start + e for e in rendered.split(meta_start) if e] 73 74 def generate_test(self, test: str, fullname: str) -> str: 75 meta = self.__get_meta(test) 76 meta.config["name"] = fullname 77 yaml_content = yaml.dump(meta.config) 78 79 bench_template = read_file(BENCH_PATH) 80 bench_code = bench_template.format( 81 copyright=self.__copyright.strip(), 82 description=yaml_content.strip(), 83 code=meta.code.strip()) 84 return bench_code 85 86 def __get_in_out_content(self, text: str, meta_start: str, meta_end: str) -> Tuple[str, str]: 87 start, end = text.find(meta_start), text.find(meta_end) 88 if start > end or start == -1 or end == -1: 89 raise InvalidMetaException("Invalid meta or meta does not exist") 90 inside_content = text[start + len(meta_start):end] 91 outside_content = text[:start] + text[end + len(meta_end):] 92 return inside_content, outside_content 93 94 def __get_meta(self, text: str) -> Meta: 95 test_text = self.__replace_symbols(text) 96 inside_content, outside_content = self.__get_in_out_content(test_text, META_START_STRING, META_END_STRING) 97 return Meta(config=self.__parse_yaml(inside_content), code=outside_content) 98 99 def __replace_symbols(self, text: str) -> str: 100 codes = [("'", '''), ('"', '"'), ('>', '>'), ('<', '<'), ('&', '&')] 101 for new, old in codes: 102 text = text.replace(old, new) 103 return text 104 105 def __parse_yaml(self, text: str) -> Dict[str, Any]: 106 try: 107 result: Dict[str, Any] = yaml.safe_load(text) 108 except Exception as exc: 109 raise InvalidFileFormatException(message=f"Could not load YAML in test params: {str(exc)}", 110 filepath=self.test_path) from exc 111 return result 112