pyegeria 5.4.0.33__py3-none-any.whl → 5.4.0.35__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.
- commands/.DS_Store +0 -0
- commands/cat/.DS_Store +0 -0
- commands/cat/.env +8 -0
- commands/cat/debug_log.2025-08-26_20-04-40_905576.log.zip +0 -0
- commands/cat/debug_log.2025-08-27_20-09-41_795022.log.zip +0 -0
- commands/cat/debug_log.log +898 -0
- commands/cat/list_format_set.py +4 -1
- commands/cat/logs/pyegeria.log +90 -0
- commands/cli/debug_log.log +0 -0
- commands/doc/.DS_Store +0 -0
- commands/ops/logs/pyegeria.log +0 -0
- md_processing/.DS_Store +0 -0
- md_processing/.idea/.gitignore +8 -0
- md_processing/.idea/inspectionProfiles/Project_Default.xml +59 -0
- md_processing/.idea/md_processing.iml +15 -0
- md_processing/.idea/modules.xml +8 -0
- md_processing/.idea/sonarlint/issuestore/index.pb +0 -0
- md_processing/.idea/sonarlint/securityhotspotstore/index.pb +0 -0
- md_processing/.idea/vcs.xml +6 -0
- md_processing/.idea/workspace.xml +107 -0
- md_processing/__init__.py +3 -2
- md_processing/data/commands.json +11496 -10345
- md_processing/dr_egeria.py +14 -6
- md_processing/dr_egeria_inbox/Derive-Dr-Gov-Defs.md +8 -0
- md_processing/dr_egeria_inbox/Dr.Egeria Templates.md +873 -0
- md_processing/dr_egeria_inbox/arch_test.md +57 -0
- md_processing/dr_egeria_inbox/archive/dr_egeria_intro.md +254 -0
- md_processing/dr_egeria_inbox/archive/dr_egeria_intro_more_terms.md +696 -0
- md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part1.md +254 -0
- md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part2.md +298 -0
- md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part3.md +608 -0
- md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part4.md +94 -0
- md_processing/dr_egeria_inbox/archive/freddie_intro.md +284 -0
- md_processing/dr_egeria_inbox/archive/freddie_intro_orig.md +275 -0
- md_processing/dr_egeria_inbox/archive/test-term.md +110 -0
- md_processing/dr_egeria_inbox/cat_test.md +100 -0
- md_processing/dr_egeria_inbox/collections.md +39 -0
- md_processing/dr_egeria_inbox/data_designer_debug.log +6 -0
- md_processing/dr_egeria_inbox/data_designer_out.md +60 -0
- md_processing/dr_egeria_inbox/data_designer_search_test.md +11 -0
- md_processing/dr_egeria_inbox/data_field.md +54 -0
- md_processing/dr_egeria_inbox/data_spec.md +77 -0
- md_processing/dr_egeria_inbox/data_spec_test.md +2406 -0
- md_processing/dr_egeria_inbox/data_test.md +179 -0
- md_processing/dr_egeria_inbox/data_test2.md +429 -0
- md_processing/dr_egeria_inbox/data_test3.md +462 -0
- md_processing/dr_egeria_inbox/dr_egeria_data_designer_1.md +124 -0
- md_processing/dr_egeria_inbox/dr_egeria_intro_categories.md +168 -0
- md_processing/dr_egeria_inbox/dr_egeria_intro_part1.md +280 -0
- md_processing/dr_egeria_inbox/dr_egeria_intro_part2.md +318 -0
- md_processing/dr_egeria_inbox/dr_egeria_intro_part3.md +1073 -0
- md_processing/dr_egeria_inbox/dr_egeria_isc1.md +44 -0
- md_processing/dr_egeria_inbox/generated_help_report.md +9 -0
- md_processing/dr_egeria_inbox/glossary_list.md +5 -0
- md_processing/dr_egeria_inbox/glossary_search_test.md +40 -0
- md_processing/dr_egeria_inbox/glossary_test1.md +363 -0
- md_processing/dr_egeria_inbox/gov_def.md +482 -0
- md_processing/dr_egeria_inbox/gov_def2.md +447 -0
- md_processing/dr_egeria_inbox/img.png +0 -0
- md_processing/dr_egeria_inbox/output_tests.md +103 -0
- md_processing/dr_egeria_inbox/product.md +211 -0
- md_processing/dr_egeria_inbox/rel.md +8 -0
- md_processing/dr_egeria_inbox/sb.md +119 -0
- md_processing/dr_egeria_inbox/solution-components.md +136 -0
- md_processing/dr_egeria_inbox/solution_blueprints.md +118 -0
- md_processing/dr_egeria_inbox/synonym_test.md +42 -0
- md_processing/dr_egeria_inbox/t2.md +268 -0
- md_processing/dr_egeria_outbox/.DS_Store +0 -0
- md_processing/dr_egeria_outbox/.obsidian/app.json +1 -0
- md_processing/dr_egeria_outbox/.obsidian/appearance.json +1 -0
- md_processing/dr_egeria_outbox/.obsidian/community-plugins.json +7 -0
- md_processing/dr_egeria_outbox/.obsidian/core-plugins.json +33 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/buttons/main.js +5164 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/buttons/manifest.json +10 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/buttons/styles.css +624 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/data.json +10 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/main.js +4459 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/manifest.json +10 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/data.json +3 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/main.js +153 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/manifest.json +11 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/styles.css +1 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/main.js +500 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/manifest.json +12 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/styles.css +1 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/data.json +38 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/main.js +37 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/manifest.json +11 -0
- md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/styles.css +220 -0
- md_processing/dr_egeria_outbox/.obsidian/types.json +28 -0
- md_processing/dr_egeria_outbox/.obsidian/workspace.json +270 -0
- md_processing/dr_egeria_outbox/Button Test.md +11 -0
- md_processing/dr_egeria_outbox/Scripts/.DS_Store +0 -0
- md_processing/dr_egeria_outbox/Scripts/sendRest.js +24 -0
- md_processing/dr_egeria_outbox/Templates/sendToApi.md.md +17 -0
- md_processing/dr_egeria_outbox/Untitled.canvas +1 -0
- md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 15:00-Derive-Dr-Gov-Defs.md +719 -0
- md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:13-Derive-Dr-Gov-Defs.md +41 -0
- md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:14-Derive-Dr-Gov-Defs.md +33 -0
- md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:50-Derive-Dr-Gov-Defs.md +192 -0
- md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 22:08-gov_def2.md +486 -0
- md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 22:10-gov_def2.md +486 -0
- md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 08:53-gov_def2.md +486 -0
- md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 08:54-gov_def2.md +486 -0
- md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:03-gov_def2.md +486 -0
- md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:06-gov_def2.md +486 -0
- md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:10-gov_def2.md +486 -0
- md_processing/md_commands/glossary_commands.py +2 -2
- md_processing/md_commands/old_project_commands.py +164 -0
- md_processing/md_commands/product_manager_commands.py +5 -5
- md_processing/md_commands/project_commands.py +368 -134
- md_processing/md_processing_utils/common_md_proc_utils.py +1 -0
- md_processing/md_processing_utils/common_md_utils.py +13 -1
- md_processing/md_processing_utils/debug_log +3 -574
- md_processing/md_processing_utils/debug_log.log +0 -0
- md_processing/md_processing_utils/determine_width.py +103 -0
- md_processing/md_processing_utils/generate_dr_help.py +44 -18
- md_processing/md_processing_utils/logs/pyegeria.log +56 -0
- md_processing/md_processing_utils/md_processing_constants.py +37 -4
- pyegeria/.DS_Store +0 -0
- pyegeria/_client_new.py +2 -2
- pyegeria/_output_formats.py +38 -10
- pyegeria/glossary_manager.py +0 -2
- pyegeria/output_formatter.py +9 -8
- pyegeria/project_manager.py +541 -420
- {pyegeria-5.4.0.33.dist-info → pyegeria-5.4.0.35.dist-info}/METADATA +2 -1
- {pyegeria-5.4.0.33.dist-info → pyegeria-5.4.0.35.dist-info}/RECORD +130 -25
- md_processing/dr-egeria-outbox/Collections-2025-08-12-13-30-37.md +0 -163
- md_processing/dr-egeria-outbox/Collections-2025-08-12-13-35-58.md +0 -474
- md_processing/md_processing_utils/dr-egeria-help-2025-07-17T17:22:09.md +0 -2065
- {pyegeria-5.4.0.33.dist-info → pyegeria-5.4.0.35.dist-info}/LICENSE +0 -0
- {pyegeria-5.4.0.33.dist-info → pyegeria-5.4.0.35.dist-info}/WHEEL +0 -0
- {pyegeria-5.4.0.33.dist-info → pyegeria-5.4.0.35.dist-info}/entry_points.txt +0 -0
pyegeria/project_manager.py
CHANGED
@@ -9,17 +9,23 @@ Copyright Contributors to the ODPi Egeria project.
|
|
9
9
|
|
10
10
|
import asyncio
|
11
11
|
|
12
|
+
from pyegeria import select_output_format_set
|
12
13
|
from pyegeria._client_new import Client2
|
14
|
+
from pyegeria._output_formats import get_output_format_type_match
|
13
15
|
from pyegeria.config import settings as app_settings
|
14
16
|
from pyegeria.models import (SearchStringRequestBody, FilterRequestBody, GetRequestBody, NewElementRequestBody,
|
15
|
-
TemplateRequestBody
|
17
|
+
TemplateRequestBody, DeleteRequestBody, UpdateElementRequestBody,
|
18
|
+
NewRelationshipRequestBody)
|
19
|
+
from pyegeria.output_formatter import generate_output, populate_columns_from_properties, \
|
20
|
+
_extract_referenceable_properties, get_required_relationships
|
16
21
|
from pyegeria.utils import body_slimmer, dynamic_catch
|
17
22
|
|
18
23
|
EGERIA_LOCAL_QUALIFIER = app_settings.User_Profile.egeria_local_qualifier
|
19
|
-
from
|
24
|
+
from loguru import logger
|
20
25
|
|
21
26
|
PROJECT_TYPES = ["Project", "Campaign", "StudyProject", "Task", "PersonalProject"]
|
22
27
|
|
28
|
+
|
23
29
|
class ProjectManager(Client2):
|
24
30
|
"""
|
25
31
|
Create and manage projects. Projects may be organized in a hierarchy.
|
@@ -45,30 +51,105 @@ class ProjectManager(Client2):
|
|
45
51
|
user_id: str,
|
46
52
|
user_pwd: str = None,
|
47
53
|
token: str = None,
|
48
|
-
|
54
|
+
):
|
49
55
|
self.view_server = view_server
|
50
56
|
self.platform_url = platform_url
|
51
57
|
self.user_id = user_id
|
52
58
|
self.user_pwd = user_pwd
|
53
59
|
self.project_command_base: str = (
|
54
|
-
f"/api/open-metadata/project-manager/projects"
|
60
|
+
f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/project-manager/projects"
|
55
61
|
)
|
56
62
|
Client2.__init__(self, view_server, platform_url, user_id, user_pwd, token)
|
57
63
|
|
64
|
+
def _extract_additional_project_properties(self, element: dict, columns_struct: dict)-> dict:
|
65
|
+
|
66
|
+
|
67
|
+
roles_required = any(column.get('key') == 'project_roles'
|
68
|
+
for column in columns_struct.get('formats', {}).get('columns', []))
|
69
|
+
project_props = {}
|
70
|
+
|
71
|
+
if roles_required:
|
72
|
+
project_roles = element['elementHeader'].get('projectRoles', [])
|
73
|
+
project_roles_list = []
|
74
|
+
for project_role in project_roles:
|
75
|
+
project_roles_list.append(project_role.get('classificationName', ""))
|
76
|
+
project_roles_md = (", \n".join(project_roles_list)).rstrip(',') if project_roles_list else ''
|
77
|
+
project_props = {
|
78
|
+
'project_roles': project_roles_md,
|
79
|
+
}
|
80
|
+
return project_props
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
def _extract_project_properties(self, element: dict, columns_struct: dict) -> dict:
|
86
|
+
props = element.get('properties', {}) or {}
|
87
|
+
normalized = {
|
88
|
+
'properties': props,
|
89
|
+
'elementHeader': element.get('elementHeader', {}),
|
90
|
+
}
|
91
|
+
col_data = populate_columns_from_properties(element, columns_struct)
|
92
|
+
# col_data = populate_columns_from_properties(normalized, columns_struct)
|
93
|
+
columns_list = col_data.get('formats', {}).get('columns', [])
|
94
|
+
header_props = _extract_referenceable_properties(element)
|
95
|
+
# Populate requested relationship-based columns generically
|
96
|
+
col_data = get_required_relationships(element, col_data)
|
97
|
+
additional_props = self._extract_additional_project_properties(element, columns_struct)
|
98
|
+
guid = header_props.get('GUID')
|
99
|
+
|
100
|
+
for column in columns_list:
|
101
|
+
key = column.get('key')
|
102
|
+
if key in header_props:
|
103
|
+
column['value'] = header_props.get(key)
|
104
|
+
elif key == 'project_roles':
|
105
|
+
column['value'] = additional_props.get('project_roles', '')
|
106
|
+
elif isinstance(key, str) and key.lower() == 'guid':
|
107
|
+
column['value'] = guid
|
108
|
+
|
109
|
+
for column in columns_list:
|
110
|
+
if column.get('key') == 'mermaid' and not column.get('value'):
|
111
|
+
column['value'] = element.get('mermaidGraph', '') or ''
|
112
|
+
break
|
113
|
+
return col_data
|
114
|
+
|
115
|
+
|
116
|
+
def _generate_project_output(self, elements: dict | list[dict], search_string: str,
|
117
|
+
element_type_name: str | None,
|
118
|
+
output_format: str = 'DICT',
|
119
|
+
output_format_set: dict | str = None) -> str | list[dict]:
|
120
|
+
entity_type = 'Project'
|
121
|
+
if output_format_set:
|
122
|
+
if isinstance(output_format_set, str):
|
123
|
+
output_formats = select_output_format_set(output_format_set, output_format)
|
124
|
+
elif isinstance(output_format_set, dict):
|
125
|
+
output_formats = get_output_format_type_match(output_format_set, output_format)
|
126
|
+
else:
|
127
|
+
output_formats = None
|
128
|
+
else:
|
129
|
+
output_formats = select_output_format_set(entity_type, output_format)
|
130
|
+
if output_formats is None:
|
131
|
+
output_formats = select_output_format_set('Default', output_format)
|
132
|
+
return generate_output(
|
133
|
+
elements=elements,
|
134
|
+
search_string=search_string,
|
135
|
+
entity_type=entity_type,
|
136
|
+
output_format=output_format,
|
137
|
+
extract_properties_func=self._extract_project_properties,
|
138
|
+
get_additional_props_func=None,
|
139
|
+
columns_struct=output_formats,
|
140
|
+
)
|
58
141
|
|
59
|
-
def _generate_project_output(self):
|
60
|
-
pass
|
61
142
|
#
|
62
143
|
# Retrieving Projects= Information - https://egeria-project.org/concepts/project
|
63
144
|
#
|
145
|
+
@dynamic_catch
|
64
146
|
async def _async_get_linked_projects(
|
65
147
|
self,
|
66
148
|
parent_guid: str,
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
) -> list | str:
|
149
|
+
body: dict | GetRequestBody = None,
|
150
|
+
output_format: str = 'JSON',
|
151
|
+
output_format_set: str | dict = None,
|
152
|
+
) -> list | str:
|
72
153
|
"""Returns the list of projects that are linked off of the supplied element. Any relationship will do.
|
73
154
|
The request body is optional, but if supplied acts as a filter on project status. Async version.
|
74
155
|
|
@@ -78,8 +159,6 @@ class ProjectManager(Client2):
|
|
78
159
|
The identity of the parent to find linked projects from.
|
79
160
|
project_status: str, optional
|
80
161
|
Optionally, filter results by project status.
|
81
|
-
effective_time: str, optional
|
82
|
-
Time at which to query for projects. Time format is "YYYY-MM-DDTHH:MM:SS" (ISO 8601).
|
83
162
|
|
84
163
|
start_from: int, [default=0], optional
|
85
164
|
When multiple pages of results are available, the page number to start from.
|
@@ -104,30 +183,25 @@ class ProjectManager(Client2):
|
|
104
183
|
|
105
184
|
"""
|
106
185
|
|
107
|
-
if page_size is None:
|
108
|
-
page_size = self.page_size
|
109
|
-
|
110
|
-
body = {
|
111
|
-
"filter": project_status,
|
112
|
-
"effectiveTime": effective_time,
|
113
|
-
}
|
114
|
-
body_s = body_slimmer(body)
|
115
186
|
url = (
|
116
187
|
f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/project-manager/"
|
117
|
-
f"metadata-elements/{parent_guid}/projects
|
188
|
+
f"metadata-elements/{parent_guid}/projects"
|
118
189
|
)
|
119
190
|
|
120
|
-
|
121
|
-
|
191
|
+
response = await self._async_get_guid_request(url, "Project", self._extract_project_properties,
|
192
|
+
body=body,
|
193
|
+
output_format=output_format,
|
194
|
+
output_format_set=output_format_set)
|
195
|
+
return response
|
122
196
|
|
197
|
+
@dynamic_catch
|
123
198
|
def get_linked_projects(
|
124
199
|
self,
|
125
200
|
parent_guid: str,
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
) -> list | str:
|
201
|
+
body: dict | GetRequestBody = None,
|
202
|
+
output_format: str = 'JSON',
|
203
|
+
output_format_set: str | dict = None) -> str | dict:
|
204
|
+
|
131
205
|
"""Returns the list of projects that are linked off of the supplied element. Any relationship will do.
|
132
206
|
The request body is optional, but if supplied acts as a filter on project status.
|
133
207
|
|
@@ -166,21 +240,23 @@ class ProjectManager(Client2):
|
|
166
240
|
resp = loop.run_until_complete(
|
167
241
|
self._async_get_linked_projects(
|
168
242
|
parent_guid,
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
page_size,
|
173
|
-
)
|
243
|
+
body,
|
244
|
+
output_format,
|
245
|
+
output_format_set
|
174
246
|
)
|
247
|
+
)
|
175
248
|
return resp
|
176
249
|
|
250
|
+
@dynamic_catch
|
177
251
|
async def _async_get_classified_projects(
|
178
252
|
self,
|
179
253
|
project_classification: str,
|
180
|
-
effective_time: str = None,
|
181
254
|
start_from: int = 0,
|
182
|
-
page_size: int =
|
183
|
-
|
255
|
+
page_size: int = 0,
|
256
|
+
output_format: str = 'JSON',
|
257
|
+
output_format_set: str | dict = None,
|
258
|
+
body: dict | GetRequestBody = None,) -> str | dict:
|
259
|
+
|
184
260
|
"""Returns the list of projects with a particular classification. The name of the classification is
|
185
261
|
supplied in the request body. Examples of these classifications include StudyProject, PersonalProject,
|
186
262
|
Campaign or Task. There is also GlossaryProject and GovernanceProject. Async version.
|
@@ -189,9 +265,6 @@ class ProjectManager(Client2):
|
|
189
265
|
----------
|
190
266
|
project_classification: str
|
191
267
|
The project classification to search for.
|
192
|
-
effective_time: str, optional
|
193
|
-
Time at which to query for projects. Time format is "YYYY-MM-DDTHH:MM:SS" (ISO 8601).
|
194
|
-
|
195
268
|
start_from: int, [default=0], optional
|
196
269
|
When multiple pages of results are available, the page number to start from.
|
197
270
|
page_size: int, [default=None]
|
@@ -215,29 +288,28 @@ class ProjectManager(Client2):
|
|
215
288
|
|
216
289
|
"""
|
217
290
|
|
218
|
-
if page_size is None:
|
219
|
-
page_size = self.page_size
|
220
291
|
|
221
|
-
body = {
|
222
|
-
"filter": project_classification,
|
223
|
-
"effectiveTime": effective_time,
|
224
|
-
}
|
225
|
-
body_s = body_slimmer(body)
|
226
292
|
url = (
|
227
293
|
f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/project-manager/"
|
228
|
-
f"projects/by-classifications
|
294
|
+
f"projects/by-classifications"
|
229
295
|
)
|
296
|
+
response = await self._async_get_name_request(url, "Project", self._extract_project_properties,
|
297
|
+
filter_string = project_classification, start_from=start_from,
|
298
|
+
page_size=page_size, body=body,
|
299
|
+
output_format=output_format,
|
300
|
+
output_format_set=output_format_set)
|
301
|
+
return response
|
230
302
|
|
231
|
-
|
232
|
-
return resp.json()
|
233
|
-
|
303
|
+
@dynamic_catch
|
234
304
|
def get_classified_projects(
|
235
305
|
self,
|
236
306
|
project_classification: str,
|
237
|
-
effective_time: str = None,
|
238
307
|
start_from: int = 0,
|
239
|
-
page_size: int =
|
240
|
-
|
308
|
+
page_size: int = 0,
|
309
|
+
output_format: str = 'JSON',
|
310
|
+
output_format_set: str | dict = None,
|
311
|
+
body: dict | GetRequestBody = None,
|
312
|
+
) -> str | dict:
|
241
313
|
"""Returns the list of projects with a particular classification. The name of the classification is
|
242
314
|
supplied in the request body. Examples of these classifications include StudyProject, PersonalProject,
|
243
315
|
Campaign or Task. There is also GlossaryProject and GovernanceProject.
|
@@ -273,129 +345,14 @@ class ProjectManager(Client2):
|
|
273
345
|
"""
|
274
346
|
loop = asyncio.get_event_loop()
|
275
347
|
resp = loop.run_until_complete(
|
276
|
-
self._async_get_classified_projects(
|
277
|
-
|
278
|
-
effective_time,
|
279
|
-
start_from,
|
280
|
-
page_size,
|
281
|
-
)
|
282
|
-
)
|
283
|
-
return resp
|
348
|
+
self._async_get_classified_projects(project_classification,
|
349
|
+
start_from,page_size,
|
284
350
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
team_role: str = None,
|
289
|
-
effective_time: str = None,
|
290
|
-
start_from: int = 0,
|
291
|
-
page_size: int = None,
|
292
|
-
) -> list | str:
|
293
|
-
"""Returns the list of actors that are linked off of the project. This includes the project managers.
|
294
|
-
The optional request body allows a teamRole to be specified as a filter. To filter out the project managers,
|
295
|
-
specify ProjectManagement as the team role. See https://egeria-project.org/concepts/project for details.
|
296
|
-
Async version.
|
297
|
-
|
298
|
-
Parameters
|
299
|
-
----------
|
300
|
-
project_guid: str
|
301
|
-
The identity of the project to return team information about.
|
302
|
-
team_role: str, optional
|
303
|
-
team role to filter on. Project managers would be "ProjectManagement".
|
304
|
-
effective_time: str, optional
|
305
|
-
Time at which to query the team role. Time format is "YYYY-MM-DDTHH:MM:SS" (ISO 8601).
|
306
|
-
|
307
|
-
start_from: int, [default=0], optional
|
308
|
-
When multiple pages of results are available, the page number to start from.
|
309
|
-
page_size: int, [default=None]
|
310
|
-
The number of items to return in a single page. If not specified, the default will be taken from
|
311
|
-
the class instance.
|
312
|
-
|
313
|
-
Returns
|
314
|
-
-------
|
315
|
-
list | str
|
316
|
-
The list of actors linked off the project, including project managers Returns a string if none found.
|
317
|
-
|
318
|
-
Raises
|
319
|
-
------
|
320
|
-
InvalidParameterException
|
321
|
-
If the client passes incorrect parameters on the request - such as bad URLs or invalid values.
|
322
|
-
PropertyServerException
|
323
|
-
Raised by the server when an issue arises in processing a valid request.
|
324
|
-
NotAuthorizedException
|
325
|
-
The principle specified by the user_id does not have authorization for the requested action.
|
326
|
-
Notes
|
327
|
-
-----
|
328
|
-
"""
|
329
|
-
|
330
|
-
if page_size is None:
|
331
|
-
page_size = self.page_size
|
332
|
-
|
333
|
-
body = {effective_time: effective_time, "filter": team_role}
|
334
|
-
body_s = body_slimmer(body)
|
335
|
-
url = (
|
336
|
-
f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/project-manager/projects/"
|
337
|
-
f"{project_guid}/team?startFrom={start_from}&pageSize={page_size}"
|
338
|
-
)
|
339
|
-
|
340
|
-
resp = await self._async_make_request("POST", url, body_s)
|
341
|
-
|
342
|
-
result = resp.json().get("elements", NO_ELEMENTS_FOUND)
|
343
|
-
return result
|
344
|
-
|
345
|
-
def get_project_team(
|
346
|
-
self,
|
347
|
-
project_guid: str,
|
348
|
-
team_role: str = None,
|
349
|
-
effective_time: str = None,
|
350
|
-
start_from: int = 0,
|
351
|
-
page_size: int = None,
|
352
|
-
) -> list | str:
|
353
|
-
"""Returns the list of actors that are linked off of the project. This includes the project managers.
|
354
|
-
The optional request body allows a teamRole to be specified as a filter. To filter out the project managers,
|
355
|
-
specify ProjectManagement as the team role. See https://egeria-project.org/concepts/project for details.
|
356
|
-
Async version.
|
357
|
-
|
358
|
-
Parameters
|
359
|
-
----------
|
360
|
-
project_guid: str
|
361
|
-
The identity of the project to return team information about.
|
362
|
-
team_role: str, optional
|
363
|
-
team role to filter on. Project managers would be "ProjectManagement".
|
364
|
-
effective_time: str, optional
|
365
|
-
Time at which to query the team role. Time format is "YYYY-MM-DDTHH:MM:SS" (ISO 8601).
|
366
|
-
|
367
|
-
start_from: int, [default=0], optional
|
368
|
-
When multiple pages of results are available, the page number to start from.
|
369
|
-
page_size: int, [default=None]
|
370
|
-
The number of items to return in a single page. If not specified, the default will be taken from
|
371
|
-
the class instance.
|
372
|
-
|
373
|
-
Returns
|
374
|
-
-------
|
375
|
-
list | str
|
376
|
-
The list of actors linked off the project, including project managers Returns a string if none found.
|
377
|
-
|
378
|
-
Raises
|
379
|
-
------
|
380
|
-
InvalidParameterException
|
381
|
-
If the client passes incorrect parameters on the request - such as bad URLs or invalid values.
|
382
|
-
PropertyServerException
|
383
|
-
Raised by the server when an issue arises in processing a valid request.
|
384
|
-
NotAuthorizedException
|
385
|
-
The principle specified by the user_id does not have authorization for the requested action.
|
386
|
-
Notes
|
387
|
-
-----
|
388
|
-
"""
|
389
|
-
loop = asyncio.get_event_loop()
|
390
|
-
resp = loop.run_until_complete(
|
391
|
-
self._async_get_project_team(
|
392
|
-
project_guid,
|
393
|
-
team_role,
|
394
|
-
effective_time,
|
395
|
-
start_from,
|
396
|
-
page_size,
|
397
|
-
)
|
351
|
+
output_format,
|
352
|
+
output_format_set,
|
353
|
+
body
|
398
354
|
)
|
355
|
+
)
|
399
356
|
return resp
|
400
357
|
|
401
358
|
@dynamic_catch
|
@@ -409,7 +366,7 @@ class ProjectManager(Client2):
|
|
409
366
|
page_size: int = 0,
|
410
367
|
output_format: str = "json", output_format_set: str | dict = None,
|
411
368
|
body: dict | SearchStringRequestBody = None
|
412
|
-
|
369
|
+
) -> list | str:
|
413
370
|
"""Returns the list of projects matching the search string.
|
414
371
|
The search string is located in the request body and is interpreted as a plain string.
|
415
372
|
The request parameters, startsWith, endsWith and ignoreCase can be used to allow a fuzzy search.
|
@@ -479,7 +436,7 @@ class ProjectManager(Client2):
|
|
479
436
|
page_size: int = 0,
|
480
437
|
output_format: str = "json", output_format_set: str | dict = None,
|
481
438
|
body: dict | SearchStringRequestBody = None
|
482
|
-
|
439
|
+
) -> list | str:
|
483
440
|
|
484
441
|
"""Returns the list of projects matching the search string.
|
485
442
|
The search string is located in the request body and is interpreted as a plain string.
|
@@ -534,29 +491,29 @@ class ProjectManager(Client2):
|
|
534
491
|
output_format,
|
535
492
|
output_format_set,
|
536
493
|
body,
|
537
|
-
)
|
538
494
|
)
|
495
|
+
)
|
539
496
|
|
540
497
|
return resp
|
541
498
|
|
542
499
|
@dynamic_catch
|
543
500
|
async def _async_get_projects_by_name(
|
544
|
-
self,
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
response = await self._async_get_name_request(url, _type="Projects",
|
552
|
-
_gen_output=self._generate_projects_output,
|
553
|
-
filter_string=filter_string,
|
554
|
-
classification_names=classification_names,
|
555
|
-
start_from=start_from, page_size=page_size,
|
556
|
-
output_format=output_format, output_format_set=output_format_set,
|
557
|
-
body=body)
|
501
|
+
self, filter_string: str = None, classification_names: list[str] = None,
|
502
|
+
body: dict | FilterRequestBody = None,
|
503
|
+
start_from: int = 0, page_size: int = 0,
|
504
|
+
output_format: str = 'JSON',
|
505
|
+
output_format_set: str | dict = None) -> list | str:
|
506
|
+
url = f"{self.project_command_base}/by-name"
|
558
507
|
|
559
|
-
|
508
|
+
response = await self._async_get_name_request(url, _type="Projects",
|
509
|
+
_gen_output=self._generate_project_output,
|
510
|
+
filter_string=filter_string,
|
511
|
+
classification_names=classification_names,
|
512
|
+
start_from=start_from, page_size=page_size,
|
513
|
+
output_format=output_format, output_format_set=output_format_set,
|
514
|
+
body=body)
|
515
|
+
|
516
|
+
return response
|
560
517
|
|
561
518
|
@dynamic_catch
|
562
519
|
def get_projects_by_name(
|
@@ -576,15 +533,15 @@ class ProjectManager(Client2):
|
|
576
533
|
page_size,
|
577
534
|
output_format,
|
578
535
|
output_format_set,
|
579
|
-
)
|
580
536
|
)
|
537
|
+
)
|
581
538
|
return resp
|
582
539
|
|
583
540
|
@dynamic_catch
|
584
541
|
async def _async_get_project_by_guid(self, project_guid: str, element_type: str = None,
|
585
|
-
|
586
|
-
|
587
|
-
|
542
|
+
body: dict | GetRequestBody = None,
|
543
|
+
output_format: str = 'JSON',
|
544
|
+
output_format_set: str | dict = None) -> dict | str:
|
588
545
|
"""Return the properties of a specific project. Async version.
|
589
546
|
|
590
547
|
Parameters
|
@@ -633,7 +590,7 @@ class ProjectManager(Client2):
|
|
633
590
|
type = element_type if element_type else "Collection"
|
634
591
|
|
635
592
|
response = await self._async_get_guid_request(url, _type=type,
|
636
|
-
_gen_output=self.
|
593
|
+
_gen_output=self._generate_project_output,
|
637
594
|
output_format=output_format, output_format_set=output_format_set,
|
638
595
|
body=body)
|
639
596
|
|
@@ -641,9 +598,9 @@ class ProjectManager(Client2):
|
|
641
598
|
|
642
599
|
@dynamic_catch
|
643
600
|
def get_project_by_guid(self, project_guid: str, element_type: str = None,
|
644
|
-
|
645
|
-
|
646
|
-
|
601
|
+
body: dict | GetRequestBody = None,
|
602
|
+
output_format: str = 'JSON',
|
603
|
+
output_format_set: str | dict = None) -> dict | str:
|
647
604
|
"""Return the properties of a specific project.
|
648
605
|
|
649
606
|
Parameters
|
@@ -688,8 +645,8 @@ class ProjectManager(Client2):
|
|
688
645
|
"""
|
689
646
|
loop = asyncio.get_event_loop()
|
690
647
|
resp = loop.run_until_complete(
|
691
|
-
self._async_get_project_by_guid(project_guid, element_type, body, output_format, output_format_set
|
692
|
-
|
648
|
+
self._async_get_project_by_guid(project_guid, element_type, body, output_format, output_format_set)
|
649
|
+
)
|
693
650
|
|
694
651
|
return resp
|
695
652
|
|
@@ -701,7 +658,7 @@ class ProjectManager(Client2):
|
|
701
658
|
body: dict | GetRequestBody = None,
|
702
659
|
output_format: str = 'JSON',
|
703
660
|
output_format_set: str | dict = None,
|
704
|
-
|
661
|
+
) -> dict | str:
|
705
662
|
"""Return the mermaid graph of a specific project. Async version.
|
706
663
|
|
707
664
|
Parameters
|
@@ -728,7 +685,6 @@ class ProjectManager(Client2):
|
|
728
685
|
|
729
686
|
"""
|
730
687
|
|
731
|
-
|
732
688
|
url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/project-manager/pr"
|
733
689
|
f"ojects/{project_guid}/graph")
|
734
690
|
|
@@ -747,7 +703,7 @@ class ProjectManager(Client2):
|
|
747
703
|
body: dict | GetRequestBody = None,
|
748
704
|
output_format: str = 'JSON',
|
749
705
|
output_format_set: str | dict = None,
|
750
|
-
|
706
|
+
) -> dict | str:
|
751
707
|
"""Return the mermaid graph of a specific project. Async version.
|
752
708
|
|
753
709
|
Parameters
|
@@ -776,7 +732,7 @@ class ProjectManager(Client2):
|
|
776
732
|
loop = asyncio.get_event_loop()
|
777
733
|
resp = loop.run_until_complete(
|
778
734
|
self._async_get_project_graph(project_guid, element_type, body, output_format, output_format_set)
|
779
|
-
|
735
|
+
)
|
780
736
|
|
781
737
|
return resp
|
782
738
|
|
@@ -787,7 +743,7 @@ class ProjectManager(Client2):
|
|
787
743
|
async def _async_create_project(
|
788
744
|
self,
|
789
745
|
body: dict | NewElementRequestBody,
|
790
|
-
|
746
|
+
) -> str:
|
791
747
|
"""Create project: https://egeria-project.org/concepts/project Async version.
|
792
748
|
|
793
749
|
Parameters
|
@@ -841,16 +797,15 @@ class ProjectManager(Client2):
|
|
841
797
|
|
842
798
|
"""
|
843
799
|
|
844
|
-
|
845
800
|
url = f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/project-manager/projects"
|
846
801
|
|
847
|
-
return await self._async_create_element_body_request(
|
802
|
+
return await self._async_create_element_body_request(url, ["ProjectProperties"], body)
|
848
803
|
|
849
804
|
@dynamic_catch
|
850
805
|
def create_project(
|
851
806
|
self,
|
852
807
|
body: dict | NewElementRequestBody,
|
853
|
-
|
808
|
+
) -> str:
|
854
809
|
"""Create project: https://egeria-project.org/concepts/project
|
855
810
|
|
856
811
|
Parameters
|
@@ -898,14 +853,14 @@ class ProjectManager(Client2):
|
|
898
853
|
loop = asyncio.get_event_loop()
|
899
854
|
resp = loop.run_until_complete(
|
900
855
|
self._async_create_project(body)
|
901
|
-
|
856
|
+
)
|
902
857
|
return resp
|
903
858
|
|
904
859
|
@dynamic_catch
|
905
860
|
async def _async_create_project_from_template(
|
906
861
|
self,
|
907
862
|
body: dict | TemplateRequestBody,
|
908
|
-
|
863
|
+
) -> str:
|
909
864
|
"""Create a new metadata element to represent a project using an existing metadata element as a template.
|
910
865
|
The template defines additional classifications and relationships that should be added to the new project.
|
911
866
|
Async version.
|
@@ -968,7 +923,7 @@ class ProjectManager(Client2):
|
|
968
923
|
def create_project_from_template(
|
969
924
|
self,
|
970
925
|
body: dict,
|
971
|
-
|
926
|
+
) -> str:
|
972
927
|
"""Create a new metadata element to represent a project using an existing metadata element as a template.
|
973
928
|
The template defines additional classifications and relationships that should be added to the new project.
|
974
929
|
|
@@ -1028,20 +983,12 @@ class ProjectManager(Client2):
|
|
1028
983
|
#
|
1029
984
|
#
|
1030
985
|
|
986
|
+
@dynamic_catch
|
1031
987
|
async def _async_update_project(
|
1032
988
|
self,
|
1033
989
|
project_guid: str,
|
1034
|
-
|
1035
|
-
|
1036
|
-
display_name: str = None,
|
1037
|
-
description: str = None,
|
1038
|
-
project_status: str = None,
|
1039
|
-
project_phase: str = None,
|
1040
|
-
project_health: str = None,
|
1041
|
-
start_date: str = None,
|
1042
|
-
planned_end_date: str = None,
|
1043
|
-
replace_all_props: bool = False,
|
1044
|
-
) -> None:
|
990
|
+
body: dict | UpdateElementRequestBody
|
991
|
+
) -> None:
|
1045
992
|
"""Update the properties of a project. Async Version.
|
1046
993
|
|
1047
994
|
Parameters
|
@@ -1083,42 +1030,20 @@ class ProjectManager(Client2):
|
|
1083
1030
|
The principle specified by the user_id does not have authorization for the requested action
|
1084
1031
|
"""
|
1085
1032
|
|
1086
|
-
replace_all_props_s = str(replace_all_props).lower()
|
1087
1033
|
url = (
|
1088
1034
|
f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/project-manager/projects/{project_guid}/"
|
1089
|
-
f"update
|
1035
|
+
f"update"
|
1090
1036
|
)
|
1091
1037
|
|
1092
|
-
|
1093
|
-
|
1094
|
-
"qualifiedName": qualified_name,
|
1095
|
-
"identifier": identifier,
|
1096
|
-
"name": display_name,
|
1097
|
-
"description": description,
|
1098
|
-
"projectStatus": project_status,
|
1099
|
-
"projectPhase": project_phase,
|
1100
|
-
"projectHealth": project_health,
|
1101
|
-
"startDate": start_date,
|
1102
|
-
"plannedEndDate": planned_end_date,
|
1103
|
-
}
|
1104
|
-
body_s = body_slimmer(body)
|
1105
|
-
await self._async_make_request("POST", url, body_s)
|
1106
|
-
return
|
1038
|
+
await self._async_update_element_body_request(url, ["ProjectProperties"], body)
|
1039
|
+
logger.info(f"Updated digital subscription {project_guid}")
|
1107
1040
|
|
1041
|
+
@dynamic_catch
|
1108
1042
|
def update_project(
|
1109
1043
|
self,
|
1110
1044
|
project_guid: str,
|
1111
|
-
|
1112
|
-
|
1113
|
-
display_name: str = None,
|
1114
|
-
description: str = None,
|
1115
|
-
project_status: str = None,
|
1116
|
-
project_phase: str = None,
|
1117
|
-
project_health: str = None,
|
1118
|
-
start_date: str = None,
|
1119
|
-
planned_end_date: str = None,
|
1120
|
-
replace_all_props: bool = False,
|
1121
|
-
) -> None:
|
1045
|
+
body: dict | UpdateElementRequestBody,
|
1046
|
+
) -> None:
|
1122
1047
|
"""Update the properties of a project.
|
1123
1048
|
|
1124
1049
|
Parameters
|
@@ -1161,26 +1086,12 @@ class ProjectManager(Client2):
|
|
1161
1086
|
"""
|
1162
1087
|
loop = asyncio.get_event_loop()
|
1163
1088
|
loop.run_until_complete(
|
1164
|
-
self._async_update_project(
|
1165
|
-
project_guid,
|
1166
|
-
qualified_name,
|
1167
|
-
identifier,
|
1168
|
-
display_name,
|
1169
|
-
description,
|
1170
|
-
project_status,
|
1171
|
-
project_phase,
|
1172
|
-
project_health,
|
1173
|
-
start_date,
|
1174
|
-
planned_end_date,
|
1175
|
-
replace_all_props,
|
1176
|
-
)
|
1177
|
-
)
|
1178
|
-
return
|
1089
|
+
self._async_update_project(project_guid, body))
|
1179
1090
|
|
1091
|
+
@dynamic_catch
|
1180
1092
|
async def _async_delete_project(
|
1181
1093
|
self,
|
1182
|
-
project_guid: str, cascade: bool = False
|
1183
|
-
) -> None:
|
1094
|
+
project_guid: str, cascade: bool = False, body: dict | DeleteRequestBody = None) -> None:
|
1184
1095
|
"""Delete a project. It is detected from all parent elements. Async version
|
1185
1096
|
|
1186
1097
|
Parameters
|
@@ -1207,18 +1118,16 @@ class ProjectManager(Client2):
|
|
1207
1118
|
cascade_s = str(cascade).lower()
|
1208
1119
|
url = (
|
1209
1120
|
f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/project-manager/projects/"
|
1210
|
-
f"{project_guid}/delete
|
1121
|
+
f"{project_guid}/delete"
|
1211
1122
|
)
|
1212
1123
|
|
1213
|
-
|
1214
|
-
|
1215
|
-
await self._async_make_request("POST", url, body)
|
1216
|
-
return
|
1124
|
+
await self._async_delete_request(url, body, cascade)
|
1125
|
+
logger.info(f"Deleted project {project_guid} with cascade {cascade}")
|
1217
1126
|
|
1127
|
+
@dynamic_catch
|
1218
1128
|
def delete_project(
|
1219
1129
|
self,
|
1220
|
-
project_guid: str, cascade: bool = False
|
1221
|
-
) -> None:
|
1130
|
+
project_guid: str, cascade: bool = False, body: dict | DeleteRequestBody = None) -> None:
|
1222
1131
|
"""Delete a project. It is detected from all parent elements.
|
1223
1132
|
|
1224
1133
|
Parameters
|
@@ -1247,40 +1156,30 @@ class ProjectManager(Client2):
|
|
1247
1156
|
|
1248
1157
|
"""
|
1249
1158
|
loop = asyncio.get_event_loop()
|
1250
|
-
loop.run_until_complete(self._async_delete_project(project_guid, cascade))
|
1251
|
-
return
|
1159
|
+
loop.run_until_complete(self._async_delete_project(project_guid, cascade, body))
|
1252
1160
|
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
effective_to: str = None,
|
1260
|
-
) -> None:
|
1261
|
-
"""Add an actor to a project. The request body is optional. If supplied, it contains the name of the role that
|
1262
|
-
the actor plays in the project. Async version.
|
1161
|
+
@dynamic_catch
|
1162
|
+
async def _async_set_project_dependency(self, project_guid: str,
|
1163
|
+
upstream_project_guid: str,
|
1164
|
+
body: dict | NewRelationshipRequestBody = None):
|
1165
|
+
""" A project depends on an upstream project.
|
1166
|
+
Request body is optional. Async version.
|
1263
1167
|
|
1264
1168
|
Parameters
|
1265
1169
|
----------
|
1170
|
+
upstream_project_guid: str
|
1171
|
+
The guid of the project depended on.
|
1266
1172
|
project_guid: str
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
team_role: str, optional, defaults to None
|
1271
|
-
Name of the role the actor plays in the project.
|
1272
|
-
effective_from: str, optional, defaults to None
|
1273
|
-
Date at which the actor becomes active in the project. Date format is ISO 8601 string format.
|
1274
|
-
effective_to: str, optional, defaults to None
|
1275
|
-
Date at which the actor is no longer active in the project. Date format is ISO 8601 string format.
|
1173
|
+
The guid of the dependent project
|
1174
|
+
body: dict | NewRelationshipRequestBody, optional, default = None
|
1175
|
+
A dict representing the details of the relationship.
|
1276
1176
|
|
1277
1177
|
Returns
|
1278
1178
|
-------
|
1279
|
-
|
1179
|
+
Nothing
|
1280
1180
|
|
1281
1181
|
Raises
|
1282
1182
|
------
|
1283
|
-
|
1284
1183
|
InvalidParameterException
|
1285
1184
|
If the client passes incorrect parameters on the request - such as bad URLs or invalid values
|
1286
1185
|
PropertyServerException
|
@@ -1288,56 +1187,122 @@ class ProjectManager(Client2):
|
|
1288
1187
|
NotAuthorizedException
|
1289
1188
|
The principle specified by the user_id does not have authorization for the requested action
|
1290
1189
|
|
1291
|
-
|
1190
|
+
Notes
|
1191
|
+
-----
|
1292
1192
|
|
1193
|
+
"""
|
1293
1194
|
url = (
|
1294
|
-
f"{self.
|
1295
|
-
f"members/{actor_guid}/attach"
|
1195
|
+
f"{self.project_command_base}/{project_guid}/project-dependencies/{upstream_project_guid}/attach"
|
1296
1196
|
)
|
1297
|
-
|
1298
|
-
|
1299
|
-
"teamRole": team_role,
|
1300
|
-
"effectiveFrom": effective_from,
|
1301
|
-
"effectiveTo": effective_to,
|
1302
|
-
}
|
1303
|
-
body_s = body_slimmer(body)
|
1304
|
-
if body_s is None:
|
1305
|
-
await self._async_make_request("POST", url)
|
1306
|
-
else:
|
1307
|
-
await self._async_make_request("POST", url, body_s)
|
1308
|
-
return
|
1197
|
+
await self._async_new_relationship_request(url, "ProjectDependencyProperties", body)
|
1198
|
+
logger.info(f"Project {project_guid} depends on -> {upstream_project_guid}")
|
1309
1199
|
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1200
|
+
@dynamic_catch
|
1201
|
+
async def _async_set_project_dependency(self, project_guid: str,
|
1202
|
+
upstream_project_guid: str,
|
1203
|
+
body: dict | NewRelationshipRequestBody = None):
|
1204
|
+
""" Link two dependent digital products. The linked elements are of type DigitalProduct.
|
1205
|
+
Request body is optional.
|
1206
|
+
|
1207
|
+
Parameters
|
1208
|
+
----------
|
1209
|
+
upstream_digital_prod_guid: str
|
1210
|
+
The guid of the first digital product
|
1211
|
+
downstream_digital_prod_guid: str
|
1212
|
+
The guid of the downstream digital product
|
1213
|
+
body: dict | NewRelationshipRequestBody, optional, default = None
|
1214
|
+
A structure representing the details of the relationship.
|
1215
|
+
|
1216
|
+
Returns
|
1217
|
+
-------
|
1218
|
+
Nothing
|
1219
|
+
|
1220
|
+
Raises
|
1221
|
+
------
|
1222
|
+
InvalidParameterException
|
1223
|
+
If the client passes incorrect parameters on the request - such as bad URLs or invalid values
|
1224
|
+
PropertyServerException
|
1225
|
+
Raised by the server when an issue arises in processing a valid request
|
1226
|
+
NotAuthorizedException
|
1227
|
+
The principle specified by the user_id does not have authorization for the requested action
|
1228
|
+
|
1229
|
+
Notes
|
1230
|
+
-----
|
1231
|
+
|
1232
|
+
"""
|
1233
|
+
loop = asyncio.get_event_loop()
|
1234
|
+
loop.run_until_complete(
|
1235
|
+
self._async_set_project_dependency(project_guid, upstream_project_guid,
|
1236
|
+
body))
|
1237
|
+
|
1238
|
+
@dynamic_catch
|
1239
|
+
async def _async_clear_project_dependency(self, project_guid: str,
|
1240
|
+
upstream_project_guid: str,
|
1241
|
+
body: dict | DeleteRequestBody = None) -> None:
|
1242
|
+
""" Unlink two dependent projects. Request body is optional. Async version.
|
1320
1243
|
|
1321
1244
|
Parameters
|
1322
1245
|
----------
|
1323
1246
|
project_guid: str
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
effective_from: str, optional, defaults to None
|
1330
|
-
Date at which the actor becomes active in the project. Date format is ISO 8601 string format.
|
1331
|
-
effective_to: str, optional, defaults to None
|
1332
|
-
Date at which the actor is no longer active in the project. Date format is ISO 8601 string format.
|
1247
|
+
The guid of the dependent project.
|
1248
|
+
upstream_project_guid: str
|
1249
|
+
The guid of the upstream digital project
|
1250
|
+
body: dict | DeleteRequestBody, optional, default = None
|
1251
|
+
A structure representing the details of the relationship.
|
1333
1252
|
|
1334
1253
|
Returns
|
1335
1254
|
-------
|
1336
|
-
|
1255
|
+
Nothing
|
1337
1256
|
|
1338
1257
|
Raises
|
1339
1258
|
------
|
1259
|
+
InvalidParameterException
|
1260
|
+
If the client passes incorrect parameters on the request - such as bad URLs or invalid values
|
1261
|
+
PropertyServerException
|
1262
|
+
Raised by the server when an issue arises in processing a valid request
|
1263
|
+
NotAuthorizedException
|
1264
|
+
The principle specified by the user_id does not have authorization for the requested action
|
1340
1265
|
|
1266
|
+
Notes
|
1267
|
+
-----
|
1268
|
+
JSON Structure looks like:
|
1269
|
+
{
|
1270
|
+
"class": "DeleteRequestBody",
|
1271
|
+
"externalSourceGUID": "add guid here",
|
1272
|
+
"externalSourceName": "add qualified name here",
|
1273
|
+
"effectiveTime": "{{$isoTimestamp}}",
|
1274
|
+
"forLineage": false,
|
1275
|
+
"forDuplicateProcessing": false
|
1276
|
+
}
|
1277
|
+
|
1278
|
+
"""
|
1279
|
+
|
1280
|
+
url = "{self.project_command_base}/{project_guid}/project-dependencies/{upstream_project_guid}/detach"
|
1281
|
+
|
1282
|
+
await self._async_delete_request(url, body)
|
1283
|
+
logger.info(
|
1284
|
+
f"Detached project {project_guid} from -> {upstream_project_guid}")
|
1285
|
+
|
1286
|
+
@dynamic_catch
|
1287
|
+
def clear_project_dependency(self, project_guid: str, upstream_project_guid: str,
|
1288
|
+
body: dict | DeleteRequestBody = None):
|
1289
|
+
""" Unlink two dependent projects. Request body is optional.
|
1290
|
+
|
1291
|
+
Parameters
|
1292
|
+
----------
|
1293
|
+
project_guid: str
|
1294
|
+
The guid of the dependent project.
|
1295
|
+
upstream_project_guid: str
|
1296
|
+
The guid of the upstream digital project
|
1297
|
+
body: dict | DeleteRequestBody, optional, default = None
|
1298
|
+
A structure representing the details of the relationship.
|
1299
|
+
|
1300
|
+
Returns
|
1301
|
+
-------
|
1302
|
+
Nothing
|
1303
|
+
|
1304
|
+
Raises
|
1305
|
+
------
|
1341
1306
|
InvalidParameterException
|
1342
1307
|
If the client passes incorrect parameters on the request - such as bad URLs or invalid values
|
1343
1308
|
PropertyServerException
|
@@ -1345,40 +1310,45 @@ class ProjectManager(Client2):
|
|
1345
1310
|
NotAuthorizedException
|
1346
1311
|
The principle specified by the user_id does not have authorization for the requested action
|
1347
1312
|
|
1313
|
+
Notes
|
1314
|
+
-----
|
1315
|
+
JSON Structure looks like:
|
1316
|
+
{
|
1317
|
+
"class": "DeleteRequestBody",
|
1318
|
+
"externalSourceGUID": "add guid here",
|
1319
|
+
"externalSourceName": "add qualified name here",
|
1320
|
+
"effectiveTime": "{{$isoTimestamp}}",
|
1321
|
+
"forLineage": false,
|
1322
|
+
"forDuplicateProcessing": false
|
1323
|
+
}
|
1348
1324
|
"""
|
1349
1325
|
loop = asyncio.get_event_loop()
|
1350
1326
|
loop.run_until_complete(
|
1351
|
-
self.
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
return
|
1327
|
+
self._async_clear_project_dependency(project_guid, upstream_project_guid, body))
|
1328
|
+
|
1329
|
+
@dynamic_catch
|
1330
|
+
async def _async_set_project_hierarchy(self, project_guid: str,
|
1331
|
+
parent_project_guid: str,
|
1332
|
+
body: dict | NewRelationshipRequestBody = None):
|
1333
|
+
""" Set a hierarchy relationship between two projects.
|
1334
|
+
Request body is optional. Async version.
|
1360
1335
|
|
1361
|
-
async def _async_remove_from_project_team(
|
1362
|
-
self,
|
1363
|
-
project_guid: str,
|
1364
|
-
actor_guid: str,
|
1365
|
-
) -> None:
|
1366
|
-
"""Remove an actor from a project. Async version.
|
1367
1336
|
|
1368
1337
|
Parameters
|
1369
1338
|
----------
|
1339
|
+
parent_project_guid: str
|
1340
|
+
The guid of the project depended on.
|
1370
1341
|
project_guid: str
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1342
|
+
The guid of the dependent project
|
1343
|
+
body: dict | NewRelationshipRequestBody, optional, default = None
|
1344
|
+
A dict representing the details of the relationship.
|
1374
1345
|
|
1375
1346
|
Returns
|
1376
1347
|
-------
|
1377
|
-
|
1348
|
+
Nothing
|
1378
1349
|
|
1379
1350
|
Raises
|
1380
1351
|
------
|
1381
|
-
|
1382
1352
|
InvalidParameterException
|
1383
1353
|
If the client passes incorrect parameters on the request - such as bad URLs or invalid values
|
1384
1354
|
PropertyServerException
|
@@ -1386,38 +1356,122 @@ class ProjectManager(Client2):
|
|
1386
1356
|
NotAuthorizedException
|
1387
1357
|
The principle specified by the user_id does not have authorization for the requested action
|
1388
1358
|
|
1389
|
-
|
1359
|
+
Notes
|
1360
|
+
-----
|
1390
1361
|
|
1362
|
+
"""
|
1391
1363
|
url = (
|
1392
|
-
f"{self.
|
1393
|
-
f"members/{actor_guid}/detach"
|
1364
|
+
f"{self.project_command_base}/{parent_project_guid}/project-dependencies/{project_guid}/attach"
|
1394
1365
|
)
|
1366
|
+
await self._async_new_relationship_request(url, ["ProjectHierarchyProperties"], body)
|
1367
|
+
logger.info(f"Project {project_guid} managed by -> {parent_project_guid}")
|
1395
1368
|
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1369
|
+
@dynamic_catch
|
1370
|
+
def set_project_hierarchy(self, project_guid: str,
|
1371
|
+
parent_project_guid: str,
|
1372
|
+
body: dict | NewRelationshipRequestBody = None):
|
1373
|
+
""" Link two dependent digital products. The linked elements are of type DigitalProduct.
|
1374
|
+
Request body is optional.
|
1399
1375
|
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1376
|
+
Parameters
|
1377
|
+
----------
|
1378
|
+
upstream_digital_prod_guid: str
|
1379
|
+
The guid of the first digital product
|
1380
|
+
downstream_digital_prod_guid: str
|
1381
|
+
The guid of the downstream digital product
|
1382
|
+
body: dict | NewRelationshipRequestBody, optional, default = None
|
1383
|
+
A structure representing the details of the relationship.
|
1384
|
+
|
1385
|
+
Returns
|
1386
|
+
-------
|
1387
|
+
Nothing
|
1388
|
+
|
1389
|
+
Raises
|
1390
|
+
------
|
1391
|
+
InvalidParameterException
|
1392
|
+
If the client passes incorrect parameters on the request - such as bad URLs or invalid values
|
1393
|
+
PropertyServerException
|
1394
|
+
Raised by the server when an issue arises in processing a valid request
|
1395
|
+
NotAuthorizedException
|
1396
|
+
The principle specified by the user_id does not have authorization for the requested action
|
1397
|
+
|
1398
|
+
Notes
|
1399
|
+
-----
|
1400
|
+
|
1401
|
+
"""
|
1402
|
+
loop = asyncio.get_event_loop()
|
1403
|
+
loop.run_until_complete(
|
1404
|
+
self._async_set_project_hierarchy(project_guid, parent_project_guid,
|
1405
|
+
body))
|
1406
|
+
|
1407
|
+
@dynamic_catch
|
1408
|
+
async def _async_clear_project_hierarchy(self, project_guid: str,
|
1409
|
+
parent_project_guid: str,
|
1410
|
+
body: dict | DeleteRequestBody = None) -> None:
|
1411
|
+
""" Unlink hierarchy relationship. Request body is optional. Async version.
|
1406
1412
|
|
1407
1413
|
Parameters
|
1408
1414
|
----------
|
1409
1415
|
project_guid: str
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1416
|
+
The guid of the dependent project.
|
1417
|
+
parent_project_guid: str
|
1418
|
+
The guid of the upstream digital project
|
1419
|
+
body: dict | DeleteRequestBody, optional, default = None
|
1420
|
+
A structure representing the details of the relationship.
|
1413
1421
|
|
1414
1422
|
Returns
|
1415
1423
|
-------
|
1416
|
-
|
1424
|
+
Nothing
|
1417
1425
|
|
1418
1426
|
Raises
|
1419
1427
|
------
|
1428
|
+
InvalidParameterException
|
1429
|
+
If the client passes incorrect parameters on the request - such as bad URLs or invalid values
|
1430
|
+
PropertyServerException
|
1431
|
+
Raised by the server when an issue arises in processing a valid request
|
1432
|
+
NotAuthorizedException
|
1433
|
+
The principle specified by the user_id does not have authorization for the requested action
|
1420
1434
|
|
1435
|
+
Notes
|
1436
|
+
-----
|
1437
|
+
JSON Structure looks like:
|
1438
|
+
{
|
1439
|
+
"class": "DeleteRequestBody",
|
1440
|
+
"externalSourceGUID": "add guid here",
|
1441
|
+
"externalSourceName": "add qualified name here",
|
1442
|
+
"effectiveTime": "{{$isoTimestamp}}",
|
1443
|
+
"forLineage": false,
|
1444
|
+
"forDuplicateProcessing": false
|
1445
|
+
}
|
1446
|
+
|
1447
|
+
"""
|
1448
|
+
|
1449
|
+
url = "{self.project_command_base}/{parent_project_guid}/project-dependencies/{project_guid}/detach"
|
1450
|
+
|
1451
|
+
await self._async_delete_request(url, body)
|
1452
|
+
logger.info(
|
1453
|
+
f"Detached project {project_guid} from -> {parent_project_guid}")
|
1454
|
+
|
1455
|
+
@dynamic_catch
|
1456
|
+
def clear_project_hierarchy(self, project_guid: str, parent_project_guid: str,
|
1457
|
+
body: dict | DeleteRequestBody = None):
|
1458
|
+
""" Unlink two dependent projects. Request body is optional.
|
1459
|
+
|
1460
|
+
Parameters
|
1461
|
+
----------
|
1462
|
+
project_guid: str
|
1463
|
+
The guid of the dependent project.
|
1464
|
+
parent_project_guid: str
|
1465
|
+
The guid of the upstream digital project
|
1466
|
+
body: dict | DeleteRequestBody, optional, default = None
|
1467
|
+
A structure representing the details of the relationship.
|
1468
|
+
|
1469
|
+
Returns
|
1470
|
+
-------
|
1471
|
+
Nothing
|
1472
|
+
|
1473
|
+
Raises
|
1474
|
+
------
|
1421
1475
|
InvalidParameterException
|
1422
1476
|
If the client passes incorrect parameters on the request - such as bad URLs or invalid values
|
1423
1477
|
PropertyServerException
|
@@ -1425,28 +1479,46 @@ class ProjectManager(Client2):
|
|
1425
1479
|
NotAuthorizedException
|
1426
1480
|
The principle specified by the user_id does not have authorization for the requested action
|
1427
1481
|
|
1482
|
+
Notes
|
1483
|
+
-----
|
1484
|
+
JSON Structure looks like:
|
1485
|
+
{
|
1486
|
+
"class": "DeleteRequestBody",
|
1487
|
+
"externalSourceGUID": "add guid here",
|
1488
|
+
"externalSourceName": "add qualified name here",
|
1489
|
+
"effectiveTime": "{{$isoTimestamp}}",
|
1490
|
+
"forLineage": false,
|
1491
|
+
"forDuplicateProcessing": false
|
1492
|
+
}
|
1428
1493
|
"""
|
1429
1494
|
loop = asyncio.get_event_loop()
|
1430
1495
|
loop.run_until_complete(
|
1431
|
-
self.
|
1432
|
-
)
|
1433
|
-
return
|
1496
|
+
self._async_clear_project_hierarchy(project_guid, parent_project_guid, body))
|
1434
1497
|
|
1435
|
-
|
1498
|
+
@dynamic_catch
|
1499
|
+
async def _async_add_to_project_team(
|
1436
1500
|
self,
|
1437
1501
|
project_guid: str,
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1502
|
+
actor_guid: str,
|
1503
|
+
assignment_type: str = None,
|
1504
|
+
description: str = None,
|
1505
|
+
body: dict | NewRelationshipRequestBody = None
|
1506
|
+
) -> None:
|
1507
|
+
"""Add an actor to a project. The request body is optional. If supplied, it contains the name of the role that
|
1508
|
+
the actor plays in the project. Async version.
|
1442
1509
|
|
1443
1510
|
Parameters
|
1444
1511
|
----------
|
1445
1512
|
project_guid: str
|
1446
|
-
identity of the project.
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1513
|
+
identity of the project to update.
|
1514
|
+
actor_guid: str
|
1515
|
+
identity of the actor to add.
|
1516
|
+
team_role: str, optional, defaults to None
|
1517
|
+
Name of the role the actor plays in the project.
|
1518
|
+
effective_from: str, optional, defaults to None
|
1519
|
+
Date at which the actor becomes active in the project. Date format is ISO 8601 string format.
|
1520
|
+
effective_to: str, optional, defaults to None
|
1521
|
+
Date at which the actor is no longer active in the project. Date format is ISO 8601 string format.
|
1450
1522
|
|
1451
1523
|
Returns
|
1452
1524
|
-------
|
@@ -1466,28 +1538,46 @@ class ProjectManager(Client2):
|
|
1466
1538
|
|
1467
1539
|
url = (
|
1468
1540
|
f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/project-manager/projects/{project_guid}/"
|
1469
|
-
f"
|
1541
|
+
f"members/{actor_guid}/attach"
|
1470
1542
|
)
|
1543
|
+
if body is None:
|
1544
|
+
body = {
|
1545
|
+
"class": "NewRelationshipRequestBody",
|
1546
|
+
"properties": {
|
1547
|
+
"class": "AssignmentScopeProperties",
|
1548
|
+
"description": description,
|
1549
|
+
"assignmentType": assignment_type,
|
1550
|
+
}
|
1551
|
+
}
|
1552
|
+
body_s = body_slimmer(body)
|
1471
1553
|
|
1472
|
-
|
1473
|
-
|
1474
|
-
return
|
1554
|
+
await self._async_new_relationship_request(url, ["AssignmentScopeRelationship"], body)
|
1555
|
+
logger.info(f"Added member {actor_guid} to project {project_guid}")
|
1475
1556
|
|
1476
|
-
|
1557
|
+
@dynamic_catch
|
1558
|
+
def add_to_project_team(
|
1477
1559
|
self,
|
1478
1560
|
project_guid: str,
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1561
|
+
actor_guid: str,
|
1562
|
+
assignment_type: str = None,
|
1563
|
+
description: str = None,
|
1564
|
+
body: dict | NewRelationshipRequestBody = None
|
1565
|
+
) -> None:
|
1566
|
+
"""Add an actor to a project. The request body is optional. If supplied, it contains the name of the role that
|
1567
|
+
the actor plays in the project.
|
1483
1568
|
|
1484
1569
|
Parameters
|
1485
1570
|
----------
|
1486
1571
|
project_guid: str
|
1487
|
-
identity of the project.
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1572
|
+
identity of the project to update.
|
1573
|
+
actor_guid: str
|
1574
|
+
identity of the actor to add.
|
1575
|
+
team_role: str, optional, defaults to None
|
1576
|
+
Name of the role the actor plays in the project.
|
1577
|
+
effective_from: str, optional, defaults to None
|
1578
|
+
Date at which the actor becomes active in the project. Date format is ISO 8601 string format.
|
1579
|
+
effective_to: str, optional, defaults to None
|
1580
|
+
Date at which the actor is no longer active in the project. Date format is ISO 8601 string format.
|
1491
1581
|
|
1492
1582
|
Returns
|
1493
1583
|
-------
|
@@ -1506,24 +1596,30 @@ class ProjectManager(Client2):
|
|
1506
1596
|
"""
|
1507
1597
|
loop = asyncio.get_event_loop()
|
1508
1598
|
loop.run_until_complete(
|
1509
|
-
self.
|
1599
|
+
self._async_add_to_project_team(
|
1600
|
+
project_guid,
|
1601
|
+
actor_guid,
|
1602
|
+
assignment_type,
|
1603
|
+
description,
|
1604
|
+
body,
|
1510
1605
|
)
|
1511
|
-
|
1606
|
+
)
|
1512
1607
|
|
1513
|
-
|
1608
|
+
@dynamic_catch
|
1609
|
+
async def _async_remove_from_project_team(
|
1514
1610
|
self,
|
1515
1611
|
project_guid: str,
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1612
|
+
actor_guid: str,
|
1613
|
+
body: dict | DeleteRequestBody = None
|
1614
|
+
) -> None:
|
1615
|
+
"""Remove an actor from a project. Async version.
|
1519
1616
|
|
1520
1617
|
Parameters
|
1521
1618
|
----------
|
1522
1619
|
project_guid: str
|
1523
|
-
identity of the project.
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1620
|
+
identity of the project to remove members from.
|
1621
|
+
actor_guid: str
|
1622
|
+
identity of the actor to remove.
|
1527
1623
|
|
1528
1624
|
Returns
|
1529
1625
|
-------
|
@@ -1543,27 +1639,27 @@ class ProjectManager(Client2):
|
|
1543
1639
|
|
1544
1640
|
url = (
|
1545
1641
|
f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/project-manager/projects/{project_guid}/"
|
1546
|
-
f"
|
1642
|
+
f"members/{actor_guid}/detach"
|
1547
1643
|
)
|
1548
1644
|
|
1549
|
-
|
1550
|
-
|
1551
|
-
return
|
1645
|
+
await self._async_delete_request(url, body)
|
1646
|
+
logger.info(f"Removed member {actor_guid} from project {project_guid}")
|
1552
1647
|
|
1553
|
-
|
1648
|
+
@dynamic_catch
|
1649
|
+
def remove_from_project_team(
|
1554
1650
|
self,
|
1555
1651
|
project_guid: str,
|
1556
|
-
|
1557
|
-
|
1558
|
-
|
1652
|
+
actor_guid: str,
|
1653
|
+
body: dict | DeleteRequestBody = None
|
1654
|
+
) -> None:
|
1655
|
+
"""Remove an actor from a project.
|
1559
1656
|
|
1560
1657
|
Parameters
|
1561
1658
|
----------
|
1562
1659
|
project_guid: str
|
1563
1660
|
identity of the project.
|
1564
|
-
|
1565
|
-
|
1566
|
-
|
1661
|
+
actor_guid: str
|
1662
|
+
identity of the actor to remove.
|
1567
1663
|
|
1568
1664
|
Returns
|
1569
1665
|
-------
|
@@ -1582,9 +1678,34 @@ class ProjectManager(Client2):
|
|
1582
1678
|
"""
|
1583
1679
|
loop = asyncio.get_event_loop()
|
1584
1680
|
loop.run_until_complete(
|
1585
|
-
self.
|
1586
|
-
|
1587
|
-
|
1681
|
+
self._async_remove_from_project_team(project_guid, actor_guid, body)
|
1682
|
+
)
|
1683
|
+
|
1684
|
+
@dynamic_catch
|
1685
|
+
async def _async_create_task_for_project(
|
1686
|
+
self,
|
1687
|
+
project_guid: str,
|
1688
|
+
body: dict | NewElementRequestBody
|
1689
|
+
) -> str:
|
1690
|
+
"""Create a new task for a project. Async version."""
|
1691
|
+
|
1692
|
+
url = f"{self.project_command_base}/{project_guid}/task"
|
1693
|
+
response = await self._async_new_element_request(url, body)
|
1694
|
+
logger.info(f"Created task for project {project_guid}")
|
1695
|
+
return response
|
1696
|
+
|
1697
|
+
@dynamic_catch
|
1698
|
+
def create_task_for_project(
|
1699
|
+
self,
|
1700
|
+
project_guid: str,
|
1701
|
+
body: dict | NewElementRequestBody
|
1702
|
+
) -> str:
|
1703
|
+
"""Create a new task for a project. """
|
1704
|
+
loop = asyncio.get_event_loop()
|
1705
|
+
resp = loop.run_until_complete(
|
1706
|
+
self._async_create_task_for_project(project_guid, body)
|
1707
|
+
)
|
1708
|
+
return resp
|
1588
1709
|
|
1589
1710
|
|
1590
1711
|
if __name__ == "__main__":
|