bricks-py 0.2.0__tar.gz → 0.2.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.
- {bricks_py-0.2.0 → bricks_py-0.2.2}/PKG-INFO +2 -2
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/core/events.py +108 -13
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/core/genesis.py +71 -10
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/common.py +1 -1
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/spider/addon.py +3 -3
- {bricks_py-0.2.0 → bricks_py-0.2.2}/pyproject.toml +2 -2
- {bricks_py-0.2.0 → bricks_py-0.2.2}/.gitignore +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/LICENSE +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/README.md +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/__main__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/client/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/client/cli.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/client/manage.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/client/runner.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/client/server/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/client/server/sanic_.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/client/server/starlette_.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/core/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/core/context.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/core/dispatch.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/core/signals.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/db/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/db/mongo.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/db/redis_.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/db/rocksdb.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/db/sqlite.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/downloader/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/downloader/cffi.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/downloader/curl.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/downloader/dp.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/downloader/go_requests.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/downloader/httpx_.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/downloader/niquests_.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/downloader/playwright_.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/downloader/primp_.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/downloader/pyhttpx_.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/downloader/requests_.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/downloader/tls_client_.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/cookies.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/counter.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/extractors.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/headers.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/items.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/nodes.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/proxies.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/queues/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/queues/cache.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/queues/local.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/queues/redis_.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/queues/rocksdb_.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/queues/smart.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/queues/sqlite_.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/request.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/response.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/lib/variable.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/plugins/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/plugins/make_seeds.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/plugins/on_request.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/plugins/scripts.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/plugins/storage.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/grpc_/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/grpc_/generic.proto +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/grpc_/generic_pb2.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/grpc_/generic_pb2.pyi +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/grpc_/generic_pb2_grpc.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/grpc_/service.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/http_/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/http_/service.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/redis_/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/redis_/service.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/socket_/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/socket_/service.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/websocket_/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/rpc/websocket_/service.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/spider/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/spider/air.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/spider/form.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/spider/template.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/state.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/tpls/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/tpls/spider/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/tpls/spider/air.tpl +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/tpls/spider/form.tpl +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/tpls/spider/template.tpl +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/utils/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/utils/arrow.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/utils/codes.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/utils/compress.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/utils/convert.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/utils/csv_.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/utils/fake/__init__.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/utils/fake/stochastic.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/utils/fake/tls.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/utils/fake/user_agent.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/utils/package.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/utils/pandora.py +0 -0
- {bricks_py-0.2.0 → bricks_py-0.2.2}/bricks/utils/scheduler.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bricks-py
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: quickly build your crawler
|
|
5
5
|
Project-URL: Homepage, https://github.com/KKKKKKKEM/bricks
|
|
6
6
|
Project-URL: Repository, https://github.com/KKKKKKKEM/bricks.git
|
|
@@ -19,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Classifier: Topic :: Internet :: WWW/HTTP
|
|
21
21
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
-
Requires-Python:
|
|
22
|
+
Requires-Python: <3.14,>=3.10
|
|
23
23
|
Requires-Dist: better-exceptions==0.3.3
|
|
24
24
|
Requires-Dist: curl-cffi==0.15.0
|
|
25
25
|
Requires-Dist: jmespath-community==1.1.3
|
|
@@ -78,6 +78,70 @@ class Task:
|
|
|
78
78
|
match_code: Optional[object] = None # lazily-compiled eval code object for str matches
|
|
79
79
|
|
|
80
80
|
|
|
81
|
+
@dataclass
|
|
82
|
+
class EventSpec:
|
|
83
|
+
"""声明式钩子元数据,由 @events.on() 附加到装饰的方法上。
|
|
84
|
+
|
|
85
|
+
与 Task 不同,EventSpec 不引用实际的可调用对象;它只保存 *声明* 参数。
|
|
86
|
+
可调用对象在实例创建时由 Pangu._install_events() 解析和绑定。
|
|
87
|
+
"""
|
|
88
|
+
form: str
|
|
89
|
+
index: Optional[int] = None
|
|
90
|
+
disposable: bool = False
|
|
91
|
+
args: Optional[list] = None
|
|
92
|
+
kwargs: Optional[dict] = None
|
|
93
|
+
match: Optional[Union[Callable, str]] = None
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# ------------------------------------------------------------------ #
|
|
97
|
+
# EventSpec helpers - attach / read metadata on functions & descriptors
|
|
98
|
+
# ------------------------------------------------------------------ #
|
|
99
|
+
|
|
100
|
+
_EVENT_SPEC_ATTR = "__event_spec__" # Backward-compatible single-spec view.
|
|
101
|
+
_EVENT_SPECS_ATTR = "__event_specs__"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _set_event_spec(func, spec: EventSpec):
|
|
105
|
+
"""将 EventSpec 附加到普通函数上,允许一个方法声明多个 hook。"""
|
|
106
|
+
specs = list(getattr(func, _EVENT_SPECS_ATTR, ()))
|
|
107
|
+
legacy_spec = getattr(func, _EVENT_SPEC_ATTR, None)
|
|
108
|
+
if legacy_spec is not None and legacy_spec not in specs:
|
|
109
|
+
specs.insert(0, legacy_spec)
|
|
110
|
+
specs.append(spec)
|
|
111
|
+
setattr(func, _EVENT_SPECS_ATTR, specs)
|
|
112
|
+
setattr(func, _EVENT_SPEC_ATTR, spec)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _get_event_spec(obj) -> Optional[EventSpec]:
|
|
116
|
+
"""从函数或描述符 (staticmethod / classmethod) 上读取最后声明的 EventSpec。"""
|
|
117
|
+
if isinstance(obj, (staticmethod, classmethod)):
|
|
118
|
+
return getattr(obj.__func__, _EVENT_SPEC_ATTR, None)
|
|
119
|
+
return getattr(obj, _EVENT_SPEC_ATTR, None)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _get_event_specs(obj) -> List[EventSpec]:
|
|
123
|
+
"""从函数或描述符上读取全部 EventSpec 元数据。"""
|
|
124
|
+
if isinstance(obj, (staticmethod, classmethod)):
|
|
125
|
+
obj = obj.__func__
|
|
126
|
+
specs = getattr(obj, _EVENT_SPECS_ATTR, None)
|
|
127
|
+
if specs:
|
|
128
|
+
return list(specs)
|
|
129
|
+
spec = getattr(obj, _EVENT_SPEC_ATTR, None)
|
|
130
|
+
return [spec] if spec is not None else []
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _has_event_spec(obj) -> bool:
|
|
134
|
+
"""检查函数或描述符是否携带 EventSpec 元数据。"""
|
|
135
|
+
return bool(_get_event_specs(obj))
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _get_event_legacy(obj):
|
|
139
|
+
"""从函数或描述符上读取旧版 __event__ 元数据,用于向后兼容。"""
|
|
140
|
+
if isinstance(obj, (staticmethod, classmethod)):
|
|
141
|
+
return getattr(obj.__func__, "__event__", None)
|
|
142
|
+
return getattr(obj, "__event__", None)
|
|
143
|
+
|
|
144
|
+
|
|
81
145
|
@dataclass
|
|
82
146
|
class Register:
|
|
83
147
|
"""事件注册信息
|
|
@@ -417,9 +481,25 @@ def on(
|
|
|
417
481
|
match: Optional[Union[Callable, str]] = None,
|
|
418
482
|
):
|
|
419
483
|
"""
|
|
420
|
-
使用装饰器的方式注册事件
|
|
484
|
+
使用装饰器的方式注册事件 / 声明事件元数据
|
|
485
|
+
|
|
486
|
+
行为取决于被装饰对象的位置:
|
|
487
|
+
|
|
488
|
+
* **模块级 / 局部函数** — 立即以 ``target=None`` 全局注册(行为与旧版一致)。
|
|
489
|
+
* **类方法 / 静态方法 / 类方法描述符** — 仅附加 ``EventSpec`` 元数据,
|
|
490
|
+
由 ``Pangu._install_events()`` 在实例化时绑定并注册。
|
|
491
|
+
|
|
492
|
+
支持两种装饰器顺序::
|
|
421
493
|
|
|
422
|
-
|
|
494
|
+
# 推荐:@events.on 在最内层
|
|
495
|
+
@staticmethod
|
|
496
|
+
@events.on("my_event")
|
|
497
|
+
def handler(context): ...
|
|
498
|
+
|
|
499
|
+
# 也支持:@events.on 在最外层
|
|
500
|
+
@events.on("my_event")
|
|
501
|
+
@staticmethod
|
|
502
|
+
def handler(context): ...
|
|
423
503
|
|
|
424
504
|
:param form: 事件类型,可以传入常量属性
|
|
425
505
|
:param index: 事件排序索引,默认按代码顺序递增,索引越大越靠后执行
|
|
@@ -434,21 +514,36 @@ def on(
|
|
|
434
514
|
def my_handler(context):
|
|
435
515
|
print("Request starting")
|
|
436
516
|
"""
|
|
517
|
+
spec = EventSpec(
|
|
518
|
+
form=form,
|
|
519
|
+
index=index,
|
|
520
|
+
disposable=disposable,
|
|
521
|
+
args=args,
|
|
522
|
+
kwargs=kwargs,
|
|
523
|
+
match=match,
|
|
524
|
+
)
|
|
437
525
|
|
|
438
526
|
def inner(func):
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
527
|
+
# 提取底层函数以检查 qualname(兼容 staticmethod / classmethod 描述符)
|
|
528
|
+
if isinstance(func, (staticmethod, classmethod)):
|
|
529
|
+
actual_func = func.__func__
|
|
530
|
+
else:
|
|
531
|
+
actual_func = func
|
|
532
|
+
|
|
533
|
+
# 模块级函数或局部函数:立即全局注册
|
|
534
|
+
if "." not in actual_func.__qualname__ or "<locals>" in actual_func.__qualname__:
|
|
535
|
+
e = Task(
|
|
536
|
+
func=actual_func,
|
|
537
|
+
index=index,
|
|
538
|
+
disposable=disposable,
|
|
539
|
+
args=args,
|
|
540
|
+
kwargs=kwargs,
|
|
541
|
+
match=match,
|
|
542
|
+
)
|
|
449
543
|
EventManager.register(Context(form=form, target=None), e)
|
|
450
544
|
else:
|
|
451
|
-
|
|
545
|
+
# 类方法:仅声明元数据,延迟到实例化时绑定注册
|
|
546
|
+
_set_event_spec(actual_func, spec)
|
|
452
547
|
|
|
453
548
|
return func
|
|
454
549
|
|
|
@@ -10,7 +10,15 @@ from loguru import logger
|
|
|
10
10
|
|
|
11
11
|
from bricks.core import dispatch, signals
|
|
12
12
|
from bricks.core.context import Context, Error, Flow
|
|
13
|
-
from bricks.core.events import
|
|
13
|
+
from bricks.core.events import (
|
|
14
|
+
REGISTERED_EVENTS,
|
|
15
|
+
EventManager,
|
|
16
|
+
EventSpec,
|
|
17
|
+
Register,
|
|
18
|
+
Task,
|
|
19
|
+
_get_event_legacy,
|
|
20
|
+
_get_event_specs,
|
|
21
|
+
)
|
|
14
22
|
from bricks.state import const
|
|
15
23
|
from bricks.utils import pandora
|
|
16
24
|
from bricks.utils.scheduler import BaseTrigger, Scheduler
|
|
@@ -33,17 +41,14 @@ class MetaClass(type):
|
|
|
33
41
|
raw_method and setattr(
|
|
34
42
|
instance, raw_method_name, method_wrapper(raw_method)
|
|
35
43
|
) # type: ignore
|
|
36
|
-
else:
|
|
37
|
-
func = getattr(instance, method, None)
|
|
38
|
-
if not func or not callable(func):
|
|
39
|
-
continue
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
# 安装 @events.on 装饰的事件钩子(仅事件能力实例,如 Pangu)
|
|
46
|
+
if hasattr(instance, "_install_events"):
|
|
47
|
+
instance._install_events()
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
# 运行生命周期 install
|
|
50
|
+
if hasattr(instance, "install"):
|
|
51
|
+
instance.install()
|
|
47
52
|
|
|
48
53
|
return instance
|
|
49
54
|
|
|
@@ -206,6 +211,62 @@ class Pangu(Chaos):
|
|
|
206
211
|
options=self.get("dispatcher.options", default={}),
|
|
207
212
|
)
|
|
208
213
|
|
|
214
|
+
def _install_events(self):
|
|
215
|
+
"""扫描 MRO 类层次中 @events.on 装饰的方法并注册为事件钩子。
|
|
216
|
+
|
|
217
|
+
处理实例方法、staticmethod 和 classmethod 描述符。
|
|
218
|
+
继承的钩子只注册一次;如果子类重写了同名方法(无论是否装饰),
|
|
219
|
+
只使用子类的版本。
|
|
220
|
+
|
|
221
|
+
支持单个方法声明多个 @events.on() 装饰器,每个 form 均会独立注册。
|
|
222
|
+
"""
|
|
223
|
+
seen = set()
|
|
224
|
+
|
|
225
|
+
for klass in type(self).__mro__:
|
|
226
|
+
for name, value in klass.__dict__.items():
|
|
227
|
+
if name in seen:
|
|
228
|
+
continue
|
|
229
|
+
seen.add(name)
|
|
230
|
+
|
|
231
|
+
specs = _get_event_specs(value)
|
|
232
|
+
|
|
233
|
+
# 向后兼容:检查旧版 __event__ 格式
|
|
234
|
+
if not specs:
|
|
235
|
+
event_val = _get_event_legacy(value)
|
|
236
|
+
if event_val is not None:
|
|
237
|
+
try:
|
|
238
|
+
old_form, old_task = event_val
|
|
239
|
+
specs = [EventSpec(
|
|
240
|
+
form=old_form,
|
|
241
|
+
index=getattr(old_task, "index", None),
|
|
242
|
+
disposable=getattr(old_task, "disposable", False),
|
|
243
|
+
args=getattr(old_task, "args", None),
|
|
244
|
+
kwargs=getattr(old_task, "kwargs", None),
|
|
245
|
+
match=getattr(old_task, "match", None),
|
|
246
|
+
)]
|
|
247
|
+
except (ValueError, TypeError):
|
|
248
|
+
pass
|
|
249
|
+
|
|
250
|
+
if not specs:
|
|
251
|
+
continue
|
|
252
|
+
|
|
253
|
+
# 通过 getattr 获取绑定的可调用对象(自动处理所有描述符类型)
|
|
254
|
+
try:
|
|
255
|
+
bound = getattr(self, name)
|
|
256
|
+
except AttributeError:
|
|
257
|
+
continue
|
|
258
|
+
|
|
259
|
+
for spec in specs:
|
|
260
|
+
task = Task(
|
|
261
|
+
func=bound,
|
|
262
|
+
index=spec.index,
|
|
263
|
+
disposable=spec.disposable,
|
|
264
|
+
args=spec.args,
|
|
265
|
+
kwargs=spec.kwargs,
|
|
266
|
+
match=spec.match,
|
|
267
|
+
)
|
|
268
|
+
self.use(spec.form, task)
|
|
269
|
+
|
|
209
270
|
@property
|
|
210
271
|
def plugins(self) -> List[Register]:
|
|
211
272
|
return REGISTERED_EVENTS.registered[self] # type: ignore
|
|
@@ -3,13 +3,13 @@ import collections
|
|
|
3
3
|
import concurrent.futures
|
|
4
4
|
import math
|
|
5
5
|
import uuid
|
|
6
|
-
from typing import
|
|
6
|
+
from typing import Any, Callable, List, Optional, Type, Union
|
|
7
7
|
|
|
8
8
|
from loguru import logger
|
|
9
9
|
|
|
10
|
-
from bricks.core import
|
|
10
|
+
from bricks.core import dispatch, signals
|
|
11
11
|
from bricks.lib.queues import Item, LocalQueue, TaskQueue
|
|
12
|
-
from bricks.rpc.common import
|
|
12
|
+
from bricks.rpc.common import MODE, start_rpc_server
|
|
13
13
|
from bricks.spider.air import Context, Spider
|
|
14
14
|
|
|
15
15
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "bricks-py"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.2"
|
|
4
4
|
description = "quickly build your crawler"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -19,7 +19,7 @@ classifiers = [
|
|
|
19
19
|
"Topic :: Internet :: WWW/HTTP",
|
|
20
20
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
21
21
|
]
|
|
22
|
-
requires-python = ">=3.10"
|
|
22
|
+
requires-python = ">=3.10,<3.14"
|
|
23
23
|
dependencies = [
|
|
24
24
|
"better-exceptions==0.3.3",
|
|
25
25
|
"curl-cffi==0.15.0",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|