ErisPulse 2.6.3.dev0__tar.gz → 2.7.0.dev0__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.
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/PKG-INFO +1 -1
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/pyproject.toml +1 -1
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/create.py +43 -3
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/__init__.py +20 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/adapter.py +77 -5
- {erispulse-2.6.3.dev0/src/ErisPulse/runtime → erispulse-2.7.0.dev0/src/ErisPulse/Core/Bases}/config_schema.py +62 -16
- erispulse-2.7.0.dev0/src/ErisPulse/Core/Bases/i18n_schema.py +239 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/module.py +37 -3
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/adapter.py +14 -1
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/constants.py +14 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/module.py +11 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/runtime/__init__.py +32 -14
- erispulse-2.7.0.dev0/src/ErisPulse/runtime/config_schema.py +37 -0
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/__init__.pyi +0 -16
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/base.pyi +0 -52
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/cli.pyi +0 -89
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/__init__.pyi +0 -9
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/create.pyi +0 -95
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/init.pyi +0 -94
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/install.pyi +0 -78
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/language.pyi +0 -51
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/list.pyi +0 -58
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/list_remote.pyi +0 -44
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/run.pyi +0 -108
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/self_update.pyi +0 -68
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/types.pyi +0 -148
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/uninstall.pyi +0 -37
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/upgrade.pyi +0 -31
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/console.pyi +0 -51
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/hints.pyi +0 -71
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/i18n/__init__.pyi +0 -115
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/i18n/locales/__init__.pyi +0 -12
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/i18n/locales/en.pyi +0 -8
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/i18n/locales/ja.pyi +0 -8
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/i18n/locales/ru.pyi +0 -8
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/i18n/locales/zh_cn.pyi +0 -8
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/i18n/locales/zh_tw.pyi +0 -8
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/registry.pyi +0 -92
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/utils/__init__.pyi +0 -11
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/utils/display.pyi +0 -114
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/utils/file_watcher.pyi +0 -123
- erispulse-2.6.3.dev0/src/ErisPulse/CLI/utils/package_manager.pyi +0 -391
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/__init__.pyi +0 -19
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/adapter.pyi +0 -786
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/client.pyi +0 -277
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/errors.pyi +0 -115
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/kv_builder.pyi +0 -125
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/manager.pyi +0 -138
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/module.pyi +0 -137
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/router.pyi +0 -451
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/send_builder.pyi +0 -231
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/send_rules.pyi +0 -167
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/storage.pyi +0 -397
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/websocket.pyi +0 -194
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/__init__.pyi +0 -28
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/base.pyi +0 -71
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/command.pyi +0 -121
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/message.pyi +0 -102
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/message_builder.pyi +0 -147
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/meta.pyi +0 -101
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/notice.pyi +0 -117
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/request.pyi +0 -86
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/session_type.pyi +0 -216
- erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/wrapper.pyi +0 -1170
- erispulse-2.6.3.dev0/src/ErisPulse/Core/__init__.pyi +0 -36
- erispulse-2.6.3.dev0/src/ErisPulse/Core/adapter.pyi +0 -494
- erispulse-2.6.3.dev0/src/ErisPulse/Core/assets/__init__.pyi +0 -65
- erispulse-2.6.3.dev0/src/ErisPulse/Core/client.pyi +0 -407
- erispulse-2.6.3.dev0/src/ErisPulse/Core/config.pyi +0 -129
- erispulse-2.6.3.dev0/src/ErisPulse/Core/constants.pyi +0 -217
- erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/__init__.pyi +0 -153
- erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/constants.pyi +0 -8
- erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/locales/__init__.pyi +0 -12
- erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/locales/en.pyi +0 -8
- erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/locales/ja.pyi +0 -8
- erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/locales/ru.pyi +0 -8
- erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/locales/zh_cn.pyi +0 -8
- erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/locales/zh_tw.pyi +0 -8
- erispulse-2.6.3.dev0/src/ErisPulse/Core/lifecycle.pyi +0 -240
- erispulse-2.6.3.dev0/src/ErisPulse/Core/logger.pyi +0 -378
- erispulse-2.6.3.dev0/src/ErisPulse/Core/master.pyi +0 -119
- erispulse-2.6.3.dev0/src/ErisPulse/Core/module.pyi +0 -300
- erispulse-2.6.3.dev0/src/ErisPulse/Core/router.pyi +0 -651
- erispulse-2.6.3.dev0/src/ErisPulse/Core/storage.pyi +0 -455
- erispulse-2.6.3.dev0/src/ErisPulse/__init__.pyi +0 -20
- erispulse-2.6.3.dev0/src/ErisPulse/__main__.pyi +0 -21
- erispulse-2.6.3.dev0/src/ErisPulse/finders/__init__.pyi +0 -19
- erispulse-2.6.3.dev0/src/ErisPulse/finders/adapter.pyi +0 -91
- erispulse-2.6.3.dev0/src/ErisPulse/finders/bases/__init__.pyi +0 -4
- erispulse-2.6.3.dev0/src/ErisPulse/finders/bases/finder.pyi +0 -66
- erispulse-2.6.3.dev0/src/ErisPulse/finders/module.pyi +0 -91
- erispulse-2.6.3.dev0/src/ErisPulse/loaders/__init__.pyi +0 -18
- erispulse-2.6.3.dev0/src/ErisPulse/loaders/adapter.pyi +0 -96
- erispulse-2.6.3.dev0/src/ErisPulse/loaders/bases/__init__.pyi +0 -4
- erispulse-2.6.3.dev0/src/ErisPulse/loaders/bases/loader.pyi +0 -20
- erispulse-2.6.3.dev0/src/ErisPulse/loaders/module.pyi +0 -185
- erispulse-2.6.3.dev0/src/ErisPulse/loaders/strategy.pyi +0 -90
- erispulse-2.6.3.dev0/src/ErisPulse/loaders/strict.pyi +0 -118
- erispulse-2.6.3.dev0/src/ErisPulse/runtime/__init__.pyi +0 -18
- erispulse-2.6.3.dev0/src/ErisPulse/runtime/config_schema.pyi +0 -285
- erispulse-2.6.3.dev0/src/ErisPulse/runtime/context.pyi +0 -34
- erispulse-2.6.3.dev0/src/ErisPulse/runtime/exceptions.pyi +0 -95
- erispulse-2.6.3.dev0/src/ErisPulse/runtime/frame_config.pyi +0 -116
- erispulse-2.6.3.dev0/src/ErisPulse/runtime/hints.pyi +0 -266
- erispulse-2.6.3.dev0/src/ErisPulse/runtime/tasks.pyi +0 -41
- erispulse-2.6.3.dev0/src/ErisPulse/sdk.pyi +0 -259
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/.gitignore +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/LICENSE +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/README.pypi.md +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/base.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/cli.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/init.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/install.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/language.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/list.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/list_remote.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/run.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/self_update.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/types.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/uninstall.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/upgrade.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/console.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/hints.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/i18n/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/i18n/locales/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/i18n/locales/en.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/i18n/locales/ja.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/i18n/locales/ru.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/i18n/locales/zh_cn.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/i18n/locales/zh_tw.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/registry.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/utils/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/utils/display.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/utils/file_watcher.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/utils/package_manager.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/client.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/errors.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/kv_builder.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/manager.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/router.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/send_builder.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/send_rules.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/storage.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/websocket.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/base.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/command.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/message.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/message_builder.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/meta.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/notice.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/request.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/session_type.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/wrapper.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/assets/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/assets/error.css +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/assets/error.html +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/assets/root.css +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/assets/root.html +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/client.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/config.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/constants.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/locales/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/locales/en.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/locales/ja.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/locales/ru.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/locales/zh_cn.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/locales/zh_tw.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/lifecycle.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/logger.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/master.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/router.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/storage.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/__main__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/finders/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/finders/adapter.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/finders/bases/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/finders/bases/finder.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/finders/module.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/loaders/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/loaders/adapter.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/loaders/bases/__init__.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/loaders/bases/loader.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/loaders/module.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/loaders/strategy.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/loaders/strict.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/py.typed +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/runtime/context.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/runtime/exceptions.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/runtime/frame_config.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/runtime/hints.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/runtime/tasks.py +0 -0
- {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/sdk.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ErisPulse
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.7.0.dev0
|
|
4
4
|
Summary: Event-driven modular async bot framework — write once, deploy to any platform | 事件驱动的模块化异步机器人框架,一次编写,多平台部署
|
|
5
5
|
Project-URL: Homepage, https://github.com/ErisPulse/ErisPulse
|
|
6
6
|
Project-URL: Documentation, https://www.erisdev.com#docs
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ErisPulse"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.7.0-dev0"
|
|
8
8
|
description = "Event-driven modular async bot framework — write once, deploy to any platform | 事件驱动的模块化异步机器人框架,一次编写,多平台部署"
|
|
9
9
|
readme = "README.pypi.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -63,9 +63,8 @@ _MODULE_INIT = """from .Core import Main
|
|
|
63
63
|
"""
|
|
64
64
|
|
|
65
65
|
_MODULE_CORE = """from dataclasses import dataclass, field
|
|
66
|
-
from ErisPulse.Core.Bases import BaseModule
|
|
66
|
+
from ErisPulse.Core.Bases import BaseConfig, BaseI18n, BaseModule, I18nKey
|
|
67
67
|
from ErisPulse.Core.Event import command, message, notice
|
|
68
|
-
from ErisPulse.runtime.config_schema import BaseConfig
|
|
69
68
|
|
|
70
69
|
|
|
71
70
|
@dataclass
|
|
@@ -79,6 +78,20 @@ class {name}Config(BaseConfig):
|
|
|
79
78
|
)
|
|
80
79
|
|
|
81
80
|
|
|
81
|
+
class {name}I18n(BaseI18n):
|
|
82
|
+
\"\"\"{name} 模块翻译键声明
|
|
83
|
+
|
|
84
|
+
声明的翻译键会被框架自动注册到 i18n 系统。
|
|
85
|
+
键路径自动生成为: <模块名>.<属性名>
|
|
86
|
+
\"\"\"
|
|
87
|
+
# 示例:取消注释并修改以启用
|
|
88
|
+
# welcome: I18nKey = I18nKey(
|
|
89
|
+
# default="Welcome to {name}!",
|
|
90
|
+
# zh_CN="欢迎使用 {name}!",
|
|
91
|
+
# en="Welcome to {name}!",
|
|
92
|
+
# )
|
|
93
|
+
|
|
94
|
+
|
|
82
95
|
class Main(BaseModule):
|
|
83
96
|
\"\"\"
|
|
84
97
|
{name}模块
|
|
@@ -87,6 +100,7 @@ class Main(BaseModule):
|
|
|
87
100
|
\"\"\"
|
|
88
101
|
|
|
89
102
|
ConfigClass = {name}Config
|
|
103
|
+
I18nClass = {name}I18n
|
|
90
104
|
|
|
91
105
|
def __init__(self, sdk=None):
|
|
92
106
|
from ErisPulse import sdk as _sdk
|
|
@@ -179,7 +193,7 @@ _ADAPTER_CORE = """import asyncio
|
|
|
179
193
|
import json
|
|
180
194
|
from dataclasses import dataclass, field
|
|
181
195
|
from ErisPulse.Core import BaseAdapter
|
|
182
|
-
from ErisPulse.
|
|
196
|
+
from ErisPulse.Core.Bases import BaseConfig, I18nKey, I18nKeys
|
|
183
197
|
from ErisPulse.Core import router
|
|
184
198
|
|
|
185
199
|
|
|
@@ -205,6 +219,31 @@ class {name}Config(BaseConfig):
|
|
|
205
219
|
)
|
|
206
220
|
|
|
207
221
|
|
|
222
|
+
class {name}I18n(BaseI18n):
|
|
223
|
+
\"\"\"{name} 适配器翻译键声明
|
|
224
|
+
|
|
225
|
+
声明的翻译键会被框架自动注册到 i18n 系统。
|
|
226
|
+
这里集中管理适配器用到的所有翻译键(含配置描述引用的键)。
|
|
227
|
+
\"\"\"
|
|
228
|
+
# 注册配置描述中引用的 i18n 键的多语言译文
|
|
229
|
+
endpoint: I18nKey = I18nKey(
|
|
230
|
+
default="Platform API Endpoint",
|
|
231
|
+
zh_CN="平台 API 地址",
|
|
232
|
+
en="Platform API Endpoint",
|
|
233
|
+
ja="APIアドレス",
|
|
234
|
+
ru="API адрес",
|
|
235
|
+
zh_TW="API 位址",
|
|
236
|
+
)
|
|
237
|
+
token: I18nKey = I18nKey(
|
|
238
|
+
default="Platform Token",
|
|
239
|
+
zh_CN="平台 Token",
|
|
240
|
+
en="Platform Token",
|
|
241
|
+
ja="トークン",
|
|
242
|
+
ru="Токен",
|
|
243
|
+
zh_TW="權杖",
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
|
|
208
247
|
class {name}(BaseAdapter):
|
|
209
248
|
\"\"\"
|
|
210
249
|
{name} 适配器
|
|
@@ -214,6 +253,7 @@ class {name}(BaseAdapter):
|
|
|
214
253
|
\"\"\"
|
|
215
254
|
|
|
216
255
|
ConfigClass = {name}Config
|
|
256
|
+
I18nClass = {name}I18n
|
|
217
257
|
|
|
218
258
|
def __init__(self, sdk=None):
|
|
219
259
|
super().__init__()
|
|
@@ -23,21 +23,41 @@ from .websocket import WebSocketConnectionBase, WSMessage
|
|
|
23
23
|
from .router import HttpRequest, WebSocketConnection, SseEmitter
|
|
24
24
|
from .client import BaseHttpClient, BaseHttpResponse, BaseClientWebSocket
|
|
25
25
|
|
|
26
|
+
# 配置 / i18n Schema 类型
|
|
27
|
+
from .config_schema import (
|
|
28
|
+
AdapterConfig,
|
|
29
|
+
BaseConfig,
|
|
30
|
+
BotAccountConfig,
|
|
31
|
+
)
|
|
32
|
+
from .i18n_schema import (
|
|
33
|
+
BaseI18n,
|
|
34
|
+
I18nKey,
|
|
35
|
+
key,
|
|
36
|
+
)
|
|
37
|
+
|
|
26
38
|
__all__ = [
|
|
39
|
+
# 配置 Schema 别名(= BaseConfig)
|
|
40
|
+
"AdapterConfig",
|
|
27
41
|
"BaseAdapter",
|
|
28
42
|
"BaseClientWebSocket",
|
|
43
|
+
"BaseConfig",
|
|
29
44
|
"BaseHttpClient",
|
|
30
45
|
"BaseHttpResponse",
|
|
46
|
+
# i18n 键声明 Schema 基类(命名对齐 BaseConfig)
|
|
47
|
+
"BaseI18n",
|
|
31
48
|
"BaseModule",
|
|
32
49
|
"BaseQueryBuilder",
|
|
33
50
|
"BaseStorage",
|
|
34
51
|
"BatchContext",
|
|
52
|
+
"BotAccountConfig",
|
|
35
53
|
"ClientConnectionError",
|
|
36
54
|
"ClientError",
|
|
37
55
|
"ClientTimeoutError",
|
|
38
56
|
"ErisPulseError",
|
|
39
57
|
"HTTPStatusError",
|
|
40
58
|
"HttpRequest",
|
|
59
|
+
# i18n 单键声明
|
|
60
|
+
"I18nKey",
|
|
41
61
|
"KVQueryBuilder",
|
|
42
62
|
"RequestDSL",
|
|
43
63
|
"SendBuilder",
|
|
@@ -965,11 +965,14 @@ class BaseAdapter(ABC):
|
|
|
965
965
|
7. 通过 self.cfg / self.accounts 访问类型安全的配置对象(实时读取)
|
|
966
966
|
8. 通过 self.emit_meta() 发送 meta 事件
|
|
967
967
|
9. 通过 self.make_response() / self.make_error() 构造标准化响应
|
|
968
|
+
10. 通过 I18nClass 声明翻译键集合,框架自动注册到 i18n 系统
|
|
968
969
|
{!--< /tips >!--}
|
|
969
970
|
"""
|
|
970
971
|
|
|
971
972
|
ConfigClass: type | None = None
|
|
972
973
|
AccountConfigClass: type | None = None
|
|
974
|
+
I18nClass: type | None = None
|
|
975
|
+
EventMixin: type | None = None
|
|
973
976
|
|
|
974
977
|
_platform: str = ""
|
|
975
978
|
_sdk: Any = None
|
|
@@ -1105,6 +1108,10 @@ class BaseAdapter(ABC):
|
|
|
1105
1108
|
self._config_instance = None
|
|
1106
1109
|
self._accounts_data = None
|
|
1107
1110
|
|
|
1111
|
+
# 注册 I18nClass 中声明的翻译键(在生成配置之前)
|
|
1112
|
+
self._ensure_i18n_registered()
|
|
1113
|
+
# EventMixin 的注册由 AdapterManager 在注入 _platform 后调用
|
|
1114
|
+
|
|
1108
1115
|
# 初始化时确保配置模板存在
|
|
1109
1116
|
if self.ConfigClass is not None:
|
|
1110
1117
|
self._ensure_config_exists()
|
|
@@ -1196,8 +1203,11 @@ class BaseAdapter(ABC):
|
|
|
1196
1203
|
"未声明 ConfigClass,请设置 MyAdapter.ConfigClass = MyConfig"
|
|
1197
1204
|
)
|
|
1198
1205
|
|
|
1199
|
-
from ...runtime.config_schema import dict_to_dataclass
|
|
1200
1206
|
from ..config import config as config_mgr
|
|
1207
|
+
from .config_schema import dict_to_dataclass
|
|
1208
|
+
|
|
1209
|
+
# 适配器的 EventMixin 在 AdapterManager.register() 注入 _platform 后注册
|
|
1210
|
+
# __init__ 阶段 _platform 尚未注入,因此不在此处调用
|
|
1201
1211
|
|
|
1202
1212
|
data = config_mgr.getConfig(self._get_config_key())
|
|
1203
1213
|
if data is None:
|
|
@@ -1248,8 +1258,8 @@ class BaseAdapter(ABC):
|
|
|
1248
1258
|
"未声明 AccountConfigClass,请设置 MyAdapter.AccountConfigClass = MyBotConfig"
|
|
1249
1259
|
)
|
|
1250
1260
|
|
|
1251
|
-
from ...runtime.config_schema import dict_to_dataclass, validate_config
|
|
1252
1261
|
from ..config import config as config_mgr
|
|
1262
|
+
from .config_schema import dict_to_dataclass, validate_config
|
|
1253
1263
|
|
|
1254
1264
|
key = f"{self._get_config_key()}.accounts"
|
|
1255
1265
|
data = config_mgr.getConfig(key)
|
|
@@ -1334,15 +1344,20 @@ class BaseAdapter(ABC):
|
|
|
1334
1344
|
确保全局配置模板存在,不存在则生成默认配置
|
|
1335
1345
|
|
|
1336
1346
|
{!--< internal-use >!--}
|
|
1347
|
+
会先行调用 _ensure_i18n_registered() 注册声明的翻译键,
|
|
1348
|
+
确保配置描述引用的 i18n 键在生成模板时已可用。
|
|
1337
1349
|
{!--< /internal-use >!--}
|
|
1338
1350
|
"""
|
|
1351
|
+
# 先行注册 i18n 键(在生成配置之前),保证配置描述中的 i18n 键可用
|
|
1352
|
+
self._ensure_i18n_registered()
|
|
1353
|
+
|
|
1339
1354
|
if self.ConfigClass is None:
|
|
1340
1355
|
return
|
|
1341
|
-
from
|
|
1356
|
+
from ..config import config as config_mgr
|
|
1357
|
+
from .config_schema import (
|
|
1342
1358
|
dataclass_to_defaults_dict,
|
|
1343
1359
|
dataclass_to_toml_with_comments,
|
|
1344
1360
|
)
|
|
1345
|
-
from ..config import config as config_mgr
|
|
1346
1361
|
|
|
1347
1362
|
key = self._get_config_key()
|
|
1348
1363
|
data = config_mgr.getConfig(key)
|
|
@@ -1353,6 +1368,63 @@ class BaseAdapter(ABC):
|
|
|
1353
1368
|
config_mgr.setConfig(key, data, immediate=True)
|
|
1354
1369
|
self._get_logger().info(f"已生成 {key} 默认配置模板:\n{toml_str}")
|
|
1355
1370
|
|
|
1371
|
+
def _ensure_i18n_registered(self):
|
|
1372
|
+
"""
|
|
1373
|
+
注册 I18nClass 中声明的翻译键到 i18n 系统
|
|
1374
|
+
|
|
1375
|
+
使用适配器配置键名(默认为类名)作为键名前缀和 domain,便于统一卸载。
|
|
1376
|
+
方法是幂等的,多次调用不会产生副作用(重复注册会覆盖旧值)。
|
|
1377
|
+
|
|
1378
|
+
{!--< internal-use >!--}
|
|
1379
|
+
由 __init__() 在生成配置之前隐式调用。
|
|
1380
|
+
{!--< /internal-use >!--}
|
|
1381
|
+
"""
|
|
1382
|
+
if self.I18nClass is None:
|
|
1383
|
+
return
|
|
1384
|
+
from .i18n_schema import BaseI18n
|
|
1385
|
+
|
|
1386
|
+
if not isinstance(self.I18nClass, type) or not issubclass(self.I18nClass, BaseI18n):
|
|
1387
|
+
# 非法声明静默跳过(避免影响适配器初始化流程)
|
|
1388
|
+
return
|
|
1389
|
+
|
|
1390
|
+
prefix = f"{self._get_config_key()}."
|
|
1391
|
+
domain = self._get_config_key()
|
|
1392
|
+
try:
|
|
1393
|
+
self.I18nClass.register(prefix=prefix, domain=domain)
|
|
1394
|
+
except Exception:
|
|
1395
|
+
# i18n 注册失败不应中断适配器初始化
|
|
1396
|
+
self._get_logger().debug(
|
|
1397
|
+
f"{self.__class__.__name__}.I18nClass.register() 失败",
|
|
1398
|
+
exc_info=True,
|
|
1399
|
+
)
|
|
1400
|
+
|
|
1401
|
+
def _ensure_event_mixin_registered(self):
|
|
1402
|
+
"""
|
|
1403
|
+
注册 EventMixin 中声明的事件扩展方法
|
|
1404
|
+
|
|
1405
|
+
适配器声明 ``EventMixin`` 时,框架自动将其注册到适配器的平台
|
|
1406
|
+
(即 ``self._platform``),而不是通配符。
|
|
1407
|
+
|
|
1408
|
+
{!--< internal-use >!--}
|
|
1409
|
+
由 __init__() 隐式调用。
|
|
1410
|
+
{!--< /internal-use >!--}
|
|
1411
|
+
"""
|
|
1412
|
+
if self.EventMixin is None:
|
|
1413
|
+
return
|
|
1414
|
+
if not isinstance(self.EventMixin, type):
|
|
1415
|
+
return
|
|
1416
|
+
|
|
1417
|
+
from ..Event import register_event_mixin
|
|
1418
|
+
|
|
1419
|
+
platform = self._platform or "*"
|
|
1420
|
+
try:
|
|
1421
|
+
register_event_mixin(platform, self.EventMixin)
|
|
1422
|
+
except Exception:
|
|
1423
|
+
self._get_logger().debug(
|
|
1424
|
+
f"{self.__class__.__name__}.EventMixin 注册失败",
|
|
1425
|
+
exc_info=True,
|
|
1426
|
+
)
|
|
1427
|
+
|
|
1356
1428
|
def _ensure_accounts_exist(self):
|
|
1357
1429
|
"""
|
|
1358
1430
|
确保多账户配置模板存在,不存在则生成默认账户配置
|
|
@@ -1362,8 +1434,8 @@ class BaseAdapter(ABC):
|
|
|
1362
1434
|
"""
|
|
1363
1435
|
if self.AccountConfigClass is None:
|
|
1364
1436
|
return
|
|
1365
|
-
from ...runtime.config_schema import dataclass_to_defaults_dict
|
|
1366
1437
|
from ..config import config as config_mgr
|
|
1438
|
+
from .config_schema import dataclass_to_defaults_dict
|
|
1367
1439
|
|
|
1368
1440
|
key = f"{self._get_config_key()}.accounts"
|
|
1369
1441
|
data = config_mgr.getConfig(key)
|
|
@@ -78,7 +78,15 @@ def _get_ui_meta(meta: Mapping | None) -> dict:
|
|
|
78
78
|
|
|
79
79
|
|
|
80
80
|
def _type_default(type_hint) -> object:
|
|
81
|
-
"""
|
|
81
|
+
"""
|
|
82
|
+
根据类型注解返回合理的默认值
|
|
83
|
+
|
|
84
|
+
{!--< internal-use >!--}
|
|
85
|
+
{!--< /internal-use >!--}
|
|
86
|
+
|
|
87
|
+
:param type_hint: Python 类型注解
|
|
88
|
+
:return: 对应类型的默认值(int→0, float→0.0, bool→False, list→[], dict→{}, str→"")
|
|
89
|
+
"""
|
|
82
90
|
type_str = str(type_hint).lower()
|
|
83
91
|
if "int" in type_str:
|
|
84
92
|
return 0
|
|
@@ -94,7 +102,15 @@ def _type_default(type_hint) -> object:
|
|
|
94
102
|
|
|
95
103
|
|
|
96
104
|
def _python_type_to_toml_type(type_hint) -> str:
|
|
97
|
-
"""
|
|
105
|
+
"""
|
|
106
|
+
将 Python 类型注解转为 TOML 类型字符串
|
|
107
|
+
|
|
108
|
+
{!--< internal-use >!--}
|
|
109
|
+
{!--< /internal-use >!--}
|
|
110
|
+
|
|
111
|
+
:param type_hint: Python 类型注解
|
|
112
|
+
:return: TOML 类型名(integer/float/boolean/array/table/string)
|
|
113
|
+
"""
|
|
98
114
|
type_str = str(type_hint).lower()
|
|
99
115
|
if "int" in type_str:
|
|
100
116
|
return "integer"
|
|
@@ -110,7 +126,15 @@ def _python_type_to_toml_type(type_hint) -> str:
|
|
|
110
126
|
|
|
111
127
|
|
|
112
128
|
def _format_toml_value(value) -> str:
|
|
113
|
-
"""
|
|
129
|
+
"""
|
|
130
|
+
将 Python 值格式化为 TOML 值字符串
|
|
131
|
+
|
|
132
|
+
{!--< internal-use >!--}
|
|
133
|
+
{!--< /internal-use >!--}
|
|
134
|
+
|
|
135
|
+
:param value: Python 值(str/int/float/bool/list/dict 等)
|
|
136
|
+
:return: TOML 格式的字符串
|
|
137
|
+
"""
|
|
114
138
|
if isinstance(value, bool):
|
|
115
139
|
return "true" if value else "false"
|
|
116
140
|
if isinstance(value, int):
|
|
@@ -129,7 +153,15 @@ def _format_toml_value(value) -> str:
|
|
|
129
153
|
|
|
130
154
|
|
|
131
155
|
def _get_field_default(f):
|
|
132
|
-
"""
|
|
156
|
+
"""
|
|
157
|
+
获取 dataclass 字段的默认值
|
|
158
|
+
|
|
159
|
+
{!--< internal-use >!--}
|
|
160
|
+
{!--< /internal-use >!--}
|
|
161
|
+
|
|
162
|
+
:param f: dataclass Field 对象
|
|
163
|
+
:return: 字段的默认值(优先 default,其次 default_factory,最后根据类型推断)
|
|
164
|
+
"""
|
|
133
165
|
if f.default is not MISSING:
|
|
134
166
|
return f.default
|
|
135
167
|
if f.default_factory is not MISSING:
|
|
@@ -138,7 +170,15 @@ def _get_field_default(f):
|
|
|
138
170
|
|
|
139
171
|
|
|
140
172
|
def _is_empty(value) -> bool:
|
|
141
|
-
"""
|
|
173
|
+
"""
|
|
174
|
+
判断值是否为空(None / 空字符串 / 空列表 / 空字典)
|
|
175
|
+
|
|
176
|
+
{!--< internal-use >!--}
|
|
177
|
+
{!--< /internal-use >!--}
|
|
178
|
+
|
|
179
|
+
:param value: 任意值
|
|
180
|
+
:return: 是否为空
|
|
181
|
+
"""
|
|
142
182
|
if value is None:
|
|
143
183
|
return True
|
|
144
184
|
if isinstance(value, str) and value.strip() == "":
|
|
@@ -147,7 +187,16 @@ def _is_empty(value) -> bool:
|
|
|
147
187
|
|
|
148
188
|
|
|
149
189
|
def _coerce_value(value, type_hint):
|
|
150
|
-
"""
|
|
190
|
+
"""
|
|
191
|
+
将值强制转换为目标类型(如 str→int、str→bool)
|
|
192
|
+
|
|
193
|
+
{!--< internal-use >!--}
|
|
194
|
+
{!--< /internal-use >!--}
|
|
195
|
+
|
|
196
|
+
:param value: 原始值
|
|
197
|
+
:param type_hint: 目标类型注解
|
|
198
|
+
:return: 转换后的值(转换失败时返回原值)
|
|
199
|
+
"""
|
|
151
200
|
if value is None:
|
|
152
201
|
return value
|
|
153
202
|
|
|
@@ -465,27 +514,24 @@ def register_config_i18n(
|
|
|
465
514
|
调用 i18n.register() 注册翻译。
|
|
466
515
|
|
|
467
516
|
两种用法:
|
|
468
|
-
1. 自动模式(translations=None):将字段 description.default
|
|
517
|
+
1. 自动模式(translations=None):将字段 description.default 注册到指定 lang
|
|
518
|
+
(description.default 是语言无关的兜底文本,调用者自行决定注册到哪种语言)
|
|
469
519
|
2. 手动模式:提供 translations 字典({i18n_key: translated_text})
|
|
470
520
|
|
|
471
521
|
使用示例::
|
|
472
522
|
|
|
473
|
-
#
|
|
523
|
+
# 将默认文本注册为中文翻译
|
|
474
524
|
register_config_i18n(MyAdapterConfig, "zh-CN")
|
|
475
525
|
|
|
476
|
-
#
|
|
526
|
+
# 将默认文本注册为英文翻译
|
|
527
|
+
register_config_i18n(MyAdapterConfig, "en")
|
|
528
|
+
|
|
529
|
+
# 手动提供英文翻译(覆盖默认文本)
|
|
477
530
|
register_config_i18n(MyAdapterConfig, "en", {
|
|
478
531
|
"my_adapter.endpoint": "API Endpoint",
|
|
479
532
|
"my_adapter.token": "Platform Token",
|
|
480
533
|
})
|
|
481
534
|
|
|
482
|
-
# 多账户配置同理
|
|
483
|
-
register_config_i18n(MyBotConfig, "zh-CN")
|
|
484
|
-
register_config_i18n(MyBotConfig, "en", {
|
|
485
|
-
"my_adapter.bot_id": "Bot ID",
|
|
486
|
-
"my_adapter.bot_token": "Bot Token",
|
|
487
|
-
})
|
|
488
|
-
|
|
489
535
|
:param config_class: dataclass 配置类
|
|
490
536
|
:param lang: 语言代码(如 "zh-CN", "en")
|
|
491
537
|
:param translations: 手动提供的翻译字典,None 则自动提取
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ErisPulse i18n 键声明 Schema 模块
|
|
3
|
+
|
|
4
|
+
提供基于类属性的 i18n 翻译键声明,支持框架自动注册。
|
|
5
|
+
适用于适配器、模块、外部项目等任何需要批量声明翻译键的场景。
|
|
6
|
+
|
|
7
|
+
{!--< tips >!--}
|
|
8
|
+
1. 继承 BaseI18n 基类,通过类属性声明翻译键(命名与 BaseConfig 对齐)
|
|
9
|
+
2. 每个属性对应一个翻译键,属性名(加模块前缀)作为键路径
|
|
10
|
+
3. 也可通过 I18nKey(key=...) 显式指定完整键路径
|
|
11
|
+
4. 框架在加载模块/适配器时自动注册所有声明的翻译键
|
|
12
|
+
5. 配合 BaseModule.I18nClass / BaseAdapter.I18nClass 使用,无需手动调用 i18n.register()
|
|
13
|
+
6. ``default`` 是语言无关的兜底文本,不会注册到任何语言;
|
|
14
|
+
要让翻译生效,必须显式传入至少一个语言参数(``zh_CN=`` / ``en=`` 等)
|
|
15
|
+
{!--< /tips >!--}
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class I18nKey:
|
|
20
|
+
"""
|
|
21
|
+
单个 i18n 翻译键的声明
|
|
22
|
+
|
|
23
|
+
:param default: 兜底文本(语言无关)。当所有已注册语言均未覆盖此键时,
|
|
24
|
+
作为最后的显示文本。**不会注册到任何语言**。
|
|
25
|
+
各国开发者可使用自己母语填写此字段,框架不做任何假设。
|
|
26
|
+
:param key: 完整的翻译键路径(如 ``"mymodule.welcome"``)。
|
|
27
|
+
省略时使用属性名 + 调用方提供的前缀自动生成。
|
|
28
|
+
:param zh_CN: 简体中文翻译
|
|
29
|
+
:param zh_TW: 繁体中文翻译
|
|
30
|
+
:param en: 英文翻译
|
|
31
|
+
:param ja: 日文翻译
|
|
32
|
+
:param ru: 俄文翻译
|
|
33
|
+
|
|
34
|
+
使用示例::
|
|
35
|
+
|
|
36
|
+
from ErisPulse.Core.Bases import BaseI18n, I18nKey
|
|
37
|
+
|
|
38
|
+
class MyModule(BaseModule):
|
|
39
|
+
class I18nClass(BaseI18n):
|
|
40
|
+
# 自动生成键: mymodule.welcome
|
|
41
|
+
welcome: I18nKey = I18nKey(
|
|
42
|
+
default="Welcome", # 语言无关的兜底
|
|
43
|
+
zh_CN="欢迎",
|
|
44
|
+
zh_TW="歡迎",
|
|
45
|
+
en="Welcome",
|
|
46
|
+
ja="ようこそ",
|
|
47
|
+
ru="Добро пожаловать",
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# 显式指定键路径
|
|
51
|
+
deep: I18nKey = I18nKey(
|
|
52
|
+
key="mymodule.deep.nested.key",
|
|
53
|
+
default="Default text",
|
|
54
|
+
zh_CN="默认文本",
|
|
55
|
+
zh_TW="預設文本",
|
|
56
|
+
en="Default text",
|
|
57
|
+
ja="デフォルトテキスト",
|
|
58
|
+
ru="Текст по умолчанию",
|
|
59
|
+
)
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
__slots__ = ("_key", "default", "translations")
|
|
63
|
+
|
|
64
|
+
def __init__(
|
|
65
|
+
self,
|
|
66
|
+
default: str,
|
|
67
|
+
*,
|
|
68
|
+
key: str | None = None,
|
|
69
|
+
zh_CN: str | None = None,
|
|
70
|
+
zh_TW: str | None = None,
|
|
71
|
+
en: str | None = None,
|
|
72
|
+
ja: str | None = None,
|
|
73
|
+
ru: str | None = None,
|
|
74
|
+
):
|
|
75
|
+
if not default:
|
|
76
|
+
raise ValueError("default 是必填项(语言无关的兜底文本)")
|
|
77
|
+
|
|
78
|
+
self._key = key
|
|
79
|
+
self.default = default
|
|
80
|
+
# translations 只包含显式声明的语言翻译
|
|
81
|
+
# default 不注册到任何语言
|
|
82
|
+
self.translations: dict[str, str] = {}
|
|
83
|
+
if zh_CN is not None:
|
|
84
|
+
self.translations["zh-CN"] = zh_CN
|
|
85
|
+
if zh_TW is not None:
|
|
86
|
+
self.translations["zh-TW"] = zh_TW
|
|
87
|
+
if en is not None:
|
|
88
|
+
self.translations["en"] = en
|
|
89
|
+
if ja is not None:
|
|
90
|
+
self.translations["ja"] = ja
|
|
91
|
+
if ru is not None:
|
|
92
|
+
self.translations["ru"] = ru
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def explicit_key(self) -> str | None:
|
|
96
|
+
"""
|
|
97
|
+
获取显式指定的键路径(如有)
|
|
98
|
+
|
|
99
|
+
:return: 显式键名字符串,或 None 表示使用前缀+属性名自动生成
|
|
100
|
+
"""
|
|
101
|
+
return self._key
|
|
102
|
+
|
|
103
|
+
def __repr__(self) -> str:
|
|
104
|
+
return (
|
|
105
|
+
f"I18nKey(key={self._key!r}, default={self.default!r}, "
|
|
106
|
+
f"langs={sorted(self.translations.keys())})"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
# 模块级别名,方便在类定义中使用更短的名称
|
|
111
|
+
# 使用示例::
|
|
112
|
+
# class MyKeys(BaseI18n):
|
|
113
|
+
# hello = key(default="Hello", en="Hello", zh_CN="你好")
|
|
114
|
+
key = I18nKey
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class BaseI18n:
|
|
118
|
+
"""
|
|
119
|
+
i18n 键声明集合的基类
|
|
120
|
+
|
|
121
|
+
命名与 :class:`BaseConfig` 对齐:用户通过嵌套类继承此类声明翻译键,
|
|
122
|
+
框架会在模块/适配器加载时自动调用 :meth:`register` 将所有声明的翻译键
|
|
123
|
+
注册到 i18n 系统。
|
|
124
|
+
|
|
125
|
+
{!--< tips >!--}
|
|
126
|
+
1. 类属性必须是 :class:`I18nKey` 实例,否则被忽略
|
|
127
|
+
2. 属性名以下划线开头的会被忽略(视为私有/内部)
|
|
128
|
+
3. 自动生成的键路径为 ``<前缀><属性名>``,前缀通常是模块名 + ``.``
|
|
129
|
+
4. 通过 :class:`I18nKey` 的 ``key=`` 参数可显式指定完整键路径
|
|
130
|
+
5. 同一 domain 可被多次注册,键值会被覆盖更新
|
|
131
|
+
6. ``I18nKey.default`` 是语言无关的兜底文本,不参与注册;
|
|
132
|
+
实际翻译必须通过 ``zh_CN=`` / ``en=`` 等参数显式声明
|
|
133
|
+
{!--< /tips >!--}
|
|
134
|
+
|
|
135
|
+
使用示例::
|
|
136
|
+
|
|
137
|
+
from ErisPulse.Core.Bases import BaseModule, BaseI18n, I18nKey
|
|
138
|
+
|
|
139
|
+
class MyModule(BaseModule):
|
|
140
|
+
class I18nClass(BaseI18n):
|
|
141
|
+
welcome: I18nKey = I18nKey(
|
|
142
|
+
default="Welcome",
|
|
143
|
+
zh_CN="欢迎",
|
|
144
|
+
zh_TW="歡迎",
|
|
145
|
+
en="Welcome",
|
|
146
|
+
ja="ようこそ",
|
|
147
|
+
ru="Добро пожаловать",
|
|
148
|
+
)
|
|
149
|
+
goodbye: I18nKey = I18nKey(
|
|
150
|
+
default="Bye",
|
|
151
|
+
zh_CN="再见",
|
|
152
|
+
zh_TW="再見",
|
|
153
|
+
en="Goodbye",
|
|
154
|
+
ja="さようなら",
|
|
155
|
+
ru="До свидания",
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
也可独立使用(手动注册)::
|
|
159
|
+
|
|
160
|
+
class MyKeys(BaseI18n):
|
|
161
|
+
hello: I18nKey = I18nKey(
|
|
162
|
+
default="Hello",
|
|
163
|
+
zh_CN="你好",
|
|
164
|
+
zh_TW="你好",
|
|
165
|
+
en="Hello",
|
|
166
|
+
ja="こんにちは",
|
|
167
|
+
ru="Привет",
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
MyKeys.register(prefix="myapp.", domain="myapp")
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
@classmethod
|
|
174
|
+
def _collect_keys(cls) -> dict[str, I18nKey]:
|
|
175
|
+
"""
|
|
176
|
+
收集类中所有声明的 I18nKey
|
|
177
|
+
|
|
178
|
+
遍历 MRO(含父类继承),收集所有非下划线开头的 I18nKey 类属性。
|
|
179
|
+
子类同名属性会覆盖父类(与 Python 属性查找语义一致)。
|
|
180
|
+
|
|
181
|
+
:return: ``{属性名: I18nKey 实例}`` 字典
|
|
182
|
+
"""
|
|
183
|
+
keys: dict[str, I18nKey] = {}
|
|
184
|
+
# 反向遍历 MRO,让子类覆盖父类
|
|
185
|
+
for klass in reversed(cls.__mro__):
|
|
186
|
+
for name, value in vars(klass).items():
|
|
187
|
+
if name.startswith("_"):
|
|
188
|
+
continue
|
|
189
|
+
if isinstance(value, I18nKey):
|
|
190
|
+
keys[name] = value
|
|
191
|
+
return keys
|
|
192
|
+
|
|
193
|
+
@classmethod
|
|
194
|
+
def register(cls, prefix: str = "", domain: str = "app") -> int:
|
|
195
|
+
"""
|
|
196
|
+
注册所有翻译键到 i18n 系统
|
|
197
|
+
|
|
198
|
+
仅注册 :class:`I18nKey` 中显式声明的语言翻译。
|
|
199
|
+
``default`` 字段是语言无关的兜底文本,不参与注册。
|
|
200
|
+
|
|
201
|
+
:param prefix: 键名前缀(通常是模块名 + ``.``,如 ``"mymodule."``)。
|
|
202
|
+
仅对未显式指定 ``key`` 的翻译键生效。
|
|
203
|
+
:param domain: i18n 域标识,用于卸载时按域统一清理。
|
|
204
|
+
建议使用模块名。
|
|
205
|
+
:return: 注册的翻译条目总数
|
|
206
|
+
|
|
207
|
+
:example:
|
|
208
|
+
>>> class MyKeys(BaseI18n):
|
|
209
|
+
... hello: I18nKey = I18nKey(
|
|
210
|
+
... default="Hello",
|
|
211
|
+
... zh_CN="你好",
|
|
212
|
+
... en="Hello",
|
|
213
|
+
... )
|
|
214
|
+
>>> MyKeys.register(prefix="myapp.", domain="myapp")
|
|
215
|
+
2 # zh-CN + en
|
|
216
|
+
"""
|
|
217
|
+
from ..i18n import i18n
|
|
218
|
+
|
|
219
|
+
count = 0
|
|
220
|
+
for attr_name, i18n_key in cls._collect_keys().items():
|
|
221
|
+
# 决定最终的 key 路径:显式 key > 前缀 + 属性名
|
|
222
|
+
final_key = i18n_key.explicit_key or f"{prefix}{attr_name}"
|
|
223
|
+
|
|
224
|
+
for lang, text in i18n_key.translations.items():
|
|
225
|
+
i18n.register(lang, {final_key: text}, domain=domain)
|
|
226
|
+
count += 1
|
|
227
|
+
|
|
228
|
+
return count
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
# ---------------------------------------------------------------------------
|
|
232
|
+
# 导出
|
|
233
|
+
# ---------------------------------------------------------------------------
|
|
234
|
+
|
|
235
|
+
__all__ = [
|
|
236
|
+
"BaseI18n",
|
|
237
|
+
"I18nKey",
|
|
238
|
+
"key",
|
|
239
|
+
]
|