deepfos 1.1.60__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- deepfos/__init__.py +6 -0
- deepfos/_version.py +21 -0
- deepfos/algo/__init__.py +0 -0
- deepfos/algo/graph.py +171 -0
- deepfos/algo/segtree.py +31 -0
- deepfos/api/V1_1/__init__.py +0 -0
- deepfos/api/V1_1/business_model.py +119 -0
- deepfos/api/V1_1/dimension.py +599 -0
- deepfos/api/V1_1/models/__init__.py +0 -0
- deepfos/api/V1_1/models/business_model.py +1033 -0
- deepfos/api/V1_1/models/dimension.py +2768 -0
- deepfos/api/V1_2/__init__.py +0 -0
- deepfos/api/V1_2/dimension.py +285 -0
- deepfos/api/V1_2/models/__init__.py +0 -0
- deepfos/api/V1_2/models/dimension.py +2923 -0
- deepfos/api/__init__.py +0 -0
- deepfos/api/account.py +167 -0
- deepfos/api/accounting_engines.py +147 -0
- deepfos/api/app.py +626 -0
- deepfos/api/approval_process.py +198 -0
- deepfos/api/base.py +983 -0
- deepfos/api/business_model.py +160 -0
- deepfos/api/consolidation.py +129 -0
- deepfos/api/consolidation_process.py +106 -0
- deepfos/api/datatable.py +341 -0
- deepfos/api/deep_pipeline.py +61 -0
- deepfos/api/deepconnector.py +36 -0
- deepfos/api/deepfos_task.py +92 -0
- deepfos/api/deepmodel.py +188 -0
- deepfos/api/dimension.py +486 -0
- deepfos/api/financial_model.py +319 -0
- deepfos/api/journal_model.py +119 -0
- deepfos/api/journal_template.py +132 -0
- deepfos/api/memory_financial_model.py +98 -0
- deepfos/api/models/__init__.py +3 -0
- deepfos/api/models/account.py +483 -0
- deepfos/api/models/accounting_engines.py +756 -0
- deepfos/api/models/app.py +1338 -0
- deepfos/api/models/approval_process.py +1043 -0
- deepfos/api/models/base.py +234 -0
- deepfos/api/models/business_model.py +805 -0
- deepfos/api/models/consolidation.py +711 -0
- deepfos/api/models/consolidation_process.py +248 -0
- deepfos/api/models/datatable_mysql.py +427 -0
- deepfos/api/models/deep_pipeline.py +55 -0
- deepfos/api/models/deepconnector.py +28 -0
- deepfos/api/models/deepfos_task.py +386 -0
- deepfos/api/models/deepmodel.py +308 -0
- deepfos/api/models/dimension.py +1576 -0
- deepfos/api/models/financial_model.py +1796 -0
- deepfos/api/models/journal_model.py +341 -0
- deepfos/api/models/journal_template.py +854 -0
- deepfos/api/models/memory_financial_model.py +478 -0
- deepfos/api/models/platform.py +178 -0
- deepfos/api/models/python.py +221 -0
- deepfos/api/models/reconciliation_engine.py +411 -0
- deepfos/api/models/reconciliation_report.py +161 -0
- deepfos/api/models/role_strategy.py +884 -0
- deepfos/api/models/smartlist.py +237 -0
- deepfos/api/models/space.py +1137 -0
- deepfos/api/models/system.py +1065 -0
- deepfos/api/models/variable.py +463 -0
- deepfos/api/models/workflow.py +946 -0
- deepfos/api/platform.py +199 -0
- deepfos/api/python.py +90 -0
- deepfos/api/reconciliation_engine.py +181 -0
- deepfos/api/reconciliation_report.py +64 -0
- deepfos/api/role_strategy.py +234 -0
- deepfos/api/smartlist.py +69 -0
- deepfos/api/space.py +582 -0
- deepfos/api/system.py +372 -0
- deepfos/api/variable.py +154 -0
- deepfos/api/workflow.py +264 -0
- deepfos/boost/__init__.py +6 -0
- deepfos/boost/py_jstream.py +89 -0
- deepfos/boost/py_pandas.py +20 -0
- deepfos/cache.py +121 -0
- deepfos/config.py +6 -0
- deepfos/core/__init__.py +27 -0
- deepfos/core/cube/__init__.py +10 -0
- deepfos/core/cube/_base.py +462 -0
- deepfos/core/cube/constants.py +21 -0
- deepfos/core/cube/cube.py +408 -0
- deepfos/core/cube/formula.py +707 -0
- deepfos/core/cube/syscube.py +532 -0
- deepfos/core/cube/typing.py +7 -0
- deepfos/core/cube/utils.py +238 -0
- deepfos/core/dimension/__init__.py +11 -0
- deepfos/core/dimension/_base.py +506 -0
- deepfos/core/dimension/dimcreator.py +184 -0
- deepfos/core/dimension/dimension.py +472 -0
- deepfos/core/dimension/dimexpr.py +271 -0
- deepfos/core/dimension/dimmember.py +155 -0
- deepfos/core/dimension/eledimension.py +22 -0
- deepfos/core/dimension/filters.py +99 -0
- deepfos/core/dimension/sysdimension.py +168 -0
- deepfos/core/logictable/__init__.py +5 -0
- deepfos/core/logictable/_cache.py +141 -0
- deepfos/core/logictable/_operator.py +663 -0
- deepfos/core/logictable/nodemixin.py +673 -0
- deepfos/core/logictable/sqlcondition.py +609 -0
- deepfos/core/logictable/tablemodel.py +497 -0
- deepfos/db/__init__.py +36 -0
- deepfos/db/cipher.py +660 -0
- deepfos/db/clickhouse.py +191 -0
- deepfos/db/connector.py +195 -0
- deepfos/db/daclickhouse.py +171 -0
- deepfos/db/dameng.py +101 -0
- deepfos/db/damysql.py +189 -0
- deepfos/db/dbkits.py +358 -0
- deepfos/db/deepengine.py +99 -0
- deepfos/db/deepmodel.py +82 -0
- deepfos/db/deepmodel_kingbase.py +83 -0
- deepfos/db/edb.py +214 -0
- deepfos/db/gauss.py +83 -0
- deepfos/db/kingbase.py +83 -0
- deepfos/db/mysql.py +184 -0
- deepfos/db/oracle.py +131 -0
- deepfos/db/postgresql.py +192 -0
- deepfos/db/sqlserver.py +99 -0
- deepfos/db/utils.py +135 -0
- deepfos/element/__init__.py +89 -0
- deepfos/element/accounting.py +348 -0
- deepfos/element/apvlprocess.py +215 -0
- deepfos/element/base.py +398 -0
- deepfos/element/bizmodel.py +1269 -0
- deepfos/element/datatable.py +2467 -0
- deepfos/element/deep_pipeline.py +186 -0
- deepfos/element/deepconnector.py +59 -0
- deepfos/element/deepmodel.py +1806 -0
- deepfos/element/dimension.py +1254 -0
- deepfos/element/fact_table.py +427 -0
- deepfos/element/finmodel.py +1485 -0
- deepfos/element/journal.py +840 -0
- deepfos/element/journal_template.py +943 -0
- deepfos/element/pyscript.py +412 -0
- deepfos/element/reconciliation.py +553 -0
- deepfos/element/rolestrategy.py +243 -0
- deepfos/element/smartlist.py +457 -0
- deepfos/element/variable.py +756 -0
- deepfos/element/workflow.py +560 -0
- deepfos/exceptions/__init__.py +239 -0
- deepfos/exceptions/hook.py +86 -0
- deepfos/lazy.py +104 -0
- deepfos/lazy_import.py +84 -0
- deepfos/lib/__init__.py +0 -0
- deepfos/lib/_javaobj.py +366 -0
- deepfos/lib/asynchronous.py +879 -0
- deepfos/lib/concurrency.py +107 -0
- deepfos/lib/constant.py +39 -0
- deepfos/lib/decorator.py +310 -0
- deepfos/lib/deepchart.py +778 -0
- deepfos/lib/deepux.py +477 -0
- deepfos/lib/discovery.py +273 -0
- deepfos/lib/edb_lexer.py +789 -0
- deepfos/lib/eureka.py +156 -0
- deepfos/lib/filterparser.py +751 -0
- deepfos/lib/httpcli.py +106 -0
- deepfos/lib/jsonstreamer.py +80 -0
- deepfos/lib/msg.py +394 -0
- deepfos/lib/nacos.py +225 -0
- deepfos/lib/patch.py +92 -0
- deepfos/lib/redis.py +241 -0
- deepfos/lib/serutils.py +181 -0
- deepfos/lib/stopwatch.py +99 -0
- deepfos/lib/subtask.py +572 -0
- deepfos/lib/sysutils.py +703 -0
- deepfos/lib/utils.py +1003 -0
- deepfos/local.py +160 -0
- deepfos/options.py +670 -0
- deepfos/translation.py +237 -0
- deepfos-1.1.60.dist-info/METADATA +33 -0
- deepfos-1.1.60.dist-info/RECORD +175 -0
- deepfos-1.1.60.dist-info/WHEEL +5 -0
- deepfos-1.1.60.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import contextvars
|
|
2
|
+
import threading
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
5
|
+
import copy
|
|
6
|
+
|
|
7
|
+
from deepfos.lib.constant import UNSET
|
|
8
|
+
from deepfos.local import Proxy
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ThreadCtxExecutor(ThreadPoolExecutor):
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
max_workers=None,
|
|
15
|
+
thread_name_prefix='',
|
|
16
|
+
initargs=()
|
|
17
|
+
):
|
|
18
|
+
self.context = contextvars.copy_context()
|
|
19
|
+
super().__init__(
|
|
20
|
+
max_workers=max_workers,
|
|
21
|
+
thread_name_prefix=thread_name_prefix,
|
|
22
|
+
initializer=self._set_context,
|
|
23
|
+
initargs=initargs
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
def _set_context(self):
|
|
27
|
+
for var, value in self.context.items():
|
|
28
|
+
var.set(value)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class _Local:
|
|
32
|
+
__slots__ = ('_thread_local', 'default')
|
|
33
|
+
|
|
34
|
+
def __init__(self):
|
|
35
|
+
self.default = None
|
|
36
|
+
self._thread_local = {}
|
|
37
|
+
|
|
38
|
+
def set_current(self, value):
|
|
39
|
+
key = threading.get_ident()
|
|
40
|
+
self._thread_local[key] = value
|
|
41
|
+
|
|
42
|
+
def get_current(self):
|
|
43
|
+
key = threading.get_ident()
|
|
44
|
+
if key not in self._thread_local:
|
|
45
|
+
self._thread_local[key] = copy.deepcopy(self.default)
|
|
46
|
+
return self._thread_local[key]
|
|
47
|
+
|
|
48
|
+
def set_default(self, value):
|
|
49
|
+
if threading.get_ident() not in self._thread_local:
|
|
50
|
+
self.default = value
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class _LocalMemo:
|
|
54
|
+
__slots__ = '_memo'
|
|
55
|
+
|
|
56
|
+
def __init__(self):
|
|
57
|
+
self._memo = defaultdict(_Local)
|
|
58
|
+
|
|
59
|
+
def get(self, attr):
|
|
60
|
+
if attr not in self._memo:
|
|
61
|
+
raise AttributeError(attr)
|
|
62
|
+
return self._memo[attr]
|
|
63
|
+
|
|
64
|
+
def set(self, attr, value):
|
|
65
|
+
tlocal = self._memo[attr]
|
|
66
|
+
tlocal.set_default(copy.deepcopy(value))
|
|
67
|
+
tlocal.set_current(value)
|
|
68
|
+
|
|
69
|
+
def __contains__(self, item):
|
|
70
|
+
return item in self._memo
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class ThreadLocal:
|
|
74
|
+
"""定义线程隔离的变量"""
|
|
75
|
+
def __init__(self):
|
|
76
|
+
self.__dict__['_memo'] = _LocalMemo()
|
|
77
|
+
|
|
78
|
+
def __setattr__(self, key, value):
|
|
79
|
+
self._memo.set(key, value)
|
|
80
|
+
|
|
81
|
+
def __getattr__(self, item):
|
|
82
|
+
_local = self._memo.get(item)
|
|
83
|
+
return _local.get_current()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class ParallelProxy(Proxy):
|
|
87
|
+
def __init__(self, payload):
|
|
88
|
+
object.__setattr__(self, '_ParallelProxy__result', UNSET)
|
|
89
|
+
object.__setattr__(self, '_ParallelProxy__payload', payload)
|
|
90
|
+
|
|
91
|
+
def __await__(self):
|
|
92
|
+
coro = self.__payload
|
|
93
|
+
return coro.__await__()
|
|
94
|
+
|
|
95
|
+
def _get_current_object(self):
|
|
96
|
+
if self.__result is not UNSET:
|
|
97
|
+
return self.__result
|
|
98
|
+
|
|
99
|
+
object.__setattr__(self, '_ParallelProxy__result', self.__payload.result())
|
|
100
|
+
return self.__result
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def compute(obj):
|
|
104
|
+
try:
|
|
105
|
+
return obj._get_current_object() # noqa
|
|
106
|
+
except AttributeError:
|
|
107
|
+
return obj
|
deepfos/lib/constant.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from requests.structures import CaseInsensitiveDict
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
UNSET = object()
|
|
5
|
+
DFLT_DATA_COLUMN = 'data'
|
|
6
|
+
COLUMN_USAGE_FIELD = 'VirtualMeasure_220922'
|
|
7
|
+
DFLT_COMMENT_COLUMN = 'VirtualMeasure_220922'
|
|
8
|
+
USED_FOR_COMMENT = 'comment'
|
|
9
|
+
USED_FOR_DATA = 'data'
|
|
10
|
+
DFLT_NAME_COLUMN = 'name'
|
|
11
|
+
DFLT_PNAME_COLUMN = 'parent_name'
|
|
12
|
+
SHAREDMEMBER = 'sharedmember'
|
|
13
|
+
|
|
14
|
+
SHAREDMEMBERV12 = 'sharedMember'
|
|
15
|
+
DFLT_PNAME_COLUMN_V12 = 'parentName'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
VIEW = "View"
|
|
19
|
+
VIEW_DICT = CaseInsensitiveDict(view=VIEW)
|
|
20
|
+
HIERARCHY = CaseInsensitiveDict(
|
|
21
|
+
Base="Base",
|
|
22
|
+
IBase="IBase",
|
|
23
|
+
Children="Children",
|
|
24
|
+
IChildren="IChildren",
|
|
25
|
+
Descendant="Descendant",
|
|
26
|
+
IDescendant="IDescendant",
|
|
27
|
+
)
|
|
28
|
+
ROOT = "#root"
|
|
29
|
+
ACCEPT_LANS = [
|
|
30
|
+
'zh-cn',
|
|
31
|
+
'en'
|
|
32
|
+
]
|
|
33
|
+
RE_DIMNAME_PARSER = re.compile('(?P<name>.*){(?P<body>.*)}')
|
|
34
|
+
RE_SERVER_NAME_PARSER = re.compile('^[a-z-]+(?P<ver>[0-9-]+)$', re.IGNORECASE)
|
|
35
|
+
RE_MODULEID_PARSER = re.compile('^[A-Z]+(?P<ver>[0-9_]+)$', re.IGNORECASE)
|
|
36
|
+
RE_SYS_SERVER_PARSER = re.compile('^(?:https?://)?([a-z-]+-server)$', re.IGNORECASE)
|
|
37
|
+
DECIMAL_COL = 'decimal_val'
|
|
38
|
+
STRING_COL = 'string_val'
|
|
39
|
+
INDEX_FIELD = 'index'
|
deepfos/lib/decorator.py
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"""装饰器"""
|
|
2
|
+
|
|
3
|
+
import threading
|
|
4
|
+
import functools
|
|
5
|
+
import warnings
|
|
6
|
+
import weakref
|
|
7
|
+
import inspect
|
|
8
|
+
|
|
9
|
+
from typing import Any, Callable, TypeVar, Tuple, Generic
|
|
10
|
+
|
|
11
|
+
from cachetools import LRUCache
|
|
12
|
+
from cachetools.keys import hashkey
|
|
13
|
+
|
|
14
|
+
from deepfos.cache import Manager
|
|
15
|
+
from deepfos.exceptions import eliminate_from_traceback
|
|
16
|
+
from deepfos.lib.asynchronous import evloop
|
|
17
|
+
from deepfos.lib.constant import UNSET
|
|
18
|
+
from deepfos.lib.utils import repr_version
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
'cached_property',
|
|
22
|
+
'cached_class_property',
|
|
23
|
+
'singleton',
|
|
24
|
+
'flagmethod',
|
|
25
|
+
'deprecated',
|
|
26
|
+
'lru_cache',
|
|
27
|
+
]
|
|
28
|
+
F = TypeVar('F', bound=Callable[..., Any])
|
|
29
|
+
RT = TypeVar('RT')
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# noinspection PyPep8Naming
|
|
33
|
+
@eliminate_from_traceback
|
|
34
|
+
class cached_property(Generic[RT]): # pragma: no cover
|
|
35
|
+
def __init__(self, func: Callable[[Any], RT]):
|
|
36
|
+
self.__doc__ = getattr(func, "__doc__")
|
|
37
|
+
self.func = func
|
|
38
|
+
self.attrname = None
|
|
39
|
+
self.lock = threading.RLock()
|
|
40
|
+
|
|
41
|
+
def __set_name__(self, owner, name):
|
|
42
|
+
self.attrname = name
|
|
43
|
+
|
|
44
|
+
def __get__(self, obj, cls) -> RT:
|
|
45
|
+
if obj is None:
|
|
46
|
+
return self
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
cache = obj.__dict__
|
|
50
|
+
except AttributeError:
|
|
51
|
+
raise TypeError(
|
|
52
|
+
f"No '__dict__' attribute on {type(obj).__name__!r} "
|
|
53
|
+
f"instance to cache {self.attrname!r} property.") from None
|
|
54
|
+
|
|
55
|
+
val = cache.get(self.attrname, UNSET)
|
|
56
|
+
if val is UNSET:
|
|
57
|
+
# If in different thread,
|
|
58
|
+
# deadlock may happen when there are future properties in function
|
|
59
|
+
# while being used in other thread in the same time
|
|
60
|
+
if evloop.in_same_thread():
|
|
61
|
+
with self.lock:
|
|
62
|
+
# check if another thread filled cache while we awaited lock
|
|
63
|
+
val = cache.get(self.attrname, UNSET)
|
|
64
|
+
if val is UNSET:
|
|
65
|
+
val = self.func(obj)
|
|
66
|
+
setattr(obj, self.attrname, val)
|
|
67
|
+
else:
|
|
68
|
+
val = self.func(obj)
|
|
69
|
+
setattr(obj, self.attrname, val)
|
|
70
|
+
return val
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# noinspection PyPep8Naming
|
|
74
|
+
class cached_class_property(Generic[RT]): # pragma: no cover
|
|
75
|
+
def __init__(self, func: Callable[[Any], RT]):
|
|
76
|
+
self.__doc__ = getattr(func, "__doc__")
|
|
77
|
+
self.func = func
|
|
78
|
+
|
|
79
|
+
def __get__(self, obj, cls) -> RT:
|
|
80
|
+
value = self.func(obj)
|
|
81
|
+
# set attribute to class
|
|
82
|
+
setattr(cls, self.func.__name__, value)
|
|
83
|
+
return value
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# noinspection PydanticTypeChecker
|
|
87
|
+
def singleton(cls):
|
|
88
|
+
"""单例"""
|
|
89
|
+
cls.__new_original__ = cls.__new__
|
|
90
|
+
singleton_lock = threading.Lock()
|
|
91
|
+
|
|
92
|
+
@functools.wraps(cls.__new__)
|
|
93
|
+
def singleton_new(cls_, *args, **kwargs):
|
|
94
|
+
with singleton_lock:
|
|
95
|
+
it = cls_.__dict__.get('__it__')
|
|
96
|
+
if it is not None:
|
|
97
|
+
return it
|
|
98
|
+
|
|
99
|
+
cls_.__it__ = it = cls_.__new_original__(cls_)
|
|
100
|
+
it.__init_original__(*args, **kwargs)
|
|
101
|
+
return it
|
|
102
|
+
|
|
103
|
+
cls.__new__ = singleton_new
|
|
104
|
+
cls.__init_original__ = cls.__init__
|
|
105
|
+
cls.__init__ = object.__init__
|
|
106
|
+
return cls
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class FlagMethod:
|
|
110
|
+
"""描述符。进出方法时设置flag。
|
|
111
|
+
|
|
112
|
+
类似于 :func:`flagmethod`,但是支持嵌套调用。
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
flag: 作为标识的属性名
|
|
116
|
+
method: 需要装饰的方法
|
|
117
|
+
|
|
118
|
+
>>> def nested_flagmethod(flag):
|
|
119
|
+
... def wrapper(method):
|
|
120
|
+
... return FlagMethod(flag, method)
|
|
121
|
+
... return wrapper
|
|
122
|
+
|
|
123
|
+
>>> class Example:
|
|
124
|
+
... def __init__(self):
|
|
125
|
+
... self.flag = False
|
|
126
|
+
...
|
|
127
|
+
... @nested_flagmethod('flag')
|
|
128
|
+
... def foo(self, arg):
|
|
129
|
+
... pass
|
|
130
|
+
...
|
|
131
|
+
... def bar(self):
|
|
132
|
+
... print(self.flag)
|
|
133
|
+
...
|
|
134
|
+
>>> example = Example()
|
|
135
|
+
>>> example.foo(example.bar())
|
|
136
|
+
True
|
|
137
|
+
>>> example.flag
|
|
138
|
+
False
|
|
139
|
+
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
def __init__(self, flag: str, method):
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
flag:
|
|
147
|
+
method:
|
|
148
|
+
"""
|
|
149
|
+
self.flag = flag
|
|
150
|
+
self.method = method
|
|
151
|
+
|
|
152
|
+
def __get__(self, instance, owner):
|
|
153
|
+
if instance is None:
|
|
154
|
+
return self
|
|
155
|
+
setattr(instance, self.flag, True)
|
|
156
|
+
self.obj = weakref.ref(instance)
|
|
157
|
+
return self
|
|
158
|
+
|
|
159
|
+
def __call__(self, *args, **kwargs):
|
|
160
|
+
try:
|
|
161
|
+
rslt = self.method(self.obj(), *args, **kwargs)
|
|
162
|
+
finally:
|
|
163
|
+
setattr(self.obj(), self.flag, False)
|
|
164
|
+
return rslt
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def flagmethod(flag: str) -> Callable[[F], F]:
|
|
168
|
+
"""进出方法时设置flag
|
|
169
|
+
|
|
170
|
+
用于method的装饰器,当调用被装饰的方法时,会将 `self.flag`
|
|
171
|
+
置为 `True`,结束调用时(包括异常退出),置为 `False`。
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
flag: 作为标识的属性名
|
|
175
|
+
|
|
176
|
+
>>> class Example:
|
|
177
|
+
... def __init__(self):
|
|
178
|
+
... self.flag = False
|
|
179
|
+
...
|
|
180
|
+
... @flagmethod('flag')
|
|
181
|
+
... def foo(self, arg):
|
|
182
|
+
... self.bar()
|
|
183
|
+
... pass
|
|
184
|
+
...
|
|
185
|
+
... @flagmethod('flag')
|
|
186
|
+
... async def async_foo(self, arg):
|
|
187
|
+
... self.bar()
|
|
188
|
+
... pass
|
|
189
|
+
...
|
|
190
|
+
... def bar(self):
|
|
191
|
+
... print(self.flag)
|
|
192
|
+
...
|
|
193
|
+
>>> example = Example()
|
|
194
|
+
>>> example.foo(1)
|
|
195
|
+
True
|
|
196
|
+
>>> import asyncio
|
|
197
|
+
>>> asyncio.run(example.async_foo(1))
|
|
198
|
+
True
|
|
199
|
+
>>> example.flag
|
|
200
|
+
False
|
|
201
|
+
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
def deco(method):
|
|
205
|
+
if inspect.iscoroutinefunction(method):
|
|
206
|
+
async def wrapper(self, *args, **kwargs):
|
|
207
|
+
setattr(self, flag, True)
|
|
208
|
+
try:
|
|
209
|
+
rslt = await method(self, *args, **kwargs)
|
|
210
|
+
finally:
|
|
211
|
+
setattr(self, flag, False)
|
|
212
|
+
return rslt
|
|
213
|
+
else:
|
|
214
|
+
def wrapper(self, *args, **kwargs):
|
|
215
|
+
setattr(self, flag, True)
|
|
216
|
+
try:
|
|
217
|
+
rslt = method(self, *args, **kwargs)
|
|
218
|
+
finally:
|
|
219
|
+
setattr(self, flag, False)
|
|
220
|
+
return rslt
|
|
221
|
+
return functools.wraps(method)(wrapper)
|
|
222
|
+
|
|
223
|
+
return deco
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def deprecated(
|
|
227
|
+
replacement: str = None,
|
|
228
|
+
version: Tuple[int, int, int] = None,
|
|
229
|
+
reason: str = None
|
|
230
|
+
):
|
|
231
|
+
"""弃用方法装饰器
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
replacement: 弃用方法的替代方法名
|
|
235
|
+
version: 开始弃用的版本
|
|
236
|
+
reason: 弃用原因
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
"""
|
|
240
|
+
|
|
241
|
+
def deco(method):
|
|
242
|
+
msg = "This method is deprecated and will be removed in near future"
|
|
243
|
+
docs = "\n" + " " * 8 + f".. deprecated:: {repr_version(version)}\n"
|
|
244
|
+
|
|
245
|
+
if replacement:
|
|
246
|
+
msg += f", use [{replacement}] instead."
|
|
247
|
+
docs += f"\n" + " " * 12 + f"请使用 :meth:`{replacement}`\n"
|
|
248
|
+
if reason:
|
|
249
|
+
msg += f"Deprecated reason: {reason}. "
|
|
250
|
+
if version:
|
|
251
|
+
msg += f"Deprecated version: {repr_version(version)}. "
|
|
252
|
+
|
|
253
|
+
if method.__doc__:
|
|
254
|
+
method.__doc__ += docs
|
|
255
|
+
else:
|
|
256
|
+
method.__doc__ = docs
|
|
257
|
+
|
|
258
|
+
if inspect.iscoroutinefunction(method):
|
|
259
|
+
@functools.wraps(method)
|
|
260
|
+
async def wrapper(*args, **kwargs):
|
|
261
|
+
warnings.warn(msg, DeprecationWarning)
|
|
262
|
+
return await method(*args, **kwargs)
|
|
263
|
+
else:
|
|
264
|
+
@functools.wraps(method)
|
|
265
|
+
def wrapper(*args, **kwargs):
|
|
266
|
+
warnings.warn(msg, DeprecationWarning)
|
|
267
|
+
return method(*args, **kwargs)
|
|
268
|
+
|
|
269
|
+
return wrapper
|
|
270
|
+
|
|
271
|
+
return deco
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def lru_cache(maxsize=128, cache_factory=LRUCache):
|
|
275
|
+
assert isinstance(maxsize, int), 'Expected maxsize to be an integer'
|
|
276
|
+
|
|
277
|
+
if maxsize == 0:
|
|
278
|
+
def dummy_deco(fun):
|
|
279
|
+
return fun
|
|
280
|
+
return dummy_deco
|
|
281
|
+
|
|
282
|
+
cache = Manager.create_cache(cache_factory, maxsize=maxsize)
|
|
283
|
+
|
|
284
|
+
def deco_fun(func):
|
|
285
|
+
if inspect.iscoroutinefunction(func):
|
|
286
|
+
@functools.wraps(func)
|
|
287
|
+
async def wrapper(*args, **kwargs):
|
|
288
|
+
key = hashkey(*args, **kwargs)
|
|
289
|
+
|
|
290
|
+
if key in cache:
|
|
291
|
+
return cache[key]
|
|
292
|
+
|
|
293
|
+
result = await func(*args, **kwargs)
|
|
294
|
+
cache[key] = result
|
|
295
|
+
return result
|
|
296
|
+
else:
|
|
297
|
+
@functools.wraps(func)
|
|
298
|
+
def wrapper(*args, **kwargs):
|
|
299
|
+
key = hashkey(*args, **kwargs)
|
|
300
|
+
|
|
301
|
+
if key in cache:
|
|
302
|
+
return cache[key]
|
|
303
|
+
|
|
304
|
+
result = func(*args, **kwargs)
|
|
305
|
+
cache[key] = result
|
|
306
|
+
return result
|
|
307
|
+
|
|
308
|
+
return wrapper
|
|
309
|
+
|
|
310
|
+
return deco_fun
|