dwf-platform-cli 0.2.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.
- dwf_cli/__init__.py +3 -0
- dwf_cli/__main__.py +4 -0
- dwf_cli/api/__init__.py +3 -0
- dwf_cli/api/auth.py +46 -0
- dwf_cli/api/client.py +113 -0
- dwf_cli/api/datamodel.py +458 -0
- dwf_cli/api/formmodel.py +197 -0
- dwf_cli/api/funcmodel.py +436 -0
- dwf_cli/cli/__init__.py +69 -0
- dwf_cli/cli/_common.py +152 -0
- dwf_cli/cli/auth.py +197 -0
- dwf_cli/cli/config.py +200 -0
- dwf_cli/cli/datamodel.py +2270 -0
- dwf_cli/cli/formmodel.py +1007 -0
- dwf_cli/cli/funcmodel.py +2055 -0
- dwf_cli/cli/schema.py +210 -0
- dwf_cli/core/__init__.py +0 -0
- dwf_cli/core/config.py +177 -0
- dwf_cli/core/crypto.py +22 -0
- dwf_cli/core/errors.py +63 -0
- dwf_cli/core/output.py +6 -0
- dwf_cli/core/validator.py +129 -0
- dwf_cli/mcp/__init__.py +3 -0
- dwf_cli/mcp/server.py +411 -0
- dwf_cli/schemas/__init__.py +37 -0
- dwf_cli/schemas/datamodel/attribute_bind.schema.json +21 -0
- dwf_cli/schemas/datamodel/attribute_create.schema.json +24 -0
- dwf_cli/schemas/datamodel/attribute_update.schema.json +21 -0
- dwf_cli/schemas/datamodel/create.schema.json +27 -0
- dwf_cli/schemas/datamodel/excel_confirm.schema.json +65 -0
- dwf_cli/schemas/datamodel/external_create.schema.json +47 -0
- dwf_cli/schemas/datamodel/external_update.schema.json +47 -0
- dwf_cli/schemas/datamodel/object_create.schema.json +24 -0
- dwf_cli/schemas/datamodel/object_update.schema.json +17 -0
- dwf_cli/schemas/datamodel/relation_create.schema.json +34 -0
- dwf_cli/schemas/datamodel/relation_update.schema.json +34 -0
- dwf_cli/schemas/datamodel/update.schema.json +26 -0
- dwf_cli/schemas/funcmodel/app_create.schema.json +150 -0
- dwf_cli/schemas/funcmodel/app_update.schema.json +153 -0
- dwf_cli/schemas/funcmodel/language-package_create.schema.json +15 -0
- dwf_cli/schemas/funcmodel/operations_create.schema.json +77 -0
- dwf_cli/schemas/funcmodel/operations_update.schema.json +76 -0
- dwf_platform_cli-0.2.0.dist-info/METADATA +347 -0
- dwf_platform_cli-0.2.0.dist-info/RECORD +47 -0
- dwf_platform_cli-0.2.0.dist-info/WHEEL +4 -0
- dwf_platform_cli-0.2.0.dist-info/entry_points.txt +3 -0
- dwf_platform_cli-0.2.0.dist-info/licenses/LICENSE +190 -0
dwf_cli/__init__.py
ADDED
dwf_cli/__main__.py
ADDED
dwf_cli/api/__init__.py
ADDED
dwf_cli/api/auth.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from dwf_cli.core.crypto import encrypt_password
|
|
8
|
+
from dwf_cli.core.errors import AuthError
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from dwf_cli.api.client import APIClient
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def login(
|
|
15
|
+
client: APIClient,
|
|
16
|
+
username: str,
|
|
17
|
+
password: str,
|
|
18
|
+
aes_key: str,
|
|
19
|
+
aes_iv: str,
|
|
20
|
+
) -> str:
|
|
21
|
+
encrypted_pwd = encrypt_password(password, aes_key, aes_iv)
|
|
22
|
+
response = client._http.request(
|
|
23
|
+
"POST",
|
|
24
|
+
"/dwf/v1/login",
|
|
25
|
+
auth=httpx.BasicAuth(username, password),
|
|
26
|
+
files={
|
|
27
|
+
"username": (None, username),
|
|
28
|
+
"password": (None, encrypted_pwd),
|
|
29
|
+
},
|
|
30
|
+
)
|
|
31
|
+
if response.status_code != 200:
|
|
32
|
+
raise AuthError(
|
|
33
|
+
f"Login failed (status={response.status_code}, body={response.text[:200]})"
|
|
34
|
+
)
|
|
35
|
+
token = response.headers.get("authorization")
|
|
36
|
+
if not token:
|
|
37
|
+
raise AuthError("No authorization token in login response header")
|
|
38
|
+
return token
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def validate_token(client: APIClient) -> bool:
|
|
42
|
+
try:
|
|
43
|
+
client.get("/dwf/v1/org/current-user-environment")
|
|
44
|
+
return True
|
|
45
|
+
except Exception:
|
|
46
|
+
return False
|
dwf_cli/api/client.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from dwf_cli.core.errors import APIError, AuthError, ConflictError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def raise_if_not_success(result: object, action: str = "Operation") -> None:
|
|
11
|
+
if isinstance(result, dict) and result.get("success") is False:
|
|
12
|
+
msg = result.get("message", "Unknown error")
|
|
13
|
+
raise APIError(200, f"{action} failed: {msg}")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class APIClient:
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
base_url: str,
|
|
20
|
+
token: str | None = None,
|
|
21
|
+
timeout: float = 30.0,
|
|
22
|
+
) -> None:
|
|
23
|
+
self.base_url = base_url.rstrip("/")
|
|
24
|
+
self.token = token
|
|
25
|
+
self._http = httpx.Client(
|
|
26
|
+
base_url=self.base_url,
|
|
27
|
+
timeout=timeout,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def _request(
|
|
31
|
+
self,
|
|
32
|
+
method: str,
|
|
33
|
+
path: str,
|
|
34
|
+
*,
|
|
35
|
+
params: dict[str, Any] | None = None,
|
|
36
|
+
json: dict[str, Any] | None = None,
|
|
37
|
+
files: dict[str, Any] | None = None,
|
|
38
|
+
) -> Any:
|
|
39
|
+
headers: dict[str, str] = {}
|
|
40
|
+
if self.token:
|
|
41
|
+
headers["Authorization"] = self.token
|
|
42
|
+
|
|
43
|
+
response = self._http.request(
|
|
44
|
+
method,
|
|
45
|
+
path,
|
|
46
|
+
headers=headers,
|
|
47
|
+
params=params,
|
|
48
|
+
json=json,
|
|
49
|
+
files=files,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if response.status_code == 401:
|
|
53
|
+
raise AuthError(f"Unauthorized (body: {response.text[:200]})")
|
|
54
|
+
if response.status_code == 404:
|
|
55
|
+
from dwf_cli.core.errors import NotFoundError
|
|
56
|
+
|
|
57
|
+
raise NotFoundError(f"Not found: {path}")
|
|
58
|
+
if response.status_code == 409:
|
|
59
|
+
raise ConflictError(
|
|
60
|
+
f"Conflict: {path}",
|
|
61
|
+
detail=response.text[:500],
|
|
62
|
+
)
|
|
63
|
+
if response.status_code >= 400:
|
|
64
|
+
raise APIError(response.status_code, response.text)
|
|
65
|
+
|
|
66
|
+
if response.status_code == 204:
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
content_type = response.headers.get("content-type", "")
|
|
70
|
+
if "application/json" in content_type:
|
|
71
|
+
return response.json()
|
|
72
|
+
return response
|
|
73
|
+
|
|
74
|
+
def download(self, path: str, **kwargs: Any) -> httpx.Response:
|
|
75
|
+
headers: dict[str, str] = {}
|
|
76
|
+
if self.token:
|
|
77
|
+
headers["Authorization"] = self.token
|
|
78
|
+
response = self._http.request(
|
|
79
|
+
"GET" if "method" not in kwargs else kwargs.pop("method"),
|
|
80
|
+
path,
|
|
81
|
+
headers=headers,
|
|
82
|
+
**kwargs,
|
|
83
|
+
)
|
|
84
|
+
if response.status_code == 401:
|
|
85
|
+
raise AuthError(f"Unauthorized (body: {response.text[:200]})")
|
|
86
|
+
if response.status_code == 404:
|
|
87
|
+
from dwf_cli.core.errors import NotFoundError
|
|
88
|
+
|
|
89
|
+
raise NotFoundError(f"Not found: {path}")
|
|
90
|
+
if response.status_code >= 400:
|
|
91
|
+
raise APIError(response.status_code, response.text)
|
|
92
|
+
return response
|
|
93
|
+
|
|
94
|
+
def raw_request(
|
|
95
|
+
self,
|
|
96
|
+
method: str,
|
|
97
|
+
path: str,
|
|
98
|
+
*,
|
|
99
|
+
auth: httpx.Auth | None = None,
|
|
100
|
+
) -> httpx.Response:
|
|
101
|
+
return self._http.request(method, path, auth=auth)
|
|
102
|
+
|
|
103
|
+
def get(self, path: str, **kwargs: Any) -> Any:
|
|
104
|
+
return self._request("GET", path, **kwargs)
|
|
105
|
+
|
|
106
|
+
def post(self, path: str, **kwargs: Any) -> Any:
|
|
107
|
+
return self._request("POST", path, **kwargs)
|
|
108
|
+
|
|
109
|
+
def put(self, path: str, **kwargs: Any) -> Any:
|
|
110
|
+
return self._request("PUT", path, **kwargs)
|
|
111
|
+
|
|
112
|
+
def delete(self, path: str, **kwargs: Any) -> None:
|
|
113
|
+
self._request("DELETE", path, **kwargs)
|
dwf_cli/api/datamodel.py
ADDED
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
import httpx
|
|
8
|
+
from dwf_cli.api.client import APIClient
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ModelType(str, Enum):
|
|
12
|
+
entity = "entity"
|
|
13
|
+
e = "e"
|
|
14
|
+
relation = "relation"
|
|
15
|
+
r = "r"
|
|
16
|
+
external = "external"
|
|
17
|
+
x = "x"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
_MODEL_TYPE_PATHS: dict[str, str] = {
|
|
21
|
+
"entity": "/dwf/v1/meta/entities-internal",
|
|
22
|
+
"e": "/dwf/v1/meta/entities-internal",
|
|
23
|
+
"relation": "/dwf/v1/meta/relations",
|
|
24
|
+
"r": "/dwf/v1/meta/relations",
|
|
25
|
+
"external": "/dwf/v1/meta/entities-external",
|
|
26
|
+
"x": "/dwf/v1/meta/entities-external",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_ENTITY_VALUES = {"entity", "e"}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def list_models(
|
|
33
|
+
client: APIClient,
|
|
34
|
+
model_type: ModelType,
|
|
35
|
+
*,
|
|
36
|
+
page: int = 0,
|
|
37
|
+
page_size: int = 25,
|
|
38
|
+
with_page_info: bool = True,
|
|
39
|
+
is_system: bool = False,
|
|
40
|
+
search: str | None = None,
|
|
41
|
+
search_fields: list[str] | None = None,
|
|
42
|
+
) -> dict[str, Any]:
|
|
43
|
+
path = _MODEL_TYPE_PATHS[model_type.value]
|
|
44
|
+
params: dict[str, Any] = {
|
|
45
|
+
"pageIndex": page,
|
|
46
|
+
"pageSize": page_size,
|
|
47
|
+
"withPageInfo": str(with_page_info).lower(),
|
|
48
|
+
}
|
|
49
|
+
if model_type.value in _ENTITY_VALUES:
|
|
50
|
+
params["isSystem"] = str(is_system).lower()
|
|
51
|
+
body: dict[str, Any] = {}
|
|
52
|
+
if search:
|
|
53
|
+
body["keyword"] = search
|
|
54
|
+
body["attributes"] = search_fields or [
|
|
55
|
+
"className",
|
|
56
|
+
"displayName",
|
|
57
|
+
"zoneName",
|
|
58
|
+
"note",
|
|
59
|
+
]
|
|
60
|
+
return client.post(path, params=params, json=body)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_class(
|
|
64
|
+
client: APIClient,
|
|
65
|
+
name: str,
|
|
66
|
+
) -> Any:
|
|
67
|
+
return client.get(f"/dwf/v1/meta/classes/{name}")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def create_entity(
|
|
71
|
+
client: APIClient,
|
|
72
|
+
classes: list[dict[str, Any]],
|
|
73
|
+
*,
|
|
74
|
+
with_parent_oid: bool = False,
|
|
75
|
+
) -> Any:
|
|
76
|
+
return client.post(
|
|
77
|
+
"/dwf/v1/meta/entities-create",
|
|
78
|
+
params={"withParentOid": str(with_parent_oid).lower()},
|
|
79
|
+
json=classes,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def update_entity(
|
|
84
|
+
client: APIClient,
|
|
85
|
+
class_data: dict[str, Any],
|
|
86
|
+
) -> Any:
|
|
87
|
+
return client.post("/dwf/v1/meta/entities-update", json=class_data)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def update_relation(
|
|
91
|
+
client: APIClient,
|
|
92
|
+
relation_data: dict[str, Any],
|
|
93
|
+
) -> Any:
|
|
94
|
+
return client.post("/dwf/v1/meta/relation-update", json=relation_data)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def delete_class(
|
|
98
|
+
client: APIClient,
|
|
99
|
+
name: str,
|
|
100
|
+
*,
|
|
101
|
+
cascade: bool = False,
|
|
102
|
+
) -> Any:
|
|
103
|
+
return client.post(
|
|
104
|
+
f"/dwf/v1/meta/classes-delete/{name}",
|
|
105
|
+
params={"cascade": str(cascade).lower()},
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def get_relations_tree(client: APIClient) -> Any:
|
|
110
|
+
return client.get("/dwf/v1/meta/relations/tree")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def list_class_names(client: APIClient) -> Any:
|
|
114
|
+
return client.get("/dwf/v1/meta/class-names")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def get_attributes(
|
|
118
|
+
client: APIClient,
|
|
119
|
+
class_name: str,
|
|
120
|
+
*,
|
|
121
|
+
need_sys_attr: bool = False,
|
|
122
|
+
) -> Any:
|
|
123
|
+
return client.get(
|
|
124
|
+
f"/dwf/v1/meta/entities/{class_name}/attributes",
|
|
125
|
+
params={"needSysAttr": str(need_sys_attr).lower()},
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def list_attributes(
|
|
130
|
+
client: APIClient,
|
|
131
|
+
*,
|
|
132
|
+
keyword: str | None = None,
|
|
133
|
+
) -> Any:
|
|
134
|
+
params: dict[str, str] = {}
|
|
135
|
+
if keyword:
|
|
136
|
+
params["keyword"] = keyword
|
|
137
|
+
return client.get("/dwf/v1/meta/attributes", params=params)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def list_objects(
|
|
141
|
+
client: APIClient,
|
|
142
|
+
class_name: str,
|
|
143
|
+
*,
|
|
144
|
+
page: int = 0,
|
|
145
|
+
page_size: int = 25,
|
|
146
|
+
with_page_info: bool = True,
|
|
147
|
+
condition: str | None = None,
|
|
148
|
+
order_condition: dict[str, str] | None = None,
|
|
149
|
+
return_attrs: list[str] | None = None,
|
|
150
|
+
) -> Any:
|
|
151
|
+
body: dict[str, Any] = {}
|
|
152
|
+
if condition:
|
|
153
|
+
body["condition"] = condition
|
|
154
|
+
if order_condition:
|
|
155
|
+
body["orderCondition"] = order_condition
|
|
156
|
+
if return_attrs:
|
|
157
|
+
body["returnAttrs"] = return_attrs
|
|
158
|
+
body["startIndex"] = page * page_size
|
|
159
|
+
body["pageSize"] = page_size
|
|
160
|
+
return client.post(
|
|
161
|
+
f"/dwf/v1/omf/entities/{class_name}/objects",
|
|
162
|
+
params={
|
|
163
|
+
"pageIndex": page,
|
|
164
|
+
"pageSize": page_size,
|
|
165
|
+
"totalCount": str(with_page_info).lower(),
|
|
166
|
+
},
|
|
167
|
+
json=body,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def query_objects(
|
|
172
|
+
client: APIClient,
|
|
173
|
+
class_name: str,
|
|
174
|
+
body: dict[str, Any],
|
|
175
|
+
*,
|
|
176
|
+
page: int = 0,
|
|
177
|
+
page_size: int = 25,
|
|
178
|
+
with_page_info: bool = True,
|
|
179
|
+
) -> Any:
|
|
180
|
+
body["startIndex"] = page * page_size
|
|
181
|
+
body["pageSize"] = page_size
|
|
182
|
+
return client.post(
|
|
183
|
+
f"/dwf/v1/omf/entities/{class_name}/objects",
|
|
184
|
+
params={
|
|
185
|
+
"pageIndex": page,
|
|
186
|
+
"pageSize": page_size,
|
|
187
|
+
"totalCount": str(with_page_info).lower(),
|
|
188
|
+
},
|
|
189
|
+
json=body,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def get_object(
|
|
194
|
+
client: APIClient,
|
|
195
|
+
class_name: str,
|
|
196
|
+
oid: str,
|
|
197
|
+
) -> Any:
|
|
198
|
+
return client.post(f"/dwf/v1/omf/entities/{class_name}/objects/{oid}")
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def create_objects(
|
|
202
|
+
client: APIClient,
|
|
203
|
+
class_name: str,
|
|
204
|
+
objects: list[dict[str, Any]],
|
|
205
|
+
) -> Any:
|
|
206
|
+
return client.post(
|
|
207
|
+
f"/dwf/v1/omf/entities/{class_name}/objects-create",
|
|
208
|
+
json=objects,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def update_objects(
|
|
213
|
+
client: APIClient,
|
|
214
|
+
class_name: str,
|
|
215
|
+
objects: list[dict[str, Any]],
|
|
216
|
+
*,
|
|
217
|
+
force_update: bool = False,
|
|
218
|
+
) -> Any:
|
|
219
|
+
return client.post(
|
|
220
|
+
f"/dwf/v1/omf/entities/{class_name}/objects-update",
|
|
221
|
+
params={"forceUpdate": str(force_update).lower()},
|
|
222
|
+
json=objects,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def delete_objects(
|
|
227
|
+
client: APIClient,
|
|
228
|
+
class_name: str,
|
|
229
|
+
oids: list[str],
|
|
230
|
+
) -> Any:
|
|
231
|
+
return client.post(
|
|
232
|
+
f"/dwf/v1/omf/entities/{class_name}/objects-delete",
|
|
233
|
+
json=oids,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def count_objects(
|
|
238
|
+
client: APIClient,
|
|
239
|
+
class_name: str,
|
|
240
|
+
*,
|
|
241
|
+
condition: str | None = None,
|
|
242
|
+
) -> Any:
|
|
243
|
+
body: dict[str, Any] = {}
|
|
244
|
+
if condition:
|
|
245
|
+
body["condition"] = condition
|
|
246
|
+
return client.post(
|
|
247
|
+
f"/dwf/v1/omf/entities/{class_name}/objects/count",
|
|
248
|
+
json=body,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def create_relations(
|
|
253
|
+
client: APIClient,
|
|
254
|
+
relations: list[dict[str, Any]],
|
|
255
|
+
) -> Any:
|
|
256
|
+
return client.post("/dwf/v1/meta/relations-create", json=relations)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def create_external_class(
|
|
260
|
+
client: APIClient,
|
|
261
|
+
class_list: list[dict[str, Any]],
|
|
262
|
+
custom_sql_map: dict[str, str] | None = None,
|
|
263
|
+
) -> Any:
|
|
264
|
+
body: dict[str, Any] = {"classList": class_list}
|
|
265
|
+
if custom_sql_map:
|
|
266
|
+
body["customSqlMap"] = custom_sql_map
|
|
267
|
+
return client.post("/dwf/v1/meta/external-entities-create", json=body)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def update_external_class(
|
|
271
|
+
client: APIClient,
|
|
272
|
+
class_list: list[dict[str, Any]],
|
|
273
|
+
custom_sql_map: dict[str, str] | None = None,
|
|
274
|
+
) -> Any:
|
|
275
|
+
body: dict[str, Any] = {"classList": class_list}
|
|
276
|
+
if custom_sql_map:
|
|
277
|
+
body["customSqlMap"] = custom_sql_map
|
|
278
|
+
return client.post("/dwf/v1/meta/external-entities-update", json=body)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def create_attributes(
|
|
282
|
+
client: APIClient,
|
|
283
|
+
attributes: list[dict[str, Any]],
|
|
284
|
+
) -> Any:
|
|
285
|
+
return client.post("/dwf/v1/meta/attributes-create", json=attributes)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def update_attribute(
|
|
289
|
+
client: APIClient,
|
|
290
|
+
attribute: dict[str, Any],
|
|
291
|
+
) -> Any:
|
|
292
|
+
return client.post("/dwf/v1/meta/attributes-update", json=attribute)
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def delete_attribute(
|
|
296
|
+
client: APIClient,
|
|
297
|
+
name: str,
|
|
298
|
+
*,
|
|
299
|
+
force: bool = False,
|
|
300
|
+
) -> Any:
|
|
301
|
+
return client.post(
|
|
302
|
+
f"/dwf/v1/meta/attributes-delete/{name}",
|
|
303
|
+
params={"force": str(force).lower()},
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def get_attribute(
|
|
308
|
+
client: APIClient,
|
|
309
|
+
name: str,
|
|
310
|
+
) -> Any:
|
|
311
|
+
return client.get(f"/dwf/v1/meta/attributes/{name}")
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def get_attribute_bind_classes(
|
|
315
|
+
client: APIClient,
|
|
316
|
+
name: str,
|
|
317
|
+
) -> Any:
|
|
318
|
+
return client.get(f"/dwf/v1/meta/attributes/{name}/bind-classes")
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def bind_attributes(
|
|
322
|
+
client: APIClient,
|
|
323
|
+
class_name: str,
|
|
324
|
+
attributes: list[dict[str, Any]],
|
|
325
|
+
*,
|
|
326
|
+
is_relation: bool = False,
|
|
327
|
+
) -> Any:
|
|
328
|
+
prefix = "relations" if is_relation else "entities"
|
|
329
|
+
return client.post(
|
|
330
|
+
f"/dwf/v1/meta/{prefix}/{class_name}/attributes-bind",
|
|
331
|
+
json=attributes,
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def unbind_attribute(
|
|
336
|
+
client: APIClient,
|
|
337
|
+
class_name: str,
|
|
338
|
+
attr_name: str,
|
|
339
|
+
*,
|
|
340
|
+
is_relation: bool = False,
|
|
341
|
+
) -> Any:
|
|
342
|
+
prefix = "relations" if is_relation else "entities"
|
|
343
|
+
return client.post(
|
|
344
|
+
f"/dwf/v1/meta/{prefix}/{class_name}/attributes-untie/{attr_name}",
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def get_import_uuid(
|
|
349
|
+
client: APIClient,
|
|
350
|
+
*,
|
|
351
|
+
update_if_exist: bool = False,
|
|
352
|
+
) -> Any:
|
|
353
|
+
return client.get(
|
|
354
|
+
"/dwf/v1/importData/getImportDataUUID",
|
|
355
|
+
params={"updateIfExist": str(update_if_exist).lower()},
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def import_data(
|
|
360
|
+
client: APIClient,
|
|
361
|
+
uuid: str,
|
|
362
|
+
sock_id: str,
|
|
363
|
+
file_path: str,
|
|
364
|
+
) -> Any:
|
|
365
|
+
with open(file_path, "rb") as f:
|
|
366
|
+
return client.post(
|
|
367
|
+
"/dwf/v1/importData/importData",
|
|
368
|
+
params={"uuid": uuid, "sockID": sock_id},
|
|
369
|
+
files={"file": f},
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def export_data(
|
|
374
|
+
client: APIClient,
|
|
375
|
+
class_name: str,
|
|
376
|
+
attributes: list[str],
|
|
377
|
+
*,
|
|
378
|
+
condition: str | None = None,
|
|
379
|
+
join_to_one: bool = False,
|
|
380
|
+
title_only: bool = False,
|
|
381
|
+
) -> httpx.Response:
|
|
382
|
+
body: dict[str, Any] = {
|
|
383
|
+
"className": class_name,
|
|
384
|
+
"attributes": attributes,
|
|
385
|
+
}
|
|
386
|
+
if condition:
|
|
387
|
+
body["condition"] = condition
|
|
388
|
+
return client.download(
|
|
389
|
+
"/dwf/v1/exportData/exportData",
|
|
390
|
+
method="POST",
|
|
391
|
+
params={
|
|
392
|
+
"joinToOneSheet": str(join_to_one).lower(),
|
|
393
|
+
"titleOnly": str(title_only).lower(),
|
|
394
|
+
},
|
|
395
|
+
json=body,
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def upload_excel(
|
|
400
|
+
client: APIClient,
|
|
401
|
+
file_path: str,
|
|
402
|
+
) -> Any:
|
|
403
|
+
with open(file_path, "rb") as f:
|
|
404
|
+
return client.post(
|
|
405
|
+
"/dwf/v1/quickStartFromExcel/uploadExcel",
|
|
406
|
+
files={"excelFile": f},
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def confirm_excel(
|
|
411
|
+
client: APIClient,
|
|
412
|
+
info: dict[str, Any],
|
|
413
|
+
) -> Any:
|
|
414
|
+
return client.post(
|
|
415
|
+
"/dwf/v1/quickStartFromExcel/confirmClassInfo",
|
|
416
|
+
json=info,
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def check_class_name_valid(
|
|
421
|
+
client: APIClient,
|
|
422
|
+
class_name: str,
|
|
423
|
+
) -> bool:
|
|
424
|
+
result = client.get(
|
|
425
|
+
"/dwf/v1/quickStartFromExcel/checkClassNameValid",
|
|
426
|
+
params={"className": class_name},
|
|
427
|
+
)
|
|
428
|
+
if isinstance(result, dict):
|
|
429
|
+
data = result.get("data", {})
|
|
430
|
+
if isinstance(data, dict):
|
|
431
|
+
return data.get("valid", False) is True
|
|
432
|
+
return False
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def check_attribute_type_valid(
|
|
436
|
+
client: APIClient,
|
|
437
|
+
attribute_name: str,
|
|
438
|
+
value_type: str,
|
|
439
|
+
) -> bool:
|
|
440
|
+
result = client.get(
|
|
441
|
+
"/dwf/v1/quickStartFromExcel/checkAttributeTypeValid",
|
|
442
|
+
params={"attributeName": attribute_name, "valueType": value_type},
|
|
443
|
+
)
|
|
444
|
+
if isinstance(result, dict):
|
|
445
|
+
data = result.get("data", {})
|
|
446
|
+
if isinstance(data, dict):
|
|
447
|
+
return data.get("valid", False) is True
|
|
448
|
+
return False
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def delete_temp_excel(
|
|
452
|
+
client: APIClient,
|
|
453
|
+
uuid: str,
|
|
454
|
+
) -> Any:
|
|
455
|
+
return client.get(
|
|
456
|
+
"/dwf/v1/quickStartFromExcel/deleteTempExcelFile",
|
|
457
|
+
params={"uuid": uuid},
|
|
458
|
+
)
|