object-pool-async 0.1.2__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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jerry
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,178 @@
1
+ Metadata-Version: 2.4
2
+ Name: object-pool-async
3
+ Version: 0.1.2
4
+ Summary: A generic, async-first object pool for Python
5
+ Author-email: Your Name <your.email@example.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Jerry-Wu-GitHub/object-pool
8
+ Keywords: object-pool,async,connection-pool
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Requires-Python: >=3.10
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Dynamic: license-file
21
+
22
+ # Object Pool
23
+
24
+ 一个功能丰富、支持异步的通用对象池,提供细粒度的对象生命周期管理、状态检测、超时回收和灵活的定制能力。
25
+
26
+ ## 特性
27
+
28
+ - ✅ **异步优先**:原生支持 `asyncio`,在高并发 I/O 场景下性能优异
29
+ - 🔄 **完整生命周期**:管理对象的 `PENDING`、`AVAILABLE`、`BORROWED`、`INVALID`、`DORMANT`、`UNKNOWN` 状态
30
+ - ⏱️ **超时回收**:支持对象级别的借出超时自动回收
31
+ - 🧩 **高度可定制**:可自定义状态检测器、对象选择器、包装器(Wrapper)和打包器(Packer)
32
+ - 🚦 **并发控制**:内置并发度限制,批量操作自动分块
33
+ - 🔁 **双 API**:同时提供异步(`*_async`)和同步接口
34
+ - 🧵 **协程安全**:基于 `AsyncRLock` 实现,在单事件循环多协程下安全
35
+
36
+ ## 安装
37
+
38
+ ```bash
39
+ pip install object-pool
40
+ ```
41
+
42
+ 或从源码安装:
43
+
44
+ ```bash
45
+ git clone https://github.com/Jerry-Wu-GitHub/object-pool.git
46
+ cd object-pool
47
+ pip install -e .
48
+ ```
49
+
50
+ ## 快速开始
51
+
52
+ ### 同步使用
53
+
54
+ ```python
55
+ from object_pool import Pool, Status
56
+ from datetime import timedelta
57
+
58
+ # 定义一个简单的状态检测函数
59
+ def check_status(wrapper):
60
+ # 假设对象有一个 is_alive 属性
61
+ if wrapper.object.is_alive():
62
+ return Status.AVAILABLE
63
+ return Status.INVALID
64
+
65
+ # 创建对象池
66
+ pool = Pool(detect_status=check_status)
67
+
68
+ # 添加对象
69
+ obj = MyResource()
70
+ pool.add(obj)
71
+
72
+ # 借出对象
73
+ with pool.borrow() as resource:
74
+ resource.do_something()
75
+ # 离开上下文时自动归还
76
+
77
+ # 手动归还
78
+ pack = pool.borrow()
79
+ pack.close() # 归还
80
+ ```
81
+
82
+ ### 异步使用
83
+
84
+ ```python
85
+ import asyncio
86
+ from object_pool import Pool, Status
87
+
88
+ async def check_status_async(wrapper):
89
+ # 异步检测对象健康状态
90
+ if await wrapper.object.ping():
91
+ return Status.AVAILABLE
92
+ return Status.INVALID
93
+
94
+ async def main():
95
+ pool = Pool(detect_status=check_status_async)
96
+ obj = AsyncResource()
97
+ await pool.add_async(obj)
98
+
99
+ pack = await pool.borrow_async(timeout=3.0)
100
+ try:
101
+ await pack.object.work()
102
+ finally:
103
+ pack.close() # 归还
104
+
105
+ # 或使用异步上下文管理器
106
+ async with await pool.borrow_async() as resource:
107
+ await resource.work()
108
+
109
+ asyncio.run(main())
110
+ ```
111
+
112
+ ## 高级用法
113
+
114
+ ### 自定义对象选择器
115
+
116
+ 默认使用随机选择。你可以实现自己的选择逻辑,例如轮询(Round-Robin)或[基于权重的选择](examples/weighted_selector.py):
117
+
118
+ ```python
119
+ def select_object(object_wrapers: List[ObjectWrapper[DummyObject]]) -> Optional[ObjectWrapper[DummyObject]]:
120
+ """
121
+ 按照权重选择一个对象。
122
+ """
123
+ if not object_wrapers:
124
+ return None
125
+ weights = [
126
+ object_wraper.weight
127
+ for object_wraper in object_wrapers
128
+ ]
129
+ return choices(object_wrapers, weights)[0]
130
+
131
+ # 注意:选择器可以是同步或异步函数,池内部会自动转换
132
+ ```
133
+
134
+ ### 定制包装器和打包器
135
+
136
+ ```python
137
+ class MyWrapper(ObjectWrapper):
138
+ def __init__(self, obj, **kwargs):
139
+ super().__init__(obj, **kwargs)
140
+ self.extra_info = kwargs.get('extra', {})
141
+
142
+ def my_packer(wrapper):
143
+ # 返回自定义的打包对象,可以增加额外行为
144
+ return MyPack(wrapper)
145
+
146
+ pool = Pool(detect_status=..., wrapper=MyWrapper, packer=my_packer)
147
+ ```
148
+
149
+ ### 使用默认数据
150
+
151
+ 通过 `wrapping_data` 为每个对象附加默认属性:
152
+
153
+ ```python
154
+ pool = Pool(..., wrapping_data={"created_at": datetime.now(), "source": "db"})
155
+ pool.add(obj) # ObjectWrapper 会自动包含 created_at 和 source
156
+ ```
157
+
158
+ ### 并发控制
159
+
160
+ `async_concurrency` 限制了同时执行状态检测或清理操作的并发任务数,避免瞬间压力过大:
161
+
162
+ ```python
163
+ pool = Pool(..., async_concurrency=10) # 最多同时检测10个对象
164
+ ```
165
+
166
+ ## 并发与线程安全
167
+
168
+ - **协程安全**:`Pool` 使用 `AsyncRLock` 保护关键操作,在**单个事件循环**内多协程并发访问是安全的。
169
+ - **线程安全**:**不保证**多线程安全。如果在多线程环境中使用同步方法(`add`、`borrow` 等),需要外部加锁(如 `threading.Lock`)。
170
+ - **建议**:在 `asyncio` 应用中始终使用异步 API;在传统多线程应用中请自行添加线程锁。
171
+
172
+ ## 依赖
173
+
174
+ - Python >= 3.10
175
+
176
+ ## 许可证
177
+
178
+ MIT
@@ -0,0 +1,157 @@
1
+ # Object Pool
2
+
3
+ 一个功能丰富、支持异步的通用对象池,提供细粒度的对象生命周期管理、状态检测、超时回收和灵活的定制能力。
4
+
5
+ ## 特性
6
+
7
+ - ✅ **异步优先**:原生支持 `asyncio`,在高并发 I/O 场景下性能优异
8
+ - 🔄 **完整生命周期**:管理对象的 `PENDING`、`AVAILABLE`、`BORROWED`、`INVALID`、`DORMANT`、`UNKNOWN` 状态
9
+ - ⏱️ **超时回收**:支持对象级别的借出超时自动回收
10
+ - 🧩 **高度可定制**:可自定义状态检测器、对象选择器、包装器(Wrapper)和打包器(Packer)
11
+ - 🚦 **并发控制**:内置并发度限制,批量操作自动分块
12
+ - 🔁 **双 API**:同时提供异步(`*_async`)和同步接口
13
+ - 🧵 **协程安全**:基于 `AsyncRLock` 实现,在单事件循环多协程下安全
14
+
15
+ ## 安装
16
+
17
+ ```bash
18
+ pip install object-pool
19
+ ```
20
+
21
+ 或从源码安装:
22
+
23
+ ```bash
24
+ git clone https://github.com/Jerry-Wu-GitHub/object-pool.git
25
+ cd object-pool
26
+ pip install -e .
27
+ ```
28
+
29
+ ## 快速开始
30
+
31
+ ### 同步使用
32
+
33
+ ```python
34
+ from object_pool import Pool, Status
35
+ from datetime import timedelta
36
+
37
+ # 定义一个简单的状态检测函数
38
+ def check_status(wrapper):
39
+ # 假设对象有一个 is_alive 属性
40
+ if wrapper.object.is_alive():
41
+ return Status.AVAILABLE
42
+ return Status.INVALID
43
+
44
+ # 创建对象池
45
+ pool = Pool(detect_status=check_status)
46
+
47
+ # 添加对象
48
+ obj = MyResource()
49
+ pool.add(obj)
50
+
51
+ # 借出对象
52
+ with pool.borrow() as resource:
53
+ resource.do_something()
54
+ # 离开上下文时自动归还
55
+
56
+ # 手动归还
57
+ pack = pool.borrow()
58
+ pack.close() # 归还
59
+ ```
60
+
61
+ ### 异步使用
62
+
63
+ ```python
64
+ import asyncio
65
+ from object_pool import Pool, Status
66
+
67
+ async def check_status_async(wrapper):
68
+ # 异步检测对象健康状态
69
+ if await wrapper.object.ping():
70
+ return Status.AVAILABLE
71
+ return Status.INVALID
72
+
73
+ async def main():
74
+ pool = Pool(detect_status=check_status_async)
75
+ obj = AsyncResource()
76
+ await pool.add_async(obj)
77
+
78
+ pack = await pool.borrow_async(timeout=3.0)
79
+ try:
80
+ await pack.object.work()
81
+ finally:
82
+ pack.close() # 归还
83
+
84
+ # 或使用异步上下文管理器
85
+ async with await pool.borrow_async() as resource:
86
+ await resource.work()
87
+
88
+ asyncio.run(main())
89
+ ```
90
+
91
+ ## 高级用法
92
+
93
+ ### 自定义对象选择器
94
+
95
+ 默认使用随机选择。你可以实现自己的选择逻辑,例如轮询(Round-Robin)或[基于权重的选择](examples/weighted_selector.py):
96
+
97
+ ```python
98
+ def select_object(object_wrapers: List[ObjectWrapper[DummyObject]]) -> Optional[ObjectWrapper[DummyObject]]:
99
+ """
100
+ 按照权重选择一个对象。
101
+ """
102
+ if not object_wrapers:
103
+ return None
104
+ weights = [
105
+ object_wraper.weight
106
+ for object_wraper in object_wrapers
107
+ ]
108
+ return choices(object_wrapers, weights)[0]
109
+
110
+ # 注意:选择器可以是同步或异步函数,池内部会自动转换
111
+ ```
112
+
113
+ ### 定制包装器和打包器
114
+
115
+ ```python
116
+ class MyWrapper(ObjectWrapper):
117
+ def __init__(self, obj, **kwargs):
118
+ super().__init__(obj, **kwargs)
119
+ self.extra_info = kwargs.get('extra', {})
120
+
121
+ def my_packer(wrapper):
122
+ # 返回自定义的打包对象,可以增加额外行为
123
+ return MyPack(wrapper)
124
+
125
+ pool = Pool(detect_status=..., wrapper=MyWrapper, packer=my_packer)
126
+ ```
127
+
128
+ ### 使用默认数据
129
+
130
+ 通过 `wrapping_data` 为每个对象附加默认属性:
131
+
132
+ ```python
133
+ pool = Pool(..., wrapping_data={"created_at": datetime.now(), "source": "db"})
134
+ pool.add(obj) # ObjectWrapper 会自动包含 created_at 和 source
135
+ ```
136
+
137
+ ### 并发控制
138
+
139
+ `async_concurrency` 限制了同时执行状态检测或清理操作的并发任务数,避免瞬间压力过大:
140
+
141
+ ```python
142
+ pool = Pool(..., async_concurrency=10) # 最多同时检测10个对象
143
+ ```
144
+
145
+ ## 并发与线程安全
146
+
147
+ - **协程安全**:`Pool` 使用 `AsyncRLock` 保护关键操作,在**单个事件循环**内多协程并发访问是安全的。
148
+ - **线程安全**:**不保证**多线程安全。如果在多线程环境中使用同步方法(`add`、`borrow` 等),需要外部加锁(如 `threading.Lock`)。
149
+ - **建议**:在 `asyncio` 应用中始终使用异步 API;在传统多线程应用中请自行添加线程锁。
150
+
151
+ ## 依赖
152
+
153
+ - Python >= 3.10
154
+
155
+ ## 许可证
156
+
157
+ MIT
@@ -0,0 +1,32 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "object-pool-async" # pip install 时使用的名字
7
+ version = "0.1.2" # 项目版本
8
+ description = "A generic, async-first object pool for Python"
9
+ readme = "README.md" # 指定项目说明文件
10
+ license = {text = "MIT"} # 许可证类型
11
+ authors = [
12
+ {name = "Your Name", email = "your.email@example.com"}
13
+ ]
14
+ keywords = ["object-pool", "async", "connection-pool"]
15
+ classifiers = [ # 帮助用户在 PyPI 上找到你的包
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Topic :: Software Development :: Libraries :: Python Modules",
24
+ ]
25
+ requires-python = ">=3.10"
26
+ dependencies = [] # 项目依赖
27
+
28
+ [project.urls] # 项目相关的链接
29
+ "Homepage" = "https://github.com/Jerry-Wu-GitHub/object-pool"
30
+
31
+ [tool.setuptools.packages.find]
32
+ where = ["src"] # 在 src 目录下找包
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,10 @@
1
+ """
2
+ 对象池。
3
+ """
4
+
5
+ from .exceptions import PoolError, ObjectNotFoundError
6
+ from .status import Status
7
+ from .pool import (
8
+ Pool,
9
+ Object, ObjectWrapper, ObjectPack
10
+ )
@@ -0,0 +1,32 @@
1
+ from typing import Any
2
+
3
+
4
+ class AttributeDict(dict):
5
+ """
6
+ A class that can read / set attribute value via both `.` and `[]`.
7
+ """
8
+
9
+ def __getattr__(self, key: str) -> Any:
10
+ """
11
+ Get an attribute value by `.`
12
+
13
+ Args:
14
+ key (str): The name of the attribute to get.
15
+
16
+ Returns:
17
+ Any: The value of the attribute.
18
+ """
19
+ return self[key]
20
+
21
+ def __setattr__(self, key: str, value: Any) -> None:
22
+ """
23
+ Set an attribute value by `.`
24
+
25
+ Args:
26
+ key (str): The name of the attribute to set.
27
+ value (Any): The value to set the attribute to.
28
+ """
29
+ self[key] = value
30
+
31
+ def __repr__(self) -> str:
32
+ return f"{self.__class__.__name__}({super().__repr__()})"
@@ -0,0 +1,14 @@
1
+ """
2
+ 异常
3
+ """
4
+
5
+ class PoolError(Exception):
6
+ """
7
+ 与对象池有关的错误。
8
+ """
9
+
10
+
11
+ class ObjectNotFoundError(PoolError):
12
+ """
13
+ 在池中没有找到对象。
14
+ """