dotflow 1.0.0.dev2__py3-none-any.whl → 1.0.0.dev4__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.
- dotflow/__init__.py +1 -1
- dotflow/cli/commands/__init__.py +4 -0
- dotflow/cli/commands/login.py +123 -0
- dotflow/cli/commands/logout.py +15 -0
- dotflow/cli/commands/start.py +2 -2
- dotflow/cli/setup.py +33 -0
- dotflow/core/config_file.py +95 -0
- dotflow/providers/server_default.py +10 -17
- {dotflow-1.0.0.dev2.dist-info → dotflow-1.0.0.dev4.dist-info}/METADATA +1 -1
- {dotflow-1.0.0.dev2.dist-info → dotflow-1.0.0.dev4.dist-info}/RECORD +13 -10
- {dotflow-1.0.0.dev2.dist-info → dotflow-1.0.0.dev4.dist-info}/WHEEL +0 -0
- {dotflow-1.0.0.dev2.dist-info → dotflow-1.0.0.dev4.dist-info}/entry_points.txt +0 -0
- {dotflow-1.0.0.dev2.dist-info → dotflow-1.0.0.dev4.dist-info}/licenses/LICENSE +0 -0
dotflow/__init__.py
CHANGED
dotflow/cli/commands/__init__.py
CHANGED
|
@@ -4,6 +4,8 @@ from dotflow.cli.commands.cloud import CloudGenerateCommand, CloudListCommand
|
|
|
4
4
|
from dotflow.cli.commands.deploy import DeployCommand
|
|
5
5
|
from dotflow.cli.commands.init import InitCommand
|
|
6
6
|
from dotflow.cli.commands.log import LogCommand
|
|
7
|
+
from dotflow.cli.commands.login import LoginCommand
|
|
8
|
+
from dotflow.cli.commands.logout import LogoutCommand
|
|
7
9
|
from dotflow.cli.commands.schedule import ScheduleCommand
|
|
8
10
|
from dotflow.cli.commands.start import StartCommand
|
|
9
11
|
|
|
@@ -13,6 +15,8 @@ __all__ = [
|
|
|
13
15
|
"DeployCommand",
|
|
14
16
|
"InitCommand",
|
|
15
17
|
"LogCommand",
|
|
18
|
+
"LoginCommand",
|
|
19
|
+
"LogoutCommand",
|
|
16
20
|
"ScheduleCommand",
|
|
17
21
|
"StartCommand",
|
|
18
22
|
]
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Command login module."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import time
|
|
7
|
+
import webbrowser
|
|
8
|
+
|
|
9
|
+
from requests import RequestException, post
|
|
10
|
+
from rich import print # type: ignore
|
|
11
|
+
|
|
12
|
+
from dotflow.cli.command import Command
|
|
13
|
+
from dotflow.core.config_file import save_cloud_config
|
|
14
|
+
from dotflow.settings import Settings as settings
|
|
15
|
+
|
|
16
|
+
DEFAULT_BASE_URL = "https://www.host.dotflow.io/api/v1"
|
|
17
|
+
DEVICE_ENDPOINT = "/cli/device"
|
|
18
|
+
TOKEN_ENDPOINT = "/cli/token"
|
|
19
|
+
TIMEOUT = 15
|
|
20
|
+
DEFAULT_INTERVAL = 5
|
|
21
|
+
MAX_POLL_INTERVAL = 60
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class LoginCommand(Command):
|
|
25
|
+
def setup(self):
|
|
26
|
+
token = getattr(self.params, "token", None)
|
|
27
|
+
base_url = self._resolve_base_url()
|
|
28
|
+
|
|
29
|
+
if token:
|
|
30
|
+
save_cloud_config(token=token, base_url=base_url)
|
|
31
|
+
print(settings.INFO_ALERT, "Token saved.")
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
handshake = self._start_device(base_url)
|
|
35
|
+
if handshake is None:
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
print(settings.INFO_ALERT, f"Opening {handshake['verification_uri']}")
|
|
39
|
+
print(settings.INFO_ALERT, f"Code: {handshake['user_code']}")
|
|
40
|
+
|
|
41
|
+
webbrowser.open(handshake["verification_uri"])
|
|
42
|
+
|
|
43
|
+
token = self._poll_token(base_url, handshake)
|
|
44
|
+
|
|
45
|
+
if not token:
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
save_cloud_config(token=token, base_url=base_url)
|
|
49
|
+
print(settings.INFO_ALERT, "Authenticated.")
|
|
50
|
+
|
|
51
|
+
def _resolve_base_url(self) -> str:
|
|
52
|
+
"""Flag or env var wins over the default."""
|
|
53
|
+
explicit = getattr(self.params, "base_url", None) or os.environ.get(
|
|
54
|
+
"SERVER_BASE_URL"
|
|
55
|
+
)
|
|
56
|
+
return explicit.rstrip("/") if explicit else DEFAULT_BASE_URL
|
|
57
|
+
|
|
58
|
+
def _start_device(self, base_url: str) -> dict | None:
|
|
59
|
+
try:
|
|
60
|
+
response = post(
|
|
61
|
+
f"{base_url}{DEVICE_ENDPOINT}",
|
|
62
|
+
timeout=TIMEOUT,
|
|
63
|
+
)
|
|
64
|
+
response.raise_for_status()
|
|
65
|
+
return response.json()
|
|
66
|
+
except RequestException as error:
|
|
67
|
+
print(
|
|
68
|
+
settings.ERROR_ALERT,
|
|
69
|
+
f"Could not reach Dotflow Cloud: {error}",
|
|
70
|
+
)
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
def _poll_token(self, base_url: str, handshake: dict) -> str | None:
|
|
74
|
+
interval = handshake.get("interval") or DEFAULT_INTERVAL
|
|
75
|
+
deadline = time.monotonic() + (handshake.get("expires_in") or 300)
|
|
76
|
+
|
|
77
|
+
while time.monotonic() < deadline:
|
|
78
|
+
try:
|
|
79
|
+
response = post(
|
|
80
|
+
f"{base_url}{TOKEN_ENDPOINT}",
|
|
81
|
+
json={"device_code": handshake["device_code"]},
|
|
82
|
+
timeout=TIMEOUT,
|
|
83
|
+
)
|
|
84
|
+
except RequestException as error:
|
|
85
|
+
print(settings.ERROR_ALERT, f"Network error: {error}")
|
|
86
|
+
return None
|
|
87
|
+
|
|
88
|
+
if response.status_code == 200:
|
|
89
|
+
return response.json().get("api_token")
|
|
90
|
+
|
|
91
|
+
detail = self._detail(response)
|
|
92
|
+
|
|
93
|
+
if (
|
|
94
|
+
response.status_code == 400
|
|
95
|
+
and detail == "authorization_pending"
|
|
96
|
+
):
|
|
97
|
+
time.sleep(interval)
|
|
98
|
+
continue
|
|
99
|
+
|
|
100
|
+
if response.status_code == 400 and detail in (
|
|
101
|
+
"slow_down",
|
|
102
|
+
"slow down",
|
|
103
|
+
):
|
|
104
|
+
interval = min(interval + 5, MAX_POLL_INTERVAL)
|
|
105
|
+
time.sleep(interval)
|
|
106
|
+
continue
|
|
107
|
+
|
|
108
|
+
if response.status_code == 410:
|
|
109
|
+
print(settings.ERROR_ALERT, "Authorization expired.")
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
print(settings.ERROR_ALERT, f"{response.status_code}: {detail}")
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
print(settings.ERROR_ALERT, "Timed out waiting for authorization.")
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def _detail(response) -> str:
|
|
120
|
+
try:
|
|
121
|
+
return str(response.json().get("detail", response.text))
|
|
122
|
+
except ValueError:
|
|
123
|
+
return response.text
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Command logout module."""
|
|
2
|
+
|
|
3
|
+
from rich import print # type: ignore
|
|
4
|
+
|
|
5
|
+
from dotflow.cli.command import Command
|
|
6
|
+
from dotflow.core.config_file import clear_cloud_config
|
|
7
|
+
from dotflow.settings import Settings as settings
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LogoutCommand(Command):
|
|
11
|
+
def setup(self):
|
|
12
|
+
if clear_cloud_config():
|
|
13
|
+
print(settings.INFO_ALERT, "Signed out.")
|
|
14
|
+
else:
|
|
15
|
+
print(settings.WARNING_ALERT, "No saved credentials.")
|
dotflow/cli/commands/start.py
CHANGED
|
@@ -35,7 +35,7 @@ class StartCommand(Command):
|
|
|
35
35
|
initial_context=self.params.initial_context,
|
|
36
36
|
)
|
|
37
37
|
|
|
38
|
-
workflow.start(mode=self.params.mode)
|
|
38
|
+
workflow.start(mode=self.params.mode, resume=self.params.resume)
|
|
39
39
|
|
|
40
40
|
def _start_from_factory(self):
|
|
41
41
|
step_only_flags = {
|
|
@@ -56,7 +56,7 @@ class StartCommand(Command):
|
|
|
56
56
|
if not isinstance(result, DotFlow):
|
|
57
57
|
raise InvalidWorkflowFactory(factory=self.params.workflow)
|
|
58
58
|
|
|
59
|
-
result.start(mode=self.params.mode)
|
|
59
|
+
result.start(mode=self.params.mode, resume=self.params.resume)
|
|
60
60
|
|
|
61
61
|
def _new_workflow(self):
|
|
62
62
|
storage = self._build_storage()
|
dotflow/cli/setup.py
CHANGED
|
@@ -9,6 +9,8 @@ from dotflow.cli.commands import (
|
|
|
9
9
|
DeployCommand,
|
|
10
10
|
InitCommand,
|
|
11
11
|
LogCommand,
|
|
12
|
+
LoginCommand,
|
|
13
|
+
LogoutCommand,
|
|
12
14
|
ScheduleCommand,
|
|
13
15
|
StartCommand,
|
|
14
16
|
)
|
|
@@ -42,12 +44,37 @@ class Command:
|
|
|
42
44
|
|
|
43
45
|
self.setup_init()
|
|
44
46
|
self.setup_logs()
|
|
47
|
+
self.setup_login()
|
|
48
|
+
self.setup_logout()
|
|
45
49
|
self.setup_start()
|
|
46
50
|
self.setup_schedule()
|
|
47
51
|
self.setup_cloud()
|
|
48
52
|
self.setup_deploy()
|
|
49
53
|
self.command()
|
|
50
54
|
|
|
55
|
+
def setup_login(self):
|
|
56
|
+
cmd = self.subparsers.add_parser(
|
|
57
|
+
"login", help="Authenticate the CLI via browser"
|
|
58
|
+
)
|
|
59
|
+
cmd_group = cmd.add_argument_group("Usage: dotflow login [OPTIONS]")
|
|
60
|
+
cmd_group.add_argument(
|
|
61
|
+
"--base-url",
|
|
62
|
+
default=None,
|
|
63
|
+
help="Override the Dotflow Cloud API base URL",
|
|
64
|
+
)
|
|
65
|
+
cmd_group.add_argument(
|
|
66
|
+
"--token",
|
|
67
|
+
default=None,
|
|
68
|
+
help="Skip the browser flow and save a pre-obtained API token",
|
|
69
|
+
)
|
|
70
|
+
cmd.set_defaults(exec=LoginCommand)
|
|
71
|
+
|
|
72
|
+
def setup_logout(self):
|
|
73
|
+
cmd = self.subparsers.add_parser(
|
|
74
|
+
"logout", help="Remove saved CLI credentials"
|
|
75
|
+
)
|
|
76
|
+
cmd.set_defaults(exec=LogoutCommand)
|
|
77
|
+
|
|
51
78
|
def setup_init(self):
|
|
52
79
|
self.cmd_init = self.subparsers.add_parser(
|
|
53
80
|
"init", help="Scaffold a new dotflow project"
|
|
@@ -93,6 +120,12 @@ class Command:
|
|
|
93
120
|
TypeExecution.PARALLEL,
|
|
94
121
|
],
|
|
95
122
|
)
|
|
123
|
+
self.cmd_start.add_argument(
|
|
124
|
+
"--resume",
|
|
125
|
+
action="store_true",
|
|
126
|
+
default=False,
|
|
127
|
+
help="Enable checkpoint-based resume",
|
|
128
|
+
)
|
|
96
129
|
|
|
97
130
|
cmd_start_parser.set_defaults(exec=StartCommand)
|
|
98
131
|
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Persistent CLI config stored at ``~/.dotflow/config.json``."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import contextlib
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
CONFIG_DIR_NAME = ".dotflow"
|
|
11
|
+
CONFIG_FILE_NAME = "config.json"
|
|
12
|
+
CLOUD_SECTION = "cloud"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def config_path() -> Path:
|
|
16
|
+
"""Return the absolute path of the CLI config file."""
|
|
17
|
+
return Path.home() / CONFIG_DIR_NAME / CONFIG_FILE_NAME
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def load_cloud_config() -> dict[str, str]:
|
|
21
|
+
"""Read the ``cloud`` section from the config file. ``{}`` when absent."""
|
|
22
|
+
path = config_path()
|
|
23
|
+
|
|
24
|
+
if not path.exists():
|
|
25
|
+
return {}
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
raw = path.read_text(encoding="utf-8")
|
|
29
|
+
except OSError:
|
|
30
|
+
return {}
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
data = json.loads(raw)
|
|
34
|
+
except json.JSONDecodeError:
|
|
35
|
+
return {}
|
|
36
|
+
|
|
37
|
+
section = data.get(CLOUD_SECTION) if isinstance(data, dict) else None
|
|
38
|
+
if not isinstance(section, dict):
|
|
39
|
+
return {}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
key: str(value)
|
|
43
|
+
for key, value in section.items()
|
|
44
|
+
if isinstance(value, str)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def save_cloud_config(token: str, base_url: str) -> Path:
|
|
49
|
+
"""Persist ``cloud`` with the given token/base_url. Returns the file path."""
|
|
50
|
+
path = config_path()
|
|
51
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
52
|
+
|
|
53
|
+
payload = {
|
|
54
|
+
CLOUD_SECTION: {
|
|
55
|
+
"base_url": base_url,
|
|
56
|
+
"token": token,
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
content = json.dumps(payload, indent=2) + "\n"
|
|
60
|
+
|
|
61
|
+
fd = os.open(
|
|
62
|
+
str(path),
|
|
63
|
+
os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
|
|
64
|
+
0o600,
|
|
65
|
+
)
|
|
66
|
+
with contextlib.suppress(OSError):
|
|
67
|
+
os.fchmod(fd, 0o600)
|
|
68
|
+
with os.fdopen(fd, "w", encoding="utf-8") as fh:
|
|
69
|
+
fh.write(content)
|
|
70
|
+
|
|
71
|
+
return path
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def clear_cloud_config() -> bool:
|
|
75
|
+
"""Remove the config file. Returns True when something was deleted."""
|
|
76
|
+
path = config_path()
|
|
77
|
+
|
|
78
|
+
if not path.exists():
|
|
79
|
+
return False
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
path.unlink()
|
|
83
|
+
return True
|
|
84
|
+
except OSError:
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def resolve(key: str, env_var: str) -> str | None:
|
|
89
|
+
"""Resolve a setting with env > file precedence. ``None`` when absent."""
|
|
90
|
+
env_value = os.environ.get(env_var)
|
|
91
|
+
|
|
92
|
+
if env_value:
|
|
93
|
+
return env_value
|
|
94
|
+
|
|
95
|
+
return load_cloud_config().get(key) or None
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""ServerDefault
|
|
1
|
+
"""ServerDefault - managed HTTP server provider."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -24,24 +24,19 @@ def managed(method):
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class ServerDefault(Server):
|
|
27
|
-
"""Default Server provider with auto-detected managed mode.
|
|
28
|
-
|
|
29
|
-
When ``SERVER_BASE_URL`` and ``SERVER_USER_TOKEN`` env vars are set,
|
|
30
|
-
sends workflow and task events to the remote API. Otherwise, all
|
|
31
|
-
methods are no-ops.
|
|
32
|
-
"""
|
|
27
|
+
"""Default Server provider with auto-detected managed mode."""
|
|
33
28
|
|
|
34
29
|
MAX_RESULT_SIZE = 5_000_000
|
|
35
30
|
TIMEOUT = 15.0
|
|
36
31
|
|
|
37
|
-
ENDPOINT_WORKFLOWS = "/workflows"
|
|
38
|
-
ENDPOINT_WORKFLOW = "/workflows/{workflow_id}"
|
|
39
|
-
ENDPOINT_TASKS = "/workflows/{workflow_id}/tasks"
|
|
40
|
-
ENDPOINT_TASK = "/workflows/{workflow_id}/tasks/{task_id}"
|
|
32
|
+
ENDPOINT_WORKFLOWS = "/cli/workflows"
|
|
33
|
+
ENDPOINT_WORKFLOW = "/cli/workflows/{workflow_id}"
|
|
34
|
+
ENDPOINT_TASKS = "/cli/workflows/{workflow_id}/tasks"
|
|
35
|
+
ENDPOINT_TASK = "/cli/workflows/{workflow_id}/tasks/{task_id}"
|
|
41
36
|
|
|
42
37
|
def __init__(self) -> None:
|
|
43
|
-
base_url = os.
|
|
44
|
-
user_token = os.
|
|
38
|
+
base_url = os.environ.get("SERVER_BASE_URL") or None
|
|
39
|
+
user_token = os.environ.get("SERVER_USER_TOKEN") or None
|
|
45
40
|
self._managed = bool(base_url and user_token)
|
|
46
41
|
|
|
47
42
|
self._base_url = base_url.rstrip("/") if base_url else None
|
|
@@ -56,25 +51,23 @@ class ServerDefault(Server):
|
|
|
56
51
|
|
|
57
52
|
def _post(self, url: str, json: dict) -> None:
|
|
58
53
|
try:
|
|
59
|
-
|
|
54
|
+
post(
|
|
60
55
|
url,
|
|
61
56
|
json=json,
|
|
62
57
|
headers=self._headers,
|
|
63
58
|
timeout=self.TIMEOUT,
|
|
64
59
|
)
|
|
65
|
-
logger.info("POST %s [%s]", url, response.status_code)
|
|
66
60
|
except RequestException as error:
|
|
67
61
|
logger.error("POST %s failed: %s", url, error)
|
|
68
62
|
|
|
69
63
|
def _patch(self, url: str, json: dict) -> None:
|
|
70
64
|
try:
|
|
71
|
-
|
|
65
|
+
patch(
|
|
72
66
|
url,
|
|
73
67
|
json=json,
|
|
74
68
|
headers=self._headers,
|
|
75
69
|
timeout=self.TIMEOUT,
|
|
76
70
|
)
|
|
77
|
-
logger.info("PATCH %s [%s]", url, response.status_code)
|
|
78
71
|
except RequestException as error:
|
|
79
72
|
logger.error("PATCH %s failed: %s", url, error)
|
|
80
73
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dotflow
|
|
3
|
-
Version: 1.0.0.
|
|
3
|
+
Version: 1.0.0.dev4
|
|
4
4
|
Summary: 🎲 Dotflow turns an idea into flow! Lightweight Python library for execution pipelines with retry, parallel, cron and async support.
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
dotflow/__init__.py,sha256=
|
|
1
|
+
dotflow/__init__.py,sha256=uorc8dzhoW2e0vy6-4AgHvGOzHXG1Y0tGipyWFod15Y,350
|
|
2
2
|
dotflow/abc/__init__.py,sha256=UIk84jCJYoHAk4In_eVXAaFAnNE63lI3dVP5qunyBJs,32
|
|
3
3
|
dotflow/abc/file.py,sha256=QEDIS-AXaW3GK5q5ckhNdoC5A3p8oOFE7VyNGSvx540,296
|
|
4
4
|
dotflow/abc/flow.py,sha256=j6m9u13UXgBCIhgrUwzvBBYHTDul_DfERD4DWA1BQBw,1436
|
|
@@ -13,15 +13,17 @@ dotflow/abc/tcp.py,sha256=v4VzXugCpvtCP8jmHjjBv1sFko7je6c_uh0TCJ4dOXU,577
|
|
|
13
13
|
dotflow/abc/tracer.py,sha256=S0fKzVydW6m39Wmam6MHcMKXTtzI01WctDjvwEIS0SE,633
|
|
14
14
|
dotflow/cli/__init__.py,sha256=1NhA5RRAaAfhj3LdBgtC2eZ7WPZlmN0f-Kz-biUkUXE,27
|
|
15
15
|
dotflow/cli/command.py,sha256=PRvZSB3VcXROsOHWasBANq3Q6-3qLY7LqJ9ecOY0C0g,236
|
|
16
|
-
dotflow/cli/commands/__init__.py,sha256=
|
|
16
|
+
dotflow/cli/commands/__init__.py,sha256=7GjVzmVDSK1KGixZru0DQo-_aCHfDL59k17TgNfuA4M,688
|
|
17
17
|
dotflow/cli/commands/cloud.py,sha256=Y4zDw6u6op3AY7z9yMG7sCF34qT6Gj3B_RXXuHtYoFg,5793
|
|
18
18
|
dotflow/cli/commands/deploy.py,sha256=qUeZx-C00OfOEMURNZ4LMRI4qYOwwDS_ajOGtLa_WbU,5849
|
|
19
19
|
dotflow/cli/commands/init.py,sha256=VySDg1gNx_8jH0vfhc15BhBJR3Yckw91v26ijyGz5Pw,387
|
|
20
20
|
dotflow/cli/commands/log.py,sha256=AJmDQM1ulbQg7_wZRsx3xac_7_6WlP8eA4pBWhpNBTo,590
|
|
21
|
+
dotflow/cli/commands/login.py,sha256=z9nmjLLjtmdX2fiwp9O3N8OuBNEeh8M1mRQs0ku1jOw,3839
|
|
22
|
+
dotflow/cli/commands/logout.py,sha256=d8F7v6KKiqXsTpsK4CspaH5qeDLyIi7sgRXhJNfN2kY,437
|
|
21
23
|
dotflow/cli/commands/schedule.py,sha256=C9wvgSowV4xgQqrx6pjNZk5-709uNDfsA7xGBjjbZYA,1442
|
|
22
|
-
dotflow/cli/commands/start.py,sha256=
|
|
24
|
+
dotflow/cli/commands/start.py,sha256=ruF_FEMMgB4TGkOjbCpWy6koA_8HtqLIwU-d6PuQ_bA,2479
|
|
23
25
|
dotflow/cli/commands/storage.py,sha256=b3CMBSFGEqYxaI9gwiO90MIirnW82CcM3GUf4XJGVYs,1549
|
|
24
|
-
dotflow/cli/setup.py,sha256=
|
|
26
|
+
dotflow/cli/setup.py,sha256=zECGX3QBQbQAxx8NsYAHVhz0YjQtc0GlKxDSDULxyjw,9135
|
|
25
27
|
dotflow/cli/validators/__init__.py,sha256=JKD-C4igDghgLjU2eBbpHkThUapoJ2mJRtC_YkeEvHg,121
|
|
26
28
|
dotflow/cli/validators/start.py,sha256=ziQQWpLds6K_XnkiZt3m8bSs3KPdDSQzIuEiea5slks,466
|
|
27
29
|
dotflow/cloud/__init__.py,sha256=N8XuL0M9P2vbP3WssHI85J8TSofVHo5llOI8EXp9RU0,21
|
|
@@ -64,6 +66,7 @@ dotflow/cloud/github/deployers/actions.py,sha256=0P752J6R0aMuhCI8cKQnoJjff61iewY
|
|
|
64
66
|
dotflow/core/__init__.py,sha256=baoenc4kd9OQjCrnmOKRm9JRinEjd5xb7luCeyQ-npY,28
|
|
65
67
|
dotflow/core/action.py,sha256=TpNHX0euI1cRHwzUCElgE_JqiBUx5BFKC3Tid1AnDys,5715
|
|
66
68
|
dotflow/core/config.py,sha256=GBJKGrYejrkBr5GJAk2JvVAF1QRow1hBUAUy3FJ1Opk,3252
|
|
69
|
+
dotflow/core/config_file.py,sha256=Y2_RZ2IxW8RjnsU_aOCferljV2X7DgW91RqPKinNsKM,2235
|
|
67
70
|
dotflow/core/context.py,sha256=X72lG-ISBHIhS03X_FalG0THdgcLpiWrJEsyH2u-g3Q,2893
|
|
68
71
|
dotflow/core/decorators/__init__.py,sha256=xPQMuZWV8TnIAH8uTF-Be9NoG46K7OmfJx_7GSWO_bc,101
|
|
69
72
|
dotflow/core/decorators/time.py,sha256=46mI6Q8EZYkxU5DRnPJ5B8KgDBdR1bKivEm0u4pqwAg,300
|
|
@@ -96,7 +99,7 @@ dotflow/providers/notify_discord.py,sha256=9cOt3YwJzuZzpNQlMLdc3sfJ5hfFRBBAmpNoU
|
|
|
96
99
|
dotflow/providers/notify_telegram.py,sha256=xiyeqVSo_xQg3FR3_Q6Dnx2Qk8Sih2J7tkIVxkFSefk,3230
|
|
97
100
|
dotflow/providers/scheduler_cron.py,sha256=wRXI5g0fDrYkBgD5zAMa5T8xxjU9v1SjDNpmsQD8nwA,8245
|
|
98
101
|
dotflow/providers/scheduler_default.py,sha256=mkgMz5D6mROTDDY5juGXV4IgEDRPM0yW8_NJWDVfRTQ,258
|
|
99
|
-
dotflow/providers/server_default.py,sha256=
|
|
102
|
+
dotflow/providers/server_default.py,sha256=KniaNtNH8kiQ4coD3HC4P5bxSIiloMT9YtlenNnd4Ik,3120
|
|
100
103
|
dotflow/providers/storage_default.py,sha256=ijE6cN0TlmTn8J5TiNvq_xakoK3JmciqI7qJWxesEBM,568
|
|
101
104
|
dotflow/providers/storage_file.py,sha256=N4BPiDWWDOUbh5suzWvYzX6ZUtjhrfdZgSqwBPDW__I,2154
|
|
102
105
|
dotflow/providers/storage_gcs.py,sha256=LgkS0zjlPElbvPhk7-uVKbNTnVn2OTtk8h5XltWIOH0,2484
|
|
@@ -110,8 +113,8 @@ dotflow/utils/__init__.py,sha256=AXiUm5p-FVG9SBWPxdG6jV0ft49EK6c40ME4aznPWQc,366
|
|
|
110
113
|
dotflow/utils/basic_functions.py,sha256=S-maghYauG5QkMtHdm7qNcxBkKkSoE4akHSiI178Bwg,131
|
|
111
114
|
dotflow/utils/error_handler.py,sha256=I8DY2AKR-WxKl8k7aUJPExS6wlzKVPy_u42ZJ9gYyts,272
|
|
112
115
|
dotflow/utils/tools.py,sha256=RtC0D1SnaNCB02cT-l0Dw8Wl6uDSQSABoZH2kdD1PJQ,787
|
|
113
|
-
dotflow-1.0.0.
|
|
114
|
-
dotflow-1.0.0.
|
|
115
|
-
dotflow-1.0.0.
|
|
116
|
-
dotflow-1.0.0.
|
|
117
|
-
dotflow-1.0.0.
|
|
116
|
+
dotflow-1.0.0.dev4.dist-info/METADATA,sha256=5-HwzHn6e-WQTasE6ce9dwwQ_9C9QGnE8lQqSyhmXTI,40730
|
|
117
|
+
dotflow-1.0.0.dev4.dist-info/WHEEL,sha256=Vz2fHgx6HFtSwhs8KvkHLqH5Ea4w1_rner5uNVGCeIE,88
|
|
118
|
+
dotflow-1.0.0.dev4.dist-info/entry_points.txt,sha256=3AW0pYKZpaMW6WZmN3t71X0FuwxQdivmQwe47_6yBp4,45
|
|
119
|
+
dotflow-1.0.0.dev4.dist-info/licenses/LICENSE,sha256=0h5VY_8dcAiTIGt0weGPV6cjxdPGB37Pjusxm_WAiPU,10766
|
|
120
|
+
dotflow-1.0.0.dev4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|