hutool-python 1.0.0__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 (89) hide show
  1. hutool/__init__.py +174 -0
  2. hutool/cache/__init__.py +7 -0
  3. hutool/cache/cache_util.py +47 -0
  4. hutool/cache/fifo_cache.py +87 -0
  5. hutool/cache/lfu_cache.py +129 -0
  6. hutool/cache/lru_cache.py +93 -0
  7. hutool/cache/timed_cache.py +115 -0
  8. hutool/captcha/__init__.py +3 -0
  9. hutool/captcha/captcha_util.py +215 -0
  10. hutool/core/__init__.py +23 -0
  11. hutool/core/_base.py +61 -0
  12. hutool/core/bean.py +214 -0
  13. hutool/core/codec.py +111 -0
  14. hutool/core/coll.py +635 -0
  15. hutool/core/date.py +1024 -0
  16. hutool/core/exceptions.py +66 -0
  17. hutool/core/io/__init__.py +0 -0
  18. hutool/core/io/data_size_util.py +79 -0
  19. hutool/core/io/file_name_util.py +111 -0
  20. hutool/core/io/file_util.py +650 -0
  21. hutool/core/io/io_util.py +133 -0
  22. hutool/core/io/path_util.py +247 -0
  23. hutool/core/io/resource_util.py +137 -0
  24. hutool/core/map.py +933 -0
  25. hutool/core/math_util.py +105 -0
  26. hutool/core/net.py +288 -0
  27. hutool/core/text/__init__.py +0 -0
  28. hutool/core/text/csv_util.py +54 -0
  29. hutool/core/text/str_builder.py +224 -0
  30. hutool/core/text/unicode_util.py +58 -0
  31. hutool/core/tree.py +242 -0
  32. hutool/core/util/__init__.py +63 -0
  33. hutool/core/util/array_util.py +503 -0
  34. hutool/core/util/boolean_util.py +124 -0
  35. hutool/core/util/charset_util.py +60 -0
  36. hutool/core/util/class_util.py +136 -0
  37. hutool/core/util/coordinate_util.py +186 -0
  38. hutool/core/util/credit_code_util.py +110 -0
  39. hutool/core/util/desensitized_util.py +194 -0
  40. hutool/core/util/enum_util.py +94 -0
  41. hutool/core/util/escape_util.py +97 -0
  42. hutool/core/util/hash_util.py +243 -0
  43. hutool/core/util/hex_util.py +140 -0
  44. hutool/core/util/id_util.py +147 -0
  45. hutool/core/util/idcard_util.py +300 -0
  46. hutool/core/util/number_util.py +720 -0
  47. hutool/core/util/object_util.py +294 -0
  48. hutool/core/util/page_util.py +61 -0
  49. hutool/core/util/phone_util.py +140 -0
  50. hutool/core/util/random_util.py +112 -0
  51. hutool/core/util/re_util.py +231 -0
  52. hutool/core/util/reflect_util.py +135 -0
  53. hutool/core/util/runtime_util.py +89 -0
  54. hutool/core/util/str_util.py +2320 -0
  55. hutool/core/util/system_util.py +62 -0
  56. hutool/core/util/url_util.py +232 -0
  57. hutool/core/util/version_util.py +41 -0
  58. hutool/core/util/xml_util.py +158 -0
  59. hutool/core/util/zip_util.py +126 -0
  60. hutool/cron/__init__.py +4 -0
  61. hutool/cron/cron_pattern.py +123 -0
  62. hutool/cron/cron_util.py +115 -0
  63. hutool/crypto/__init__.py +5 -0
  64. hutool/crypto/digest_util.py +167 -0
  65. hutool/crypto/secure_util.py +311 -0
  66. hutool/crypto/sign_util.py +74 -0
  67. hutool/dfa/__init__.py +3 -0
  68. hutool/dfa/sensitive_util.py +114 -0
  69. hutool/extra/__init__.py +6 -0
  70. hutool/extra/emoji_util.py +90 -0
  71. hutool/extra/pinyin_util.py +44 -0
  72. hutool/extra/qr_code_util.py +58 -0
  73. hutool/extra/template_util.py +41 -0
  74. hutool/http/__init__.py +6 -0
  75. hutool/http/html_util.py +88 -0
  76. hutool/http/http_request.py +188 -0
  77. hutool/http/http_response.py +139 -0
  78. hutool/http/http_util.py +237 -0
  79. hutool/json_util.py +251 -0
  80. hutool/jwt_util.py +57 -0
  81. hutool/setting/__init__.py +5 -0
  82. hutool/setting/props_util.py +79 -0
  83. hutool/setting/setting_util.py +80 -0
  84. hutool/setting/yaml_util.py +45 -0
  85. hutool_python-1.0.0.dist-info/LICENSE +127 -0
  86. hutool_python-1.0.0.dist-info/METADATA +438 -0
  87. hutool_python-1.0.0.dist-info/RECORD +89 -0
  88. hutool_python-1.0.0.dist-info/WHEEL +5 -0
  89. hutool_python-1.0.0.dist-info/top_level.txt +1 -0
hutool/__init__.py ADDED
@@ -0,0 +1,174 @@
1
+ """Hutool-Python - Java Hutool 的 Python 移植版工具库。
2
+
3
+ 全量移植 Java Hutool 的 Python 版工具库,涵盖:
4
+ - core: 核心工具类(字符串、数字、集合、日期、IO、Bean、编解码等)
5
+ - http: HTTP 客户端工具
6
+ - json_util: JSON 工具
7
+ - crypto: 加密工具(摘要、对称/非对称加密、签名)
8
+ - cache: 缓存工具(FIFO、LFU、LRU、定时)
9
+ - captcha: 验证码
10
+ - dfa: 敏感词过滤
11
+ - extra: 扩展工具(拼音、Emoji、模板、二维码)
12
+ - cron: 定时任务
13
+ - jwt_util: JWT 工具
14
+ - setting: 配置工具(YAML、Properties)
15
+ """
16
+
17
+ __version__ = "1.0.0"
18
+
19
+ # 核心工具类 - 顶层快捷导入
20
+ from .core.bean import BeanUtil
21
+ from .core.codec import Base32, Base64
22
+ from .core.coll import CollUtil, ListUtil
23
+ from .core.date import DateTime, DateUtil
24
+ from .core.io.data_size_util import DataSizeUtil
25
+ from .core.io.file_name_util import FileNameUtil
26
+ from .core.io.file_util import FileUtil
27
+ from .core.io.io_util import IoUtil
28
+ from .core.io.path_util import PathUtil
29
+ from .core.io.resource_util import ResourceUtil
30
+ from .core.map import BiMap, DictUtil, MapUtil
31
+ from .core.math_util import BitStatusUtil, MathUtil
32
+ from .core.net import Ipv4Util, MaskBit, NetUtil
33
+ from .core.text.csv_util import CsvUtil
34
+ from .core.text.str_builder import StrBuilder
35
+ from .core.text.unicode_util import UnicodeUtil
36
+ from .core.tree import TreeNode, TreeUtil
37
+ from .core.util.array_util import ArrayUtil
38
+ from .core.util.boolean_util import BooleanUtil
39
+ from .core.util.charset_util import CharsetUtil
40
+ from .core.util.class_util import ClassUtil
41
+ from .core.util.coordinate_util import Coordinate, CoordinateUtil
42
+ from .core.util.credit_code_util import CreditCodeUtil
43
+ from .core.util.desensitized_util import DesensitizedUtil
44
+ from .core.util.enum_util import EnumUtil
45
+ from .core.util.escape_util import EscapeUtil
46
+ from .core.util.hash_util import HashUtil
47
+ from .core.util.hex_util import HexUtil
48
+ from .core.util.id_util import IdUtil
49
+ from .core.util.idcard_util import IdcardUtil
50
+ from .core.util.number_util import NumberUtil
51
+ from .core.util.object_util import ObjectUtil
52
+ from .core.util.page_util import PageUtil
53
+ from .core.util.phone_util import PhoneUtil
54
+ from .core.util.random_util import RandomUtil
55
+ from .core.util.re_util import ReUtil
56
+ from .core.util.reflect_util import ReflectUtil
57
+ from .core.util.runtime_util import RuntimeUtil
58
+ from .core.util.str_util import CharPool, CharUtil, StrUtil
59
+ from .core.util.system_util import SystemUtil
60
+ from .core.util.url_util import URLUtil
61
+ from .core.util.version_util import VersionUtil
62
+ from .core.util.xml_util import XmlUtil
63
+ from .core.util.zip_util import ZipUtil
64
+
65
+ # 其他模块
66
+ from .cache import CacheUtil, FIFOCache, LFUCache, LRUCache, TimedCache
67
+ from .captcha import ArithmeticCaptcha, CaptchaUtil, LineCaptcha
68
+ from .crypto import DigestUtil, SecureUtil, SignUtil
69
+ from .cron import CronPattern, CronUtil
70
+ from .dfa import SensitiveUtil
71
+ from .extra import EmojiUtil, PinyinUtil, QrCodeUtil, TemplateUtil
72
+ from .http import HtmlUtil, HttpRequest, HttpResponse, HttpUtil
73
+ from .json_util import JSONUtil
74
+ from .jwt_util import JWTUtil
75
+ from .setting import PropsUtil, SettingUtil, YamlUtil
76
+
77
+ __all__ = [
78
+ # core/util
79
+ "ArrayUtil",
80
+ "BooleanUtil",
81
+ "CharsetUtil",
82
+ "CharPool",
83
+ "CharUtil",
84
+ "ClassUtil",
85
+ "Coordinate",
86
+ "CoordinateUtil",
87
+ "CreditCodeUtil",
88
+ "DesensitizedUtil",
89
+ "EnumUtil",
90
+ "EscapeUtil",
91
+ "HashUtil",
92
+ "HexUtil",
93
+ "IdUtil",
94
+ "IdcardUtil",
95
+ "NumberUtil",
96
+ "ObjectUtil",
97
+ "PageUtil",
98
+ "PhoneUtil",
99
+ "RandomUtil",
100
+ "ReUtil",
101
+ "ReflectUtil",
102
+ "RuntimeUtil",
103
+ "StrUtil",
104
+ "SystemUtil",
105
+ "URLUtil",
106
+ "VersionUtil",
107
+ "XmlUtil",
108
+ "ZipUtil",
109
+ # core/io
110
+ "DataSizeUtil",
111
+ "FileNameUtil",
112
+ "FileUtil",
113
+ "IoUtil",
114
+ "PathUtil",
115
+ "ResourceUtil",
116
+ # core/text
117
+ "CsvUtil",
118
+ "StrBuilder",
119
+ "UnicodeUtil",
120
+ # core 其他
121
+ "Base32",
122
+ "Base64",
123
+ "BeanUtil",
124
+ "BiMap",
125
+ "BitStatusUtil",
126
+ "CollUtil",
127
+ "DateTime",
128
+ "DateUtil",
129
+ "DictUtil",
130
+ "Ipv4Util",
131
+ "ListUtil",
132
+ "MapUtil",
133
+ "MaskBit",
134
+ "MathUtil",
135
+ "NetUtil",
136
+ "TreeNode",
137
+ "TreeUtil",
138
+ # http
139
+ "HtmlUtil",
140
+ "HttpRequest",
141
+ "HttpResponse",
142
+ "HttpUtil",
143
+ # json / jwt
144
+ "JSONUtil",
145
+ "JWTUtil",
146
+ # cache
147
+ "CacheUtil",
148
+ "FIFOCache",
149
+ "LFUCache",
150
+ "LRUCache",
151
+ "TimedCache",
152
+ # captcha
153
+ "ArithmeticCaptcha",
154
+ "CaptchaUtil",
155
+ "LineCaptcha",
156
+ # crypto
157
+ "DigestUtil",
158
+ "SecureUtil",
159
+ "SignUtil",
160
+ # cron
161
+ "CronPattern",
162
+ "CronUtil",
163
+ # dfa
164
+ "SensitiveUtil",
165
+ # extra
166
+ "EmojiUtil",
167
+ "PinyinUtil",
168
+ "QrCodeUtil",
169
+ "TemplateUtil",
170
+ # setting
171
+ "PropsUtil",
172
+ "SettingUtil",
173
+ "YamlUtil",
174
+ ]
@@ -0,0 +1,7 @@
1
+ from .cache_util import CacheUtil
2
+ from .fifo_cache import FIFOCache
3
+ from .lfu_cache import LFUCache
4
+ from .lru_cache import LRUCache
5
+ from .timed_cache import TimedCache
6
+
7
+ __all__ = ["CacheUtil", "FIFOCache", "LFUCache", "LRUCache", "TimedCache"]
@@ -0,0 +1,47 @@
1
+ from .fifo_cache import FIFOCache
2
+ from .lfu_cache import LFUCache
3
+ from .lru_cache import LRUCache
4
+ from .timed_cache import TimedCache
5
+
6
+
7
+ class CacheUtil:
8
+ """缓存工厂类。
9
+
10
+ 提供各种缓存实现的便捷创建方法。
11
+ """
12
+
13
+ @staticmethod
14
+ def new_fifo_cache(capacity: int = 16) -> FIFOCache:
15
+ """创建FIFO(先进先出)缓存。
16
+
17
+ :param capacity: 缓存最大容量,默认16
18
+ :return: FIFOCache实例
19
+ """
20
+ return FIFOCache(capacity)
21
+
22
+ @staticmethod
23
+ def new_lfu_cache(capacity: int = 16) -> LFUCache:
24
+ """创建LFU(最不经常使用)缓存。
25
+
26
+ :param capacity: 缓存最大容量,默认16
27
+ :return: LFUCache实例
28
+ """
29
+ return LFUCache(capacity)
30
+
31
+ @staticmethod
32
+ def new_lru_cache(capacity: int = 16) -> LRUCache:
33
+ """创建LRU(最近最少使用)缓存。
34
+
35
+ :param capacity: 缓存最大容量,默认16
36
+ :return: LRUCache实例
37
+ """
38
+ return LRUCache(capacity)
39
+
40
+ @staticmethod
41
+ def new_timed_cache(timeout: int = 60) -> TimedCache:
42
+ """创建定时缓存。
43
+
44
+ :param timeout: 默认过期时间(秒),默认60秒
45
+ :return: TimedCache实例
46
+ """
47
+ return TimedCache(timeout)
@@ -0,0 +1,87 @@
1
+ from collections import OrderedDict
2
+ from typing import Any, KeysView
3
+
4
+
5
+ class FIFOCache:
6
+ """FIFO(先进先出)缓存实现。
7
+
8
+ 当缓存满时,最早插入的元素会被淘汰。
9
+ """
10
+
11
+ def __init__(self, capacity: int = 16) -> None:
12
+ """初始化FIFO缓存。
13
+
14
+ :param capacity: 缓存最大容量,默认16
15
+ """
16
+ self._capacity: int = capacity
17
+ self._cache: OrderedDict = OrderedDict()
18
+
19
+ def get(self, key: Any, default: Any = None) -> Any:
20
+ """获取缓存值。
21
+
22
+ :param key: 缓存键
23
+ :param default: 键不存在时返回的默认值
24
+ :return: 缓存值,不存在时返回默认值
25
+ """
26
+ return self._cache.get(key, default)
27
+
28
+ def put(self, key: Any, value: Any) -> None:
29
+ """放入缓存。如果缓存已满,淘汰最早插入的元素。
30
+
31
+ :param key: 缓存键
32
+ :param value: 缓存值
33
+ """
34
+ if key in self._cache:
35
+ self._cache[key] = value
36
+ return
37
+ if len(self._cache) >= self._capacity:
38
+ self._cache.popitem(last=False)
39
+ self._cache[key] = value
40
+
41
+ def remove(self, key: Any) -> Any:
42
+ """移除指定键的缓存。
43
+
44
+ :param key: 缓存键
45
+ :return: 被移除的值,键不存在时返回None
46
+ """
47
+ return self._cache.pop(key, None)
48
+
49
+ def size(self) -> int:
50
+ """获取当前缓存大小。
51
+
52
+ :return: 当前缓存条目数
53
+ """
54
+ return len(self._cache)
55
+
56
+ def capacity(self) -> int:
57
+ """获取缓存最大容量。
58
+
59
+ :return: 缓存最大容量
60
+ """
61
+ return self._capacity
62
+
63
+ def clear(self) -> None:
64
+ """清空所有缓存。"""
65
+ self._cache.clear()
66
+
67
+ def is_full(self) -> bool:
68
+ """判断缓存是否已满。
69
+
70
+ :return: 缓存已满返回True,否则返回False
71
+ """
72
+ return len(self._cache) >= self._capacity
73
+
74
+ def keys(self) -> KeysView:
75
+ """获取所有缓存键。
76
+
77
+ :return: 缓存键的视图
78
+ """
79
+ return self._cache.keys()
80
+
81
+ def __contains__(self, key: Any) -> bool:
82
+ """判断键是否存在于缓存中。"""
83
+ return key in self._cache
84
+
85
+ def __len__(self) -> int:
86
+ """返回缓存大小。"""
87
+ return len(self._cache)
@@ -0,0 +1,129 @@
1
+ from collections import defaultdict
2
+ from typing import Any
3
+
4
+
5
+ class LFUCache:
6
+ """LFU(最不经常使用)缓存实现。
7
+
8
+ 当缓存满时,访问频率最低的元素会被淘汰。
9
+ 若有多个元素频率相同,淘汰最早插入的。
10
+ """
11
+
12
+ def __init__(self, capacity: int = 16) -> None:
13
+ """初始化LFU缓存。
14
+
15
+ :param capacity: 缓存最大容量,默认16
16
+ """
17
+ self._capacity: int = capacity
18
+ self._cache: dict = {} # key -> value
19
+ self._freq: dict = {} # key -> frequency
20
+ self._freq_to_keys: dict = defaultdict(list) # frequency -> [keys]
21
+ self._min_freq: int = 0
22
+
23
+ def get(self, key: Any, default: Any = None) -> Any:
24
+ """获取缓存值,并更新访问频率。
25
+
26
+ :param key: 缓存键
27
+ :param default: 键不存在时返回的默认值
28
+ :return: 缓存值,不存在时返回默认值
29
+ """
30
+ if key not in self._cache:
31
+ return default
32
+ self._update_freq(key)
33
+ return self._cache[key]
34
+
35
+ def put(self, key: Any, value: Any) -> None:
36
+ """放入缓存。如果缓存已满,淘汰访问频率最低的元素。
37
+
38
+ :param key: 缓存键
39
+ :param value: 缓存值
40
+ """
41
+ if self._capacity <= 0:
42
+ return
43
+
44
+ if key in self._cache:
45
+ self._cache[key] = value
46
+ self._update_freq(key)
47
+ return
48
+
49
+ if len(self._cache) >= self._capacity:
50
+ self._evict()
51
+
52
+ self._cache[key] = value
53
+ self._freq[key] = 1
54
+ self._freq_to_keys[1].append(key)
55
+ self._min_freq = 1
56
+
57
+ def remove(self, key: Any) -> Any:
58
+ """移除指定键的缓存。
59
+
60
+ :param key: 缓存键
61
+ :return: 被移除的值,键不存在时返回None
62
+ """
63
+ if key not in self._cache:
64
+ return None
65
+
66
+ freq = self._freq[key]
67
+ self._freq_to_keys[freq].remove(key)
68
+ if not self._freq_to_keys[freq]:
69
+ del self._freq_to_keys[freq]
70
+ if self._min_freq == freq:
71
+ self._min_freq = min(self._freq_to_keys.keys()) if self._freq_to_keys else 0
72
+
73
+ value = self._cache[key]
74
+ del self._cache[key]
75
+ del self._freq[key]
76
+ return value
77
+
78
+ def size(self) -> int:
79
+ """获取当前缓存大小。
80
+
81
+ :return: 当前缓存条目数
82
+ """
83
+ return len(self._cache)
84
+
85
+ def capacity(self) -> int:
86
+ """获取缓存最大容量。
87
+
88
+ :return: 缓存最大容量
89
+ """
90
+ return self._capacity
91
+
92
+ def clear(self) -> None:
93
+ """清空所有缓存。"""
94
+ self._cache.clear()
95
+ self._freq.clear()
96
+ self._freq_to_keys.clear()
97
+ self._min_freq = 0
98
+
99
+ def is_full(self) -> bool:
100
+ """判断缓存是否已满。
101
+
102
+ :return: 缓存已满返回True,否则返回False
103
+ """
104
+ return len(self._cache) >= self._capacity
105
+
106
+ def _update_freq(self, key: Any) -> None:
107
+ """更新键的访问频率。
108
+
109
+ :param key: 缓存键
110
+ """
111
+ freq = self._freq[key]
112
+ self._freq_to_keys[freq].remove(key)
113
+ if not self._freq_to_keys[freq]:
114
+ del self._freq_to_keys[freq]
115
+ if self._min_freq == freq:
116
+ self._min_freq = freq + 1
117
+
118
+ new_freq = freq + 1
119
+ self._freq[key] = new_freq
120
+ self._freq_to_keys[new_freq].append(key)
121
+
122
+ def _evict(self) -> None:
123
+ """淘汰访问频率最低且最早插入的元素。"""
124
+ keys = self._freq_to_keys[self._min_freq]
125
+ evict_key = keys.pop(0)
126
+ if not keys:
127
+ del self._freq_to_keys[self._min_freq]
128
+ del self._cache[evict_key]
129
+ del self._freq[evict_key]
@@ -0,0 +1,93 @@
1
+ from collections import OrderedDict
2
+ from typing import Any, KeysView
3
+
4
+
5
+ class LRUCache:
6
+ """LRU(最近最少使用)缓存实现。
7
+
8
+ 当缓存满时,最近最少使用的元素会被淘汰。
9
+ 每次get操作会将元素移至最新位置。
10
+ """
11
+
12
+ def __init__(self, capacity: int = 16) -> None:
13
+ """初始化LRU缓存。
14
+
15
+ :param capacity: 缓存最大容量,默认16
16
+ """
17
+ self._capacity: int = capacity
18
+ self._cache: OrderedDict = OrderedDict()
19
+
20
+ def get(self, key: Any, default: Any = None) -> Any:
21
+ """获取缓存值,并将该元素移至最新位置。
22
+
23
+ :param key: 缓存键
24
+ :param default: 键不存在时返回的默认值
25
+ :return: 缓存值,不存在时返回默认值
26
+ """
27
+ if key not in self._cache:
28
+ return default
29
+ self._cache.move_to_end(key)
30
+ return self._cache[key]
31
+
32
+ def put(self, key: Any, value: Any) -> None:
33
+ """放入缓存。如果键已存在则更新并移至最新位置;
34
+ 如果缓存已满,淘汰最近最少使用的元素。
35
+
36
+ :param key: 缓存键
37
+ :param value: 缓存值
38
+ """
39
+ if key in self._cache:
40
+ self._cache.move_to_end(key)
41
+ self._cache[key] = value
42
+ return
43
+ if len(self._cache) >= self._capacity:
44
+ self._cache.popitem(last=False)
45
+ self._cache[key] = value
46
+
47
+ def remove(self, key: Any) -> Any:
48
+ """移除指定键的缓存。
49
+
50
+ :param key: 缓存键
51
+ :return: 被移除的值,键不存在时返回None
52
+ """
53
+ return self._cache.pop(key, None)
54
+
55
+ def size(self) -> int:
56
+ """获取当前缓存大小。
57
+
58
+ :return: 当前缓存条目数
59
+ """
60
+ return len(self._cache)
61
+
62
+ def capacity(self) -> int:
63
+ """获取缓存最大容量。
64
+
65
+ :return: 缓存最大容量
66
+ """
67
+ return self._capacity
68
+
69
+ def clear(self) -> None:
70
+ """清空所有缓存。"""
71
+ self._cache.clear()
72
+
73
+ def is_full(self) -> bool:
74
+ """判断缓存是否已满。
75
+
76
+ :return: 缓存已满返回True,否则返回False
77
+ """
78
+ return len(self._cache) >= self._capacity
79
+
80
+ def keys(self) -> KeysView:
81
+ """获取所有缓存键,按使用顺序排列。
82
+
83
+ :return: 缓存键的视图(从最久未使用到最近使用)
84
+ """
85
+ return self._cache.keys()
86
+
87
+ def __contains__(self, key: Any) -> bool:
88
+ """判断键是否存在于缓存中。"""
89
+ return key in self._cache
90
+
91
+ def __len__(self) -> int:
92
+ """返回缓存大小。"""
93
+ return len(self._cache)
@@ -0,0 +1,115 @@
1
+ import threading
2
+ import time
3
+ from typing import Any, Optional
4
+
5
+
6
+ class TimedCache:
7
+ """定时缓存实现。
8
+
9
+ 每个缓存条目可以设置独立的过期时间,过期后自动失效。
10
+ 支持定时清理过期条目以释放内存。
11
+ """
12
+
13
+ def __init__(self, timeout: int = 60) -> None:
14
+ """初始化定时缓存。
15
+
16
+ :param timeout: 默认过期时间(秒),默认60秒
17
+ """
18
+ self._timeout: int = timeout
19
+ self._cache: dict = {} # key -> (value, expire_time)
20
+ self._lock: threading.Lock = threading.Lock()
21
+ self._prune_timer: Optional[threading.Timer] = None
22
+
23
+ def get(self, key: Any, default: Any = None) -> Any:
24
+ """获取缓存值。若已过期则返回默认值。
25
+
26
+ :param key: 缓存键
27
+ :param default: 键不存在或已过期时返回的默认值
28
+ :return: 缓存值,不存在或已过期时返回默认值
29
+ """
30
+ with self._lock:
31
+ if key not in self._cache:
32
+ return default
33
+ value, expire_time = self._cache[key]
34
+ if time.time() > expire_time:
35
+ del self._cache[key]
36
+ return default
37
+ return value
38
+
39
+ def put(self, key: Any, value: Any, timeout: Optional[int] = None) -> None:
40
+ """放入缓存。
41
+
42
+ :param key: 缓存键
43
+ :param value: 缓存值
44
+ :param timeout: 过期时间(秒),为None时使用默认过期时间
45
+ """
46
+ expire_time = time.time() + (timeout if timeout is not None else self._timeout)
47
+ with self._lock:
48
+ self._cache[key] = (value, expire_time)
49
+
50
+ def remove(self, key: Any) -> Any:
51
+ """移除指定键的缓存。
52
+
53
+ :param key: 缓存键
54
+ :return: 被移除的值,键不存在时返回None
55
+ """
56
+ with self._lock:
57
+ entry = self._cache.pop(key, None)
58
+ if entry is None:
59
+ return None
60
+ value, _ = entry
61
+ return value
62
+
63
+ def size(self) -> int:
64
+ """获取当前缓存大小(包含已过期但未清理的条目)。
65
+
66
+ :return: 当前缓存条目数
67
+ """
68
+ with self._lock:
69
+ return len(self._cache)
70
+
71
+ def clear(self) -> None:
72
+ """清空所有缓存。"""
73
+ with self._lock:
74
+ self._cache.clear()
75
+
76
+ def prune(self) -> int:
77
+ """清理过期缓存条目。
78
+
79
+ :return: 被清理的条目数
80
+ """
81
+ now = time.time()
82
+ expired_keys: list = []
83
+ with self._lock:
84
+ for key, (_, expire_time) in self._cache.items():
85
+ if now > expire_time:
86
+ expired_keys.append(key)
87
+ for key in expired_keys:
88
+ del self._cache[key]
89
+ return len(expired_keys)
90
+
91
+ def schedule_prune(self, delay_seconds: int = 60) -> None:
92
+ """启动定时清理线程,定期清理过期缓存。
93
+
94
+ :param delay_seconds: 清理间隔(秒),默认60秒
95
+ """
96
+ self._cancel_prune_timer()
97
+ self._prune_timer = threading.Timer(delay_seconds, self._prune_callback, args=(delay_seconds,))
98
+ self._prune_timer.daemon = True
99
+ self._prune_timer.start()
100
+
101
+ def _prune_callback(self, delay_seconds: int) -> None:
102
+ """清理回调,执行清理后重新调度。
103
+
104
+ :param delay_seconds: 下次清理间隔(秒)
105
+ """
106
+ self.prune()
107
+ self._prune_timer = threading.Timer(delay_seconds, self._prune_callback, args=(delay_seconds,))
108
+ self._prune_timer.daemon = True
109
+ self._prune_timer.start()
110
+
111
+ def _cancel_prune_timer(self) -> None:
112
+ """取消定时清理线程。"""
113
+ if self._prune_timer is not None:
114
+ self._prune_timer.cancel()
115
+ self._prune_timer = None
@@ -0,0 +1,3 @@
1
+ from .captcha_util import ArithmeticCaptcha, CaptchaUtil, LineCaptcha
2
+
3
+ __all__ = ["ArithmeticCaptcha", "CaptchaUtil", "LineCaptcha"]