zsynctech-studio-sdk 0.1.0__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.
- zsynctech_studio_sdk/__init__.py +21 -0
- zsynctech_studio_sdk/client.py +39 -0
- zsynctech_studio_sdk/enums/__init__.py +10 -0
- zsynctech_studio_sdk/enums/execution.py +11 -0
- zsynctech_studio_sdk/enums/step.py +8 -0
- zsynctech_studio_sdk/enums/task.py +9 -0
- zsynctech_studio_sdk/execution.py +156 -0
- zsynctech_studio_sdk/models/__init__.py +12 -0
- zsynctech_studio_sdk/models/base.py +47 -0
- zsynctech_studio_sdk/models/config.py +32 -0
- zsynctech_studio_sdk/models/execution.py +18 -0
- zsynctech_studio_sdk/models/step.py +28 -0
- zsynctech_studio_sdk/models/task.py +29 -0
- zsynctech_studio_sdk/start.py +88 -0
- zsynctech_studio_sdk/step.py +90 -0
- zsynctech_studio_sdk/task.py +103 -0
- zsynctech_studio_sdk/utils.py +21 -0
- zsynctech_studio_sdk-0.1.0.dist-info/METADATA +289 -0
- zsynctech_studio_sdk-0.1.0.dist-info/RECORD +21 -0
- zsynctech_studio_sdk-0.1.0.dist-info/WHEEL +4 -0
- zsynctech_studio_sdk-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from zsynctech_studio_sdk.client import set_credentials
|
|
2
|
+
from zsynctech_studio_sdk.models.config import Config
|
|
3
|
+
from zsynctech_studio_sdk.start import StartService
|
|
4
|
+
from zsynctech_studio_sdk.execution import Execution
|
|
5
|
+
from zsynctech_studio_sdk.task import Task
|
|
6
|
+
from zsynctech_studio_sdk.step import Step
|
|
7
|
+
import tomllib
|
|
8
|
+
|
|
9
|
+
with open("pyproject.toml", "rb") as f:
|
|
10
|
+
config = tomllib.load(f)
|
|
11
|
+
|
|
12
|
+
__version__ = config.get("project").get("version")
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"set_credentials",
|
|
16
|
+
"StartService",
|
|
17
|
+
"Execution",
|
|
18
|
+
"Task",
|
|
19
|
+
"Step",
|
|
20
|
+
"Config"
|
|
21
|
+
]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
|
|
3
|
+
_client = None
|
|
4
|
+
_secret_key = None
|
|
5
|
+
_instance_id = None
|
|
6
|
+
_server = None
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def set_credentials(secret_key: str, instance_id: str, server: str):
|
|
10
|
+
global _client, _secret_key, _server, _instance_id
|
|
11
|
+
_secret_key = secret_key
|
|
12
|
+
_instance_id = instance_id
|
|
13
|
+
_server = str(server).rstrip("/")
|
|
14
|
+
_client = httpx.Client(
|
|
15
|
+
base_url=f"{_server}/automation-gateway/",
|
|
16
|
+
headers={
|
|
17
|
+
"Authorization": f"Bearer {_secret_key}::{_instance_id}"
|
|
18
|
+
}
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def request(method: str, endpoint: str, **kwargs) -> httpx.Response:
|
|
23
|
+
if _client is None:
|
|
24
|
+
raise RuntimeError("Credentials not set. Call set_credentials() first.")
|
|
25
|
+
response = _client.request(method, endpoint, **kwargs)
|
|
26
|
+
response.raise_for_status()
|
|
27
|
+
return response
|
|
28
|
+
|
|
29
|
+
def get(endpoint: str, params: dict = None) -> httpx.Response:
|
|
30
|
+
return request("GET", endpoint, params=params)
|
|
31
|
+
|
|
32
|
+
def post(endpoint: str, json: dict = None) -> httpx.Response:
|
|
33
|
+
return request("POST", endpoint, json=json)
|
|
34
|
+
|
|
35
|
+
def put(endpoint: str, json: dict = None) -> httpx.Response:
|
|
36
|
+
return request("PUT", endpoint, json=json)
|
|
37
|
+
|
|
38
|
+
def delete(endpoint: str) -> httpx.Response:
|
|
39
|
+
return request("DELETE", endpoint)
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
from zsynctech_studio_sdk.models import ExecutionModel
|
|
2
|
+
from zsynctech_studio_sdk.enums import ExecutionStatus
|
|
3
|
+
from zsynctech_studio_sdk.utils import get_utc_now
|
|
4
|
+
from zsynctech_studio_sdk import client
|
|
5
|
+
from typing import Optional, Any
|
|
6
|
+
|
|
7
|
+
EXECUTION_STATUS_COMPLETED = [
|
|
8
|
+
ExecutionStatus.ERROR,
|
|
9
|
+
ExecutionStatus.FINISHED,
|
|
10
|
+
ExecutionStatus.OUT_OF_OPERATING_HOURS,
|
|
11
|
+
ExecutionStatus.INTERRUPTED,
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Execution:
|
|
16
|
+
def __init__(self, execution_id: str):
|
|
17
|
+
self._current_execution = ExecutionModel(
|
|
18
|
+
id=execution_id
|
|
19
|
+
)
|
|
20
|
+
self._resource_path = "executions"
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def execution_id(self):
|
|
24
|
+
return self._current_execution.id
|
|
25
|
+
|
|
26
|
+
def _update(
|
|
27
|
+
self,
|
|
28
|
+
status: Optional[ExecutionStatus] = None,
|
|
29
|
+
observation: Optional[str] = None,
|
|
30
|
+
total_task_count: Optional[int] = None,
|
|
31
|
+
current_task_count: Optional[int] = None,
|
|
32
|
+
) -> dict:
|
|
33
|
+
|
|
34
|
+
if self._current_execution.status in EXECUTION_STATUS_COMPLETED:
|
|
35
|
+
return self._current_execution.model_dump()
|
|
36
|
+
|
|
37
|
+
if status in EXECUTION_STATUS_COMPLETED:
|
|
38
|
+
self._current_execution.endDate = get_utc_now()
|
|
39
|
+
|
|
40
|
+
if status is not None:
|
|
41
|
+
self._current_execution.status = status
|
|
42
|
+
|
|
43
|
+
if observation is not None:
|
|
44
|
+
self._current_execution.observation = observation
|
|
45
|
+
|
|
46
|
+
if total_task_count is not None:
|
|
47
|
+
self._current_execution.totalTaskCount = total_task_count
|
|
48
|
+
|
|
49
|
+
if current_task_count is not None:
|
|
50
|
+
self._current_execution.currentTaskCount = current_task_count
|
|
51
|
+
|
|
52
|
+
client.post(
|
|
53
|
+
endpoint=self._resource_path,
|
|
54
|
+
json=self._current_execution.model_dump()
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return self._current_execution.model_dump()
|
|
58
|
+
|
|
59
|
+
def set_total_task_count(self, total_task_count: int) -> dict[str, Any]:
|
|
60
|
+
"""Update the total number of tasks to be processed
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
total_task_count (int): total number of tasks to be processed.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
dict: Dictionary containing the information of the current execution
|
|
67
|
+
"""
|
|
68
|
+
return self._update(total_task_count=total_task_count)
|
|
69
|
+
|
|
70
|
+
def update_current_task_count(self, current_task_count: int) -> dict[str, Any]:
|
|
71
|
+
"""Update the number of tasks currently processed
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
current_task_count (int): Number of tasks processed.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
dict: Dictionary containing the information of the current execution
|
|
78
|
+
"""
|
|
79
|
+
return self._update(current_task_count=current_task_count)
|
|
80
|
+
|
|
81
|
+
def update_observation(self, observation: str) -> dict[str, Any]:
|
|
82
|
+
"""Updates the execution observation text
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
observation (str): Execution observation text.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
dict: Dictionary containing the information of the current execution
|
|
89
|
+
"""
|
|
90
|
+
return self._update(observation=observation)
|
|
91
|
+
|
|
92
|
+
def start(self, observation: Optional[str] = None) -> dict:
|
|
93
|
+
"""Updates the execution status to running
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
observation (Optional[str], optional): Execution observation text. Defaults to None.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
dict: Dictionary containing the information of the current execution
|
|
100
|
+
"""
|
|
101
|
+
return self._update(ExecutionStatus.RUNNING, observation)
|
|
102
|
+
|
|
103
|
+
def error(self, observation: Optional[str] = None) -> dict:
|
|
104
|
+
"""Updates the execution status to error
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
observation (Optional[str], optional): Execution observation text. Defaults to None.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
dict: Dictionary containing the information of the current execution
|
|
111
|
+
"""
|
|
112
|
+
return self._update(ExecutionStatus.ERROR, observation=observation)
|
|
113
|
+
|
|
114
|
+
def waiting(self, observation: Optional[str] = None) -> dict:
|
|
115
|
+
"""Updates the execution status to waiting
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
observation (Optional[str], optional): Execution observation text. Defaults to None.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
dict: Dictionary containing the information of the current execution
|
|
122
|
+
"""
|
|
123
|
+
return self._update(ExecutionStatus.WAITING, observation=observation)
|
|
124
|
+
|
|
125
|
+
def out_of_operating_hours(self, observation: Optional[str] = None) -> dict:
|
|
126
|
+
"""Updates the execution status to out_of_operating_hours
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
observation (Optional[str], optional): Execution observation text. Defaults to None.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
dict: Dictionary containing the information of the current execution
|
|
133
|
+
"""
|
|
134
|
+
return self._update(ExecutionStatus.OUT_OF_OPERATING_HOURS, observation=observation)
|
|
135
|
+
|
|
136
|
+
def finished(self, observation: Optional[str] = None) -> dict:
|
|
137
|
+
"""Updates the execution status to finished
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
observation (Optional[str], optional): Execution observation text. Defaults to None.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
dict: Dictionary containing the information of the current execution
|
|
144
|
+
"""
|
|
145
|
+
return self._update(ExecutionStatus.FINISHED, observation=observation)
|
|
146
|
+
|
|
147
|
+
def interrupted(self, observation: Optional[str] = None) -> dict:
|
|
148
|
+
"""Updates the execution status to finished
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
observation (Optional[str], optional): Execution observation text. Defaults to None.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
dict: Dictionary containing the information of the current execution
|
|
155
|
+
"""
|
|
156
|
+
return self._update(ExecutionStatus.INTERRUPTED, observation=observation)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from zsynctech_studio_sdk.enums.execution import ExecutionStatus
|
|
2
|
+
from pydantic import BaseModel, Field, field_validator
|
|
3
|
+
from zsynctech_studio_sdk.enums.step import StepStatus
|
|
4
|
+
from zsynctech_studio_sdk.enums.task import TaskStatus
|
|
5
|
+
from uuid_extensions.uuid7 import uuid7
|
|
6
|
+
from typing import Optional, Union
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
import re
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BaseEntity(BaseModel):
|
|
12
|
+
id: str = Field(
|
|
13
|
+
default_factory=lambda: str(uuid7()),
|
|
14
|
+
min_length=1,
|
|
15
|
+
description="ID único da execução"
|
|
16
|
+
)
|
|
17
|
+
observation: Optional[str] = None
|
|
18
|
+
status: Optional[Union[ExecutionStatus, StepStatus, TaskStatus]] = None
|
|
19
|
+
endDate: Optional[str] = None
|
|
20
|
+
|
|
21
|
+
@field_validator('id')
|
|
22
|
+
@classmethod
|
|
23
|
+
def validate_id_format(cls, v):
|
|
24
|
+
if not re.match(r'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$', v):
|
|
25
|
+
raise ValueError('ID deve ser um UUID válido')
|
|
26
|
+
version = int(v[14], 16)
|
|
27
|
+
if version != 7:
|
|
28
|
+
raise ValueError('ID deve ser um UUID7 válido')
|
|
29
|
+
return v
|
|
30
|
+
|
|
31
|
+
@field_validator('endDate')
|
|
32
|
+
@classmethod
|
|
33
|
+
def validate_end_date_format(cls, v):
|
|
34
|
+
if v is None:
|
|
35
|
+
return v
|
|
36
|
+
pattern = r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$'
|
|
37
|
+
if not re.match(pattern, v):
|
|
38
|
+
raise ValueError('endDate deve estar no formato ISO 8601 com Z')
|
|
39
|
+
try:
|
|
40
|
+
datetime.fromisoformat(v.replace('Z', '+00:00'))
|
|
41
|
+
except ValueError:
|
|
42
|
+
raise ValueError('endDate deve ser uma data válida')
|
|
43
|
+
return v
|
|
44
|
+
|
|
45
|
+
class Config:
|
|
46
|
+
extra = "forbid"
|
|
47
|
+
validate_assignment = True
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from typing import Optional, List
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class InputOutputTypes(StrEnum):
|
|
7
|
+
FTP = 'FTP'
|
|
8
|
+
API = 'API'
|
|
9
|
+
FILA = 'FILA'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Credential(BaseModel):
|
|
13
|
+
key: str
|
|
14
|
+
value: str
|
|
15
|
+
encrypted: bool
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Config(BaseModel):
|
|
19
|
+
instanceId: str
|
|
20
|
+
executionId: str
|
|
21
|
+
automationName: Optional[str] = "System"
|
|
22
|
+
clientId: Optional[str] = None
|
|
23
|
+
userId: Optional[str] = "System"
|
|
24
|
+
outputPath: Optional[str] = None
|
|
25
|
+
inputPath: Optional[str] = None
|
|
26
|
+
inputMetaData: Optional[dict] = None
|
|
27
|
+
inputType: Optional[InputOutputTypes] = InputOutputTypes.FTP
|
|
28
|
+
outputType: Optional[InputOutputTypes] = InputOutputTypes.FTP
|
|
29
|
+
outputMetaData: Optional[dict] = None
|
|
30
|
+
keepAlive: Optional[bool] = False
|
|
31
|
+
keepAliveInterval: Optional[int] = 30
|
|
32
|
+
credentials: Optional[List[Credential]] = None
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from zsynctech_studio_sdk.enums.execution import ExecutionStatus
|
|
2
|
+
from zsynctech_studio_sdk.models.base import BaseEntity
|
|
3
|
+
from pydantic import model_validator
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ExecutionModel(BaseEntity):
|
|
7
|
+
totalTaskCount: int = 0
|
|
8
|
+
currentTaskCount: int = 0
|
|
9
|
+
status: ExecutionStatus = ExecutionStatus.WAITING
|
|
10
|
+
|
|
11
|
+
@model_validator(mode='after')
|
|
12
|
+
def validate_business_rules(self):
|
|
13
|
+
current = self.currentTaskCount or 0
|
|
14
|
+
total = self.totalTaskCount or 0
|
|
15
|
+
if current > total:
|
|
16
|
+
raise ValueError('currentTaskCount não pode ser maior que totalTaskCount')
|
|
17
|
+
|
|
18
|
+
return self
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from zsynctech_studio_sdk.models.base import BaseEntity
|
|
2
|
+
from zsynctech_studio_sdk.enums.step import StepStatus
|
|
3
|
+
from pydantic import field_validator
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Optional
|
|
6
|
+
import re
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class StepModel(BaseEntity):
|
|
10
|
+
status: StepStatus = StepStatus.UNPROCESSED
|
|
11
|
+
taskId: Optional[str] = None
|
|
12
|
+
stepCode: Optional[str] = None
|
|
13
|
+
startDate: Optional[str] = None
|
|
14
|
+
automationOnClientId: str
|
|
15
|
+
|
|
16
|
+
@field_validator('startDate')
|
|
17
|
+
@classmethod
|
|
18
|
+
def validate_end_date_format(cls, v):
|
|
19
|
+
if v is None:
|
|
20
|
+
return v
|
|
21
|
+
pattern = r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$'
|
|
22
|
+
if not re.match(pattern, v):
|
|
23
|
+
raise ValueError('endDate deve estar no formato ISO 8601 com Z')
|
|
24
|
+
try:
|
|
25
|
+
datetime.fromisoformat(v.replace('Z', '+00:00'))
|
|
26
|
+
except ValueError:
|
|
27
|
+
raise ValueError('endDate deve ser uma data válida')
|
|
28
|
+
return v
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from zsynctech_studio_sdk.models.base import BaseEntity
|
|
2
|
+
from zsynctech_studio_sdk.enums.task import TaskStatus
|
|
3
|
+
from pydantic import field_validator
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Optional
|
|
6
|
+
import re
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TaskModel(BaseEntity):
|
|
10
|
+
status: TaskStatus = TaskStatus.UNPROCESSED
|
|
11
|
+
description: Optional[str] = None
|
|
12
|
+
jsonData: Optional[dict] = {}
|
|
13
|
+
code: Optional[str] = None
|
|
14
|
+
executionId: Optional[str] = None
|
|
15
|
+
startDate: Optional[str] = None
|
|
16
|
+
|
|
17
|
+
@field_validator('startDate')
|
|
18
|
+
@classmethod
|
|
19
|
+
def validate_end_date_format(cls, v):
|
|
20
|
+
if v is None:
|
|
21
|
+
return v
|
|
22
|
+
pattern = r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$'
|
|
23
|
+
if not re.match(pattern, v):
|
|
24
|
+
raise ValueError('endDate deve estar no formato ISO 8601 com Z')
|
|
25
|
+
try:
|
|
26
|
+
datetime.fromisoformat(v.replace('Z', '+00:00'))
|
|
27
|
+
except ValueError:
|
|
28
|
+
raise ValueError('endDate deve ser uma data válida')
|
|
29
|
+
return v
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from zsynctech_studio_sdk.utils import validate_id_format
|
|
2
|
+
from zsynctech_studio_sdk.models import Config
|
|
3
|
+
from zsynctech_studio_sdk import client
|
|
4
|
+
from typing import Callable, Optional
|
|
5
|
+
import pika
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
EXCHANGE_NAME = "start"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class StartService:
|
|
12
|
+
def __init__(self, rabbitmq_url: str, heartbeat: int = 5400):
|
|
13
|
+
if client._instance_id is None:
|
|
14
|
+
raise RuntimeError("Credentials not set. Call set_credentials() first.")
|
|
15
|
+
self._instance_id = validate_id_format(client._instance_id)
|
|
16
|
+
self._queue_name = f"robot_{self._instance_id}"
|
|
17
|
+
self._connection = pika.BlockingConnection(
|
|
18
|
+
parameters=pika.URLParameters(
|
|
19
|
+
f"{rabbitmq_url}?heartbeat={heartbeat}"
|
|
20
|
+
)
|
|
21
|
+
)
|
|
22
|
+
self._channel = self._connection.channel()
|
|
23
|
+
|
|
24
|
+
self._channel.exchange_declare(
|
|
25
|
+
exchange=EXCHANGE_NAME,
|
|
26
|
+
exchange_type='direct',
|
|
27
|
+
durable=True
|
|
28
|
+
)
|
|
29
|
+
self._channel.queue_declare(
|
|
30
|
+
queue=self._queue_name,
|
|
31
|
+
durable=True
|
|
32
|
+
)
|
|
33
|
+
self._channel.queue_bind(
|
|
34
|
+
exchange=EXCHANGE_NAME,
|
|
35
|
+
queue=self._queue_name,
|
|
36
|
+
routing_key=f"instance.{self._instance_id}"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def get_start_config(self) -> Optional[Config]:
|
|
40
|
+
"""Checks if there are start events in the queue
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Optional[Config]: Returns the configuration json,
|
|
44
|
+
if the queue is empty it returns None
|
|
45
|
+
"""
|
|
46
|
+
method_frame, _, body = self._channel.basic_get(
|
|
47
|
+
queue=self._queue_name,
|
|
48
|
+
auto_ack=True
|
|
49
|
+
)
|
|
50
|
+
if method_frame:
|
|
51
|
+
try:
|
|
52
|
+
message = json.loads(body)
|
|
53
|
+
except json.JSONDecodeError:
|
|
54
|
+
message = body.decode()
|
|
55
|
+
return Config(**message)
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
def start_listener(self, callback: Callable):
|
|
59
|
+
"""Starts a consumer to check for start events
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
callback (Callable): Function that will be
|
|
63
|
+
called when there is an event.
|
|
64
|
+
"""
|
|
65
|
+
def _internal_callback(ch, method, properties, body):
|
|
66
|
+
try:
|
|
67
|
+
message = json.loads(body)
|
|
68
|
+
except json.JSONDecodeError:
|
|
69
|
+
message = body.decode()
|
|
70
|
+
callback(Config(**message))
|
|
71
|
+
|
|
72
|
+
self._channel.basic_consume(
|
|
73
|
+
queue=self._queue_name,
|
|
74
|
+
on_message_callback=_internal_callback,
|
|
75
|
+
auto_ack=True
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
print(f"[StartService] Waiting for events in queue: {self._queue_name}...")
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
self._channel.start_consuming()
|
|
82
|
+
except KeyboardInterrupt:
|
|
83
|
+
self.close()
|
|
84
|
+
|
|
85
|
+
def close(self):
|
|
86
|
+
if self._connection and not self._connection.is_closed:
|
|
87
|
+
self._connection.close()
|
|
88
|
+
print("[StartService] Connection closed.")
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from zsynctech_studio_sdk.utils import get_utc_now
|
|
2
|
+
from zsynctech_studio_sdk.models import StepModel
|
|
3
|
+
from zsynctech_studio_sdk.enums import StepStatus
|
|
4
|
+
from zsynctech_studio_sdk import client
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
STEP_STATUS_COMPLETED = [
|
|
9
|
+
StepStatus.FAIL,
|
|
10
|
+
StepStatus.SUCCESS,
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Step(StepModel):
|
|
15
|
+
def __init__(self, task_id: str, code: str, observation: Optional[str] = None):
|
|
16
|
+
self._current_step = StepModel(
|
|
17
|
+
stepCode=code,
|
|
18
|
+
taskId=task_id,
|
|
19
|
+
startDate=get_utc_now(),
|
|
20
|
+
observation=observation,
|
|
21
|
+
automationOnClientId=client._instance_id
|
|
22
|
+
)
|
|
23
|
+
self._resource_path = "taskSteps"
|
|
24
|
+
|
|
25
|
+
def _update(
|
|
26
|
+
self,
|
|
27
|
+
status: Optional[StepStatus] = None,
|
|
28
|
+
observation: Optional[str] = None,
|
|
29
|
+
) -> dict:
|
|
30
|
+
if status in STEP_STATUS_COMPLETED:
|
|
31
|
+
self._current_step.endDate = get_utc_now()
|
|
32
|
+
|
|
33
|
+
if observation is not None:
|
|
34
|
+
self._current_step.observation = observation
|
|
35
|
+
|
|
36
|
+
if status is not None:
|
|
37
|
+
self._current_step.status = status
|
|
38
|
+
|
|
39
|
+
client.post(
|
|
40
|
+
endpoint=f"{self._resource_path}",
|
|
41
|
+
json=self._current_step.model_dump()
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
return self._current_step.model_dump()
|
|
45
|
+
|
|
46
|
+
def _start(self, observation: Optional[str] = None) -> dict:
|
|
47
|
+
"""Updates the step status to running
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
observation (Optional[str], optional): Step observation text. Defaults to None.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
dict: Dictionary containing the information of the current step
|
|
54
|
+
"""
|
|
55
|
+
return self._update(status=StepStatus.RUNNING, observation=observation)
|
|
56
|
+
|
|
57
|
+
def fail(self, observation: Optional[str] = None) -> dict:
|
|
58
|
+
"""Updates the step status to fail
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
observation (Optional[str], optional): Step observation text. Defaults to None.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
dict: Dictionary containing the information of the current step
|
|
65
|
+
"""
|
|
66
|
+
return self._update(status=StepStatus.FAIL, observation=observation)
|
|
67
|
+
|
|
68
|
+
def success(self, observation: Optional[str] = None) -> dict:
|
|
69
|
+
"""Updates the step status to success
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
observation (Optional[str], optional): Step observation text. Defaults to None.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
dict: Dictionary containing the information of the current step
|
|
76
|
+
"""
|
|
77
|
+
return self._update(status=StepStatus.SUCCESS, observation=observation)
|
|
78
|
+
|
|
79
|
+
def __enter__(self):
|
|
80
|
+
self._start()
|
|
81
|
+
return self
|
|
82
|
+
|
|
83
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
84
|
+
if self._current_step.status not in STEP_STATUS_COMPLETED:
|
|
85
|
+
if exc_type is not None:
|
|
86
|
+
self.fail(observation=str(exc_value))
|
|
87
|
+
else:
|
|
88
|
+
self.success()
|
|
89
|
+
|
|
90
|
+
return False
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from zsynctech_studio_sdk.utils import get_utc_now
|
|
2
|
+
from zsynctech_studio_sdk.models import TaskModel
|
|
3
|
+
from zsynctech_studio_sdk.enums import TaskStatus
|
|
4
|
+
from zsynctech_studio_sdk import client
|
|
5
|
+
from uuid_extensions import uuid7
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
TASK_STATUS_COMPLETED = [
|
|
10
|
+
TaskStatus.FAIL,
|
|
11
|
+
TaskStatus.SUCCESS,
|
|
12
|
+
TaskStatus.VALIDATION_ERROR,
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Task:
|
|
17
|
+
def __init__(self, execution_id: str, code: Optional[str] = None, description: Optional[str] = None):
|
|
18
|
+
self._current_task = TaskModel(
|
|
19
|
+
executionId=execution_id,
|
|
20
|
+
startDate=get_utc_now()
|
|
21
|
+
)
|
|
22
|
+
self._resource_path = "tasks"
|
|
23
|
+
|
|
24
|
+
if code:
|
|
25
|
+
self._current_task.code = code
|
|
26
|
+
else:
|
|
27
|
+
self._current_task.code = str(uuid7())
|
|
28
|
+
|
|
29
|
+
if description:
|
|
30
|
+
self._current_task.description = description
|
|
31
|
+
else:
|
|
32
|
+
self._current_task.description = "Descrição não informada"
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def task_id(self):
|
|
36
|
+
return self._current_task.id
|
|
37
|
+
|
|
38
|
+
def _update(
|
|
39
|
+
self,
|
|
40
|
+
status: Optional[TaskStatus] = None,
|
|
41
|
+
observation: Optional[str] = None,
|
|
42
|
+
) -> dict:
|
|
43
|
+
if status in TASK_STATUS_COMPLETED:
|
|
44
|
+
self._current_task.endDate = get_utc_now()
|
|
45
|
+
|
|
46
|
+
if status is not None:
|
|
47
|
+
self._current_task.status = status
|
|
48
|
+
|
|
49
|
+
if observation is not None:
|
|
50
|
+
self._current_task.observation = observation
|
|
51
|
+
|
|
52
|
+
client.post(
|
|
53
|
+
endpoint=self._resource_path,
|
|
54
|
+
json=self._current_task.model_dump()
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return self._current_task.model_dump()
|
|
58
|
+
|
|
59
|
+
def start(self, observation: Optional[str] = None) -> dict:
|
|
60
|
+
"""Updates the task status to running
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
observation (Optional[str], optional): Task observation text. Defaults to None.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
dict: Dictionary containing the information of the current task
|
|
67
|
+
"""
|
|
68
|
+
return self._update(TaskStatus.RUNNING, observation)
|
|
69
|
+
|
|
70
|
+
def fail(self, observation: Optional[str] = None) -> dict:
|
|
71
|
+
"""Updates the task status to fail
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
observation (Optional[str], optional): Task observation text. Defaults to None.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
dict: Dictionary containing the information of the current task
|
|
78
|
+
"""
|
|
79
|
+
return self._update(TaskStatus.FAIL, observation=observation)
|
|
80
|
+
|
|
81
|
+
def success(self, observation: Optional[str] = None) -> dict:
|
|
82
|
+
"""Updates the task status to success
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
observation (Optional[str], optional): Task observation text. Defaults to None.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
dict: Dictionary containing the information of the current task
|
|
89
|
+
"""
|
|
90
|
+
return self._update(TaskStatus.SUCCESS, observation=observation)
|
|
91
|
+
|
|
92
|
+
def __enter__(self):
|
|
93
|
+
self.start()
|
|
94
|
+
return self
|
|
95
|
+
|
|
96
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
97
|
+
if self._current_task.status not in TASK_STATUS_COMPLETED:
|
|
98
|
+
if exc_type is not None:
|
|
99
|
+
self.fail(observation=str(exc_value))
|
|
100
|
+
else:
|
|
101
|
+
self.success()
|
|
102
|
+
|
|
103
|
+
return False
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from datetime import datetime, timezone
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def get_utc_now() -> str:
|
|
6
|
+
"""
|
|
7
|
+
Get the current date and time in UTC format as an ISO string.
|
|
8
|
+
|
|
9
|
+
Returns:
|
|
10
|
+
str: Current UTC datetime in ISO format with 'Z' suffix (e.g., '2024-01-15T10:30:45.123Z')
|
|
11
|
+
"""
|
|
12
|
+
return datetime.now(timezone.utc).isoformat(timespec='milliseconds').replace('+00:00', 'Z')
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def validate_id_format(v):
|
|
16
|
+
if not re.match(r'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$', v):
|
|
17
|
+
raise ValueError('ID deve ser um UUID válido')
|
|
18
|
+
version = int(v[14], 16)
|
|
19
|
+
if version != 7:
|
|
20
|
+
raise ValueError('ID deve ser um UUID7 válido')
|
|
21
|
+
return v
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zsynctech-studio-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lib
|
|
5
|
+
Author-email: ZSync Tech LTDA <contato@zsynctech.com>
|
|
6
|
+
Requires-Python: >=3.13
|
|
7
|
+
Requires-Dist: httpx>=0.28.1
|
|
8
|
+
Requires-Dist: pika>=1.3.2
|
|
9
|
+
Requires-Dist: pydantic>=2.11.7
|
|
10
|
+
Requires-Dist: rich>=14.1.0
|
|
11
|
+
Requires-Dist: uuid7>=0.1.0
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# ZSync Tech Studio SDK
|
|
15
|
+
|
|
16
|
+
SDK oficial da ZSync Tech para integração com o ZSync Tech Studio, uma plataforma de automação de processos. Este SDK permite que você desenvolva robôs de automação que se integram perfeitamente com o ecossistema ZSync Tech.
|
|
17
|
+
|
|
18
|
+

|
|
19
|
+
|
|
20
|
+
## 📋 Índice
|
|
21
|
+
|
|
22
|
+
- [Instalação](#instalação)
|
|
23
|
+
- [Configuração Inicial](#configuração-inicial)
|
|
24
|
+
- [Conceitos Básicos](#conceitos-básicos)
|
|
25
|
+
- [Guia de Uso](#guia-de-uso)
|
|
26
|
+
- [StartService - Recebendo Configurações](#startservice---recebendo-configurações)
|
|
27
|
+
- [Execution - Gerenciando Execuções](#execution---gerenciando-execuções)
|
|
28
|
+
- [Task - Gerenciando Tarefas](#task---gerenciando-tarefas)
|
|
29
|
+
- [Step - Gerenciando Passos](#step---gerenciando-passos)
|
|
30
|
+
- [Exemplo Completo](#exemplo-completo)
|
|
31
|
+
- [API Reference](#api-reference)
|
|
32
|
+
- [Dependências](#dependências)
|
|
33
|
+
- [Suporte](#suporte)
|
|
34
|
+
|
|
35
|
+
## 🚀 Instalação via pip
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install zsynctech-studio-sdk
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 🚀 Instalação via uv
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
uv add zsynctech-studio-sdk
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## ⚙️ Configuração Inicial
|
|
48
|
+
|
|
49
|
+
Antes de usar o SDK, você precisa configurar suas credenciais:
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from zsynctech_studio_sdk import set_credentials
|
|
53
|
+
|
|
54
|
+
# Configure suas credenciais
|
|
55
|
+
set_credentials(
|
|
56
|
+
secret_key="sua_secret_key",
|
|
57
|
+
instance_id="seu_instance_id",
|
|
58
|
+
server="https://seu-servidor.com"
|
|
59
|
+
)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 🧠 Conceitos Básicos
|
|
63
|
+
|
|
64
|
+
O ZSync Tech Studio SDK trabalha com uma hierarquia de conceitos:
|
|
65
|
+
|
|
66
|
+
1. **Execution (Execução)**: Representa uma execução completa de um robô
|
|
67
|
+
2. **Task (Tarefa)**: Uma tarefa específica dentro de uma execução
|
|
68
|
+
3. **Step (Passo)**: Um passo individual dentro de uma tarefa
|
|
69
|
+
|
|
70
|
+
Cada nível pode ter diferentes status e observações para rastreamento detalhado.
|
|
71
|
+
|
|
72
|
+
## 📖 Guia de Uso
|
|
73
|
+
|
|
74
|
+
### StartService - Recebendo Configurações
|
|
75
|
+
|
|
76
|
+
O `StartService` permite que seu robô receba configurações via RabbitMQ:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from zsynctech_studio_sdk import StartService
|
|
80
|
+
|
|
81
|
+
# Configure o serviço
|
|
82
|
+
start_service = StartService(
|
|
83
|
+
rabbitmq_url="amqp://usuario:senha@servidor:5672/",
|
|
84
|
+
heartbeat=5400
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Verificar se há configurações disponíveis
|
|
88
|
+
config = start_service.get_start_config()
|
|
89
|
+
if config:
|
|
90
|
+
print(f"Execução recebida: {config.executionId}")
|
|
91
|
+
# Processar a configuração...
|
|
92
|
+
|
|
93
|
+
# Ou usar um listener contínuo
|
|
94
|
+
def process_config(config):
|
|
95
|
+
print(f"Processando execução: {config.executionId}")
|
|
96
|
+
# Sua lógica aqui...
|
|
97
|
+
|
|
98
|
+
start_service.start_listener(process_config)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Execution - Gerenciando Execuções
|
|
102
|
+
|
|
103
|
+
A classe `Execution` gerencia o ciclo de vida de uma execução:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from zsynctech_studio_sdk import Execution, ExecutionStatus
|
|
107
|
+
|
|
108
|
+
# Criar uma execução
|
|
109
|
+
execution = Execution(config.executionId)
|
|
110
|
+
|
|
111
|
+
# Iniciar a execução
|
|
112
|
+
execution.start("Iniciando processamento...")
|
|
113
|
+
|
|
114
|
+
# Atualizar progresso
|
|
115
|
+
execution.set_total_task_count(100)
|
|
116
|
+
execution.update_current_task_count(50)
|
|
117
|
+
|
|
118
|
+
# Atualizar observação
|
|
119
|
+
execution.update_observation("Processando dados...")
|
|
120
|
+
|
|
121
|
+
# Finalizar com sucesso
|
|
122
|
+
execution.finished("Processamento concluído com sucesso!")
|
|
123
|
+
|
|
124
|
+
# Ou em caso de erro
|
|
125
|
+
execution.error("Erro ao processar dados")
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Task - Gerenciando Tarefas
|
|
129
|
+
|
|
130
|
+
A classe `Task` gerencia tarefas individuais:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from zsynctech_studio_sdk import Task
|
|
134
|
+
|
|
135
|
+
# Criar uma tarefa
|
|
136
|
+
task = Task(
|
|
137
|
+
execution_id=execution.execution_id,
|
|
138
|
+
code="TASK_001",
|
|
139
|
+
description="Processar arquivo de dados"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Usar como context manager (recomendado)
|
|
143
|
+
with task:
|
|
144
|
+
# Sua lógica aqui
|
|
145
|
+
process_file()
|
|
146
|
+
# Status será automaticamente SUCCESS ou FAIL
|
|
147
|
+
|
|
148
|
+
# Ou gerenciar manualmente
|
|
149
|
+
task.start("Iniciando processamento do arquivo")
|
|
150
|
+
try:
|
|
151
|
+
process_file()
|
|
152
|
+
task.success("Arquivo processado com sucesso")
|
|
153
|
+
except Exception as e:
|
|
154
|
+
task.fail(f"Erro ao processar arquivo: {str(e)}")
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Step - Gerenciando Passos
|
|
158
|
+
|
|
159
|
+
A classe `Step` gerencia passos individuais dentro de uma tarefa:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from zsynctech_studio_sdk import Step
|
|
163
|
+
|
|
164
|
+
# Criar um passo
|
|
165
|
+
step = Step(
|
|
166
|
+
task_id=task.task_id,
|
|
167
|
+
code="STEP_001",
|
|
168
|
+
observation="Validando dados"
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Usar como context manager (recomendado)
|
|
172
|
+
with step:
|
|
173
|
+
# Sua lógica aqui
|
|
174
|
+
validate_data()
|
|
175
|
+
# Status será automaticamente SUCCESS ou FAIL
|
|
176
|
+
|
|
177
|
+
# Ou gerenciar manualmente
|
|
178
|
+
step._start("Iniciando validação")
|
|
179
|
+
try:
|
|
180
|
+
validate_data()
|
|
181
|
+
step.success("Dados validados com sucesso")
|
|
182
|
+
except Exception as e:
|
|
183
|
+
step.fail(f"Erro na validação: {str(e)}")
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## 💡 Exemplo Completo
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
from zsynctech_studio_sdk import (
|
|
190
|
+
set_credentials, StartService, Execution, Task, Step
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# 1. Configurar credenciais
|
|
194
|
+
set_credentials(
|
|
195
|
+
secret_key="sua_secret_key",
|
|
196
|
+
instance_id="seu_instance_id",
|
|
197
|
+
server="https://seu-servidor.com"
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# 2. Configurar StartService
|
|
201
|
+
start_service = StartService("amqp://usuario:senha@servidor:5672/")
|
|
202
|
+
|
|
203
|
+
def process_automation(config):
|
|
204
|
+
"""Função principal de processamento"""
|
|
205
|
+
|
|
206
|
+
# 3. Criar execução
|
|
207
|
+
execution = Execution(config.executionId)
|
|
208
|
+
execution.start("Iniciando automação")
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
# 4. Definir total de tarefas
|
|
212
|
+
execution.set_total_task_count(3)
|
|
213
|
+
|
|
214
|
+
# 5. Processar cada tarefa
|
|
215
|
+
for i, data in enumerate(data_to_process):
|
|
216
|
+
with Task(execution.execution_id, f"TASK_{i:03d}", f"Processar {data}") as task:
|
|
217
|
+
|
|
218
|
+
# 6. Processar passos da tarefa
|
|
219
|
+
with Step(task.task_id, "VALIDATE", "Validando arquivo") as step:
|
|
220
|
+
validate_file(data)
|
|
221
|
+
|
|
222
|
+
with Step(task.task_id, "PROCESS", "Processando dados") as step:
|
|
223
|
+
process_file(data)
|
|
224
|
+
|
|
225
|
+
with Step(task.task_id, "SAVE", "Salvando resultado") as step:
|
|
226
|
+
save_result(data)
|
|
227
|
+
|
|
228
|
+
# 7. Atualizar progresso
|
|
229
|
+
execution.update_current_task_count(i)
|
|
230
|
+
|
|
231
|
+
# 8. Finalizar com sucesso
|
|
232
|
+
execution.finished("Automação concluída com sucesso!")
|
|
233
|
+
|
|
234
|
+
except Exception as e:
|
|
235
|
+
execution.error(f"Erro na automação: {str(e)}")
|
|
236
|
+
|
|
237
|
+
# 9. Iniciar listener
|
|
238
|
+
start_service.start_listener(process_automation)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## 📚 API Reference
|
|
242
|
+
|
|
243
|
+
### StartService
|
|
244
|
+
|
|
245
|
+
- `__init__(rabbitmq_url: str, heartbeat: int = 5400)`: Inicializa o serviço
|
|
246
|
+
- `get_start_config() -> Optional[Config]`: Obtém configuração disponível
|
|
247
|
+
- `start_listener(callback: Callable)`: Inicia listener contínuo
|
|
248
|
+
- `close()`: Fecha conexão
|
|
249
|
+
|
|
250
|
+
### Execution
|
|
251
|
+
|
|
252
|
+
- `start(observation: Optional[str] = None)`: Inicia execução
|
|
253
|
+
- `finished(observation: Optional[str] = None)`: Finaliza com sucesso
|
|
254
|
+
- `error(observation: Optional[str] = None)`: Marca como erro
|
|
255
|
+
- `waiting(observation: Optional[str] = None)`: Marca como aguardando
|
|
256
|
+
- `set_total_task_count(count: int)`: Define total de tarefas
|
|
257
|
+
- `update_current_task_count(count: int)`: Atualiza progresso
|
|
258
|
+
- `update_observation(observation: str)`: Atualiza observação
|
|
259
|
+
|
|
260
|
+
### Task
|
|
261
|
+
|
|
262
|
+
- `start(observation: Optional[str] = None)`: Inicia tarefa
|
|
263
|
+
- `success(observation: Optional[str] = None)`: Marca como sucesso
|
|
264
|
+
- `fail(observation: Optional[str] = None)`: Marca como falha
|
|
265
|
+
- Suporte a context manager (`with`)
|
|
266
|
+
|
|
267
|
+
### Step
|
|
268
|
+
|
|
269
|
+
- `_start(observation: Optional[str] = None)`: Inicia passo
|
|
270
|
+
- `success(observation: Optional[str] = None)`: Marca como sucesso
|
|
271
|
+
- `fail(observation: Optional[str] = None)`: Marca como falha
|
|
272
|
+
- Suporte a context manager (`with`)
|
|
273
|
+
|
|
274
|
+
## 📦 Dependências
|
|
275
|
+
|
|
276
|
+
- `httpx>=0.28.1` - Cliente HTTP
|
|
277
|
+
- `pika>=1.3.2` - Cliente RabbitMQ
|
|
278
|
+
- `pydantic>=2.11.7` - Validação de dados
|
|
279
|
+
- `rich>=14.1.0` - Interface rica
|
|
280
|
+
- `uuid7>=0.1.0` - Geração de UUIDs
|
|
281
|
+
|
|
282
|
+
## 🆘 Suporte
|
|
283
|
+
|
|
284
|
+
Para suporte técnico, entre em contato:
|
|
285
|
+
|
|
286
|
+
- **Email**: contato@zsynctech.com
|
|
287
|
+
- **Empresa**: ZSync Tech LTDA
|
|
288
|
+
|
|
289
|
+
---
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
zsynctech_studio_sdk/__init__.py,sha256=ZAnvP6KLyduIxoA5aIPUcW2-WgAr7kq9V-Q5CFgTDuI,549
|
|
2
|
+
zsynctech_studio_sdk/client.py,sha256=FN4XAyaCISyzHnSdU6Fu3eY1X8h_UXpUpcjdfU6KAug,1195
|
|
3
|
+
zsynctech_studio_sdk/execution.py,sha256=-u-roSf8RHsS5EWPsAHTudH45qSeipi0aGO6BxmwVcg,5514
|
|
4
|
+
zsynctech_studio_sdk/start.py,sha256=XiNxtf-7BKKJ87eASIErgJH6nL72flpMMQV52OcGths,2845
|
|
5
|
+
zsynctech_studio_sdk/step.py,sha256=9jp_Byn-9hkkN67KqD7Cqvjd3Dqb_026FsHEtFihtoY,2849
|
|
6
|
+
zsynctech_studio_sdk/task.py,sha256=7p6UVLCyniHsI_pAusnq1LW_j39MaWNAi75V1SXMv3s,3150
|
|
7
|
+
zsynctech_studio_sdk/utils.py,sha256=uKgNffummtFJYnnozl9l4YRq9ViE9XkVFgU0KJLCdYc,664
|
|
8
|
+
zsynctech_studio_sdk/enums/__init__.py,sha256=bM5eghvamVTAvFR2RSF8h-zQrKPbs1oTIklpcRuNPtw,171
|
|
9
|
+
zsynctech_studio_sdk/enums/execution.py,sha256=DTKys4F3oXOxEZBef01gsgJYYea6t3Zfp0gLQ6_wJlo,267
|
|
10
|
+
zsynctech_studio_sdk/enums/step.py,sha256=gw1PoRk8oNZfDdwMKNAjYvQFRuUsZQSaueF0qpEGn0g,152
|
|
11
|
+
zsynctech_studio_sdk/enums/task.py,sha256=EaqTKCuQBRQ5P7R1U6ppa9Hcy8_d_KKB_ylsNoYteWQ,194
|
|
12
|
+
zsynctech_studio_sdk/models/__init__.py,sha256=oQfAKeDbTwvJXRsiBQ096v3AdqTjxCaat798vQfN3RM,206
|
|
13
|
+
zsynctech_studio_sdk/models/base.py,sha256=NTy3NVJaEt4Xhp0XXIXCRBPDLs_7AsyQVqvux_cyVrc,1615
|
|
14
|
+
zsynctech_studio_sdk/models/config.py,sha256=iCfwWji3rXTcZR2g5bMa0Ar0k5aG6jCy6DSLb1zv9ds,857
|
|
15
|
+
zsynctech_studio_sdk/models/execution.py,sha256=VAFkGxOwVEjGq1oCoLqPSRAvLxadMoJXCld93kDue40,604
|
|
16
|
+
zsynctech_studio_sdk/models/step.py,sha256=qq9dO42wHvyP1ABpiEjhLzuKb9ExclSX73ota4zycfA,931
|
|
17
|
+
zsynctech_studio_sdk/models/task.py,sha256=MNrbAovV-tRwoyrIUtfKgnchr6SZPtGd74FfRVoLHQU,973
|
|
18
|
+
zsynctech_studio_sdk-0.1.0.dist-info/METADATA,sha256=-a2hSnb0vaNecMxJy9zrQTy8ChUpWDHPzht2GzllVf4,8042
|
|
19
|
+
zsynctech_studio_sdk-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
20
|
+
zsynctech_studio_sdk-0.1.0.dist-info/entry_points.txt,sha256=I8nmQxT0vbevct2PeNvBGQOXZ5rAQqqFvZbRMihwrOM,69
|
|
21
|
+
zsynctech_studio_sdk-0.1.0.dist-info/RECORD,,
|