vools 0.2.1__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.
- {vools-0.2.1/vools.egg-info → vools-0.2.2}/PKG-INFO +1 -1
- {vools-0.2.1 → vools-0.2.2}/vools/__init__.py +1 -1
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/_base.py +2 -2
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/core/sigcache.py +106 -50
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/freebasic/transport.py +6 -1
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/manager.py +3 -1
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/zig/compiler.py +1 -1
- vools-0.2.2/vools/core/asyncio_compat.py +122 -0
- {vools-0.2.1 → vools-0.2.2}/vools/core/dataclass_compat.py +16 -3
- vools-0.2.2/vools/core/datetime_compat.py +180 -0
- vools-0.2.2/vools/core/inspect_compat.py +50 -0
- {vools-0.2.1 → vools-0.2.2}/vools/datetime/__init__.py +9 -1
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/__init__.py +9 -1
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/core/schedulers.py +1 -1
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/operators/extended_operators.py +7 -6
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/operators/operators.py +3 -2
- {vools-0.2.1 → vools-0.2.2}/vools/security/safe_eval.py +9 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/codec.py +9 -4
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/type_registry.py +5 -3
- {vools-0.2.1 → vools-0.2.2}/vools/task/core/models.py +6 -5
- {vools-0.2.1 → vools-0.2.2}/vools/task/core/storage.py +18 -10
- {vools-0.2.1 → vools-0.2.2/vools.egg-info}/PKG-INFO +1 -1
- {vools-0.2.1 → vools-0.2.2}/vools.egg-info/SOURCES.txt +3 -29
- vools-0.2.1/tests/benchmark_curry.py +0 -179
- vools-0.2.1/tests/benchmark_curry_optimized.py +0 -226
- vools-0.2.1/tests/benchmark_modules.py +0 -190
- vools-0.2.1/tests/benchmark_placeholder.py +0 -176
- vools-0.2.1/tests/benchmark_reactive.py +0 -176
- vools-0.2.1/tests/benchmark_signature_cache.py +0 -230
- vools-0.2.1/tests/compare_rxpy_vools.py +0 -190
- vools-0.2.1/tests/compare_with_rx_spec.py +0 -251
- vools-0.2.1/tests/debug_curry.py +0 -26
- vools-0.2.1/tests/explore_rxpy_api.py +0 -180
- vools-0.2.1/tests/test_box.py +0 -238
- vools-0.2.1/tests/test_crypto.py +0 -153
- vools-0.2.1/tests/test_csharp_bridge.py +0 -258
- vools-0.2.1/tests/test_curried_performance.py +0 -316
- vools-0.2.1/tests/test_do.py +0 -41
- vools-0.2.1/tests/test_encoding.py +0 -111
- vools-0.2.1/tests/test_functional.py +0 -231
- vools-0.2.1/tests/test_functional_simple.py +0 -231
- vools-0.2.1/tests/test_import.py +0 -26
- vools-0.2.1/tests/test_itor.py +0 -662
- vools-0.2.1/tests/test_main_import.py +0 -70
- vools-0.2.1/tests/test_new_features.py +0 -68
- vools-0.2.1/tests/test_r_bridge.py +0 -399
- vools-0.2.1/tests/test_rust_async.py +0 -146
- vools-0.2.1/tests/test_rust_async_quick.py +0 -139
- vools-0.2.1/tests/test_rust_decorator.py +0 -246
- vools-0.2.1/tests/test_stuff.py +0 -165
- vools-0.2.1/tests/test_vools.py +0 -181
- vools-0.2.1/vools/utils/asyncio_compat.py +0 -91
- {vools-0.2.1 → vools-0.2.2}/LICENSE +0 -0
- {vools-0.2.1 → vools-0.2.2}/NOTICE +0 -0
- {vools-0.2.1 → vools-0.2.2}/README.md +0 -0
- {vools-0.2.1 → vools-0.2.2}/autopypi/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/autopypi/config.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/autopypi/environment.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/autopypi/fabfile.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/autopypi/logger.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/autopypi/packaging.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/autopypi/publishing.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/autopypi/release.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/autopypi/versioning.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/pyproject.toml +0 -0
- {vools-0.2.1 → vools-0.2.2}/setup.cfg +0 -0
- {vools-0.2.1 → vools-0.2.2}/tests/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/tests/_serialize_helpers.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/tests/conftest.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/tests/test_functions.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/README.md +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/__main__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/_logging.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/_nim_crypto.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/_nim_curried.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/_nim_datetime.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/_nim_encoding.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/_nim_loader.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/_nim_seq.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/api/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/api/curry_cmd.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/api/memoize_cmd.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/api/ops_cmd.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/api/seq_cmd.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/api/typer_app.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/_examples.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/c/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/cangjie/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/cangjie/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/cangjie/loader.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/cangjie/templates.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/cangjie/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/core/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/core/decorators.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/core/loader.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/core/serialization.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/core/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/cpp/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/csharp/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/csharp/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/csharp/loader.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/csharp/templates.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/csharp/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/dart/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/dart/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/dart/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/freebasic/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/freebasic/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/freebasic/loader.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/freebasic/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/go/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/go/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/java/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/java/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/java/decorator.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/java/loader.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/java/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/julia/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/julia/_loader.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/julia/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/julia/decorator.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/julia/templates.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/julia/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/kotlin/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/kotlin/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/kotlin/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/lua/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/lua/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/lua/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/mojo/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/mojo/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/mojo/loader.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/mojo/templates.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/mojo/transport.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/mojo/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/moonbit/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/moonbit/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/moonbit/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/nim/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/nim/_loader.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/nim/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/nim/crypto.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/nim/curried.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/nim/datetime.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/nim/encoding.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/nim/seq.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/perl/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/perl/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/perl/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/php/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/php/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/php/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/powershell/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/powershell/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/powershell/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/probe.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/r/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/r/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/r/loader.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/r/templates.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/r/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/ruby/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/ruby/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/rust/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/rust/_loader.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/rust/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/rust/decorator.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/rust/templates.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/rust/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/scala/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/scala/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/scala/decorator.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/scala/loader.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/scala/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/scala/utils.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/shell/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/shell/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/shell/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/swift/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/swift/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/swift/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/typescript/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/typescript/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/vbnet/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/vbnet/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/vbnet/templates.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/vbnet/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/vbscript/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/vbscript/compiler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/vbscript/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/zig/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/bridge/zig/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/cache/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/cache/memorize.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/cache/once.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/cache/persist.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/cache/sigcache.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/config.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/config.template.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/core/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/core/base.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/core/config.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/core/exceptions.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/crypto/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/crypto/core.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/curried/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/curried/collection.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/curried/composition.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/curried/core.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/curried/iteration.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/curried/math.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/curried/predicate.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/curried/string.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/data/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/data/itor.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/data/seq.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/data/vlist.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/data/vtext.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/datetime/dates_format.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/datetime/utils.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/datetime/vdate_class.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/cache.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/control.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/curried.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/curry_core.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/curry_decorator.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/curry_delay.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/lazy.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/overcurry.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/overload.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/overloads.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/rself.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/selector.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/shotcut.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/decorators/trd.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/encoding/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/encoding/core.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/functional/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/functional/arrow_func.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/functional/box.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/functional/funcs.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/functional/iif.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/functional/pipe_ops.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/functional/placeholder.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/functional/placeholder_impl.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/functional/result.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/lib/libgcc_s_seh-1.dll +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/lib/libstdc++-6.dll +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/lib/libwinpthread-1.dll +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/lib/linux/libvools_crypto.so +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/lib/linux/libvools_curried.so +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/lib/linux/libvools_datetime.so +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/lib/linux/libvools_encoding.so +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/lib/linux/libvools_seq.so +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/lib/vools_crypto.dll +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/lib/vools_curried.dll +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/lib/vools_datetime.dll +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/lib/vools_encoding.dll +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/lib/vools_seq.dll +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/oop/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/oop/calltype.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/oop/extend.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/oop/fusion.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/oop/method_extend.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/oop/mixer.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/oop/selector.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/core/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/core/connectable.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/core/object_pool.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/core/observable.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/core/subject.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/monitoring/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/monitoring/_monitoring.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/monitoring/clipboard.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/monitoring/file_watcher.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/monitoring/folder_watcher.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/monitoring/keyboard.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/monitoring/monitor_observer.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/monitoring/monitor_subject.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/monitoring/mouse.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/operators/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/operators/monitor_operators.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/reactive/operators/stats_operators.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/security/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/security/_constants.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/security/expression_handler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/backends/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/backends/base.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/backends/json_backend.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/backends/msgpack_backend.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/backends/pickle_backend.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/callable/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/callable/decorator_handler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/callable/functional_handler.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/config.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/context.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/core.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/decorators.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/serialize/sentinel.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/core/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/core/builder.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/core/config.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/core/connection.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/core/decorators.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/core/dialect.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/core/result.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/core/types.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/manager.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/postgres/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/postgres/connection.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/postgres/dialect.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/spark/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/spark/connection.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/spark/dialect.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/spark/scala_bridge.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/sqlite/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/sqlite/connection.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sql/sqlite/dialect.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sys/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sys/compile_cmd.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sys/dll.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sys/dll_cmd.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sys/env_cmd.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sys/exe.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sys/fire_app.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/sys/run_cmd.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/task/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/task/core/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/task/core/queue.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/task/core/worker.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/task/decorators/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/task/decorators/task_decorator.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/task/rules/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/task/rules/dag.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/task/rules/engine.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/task/rules/rule.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/task/utils/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/utils/__init__.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/utils/hoder.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/utils/stuff.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools/utils/tools.py +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools.egg-info/dependency_links.txt +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools.egg-info/entry_points.txt +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools.egg-info/requires.txt +0 -0
- {vools-0.2.1 → vools-0.2.2}/vools.egg-info/top_level.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
"""
|
|
2
2
|
vools.bridge._base - 跨语言桥接抽象接口 (Lang Bridge)
|
|
3
3
|
|
|
4
4
|
定义统一的 Lang 接口规范,所有语言桥接模块必须实现此接口。
|
|
@@ -59,7 +59,7 @@ from typing import (
|
|
|
59
59
|
get_type_hints,
|
|
60
60
|
)
|
|
61
61
|
from vools.core.dataclass_compat import dataclass, field
|
|
62
|
-
from vools.
|
|
62
|
+
from vools.core.asyncio_compat import run as asyncio_run
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
# ============================================================================
|
|
@@ -19,6 +19,7 @@ vools.bridge.core.sigcache - Bridge 子包签名缓存机制
|
|
|
19
19
|
|
|
20
20
|
import inspect
|
|
21
21
|
import logging
|
|
22
|
+
import weakref
|
|
22
23
|
from collections import OrderedDict
|
|
23
24
|
from typing import Any, Callable, Dict, Optional, List
|
|
24
25
|
|
|
@@ -32,6 +33,7 @@ class BridgeSigCache:
|
|
|
32
33
|
"""Bridge 签名缓存类,每种语言桥接可以有自己的缓存实例。
|
|
33
34
|
|
|
34
35
|
使用 OrderedDict 实现 LRU 淘汰策略,按语言命名空间隔离缓存。
|
|
36
|
+
使用 weakref 跟踪函数对象生命周期,避免 id 复用导致的缓存错误命中。
|
|
35
37
|
|
|
36
38
|
Attributes:
|
|
37
39
|
lang: 语言名称,用于标识缓存命名空间。
|
|
@@ -51,9 +53,61 @@ class BridgeSigCache:
|
|
|
51
53
|
self._annotations_cache: OrderedDict = OrderedDict()
|
|
52
54
|
self._body_cache: OrderedDict = OrderedDict()
|
|
53
55
|
self._spec_cache: OrderedDict = OrderedDict()
|
|
56
|
+
self._weak_refs: Dict[int, weakref.ref] = {}
|
|
54
57
|
self._hits = 0
|
|
55
58
|
self._misses = 0
|
|
56
59
|
|
|
60
|
+
def _on_object_dead(self, ref: weakref.ref) -> None:
|
|
61
|
+
"""弱引用回调:当被引用的函数对象被回收时,清理对应缓存。
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
ref: 已失效的弱引用对象。
|
|
65
|
+
"""
|
|
66
|
+
dead_id = None
|
|
67
|
+
for obj_id, r in list(self._weak_refs.items()):
|
|
68
|
+
if r is ref:
|
|
69
|
+
dead_id = obj_id
|
|
70
|
+
break
|
|
71
|
+
if dead_id is not None:
|
|
72
|
+
self._weak_refs.pop(dead_id, None)
|
|
73
|
+
self._sig_cache.pop(dead_id, None)
|
|
74
|
+
self._annotations_cache.pop(dead_id, None)
|
|
75
|
+
for key in list(self._body_cache.keys()):
|
|
76
|
+
if isinstance(key, tuple) and key[0] == dead_id:
|
|
77
|
+
self._body_cache.pop(key, None)
|
|
78
|
+
for key in list(self._spec_cache.keys()):
|
|
79
|
+
if isinstance(key, tuple) and key[0] == dead_id:
|
|
80
|
+
self._spec_cache.pop(key, None)
|
|
81
|
+
|
|
82
|
+
def _register_weakref(self, func: Callable) -> None:
|
|
83
|
+
"""注册函数对象的弱引用,用于检测对象回收。
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
func: 要跟踪的函数对象。
|
|
87
|
+
"""
|
|
88
|
+
obj_id = id(func)
|
|
89
|
+
if obj_id not in self._weak_refs:
|
|
90
|
+
try:
|
|
91
|
+
ref = weakref.ref(func, self._on_object_dead)
|
|
92
|
+
self._weak_refs[obj_id] = ref
|
|
93
|
+
except TypeError:
|
|
94
|
+
pass
|
|
95
|
+
|
|
96
|
+
def _is_valid(self, func: Callable, obj_id: int) -> bool:
|
|
97
|
+
"""检查缓存键对应的对象是否仍然有效。
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
func: 当前函数对象(用于验证)。
|
|
101
|
+
obj_id: 缓存键(id)。
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
True 如果缓存有效,False 如果已失效。
|
|
105
|
+
"""
|
|
106
|
+
if obj_id not in self._weak_refs:
|
|
107
|
+
return False
|
|
108
|
+
ref = self._weak_refs[obj_id]
|
|
109
|
+
return ref() is func
|
|
110
|
+
|
|
57
111
|
def _cache_get(self, cache: OrderedDict, key: int) -> Any:
|
|
58
112
|
"""从 OrderedDict 缓存中获取值并更新 LRU 顺序。
|
|
59
113
|
|
|
@@ -100,13 +154,13 @@ class BridgeSigCache:
|
|
|
100
154
|
inspect.Signature 对象。
|
|
101
155
|
"""
|
|
102
156
|
key = id(func)
|
|
103
|
-
|
|
157
|
+
if key in self._sig_cache and self._is_valid(func, key):
|
|
104
158
|
return self._cache_get(self._sig_cache, key)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
159
|
+
self._misses += 1
|
|
160
|
+
self._register_weakref(func)
|
|
161
|
+
sig = inspect.signature(func)
|
|
162
|
+
self._cache_set(self._sig_cache, key, sig)
|
|
163
|
+
return sig
|
|
110
164
|
|
|
111
165
|
def has_signature(self, func: Callable[..., Any]) -> bool:
|
|
112
166
|
"""检查函数签名是否已缓存。
|
|
@@ -117,7 +171,8 @@ class BridgeSigCache:
|
|
|
117
171
|
Returns:
|
|
118
172
|
True 如果已缓存,否则 False。
|
|
119
173
|
"""
|
|
120
|
-
|
|
174
|
+
key = id(func)
|
|
175
|
+
return key in self._sig_cache and self._is_valid(func, key)
|
|
121
176
|
|
|
122
177
|
# ------------------------------------------------------------------
|
|
123
178
|
# 类型注解缓存
|
|
@@ -137,16 +192,16 @@ class BridgeSigCache:
|
|
|
137
192
|
from typing import get_type_hints
|
|
138
193
|
|
|
139
194
|
key = id(func)
|
|
140
|
-
|
|
195
|
+
if key in self._annotations_cache and self._is_valid(func, key):
|
|
141
196
|
return self._cache_get(self._annotations_cache, key)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
197
|
+
self._misses += 1
|
|
198
|
+
self._register_weakref(func)
|
|
199
|
+
try:
|
|
200
|
+
annotations = get_type_hints(func)
|
|
201
|
+
except Exception:
|
|
202
|
+
annotations = getattr(func, '__annotations__', {}) or {}
|
|
203
|
+
self._cache_set(self._annotations_cache, key, annotations)
|
|
204
|
+
return annotations
|
|
150
205
|
|
|
151
206
|
def has_annotations(self, func: Callable[..., Any]) -> bool:
|
|
152
207
|
"""检查函数类型注解是否已缓存。
|
|
@@ -157,7 +212,8 @@ class BridgeSigCache:
|
|
|
157
212
|
Returns:
|
|
158
213
|
True 如果已缓存,否则 False。
|
|
159
214
|
"""
|
|
160
|
-
|
|
215
|
+
key = id(func)
|
|
216
|
+
return key in self._annotations_cache and self._is_valid(func, key)
|
|
161
217
|
|
|
162
218
|
# ------------------------------------------------------------------
|
|
163
219
|
# 函数体缓存
|
|
@@ -182,13 +238,13 @@ class BridgeSigCache:
|
|
|
182
238
|
|
|
183
239
|
cache_key = (id(func), _hash_args(args, kwargs))
|
|
184
240
|
|
|
185
|
-
|
|
241
|
+
if cache_key in self._body_cache and self._is_valid(func, id(func)):
|
|
186
242
|
return self._cache_get(self._body_cache, cache_key)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
243
|
+
self._misses += 1
|
|
244
|
+
self._register_weakref(func)
|
|
245
|
+
body = _extract_body(func, args, kwargs)
|
|
246
|
+
self._cache_set(self._body_cache, cache_key, body)
|
|
247
|
+
return body
|
|
192
248
|
|
|
193
249
|
def has_body(self, func: Callable[..., Any], args: tuple = (), kwargs: Optional[Dict[str, Any]] = None) -> bool:
|
|
194
250
|
"""检查函数体是否已缓存。
|
|
@@ -204,7 +260,7 @@ class BridgeSigCache:
|
|
|
204
260
|
if kwargs is None:
|
|
205
261
|
kwargs = {}
|
|
206
262
|
cache_key = (id(func), _hash_args(args, kwargs))
|
|
207
|
-
return cache_key in self._body_cache
|
|
263
|
+
return cache_key in self._body_cache and self._is_valid(func, id(func))
|
|
208
264
|
|
|
209
265
|
# ------------------------------------------------------------------
|
|
210
266
|
# FunctionSpec 缓存
|
|
@@ -228,32 +284,32 @@ class BridgeSigCache:
|
|
|
228
284
|
|
|
229
285
|
cache_key = (id(func), _hash_args(args, kwargs))
|
|
230
286
|
|
|
231
|
-
|
|
287
|
+
if cache_key in self._spec_cache and self._is_valid(func, id(func)):
|
|
232
288
|
return self._cache_get(self._spec_cache, cache_key)
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
289
|
+
self._misses += 1
|
|
290
|
+
self._register_weakref(func)
|
|
291
|
+
from .._base import FunctionSpec
|
|
292
|
+
|
|
293
|
+
name = func.__name__
|
|
294
|
+
annotations = self.get_annotations(func)
|
|
295
|
+
sig = self.get_signature(func)
|
|
296
|
+
|
|
297
|
+
defaults = {}
|
|
298
|
+
for param_name, param in sig.parameters.items():
|
|
299
|
+
if param.default is not inspect.Parameter.empty:
|
|
300
|
+
defaults[param_name] = param.default
|
|
301
|
+
|
|
302
|
+
body = self.get_body(func, args, kwargs)
|
|
303
|
+
|
|
304
|
+
spec = FunctionSpec(
|
|
305
|
+
name=name,
|
|
306
|
+
annotations=annotations,
|
|
307
|
+
args=args,
|
|
308
|
+
defaults=defaults,
|
|
309
|
+
body=body,
|
|
310
|
+
)
|
|
311
|
+
self._cache_set(self._spec_cache, cache_key, spec)
|
|
312
|
+
return spec
|
|
257
313
|
|
|
258
314
|
def has_spec(self, func: Callable[..., Any], args: tuple = (), kwargs: Optional[Dict[str, Any]] = None) -> bool:
|
|
259
315
|
"""检查 FunctionSpec 是否已缓存。
|
|
@@ -269,7 +325,7 @@ class BridgeSigCache:
|
|
|
269
325
|
if kwargs is None:
|
|
270
326
|
kwargs = {}
|
|
271
327
|
cache_key = (id(func), _hash_args(args, kwargs))
|
|
272
|
-
return cache_key in self._spec_cache
|
|
328
|
+
return cache_key in self._spec_cache and self._is_valid(func, id(func))
|
|
273
329
|
|
|
274
330
|
# ------------------------------------------------------------------
|
|
275
331
|
# 缓存管理
|
|
@@ -11,12 +11,17 @@ vools.bridge.freebasic.transport - 免序列化 Transport 抽象
|
|
|
11
11
|
- 本模块让 list 直接以 POINTER(c_long) 形式传入,跳过 CSV 中转
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
from typing import Any, Tuple
|
|
14
|
+
from typing import Any, Tuple
|
|
15
15
|
|
|
16
16
|
import ctypes
|
|
17
17
|
|
|
18
18
|
from .types import FB_TO_CTYPES, is_array_type
|
|
19
19
|
|
|
20
|
+
try:
|
|
21
|
+
from typing import Protocol
|
|
22
|
+
except ImportError:
|
|
23
|
+
Protocol = object
|
|
24
|
+
|
|
20
25
|
|
|
21
26
|
class Transport(object):
|
|
22
27
|
"""
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
"""
|
|
2
2
|
vools.bridge.manager - 跨语言桥接统一管理器
|
|
3
3
|
|
|
4
4
|
提供各种外部语言编译器和运行时环境的统一配置、管理和查询。
|
|
@@ -98,6 +98,8 @@ class LanguageConfig:
|
|
|
98
98
|
elif _IS_MACOS and self.library_suffix == '':
|
|
99
99
|
self.library_suffix = '.dylib'
|
|
100
100
|
|
|
101
|
+
__attrs_post_init__ = __post_init__
|
|
102
|
+
|
|
101
103
|
|
|
102
104
|
@dataclass
|
|
103
105
|
class LanguageStatus:
|
|
@@ -17,7 +17,7 @@ import shutil
|
|
|
17
17
|
from typing import Optional, Any, Dict, List
|
|
18
18
|
|
|
19
19
|
from vools.bridge._base import LangBridge, FunctionSpec
|
|
20
|
-
from vools.
|
|
20
|
+
from vools.core.asyncio_compat import run as asyncio_run
|
|
21
21
|
from .types import PY_TO_ZIG_TYPE, ZIG_TO_CTYPES, get_zig_type, get_zig_ctype
|
|
22
22
|
|
|
23
23
|
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""
|
|
2
|
+
asyncio 兼容层 — 统一处理 Python 不同版本的 asyncio 接口
|
|
3
|
+
|
|
4
|
+
在高版本 Python 使用标准库 asyncio 的原生接口,
|
|
5
|
+
在低版本(<3.7)提供手动实现的兼容版本。
|
|
6
|
+
|
|
7
|
+
提供与标准库一致的接口:
|
|
8
|
+
- get_running_loop() → 获取当前运行的事件循环
|
|
9
|
+
- run(coro, *, debug=False) → 运行协程并返回结果
|
|
10
|
+
- create_task(coro, *, name=None) → 创建任务
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__all__ = ['get_running_loop', 'run', 'create_task']
|
|
14
|
+
|
|
15
|
+
import asyncio
|
|
16
|
+
import sys
|
|
17
|
+
|
|
18
|
+
# ================================================================
|
|
19
|
+
# 检测运行环境
|
|
20
|
+
# ================================================================
|
|
21
|
+
|
|
22
|
+
_HAS_GET_RUNNING_LOOP = sys.version_info >= (3, 7)
|
|
23
|
+
_HAS_ASYNCIO_RUN = sys.version_info >= (3, 7)
|
|
24
|
+
_HAS_CREATE_TASK = sys.version_info >= (3, 7)
|
|
25
|
+
|
|
26
|
+
if _HAS_GET_RUNNING_LOOP and _HAS_ASYNCIO_RUN and _HAS_CREATE_TASK:
|
|
27
|
+
# ── 标准库 asyncio(3.7+) ──
|
|
28
|
+
get_running_loop = asyncio.get_running_loop
|
|
29
|
+
run = asyncio.run
|
|
30
|
+
create_task = asyncio.create_task
|
|
31
|
+
|
|
32
|
+
else:
|
|
33
|
+
# ── Python 3.6 兼容实现 ──
|
|
34
|
+
|
|
35
|
+
def get_running_loop():
|
|
36
|
+
"""
|
|
37
|
+
获取当前运行的事件循环。
|
|
38
|
+
|
|
39
|
+
Python 3.7+ 有 asyncio.get_running_loop(),
|
|
40
|
+
Python 3.6 使用 asyncio._get_running_loop() 作为替代。
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
当前运行的事件循环。
|
|
44
|
+
|
|
45
|
+
Raises:
|
|
46
|
+
RuntimeError: 如果没有正在运行的事件循环。
|
|
47
|
+
"""
|
|
48
|
+
loop = asyncio._get_running_loop()
|
|
49
|
+
if loop is None:
|
|
50
|
+
raise RuntimeError('no running event loop')
|
|
51
|
+
return loop
|
|
52
|
+
|
|
53
|
+
def run(coro, *, debug=False):
|
|
54
|
+
"""
|
|
55
|
+
运行一个协程并返回结果。
|
|
56
|
+
|
|
57
|
+
Python 3.7+ 有 asyncio.run(),
|
|
58
|
+
Python 3.6 手动实现。
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
coro: 要运行的协程。
|
|
62
|
+
debug: 是否启用调试模式。
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
协程的返回值。
|
|
66
|
+
"""
|
|
67
|
+
loop = asyncio.new_event_loop()
|
|
68
|
+
try:
|
|
69
|
+
asyncio.set_event_loop(loop)
|
|
70
|
+
loop.set_debug(debug)
|
|
71
|
+
return loop.run_until_complete(coro)
|
|
72
|
+
finally:
|
|
73
|
+
try:
|
|
74
|
+
_cancel_all_tasks(loop)
|
|
75
|
+
if hasattr(loop, 'shutdown_asyncgens'):
|
|
76
|
+
loop.run_until_complete(loop.shutdown_asyncgens())
|
|
77
|
+
finally:
|
|
78
|
+
asyncio.set_event_loop(None)
|
|
79
|
+
loop.close()
|
|
80
|
+
|
|
81
|
+
def create_task(coro, *, name=None):
|
|
82
|
+
"""
|
|
83
|
+
创建一个任务。
|
|
84
|
+
|
|
85
|
+
Python 3.7+ 有 asyncio.create_task(),
|
|
86
|
+
Python 3.6 使用 asyncio.ensure_future() 作为替代。
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
coro: 协程对象。
|
|
90
|
+
name: 任务名称(3.6 忽略)。
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Task 对象。
|
|
94
|
+
"""
|
|
95
|
+
return asyncio.ensure_future(coro)
|
|
96
|
+
|
|
97
|
+
def _cancel_all_tasks(loop):
|
|
98
|
+
"""取消所有任务(Python 3.6 兼容)"""
|
|
99
|
+
if hasattr(asyncio, 'all_tasks'):
|
|
100
|
+
to_cancel = asyncio.all_tasks(loop)
|
|
101
|
+
else:
|
|
102
|
+
to_cancel = asyncio.Task.all_tasks(loop)
|
|
103
|
+
|
|
104
|
+
if not to_cancel:
|
|
105
|
+
return
|
|
106
|
+
|
|
107
|
+
for task in to_cancel:
|
|
108
|
+
task.cancel()
|
|
109
|
+
|
|
110
|
+
loop.run_until_complete(
|
|
111
|
+
asyncio.gather(*to_cancel, loop=loop, return_exceptions=True)
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
for task in to_cancel:
|
|
115
|
+
if task.cancelled():
|
|
116
|
+
continue
|
|
117
|
+
if task.exception() is not None:
|
|
118
|
+
loop.call_exception_handler({
|
|
119
|
+
'message': 'unhandled exception during asyncio.run() shutdown',
|
|
120
|
+
'exception': task.exception(),
|
|
121
|
+
'task': task,
|
|
122
|
+
})
|
|
@@ -11,7 +11,7 @@ dataclass 兼容层 — 统一处理 Python 不同版本的 dataclass 导入
|
|
|
11
11
|
- is_dataclass(obj) → 判断
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
__all__ = ['dataclass', 'field', 'asdict', 'is_dataclass', 'MISSING']
|
|
14
|
+
__all__ = ['dataclass', 'field', 'asdict', 'is_dataclass', 'MISSING', 'FrozenInstanceError']
|
|
15
15
|
|
|
16
16
|
from typing import Any, Dict, Callable, TypeVar, Optional
|
|
17
17
|
import sys
|
|
@@ -31,6 +31,7 @@ if _HAS_DATACLASSES:
|
|
|
31
31
|
from dataclasses import asdict as _std_asdict
|
|
32
32
|
from dataclasses import is_dataclass as _std_is_dataclass
|
|
33
33
|
from dataclasses import MISSING as _std_MISSING
|
|
34
|
+
from dataclasses import FrozenInstanceError as _std_FrozenInstanceError
|
|
34
35
|
|
|
35
36
|
def dataclass(cls: Optional[_T] = None, **kwargs) -> _T:
|
|
36
37
|
"""dataclass 装饰器(标准库模式)"""
|
|
@@ -42,12 +43,14 @@ if _HAS_DATACLASSES:
|
|
|
42
43
|
asdict = _std_asdict
|
|
43
44
|
is_dataclass = _std_is_dataclass
|
|
44
45
|
MISSING = _std_MISSING
|
|
46
|
+
FrozenInstanceError = _std_FrozenInstanceError
|
|
45
47
|
|
|
46
48
|
else:
|
|
47
49
|
# ── attrs 降级模式 ──
|
|
48
50
|
try:
|
|
49
51
|
from attr import attrs, attrib, asdict as _attr_asdict
|
|
50
52
|
from attr import has as _attr_has
|
|
53
|
+
from attr.exceptions import FrozenInstanceError as _attr_FrozenInstanceError
|
|
51
54
|
except ImportError:
|
|
52
55
|
msg = (
|
|
53
56
|
"Python < 3.7 detected but 'attrs' package is not installed. "
|
|
@@ -92,11 +95,19 @@ else:
|
|
|
92
95
|
- order: bool → 忽略(attrs 不支持自动排序)
|
|
93
96
|
"""
|
|
94
97
|
frozen = kwargs.pop('frozen', False)
|
|
98
|
+
|
|
99
|
+
def _wrap(c):
|
|
100
|
+
wrapped = attrs(c, frozen=frozen, auto_attribs=True)
|
|
101
|
+
# 兼容 __post_init__: attrs 用 __attrs_post_init__
|
|
102
|
+
if hasattr(wrapped, '__post_init__') and not hasattr(wrapped, '__attrs_post_init__'):
|
|
103
|
+
wrapped.__attrs_post_init__ = wrapped.__post_init__
|
|
104
|
+
return wrapped
|
|
105
|
+
|
|
95
106
|
# attrs 的 frozen 默认是 False,等价
|
|
96
107
|
if cls is not None:
|
|
97
|
-
return
|
|
108
|
+
return _wrap(cls)
|
|
98
109
|
# 带参装饰器模式: @dataclass(frozen=True)
|
|
99
|
-
return
|
|
110
|
+
return _wrap
|
|
100
111
|
|
|
101
112
|
def field(*, default=MISSING, default_factory=MISSING, **kwargs) -> Any:
|
|
102
113
|
"""
|
|
@@ -123,3 +134,5 @@ else:
|
|
|
123
134
|
def is_dataclass(obj) -> bool:
|
|
124
135
|
"""判断是否为 dataclass/attrs 实例"""
|
|
125
136
|
return _attr_has(obj)
|
|
137
|
+
|
|
138
|
+
FrozenInstanceError = _attr_FrozenInstanceError
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""
|
|
2
|
+
datetime 兼容层 — 统一处理 Python 不同版本的 datetime 接口
|
|
3
|
+
|
|
4
|
+
在高版本 Python 使用标准库 datetime 的原生接口,
|
|
5
|
+
在低版本(<3.7)提供兼容实现。
|
|
6
|
+
|
|
7
|
+
提供的兼容接口:
|
|
8
|
+
- datetime_fromisoformat(date_string) → datetime.fromisoformat
|
|
9
|
+
- date_fromisoformat(date_string) → date.fromisoformat
|
|
10
|
+
- time_fromisoformat(time_string) → time.fromisoformat
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
'datetime_fromisoformat',
|
|
15
|
+
'date_fromisoformat',
|
|
16
|
+
'time_fromisoformat',
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
import sys
|
|
20
|
+
import datetime
|
|
21
|
+
|
|
22
|
+
_HAS_FROMISOFORMAT = sys.version_info >= (3, 7)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
if _HAS_FROMISOFORMAT:
|
|
26
|
+
# ── 标准库 datetime(3.7+) ──
|
|
27
|
+
|
|
28
|
+
def datetime_fromisoformat(date_string):
|
|
29
|
+
"""Python 3.7+ 的 datetime.fromisoformat"""
|
|
30
|
+
return datetime.datetime.fromisoformat(date_string)
|
|
31
|
+
|
|
32
|
+
def date_fromisoformat(date_string):
|
|
33
|
+
"""Python 3.7+ 的 date.fromisoformat"""
|
|
34
|
+
return datetime.date.fromisoformat(date_string)
|
|
35
|
+
|
|
36
|
+
def time_fromisoformat(time_string):
|
|
37
|
+
"""Python 3.7+ 的 time.fromisoformat"""
|
|
38
|
+
return datetime.time.fromisoformat(time_string)
|
|
39
|
+
|
|
40
|
+
else:
|
|
41
|
+
# ── Python 3.6 兼容实现 ──
|
|
42
|
+
# 使用 strptime 解析常见的 ISO 格式
|
|
43
|
+
|
|
44
|
+
import re
|
|
45
|
+
|
|
46
|
+
_DATETIME_RE = re.compile(
|
|
47
|
+
r'^(\d{4})-(\d{1,2})-(\d{1,2})'
|
|
48
|
+
r'[T ](\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d{1,6}))?)?'
|
|
49
|
+
r'(?:Z|[+-]\d{2}:?\d{2})?$'
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
_DATE_RE = re.compile(r'^(\d{4})-(\d{1,2})-(\d{1,2})$')
|
|
53
|
+
|
|
54
|
+
_TIME_RE = re.compile(
|
|
55
|
+
r'^(\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d{1,6}))?)?$'
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def datetime_fromisoformat(date_string):
|
|
59
|
+
"""
|
|
60
|
+
兼容版 datetime.fromisoformat(Python 3.6)。
|
|
61
|
+
|
|
62
|
+
支持常见的 ISO 8601 格式:
|
|
63
|
+
- YYYY-MM-DDTHH:MM:SS
|
|
64
|
+
- YYYY-MM-DD HH:MM:SS
|
|
65
|
+
- 带微秒、不带秒等变体
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
date_string: ISO 格式的日期时间字符串。
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
datetime.datetime 对象。
|
|
72
|
+
|
|
73
|
+
Raises:
|
|
74
|
+
ValueError: 如果字符串格式不支持。
|
|
75
|
+
"""
|
|
76
|
+
if isinstance(date_string, datetime.datetime):
|
|
77
|
+
return date_string
|
|
78
|
+
|
|
79
|
+
s = str(date_string).strip()
|
|
80
|
+
|
|
81
|
+
# 先尝试用 strptime 解析常见格式
|
|
82
|
+
formats = [
|
|
83
|
+
'%Y-%m-%dT%H:%M:%S.%f',
|
|
84
|
+
'%Y-%m-%d %H:%M:%S.%f',
|
|
85
|
+
'%Y-%m-%dT%H:%M:%S',
|
|
86
|
+
'%Y-%m-%d %H:%M:%S',
|
|
87
|
+
'%Y-%m-%dT%H:%M',
|
|
88
|
+
'%Y-%m-%d %H:%M',
|
|
89
|
+
]
|
|
90
|
+
for fmt in formats:
|
|
91
|
+
try:
|
|
92
|
+
return datetime.datetime.strptime(s, fmt)
|
|
93
|
+
except ValueError:
|
|
94
|
+
continue
|
|
95
|
+
|
|
96
|
+
# 尝试用正则解析
|
|
97
|
+
m = _DATETIME_RE.match(s)
|
|
98
|
+
if m:
|
|
99
|
+
year, month, day = int(m.group(1)), int(m.group(2)), int(m.group(3))
|
|
100
|
+
hour, minute = int(m.group(4)), int(m.group(5))
|
|
101
|
+
second = int(m.group(6)) if m.group(6) else 0
|
|
102
|
+
microsecond = 0
|
|
103
|
+
if m.group(7):
|
|
104
|
+
micro_str = m.group(7).ljust(6, '0')
|
|
105
|
+
microsecond = int(micro_str)
|
|
106
|
+
return datetime.datetime(
|
|
107
|
+
year, month, day, hour, minute, second, microsecond
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
raise ValueError(
|
|
111
|
+
'Invalid isoformat string: %r' % date_string
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
def date_fromisoformat(date_string):
|
|
115
|
+
"""
|
|
116
|
+
兼容版 date.fromisoformat(Python 3.6)。
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
date_string: ISO 格式的日期字符串。
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
datetime.date 对象。
|
|
123
|
+
"""
|
|
124
|
+
if isinstance(date_string, datetime.date):
|
|
125
|
+
return date_string
|
|
126
|
+
|
|
127
|
+
s = str(date_string).strip()
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
return datetime.datetime.strptime(s, '%Y-%m-%d').date()
|
|
131
|
+
except ValueError:
|
|
132
|
+
pass
|
|
133
|
+
|
|
134
|
+
m = _DATE_RE.match(s)
|
|
135
|
+
if m:
|
|
136
|
+
return datetime.date(int(m.group(1)), int(m.group(2)), int(m.group(3)))
|
|
137
|
+
|
|
138
|
+
raise ValueError(
|
|
139
|
+
'Invalid isoformat string: %r' % date_string
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
def time_fromisoformat(time_string):
|
|
143
|
+
"""
|
|
144
|
+
兼容版 time.fromisoformat(Python 3.6)。
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
time_string: ISO 格式的时间字符串。
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
datetime.time 对象。
|
|
151
|
+
"""
|
|
152
|
+
if isinstance(time_string, datetime.time):
|
|
153
|
+
return time_string
|
|
154
|
+
|
|
155
|
+
s = str(time_string).strip()
|
|
156
|
+
|
|
157
|
+
formats = [
|
|
158
|
+
'%H:%M:%S.%f',
|
|
159
|
+
'%H:%M:%S',
|
|
160
|
+
'%H:%M',
|
|
161
|
+
]
|
|
162
|
+
for fmt in formats:
|
|
163
|
+
try:
|
|
164
|
+
return datetime.datetime.strptime(s, fmt).time()
|
|
165
|
+
except ValueError:
|
|
166
|
+
continue
|
|
167
|
+
|
|
168
|
+
m = _TIME_RE.match(s)
|
|
169
|
+
if m:
|
|
170
|
+
hour, minute = int(m.group(1)), int(m.group(2))
|
|
171
|
+
second = int(m.group(3)) if m.group(3) else 0
|
|
172
|
+
microsecond = 0
|
|
173
|
+
if m.group(4):
|
|
174
|
+
micro_str = m.group(4).ljust(6, '0')
|
|
175
|
+
microsecond = int(micro_str)
|
|
176
|
+
return datetime.time(hour, minute, second, microsecond)
|
|
177
|
+
|
|
178
|
+
raise ValueError(
|
|
179
|
+
'Invalid isoformat string: %r' % time_string
|
|
180
|
+
)
|