• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright (c) 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 operator
19from functools import reduce
20from typing import Any, Iterable, Optional, Tuple, Type
21
22import rich.repr
23
24from .base import MirrorMeta, _arkts_str
25from .type_cache import type_cache
26
27
28class ObjectMeta(MirrorMeta):
29
30    def __new__(mcls, name: str, bases: Tuple[Type], namespace: dict[str, Any], **kwargs: Any):
31        namespace = {
32            **namespace,
33            "__eq__": ObjectMeta.__eq__,
34            "__repr__": ObjectMeta.__repr__,
35            "__rich_repr__": ObjectMeta.__rich_repr__,
36            "__arkts_repr__": ObjectMeta.__arkts_repr__,
37            "__arkts_str__": ObjectMeta.__arkts_str__,
38            "__hash__": ObjectMeta.__hash__,
39        }
40        cls = super().__new__(mcls, name, bases, namespace, **kwargs)
41        return rich.repr.auto(cls)
42
43    # CC-OFFNXT(G.NAM.05) Standard function from rich package
44    def __rich_repr__(self) -> Iterable[Tuple[str, Any]]:
45        return [(name, attr) for name, attr in vars(self).items() if not callable(attr)]
46
47    # CC-OFFNXT(G.NAM.05) internal function name
48    def __arkts_repr__(self) -> Iterable[Tuple[str, Any]]:
49        return [
50            (name, attr)
51            for name, attr in [(name, getattr(self, name)) for name in dir(self) if not name.startswith("_")]
52            if not callable(attr)
53        ]
54
55    def __eq__(self, other: Any) -> bool:
56        if type(self).__name__ != type(other).__name__:
57            return False
58        if vars(self).keys() != vars(other).keys():
59            return False
60        for k, v in vars(self).items():
61            if v != vars(other).get(k, None):
62                return False
63        return True
64
65    # CC-OFFNXT(G.NAM.05) internal function name
66    def __arkts_str__(self, *, depth: Optional[int] = None) -> str:
67        if depth == 0:
68            return f"{self.__class__.__name__} {{...}}"
69        next_depth = depth - 1 if depth is not None else None
70        params = ", ".join([f"{name}: {_arkts_str(param, depth=next_depth)}" for name, param in self.__arkts_repr__()])
71        return f"{self.__class__.__name__} {{{params}}}"
72
73    def __hash__(self) -> int:
74        return reduce(operator.xor, [hash(k) for k in vars(self).keys()]) ^ hash(type(self).__name__)
75
76
77class Object(metaclass=ObjectMeta):
78    """Base class for ArkTS mirror classes."""
79
80    pass
81
82
83@type_cache(scope="test")
84def mirror_object_type(cls_name: str, /, **kwargs) -> Type:
85    t = ObjectMeta(cls_name, (Object,), kwargs, module=__package__)
86    return t
87
88
89def mirror_object(cls_name: str, /, **kwargs):
90    t = mirror_object_type(cls_name, **dict.fromkeys(kwargs.keys()))
91    obj = t()
92    for k, v in kwargs.items():
93        setattr(obj, k, v)
94    return obj
95