123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- # Copyright 2021-2024 Avaiga Private Limited
- #
- # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
- # the License. You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
- # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
- # specific language governing permissions and limitations under the License.
- import inspect
- import json
- import os
- import sys
- import types
- import typing as t
- from taipy.logger._taipy_logger import _TaipyLogger
- from ..utils.singleton import _Singleton
- from ..utils.viselements import VisElements, resolve_inherits
- from ._element import _Block, _Control
- if t.TYPE_CHECKING:
- from ..extension.library import ElementLibrary
- class _ElementApiGenerator(object, metaclass=_Singleton):
- def __init__(self) -> None:
- self.__module: t.Optional[types.ModuleType] = None
- @staticmethod
- def find_default_property(property_list: t.List[t.Dict[str, t.Any]]) -> str:
- for property in property_list:
- if "default_property" in property and property["default_property"] is True:
- return property["name"]
- return ""
- def add_default(self):
- current_frame = inspect.currentframe()
- error_message = "Cannot generate elements API for the current module"
- if current_frame is None:
- raise RuntimeError(f"{error_message}: No frame found.")
- if current_frame.f_back is None:
- raise RuntimeError(f"{error_message}: taipy-gui module not found.")
- module_name = current_frame.f_back.f_globals["__name__"]
- self.__module = module = sys.modules[module_name]
- with open(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "viselements.json"))) as f:
- viselements_json = json.load(f)
- if "blocks" not in viselements_json or "controls" not in viselements_json:
- raise RuntimeError(f"{error_message}: Invalid viselements.json file.")
- viselements = resolve_inherits(t.cast(VisElements, viselements_json))
- for blockElement in viselements["blocks"]:
- default_property = _ElementApiGenerator.find_default_property(blockElement[1]["properties"])
- setattr(
- module,
- blockElement[0],
- _ElementApiGenerator.create_block_api(blockElement[0], blockElement[0], default_property),
- )
- for controlElement in viselements["controls"]:
- default_property = _ElementApiGenerator.find_default_property(controlElement[1]["properties"])
- setattr(
- module,
- controlElement[0],
- _ElementApiGenerator.create_control_api(controlElement[0], controlElement[0], default_property),
- )
- def add_library(self, library: "ElementLibrary"):
- library_name = library.get_name()
- if self.__module is None:
- _TaipyLogger._get_logger().info(
- f"Python API for extension library '{library_name}' is not available. To fix this, import 'taipy.gui.builder' before importing the extension library." # noqa: E501
- )
- return
- library_module = getattr(self.__module, library_name, None)
- if library_module is None:
- library_module = types.ModuleType(library_name)
- setattr(self.__module, library_name, library_module)
- for element_name, element in library.get_elements().items():
- setattr(
- library_module,
- element_name,
- _ElementApiGenerator().create_control_api(
- element_name, f"{library_name}.{element_name}", element.default_attribute
- ),
- )
- # Allow element to be accessed from the root module
- if hasattr(self.__module, element_name):
- _TaipyLogger()._get_logger().info(
- f"Can't add element `{element_name}` of library `{library_name}` to the root of Builder API as another element with the same name already exists." # noqa: E501
- )
- continue
- setattr(self.__module, element_name, getattr(library_module, element_name))
- @staticmethod
- def create_block_api(
- classname: str,
- element_name: str,
- default_property: str,
- ):
- return _ElementApiGenerator.create_element_api(classname, element_name, default_property, _Block)
- @staticmethod
- def create_control_api(
- classname: str,
- element_name: str,
- default_property: str,
- ):
- return _ElementApiGenerator.create_element_api(classname, element_name, default_property, _Control)
- @staticmethod
- def create_element_api(
- classname: str,
- element_name: str,
- default_property: str,
- ElementBaseClass: t.Union[t.Type[_Block], t.Type[_Control]],
- ):
- return type(
- classname,
- (ElementBaseClass,),
- {
- "_ELEMENT_NAME": element_name,
- "_DEFAULT_PROPERTY": default_property,
- },
- )
|