pyutilities_simple 0.1.0__tar.gz

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.
@@ -0,0 +1,207 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+ #poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ #pdm.lock
116
+ #pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ #pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # SageMath parsed files
135
+ *.sage.py
136
+
137
+ # Environments
138
+ .env
139
+ .envrc
140
+ .venv
141
+ env/
142
+ venv/
143
+ ENV/
144
+ env.bak/
145
+ venv.bak/
146
+
147
+ # Spyder project settings
148
+ .spyderproject
149
+ .spyproject
150
+
151
+ # Rope project settings
152
+ .ropeproject
153
+
154
+ # mkdocs documentation
155
+ /site
156
+
157
+ # mypy
158
+ .mypy_cache/
159
+ .dmypy.json
160
+ dmypy.json
161
+
162
+ # Pyre type checker
163
+ .pyre/
164
+
165
+ # pytype static type analyzer
166
+ .pytype/
167
+
168
+ # Cython debug symbols
169
+ cython_debug/
170
+
171
+ # PyCharm
172
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
173
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
174
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
175
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
176
+ #.idea/
177
+
178
+ # Abstra
179
+ # Abstra is an AI-powered process automation framework.
180
+ # Ignore directories containing user credentials, local state, and settings.
181
+ # Learn more at https://abstra.io/docs
182
+ .abstra/
183
+
184
+ # Visual Studio Code
185
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
188
+ # you could uncomment the following to ignore the entire vscode folder
189
+ # .vscode/
190
+
191
+ # Ruff stuff:
192
+ .ruff_cache/
193
+
194
+ # PyPI configuration file
195
+ .pypirc
196
+
197
+ # Cursor
198
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
199
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
200
+ # refer to https://docs.cursor.com/context/ignore-files
201
+ .cursorignore
202
+ .cursorindexingignore
203
+
204
+ # Marimo
205
+ marimo/_static/
206
+ marimo/_lsp/
207
+ __marimo__/
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 YoucheeXu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,30 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyutilities_simple
3
+ Version: 0.1.0
4
+ Summary: Add your description here
5
+ Project-URL: Homepage, https://github.com/YoucheeXu/pyutilities
6
+ Project-URL: Issues, https://github.com/YoucheeXu/pyutilities/issues
7
+ Author-email: Youchee <youchi.xu@live.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python :: 3
12
+ Requires-Python: >=3.13
13
+ Description-Content-Type: text/markdown
14
+
15
+ # Readme
16
+
17
+ [TOC]
18
+
19
+ ## test
20
+
21
+ ```bash
22
+ uv pip install -e .
23
+ ```
24
+
25
+ ## build & publish
26
+
27
+ ```bash
28
+ uv build
29
+ uv publish
30
+ ```
@@ -0,0 +1,16 @@
1
+ # Readme
2
+
3
+ [TOC]
4
+
5
+ ## test
6
+
7
+ ```bash
8
+ uv pip install -e .
9
+ ```
10
+
11
+ ## build & publish
12
+
13
+ ```bash
14
+ uv build
15
+ uv publish
16
+ ```
@@ -0,0 +1,32 @@
1
+ [project]
2
+ name = "pyutilities_simple"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Youchee", email = "youchi.xu@live.com" }
8
+ ]
9
+ requires-python = ">=3.13"
10
+ dependencies = []
11
+
12
+ classifiers = [
13
+ "Programming Language :: Python :: 3",
14
+ "Operating System :: OS Independent",
15
+ ]
16
+ license = "MIT"
17
+ license-files = ["LICEN[CS]E*"]
18
+
19
+ [project.urls]
20
+ Homepage = "https://github.com/YoucheeXu/pyutilities"
21
+ Issues = "https://github.com/YoucheeXu/pyutilities/issues"
22
+
23
+ [build-system]
24
+ requires = ["hatchling"]
25
+ build-backend = "hatchling.build"
26
+
27
+ [dependency-groups]
28
+ dev = [
29
+ "pytest>=9.0.2",
30
+ "pytest-cov>=7.0.0",
31
+ "pytest-timeout>=2.4.0",
32
+ ]
@@ -0,0 +1,3 @@
1
+ [pytest]
2
+ # 将当前目录(pygui)加入Python模块搜索路径
3
+ pythonpath = .
@@ -0,0 +1,2 @@
1
+ def main() -> None:
2
+ print("Hello from pyutilities!")
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/python3
2
+ # -*- coding: UTF-8 -*-
3
+ import sys
4
+ from types import ModuleType
5
+ from typing import Final, Callable
6
+
7
+ from pyutilities_simple.singleton import singleton
8
+
9
+
10
+ @singleton
11
+ class _const(ModuleType):
12
+ """ 单例模式的常量管理模块
13
+
14
+ 特性:
15
+ - 常量名称必须全大写(强制命名规范)
16
+ - 常量一旦定义不可修改或删除(只读特性)
17
+ - 全局唯一实例,确保常量在整个程序中保持一致
18
+ """
19
+
20
+ class ConstError(PermissionError):
21
+ """尝试修改或删除已定义常量时触发的异常"""
22
+ pass
23
+
24
+ class ConstCaseError(TypeError):
25
+ """常量名称不是全大写时触发的异常"""
26
+ pass
27
+
28
+ def __init__(self, module_name: str | None = None) -> None:
29
+ """初始化常量模块,继承ModuleType的特性"""
30
+ # 确定模块名称,默认使用当前模块名
31
+ name = module_name if module_name is not None else __name__
32
+ super().__init__(name)
33
+
34
+ # 初始化内置属性(标记为"内置",清空时保留)
35
+ self.__dict__["__version__"] = "1.0.0"
36
+ self.__dict__["__description__"] = "A singleton-based constant management module"
37
+ # 手动绑定模块原生属性(解决coverage访问__file__的问题)
38
+ self.__dict__["__file__"] = sys.modules[name].__file__ if name in sys.modules else __file__
39
+ self.__dict__["__name__"] = name
40
+
41
+ def __setattr__(self, name: str, value: object) -> None:
42
+ """ 重写属性设置方法,实现常量约束:
43
+ 1. 已存在的常量不允许重新赋值
44
+ 2. 常量名称必须使用全大写字母
45
+ """
46
+ # 跳过内置特殊属性的设置(避免覆盖__file__等)
47
+ if name.startswith("__") and name.endswith("__"):
48
+ self.__dict__[name] = value
49
+ return
50
+ # 校验1:不允许重复赋值(已存在则报错)
51
+ if name in self.__dict__:
52
+ raise self.ConstError(f"Cannot modify constant '{name}': constants are immutable")
53
+ # 校验2:名称必须全大写
54
+ if not name.isupper():
55
+ raise self.ConstCaseError(f"Constant name '{name}' must be in uppercase")
56
+ # 合法常量:添加到字典
57
+ self.__dict__[name] = value
58
+
59
+ def __delattr__(self, name: str) -> None:
60
+ """重写属性删除方法,禁止删除已定义的常量"""
61
+ # 跳过内置特殊属性的设置(避免覆盖__file__等)
62
+ if name.startswith("__") and name.endswith("__"):
63
+ raise self.ConstError(f"Cannot delete built-in attribute '{name}'")
64
+ if name in self.__dict__:
65
+ raise self.ConstError(f"Cannot delete constant '{name}': constants cannot be deleted")
66
+ raise NameError(f"Constant '{name}' is not defined")
67
+
68
+ def __getattr__(self, name: str) -> object:
69
+ """获取属性:内置属性正常返回,未定义常量抛异常"""
70
+ if name.startswith("__") and name.endswith("__"):
71
+ return super().__getattribute__(name)
72
+ if name not in self.__dict__:
73
+ raise NameError(f"Constant '{name}' is not defined")
74
+ return self.__dict__[name]
75
+
76
+ def list_constants(self) -> list[str]:
77
+ """返回所有用户定义的常量名称(排除模块内置属性)"""
78
+ return [
79
+ name for name in sorted(self.__dict__.keys())
80
+ if name.isupper() and not name.startswith("__")
81
+ ]
82
+
83
+ def get_constant(self, name: str) -> object | None:
84
+ """安全获取常量值,不存在时返回None而非抛出异常"""
85
+ return self.__dict__.get(name)
86
+
87
+ def clear_user_constants(self) -> None:
88
+ """彻底清空所有用户常量(保留内置属性)"""
89
+ # 遍历并删除所有用户定义的常量(全大写、非双下划线)
90
+ for name in list(self.__dict__.keys()): # 转列表避免遍历中修改字典
91
+ if name.isupper() and not name.startswith("__"):
92
+ del self.__dict__[name]
93
+
94
+
95
+ # 替换模块为单例实例(全局唯一)
96
+ sys.modules[__name__] = _const(__name__)
97
+
98
+
99
+ # 导出公共接口
100
+ __all__ = ["ConstError", "ConstCaseError", "list_constants", "get_constant", "clear_user_constants"]
101
+
102
+ # 为公共接口添加Final类型提示,明确其不可修改性,绑定模块级接口
103
+ list_constants: Final[Callable[[], list[str]]] = sys.modules[__name__].list_constants
104
+ get_constant: Final[Callable[[str], object | None]] = sys.modules[__name__].get_constant
105
+ ConstError: Final[type[PermissionError]] = sys.modules[__name__].ConstError
106
+ ConstCaseError: Final[type[TypeError]] = sys.modules[__name__].ConstCaseError
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/python3
2
+ # -*- coding: UTF-8 -*-
3
+ import sys
4
+ from types import ModuleType
5
+ from typing import Final, Callable, override, cast
6
+
7
+ from pyutilities_simple.singleton import singleton
8
+
9
+ @singleton
10
+ class GlobalVarModule(ModuleType):
11
+ """
12
+ 单例模式的全局变量管理模块
13
+ 特性:
14
+ 1. 全局唯一实例,跨模块共享变量
15
+ 2. 支持安全获取变量(不存在返回None)
16
+ 3. 支持列出所有全局变量
17
+ 4. 支持清空全局变量(主要用于测试)
18
+ 5. 可选只读变量保护
19
+ """
20
+ # 内置只读变量(不可修改/删除)
21
+ _READ_ONLY_KEYS: Final[list[str]] = ["ver"]
22
+
23
+ def __init__(self, module_name: str = __name__) -> None:
24
+ """初始化全局变量模块,继承ModuleType以兼容模块特性"""
25
+ super().__init__(module_name)
26
+ # 初始化内置版本号(只读)
27
+ self.__dict__["ver"] = "0.1.0"
28
+ # 模块元信息
29
+ self.__dict__["__description__"] = "Singleton-based global variable manager"
30
+
31
+ @override
32
+ def __setattr__(self, name: str, value: object) -> None:
33
+ """重写属性设置:保护只读变量"""
34
+ # 保护内置只读变量
35
+ if name in self._READ_ONLY_KEYS and name in self.__dict__:
36
+ raise PermissionError(f"Read-only variable '{name}' cannot be modified")
37
+ self.__dict__[name] = value
38
+
39
+ @override
40
+ def __delattr__(self, name: str) -> None:
41
+ """重写属性删除:保护只读变量"""
42
+ if name in self._READ_ONLY_KEYS:
43
+ raise PermissionError(f"Read-only variable '{name}' cannot be deleted")
44
+ if name not in self.__dict__:
45
+ raise NameError(f"Global variable '{name}' does not exist")
46
+ del self.__dict__[name]
47
+
48
+ def get_var(self, name: str, default: object = None):
49
+ """
50
+ 安全获取全局变量
51
+ Args:
52
+ name: 变量名
53
+ default: 不存在时的默认值(默认None)
54
+ Returns:
55
+ 变量值或默认值
56
+ """
57
+ return cast(object, self.__dict__.get(name, default))
58
+
59
+ def list_vars(self):
60
+ """返回所有用户定义的全局变量(排除内置属性)"""
61
+ return [
62
+ name for name in sorted(self.__dict__.keys())
63
+ if not name.startswith("__") and name not in self._READ_ONLY_KEYS
64
+ ]
65
+
66
+ def list_all_vars(self):
67
+ """返回所有变量(包含内置/只读变量)"""
68
+ return sorted(self.__dict__.keys())
69
+
70
+ def clear_vars(self):
71
+ """清空所有非只读的全局变量(仅用于测试/重置)"""
72
+ for name in self.list_vars():
73
+ del self.__dict__[name]
74
+
75
+ # 将模块替换为单例实例,实现全局唯一
76
+ sys.modules[__name__] = GlobalVarModule(__name__)
77
+
78
+ # 导出公共接口(增强类型提示)
79
+ __all__ = ["get_var", "list_vars", "list_all_vars", "clear_vars"]
80
+
81
+ # 绑定模块级接口(适配直接调用)
82
+ get_var: Final[Callable[[str, object | None], object | None]] = sys.modules[__name__].get_var
83
+ list_vars: Final[Callable[[], list[str]]] = sys.modules[__name__].list_vars
84
+ list_all_vars: Final[Callable[[], list[str]]] = sys.modules[__name__].list_all_vars
85
+ clear_vars: Final[Callable[[], None]] = sys.modules[__name__].clear_vars