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.
- hutool/__init__.py +174 -0
- hutool/cache/__init__.py +7 -0
- hutool/cache/cache_util.py +47 -0
- hutool/cache/fifo_cache.py +87 -0
- hutool/cache/lfu_cache.py +129 -0
- hutool/cache/lru_cache.py +93 -0
- hutool/cache/timed_cache.py +115 -0
- hutool/captcha/__init__.py +3 -0
- hutool/captcha/captcha_util.py +215 -0
- hutool/core/__init__.py +23 -0
- hutool/core/_base.py +61 -0
- hutool/core/bean.py +214 -0
- hutool/core/codec.py +111 -0
- hutool/core/coll.py +635 -0
- hutool/core/date.py +1024 -0
- hutool/core/exceptions.py +66 -0
- hutool/core/io/__init__.py +0 -0
- hutool/core/io/data_size_util.py +79 -0
- hutool/core/io/file_name_util.py +111 -0
- hutool/core/io/file_util.py +650 -0
- hutool/core/io/io_util.py +133 -0
- hutool/core/io/path_util.py +247 -0
- hutool/core/io/resource_util.py +137 -0
- hutool/core/map.py +933 -0
- hutool/core/math_util.py +105 -0
- hutool/core/net.py +288 -0
- hutool/core/text/__init__.py +0 -0
- hutool/core/text/csv_util.py +54 -0
- hutool/core/text/str_builder.py +224 -0
- hutool/core/text/unicode_util.py +58 -0
- hutool/core/tree.py +242 -0
- hutool/core/util/__init__.py +63 -0
- hutool/core/util/array_util.py +503 -0
- hutool/core/util/boolean_util.py +124 -0
- hutool/core/util/charset_util.py +60 -0
- hutool/core/util/class_util.py +136 -0
- hutool/core/util/coordinate_util.py +186 -0
- hutool/core/util/credit_code_util.py +110 -0
- hutool/core/util/desensitized_util.py +194 -0
- hutool/core/util/enum_util.py +94 -0
- hutool/core/util/escape_util.py +97 -0
- hutool/core/util/hash_util.py +243 -0
- hutool/core/util/hex_util.py +140 -0
- hutool/core/util/id_util.py +147 -0
- hutool/core/util/idcard_util.py +300 -0
- hutool/core/util/number_util.py +720 -0
- hutool/core/util/object_util.py +294 -0
- hutool/core/util/page_util.py +61 -0
- hutool/core/util/phone_util.py +140 -0
- hutool/core/util/random_util.py +112 -0
- hutool/core/util/re_util.py +231 -0
- hutool/core/util/reflect_util.py +135 -0
- hutool/core/util/runtime_util.py +89 -0
- hutool/core/util/str_util.py +2320 -0
- hutool/core/util/system_util.py +62 -0
- hutool/core/util/url_util.py +232 -0
- hutool/core/util/version_util.py +41 -0
- hutool/core/util/xml_util.py +158 -0
- hutool/core/util/zip_util.py +126 -0
- hutool/cron/__init__.py +4 -0
- hutool/cron/cron_pattern.py +123 -0
- hutool/cron/cron_util.py +115 -0
- hutool/crypto/__init__.py +5 -0
- hutool/crypto/digest_util.py +167 -0
- hutool/crypto/secure_util.py +311 -0
- hutool/crypto/sign_util.py +74 -0
- hutool/dfa/__init__.py +3 -0
- hutool/dfa/sensitive_util.py +114 -0
- hutool/extra/__init__.py +6 -0
- hutool/extra/emoji_util.py +90 -0
- hutool/extra/pinyin_util.py +44 -0
- hutool/extra/qr_code_util.py +58 -0
- hutool/extra/template_util.py +41 -0
- hutool/http/__init__.py +6 -0
- hutool/http/html_util.py +88 -0
- hutool/http/http_request.py +188 -0
- hutool/http/http_response.py +139 -0
- hutool/http/http_util.py +237 -0
- hutool/json_util.py +251 -0
- hutool/jwt_util.py +57 -0
- hutool/setting/__init__.py +5 -0
- hutool/setting/props_util.py +79 -0
- hutool/setting/setting_util.py +80 -0
- hutool/setting/yaml_util.py +45 -0
- hutool_python-1.0.0.dist-info/LICENSE +127 -0
- hutool_python-1.0.0.dist-info/METADATA +438 -0
- hutool_python-1.0.0.dist-info/RECORD +89 -0
- hutool_python-1.0.0.dist-info/WHEEL +5 -0
- hutool_python-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""异常类定义,对应 Java cn.hutool.core.exceptions。"""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class UtilException(Exception):
|
|
5
|
+
"""工具类通用异常。
|
|
6
|
+
|
|
7
|
+
对应 Java cn.hutool.core.exceptions.UtilException。
|
|
8
|
+
支持 format 风格的消息格式化。
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, message: str, *args):
|
|
12
|
+
if args:
|
|
13
|
+
message = message.format(*args)
|
|
14
|
+
super().__init__(message)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class IORuntimeException(UtilException):
|
|
18
|
+
"""IO 运行时异常。
|
|
19
|
+
|
|
20
|
+
对应 Java cn.hutool.core.exceptions.IORuntimeException。
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, message: str, *args):
|
|
24
|
+
super().__init__(message, *args)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class StatefulException(UtilException):
|
|
28
|
+
"""有状态的异常,可携带额外状态信息。"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, message: str, *args):
|
|
31
|
+
super().__init__(message, *args)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class NotInitedException(UtilException):
|
|
35
|
+
"""未初始化异常。"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, message: str = "Not initialized", *args):
|
|
38
|
+
super().__init__(message, *args)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class NullPointerException(UtilException):
|
|
42
|
+
"""空指针异常。"""
|
|
43
|
+
|
|
44
|
+
def __init__(self, message: str = "Null pointer", *args):
|
|
45
|
+
super().__init__(message, *args)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class IllegalArgumentException(UtilException):
|
|
49
|
+
"""非法参数异常。"""
|
|
50
|
+
|
|
51
|
+
def __init__(self, message: str, *args):
|
|
52
|
+
super().__init__(message, *args)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class IllegalStateException(UtilException):
|
|
56
|
+
"""非法状态异常。"""
|
|
57
|
+
|
|
58
|
+
def __init__(self, message: str, *args):
|
|
59
|
+
super().__init__(message, *args)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class UnsupportedOperationException(UtilException):
|
|
63
|
+
"""不支持的操作异常。"""
|
|
64
|
+
|
|
65
|
+
def __init__(self, message: str = "Unsupported operation", *args):
|
|
66
|
+
super().__init__(message, *args)
|
|
File without changes
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""数据大小工具模块"""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import Dict
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DataSizeUtil:
|
|
8
|
+
"""数据大小工具类"""
|
|
9
|
+
|
|
10
|
+
_UNITS: Dict[str, int] = {
|
|
11
|
+
"B": 1,
|
|
12
|
+
"KB": 1024,
|
|
13
|
+
"MB": 1024**2,
|
|
14
|
+
"GB": 1024**3,
|
|
15
|
+
"TB": 1024**4,
|
|
16
|
+
"PB": 1024**5,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
# 用于匹配 "数字 + 可选空格 + 单位" 的正则
|
|
20
|
+
_SIZE_PATTERN = re.compile(
|
|
21
|
+
r"^\s*(\d+(?:\.\d+)?)\s*(B|KB|MB|GB|TB|PB)\s*$",
|
|
22
|
+
re.IGNORECASE,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def parse(size_str: str) -> int:
|
|
27
|
+
"""解析数据大小字符串为字节数
|
|
28
|
+
|
|
29
|
+
支持的单位(不区分大小写): B, KB, MB, GB, TB, PB
|
|
30
|
+
|
|
31
|
+
示例::
|
|
32
|
+
|
|
33
|
+
DataSizeUtil.parse("10KB") -> 10240
|
|
34
|
+
DataSizeUtil.parse("1.5GB") -> 1610612736
|
|
35
|
+
DataSizeUtil.parse("512 B") -> 512
|
|
36
|
+
|
|
37
|
+
:param size_str: 数据大小字符串,如 "10KB"、"1.5 GB"
|
|
38
|
+
:return: 对应的字节数(int)
|
|
39
|
+
:raises ValueError: 无法解析时抛出
|
|
40
|
+
"""
|
|
41
|
+
match = DataSizeUtil._SIZE_PATTERN.match(size_str)
|
|
42
|
+
if not match:
|
|
43
|
+
raise ValueError(f"无法解析数据大小字符串: '{size_str}'")
|
|
44
|
+
number = float(match.group(1))
|
|
45
|
+
unit = match.group(2).upper()
|
|
46
|
+
multiplier = DataSizeUtil._UNITS[unit]
|
|
47
|
+
return int(number * multiplier)
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def format_size(size: int) -> str:
|
|
51
|
+
"""将字节数格式化为可读字符串
|
|
52
|
+
|
|
53
|
+
自动选择最合适的单位,保留两位小数并去除末尾的零。
|
|
54
|
+
|
|
55
|
+
示例::
|
|
56
|
+
|
|
57
|
+
DataSizeUtil.format_size(10240) -> "10KB"
|
|
58
|
+
DataSizeUtil.format_size(1073741824) -> "1GB"
|
|
59
|
+
DataSizeUtil.format_size(512) -> "512B"
|
|
60
|
+
|
|
61
|
+
:param size: 字节数
|
|
62
|
+
:return: 格式化后的字符串
|
|
63
|
+
"""
|
|
64
|
+
if size < 0:
|
|
65
|
+
return "-" + DataSizeUtil.format_size(-size)
|
|
66
|
+
|
|
67
|
+
if size < DataSizeUtil._UNITS["KB"]:
|
|
68
|
+
return f"{size}B"
|
|
69
|
+
|
|
70
|
+
# 从大到小尝试匹配合适的单位
|
|
71
|
+
for unit in ("PB", "TB", "GB", "MB", "KB"):
|
|
72
|
+
unit_size = DataSizeUtil._UNITS[unit]
|
|
73
|
+
if size >= unit_size:
|
|
74
|
+
value = size / unit_size
|
|
75
|
+
# 保留两位小数,去除末尾多余的零和小数点
|
|
76
|
+
formatted = f"{value:.2f}".rstrip("0").rstrip(".")
|
|
77
|
+
return f"{formatted}{unit}"
|
|
78
|
+
|
|
79
|
+
return f"{size}B"
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""文件名工具模块"""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
from typing import List
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FileNameUtil:
|
|
9
|
+
"""文件名工具类"""
|
|
10
|
+
|
|
11
|
+
# 文件名中不允许出现的字符(Windows + 通用)
|
|
12
|
+
_INVALID_CHARS = re.compile(r'[<>:"/\\|?*\x00-\x1f]')
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def get_name(path: str) -> str:
|
|
16
|
+
"""获取文件名(含扩展名)
|
|
17
|
+
|
|
18
|
+
:param path: 文件路径
|
|
19
|
+
:return: 文件名,如 "document.txt"
|
|
20
|
+
"""
|
|
21
|
+
return os.path.basename(path)
|
|
22
|
+
|
|
23
|
+
@staticmethod
|
|
24
|
+
def get_prefix(path: str) -> str:
|
|
25
|
+
"""获取文件名前缀(不含扩展名)
|
|
26
|
+
|
|
27
|
+
:param path: 文件路径
|
|
28
|
+
:return: 文件名前缀,如 "document"
|
|
29
|
+
"""
|
|
30
|
+
name = os.path.basename(path)
|
|
31
|
+
dot_index = name.rfind(".")
|
|
32
|
+
if dot_index <= 0:
|
|
33
|
+
return name
|
|
34
|
+
return name[:dot_index]
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def get_suffix(path: str) -> str:
|
|
38
|
+
"""获取扩展名(不含点)
|
|
39
|
+
|
|
40
|
+
:param path: 文件路径
|
|
41
|
+
:return: 扩展名,如 "txt";无扩展名时返回空字符串
|
|
42
|
+
"""
|
|
43
|
+
name = os.path.basename(path)
|
|
44
|
+
dot_index = name.rfind(".")
|
|
45
|
+
if dot_index < 0 or dot_index == len(name) - 1:
|
|
46
|
+
return ""
|
|
47
|
+
return name[dot_index + 1 :]
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def main_name(path: str) -> str:
|
|
51
|
+
"""获取主文件名(等同于 get_prefix)
|
|
52
|
+
|
|
53
|
+
:param path: 文件路径
|
|
54
|
+
:return: 主文件名
|
|
55
|
+
"""
|
|
56
|
+
return FileNameUtil.get_prefix(path)
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def ext_name(path: str) -> str:
|
|
60
|
+
"""获取扩展名(同 get_suffix)
|
|
61
|
+
|
|
62
|
+
:param path: 文件路径
|
|
63
|
+
:return: 扩展名
|
|
64
|
+
"""
|
|
65
|
+
return FileNameUtil.get_suffix(path)
|
|
66
|
+
|
|
67
|
+
@staticmethod
|
|
68
|
+
def normalize(path: str) -> str:
|
|
69
|
+
"""标准化文件名路径
|
|
70
|
+
|
|
71
|
+
将路径中的反斜杠统一替换为正斜杠,并去除多余分隔符。
|
|
72
|
+
|
|
73
|
+
:param path: 文件路径
|
|
74
|
+
:return: 标准化后的路径
|
|
75
|
+
"""
|
|
76
|
+
normalized = path.replace("\\", "/")
|
|
77
|
+
# 去除连续的斜杠(保留开头的 ./ 或协议部分)
|
|
78
|
+
parts = normalized.split("/")
|
|
79
|
+
result_parts: List[str] = []
|
|
80
|
+
for part in parts:
|
|
81
|
+
if part == "" and result_parts:
|
|
82
|
+
continue
|
|
83
|
+
result_parts.append(part)
|
|
84
|
+
return "/".join(result_parts)
|
|
85
|
+
|
|
86
|
+
@staticmethod
|
|
87
|
+
def clean_invalid(name: str) -> str:
|
|
88
|
+
"""清理文件名中的非法字符
|
|
89
|
+
|
|
90
|
+
移除 Windows 及通用文件系统中不允许出现的字符。
|
|
91
|
+
|
|
92
|
+
:param name: 原始文件名
|
|
93
|
+
:return: 清理后的合法文件名
|
|
94
|
+
"""
|
|
95
|
+
cleaned = FileNameUtil._INVALID_CHARS.sub("", name)
|
|
96
|
+
# 去除首尾空格和点(Windows 不允许)
|
|
97
|
+
cleaned = cleaned.strip(" .")
|
|
98
|
+
return cleaned if cleaned else "unnamed"
|
|
99
|
+
|
|
100
|
+
@staticmethod
|
|
101
|
+
def is_type(path: str, ext: str) -> bool:
|
|
102
|
+
"""检查文件扩展名是否匹配
|
|
103
|
+
|
|
104
|
+
比较时忽略大小写。
|
|
105
|
+
|
|
106
|
+
:param path: 文件路径
|
|
107
|
+
:param ext: 期望的扩展名(不含点,如 "txt")
|
|
108
|
+
:return: 匹配返回 True,否则 False
|
|
109
|
+
"""
|
|
110
|
+
actual = FileNameUtil.get_suffix(path)
|
|
111
|
+
return actual.lower() == ext.lower().lstrip(".")
|