zrb 1.0.0a21__py3-none-any.whl → 1.0.0b2__py3-none-any.whl
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.
- zrb/__init__.py +2 -1
- zrb/__main__.py +0 -3
- zrb/builtin/__init__.py +3 -0
- zrb/builtin/group.py +1 -0
- zrb/builtin/llm/llm_chat.py +2 -2
- zrb/builtin/llm/tool/web.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_task.py +2 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/config.py +5 -2
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +80 -20
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +150 -42
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/my_entity_service.py +113 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/my_entity_service_factory.py +9 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/repository/my_entity_db_repository.py +0 -10
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/repository/my_entity_repository.py +37 -16
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/repository/{factory.py → my_entity_repository_factory.py} +2 -2
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/schema/my_entity.py +16 -6
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/client_method.py +57 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/gateway_subroute.py +72 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/format_task.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/input.py +13 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_task.py +23 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +42 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/gateway/subroute/my_module.py +7 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/my_module_api_client.py +6 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/{any_client.py → my_module_client.py} +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/my_module_client_factory.py +11 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/my_module_direct_client.py +5 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/route.py +11 -11
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/module_task_definition.py +2 -2
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/task.py +8 -8
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/util.py +47 -20
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app_factory.py +29 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_db_repository.py +185 -101
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_service.py +236 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/{db_engine.py → db_engine_factory.py} +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/error.py +12 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/logger_factory.py +10 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/parser_factory.py +7 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/app.py +47 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/parser.py +105 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/user_agent.py +58 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/view.py +37 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/config.py +25 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/main.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_api_client.py +16 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client.py +163 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client_factory.py +9 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_direct_client.py +15 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_auth_tables.py +160 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration_metadata.py +18 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py +7 -3
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service.py +117 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service_factory.py +11 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_db_repository.py +26 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_repository.py +61 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_repository_factory.py +13 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_db_repository.py +75 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository.py +59 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository_factory.py +13 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service.py +105 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service_factory.py +7 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_db_repository.py +42 -13
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository.py +38 -17
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository_factory.py +2 -2
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service.py +105 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service_factory.py +7 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py +43 -14
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py +198 -28
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/util/view.py +74 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/error.html +6 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/homepage.html +6 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/android-chrome-192x192.png +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/android-chrome-512x512.png +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/favicon-32x32.png +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.amber.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.blue.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.cyan.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.fuchsia.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.green.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.grey.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.indigo.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.jade.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.lime.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.orange.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.pink.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.pumpkin.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.purple.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.red.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.sand.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.slate.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.violet.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.yellow.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.zinc.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/template/default.html +34 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt +1 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/permission.py +17 -5
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/role.py +50 -4
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/session.py +52 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/user.py +30 -5
- zrb/builtin/python.py +1 -1
- zrb/builtin/random.py +61 -0
- zrb/cmd/cmd_val.py +6 -5
- zrb/content_transformer/any_content_transformer.py +7 -0
- zrb/content_transformer/content_transformer.py +6 -0
- zrb/runner/cli.py +14 -7
- zrb/runner/web_app.py +28 -280
- zrb/runner/web_config/config.py +91 -0
- zrb/runner/web_config/config_factory.py +26 -0
- zrb/runner/web_route/docs_route.py +17 -0
- zrb/runner/web_route/error_page/serve_default_404.py +28 -0
- zrb/runner/{web_controller/error_page/controller.py → web_route/error_page/show_error_page.py} +2 -2
- zrb/runner/{web_controller → web_route}/error_page/view.html +5 -0
- zrb/runner/web_route/home_page/home_page_route.py +51 -0
- zrb/runner/web_route/login_api_route.py +31 -0
- zrb/runner/web_route/login_page/login_page_route.py +39 -0
- zrb/runner/web_route/logout_api_route.py +18 -0
- zrb/runner/web_route/logout_page/logout_page_route.py +40 -0
- zrb/runner/{web_controller/group_info_page/controller.py → web_route/node_page/group/show_group_page.py} +3 -3
- zrb/runner/web_route/node_page/node_page_route.py +50 -0
- zrb/runner/{web_controller/session_page/controller.py → web_route/node_page/task/show_task_page.py} +3 -3
- zrb/runner/web_route/refresh_token_api_route.py +38 -0
- zrb/runner/web_route/static/static_route.py +44 -0
- zrb/runner/web_route/task_input_api_route.py +47 -0
- zrb/runner/web_route/task_session_api_route.py +102 -0
- zrb/runner/web_schema/session.py +5 -0
- zrb/runner/web_schema/token.py +11 -0
- zrb/runner/web_schema/user.py +32 -0
- zrb/runner/web_util/cookie.py +29 -0
- zrb/runner/{web_util.py → web_util/html.py} +1 -23
- zrb/runner/web_util/token.py +72 -0
- zrb/runner/web_util/user.py +63 -0
- zrb/session/session.py +6 -4
- zrb/session_state_logger/{default_session_state_logger.py → session_state_logger_factory.py} +1 -1
- zrb/task/base_task.py +53 -6
- zrb/task/base_trigger.py +2 -0
- zrb/task/cmd_task.py +9 -5
- zrb/task/http_check.py +2 -0
- zrb/task/llm_task.py +2 -0
- zrb/task/make_task.py +2 -0
- zrb/task/rsync_task.py +2 -0
- zrb/task/scaffolder.py +8 -5
- zrb/task/scheduler.py +2 -0
- zrb/task/tcp_check.py +2 -0
- zrb/task_status/task_status.py +4 -3
- zrb/util/cmd/command.py +1 -0
- zrb/util/file.py +7 -1
- {zrb-1.0.0a21.dist-info → zrb-1.0.0b2.dist-info}/METADATA +1 -1
- zrb-1.0.0b2.dist-info/RECORD +307 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/any_client_method.py +0 -27
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/my_entity_usecase.py +0 -65
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/api_client.py +0 -6
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/direct_client.py +0 -6
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/factory.py +0 -9
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app.py +0 -20
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_usecase.py +0 -245
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/any_client.py +0 -33
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/api_client.py +0 -7
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/direct_client.py +0 -6
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/factory.py +0 -9
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_user_table.py +0 -37
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase.py +0 -53
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase_factory.py +0 -6
- zrb/runner/web_config.py +0 -274
- zrb/runner/web_controller/home_page/controller.py +0 -33
- zrb/runner/web_controller/login_page/controller.py +0 -25
- zrb/runner/web_controller/logout_page/controller.py +0 -26
- zrb-1.0.0a21.dist-info/RECORD +0 -244
- /zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/{create_column_task.py → add_column_task.py} +0 -0
- /zrb/{runner/web_controller → builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission}/__init__.py +0 -0
- /zrb/{runner/web_controller/group_info_page → builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role}/__init__.py +0 -0
- /zrb/runner/{web_controller/home_page → web_route}/__init__.py +0 -0
- /zrb/runner/{web_controller/session_page → web_route/home_page}/__init__.py +0 -0
- /zrb/runner/{web_controller → web_route}/home_page/view.html +0 -0
- /zrb/runner/{web_controller → web_route}/login_page/view.html +0 -0
- /zrb/runner/{web_controller → web_route}/logout_page/view.html +0 -0
- /zrb/runner/{web_controller/group_info_page → web_route/node_page/group}/view.html +0 -0
- /zrb/runner/{web_controller/session_page → web_route/node_page/task}/partial/input.html +0 -0
- /zrb/runner/{web_controller/session_page → web_route/node_page/task}/view.html +0 -0
- /zrb/runner/{refresh-token.template.js → web_route/static/refresh-token.template.js} +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/common.css +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/favicon-32x32.png +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/login/event.js +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/logout/event.js +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/pico.min.css +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/session/common-util.js +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/session/current-session.js +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/session/event.js +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/session/past-session.js +0 -0
- {zrb-1.0.0a21.dist-info → zrb-1.0.0b2.dist-info}/WHEEL +0 -0
- {zrb-1.0.0a21.dist-info → zrb-1.0.0b2.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from zrb.runner.web_config.config import WebConfig
|
4
|
+
from zrb.runner.web_schema.user import User
|
5
|
+
|
6
|
+
if TYPE_CHECKING:
|
7
|
+
# Import Request only for type checking to reduce runtime dependencies
|
8
|
+
from fastapi import Request
|
9
|
+
|
10
|
+
|
11
|
+
def get_user_by_credentials(
|
12
|
+
web_config: WebConfig, username: str, password: str
|
13
|
+
) -> User | None:
|
14
|
+
user = web_config.find_user_by_username(username)
|
15
|
+
if user is None or not user.is_password_match(password):
|
16
|
+
return None
|
17
|
+
return user
|
18
|
+
|
19
|
+
|
20
|
+
async def get_user_from_request(
|
21
|
+
web_config: WebConfig, request: "Request"
|
22
|
+
) -> User | None:
|
23
|
+
from fastapi.security import OAuth2PasswordBearer
|
24
|
+
|
25
|
+
if not web_config.enable_auth:
|
26
|
+
return web_config.default_user
|
27
|
+
# Normally we use "Depends"
|
28
|
+
get_bearer_token = OAuth2PasswordBearer(tokenUrl="/api/v1/login", auto_error=False)
|
29
|
+
bearer_token = await get_bearer_token(request)
|
30
|
+
token_user = _get_user_from_token(web_config, bearer_token)
|
31
|
+
if token_user is not None:
|
32
|
+
return token_user
|
33
|
+
cookie_user = _get_user_from_cookie(web_config, request)
|
34
|
+
if cookie_user is not None:
|
35
|
+
return cookie_user
|
36
|
+
return web_config.default_user
|
37
|
+
|
38
|
+
|
39
|
+
def _get_user_from_cookie(web_config: WebConfig, request: "Request") -> User | None:
|
40
|
+
token = request.cookies.get(web_config.access_token_cookie_name)
|
41
|
+
if token:
|
42
|
+
return _get_user_from_token(web_config, token)
|
43
|
+
return None
|
44
|
+
|
45
|
+
|
46
|
+
def _get_user_from_token(web_config: WebConfig, token: str) -> User | None:
|
47
|
+
try:
|
48
|
+
from jose import jwt
|
49
|
+
|
50
|
+
payload = jwt.decode(
|
51
|
+
token,
|
52
|
+
web_config.secret_key,
|
53
|
+
options={"require_sub": True, "require_exp": True},
|
54
|
+
)
|
55
|
+
username: str = payload.get("sub")
|
56
|
+
if username is None:
|
57
|
+
return None
|
58
|
+
user = web_config.find_user_by_username(username)
|
59
|
+
if user is None:
|
60
|
+
return None
|
61
|
+
return user
|
62
|
+
except Exception:
|
63
|
+
return None
|
zrb/session/session.py
CHANGED
@@ -11,9 +11,7 @@ from zrb.session_state_log.session_state_log import (
|
|
11
11
|
TaskStatusStateLog,
|
12
12
|
)
|
13
13
|
from zrb.session_state_logger.any_session_state_logger import AnySessionStateLogger
|
14
|
-
from zrb.session_state_logger.
|
15
|
-
default_session_state_logger,
|
16
|
-
)
|
14
|
+
from zrb.session_state_logger.session_state_logger_factory import session_state_logger
|
17
15
|
from zrb.task.any_task import AnyTask
|
18
16
|
from zrb.task_status.task_status import TaskStatus
|
19
17
|
from zrb.util.cli.style import (
|
@@ -126,7 +124,7 @@ class Session(AnySession):
|
|
126
124
|
@property
|
127
125
|
def state_logger(self) -> AnySessionStateLogger:
|
128
126
|
if self._state_logger is None:
|
129
|
-
return
|
127
|
+
return session_state_logger
|
130
128
|
return self._state_logger
|
131
129
|
|
132
130
|
def set_main_task(self, main_task: AnyTask):
|
@@ -215,6 +213,10 @@ class Session(AnySession):
|
|
215
213
|
self._register_single_task(task)
|
216
214
|
for readiness_check in task.readiness_checks:
|
217
215
|
self.register_task(readiness_check)
|
216
|
+
for successor in task.successors:
|
217
|
+
self.register_task(successor)
|
218
|
+
for fallback in task.fallbacks:
|
219
|
+
self.register_task(fallback)
|
218
220
|
for upstream in task.upstreams:
|
219
221
|
self.register_task(upstream)
|
220
222
|
if task not in self._downstreams[upstream]:
|
zrb/task/base_task.py
CHANGED
@@ -242,7 +242,29 @@ class BaseTask(AnyTask):
|
|
242
242
|
def run(
|
243
243
|
self, session: AnySession | None = None, str_kwargs: dict[str, str] = {}
|
244
244
|
) -> Any:
|
245
|
-
|
245
|
+
loop = asyncio.new_event_loop()
|
246
|
+
try:
|
247
|
+
return loop.run_until_complete(self._run_and_cleanup(session, str_kwargs))
|
248
|
+
finally:
|
249
|
+
loop.close()
|
250
|
+
|
251
|
+
async def _run_and_cleanup(
|
252
|
+
self, session: AnySession | None = None, str_kwargs: dict[str, str] = {}
|
253
|
+
) -> Any:
|
254
|
+
try:
|
255
|
+
result = await self.async_run(session, str_kwargs)
|
256
|
+
finally:
|
257
|
+
if not session.is_terminated:
|
258
|
+
session.terminate()
|
259
|
+
# Cancel all running tasks except the current one
|
260
|
+
current_task = asyncio.current_task()
|
261
|
+
pending = [task for task in asyncio.all_tasks() if task is not current_task]
|
262
|
+
for task in pending:
|
263
|
+
task.cancel()
|
264
|
+
# Wait for all tasks to complete with a timeout
|
265
|
+
if pending:
|
266
|
+
await asyncio.wait(pending, timeout=5)
|
267
|
+
return result
|
246
268
|
|
247
269
|
async def async_run(
|
248
270
|
self, session: AnySession | None = None, str_kwargs: dict[str, str] = {}
|
@@ -265,11 +287,9 @@ class BaseTask(AnyTask):
|
|
265
287
|
def __fill_shared_context_envs(self, shared_context: AnySharedContext):
|
266
288
|
# Inject os environ
|
267
289
|
os_env_map = {
|
268
|
-
key: val
|
269
|
-
for key, val in os.environ.items()
|
270
|
-
if key not in shared_context._env
|
290
|
+
key: val for key, val in os.environ.items() if key not in shared_context.env
|
271
291
|
}
|
272
|
-
shared_context.
|
292
|
+
shared_context.env.update(os_env_map)
|
273
293
|
|
274
294
|
async def exec_root_tasks(self, session: AnySession):
|
275
295
|
session.set_main_task(self)
|
@@ -416,6 +436,23 @@ class BaseTask(AnyTask):
|
|
416
436
|
ctx.log_info("Continue monitoring")
|
417
437
|
|
418
438
|
async def __exec_action_and_retry(self, session: AnySession) -> Any:
|
439
|
+
"""
|
440
|
+
Executes an action with retry logic.
|
441
|
+
|
442
|
+
This method attempts to execute the action defined in `_exec_action` with a specified number of retries.
|
443
|
+
If the action fails, it will retry after a specified period until the maximum number of attempts is reached.
|
444
|
+
If the action succeeds, it marks the task as completed and executes any successors.
|
445
|
+
If the action fails permanently, it marks the task as permanently failed and executes any fallbacks.
|
446
|
+
|
447
|
+
Args:
|
448
|
+
session (AnySession): The session object containing the task status and context.
|
449
|
+
|
450
|
+
Returns:
|
451
|
+
Any: The result of the executed action if successful.
|
452
|
+
|
453
|
+
Raises:
|
454
|
+
Exception: If the action fails permanently after all retry attempts.
|
455
|
+
"""
|
419
456
|
ctx = self.get_ctx(session)
|
420
457
|
max_attempt = self._retries + 1
|
421
458
|
ctx.set_max_attempt(max_attempt)
|
@@ -433,13 +470,14 @@ class BaseTask(AnyTask):
|
|
433
470
|
# Put result on xcom
|
434
471
|
task_xcom: Xcom = ctx.xcom.get(self.name)
|
435
472
|
task_xcom.push(result)
|
473
|
+
self.__skip_fallbacks(session)
|
436
474
|
await run_async(self.__exec_successors(session))
|
437
475
|
return result
|
438
476
|
except (asyncio.CancelledError, KeyboardInterrupt):
|
439
477
|
ctx.log_info("Marked as failed")
|
440
478
|
session.get_task_status(self).mark_as_failed()
|
441
479
|
return
|
442
|
-
except
|
480
|
+
except BaseException as e:
|
443
481
|
ctx.log_error(e)
|
444
482
|
if attempt < max_attempt - 1:
|
445
483
|
ctx.log_info("Marked as failed")
|
@@ -447,6 +485,7 @@ class BaseTask(AnyTask):
|
|
447
485
|
continue
|
448
486
|
ctx.log_info("Marked as permanently failed")
|
449
487
|
session.get_task_status(self).mark_as_permanently_failed()
|
488
|
+
self.__skip_successors(session)
|
450
489
|
await run_async(self.__exec_fallbacks(session))
|
451
490
|
raise e
|
452
491
|
|
@@ -457,6 +496,10 @@ class BaseTask(AnyTask):
|
|
457
496
|
]
|
458
497
|
await asyncio.gather(*successor_coros)
|
459
498
|
|
499
|
+
def __skip_successors(self, session: AnySession) -> Any:
|
500
|
+
for successor in self.successors:
|
501
|
+
session.get_task_status(successor).mark_as_skipped()
|
502
|
+
|
460
503
|
async def __exec_fallbacks(self, session: AnySession) -> Any:
|
461
504
|
fallbacks: list[AnyTask] = self.fallbacks
|
462
505
|
fallback_coros = [
|
@@ -464,6 +507,10 @@ class BaseTask(AnyTask):
|
|
464
507
|
]
|
465
508
|
await asyncio.gather(*fallback_coros)
|
466
509
|
|
510
|
+
def __skip_fallbacks(self, session: AnySession) -> Any:
|
511
|
+
for fallback in self.fallbacks:
|
512
|
+
session.get_task_status(fallback).mark_as_skipped()
|
513
|
+
|
467
514
|
async def _exec_action(self, ctx: AnyContext) -> Any:
|
468
515
|
"""Execute the main action of the task.
|
469
516
|
By default will render and run the _action attribute.
|
zrb/task/base_trigger.py
CHANGED
@@ -42,6 +42,7 @@ class BaseTrigger(BaseTask):
|
|
42
42
|
monitor_readiness: bool = False,
|
43
43
|
upstream: list[AnyTask] | AnyTask | None = None,
|
44
44
|
fallback: list[AnyTask] | AnyTask | None = None,
|
45
|
+
successor: list[AnyTask] | AnyTask | None = None,
|
45
46
|
):
|
46
47
|
super().__init__(
|
47
48
|
name=name,
|
@@ -63,6 +64,7 @@ class BaseTrigger(BaseTask):
|
|
63
64
|
monitor_readiness=monitor_readiness,
|
64
65
|
upstream=upstream,
|
65
66
|
fallback=fallback,
|
67
|
+
successor=successor,
|
66
68
|
)
|
67
69
|
self._callbacks = callback
|
68
70
|
self._queue_name = queue_name
|
zrb/task/cmd_task.py
CHANGED
@@ -56,6 +56,7 @@ class CmdTask(BaseTask):
|
|
56
56
|
monitor_readiness: bool = False,
|
57
57
|
upstream: list[AnyTask] | AnyTask | None = None,
|
58
58
|
fallback: list[AnyTask] | AnyTask | None = None,
|
59
|
+
successor: list[AnyTask] | AnyTask | None = None,
|
59
60
|
):
|
60
61
|
super().__init__(
|
61
62
|
name=name,
|
@@ -76,6 +77,7 @@ class CmdTask(BaseTask):
|
|
76
77
|
monitor_readiness=monitor_readiness,
|
77
78
|
upstream=upstream,
|
78
79
|
fallback=fallback,
|
80
|
+
successor=successor,
|
79
81
|
)
|
80
82
|
self._shell = shell
|
81
83
|
self._render_shell = render_shell
|
@@ -233,17 +235,18 @@ class CmdTask(BaseTask):
|
|
233
235
|
|
234
236
|
def _render_cmd_val(self, ctx: AnyContext, cmd_val: CmdVal) -> str:
|
235
237
|
if isinstance(cmd_val, list):
|
238
|
+
cmd_val_list = [
|
239
|
+
self.__render_single_cmd_val(ctx, single_cmd_val)
|
240
|
+
for single_cmd_val in cmd_val
|
241
|
+
]
|
236
242
|
return "\n".join(
|
237
|
-
[
|
238
|
-
self.__render_single_cmd_val(ctx, single_cmd_val)
|
239
|
-
for single_cmd_val in cmd_val
|
240
|
-
]
|
243
|
+
[cmd_val for cmd_val in cmd_val_list if cmd_val is not None]
|
241
244
|
)
|
242
245
|
return self.__render_single_cmd_val(ctx, cmd_val)
|
243
246
|
|
244
247
|
def __render_single_cmd_val(
|
245
248
|
self, ctx: AnyContext, single_cmd_val: SingleCmdVal
|
246
|
-
) -> str:
|
249
|
+
) -> str | None:
|
247
250
|
if callable(single_cmd_val):
|
248
251
|
return single_cmd_val(ctx)
|
249
252
|
if isinstance(single_cmd_val, str):
|
@@ -252,6 +255,7 @@ class CmdTask(BaseTask):
|
|
252
255
|
return single_cmd_val
|
253
256
|
if isinstance(single_cmd_val, AnyCmdVal):
|
254
257
|
return single_cmd_val.to_str(ctx)
|
258
|
+
return None
|
255
259
|
|
256
260
|
def __get_multiline_repr(self, text: str) -> str:
|
257
261
|
lines_repr: list[str] = []
|
zrb/task/http_check.py
CHANGED
@@ -28,6 +28,7 @@ class HttpCheck(BaseTask):
|
|
28
28
|
execute_condition: bool | str | Callable[[Context], bool] = True,
|
29
29
|
upstream: list[AnyTask] | AnyTask | None = None,
|
30
30
|
fallback: list[AnyTask] | AnyTask | None = None,
|
31
|
+
successor: list[AnyTask] | AnyTask | None = None,
|
31
32
|
):
|
32
33
|
super().__init__(
|
33
34
|
name=name,
|
@@ -41,6 +42,7 @@ class HttpCheck(BaseTask):
|
|
41
42
|
retries=0,
|
42
43
|
upstream=upstream,
|
43
44
|
fallback=fallback,
|
45
|
+
successor=successor,
|
44
46
|
)
|
45
47
|
self._url = url
|
46
48
|
self._render_url = render_url
|
zrb/task/llm_task.py
CHANGED
@@ -67,6 +67,7 @@ class LLMTask(BaseTask):
|
|
67
67
|
monitor_readiness: bool = False,
|
68
68
|
upstream: list[AnyTask] | AnyTask | None = None,
|
69
69
|
fallback: list[AnyTask] | AnyTask | None = None,
|
70
|
+
successor: list[AnyTask] | AnyTask | None = None,
|
70
71
|
):
|
71
72
|
super().__init__(
|
72
73
|
name=name,
|
@@ -87,6 +88,7 @@ class LLMTask(BaseTask):
|
|
87
88
|
monitor_readiness=monitor_readiness,
|
88
89
|
upstream=upstream,
|
89
90
|
fallback=fallback,
|
91
|
+
successor=successor,
|
90
92
|
)
|
91
93
|
self._model = model
|
92
94
|
self._render_model = render_model
|
zrb/task/make_task.py
CHANGED
@@ -29,6 +29,7 @@ def make_task(
|
|
29
29
|
monitor_readiness: bool = False,
|
30
30
|
upstream: list[AnyTask] | AnyTask | None = None,
|
31
31
|
fallback: list[AnyTask] | AnyTask | None = None,
|
32
|
+
successor: list[AnyTask] | AnyTask | None = None,
|
32
33
|
group: AnyGroup | None = None,
|
33
34
|
alias: str | None = None,
|
34
35
|
) -> Callable[[Callable[[AnyContext], Any]], AnyTask]:
|
@@ -53,6 +54,7 @@ def make_task(
|
|
53
54
|
monitor_readiness=monitor_readiness,
|
54
55
|
upstream=upstream,
|
55
56
|
fallback=fallback,
|
57
|
+
successor=successor,
|
56
58
|
)
|
57
59
|
if group is not None:
|
58
60
|
return group.add_task(task, alias=alias)
|
zrb/task/rsync_task.py
CHANGED
@@ -49,6 +49,7 @@ class RsyncTask(CmdTask):
|
|
49
49
|
readiness_check: list[AnyTask] | AnyTask | None = None,
|
50
50
|
upstream: list[AnyTask] | AnyTask | None = None,
|
51
51
|
fallback: list[AnyTask] | AnyTask | None = None,
|
52
|
+
successor: list[AnyTask] | AnyTask | None = None,
|
52
53
|
):
|
53
54
|
super().__init__(
|
54
55
|
name=name,
|
@@ -80,6 +81,7 @@ class RsyncTask(CmdTask):
|
|
80
81
|
readiness_check=readiness_check,
|
81
82
|
upstream=upstream,
|
82
83
|
fallback=fallback,
|
84
|
+
successor=successor,
|
83
85
|
)
|
84
86
|
self._remote_source_path = remote_source_path
|
85
87
|
self._render_remote_source_path = render_remote_source_path
|
zrb/task/scaffolder.py
CHANGED
@@ -11,6 +11,7 @@ from zrb.input.any_input import AnyInput
|
|
11
11
|
from zrb.task.any_task import AnyTask
|
12
12
|
from zrb.task.base_task import BaseTask
|
13
13
|
from zrb.util.attr import get_str_attr
|
14
|
+
from zrb.util.cli.style import stylize_faint
|
14
15
|
|
15
16
|
TransformConfig = dict[str, str] | Callable[[AnyContext, str], str]
|
16
17
|
|
@@ -46,6 +47,7 @@ class Scaffolder(BaseTask):
|
|
46
47
|
monitor_readiness: bool = False,
|
47
48
|
upstream: list[AnyTask] | AnyTask | None = None,
|
48
49
|
fallback: list[AnyTask] | AnyTask | None = None,
|
50
|
+
successor: list[AnyTask] | AnyTask | None = None,
|
49
51
|
):
|
50
52
|
super().__init__(
|
51
53
|
name=name,
|
@@ -66,6 +68,7 @@ class Scaffolder(BaseTask):
|
|
66
68
|
monitor_readiness=monitor_readiness,
|
67
69
|
upstream=upstream,
|
68
70
|
fallback=fallback,
|
71
|
+
successor=successor,
|
69
72
|
)
|
70
73
|
self._source_path = source_path
|
71
74
|
self._render_source_path = render_source_path
|
@@ -83,13 +86,12 @@ class Scaffolder(BaseTask):
|
|
83
86
|
return get_str_attr(ctx, self._destination_path, "", auto_render=True)
|
84
87
|
|
85
88
|
def _get_content_transformers(self) -> list[AnyContentTransformer]:
|
86
|
-
if callable(self._content_transformers)
|
87
|
-
|
88
|
-
|
89
|
-
]
|
90
|
-
if isinstance(self._content_transformers, dict):
|
89
|
+
if callable(self._content_transformers) or isinstance(
|
90
|
+
self._content_transformers, dict
|
91
|
+
):
|
91
92
|
return [
|
92
93
|
ContentTransformer(
|
94
|
+
name="default-transform",
|
93
95
|
match=".*",
|
94
96
|
transform=self._content_transformers,
|
95
97
|
auto_render=self._render_content_transformers,
|
@@ -109,6 +111,7 @@ class Scaffolder(BaseTask):
|
|
109
111
|
for transformer in transformers:
|
110
112
|
if transformer.match(ctx, file_path):
|
111
113
|
try:
|
114
|
+
ctx.print(stylize_faint(f"{transformer.name}: {file_path}"))
|
112
115
|
transformer.transform_file(ctx, file_path)
|
113
116
|
except UnicodeDecodeError:
|
114
117
|
pass
|
zrb/task/scheduler.py
CHANGED
@@ -39,6 +39,7 @@ class Scheduler(BaseTrigger):
|
|
39
39
|
monitor_readiness: bool = False,
|
40
40
|
upstream: list[AnyTask] | AnyTask | None = None,
|
41
41
|
fallback: list[AnyTask] | AnyTask | None = None,
|
42
|
+
successor: list[AnyTask] | AnyTask | None = None,
|
42
43
|
):
|
43
44
|
super().__init__(
|
44
45
|
name=name,
|
@@ -61,6 +62,7 @@ class Scheduler(BaseTrigger):
|
|
61
62
|
monitor_readiness=monitor_readiness,
|
62
63
|
upstream=upstream,
|
63
64
|
fallback=fallback,
|
65
|
+
successor=successor,
|
64
66
|
)
|
65
67
|
self._cron_pattern = schedule
|
66
68
|
|
zrb/task/tcp_check.py
CHANGED
@@ -28,6 +28,7 @@ class TcpCheck(BaseTask):
|
|
28
28
|
execute_condition: bool | str | Callable[[Context], bool] = True,
|
29
29
|
upstream: list[AnyTask] | AnyTask | None = None,
|
30
30
|
fallback: list[AnyTask] | AnyTask | None = None,
|
31
|
+
successor: list[AnyTask] | AnyTask | None = None,
|
31
32
|
):
|
32
33
|
super().__init__(
|
33
34
|
name=name,
|
@@ -41,6 +42,7 @@ class TcpCheck(BaseTask):
|
|
41
42
|
retries=0,
|
42
43
|
upstream=upstream,
|
43
44
|
fallback=fallback,
|
45
|
+
successor=successor,
|
44
46
|
)
|
45
47
|
self._host = host
|
46
48
|
self._render_host = render_host
|
zrb/task_status/task_status.py
CHANGED
@@ -62,9 +62,10 @@ class TaskStatus:
|
|
62
62
|
self._history.append((TASK_PERMANENTLY_FAILED, datetime.datetime.now()))
|
63
63
|
|
64
64
|
def mark_as_terminated(self):
|
65
|
-
self._is_terminated
|
66
|
-
|
67
|
-
self.
|
65
|
+
if not self._is_terminated:
|
66
|
+
self._is_terminated = True
|
67
|
+
if not (self.is_skipped or self.is_completed or self.is_permanently_failed):
|
68
|
+
self._history.append((TASK_TERMINATED, datetime.datetime.now()))
|
68
69
|
|
69
70
|
@property
|
70
71
|
def is_started(self) -> bool:
|
zrb/util/cmd/command.py
CHANGED
zrb/util/file.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import os
|
2
|
+
import re
|
2
3
|
|
3
4
|
|
4
5
|
def read_file(file_path: str, replace_map: dict[str, str] = {}) -> str:
|
@@ -14,5 +15,10 @@ def write_file(file_path: str, content: str | list[str]):
|
|
14
15
|
content = "\n".join([line for line in content if line is not None])
|
15
16
|
dir_path = os.path.dirname(file_path)
|
16
17
|
os.makedirs(dir_path, exist_ok=True)
|
18
|
+
content = re.sub(r"\n{3,}$", "\n\n", content)
|
19
|
+
# Remove trailing newlines, but keep one if it exists
|
20
|
+
content = content.rstrip("\n")
|
21
|
+
if content.endswith("\n"):
|
22
|
+
content += "\n"
|
17
23
|
with open(file_path, "w") as f:
|
18
|
-
f.write(content
|
24
|
+
f.write(content)
|