pyxllib 0.3.197__py3-none-any.whl → 3.201.1__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.
Files changed (127) hide show
  1. pyxllib/__init__.py +14 -21
  2. pyxllib/algo/__init__.py +8 -8
  3. pyxllib/algo/disjoint.py +54 -54
  4. pyxllib/algo/geo.py +537 -541
  5. pyxllib/algo/intervals.py +964 -964
  6. pyxllib/algo/matcher.py +389 -389
  7. pyxllib/algo/newbie.py +166 -166
  8. pyxllib/algo/pupil.py +629 -629
  9. pyxllib/algo/shapelylib.py +67 -67
  10. pyxllib/algo/specialist.py +241 -241
  11. pyxllib/algo/stat.py +494 -494
  12. pyxllib/algo/treelib.py +145 -149
  13. pyxllib/algo/unitlib.py +62 -66
  14. pyxllib/autogui/__init__.py +5 -5
  15. pyxllib/autogui/activewin.py +246 -246
  16. pyxllib/autogui/all.py +9 -9
  17. pyxllib/autogui/autogui.py +846 -852
  18. pyxllib/autogui/uiautolib.py +362 -362
  19. pyxllib/autogui/virtualkey.py +102 -102
  20. pyxllib/autogui/wechat.py +827 -827
  21. pyxllib/autogui/wechat_msg.py +421 -421
  22. pyxllib/autogui/wxautolib.py +84 -84
  23. pyxllib/cv/__init__.py +5 -5
  24. pyxllib/cv/expert.py +267 -267
  25. pyxllib/cv/imfile.py +159 -159
  26. pyxllib/cv/imhash.py +39 -39
  27. pyxllib/cv/pupil.py +9 -9
  28. pyxllib/cv/rgbfmt.py +1525 -1525
  29. pyxllib/cv/slidercaptcha.py +137 -137
  30. pyxllib/cv/trackbartools.py +251 -251
  31. pyxllib/cv/xlcvlib.py +1040 -1040
  32. pyxllib/cv/xlpillib.py +423 -423
  33. pyxllib/data/echarts.py +236 -240
  34. pyxllib/data/jsonlib.py +85 -89
  35. pyxllib/data/oss.py +72 -72
  36. pyxllib/data/pglib.py +1111 -1127
  37. pyxllib/data/sqlite.py +568 -568
  38. pyxllib/data/sqllib.py +297 -297
  39. pyxllib/ext/JLineViewer.py +505 -505
  40. pyxllib/ext/__init__.py +6 -6
  41. pyxllib/ext/demolib.py +251 -246
  42. pyxllib/ext/drissionlib.py +277 -277
  43. pyxllib/ext/kq5034lib.py +12 -12
  44. pyxllib/ext/qt.py +449 -449
  45. pyxllib/ext/robustprocfile.py +493 -497
  46. pyxllib/ext/seleniumlib.py +76 -76
  47. pyxllib/ext/tk.py +173 -173
  48. pyxllib/ext/unixlib.py +821 -827
  49. pyxllib/ext/utools.py +345 -351
  50. pyxllib/ext/webhook.py +124 -119
  51. pyxllib/ext/win32lib.py +40 -40
  52. pyxllib/ext/wjxlib.py +91 -88
  53. pyxllib/ext/wpsapi.py +124 -124
  54. pyxllib/ext/xlwork.py +9 -9
  55. pyxllib/ext/yuquelib.py +1110 -1105
  56. pyxllib/file/__init__.py +17 -17
  57. pyxllib/file/docxlib.py +757 -761
  58. pyxllib/file/gitlib.py +309 -309
  59. pyxllib/file/libreoffice.py +165 -165
  60. pyxllib/file/movielib.py +144 -148
  61. pyxllib/file/newbie.py +10 -10
  62. pyxllib/file/onenotelib.py +1469 -1469
  63. pyxllib/file/packlib/__init__.py +330 -330
  64. pyxllib/file/packlib/zipfile.py +2441 -2441
  65. pyxllib/file/pdflib.py +422 -426
  66. pyxllib/file/pupil.py +185 -185
  67. pyxllib/file/specialist/__init__.py +681 -685
  68. pyxllib/file/specialist/dirlib.py +799 -799
  69. pyxllib/file/specialist/download.py +193 -193
  70. pyxllib/file/specialist/filelib.py +2825 -2829
  71. pyxllib/file/xlsxlib.py +3122 -3131
  72. pyxllib/file/xlsyncfile.py +341 -341
  73. pyxllib/prog/__init__.py +5 -5
  74. pyxllib/prog/cachetools.py +58 -64
  75. pyxllib/prog/deprecatedlib.py +233 -233
  76. pyxllib/prog/filelock.py +42 -42
  77. pyxllib/prog/ipyexec.py +253 -253
  78. pyxllib/prog/multiprogs.py +940 -940
  79. pyxllib/prog/newbie.py +451 -451
  80. pyxllib/prog/pupil.py +1208 -1197
  81. pyxllib/prog/sitepackages.py +33 -33
  82. pyxllib/prog/specialist/__init__.py +348 -391
  83. pyxllib/prog/specialist/bc.py +203 -203
  84. pyxllib/prog/specialist/browser.py +497 -497
  85. pyxllib/prog/specialist/common.py +347 -347
  86. pyxllib/prog/specialist/datetime.py +198 -198
  87. pyxllib/prog/specialist/tictoc.py +240 -240
  88. pyxllib/prog/specialist/xllog.py +180 -180
  89. pyxllib/prog/xlosenv.py +110 -108
  90. pyxllib/stdlib/__init__.py +17 -17
  91. pyxllib/stdlib/tablepyxl/__init__.py +10 -10
  92. pyxllib/stdlib/tablepyxl/style.py +303 -303
  93. pyxllib/stdlib/tablepyxl/tablepyxl.py +130 -130
  94. pyxllib/text/__init__.py +8 -8
  95. pyxllib/text/ahocorasick.py +36 -39
  96. pyxllib/text/airscript.js +754 -744
  97. pyxllib/text/charclasslib.py +121 -121
  98. pyxllib/text/jiebalib.py +267 -267
  99. pyxllib/text/jinjalib.py +27 -32
  100. pyxllib/text/jsa_ai_prompt.md +271 -271
  101. pyxllib/text/jscode.py +922 -922
  102. pyxllib/text/latex/__init__.py +158 -158
  103. pyxllib/text/levenshtein.py +303 -303
  104. pyxllib/text/nestenv.py +1215 -1215
  105. pyxllib/text/newbie.py +300 -300
  106. pyxllib/text/pupil/__init__.py +8 -8
  107. pyxllib/text/pupil/common.py +1121 -1121
  108. pyxllib/text/pupil/xlalign.py +326 -326
  109. pyxllib/text/pycode.py +47 -47
  110. pyxllib/text/specialist/__init__.py +8 -8
  111. pyxllib/text/specialist/common.py +112 -112
  112. pyxllib/text/specialist/ptag.py +186 -186
  113. pyxllib/text/spellchecker.py +172 -172
  114. pyxllib/text/templates/echart_base.html +10 -10
  115. pyxllib/text/templates/highlight_code.html +16 -16
  116. pyxllib/text/templates/latex_editor.html +102 -102
  117. pyxllib/text/vbacode.py +17 -17
  118. pyxllib/text/xmllib.py +741 -747
  119. pyxllib/xl.py +42 -39
  120. pyxllib/xlcv.py +17 -17
  121. pyxllib-3.201.1.dist-info/METADATA +296 -0
  122. pyxllib-3.201.1.dist-info/RECORD +125 -0
  123. {pyxllib-0.3.197.dist-info → pyxllib-3.201.1.dist-info}/licenses/LICENSE +190 -190
  124. pyxllib/ext/old.py +0 -663
  125. pyxllib-0.3.197.dist-info/METADATA +0 -48
  126. pyxllib-0.3.197.dist-info/RECORD +0 -126
  127. {pyxllib-0.3.197.dist-info → pyxllib-3.201.1.dist-info}/WHEEL +0 -0
pyxllib/prog/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # @Author : 陈坤泽
4
- # @Email : 877362867@qq.com
5
- # @Date : 2021/06/03 21:14
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # @Author : 陈坤泽
4
+ # @Email : 877362867@qq.com
5
+ # @Date : 2021/06/03 21:14
@@ -1,64 +1,58 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # @Author : 陈坤泽
4
- # @Email : 877362867@qq.com
5
- # @Date : 2024/05/29
6
-
7
- from pyxllib.prog.pupil import check_install_package
8
-
9
- # cachetools,通用缓存工具,适用范围更广
10
- check_install_package('cachetools')
11
- # cached-property,类属性特用工具,相对比较简洁些
12
- check_install_package('cached_property', 'cached-property')
13
-
14
- # 对于普通函数,一般用lru_cache即可
15
- from functools import lru_cache
16
- import threading
17
-
18
- from cachetools import cached, LRUCache, TTLCache
19
-
20
- # 官方文档:https://pypi.org/project/cached-property/
21
- from cached_property import cached_property
22
- from cached_property import threaded_cached_property # 线程安全
23
- from cached_property import cached_property_with_ttl # 限时缓存,单位秒
24
- from cached_property import threaded_cached_property_with_ttl # 线程 + 限时
25
-
26
-
27
- # todo 240609周日21:19 https://github.com/awolverp/cachebox,据说这个缓存库速度更快的多
28
-
29
- # 进一步封装的更通用、自己常用的装饰器
30
-
31
- def xlcache(maxsize=128, *, ttl=None, lock=None, property=False):
32
- """ 那些工具接口太复杂难记,自己封装一个统一的工具
33
-
34
- 就是一个装饰器,最大缓存多少项,然后是否要开多线程安全,是否要设置限时重置,是否是作为类成员属性修饰
35
-
36
- :param property: 是否作为类成员属性修饰,不过一般不建议通过这里设置,
37
- 而是外部再加一层@property,不然IDE会识别不了这是一个property,影响开发
38
-
39
- """
40
- def decorator(func):
41
- if property:
42
- if ttl is not None:
43
- if lock:
44
- # 使用带有时间限制和线程安全的缓存属性
45
- return threaded_cached_property_with_ttl(ttl)(func)
46
- else:
47
- # 使用带有时间限制但非线程安全的缓存属性
48
- return cached_property_with_ttl(ttl)(func)
49
- else:
50
- if lock:
51
- # 使用线程安全的缓存属性
52
- return threaded_cached_property(func)
53
- else:
54
- # 使用普通的缓存属性
55
- return cached_property(func)
56
- else:
57
- lock2 = threading.RLock() if lock is True else lock
58
- if ttl is None:
59
- return cached(LRUCache(maxsize), lock=lock2)(func)
60
- else:
61
- cache = TTLCache(maxsize=maxsize, ttl=ttl)
62
- return cached(cache, lock=lock2)(func)
63
-
64
- return decorator
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # @Author : 陈坤泽
4
+ # @Email : 877362867@qq.com
5
+ # @Date : 2024/05/29
6
+
7
+ # 对于普通函数,一般用lru_cache即可
8
+ from functools import lru_cache
9
+ import threading
10
+
11
+ from cachetools import cached, LRUCache, TTLCache
12
+
13
+ # 官方文档:https://pypi.org/project/cached-property/
14
+ from cached_property import cached_property
15
+ from cached_property import threaded_cached_property # 线程安全
16
+ from cached_property import cached_property_with_ttl # 限时缓存,单位秒
17
+ from cached_property import threaded_cached_property_with_ttl # 线程 + 限时
18
+
19
+
20
+ # todo 240609周日21:19 https://github.com/awolverp/cachebox,据说这个缓存库速度更快的多
21
+
22
+ # 进一步封装的更通用、自己常用的装饰器
23
+
24
+ def xlcache(maxsize=128, *, ttl=None, lock=None, property=False):
25
+ """ 那些工具接口太复杂难记,自己封装一个统一的工具
26
+
27
+ 就是一个装饰器,最大缓存多少项,然后是否要开多线程安全,是否要设置限时重置,是否是作为类成员属性修饰
28
+
29
+ :param property: 是否作为类成员属性修饰,不过一般不建议通过这里设置,
30
+ 而是外部再加一层@property,不然IDE会识别不了这是一个property,影响开发
31
+
32
+ """
33
+
34
+ def decorator(func):
35
+ if property:
36
+ if ttl is not None:
37
+ if lock:
38
+ # 使用带有时间限制和线程安全的缓存属性
39
+ return threaded_cached_property_with_ttl(ttl)(func)
40
+ else:
41
+ # 使用带有时间限制但非线程安全的缓存属性
42
+ return cached_property_with_ttl(ttl)(func)
43
+ else:
44
+ if lock:
45
+ # 使用线程安全的缓存属性
46
+ return threaded_cached_property(func)
47
+ else:
48
+ # 使用普通的缓存属性
49
+ return cached_property(func)
50
+ else:
51
+ lock2 = threading.RLock() if lock is True else lock
52
+ if ttl is None:
53
+ return cached(LRUCache(maxsize), lock=lock2)(func)
54
+ else:
55
+ cache = TTLCache(maxsize=maxsize, ttl=ttl)
56
+ return cached(cache, lock=lock2)(func)
57
+
58
+ return decorator
@@ -1,233 +1,233 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # @Author : 陈坤泽
4
- # @Email : 877362867@qq.com
5
- # @Date : 2021/06/06 00:50
6
-
7
- """
8
- 原官方库: https://pypi.org/project/Deprecated
9
-
10
- 其deprecated装饰器的action='once'功能跟我设想的不一样
11
-
12
- 其实从实际使用角度看,默认的每个物理行只警告一次是最合理的模式,使用起来无伤大雅
13
- 但我非要把这个'once'情景的功能给补完善~~
14
-
15
- 从 deprecated.classic 文件改编而来
16
- """
17
-
18
- import functools
19
- import inspect
20
- import platform
21
- import warnings
22
-
23
- import wrapt
24
-
25
- try:
26
- # If the C extension for wrapt was compiled and wrapt/_wrappers.pyd exists, then the
27
- # stack level that should be passed to warnings.warn should be 2. However, if using
28
- # a pure python wrapt, a extra stacklevel is required.
29
- import wrapt._wrappers
30
-
31
- _routine_stacklevel = 2
32
- _class_stacklevel = 2
33
- except ImportError:
34
- _routine_stacklevel = 3
35
- if platform.python_implementation() == "PyPy":
36
- _class_stacklevel = 2
37
- else:
38
- _class_stacklevel = 3
39
-
40
- string_types = (type(b''), type(u''))
41
-
42
-
43
- class ClassicAdapter(wrapt.AdapterFactory):
44
- """
45
- Classic adapter -- *for advanced usage only*
46
-
47
- This adapter is used to get the deprecation message according to the wrapped object type:
48
- class, function, standard method, static method, or class method.
49
-
50
- This is the base class of the :class:`~deprecated.sphinx.SphinxAdapter` class
51
- which is used to update the wrapped object docstring.
52
-
53
- You can also inherit this class to change the deprecation message.
54
-
55
- In the following example, we change the message into "The ... is deprecated.":
56
-
57
- .. code-block:: python
58
-
59
- import inspect
60
-
61
- from deprecated.classic import ClassicAdapter
62
- from deprecated.classic import deprecated
63
-
64
-
65
- class MyClassicAdapter(ClassicAdapter):
66
- def get_deprecated_msg(self, wrapped, instance):
67
- if instance is None:
68
- if inspect.isclass(wrapped):
69
- fmt = "The class {name} is deprecated."
70
- else:
71
- fmt = "The function {name} is deprecated."
72
- else:
73
- if inspect.isclass(instance):
74
- fmt = "The class method {name} is deprecated."
75
- else:
76
- fmt = "The method {name} is deprecated."
77
- if self.reason:
78
- fmt += " ({reason})"
79
- if self.version:
80
- fmt += " -- Deprecated since version {version}."
81
- return fmt.format(name=wrapped.__name__,
82
- reason=self.reason or "",
83
- version=self.version or "")
84
-
85
- Then, you can use your ``MyClassicAdapter`` class like this in your source code:
86
-
87
- .. code-block:: python
88
-
89
- @deprecated(reason="use another function", adapter_cls=MyClassicAdapter)
90
- def some_old_function(x, y):
91
- return x + y
92
- """
93
-
94
- def __init__(self, reason="", version="", action=None, category=DeprecationWarning):
95
- """
96
- Construct a wrapper adapter.
97
-
98
- :type reason: str
99
- :param reason:
100
- Reason message which documents the deprecation in your library (can be omitted).
101
-
102
- :type version: str
103
- :param version:
104
- Version of your project which deprecates this feature.
105
- If you follow the `Semantic Versioning <https://semver.org/>`_,
106
- the version number has the format "MAJOR.MINOR.PATCH".
107
-
108
- :type action: str
109
- :param action:
110
- A warning filter used to activate or not the deprecation warning.
111
- Can be one of "error", "ignore", "always", "default", "module", or "once".
112
- If ``None`` or empty, the the global filtering mechanism is used.
113
- See: `The Warnings Filter`_ in the Python documentation.
114
-
115
- :type category: type
116
- :param category:
117
- The warning category to use for the deprecation warning.
118
- By default, the category class is :class:`~DeprecationWarning`,
119
- you can inherit this class to define your own deprecation warning category.
120
- """
121
- self.reason = reason or ""
122
- self.version = version or ""
123
- self.action = action
124
- self.category = category
125
- super(ClassicAdapter, self).__init__()
126
-
127
- def get_deprecated_msg(self, wrapped, instance):
128
- """
129
- Get the deprecation warning message for the user.
130
-
131
- :param wrapped: Wrapped class or function.
132
-
133
- :param instance: The object to which the wrapped function was bound when it was called.
134
-
135
- :return: The warning message.
136
- """
137
- if instance is None:
138
- if inspect.isclass(wrapped):
139
- fmt = "Call to deprecated class {name}."
140
- else:
141
- fmt = "Call to deprecated function (or staticmethod) {name}."
142
- else:
143
- if inspect.isclass(instance):
144
- fmt = "Call to deprecated class method {name}."
145
- else:
146
- fmt = "Call to deprecated method {name}."
147
- if self.reason:
148
- fmt += " ({reason})"
149
- if self.version:
150
- fmt += " -- Deprecated since version {version}."
151
- return fmt.format(name=wrapped.__name__, reason=self.reason or "", version=self.version or "")
152
-
153
- def __call__(self, wrapped):
154
- """
155
- Decorate your class or function.
156
-
157
- :param wrapped: Wrapped class or function.
158
-
159
- :return: the decorated class or function.
160
-
161
- .. versionchanged:: 1.2.4
162
- Don't pass arguments to :meth:`object.__new__` (other than *cls*).
163
-
164
- .. versionchanged:: 1.2.8
165
- The warning filter is not set if the *action* parameter is ``None`` or empty.
166
- """
167
- if inspect.isclass(wrapped):
168
- old_new1 = wrapped.__new__
169
-
170
- def wrapped_cls(cls, *args, **kwargs):
171
- msg = self.get_deprecated_msg(wrapped, None)
172
- if self.action:
173
- with warnings.catch_warnings():
174
- warnings.simplefilter(self.action, self.category)
175
- warnings.warn(msg, category=self.category, stacklevel=_class_stacklevel)
176
- else:
177
- warnings.warn(msg, category=self.category, stacklevel=_class_stacklevel)
178
- if old_new1 is object.__new__:
179
- return old_new1(cls)
180
- # actually, we don't know the real signature of *old_new1*
181
- return old_new1(cls, *args, **kwargs)
182
-
183
- wrapped.__new__ = staticmethod(wrapped_cls)
184
-
185
- return wrapped
186
-
187
-
188
- def deprecated(*args, **kwargs):
189
- """
190
- """
191
- if args and isinstance(args[0], string_types):
192
- kwargs['reason'] = args[0]
193
- args = args[1:]
194
-
195
- if args and not callable(args[0]):
196
- raise TypeError(repr(type(args[0])))
197
-
198
- if args:
199
- action = kwargs.get('action')
200
- category = kwargs.get('category', DeprecationWarning)
201
- adapter_cls = kwargs.pop('adapter_cls', ClassicAdapter)
202
- adapter = adapter_cls(**kwargs)
203
-
204
- wrapped = args[0]
205
- if inspect.isclass(wrapped):
206
- wrapped = adapter(wrapped)
207
- return wrapped
208
-
209
- elif inspect.isroutine(wrapped):
210
- once = False
211
-
212
- @wrapt.decorator(adapter=adapter)
213
- def wrapper_function(wrapped_, instance_, args_, kwargs_):
214
- nonlocal once
215
- msg = adapter.get_deprecated_msg(wrapped_, instance_)
216
- if action:
217
- if action == 'once' and once:
218
- pass
219
- else:
220
- once = True
221
- with warnings.catch_warnings():
222
- warnings.simplefilter(action, category)
223
- warnings.warn(msg, category=category, stacklevel=_routine_stacklevel)
224
- else:
225
- warnings.warn(msg, category=category, stacklevel=_routine_stacklevel)
226
- return wrapped_(*args_, **kwargs_)
227
-
228
- return wrapper_function(wrapped)
229
-
230
- else:
231
- raise TypeError(repr(type(wrapped)))
232
-
233
- return functools.partial(deprecated, **kwargs)
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # @Author : 陈坤泽
4
+ # @Email : 877362867@qq.com
5
+ # @Date : 2021/06/06 00:50
6
+
7
+ """
8
+ 原官方库: https://pypi.org/project/Deprecated
9
+
10
+ 其deprecated装饰器的action='once'功能跟我设想的不一样
11
+
12
+ 其实从实际使用角度看,默认的每个物理行只警告一次是最合理的模式,使用起来无伤大雅
13
+ 但我非要把这个'once'情景的功能给补完善~~
14
+
15
+ 从 deprecated.classic 文件改编而来
16
+ """
17
+
18
+ import functools
19
+ import inspect
20
+ import platform
21
+ import warnings
22
+
23
+ import wrapt
24
+
25
+ try:
26
+ # If the C extension for wrapt was compiled and wrapt/_wrappers.pyd exists, then the
27
+ # stack level that should be passed to warnings.warn should be 2. However, if using
28
+ # a pure python wrapt, a extra stacklevel is required.
29
+ import wrapt._wrappers
30
+
31
+ _routine_stacklevel = 2
32
+ _class_stacklevel = 2
33
+ except ImportError:
34
+ _routine_stacklevel = 3
35
+ if platform.python_implementation() == "PyPy":
36
+ _class_stacklevel = 2
37
+ else:
38
+ _class_stacklevel = 3
39
+
40
+ string_types = (type(b''), type(u''))
41
+
42
+
43
+ class ClassicAdapter(wrapt.AdapterFactory):
44
+ """
45
+ Classic adapter -- *for advanced usage only*
46
+
47
+ This adapter is used to get the deprecation message according to the wrapped object type:
48
+ class, function, standard method, static method, or class method.
49
+
50
+ This is the base class of the :class:`~deprecated.sphinx.SphinxAdapter` class
51
+ which is used to update the wrapped object docstring.
52
+
53
+ You can also inherit this class to change the deprecation message.
54
+
55
+ In the following example, we change the message into "The ... is deprecated.":
56
+
57
+ .. code-block:: python
58
+
59
+ import inspect
60
+
61
+ from deprecated.classic import ClassicAdapter
62
+ from deprecated.classic import deprecated
63
+
64
+
65
+ class MyClassicAdapter(ClassicAdapter):
66
+ def get_deprecated_msg(self, wrapped, instance):
67
+ if instance is None:
68
+ if inspect.isclass(wrapped):
69
+ fmt = "The class {name} is deprecated."
70
+ else:
71
+ fmt = "The function {name} is deprecated."
72
+ else:
73
+ if inspect.isclass(instance):
74
+ fmt = "The class method {name} is deprecated."
75
+ else:
76
+ fmt = "The method {name} is deprecated."
77
+ if self.reason:
78
+ fmt += " ({reason})"
79
+ if self.version:
80
+ fmt += " -- Deprecated since version {version}."
81
+ return fmt.format(name=wrapped.__name__,
82
+ reason=self.reason or "",
83
+ version=self.version or "")
84
+
85
+ Then, you can use your ``MyClassicAdapter`` class like this in your source code:
86
+
87
+ .. code-block:: python
88
+
89
+ @deprecated(reason="use another function", adapter_cls=MyClassicAdapter)
90
+ def some_old_function(x, y):
91
+ return x + y
92
+ """
93
+
94
+ def __init__(self, reason="", version="", action=None, category=DeprecationWarning):
95
+ """
96
+ Construct a wrapper adapter.
97
+
98
+ :type reason: str
99
+ :param reason:
100
+ Reason message which documents the deprecation in your library (can be omitted).
101
+
102
+ :type version: str
103
+ :param version:
104
+ Version of your project which deprecates this feature.
105
+ If you follow the `Semantic Versioning <https://semver.org/>`_,
106
+ the version number has the format "MAJOR.MINOR.PATCH".
107
+
108
+ :type action: str
109
+ :param action:
110
+ A warning filter used to activate or not the deprecation warning.
111
+ Can be one of "error", "ignore", "always", "default", "module", or "once".
112
+ If ``None`` or empty, the the global filtering mechanism is used.
113
+ See: `The Warnings Filter`_ in the Python documentation.
114
+
115
+ :type category: type
116
+ :param category:
117
+ The warning category to use for the deprecation warning.
118
+ By default, the category class is :class:`~DeprecationWarning`,
119
+ you can inherit this class to define your own deprecation warning category.
120
+ """
121
+ self.reason = reason or ""
122
+ self.version = version or ""
123
+ self.action = action
124
+ self.category = category
125
+ super(ClassicAdapter, self).__init__()
126
+
127
+ def get_deprecated_msg(self, wrapped, instance):
128
+ """
129
+ Get the deprecation warning message for the user.
130
+
131
+ :param wrapped: Wrapped class or function.
132
+
133
+ :param instance: The object to which the wrapped function was bound when it was called.
134
+
135
+ :return: The warning message.
136
+ """
137
+ if instance is None:
138
+ if inspect.isclass(wrapped):
139
+ fmt = "Call to deprecated class {name}."
140
+ else:
141
+ fmt = "Call to deprecated function (or staticmethod) {name}."
142
+ else:
143
+ if inspect.isclass(instance):
144
+ fmt = "Call to deprecated class method {name}."
145
+ else:
146
+ fmt = "Call to deprecated method {name}."
147
+ if self.reason:
148
+ fmt += " ({reason})"
149
+ if self.version:
150
+ fmt += " -- Deprecated since version {version}."
151
+ return fmt.format(name=wrapped.__name__, reason=self.reason or "", version=self.version or "")
152
+
153
+ def __call__(self, wrapped):
154
+ """
155
+ Decorate your class or function.
156
+
157
+ :param wrapped: Wrapped class or function.
158
+
159
+ :return: the decorated class or function.
160
+
161
+ .. versionchanged:: 1.2.4
162
+ Don't pass arguments to :meth:`object.__new__` (other than *cls*).
163
+
164
+ .. versionchanged:: 1.2.8
165
+ The warning filter is not set if the *action* parameter is ``None`` or empty.
166
+ """
167
+ if inspect.isclass(wrapped):
168
+ old_new1 = wrapped.__new__
169
+
170
+ def wrapped_cls(cls, *args, **kwargs):
171
+ msg = self.get_deprecated_msg(wrapped, None)
172
+ if self.action:
173
+ with warnings.catch_warnings():
174
+ warnings.simplefilter(self.action, self.category)
175
+ warnings.warn(msg, category=self.category, stacklevel=_class_stacklevel)
176
+ else:
177
+ warnings.warn(msg, category=self.category, stacklevel=_class_stacklevel)
178
+ if old_new1 is object.__new__:
179
+ return old_new1(cls)
180
+ # actually, we don't know the real signature of *old_new1*
181
+ return old_new1(cls, *args, **kwargs)
182
+
183
+ wrapped.__new__ = staticmethod(wrapped_cls)
184
+
185
+ return wrapped
186
+
187
+
188
+ def deprecated(*args, **kwargs):
189
+ """
190
+ """
191
+ if args and isinstance(args[0], string_types):
192
+ kwargs['reason'] = args[0]
193
+ args = args[1:]
194
+
195
+ if args and not callable(args[0]):
196
+ raise TypeError(repr(type(args[0])))
197
+
198
+ if args:
199
+ action = kwargs.get('action')
200
+ category = kwargs.get('category', DeprecationWarning)
201
+ adapter_cls = kwargs.pop('adapter_cls', ClassicAdapter)
202
+ adapter = adapter_cls(**kwargs)
203
+
204
+ wrapped = args[0]
205
+ if inspect.isclass(wrapped):
206
+ wrapped = adapter(wrapped)
207
+ return wrapped
208
+
209
+ elif inspect.isroutine(wrapped):
210
+ once = False
211
+
212
+ @wrapt.decorator(adapter=adapter)
213
+ def wrapper_function(wrapped_, instance_, args_, kwargs_):
214
+ nonlocal once
215
+ msg = adapter.get_deprecated_msg(wrapped_, instance_)
216
+ if action:
217
+ if action == 'once' and once:
218
+ pass
219
+ else:
220
+ once = True
221
+ with warnings.catch_warnings():
222
+ warnings.simplefilter(action, category)
223
+ warnings.warn(msg, category=category, stacklevel=_routine_stacklevel)
224
+ else:
225
+ warnings.warn(msg, category=category, stacklevel=_routine_stacklevel)
226
+ return wrapped_(*args_, **kwargs_)
227
+
228
+ return wrapper_function(wrapped)
229
+
230
+ else:
231
+ raise TypeError(repr(type(wrapped)))
232
+
233
+ return functools.partial(deprecated, **kwargs)