pyegeria 5.4.0.19__py3-none-any.whl → 5.4.0.22__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.
@@ -9,34 +9,33 @@ Copyright Contributors to the ODPi Egeria project.
9
9
  import asyncio
10
10
  import inspect
11
11
  from datetime import datetime
12
- from typing import Dict, Union, List, Optional, Annotated, Literal
12
+ from typing import Optional, Annotated, Literal
13
13
 
14
- import pydantic_core
15
- # from jsonschema import ValidationError
16
14
  from loguru import logger
17
- from pydantic import BaseModel, ValidationError, TypeAdapter, Field
15
+ from pydantic import ValidationError, Field, HttpUrl
18
16
 
19
- from pyegeria._exceptions_new import PyegeriaInvalidParameterException, PyegeriaException
20
- from pyegeria._output_formats import select_output_format_set, get_output_format_type_match
21
- from pyegeria._client import Client
17
+ from pyegeria._exceptions_new import PyegeriaInvalidParameterException
22
18
  from pyegeria._globals import NO_ELEMENTS_FOUND, NO_GUID_RETURNED, NO_MEMBERS_FOUND
23
- from pyegeria._validators import validate_guid, validate_search_string
24
- from pyegeria.output_formatter import (generate_output,
25
- _extract_referenceable_properties)
26
- from pyegeria.utils import body_slimmer, dynamic_catch
19
+ from pyegeria._output_formats import select_output_format_set, get_output_format_type_match
20
+ from pyegeria.load_config import get_app_config
27
21
  from pyegeria.models import (SearchStringRequestBody, FilterRequestBody, GetRequestBody, NewElementRequestBody,
28
22
  ReferenceableProperties, InitialClassifications, TemplateRequestBody,
29
23
  UpdateElementRequestBody, UpdateStatusRequestBody, NewRelationshipRequestBody,
30
- DeleteRequestBody)
31
- from pyegeria.load_config import get_app_config
24
+ DeleteRequestBody, UpdateRelationshipRequestBody, ResultsRequestBody)
25
+ from pyegeria.output_formatter import (generate_output,
26
+ _extract_referenceable_properties)
27
+ from pyegeria.utils import body_slimmer, dynamic_catch
28
+
32
29
 
33
30
  app_settings = get_app_config()
34
31
  EGERIA_LOCAL_QUALIFIER = app_settings.User_Profile.egeria_local_qualifier
35
32
 
36
- COLLECTION_PROPERTIES_LIST = ["CollectionPropertie", "DataDictionaryProperties",
33
+ COLLECTION_PROPERTIES_LIST = ["CollectionProperties", "DataDictionaryProperties",
37
34
  "DataSpecProperties", "DigitalProductProperties",
38
35
  "AgreementProperties"]
39
36
 
37
+ AGREEMENT_PROPERTIES_LIST = ["AgreementProperties", "DigitalSubscriptionProperties",]
38
+
40
39
 
41
40
  def query_seperator(current_string):
42
41
  if current_string == "":
@@ -260,163 +259,22 @@ class CollectionManager(Client2):
260
259
 
261
260
 
262
261
  @dynamic_catch
263
- async def _async_find_collections_w_body(self, body: dict | SearchStringRequestBody,
264
- output_format: str = 'JSON',
265
- output_format_set: str | dict = None) -> list | str:
266
- """ Returns the list of collections matching the search string filtered by the optional classification.
267
- The search string is located in the request body and is interpreted as a plain string. The full
268
- body allows complete control including status, asOfTime and effectiveTime.
269
- The request parameters, startsWith, endsWith and ignoreCase can be used to allow a fuzzy search.
270
-
271
- Parameters
272
- ----------
273
- body: dict
274
- Details of the search request - see the notes below for details.
275
- output_format: str, default = "JSON"
276
- - one of "MD", "LIST", "FORM", "REPORT", "DICT", "MERMAID" or "JSON"
277
- output_format_set: str | dict , optional, default = None
278
- - The desired output columns/field options.
279
- Returns
280
- -------
281
- List | str
282
-
283
- A list of collections match matching the search string. Returns a string if none found.
284
-
285
- Raises
286
- ------
287
-
288
- InvalidParameterException
289
- If the client passes incorrect parameters on the request - such as bad URLs or invalid values
290
- PropertyServerException
291
- Raised by the server when an issue arises in processing a valid request
292
- NotAuthorizedException
293
- The principle specified by the user_id does not have authorization for the requested action
294
-
295
- Notes
296
- -----
297
-
298
- {
299
- "class" : "SearchStringRequestBody",
300
- "searchString" : "Data Product Development Journey",
301
- "includeOnlyClassifiedElements" : ["RootCollection"],
302
- "startsWith" : false,
303
- "endsWith" : false,
304
- "ignoreCase" : true,
305
- "startFrom" : 0,
306
- "pageSize": 0,
307
- "asOfTime" : "{{$isoTimestamp}}",
308
- "effectiveTime" : "{{$isoTimestamp}}",
309
- "forLineage" : false,
310
- "forDuplicateProcessing" : false,
311
- "limitResultsByStatus" : ["ACTIVE"],
312
- "sequencingOrder" : "PROPERTY_ASCENDING",
313
- "sequencingProperty" : "qualifiedName"
314
- }
315
- """
316
- if isinstance(body, SearchStringRequestBody):
317
- validated_body = body
318
- elif isinstance(body, dict):
319
- try:
320
- validated_body = self._search_string_request_adapter.validate_python(body)
321
- except ValidationError as e:
322
- context: dict = {
323
- 'class name': __class__.__name__, 'caller method': inspect.currentframe().f_back.f_code.co_name
324
- }
325
- raise PyegeriaInvalidParameterException(context = context, Exception = e)
326
- else:
327
- raise TypeError("Invalid parameter type")
328
-
329
- val_json = validated_body.model_dump_json()
330
-
331
- url = f"{self.collection_command_root}/by-search-string"
332
- classification_name = validated_body.include_only_classified_elements
333
-
334
- response = await self._async_make_request("POST", url, val_json)
335
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
336
- if type(elements) is str:
337
- logger.info(NO_ELEMENTS_FOUND)
338
- return NO_ELEMENTS_FOUND
339
-
340
- if output_format != 'JSON': # return a simplified markdown representation
341
- # logger.info(f"Found elements, output format: {output_format} and output_format_set: {output_format_set}")
342
- return self._generate_collection_output(elements, None, classification_name,
343
- output_format, output_format_set)
344
- return elements
345
-
346
- @dynamic_catch
347
- def find_collections_w_body(self, body: dict | SearchStringRequestBody, output_format: str = 'JSON',
348
- output_format_set: str | dict = None) -> list | str:
349
- """ Returns the list of collections matching the search string filtered by the optional classification.
350
- The search string is located in the request body and is interpreted as a plain string. The full
351
- body allows complete control including status, asOfTime and effectiveTime.
352
- The request parameters, startsWith, endsWith and ignoreCase can be used to allow a fuzzy search.
353
-
354
- Parameters
355
- ----------
356
- body: dict
357
- Details of the search request - see the notes below for details.
358
- output_format: str, default = "JSON"
359
- - one of "MD", "LIST", "FORM", "REPORT", "DICT", "MERMAID" or "JSON"
360
- output_format_set: str | dict , optional, default = None
361
- - The desired output columns/field options.
362
- Returns
363
- -------
364
- List | str
365
-
366
- A list of collections match matching the search string. Returns a string if none found.
367
-
368
- Raises
369
- ------
370
-
371
- InvalidParameterException
372
- If the client passes incorrect parameters on the request - such as bad URLs or invalid values
373
- PropertyServerException
374
- Raised by the server when an issue arises in processing a valid request
375
- NotAuthorizedException
376
- The principle specified by the user_id does not have authorization for the requested action
377
-
378
- Notes
379
- -----
380
-
381
- {
382
- "class" : "SearchStringRequestBody",
383
- "searchString" : "Data Product Development Journey",
384
- "includeOnlyClassifiedElements" : ["RootCollection"],
385
- "startsWith" : false,
386
- "endsWith" : false,
387
- "ignoreCase" : true,
388
- "startFrom" : 0,
389
- "pageSize": 0,
390
- "asOfTime" : "{{$isoTimestamp}}",
391
- "effectiveTime" : "{{$isoTimestamp}}",
392
- "forLineage" : false,
393
- "forDuplicateProcessing" : false,
394
- "limitResultsByStatus" : ["ACTIVE"],
395
- "sequencingOrder" : "PROPERTY_ASCENDING",
396
- "sequencingProperty" : "qualifiedName"
397
- }
398
- """
399
- return asyncio.get_event_loop().run_until_complete(
400
- self._async_find_collections_w_body(body, output_format, output_format_set))
401
-
402
-
403
- @dynamic_catch
404
- async def _async_find_collections(self, search_string: str = '*', classification_name: str = None,
262
+ async def _async_find_collections(self, search_string: str = '*', classification_names: list[str] = None,
405
263
  starts_with: bool = True, ends_with: bool = False, ignore_case: bool = False,
406
264
  start_from: int = 0, page_size: int = 0, output_format: str = 'JSON',
407
- output_format_set: str | dict = None) -> list | str:
265
+ output_format_set: str | dict = None,
266
+ body: dict | SearchStringRequestBody = None) -> list | str:
408
267
  """ Returns the list of collections matching the search string filtered by the optional classification.
409
- The search string is located in the request body and is interpreted as a plain string. The full
410
- body allows complete control including status, asOfTime and effectiveTime.
411
- The request parameters, startsWith, endsWith and ignoreCase can be used to allow a fuzzy search.
268
+ This method can either be used with a body, allowing full control, or with the individual parameters.
269
+ If the body is provided it will be used and the search_string will be ignored.
412
270
 
413
271
  Parameters
414
272
  ----------
415
273
  search_string: str
416
274
  Search string to match against - None or '*' indicate match against all collections (may be filtered by
417
275
  classification).
418
- classification_name: str, optional, default=None
419
- A classification name to filter on - for example, DataSpec for data specifications. If none,
276
+ initial_classifications: list[str], optional, default=None
277
+ A list of classification names to filter on - for example, ["DataSpec"], for data specifications. If none,
420
278
  then all classifications are returned.
421
279
  starts_with : bool, [default=False], optional
422
280
  Starts with the supplied string.
@@ -431,57 +289,56 @@ class CollectionManager(Client2):
431
289
  the class instance.
432
290
  output_format: str, default = "JSON"
433
291
  - one of "MD", "LIST", "FORM", "REPORT", "DICT", "MERMAID" or "JSON"
434
- output_format_set: str | dict , optional, default = None
292
+ output_format_set: str | dict , optional, default = None
435
293
  - The desired output columns/fields to include.
294
+ body: dict | SearchStringRequestBody, optional, default = None
295
+ - if provided, the search parameters in the body will supercede other attributes, such as "search_string"
296
+
436
297
  Returns
437
298
  -------
438
299
  List | str
439
300
 
440
- A list of collections match matching the search string. Returns a string if none found.
301
+ Output depends on the output format specified.
441
302
 
442
303
  Raises
443
304
  ------
444
305
 
445
- InvalidParameterException
446
- If the client passes incorrect parameters on the request - such as bad URLs or invalid values
447
- PropertyServerException
448
- Raised by the server when an issue arises in processing a valid request
306
+ ValidationError
307
+ If the client passes incorrect parameters on the request that don't conform to the data model.
308
+ PyegeriaException
309
+ Issues raised in communicating or server side processing.
449
310
  NotAuthorizedException
450
311
  The principle specified by the user_id does not have authorization for the requested action
451
312
 
452
313
  """
453
- search_string = search_string if search_string != "*" else None
454
-
455
- body = SearchStringRequestBody(
456
- class_="SearchStringRequestBody",
457
- starts_with=starts_with,
458
- ends_with=ends_with,
459
- ignore_case=ignore_case,
460
- include_only_classified_elements = [classification_name],
461
- search_string=search_string,
462
- start_from=start_from,
463
- page_size=page_size
464
- )
314
+ url = str(HttpUrl(f"{self.collection_command_root}/by-search-string"))
315
+ response = await self._async_find_request(url, _type="Collection",
316
+ _gen_output=self._generate_collection_output,
317
+ search_string = search_string, classification_names = classification_names,
318
+ starts_with = starts_with, ends_with = ends_with, ignore_case = ignore_case,
319
+ start_from = start_from, page_size = page_size,
320
+ output_format=output_format, output_format_set=output_format_set,
321
+ body=body)
465
322
 
466
- resp = await self._async_find_collections_w_body(body, output_format, output_format_set)
467
- return resp
323
+ return response
468
324
 
469
325
  @dynamic_catch
470
- def find_collections(self, search_string: str = '*', classification_name: str = None, starts_with: bool = True,
326
+ def find_collections(self, search_string: str = '*', classification_names: str = None, starts_with: bool = True,
471
327
  ends_with: bool = False, ignore_case: bool = False,
472
328
  start_from: int = 0, page_size: int = 0, output_format: str = 'JSON',
473
- output_format_set: str | dict = None) -> list | str:
329
+ output_format_set: str | dict = None,
330
+ body: dict | SearchStringRequestBody = None) -> list | str:
474
331
  """ Returns the list of collections matching the search string filtered by the optional classification.
475
- The search string is located in the request body and is interpreted as a plain string. The full
476
- body allows complete control including status, asOfTime and effectiveTime.
477
- The request parameters, startsWith, endsWith and ignoreCase can be used to allow a fuzzy search.
332
+ This method can either be used with a body, allowing full control, or with the individual parameters.
333
+ If the body is provided it will be used and the search_string will be ignored.
478
334
 
479
335
  Parameters
480
336
  ----------
481
337
  search_string: str
482
- String to match against - None or '*' indicate match against all collections (may be filtered
483
- classification_name: str, optional, default=None
484
- A classification name to filter on - for example, DataSpec for data specifications. If none,
338
+ Search string to match against - None or '*' indicate match against all collections (may be filtered by
339
+ classification).
340
+ initial_classifications: list[str], optional, default=None
341
+ A list of classification names to filter on - for example, ["DataSpec"], for data specifications. If none,
485
342
  then all classifications are returned.
486
343
  starts_with : bool, [default=False], optional
487
344
  Starts with the supplied string.
@@ -496,32 +353,35 @@ class CollectionManager(Client2):
496
353
  the class instance.
497
354
  output_format: str, default = "JSON"
498
355
  - one of "MD", "LIST", "FORM", "REPORT", "DICT", "MERMAID" or "JSON"
499
- output_format_set: str | dict , optional, default = None
356
+ output_format_set: str | dict , optional, default = None
500
357
  - The desired output columns/fields to include.
358
+ body: dict | SearchStringRequestBody, optional, default = None
359
+ - if provided, the search parameters in the body will supercede other attributes, such as "search_string"
360
+
501
361
  Returns
502
362
  -------
503
363
  List | str
504
364
 
505
- A list of collections match matching the search string. Returns a string if none found.
365
+ Output depends on the output format specified.
506
366
 
507
367
  Raises
508
368
  ------
509
369
 
510
- InvalidParameterException
511
- If the client passes incorrect parameters on the request - such as bad URLs or invalid values
512
- PropertyServerException
513
- Raised by the server when an issue arises in processing a valid request
370
+ ValidationError
371
+ If the client passes incorrect parameters on the request that don't conform to the data model.
372
+ PyegeriaException
373
+ Issues raised in communicating or server side processing.
514
374
  NotAuthorizedException
515
375
  The principle specified by the user_id does not have authorization for the requested action
516
376
 
517
377
  """
518
378
  return asyncio.get_event_loop().run_until_complete(
519
- self._async_find_collections(search_string, classification_name, starts_with, ends_with, ignore_case,
520
- start_from, page_size, output_format, output_format_set))
379
+ self._async_find_collections(search_string, classification_names, starts_with, ends_with, ignore_case,
380
+ start_from, page_size, output_format, output_format_set, body))
521
381
 
522
382
 
523
383
  @dynamic_catch
524
- async def _async_get_collections_by_name(self, name: str = None, classification_name: str = None,
384
+ async def _async_get_collections_by_name(self, filter_string: str = None, classification_names: list[str] = None,
525
385
  body: dict | FilterRequestBody = None,
526
386
  start_from: int = 0, page_size: int = 0,
527
387
  output_format: str = 'JSON',
@@ -532,7 +392,7 @@ class CollectionManager(Client2):
532
392
  ----------
533
393
  name: str,
534
394
  name to use to find matching collections.
535
- classification_name: str, optional, default = None
395
+ classification_names: list[str], optional, default = None
536
396
  type of collection to filter by - e.g., DataDict, Folder, Root
537
397
  body: dict, optional, default = None
538
398
  Provides, a full request body. If specified, the body supercedes the name parameter.
@@ -543,7 +403,7 @@ class CollectionManager(Client2):
543
403
  the class instance.
544
404
  output_format: str, default = "JSON"
545
405
  - one of "DICT", "MERMAID" or "JSON"
546
- output_format_set: dict , optional, default = None
406
+ output_format_set: dict , optional, default = None
547
407
  The desired output columns/fields to include.
548
408
 
549
409
  Returns
@@ -562,47 +422,20 @@ class CollectionManager(Client2):
562
422
  NotAuthorizedException
563
423
  The principle specified by the user_id does not have authorization for the requested action
564
424
  """
425
+ url = str(HttpUrl(f"{self.collection_command_root}/by-name"))
426
+ response = await self._async_get_name_request(url, _type="Collection",
427
+ _gen_output=self._generate_collection_output,
428
+ filter_string = filter_string, classification_names = classification_names,
429
+ start_from = start_from, page_size = page_size,
430
+ output_format=output_format, output_format_set=output_format_set,
431
+ body=body)
565
432
 
566
- if body is None:
567
- validated_body = FilterRequestBody(
568
- class_ = "FilterRequestBody",
569
- filter = name,
570
- start_from = start_from,
571
- page_size = page_size,
572
- include_only_classified_elements= [classification_name] if classification_name else None
573
- )
574
- elif isinstance(body, FilterRequestBody):
575
- validated_body = body
576
- elif isinstance(body, dict):
577
- try:
578
- validated_body = self._filter_request_adapter.validate_python(body)
579
- except ValidationError as e:
580
- context: dict = {
581
- 'class name': __class__.__name__, 'caller method': inspect.currentframe().f_back.f_code.co_name
582
- }
583
- raise PyegeriaInvalidParameterException(context=context, Exception=e)
584
- else:
585
- raise TypeError("Invalid parameter type")
586
-
587
- url = f"{self.collection_command_root}/by-name"
588
- classification_name = validated_body.include_only_classified_elements
589
-
590
- response = await self._async_make_request("POST", url, validated_body.model_dump_json())
591
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
592
- if type(elements) is str:
593
- logger.info(NO_ELEMENTS_FOUND)
594
- return NO_ELEMENTS_FOUND
595
-
596
- if output_format != 'JSON': # return a simplified markdown representation
597
- logger.info(f"Found elements, output format: {output_format}, output_format_set: {output_format_set}")
598
- return self._generate_collection_output(elements, filter, classification_name,
599
- output_format, output_format_set)
600
- return elements
433
+ return response
601
434
 
602
435
 
603
- def get_collections_by_name(self, name: str = None, classification_name: str = None,
436
+ def get_collections_by_name(self, name: str = None, classification_names: list[str] = None,
604
437
  body: dict | FilterRequestBody = None,
605
- start_from: int = 0, page_size: int = None, output_format: str = 'JSON',
438
+ start_from: int = 0, page_size: int = 0, output_format: str = 'JSON',
606
439
  output_format_set: str | dict = None) -> list | str:
607
440
  """Returns the list of collections matching the search string. Async version.
608
441
  The search string is located in the request body and is interpreted as a plain string.
@@ -612,7 +445,7 @@ class CollectionManager(Client2):
612
445
  ----------
613
446
  name: str,
614
447
  name to use to find matching collections.
615
- classification_name: str, optional, default = None
448
+ classification_names: list[str], optional, default = None
616
449
  type of collection to filter by - e.g., DataDict, Folder, Root
617
450
  body: dict, optional, default = None
618
451
  Provides, a full request body. If specified, the body supercedes the name parameter.
@@ -638,24 +471,24 @@ class CollectionManager(Client2):
638
471
 
639
472
  """
640
473
  return asyncio.get_event_loop().run_until_complete(
641
- self._async_get_collections_by_name(name, classification_name, body, start_from, page_size,
474
+ self._async_get_collections_by_name(name, classification_names, body, start_from, page_size,
642
475
  output_format, output_format_set))
643
476
 
644
477
 
645
478
  @dynamic_catch
646
- async def _async_get_collections_by_type(self, collection_type: str, classification_name: str = None,
479
+ async def _async_get_collections_by_category(self, category: str, classification_names: list[str] = None,
647
480
  body: dict | FilterRequestBody = None, start_from: int = 0, page_size: int = 0,
648
481
  output_format: str = 'JSON',
649
482
  output_format_set: str | dict = None) -> list | str:
650
- """Returns the list of collections with a particular collectionType. This is an optional text field in the
483
+ """Returns the list of collections with a particular category. This is an optional text field in the
651
484
  collection element.
652
485
 
653
486
  Parameters
654
487
  ----------
655
- collection_type: str
656
- collection_type to use to find matching collections.
657
- classification_name: str, optional
658
- An optional filter on the search, e.g., DataSpec
488
+ category: str
489
+ category to use to find matching collections.
490
+ classification_names: str, optional
491
+ An optional filter on the search, e.g., DataSpec
659
492
  body: dict, optional, default = None
660
493
  Provides, a full request body. If specified, the body filter parameter supercedes the collection_type
661
494
  parameter.
@@ -692,49 +525,23 @@ class CollectionManager(Client2):
692
525
  "limitResultsByStatus": ["ACTIVE"],
693
526
  "sequencingOrder": "PROPERTY_ASCENDING",
694
527
  "sequencingProperty": "qualifiedName",
695
- "filter": "Add collection type here"
528
+ "filter": "Add category here"
696
529
  }
697
530
 
698
531
  """
699
- if body is None:
700
- validated_body = FilterRequestBody(
701
- class_ = "FilterRequestBody",
702
- filter = collection_type,
703
- start_from = start_from,
704
- page_size = page_size,
705
- include_only_classified_elements= [classification_name] if classification_name else None
706
- )
707
- elif isinstance(body, FilterRequestBody):
708
- validated_body = body
709
- elif isinstance(body, dict):
710
- try:
711
- validated_body = self._filter_request_adapter.validate_python(body)
712
- except ValidationError as e:
713
- context: dict = {
714
- 'class name': __class__.__name__, 'caller method': inspect.currentframe().f_back.f_code.co_name
715
- }
716
- raise PyegeriaInvalidParameterException(context=context, Exception=e)
717
- else:
718
- raise TypeError("Invalid parameter type")
532
+ url = str(HttpUrl(f"{self.collection_command_root}/by-collection-category"))
533
+ response = await self._async_get_name_request(url, _type="Collection",
534
+ _gen_output=self._generate_collection_output,
535
+ filter_string = category, classification_names = classification_names,
536
+ start_from = start_from, page_size = page_size,
537
+ output_format=output_format, output_format_set=output_format_set,
538
+ body=body)
719
539
 
720
- classification_name = validated_body.include_only_classified_elements
540
+ return response
721
541
 
722
- url = f"{self.collection_command_root}/by-collection-category"
723
542
 
724
- response = await self._async_make_request("POST", url, validated_body.model_dump_json())
725
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
726
- if type(elements) is str:
727
- logger.info(NO_ELEMENTS_FOUND)
728
- return NO_ELEMENTS_FOUND
729
543
 
730
- if output_format != 'JSON': # return a simplified markdown representation
731
- logger.info(f"Found elements, output format: {output_format}, output_format_set: {output_format_set}")
732
- return self._generate_collection_output(elements, filter, classification_name,
733
- output_format, output_format_set)
734
- return elements
735
-
736
-
737
- def get_collections_by_type(self, collection_type: str, classification_name: str = None,
544
+ def get_collections_by_category(self, category: str, classification_names: list[str] = None,
738
545
  body: dict | FilterRequestBody = None,
739
546
  start_from: int = 0, page_size: int = 0, output_format: str = 'JSON',
740
547
  output_format_set: str | dict = None) -> list | str:
@@ -743,9 +550,9 @@ class CollectionManager(Client2):
743
550
 
744
551
  Parameters
745
552
  ----------
746
- collection_type: str
553
+ category: str
747
554
  category to use to find matching collections.
748
- classification_name: str, optional
555
+ classification_names: list[str], optional
749
556
  An optional filter on the search, e.g., DataSpec
750
557
  body: dict, optional, default = None
751
558
  Provides, a full request body. If specified, the body filter parameter supersedes the category
@@ -757,14 +564,14 @@ class CollectionManager(Client2):
757
564
  the class instance.
758
565
  output_format: str, default = "JSON"
759
566
  - one of "DICT", "MERMAID" or "JSON"
760
- output_format_set: str | dict , optional, default = None
567
+ output_format_set: str | dict, optional, default = None
761
568
  The desired output columns/fields to include.
762
569
 
763
570
  Returns
764
571
  -------
765
572
  List | str
766
573
 
767
- A list of collections of the specified collection type. Returns a string if none found.
574
+ A list of collections filtered by the specified category. Output based on specified output format.
768
575
 
769
576
  Raises
770
577
  ------
@@ -789,13 +596,13 @@ class CollectionManager(Client2):
789
596
  "limitResultsByStatus": ["ACTIVE"],
790
597
  "sequencingOrder": "PROPERTY_ASCENDING",
791
598
  "sequencingProperty": "qualifiedName",
792
- "filter": "Add collection type here"
599
+ "filter": "Add category here"
793
600
  }
794
601
 
795
602
  """
796
603
 
797
604
  return asyncio.get_event_loop().run_until_complete(
798
- self._async_get_collections_by_type(collection_type, classification_name, body, start_from, page_size,
605
+ self._async_get_collections_by_category(category, classification_names, body, start_from, page_size,
799
606
  output_format, output_format_set))
800
607
 
801
608
 
@@ -810,13 +617,13 @@ class CollectionManager(Client2):
810
617
  ----------
811
618
  collection_guid: str,
812
619
  unique identifier of the collection.
813
- collection_type: str, default = None, optional
814
- type of collection - Data Dictionary, Data Spec, Data Product, etc.
815
- body: dict, optional, default = None
620
+ element_type: str, default = None, optional
621
+ type of collection - Collection, DataSpec, Agreement, etc.
622
+ body: dict | GetRequestBody, optional, default = None
816
623
  full request body.
817
624
  output_format: str, default = "JSON"
818
625
  - one of "DICT", "MERMAID" or "JSON"
819
- output_format_set: str | dict , optional, default = None
626
+ output_format_set: str | dict, optional, default = None
820
627
  The desired output columns/fields to include.
821
628
 
822
629
  Returns
@@ -847,43 +654,20 @@ class CollectionManager(Client2):
847
654
  }
848
655
  """
849
656
 
850
- if body is None:
851
- validated_body = GetRequestBody(
852
- class_ = "GetRequestBody",
853
- metadata_element_type_name=element_type
854
- )
855
- elif isinstance(body, FilterRequestBody):
856
- validated_body = body
857
- elif isinstance(body, dict):
858
- try:
859
- validated_body = self._get_request_adapter.validate_python(body)
860
- except ValidationError as e:
861
- context: dict = {
862
- 'class name': __class__.__name__, 'caller method': inspect.currentframe().f_back.f_code.co_name
863
- }
864
- raise PyegeriaInvalidParameterException(context=context, Exception=e)
865
- else:
866
- raise TypeError("Invalid parameter type")
867
-
868
- url = f"{self.collection_command_root}/{collection_guid}"
657
+ url = str(HttpUrl(f"{self.collection_command_root}/{collection_guid}"))
658
+ type = element_type if element_type else "Collection"
869
659
 
660
+ response = await self._async_get_guid_request(url, _type=type,
661
+ _gen_output=self._generate_collection_output,
662
+ output_format=output_format, output_format_set=output_format_set,
663
+ body=body)
870
664
 
871
- response = await self._async_make_request("POST", url,
872
- validated_body.model_dump_json())
665
+ return response
873
666
 
874
- elements = response.json().get("element", NO_ELEMENTS_FOUND)
875
- if type(elements) is str:
876
- logger.info(NO_ELEMENTS_FOUND)
877
- return NO_ELEMENTS_FOUND
878
667
 
879
- if output_format != 'JSON': # return a simplified markdown representation
880
- logger.info(f"Found elements, output format: {output_format}, output_format_set: {output_format_set}")
881
- return self._generate_collection_output(elements, None, element_type,
882
- output_format, output_format_set)
883
- return elements
884
668
 
885
669
 
886
- def get_collection_by_guid(self, collection_guid: str, element_type: str = None, body: dict = None,
670
+ def get_collection_by_guid(self, collection_guid: str, element_type: str = None, body: dict | GetRequestBody= None,
887
671
  output_format: str = 'JSON', output_format_set: str | dict = None) -> dict | str:
888
672
  """ Return the properties of a specific collection. Async version.
889
673
 
@@ -891,13 +675,13 @@ class CollectionManager(Client2):
891
675
  ----------
892
676
  collection_guid: str,
893
677
  unique identifier of the collection.
894
- collection_type: str, default = None, optional
895
- type of collection - Data Dictionary, Data Spec, Data Product, etc.
896
- body: dict, optional, default = None
678
+ element_type: str, default = None, optional
679
+ type of element - Collection, DataSpec, Agreement, etc.
680
+ body: dict | GetRequestBody, optional, default = None
897
681
  full request body.
898
682
  output_format: str, default = "JSON"
899
683
  - one of "DICT", "MERMAID" or "JSON"
900
- output_format_set: dict , optional, default = None
684
+ output_format_set: dict , optional, default = None
901
685
  The desired output columns/fields to include.
902
686
 
903
687
 
@@ -935,7 +719,7 @@ class CollectionManager(Client2):
935
719
 
936
720
  @dynamic_catch
937
721
  async def _async_get_collection_members(self, collection_guid: str = None, collection_name: str = None,
938
- collection_qname: str = None, body: dict = None, start_from: int = 0,
722
+ collection_qname: str = None, body: dict | ResultsRequestBody = None, start_from: int = 0,
939
723
  page_size: int = 0, output_format: str = "JSON",
940
724
  output_format_set: str | dict = None) -> list | str:
941
725
  """Return a list of elements that are a member of a collection. Async version.
@@ -994,27 +778,18 @@ class CollectionManager(Client2):
994
778
  """
995
779
 
996
780
  if collection_guid is None:
997
- collection_guid = self.__get_guid__(collection_guid, collection_name, "name",
781
+ collection_guid = self.__get_guid__(collection_guid, collection_name, "displayName",
998
782
  collection_qname, None, )
999
783
 
1000
- url = (f"{self.collection_command_root}/{collection_guid}/"
1001
- f"members?startFrom={start_from}&pageSize={page_size}")
784
+ url = str(HttpUrl(f"{self.collection_command_root}/{collection_guid}/members"))
1002
785
 
1003
- if body:
1004
- response = await self._async_make_request("POST", url, body_slimmer(body))
1005
- else:
1006
- response = await self._async_make_request("POST", url)
1007
786
 
1008
- elements = response.json().get("elements", NO_MEMBERS_FOUND)
1009
- if type(elements) is str:
1010
- logger.trace(f"No elements found for collection {collection_guid}")
1011
- return NO_MEMBERS_FOUND
787
+ response = await self._async_get_results_body_request(url, _type="Collection",
788
+ _gen_output=self._generate_collection_output,
789
+ output_format=output_format, output_format_set=output_format_set,
790
+ body=body)
1012
791
 
1013
- if output_format != 'JSON': # return a simplified markdown representation
1014
- logger.debug(f"Found elements, output format: {output_format}, output_format_set: {output_format_set}")
1015
- return self._generate_collection_output(elements, None, None,
1016
- output_format, output_format_set)
1017
- return elements
792
+ return response
1018
793
 
1019
794
 
1020
795
  def get_collection_members(self, collection_guid: str = None, collection_name: str = None,
@@ -1083,19 +858,17 @@ class CollectionManager(Client2):
1083
858
 
1084
859
 
1085
860
  @dynamic_catch
1086
- async def _async_get_collection_graph(self, collection_guid: str, body: dict = None, start_from: int = 0,
861
+ async def _async_get_collection_hierarchy(self, collection_guid: str, body: dict | ResultsRequestBody = None, start_from: int = 0,
1087
862
  page_size: int = 0, output_format: str = "JSON",
1088
863
  output_format_set: str | dict = None) -> list | str:
1089
- """ Return a graph of elements that are the nested members of a collection along
1090
- with elements immediately connected to the starting collection. The result
1091
- includes a mermaid graph of the returned elements. Async version.
864
+ """ Return a hierarchy of nested collections. Request body is optional Async version.
1092
865
 
1093
866
  Parameters
1094
867
  ----------
1095
868
  collection_guid: str,
1096
869
  identity of the collection to return members for. If none, collection_name or
1097
870
  collection_qname are used.
1098
- body: dict, optional, default = None
871
+ body: dict | ResultsRequestBody, optional, default = None
1099
872
  Providing the body allows full control of the request and replaces filter parameters.
1100
873
  start_from: int, [default=0], optional
1101
874
  When multiple pages of results are available, the page number to start from.
@@ -1104,14 +877,14 @@ class CollectionManager(Client2):
1104
877
  the class instance.
1105
878
  output_format: str, default = "JSON"
1106
879
  - one of "MD", "LIST", "FORM", "REPORT", "DICT", "MERMAID" or "JSON"
1107
- output_format_set: dict , optional, default = None
880
+ output_format_set: dict , optional, default = None
1108
881
  The desired output columns/fields to include.
1109
882
 
1110
883
  Returns
1111
884
  -------
1112
885
  List | str
1113
886
 
1114
- A graph anchored in the collection.
887
+ Results based on the output format.
1115
888
 
1116
889
  Raises
1117
890
  ------
@@ -1126,37 +899,29 @@ class CollectionManager(Client2):
1126
899
  Notes:
1127
900
  -----
1128
901
  Body sample:
1129
- {
1130
- "class": "ResultsRequestBody",
1131
- "effectiveTime": "{{$isoTimestamp}}",
1132
- "limitResultsByStatus": ["ACTIVE"],
1133
- "asOfTime": "{{$isoTimestamp}}",
1134
- "sequencingOrder": "CREATION_DATE_RECENT",
1135
- "sequencingProperty": ""
1136
- }
902
+ {
903
+ "class": "ResultsRequestBody",
904
+ "startFrom": 0,
905
+ "pageSize": 0,
906
+ "effectiveTime": "{{$isoTimestamp}}",
907
+ "limitResultsByStatus": ["ACTIVE"],
908
+ "asOfTime": "{{$isoTimestamp}}",
909
+ "sequencingOrder": "CREATION_DATE_RECENT",
910
+ "sequencingProperty": ""
911
+ }
1137
912
  """
1138
913
 
1139
- url = (f"{self.collection_command_root}/{collection_guid}/"
1140
- f"graph?startFrom={start_from}&pageSize={page_size}")
914
+ url = str(HttpUrl(f"{self.collection_command_root}/{collection_guid}/hierarchy"))
915
+ response = await self._async_get_results_body_request(url, _type="Collection",
916
+ _gen_output=self._generate_collection_output,
917
+ start_from=start_from, page_size=page_size,
918
+ output_format=output_format,
919
+ output_format_set=output_format_set,
920
+ body=body)
1141
921
 
1142
- if body:
1143
- response = await self._async_make_request("POST", url, body_slimmer(body))
1144
- else:
1145
- response = await self._async_make_request("POST", url)
922
+ return response
1146
923
 
1147
- elements = response.json().get("graph", NO_ELEMENTS_FOUND)
1148
- if type(elements) is str:
1149
- logger.info(NO_ELEMENTS_FOUND)
1150
- return NO_ELEMENTS_FOUND
1151
-
1152
- if output_format != 'JSON': # return a simplified markdown representation
1153
- logger.info(f"Found elements, output format: {output_format}, output_format_set: {output_format_set}")
1154
- return self._generate_collection_output(elements, None, None,
1155
- output_format, output_format_set)
1156
- return elements
1157
-
1158
-
1159
- def get_collection_graph(self, collection_guid: str = None, body: dict = None, start_from: int = 0,
924
+ def get_collection_hierarchy(self, collection_guid: str = None, body: dict| ResultsRequestBody = None, start_from: int = 0,
1160
925
  page_size: int = 0, output_format: str = "JSON",
1161
926
  output_format_set: str | dict = None) -> list | str:
1162
927
  """ Return a graph of elements that are the nested members of a collection along
@@ -1209,168 +974,14 @@ class CollectionManager(Client2):
1209
974
  }
1210
975
  """
1211
976
  return asyncio.get_event_loop().run_until_complete(
1212
- self._async_get_collection_graph(collection_guid, body, start_from, page_size,
977
+ self._async_get_collection_hierarchy(collection_guid, body, start_from, page_size,
1213
978
  output_format, output_format_set))
1214
979
 
1215
980
 
1216
- @dynamic_catch
1217
- async def _async_get_collection_graph_w_body(self, collection_guid: str, body: dict = None, start_from: int = 0,
1218
- page_size: int = None, output_format: str = "JSON",
1219
- output_format_set: str | dict = None) -> list | str:
1220
- """ Return a graph of elements that are the nested members of a collection along
1221
- with elements immediately connected to the starting collection. The result
1222
- includes a mermaid graph of the returned elements. Async version.
1223
-
1224
- Parameters
1225
- ----------
1226
- collection_guid: str,
1227
- identity of the collection to return members for.
1228
- body: dict
1229
- A dictionary containing the body of the request. See Note.
1230
- start_from: int, [default=0], optional
1231
- When multiple pages of results are available, the page number to start from.
1232
- page_size: int, [default=None]
1233
- The number of items to return in a single page. If not specified, the default will be taken from
1234
- the class instance.
1235
- output_format: str, default = "JSON"
1236
- - one of "MD", "LIST", "FORM", "REPORT", "DICT", "MERMAID" or "JSON"
1237
- output_format_set: dict , optional, default = None
1238
-
1239
- Returns
1240
- -------
1241
- List | str
1242
-
1243
- A list of collection members in the collection.
1244
-
1245
- Raises
1246
- ------
1247
- InvalidParameterException
1248
- If the client passes incorrect parameters on the request - such as bad URLs or invalid values
1249
- PropertyServerException
1250
- Raised by the server when an issue arises in processing a valid request
1251
- NotAuthorizedException
1252
- The principle specified by the user_id does not have authorization for the requested action
1253
-
1254
- Note
1255
- ____
1256
- {
1257
- "class": "ResultsRequestBody",
1258
- "effectiveTime": "{{$isoTimestamp}}",
1259
- "limitResultsByStatus": ["ACTIVE"],
1260
- "asOfTime": "{{$isoTimestamp}}",
1261
- "sequencingOrder": "CREATION_DATE_RECENT",
1262
- "sequencingProperty": ""
1263
- }
1264
-
1265
- """
1266
-
1267
- if page_size is None:
1268
- page_size = self.page_size
1269
-
1270
- url = (f"{self.collection_command_root}/{collection_guid}/"
1271
- f"graph?startFrom={start_from}&pageSize={page_size}")
1272
-
1273
- response = await self._async_make_request("GET", url, body_slimmer(body))
1274
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
1275
- if type(elements) is str:
1276
- logger.info(NO_ELEMENTS_FOUND)
1277
- return NO_ELEMENTS_FOUND
1278
-
1279
- if output_format != 'JSON': # return a simplified markdown representation
1280
- logger.info(f"Found elements, output format: {output_format}, output_format_set: {output_format_set}")
1281
- return self._generate_collection_output(elements, None, None,
1282
- output_format, output_format_set)
1283
- return elements
1284
-
1285
-
1286
- def get_collection_graph_w_body(self, collection_guid: str, body: dict = None, start_from: int = 0,
1287
- page_size: int = None, output_format: str = "JSON",
1288
- output_format_set: str | dict = None) -> list | str:
1289
- """ Return a graph of elements that are the nested members of a collection along
1290
- with elements immediately connected to the starting collection. The result
1291
- includes a mermaid graph of the returned elements.
1292
-
1293
- Parameters
1294
- ----------
1295
- collection_guid: str,
1296
- identity of the collection to return members for.
1297
- body: dict
1298
- A dictionary containing the body of the request. See Note.
1299
- start_from: int, [default=0], optional
1300
- When multiple pages of results are available, the page number to start from.
1301
- page_size: int, [default=None]
1302
- The number of items to return in a single page. If not specified, the default will be taken from
1303
- the class instance.
1304
- output_format: str, default = "JSON"
1305
- - one of "MD", "LIST", "FORM", "REPORT", "DICT", "MERMAID" or "JSON"
1306
- output_format_set: str | dict , optional, default = None
1307
- The desired output columns/fields to include.
1308
-
1309
- Returns
1310
- -------
1311
- List | str
1312
-
1313
- A list of collection members in the collection.
1314
-
1315
- Raises
1316
- ------
1317
- InvalidParameterException
1318
- If the client passes incorrect parameters on the request - such as bad URLs or invalid values
1319
- PropertyServerException
1320
- Raised by the server when an issue arises in processing a valid request
1321
- NotAuthorizedException
1322
- The principle specified by the user_id does not have authorization for the requested action
1323
-
1324
- Note
1325
- ____
1326
- {
1327
- "class": "ResultsRequestBody",
1328
- "effectiveTime": "{{$isoTimestamp}}",
1329
- "limitResultsByStatus": ["ACTIVE"],
1330
- "asOfTime": "{{$isoTimestamp}}",
1331
- "sequencingOrder": "CREATION_DATE_RECENT",
1332
- "sequencingProperty": ""
1333
- }
1334
-
1335
- """
1336
-
1337
- return asyncio.get_event_loop().run_until_complete(
1338
- self._async_get_collection_graph_w_body(collection_guid, body, start_from,
1339
- page_size, output_format, output_format_set))
1340
-
1341
- #
1342
- # Create collection methods
1343
- #
1344
-
1345
- ###
1346
- # =====================================================================================================================
1347
- # Create Collections: https://egeria-project.org/concepts/collection
1348
- # These requests use the following parameters:
1349
- #
1350
- # anchorGUID - the unique identifier of the element that should be the anchor for the new element. Set to
1351
- # null if
1352
- # no anchor,
1353
- # or if this collection is to be its own anchor.
1354
- #
1355
- # isOwnAnchor -this element should be classified as its own anchor or not. The default is false.
1356
- #
1357
- # parentGUID - the optional unique identifier for an element that should be connected to the newly
1358
- # created element.
1359
- # If this property is specified, parentRelationshipTypeName must also be specified
1360
- #
1361
- # parentRelationshipTypeName - the name of the relationship, if any, that should be established between
1362
- # the new
1363
- # element and the parent element.
1364
- # Examples could be "ResourceList" or "DigitalServiceProduct".
1365
- #
1366
- # parentAtEnd1 -identifies which end any parent entity sits on the relationship.
1367
- #
1368
-
1369
-
1370
981
  @dynamic_catch
1371
982
  async def _async_create_collection(self, display_name: str = None, description: str = None,
1372
- category: str = None, classification_name: str = None,
1373
- body: dict | NewElementRequestBody = None) -> str:
983
+ category: str = None, initial_classifications: list[str] = None,
984
+ body: dict | NewElementRequestBody = None) -> str:
1374
985
  """ Create a new generic collection. If the body is not present, the display_name, description, category
1375
986
  and classification will be used to create a simple, self-anchored collection.
1376
987
  Collections: https://egeria-project.org/concepts/collection
@@ -1385,8 +996,8 @@ class CollectionManager(Client2):
1385
996
  The description of the collection.
1386
997
  category: str, optional
1387
998
  An optional user-assigned category for the collection.
1388
- classification: str, optional
1389
- An initial classification for the collection. This can be used to distinguish, for instance, Folders
999
+ initial_classifications: list[str], optional
1000
+ An initial list of classifications for the collection. This can be used to distinguish, for instance, Folders
1390
1001
  from Root Collections.
1391
1002
 
1392
1003
  body: dict | NewElementRequestBody, optional
@@ -1473,30 +1084,19 @@ class CollectionManager(Client2):
1473
1084
  }
1474
1085
 
1475
1086
  """
1476
-
1477
-
1478
- if isinstance(body, NewElementRequestBody):
1479
- validated_body = body
1480
- elif isinstance(body, dict):
1481
- try:
1482
- validated_body = self._new_element_request_adapter.validate_python(body)
1483
- except ValidationError as e:
1484
- logger.error(f"Validation error: {e}")
1485
- raise ValidationError(e)
1486
- elif display_name is not None:
1487
- pre = classification_name if classification_name is not None else "Collection "
1488
- qualified_name = self.__create_qualified_name__(pre, display_name, EGERIA_LOCAL_QUALIFIER)
1489
- print(f"\n\tDisplayName was {display_name}, classification {classification_name}\n")
1490
- if classification_name:
1491
- initial_classifications_data = {"class": "ClassificationProperties"}
1492
- initial_classification_dict = {
1493
- classification_name: InitialClassifications.model_validate(initial_classifications_data)
1494
- }
1087
+ if body:
1088
+ validated_body = self.validate_new_element_request(body,"CollectionProperties")
1089
+ elif (body is None) and (display_name is not None):
1090
+ pre = initial_classifications[0] if initial_classifications is not None else "Collection"
1091
+ qualified_name = self.__create_qualified_name__(pre, display_name, EGERIA_LOCAL_QUALIFIER)
1092
+ if initial_classifications:
1093
+ initial_classifications_dict = {}
1094
+ for c in initial_classifications:
1095
+ initial_classifications_dict = initial_classifications_dict | {c : {"class": "ClassificationProperties"}}
1096
+
1495
1097
  else:
1496
- initial_classification_dict = None
1497
- initial_classification_dict = {
1498
- classification_name: InitialClassifications.model_validate(initial_classifications_data)
1499
- }
1098
+ initial_classifications_dict = None
1099
+
1500
1100
  collection_properties = CollectionProperties( class_ = "CollectionProperties",
1501
1101
  qualified_name = qualified_name,
1502
1102
  display_name = display_name,
@@ -1506,12 +1106,12 @@ class CollectionManager(Client2):
1506
1106
  body = {
1507
1107
  "class" :"NewElementRequestBody",
1508
1108
  "isOwnAnchor": True,
1509
- "initialClassifications": initial_classification_dict,
1109
+ "initialClassifications": initial_classifications_dict,
1510
1110
  "properties": collection_properties.model_dump()
1511
1111
  }
1512
1112
  validated_body = NewElementRequestBody.model_validate(body)
1513
1113
  else:
1514
- raise TypeError("Invalid parameter type")
1114
+ raise PyegeriaInvalidParameterException(additional_info={"reason": "Invalid input parameters"})
1515
1115
 
1516
1116
  url = f"{self.collection_command_root}"
1517
1117
  json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
@@ -1522,7 +1122,7 @@ class CollectionManager(Client2):
1522
1122
 
1523
1123
 
1524
1124
  def create_collection(self, display_name: str = None, description: str = None,
1525
- category: str = None, classification_name: str = None,
1125
+ category: str = None, initial_classifications: list[str] = None,
1526
1126
  body: dict | NewElementRequestBody = None) -> str:
1527
1127
  """ Create a new generic collection. If the body is not present, the display_name, description, category
1528
1128
  and classification will be used to create a simple, self-anchored collection.
@@ -1537,7 +1137,7 @@ class CollectionManager(Client2):
1537
1137
  The description of the collection.
1538
1138
  category: str, optional
1539
1139
  An optional user-assigned category for the collection.
1540
- classification: str, optional
1140
+ initial_classifications: str, optional
1541
1141
  An initial classification for the collection. This can be used to distinguish, for instance, Folders
1542
1142
  from Root Collections.
1543
1143
 
@@ -1629,7 +1229,7 @@ class CollectionManager(Client2):
1629
1229
 
1630
1230
  return asyncio.get_event_loop().run_until_complete(
1631
1231
  self._async_create_collection(display_name, description,category,
1632
- classification_name, body))
1232
+ initial_classifications, body))
1633
1233
 
1634
1234
 
1635
1235
  @dynamic_catch
@@ -1668,11 +1268,9 @@ class CollectionManager(Client2):
1668
1268
 
1669
1269
  return asyncio.get_event_loop().run_until_complete(
1670
1270
  self._async_create_collection(display_name, description, category,
1671
- "RootCollection", body))
1271
+ ["RootCollection"], body))
1672
1272
 
1673
- #######
1674
1273
 
1675
- return resp
1676
1274
  @dynamic_catch
1677
1275
  def create_folder_collection(self, display_name: str = None, description: str = None,
1678
1276
  category: str = None, body: dict | NewElementRequestBody = None) -> str:
@@ -1709,7 +1307,7 @@ class CollectionManager(Client2):
1709
1307
 
1710
1308
  return asyncio.get_event_loop().run_until_complete(
1711
1309
  self._async_create_collection(display_name, description, category,
1712
- "Folder", body))
1310
+ ["Folder"], body))
1713
1311
 
1714
1312
 
1715
1313
 
@@ -1750,14 +1348,10 @@ class CollectionManager(Client2):
1750
1348
 
1751
1349
  return asyncio.get_event_loop().run_until_complete(
1752
1350
  self._async_create_collection(display_name, description, category,
1753
- "ReferenceList", body))
1754
-
1755
-
1351
+ ["ReferenceList"], body))
1756
1352
 
1757
-
1758
- return resp
1759
1353
  @dynamic_catch
1760
- def create_reference_list_collection(self, display_name: str = None, description: str = None,
1354
+ def create_context_event_collection(self, display_name: str = None, description: str = None,
1761
1355
  category: str = None, body: dict | NewElementRequestBody = None) -> str:
1762
1356
  """ Create a new collection with the RootCollection classification. Used to identify the top of a
1763
1357
  collection hierarchy.
@@ -1792,7 +1386,7 @@ class CollectionManager(Client2):
1792
1386
 
1793
1387
  return asyncio.get_event_loop().run_until_complete(
1794
1388
  self._async_create_collection(display_name, description, category,
1795
- "ReferenceList", body))
1389
+ ["ContextEvent"], body))
1796
1390
 
1797
1391
  @dynamic_catch
1798
1392
  async def _async_create_data_spec_collection(self, display_name: str = None, description: str = None,
@@ -1900,51 +1494,35 @@ class CollectionManager(Client2):
1900
1494
  }
1901
1495
 
1902
1496
  """
1497
+ validated_body = self.validate_new_element_request(body,"DataSpecProperties")
1903
1498
 
1904
- try:
1905
- if isinstance(body, NewElementRequestBody):
1906
- if body.properties.class_ == "DataSpecProperties":
1907
- validated_body = body
1908
- else:
1909
- raise PyegeriaInvalidParameterException(additional_info =
1910
- {"reason" : "unexpected property class name"})
1911
-
1912
- elif isinstance(body, dict):
1913
- if body.get("properties", {}).get("class", "") == "DataSpecProperties":
1914
- validated_body = self._new_element_request_adapter.validate_python(body)
1915
- else:
1916
- raise PyegeriaInvalidParameterException(additional_info =
1917
- {"reason" : "unexpected property class name"})
1918
-
1919
- elif display_name is not None:
1920
- qualified_name = self.__create_qualified_name__("DataSpec", display_name, EGERIA_LOCAL_QUALIFIER)
1921
- print(f"\n\tDisplayName was {display_name}, classification {classification_name}\n")
1922
- initial_classifications_data = {"class" : "ClassificationProperties"}
1923
- if classification_name:
1924
- initial_classification_dict = {
1925
- classification_name: InitialClassifications.model_validate(initial_classifications_data)
1926
- }
1927
- else:
1928
- initial_classification_dict = None
1929
- collection_properties = DataSpecProperties( class_ = "DataSpecProperties",
1930
- qualified_name = qualified_name,
1931
- display_name = display_name,
1932
- description = description,
1933
- category = category
1934
- )
1935
- body = {
1936
- "class" :"NewElementRequestBody",
1937
- "isOwnAnchor": True,
1938
- "initialClassifications": initial_classification_dict,
1939
- "properties": collection_properties.model_dump()
1940
- }
1941
- validated_body = NewElementRequestBody.model_validate(body)
1499
+ if validated_body is None and display_name is not None:
1500
+ qualified_name = self.__create_qualified_name__("DataSpec", display_name, EGERIA_LOCAL_QUALIFIER)
1501
+ print(f"\n\tDisplayName was {display_name}, classification {classification_name}\n")
1502
+ initial_classifications_data = {"class" : "ClassificationProperties"}
1503
+ if classification_name:
1504
+ initial_classification_dict = {
1505
+ classification_name: InitialClassifications.model_validate(initial_classifications_data)
1506
+ }
1942
1507
  else:
1943
- raise TypeError("Invalid parameter type")
1508
+ initial_classification_dict = None
1509
+ collection_properties = DataSpecProperties( class_ = "DataSpecProperties",
1510
+ qualified_name = qualified_name,
1511
+ display_name = display_name,
1512
+ description = description,
1513
+ category = category
1514
+ )
1515
+ body = {
1516
+ "class" :"NewElementRequestBody",
1517
+ "isOwnAnchor": True,
1518
+ "initialClassifications": initial_classification_dict,
1519
+ "properties": collection_properties.model_dump()
1520
+ }
1521
+ validated_body = NewElementRequestBody.model_validate(body)
1522
+ else:
1523
+ raise PyegeriaInvalidParameterException(additional_info={"reason": "Invalid input parameters"})
1524
+
1944
1525
 
1945
- except ValidationError as e:
1946
- logger.error(f"Validation error: {e}")
1947
- raise ValidationError(e)
1948
1526
 
1949
1527
 
1950
1528
  url = f"{self.collection_command_root}"
@@ -1971,7 +1549,7 @@ class CollectionManager(Client2):
1971
1549
  The description of the collection.
1972
1550
  category: str, optional
1973
1551
  An optional user-assigned category for the collection.
1974
- classification: str, optional
1552
+ classification_name: str, optional
1975
1553
  An initial classification for the collection. This can be used to distinguish, for instance, Folders
1976
1554
  from Root Collections.
1977
1555
 
@@ -2173,49 +1751,33 @@ class CollectionManager(Client2):
2173
1751
 
2174
1752
  """
2175
1753
 
2176
- try:
2177
- if isinstance(body, NewElementRequestBody):
2178
- if body.properties.class_ == "DataDictionaryProperties":
2179
- validated_body = body
2180
- else:
2181
- raise PyegeriaInvalidParameterException(additional_info =
2182
- {"reason" : "unexpected property class name"})
2183
-
2184
- elif isinstance(body, dict):
2185
- if body.get("properties", {}).get("class", "") == "DataDictionaryProperties":
2186
- validated_body = self._new_element_request_adapter.validate_python(body)
2187
- else:
2188
- raise PyegeriaInvalidParameterException(additional_info =
2189
- {"reason" : "unexpected property class name"})
2190
-
2191
- elif display_name is not None:
2192
- qualified_name = self.__create_qualified_name__("DataDictionary", display_name, EGERIA_LOCAL_QUALIFIER)
2193
- initial_classifications_data = {"class" : "ClassificationProperties"}
2194
- if classification_name:
2195
- initial_classification_dict = {
2196
- classification_name: InitialClassifications.model_validate(initial_classifications_data)
2197
- }
2198
- else:
2199
- initial_classification_dict = None
2200
- collection_properties = DataDictionaryProperties( class_ = "DataDictionaryProperties",
2201
- qualified_name = qualified_name,
2202
- display_name = display_name,
2203
- description = description,
2204
- category = category
2205
- )
2206
- body = {
2207
- "class" :"NewElementRequestBody",
2208
- "isOwnAnchor": True,
2209
- "initialClassifications": initial_classification_dict,
2210
- "properties": collection_properties.model_dump()
2211
- }
2212
- validated_body = NewElementRequestBody.model_validate(body)
1754
+ validated_body = self.validate_new_element_request(body,"DataDictionaryProperties")
1755
+
1756
+ if validated_body is None and display_name is not None:
1757
+ qualified_name = self.__create_qualified_name__("DataDictionary", display_name, EGERIA_LOCAL_QUALIFIER)
1758
+ initial_classifications_data = {"class" : "ClassificationProperties"}
1759
+ if classification_name:
1760
+ initial_classification_dict = {
1761
+ classification_name: InitialClassifications.model_validate(initial_classifications_data)
1762
+ }
2213
1763
  else:
2214
- raise TypeError("Invalid parameter type")
1764
+ initial_classification_dict = None
1765
+ collection_properties = DataDictionaryProperties( class_ = "DataDictionaryProperties",
1766
+ qualified_name = qualified_name,
1767
+ display_name = display_name,
1768
+ description = description,
1769
+ category = category
1770
+ )
1771
+ body = {
1772
+ "class" :"NewElementRequestBody",
1773
+ "isOwnAnchor": True,
1774
+ "initialClassifications": initial_classification_dict,
1775
+ "properties": collection_properties.model_dump()
1776
+ }
1777
+ validated_body = NewElementRequestBody.model_validate(body)
2215
1778
 
2216
- except ValidationError as e:
2217
- logger.error(f"Validation error: {e}")
2218
- raise ValidationError(e)
1779
+ if validated_body is None:
1780
+ raise PyegeriaInvalidParameterException(additional_info={"reason": "Invalid input parameters"})
2219
1781
 
2220
1782
 
2221
1783
  url = f"{self.collection_command_root}"
@@ -2400,18 +1962,17 @@ class CollectionManager(Client2):
2400
1962
 
2401
1963
  """
2402
1964
 
2403
- try:
2404
- if isinstance(body, TemplateRequestBody):
2405
- validated_body = body
2406
1965
 
2407
- elif isinstance(body, dict):
2408
- validated_body = self._new_element_template_request_adapter.validate_python(body)
1966
+ if isinstance(body, TemplateRequestBody):
1967
+ validated_body = body
1968
+
1969
+ elif isinstance(body, dict):
1970
+ validated_body = self._template_request_adapter.validate_python(body)
1971
+
2409
1972
 
2410
- except ValidationError as e:
2411
- logger.error(f"Validation error: {e}")
2412
- raise ValidationError(e)
2413
1973
 
2414
- url = f"{self.collection_command_root}"
1974
+
1975
+ url = f"{self.collection_command_root}/from-template"
2415
1976
  json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
2416
1977
  logger.info(json_body)
2417
1978
  resp = await self._async_make_request("POST", url, json_body, is_json=True)
@@ -2481,8 +2042,7 @@ class CollectionManager(Client2):
2481
2042
 
2482
2043
 
2483
2044
  @dynamic_catch
2484
- async def _async_update_collection(self, collection_guid: str, body: dict | NewElementRequestBody,
2485
- merge_update: bool = True) -> None:
2045
+ async def _async_update_collection(self, collection_guid: str, body: dict | UpdateElementRequestBody) -> None:
2486
2046
  """ Update the properties of a collection. Use the correct properties object (CollectionProperties,
2487
2047
  DigitalProductProperties, AgreementProperties, etc), that is appropriate for your element.
2488
2048
  Collections: https://egeria-project.org/concepts/collection
@@ -2493,7 +2053,7 @@ class CollectionManager(Client2):
2493
2053
  collection_guid: str
2494
2054
  The guid of the collection to update.
2495
2055
 
2496
- body: dict | NewElementRequestBody, optional
2056
+ body: dict | UpdateElementRequestBody, optional
2497
2057
  A dict or NewElementRequestBody representing the details of the collection to create. If supplied, this
2498
2058
  information will be used to create the collection and the other attributes will be ignored. The body is
2499
2059
  validated before being used.
@@ -2535,44 +2095,18 @@ class CollectionManager(Client2):
2535
2095
  }
2536
2096
  """
2537
2097
 
2538
- try:
2539
- if isinstance(body, NewElementRequestBody):
2540
- if body.properties.class_ in COLLECTION_PROPERTIES_LIST:
2541
- validated_body = body
2542
- else:
2543
- raise PyegeriaInvalidParameterException(additional_info =
2544
- {"reason" : "unexpected property class name"})
2545
-
2546
- elif isinstance(body, dict):
2547
- if body.get("properties", {}).get("class", "") in COLLECTION_PROPERTIES_LIST:
2548
- validated_body = self._new_element_request_adapter.validate_python(body)
2549
- else:
2550
- raise PyegeriaInvalidParameterException(additional_info =
2551
- {"reason" : "unexpected property class name"})
2552
- else:
2553
- raise TypeError("Invalid parameter type")
2554
-
2555
- except ValidationError as e:
2556
- logger.error(f"Validation error: {e}")
2557
- raise ValidationError(e)
2558
-
2559
- merge_update_s = str(merge_update).lower()
2098
+ # try:
2560
2099
 
2561
- url = (f"{self.collection_command_root}/{collection_guid}/update?"
2562
- f"replaceAllProperties={merge_update_s}")
2563
-
2564
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
2100
+ url = (f"{self.collection_command_root}/{collection_guid}/update")
2101
+ await self._async_update_element_body_request(url, COLLECTION_PROPERTIES_LIST,body)
2565
2102
 
2566
- await self._async_make_request("POST", url, json_body)
2567
2103
 
2568
- logger.info(f"Successfully updated {collection_guid} with {json_body}")
2569
2104
 
2570
2105
 
2571
2106
 
2572
2107
 
2573
2108
  @dynamic_catch
2574
- def update_collection(self, collection_guid: str, body: dict | NewElementRequestBody,
2575
- merge_update: bool = True) -> None:
2109
+ def update_collection(self, collection_guid: str, body: dict | NewElementRequestBody) -> None:
2576
2110
  """ Update the properties of a collection. Use the correct properties object (CollectionProperties,
2577
2111
  DigitalProductProperties, AgreementProperties, etc), that is appropriate for your element.
2578
2112
  Collections: https://egeria-project.org/concepts/collection
@@ -2625,7 +2159,7 @@ class CollectionManager(Client2):
2625
2159
  """
2626
2160
 
2627
2161
  return asyncio.get_event_loop().run_until_complete(
2628
- self._async_update_collection(collection_guid, body, merge_update))
2162
+ self._async_update_collection(collection_guid, body))
2629
2163
 
2630
2164
 
2631
2165
  @dynamic_catch
@@ -2696,34 +2230,9 @@ class CollectionManager(Client2):
2696
2230
  OTHER. If using OTHER, set the userDefinedStatus with the status value you want. If not specified, will
2697
2231
  default to ACTIVE.
2698
2232
  """
2699
- try:
2700
- if isinstance(body, NewElementRequestBody):
2701
- if body.properties.class_ == "DigitalProductProperties":
2702
- validated_body = body
2703
- else:
2704
- raise PyegeriaInvalidParameterException(additional_info=
2705
- {"reason": "unexpected property class name"})
2706
-
2707
- elif isinstance(body, dict):
2708
- if body.get("properties", {}).get("class", "") == "DigitalProductProperties":
2709
- validated_body = self._new_element_request_adapter.validate_python(body)
2710
- else:
2711
- raise PyegeriaInvalidParameterException(additional_info=
2712
- {"reason": "unexpected property class name"})
2713
-
2714
- else:
2715
- raise TypeError("Invalid parameter type")
2716
-
2717
- except ValidationError as e:
2718
- logger.error(f"Validation error: {e}")
2719
- raise ValidationError(e)
2720
-
2721
2233
  url = f"{self.collection_command_root}"
2722
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
2723
- logger.info(json_body)
2724
- resp = await self._async_make_request("POST", url, json_body, is_json=True)
2725
- logger.info(f"Create collection with GUID: {resp.json().get('guid')}")
2726
- return resp.json().get("guid", NO_GUID_RETURNED)
2234
+ return await self._async_create_element_body_request(url, "DigitalProductProperties", body)
2235
+
2727
2236
 
2728
2237
  @dynamic_catch
2729
2238
  def create_digital_product(self, body: dict | NewElementRequestBody = None) -> str:
@@ -2798,8 +2307,7 @@ class CollectionManager(Client2):
2798
2307
 
2799
2308
 
2800
2309
  @dynamic_catch
2801
- async def _async_update_digital_product(self, collection_guid: str, body: dict | UpdateElementRequestBody,
2802
- merge_update: bool = True) -> None:
2310
+ async def _async_update_digital_product(self, collection_guid: str, body: dict | UpdateElementRequestBody) -> None:
2803
2311
  """ Update the properties of a digital product.
2804
2312
  Collections: https://egeria-project.org/concepts/collection
2805
2313
 
@@ -2863,37 +2371,8 @@ class CollectionManager(Client2):
2863
2371
  }
2864
2372
  """
2865
2373
 
2866
- try:
2867
- if isinstance(body, NewElementRequestBody):
2868
- if body.properties.class_ == "DigitalProductProperties":
2869
- validated_body = body
2870
- else:
2871
- raise PyegeriaInvalidParameterException(additional_info =
2872
- {"reason" : "unexpected property class name"})
2873
-
2874
- elif isinstance(body, dict):
2875
- if body.get("properties", {}).get("class", "") == "DigitalProductProperties":
2876
- validated_body = self._update_element_request_adapter.validate_python(body)
2877
- else:
2878
- raise PyegeriaInvalidParameterException(additional_info =
2879
- {"reason" : "unexpected property class name"})
2880
- else:
2881
- raise TypeError("Invalid parameter type")
2882
-
2883
- except ValidationError as e:
2884
- logger.error(f"Validation error: {e}")
2885
- raise ValidationError(e)
2886
-
2887
- merge_update_s = str(merge_update).lower()
2888
-
2889
- url = (f"{self.collection_command_root}/{collection_guid}/update?"
2890
- f"replaceAllProperties={merge_update_s}")
2891
-
2892
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
2893
-
2894
- await self._async_make_request("POST", url, json_body)
2895
-
2896
- logger.info(f"Successfully updated {collection_guid} with {json_body}")
2374
+ url = (f"{self.collection_command_root}/{collection_guid}/update")
2375
+ await self._async_update_element_request_body(url, "DigitalProductProperties", body )
2897
2376
 
2898
2377
 
2899
2378
  @dynamic_catch
@@ -2966,15 +2445,19 @@ class CollectionManager(Client2):
2966
2445
 
2967
2446
 
2968
2447
  @dynamic_catch
2969
- async def _async_update_collection_status(self, collection_guid: str, body: dict | UpdateStatusRequestBody):
2448
+ async def _async_update_collection_status(self, collection_guid: str, status: str = None,
2449
+ body: dict | UpdateStatusRequestBody = None):
2970
2450
  """Update the status of a collection. Async version.
2971
2451
 
2972
2452
  Parameters
2973
2453
  ----------
2974
2454
  collection_guid: str
2975
2455
  The guid of the collection to update.
2976
- body: dict | UpdateStatusRequestBody
2977
- A structure representing the details of the collection to create.
2456
+ status: str, optional
2457
+ The new lifecycle status for the collection. Ignored, if the body is provided.
2458
+ body: dict | UpdateStatusRequestBody, optional
2459
+ A structure representing the details of the collection to create. If supplied, these details
2460
+ supersede the status parameter provided.
2978
2461
 
2979
2462
  Returns
2980
2463
  -------
@@ -3002,31 +2485,24 @@ class CollectionManager(Client2):
3002
2485
  "forDuplicateProcessing": false
3003
2486
  }
3004
2487
  """
3005
- try:
3006
- if isinstance(body, UpdateStatusRequestBody):
3007
- validated_body = body
3008
- elif isinstance(body, dict):
3009
- validated_body = self._update_status_request_adapter.validate_python(body)
3010
-
3011
- except ValidationError as e:
3012
- logger.error(f"Validation error: {e}")
3013
- raise ValidationError(e)
3014
2488
 
3015
2489
  url = f"{self.collection_command_root}/{collection_guid}/update-status"
3016
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3017
- await self._async_make_request("POST", url, json_body)
3018
- logger.info(f"Successfully updated {collection_guid} with {json_body}")
2490
+ await self._async_update_status_request(url, status, body)
3019
2491
 
3020
2492
  @dynamic_catch
3021
- def update_collection_status(self, collection_guid: str, body: dict | UpdateStatusRequestBody):
2493
+ def update_collection_status(self, collection_guid: str, status: str = None,
2494
+ body: dict | UpdateStatusRequestBody = None):
3022
2495
  """Update the status of a DigitalProduct collection.
3023
2496
 
3024
2497
  Parameters
3025
2498
  ----------
3026
2499
  collection_guid: str
3027
2500
  The guid of the collection to update.
3028
- body: dict | UpdateStatusRequestBody
3029
- A structure representing the details of the collection to create.
2501
+ status: str, optional
2502
+ The new lifecycle status for the digital product. Ignored, if the body is provided.
2503
+ body: dict | UpdateStatusRequestBody, optional
2504
+ A structure representing the details of the collection to create. If supplied, these details
2505
+ supersede the status parameter provided.
3030
2506
 
3031
2507
  Returns
3032
2508
  -------
@@ -3055,19 +2531,23 @@ class CollectionManager(Client2):
3055
2531
  }
3056
2532
  """
3057
2533
  loop = asyncio.get_event_loop()
3058
- loop.run_until_complete(self._async_update_collection_status(collection_guid, body))
2534
+ loop.run_until_complete(self._async_update_collection_status(collection_guid, status, body))
3059
2535
 
3060
2536
 
3061
2537
  @dynamic_catch
3062
- def update_digital_product_status(self, digital_product_guid: str, body: dict | UpdateStatusRequestBody):
2538
+ def update_digital_product_status(self, digital_product_guid: str, status: str = None,
2539
+ body: dict | UpdateStatusRequestBody = None):
3063
2540
  """Update the status of a DigitalProduct collection.
3064
2541
 
3065
2542
  Parameters
3066
2543
  ----------
3067
2544
  digital_product_guid: str
3068
- The guid of the digital product collection to update.
3069
- body: dict | UpdateStatusRequestBody
3070
- A structure representing the details of the collection to create.
2545
+ The guid of the collection to update.
2546
+ status: str, optional
2547
+ The new lifecycle status for the digital product. Ignored, if the body is provided.
2548
+ body: dict | UpdateStatusRequestBody, optional
2549
+ A structure representing the details of the collection to create. If supplied, these details
2550
+ supersede the status parameter provided.
3071
2551
 
3072
2552
  Returns
3073
2553
  -------
@@ -3096,7 +2576,7 @@ class CollectionManager(Client2):
3096
2576
  }
3097
2577
  """
3098
2578
  loop = asyncio.get_event_loop()
3099
- loop.run_until_complete(self._async_update_collection_status(digital_product_guid, body))
2579
+ loop.run_until_complete(self._async_update_collection_status(digital_product_guid, status, body))
3100
2580
 
3101
2581
 
3102
2582
  @dynamic_catch
@@ -3147,28 +2627,11 @@ class CollectionManager(Client2):
3147
2627
  }
3148
2628
  }
3149
2629
  """
3150
- try:
3151
- if isinstance(body, NewRelationshipRequestBody):
3152
- validated_body = body
3153
- elif isinstance(body, dict):
3154
- validated_body = self._new_relationship_request_adapter.validate_python(body)
3155
- else:
3156
- validated_body = None
3157
-
3158
- except ValidationError as e:
3159
- logger.error(f"Validation error: {e}")
3160
- raise ValidationError(e)
3161
-
3162
-
3163
2630
  url = (
3164
2631
  f"{self.platform_url}/servers/"
3165
2632
  f"{self.view_server}/api/open-metadata/collection-manager/collections/digital-products/"
3166
2633
  f"{upstream_digital_prod_guid}/product-dependencies/{downstream_digital_prod_guid}/attach")
3167
- if validated_body:
3168
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3169
- await self._async_make_request("POST", url, json_body)
3170
- else:
3171
- await self._async_make_request("POST", url)
2634
+ await self._async_new_relationship_request(url, "InformationSupplyChainLinkProperties", body)
3172
2635
  logger.info(f"Linked {upstream_digital_prod_guid} -> {downstream_digital_prod_guid}")
3173
2636
 
3174
2637
 
@@ -3267,30 +2730,13 @@ class CollectionManager(Client2):
3267
2730
  }
3268
2731
 
3269
2732
  """
3270
- try:
3271
- if isinstance(body, DeleteRequestBody):
3272
- validated_body = body
3273
- elif isinstance(body, dict):
3274
- validated_body = self._delete_request_adapter.validate_python(body)
3275
- else:
3276
- validated_body = None
3277
-
3278
- except ValidationError as e:
3279
- logger.error(f"Validation error: {e}")
3280
- raise ValidationError(e)
3281
-
3282
2733
 
3283
2734
  url = (
3284
2735
  f"{self.platform_url}/servers/"
3285
2736
  f"{self.view_server}/api/open-metadata/collection-manager/collections/digital-products/"
3286
2737
  f"{upstream_digital_prod_guid}/product-dependencies/{downstream_digital_prod_guid}/detach")
3287
-
3288
- if validated_body:
3289
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3290
- await self._async_make_request("POST", url, json_body)
3291
- else:
3292
- await self._async_make_request("POST", url)
3293
- logger.info(f"Detched digital product dependency {upstream_digital_prod_guid} -> {downstream_digital_prod_guid}")
2738
+ await self._async_delete_request(url, body)
2739
+ logger.info(f"Detached digital product dependency {upstream_digital_prod_guid} -> {downstream_digital_prod_guid}")
3294
2740
 
3295
2741
 
3296
2742
  def detach_digital_product_dependency(self, upstream_digital_prod_guid: str, downstream_digital_prod_guid: str,
@@ -3386,30 +2832,12 @@ class CollectionManager(Client2):
3386
2832
  }
3387
2833
 
3388
2834
  """
3389
- try:
3390
- if isinstance(body, NewRelationshipRequestBody):
3391
- validated_body = body
3392
- elif isinstance(body, dict):
3393
- validated_body = self._new_relationship_request_adapter.validate_python(body)
3394
- else:
3395
- validated_body = None
3396
- raise PyegeriaInvalidParameterException(additional_info=
3397
- {"reason": "unexpected body type"})
3398
- except ValidationError as e:
3399
- logger.error(f"Validation error: {e}")
3400
- raise ValidationError(e)
3401
-
3402
2835
  url = (
3403
2836
  f"{self.platform_url}/servers/"
3404
2837
  f"{self.view_server}/api/open-metadata/collection-manager/collections/digital"
3405
2838
  f"-products/"
3406
2839
  f"{digital_prod_guid}/product-managers/{digital_prod_manager_guid}/attach")
3407
-
3408
- if validated_body:
3409
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3410
- await self._async_make_request("POST", url, json_body)
3411
- else:
3412
- await self._async_make_request("POST", url)
2840
+ await self._async_new_relationship_request(url, "AssignmentScopeProperties",body)
3413
2841
  logger.info(f"Attached digital product manager {digital_prod_guid} -> {digital_prod_manager_guid}")
3414
2842
 
3415
2843
 
@@ -3503,31 +2931,12 @@ class CollectionManager(Client2):
3503
2931
  }
3504
2932
 
3505
2933
  """
3506
- try:
3507
- if isinstance(body, DeleteRequestBody):
3508
- validated_body = body
3509
- elif isinstance(body, dict):
3510
- validated_body = self._delete_request_adapter.validate_python(body)
3511
- else:
3512
- validated_body = None
3513
- raise PyegeriaInvalidParameterException(additional_info=
3514
- {"reason": "unexpected body type"})
3515
- except ValidationError as e:
3516
- logger.error(f"Validation error: {e}")
3517
- raise ValidationError(e)
3518
-
3519
-
3520
2934
  url = (
3521
2935
  f"{self.platform_url}/servers/"
3522
2936
  f"{self.view_server}/api/open-metadata/collection-manager/collections/digital-products/"
3523
2937
  f"{digital_prod_guid}/product-dependencies/{digital_prod_manager_guid}/detach")
3524
-
3525
- if validated_body:
3526
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3527
- await self._async_make_request("POST", url, json_body)
3528
- else:
3529
- await self._async_make_request("POST", url)
3530
- logger.info(f"Detched digital product manager {digital_prod_guid} -> {digital_prod_manager_guid}")
2938
+ await self._async_delete_request(url, body)
2939
+ logger.info(f"Detached digital product manager {digital_prod_guid} -> {digital_prod_manager_guid}")
3531
2940
 
3532
2941
  @dynamic_catch
3533
2942
  def detach_product_manager(self, digital_prod_guid: str, digital_prod_manager_guid: str,
@@ -3573,173 +2982,20 @@ class CollectionManager(Client2):
3573
2982
  loop = asyncio.get_event_loop()
3574
2983
  loop.run_until_complete(
3575
2984
  self._async_detach_product_manager(digital_prod_guid, digital_prod_manager_guid,
3576
- body))
3577
-
3578
-
3579
- #
3580
-
3581
- @dynamic_catch
3582
- async def _async_create_agreement(self, body: dict | NewElementRequestBody) -> str:
3583
- """ Create a new collection that represents an agreement.
3584
- Async version.
3585
-
3586
- Parameters
3587
- ----------
3588
- body: dict | NewElementRequestBody
3589
- A structure representing the details of the agreement to create.
3590
-
3591
- Returns
3592
- -------
3593
- str - the guid of the created collection
3594
-
3595
- Raises
3596
- ------
3597
- PyegeriaException
3598
- If the client passes incorrect parameters on the request - such as bad URLs or invalid values
3599
- ValidationError
3600
- Raised by the pydantic validator if the body does not conform to the NewElementRequestBody.
3601
- NotAuthorizedException
3602
- The principle specified by the user_id does not have authorization for the requested action
3603
-
3604
- Notes
3605
- -----
3606
- Note: the three dates: introductionDate, nextVersionDate and withdrawDate must
3607
- be valid dates if specified, otherwise you will get a 400 error response.
3608
-
3609
- JSON Structure looks like:
3610
- {
3611
- "class" : "NewElementRequestBody",
3612
- "isOwnAnchor" : true,
3613
- "anchorScopeGUID" : "optional GUID of search scope",
3614
- "parentGUID" : "xxx",
3615
- "parentRelationshipTypeName" : "CollectionMembership",
3616
- "parentAtEnd1": true,
3617
- "properties": {
3618
- "class" : "AgreementProperties",
3619
- "qualifiedName": "Agreement::Add agreement name here",
3620
- "name" : "display name",
3621
- "description" : "Add description of the agreement here",
3622
- "identifier" : "Add agreement identifier here",
3623
- "additionalProperties": {
3624
- "property1Name" : "property1Value",
3625
- "property2Name" : "property2Value"
3626
- }
3627
- },
3628
- "externalSourceGUID": "add guid here",
3629
- "externalSourceName": "add qualified name here",
3630
- "effectiveTime" : "{{$isoTimestamp}}",
3631
- "forLineage" : false,
3632
- "forDuplicateProcessing" : false,
3633
- "initialStatus" : "ACTIVE"
3634
- }
3635
-
3636
- The valid values for initialStatus are: DRAFT, PREPARED, PROPOSED, APPROVED, REJECTED, APPROVED_CONCEPT,
3637
- UNDER_DEVELOPMENT, DEVELOPMENT_COMPLETE, APPROVED_FOR_DEPLOYMENT, ACTIVE, DISABLED, DEPRECATED,
3638
- OTHER. If using OTHER, set the userDefinedStatus with the status value you want. If not specified, will
3639
- default to ACTIVE.
3640
- """
3641
- try:
3642
- if isinstance(body, NewElementRequestBody):
3643
- if body.properties.class_ == "AgreementProperties":
3644
- validated_body = body
3645
- else:
3646
- raise PyegeriaInvalidParameterException(additional_info=
3647
- {"reason": "unexpected property class name"})
3648
-
3649
- elif isinstance(body, dict):
3650
- if body.get("properties", {}).get("class", "") == "AgreementProperties":
3651
- validated_body = self._new_element_request_adapter.validate_python(body)
3652
- else:
3653
- raise PyegeriaInvalidParameterException(additional_info=
3654
- {"reason": "unexpected property class name"})
3655
-
3656
- else:
3657
- raise TypeError("Invalid parameter type")
3658
-
3659
- except ValidationError as e:
3660
- logger.error(f"Validation error: {e}")
3661
- raise ValidationError(e)
3662
-
3663
- url = f"{self.collection_command_root}"
3664
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3665
- logger.info(json_body)
3666
- resp = await self._async_make_request("POST", url, json_body, is_json=True)
3667
- logger.info(f"Create collection with GUID: {resp.json().get('guid')}")
3668
- return resp.json().get("guid", NO_GUID_RETURNED)
3669
-
3670
- @dynamic_catch
3671
- def create_agreement(self, body: dict | NewElementRequestBody = None) -> str:
3672
- """ Create a new collection that represents an agreement..
3673
-
3674
- Parameters
3675
- ----------
3676
- body: dict | NewElementRequestBody
3677
- A structure representing the details of the agreement to create.
3678
-
3679
- Returns
3680
- -------
3681
- str - the guid of the created collection
3682
-
3683
- Raises
3684
- ------
3685
- PyegeriaException
3686
- If the client passes incorrect parameters on the request - such as bad URLs or invalid values
3687
- ValidationError
3688
- Raised by the pydantic validator if the body does not conform to the NewElementRequestBody.
3689
- NotAuthorizedException
3690
- The principle specified by the user_id does not have authorization for the requested action
3691
-
3692
- Notes
3693
- -----
3694
- Note: the three dates: introductionDate, nextVersionDate and withdrawDate must
3695
- be valid dates if specified, otherwise you will get a 400 error response.
3696
-
3697
- JSON Structure looks like:
3698
- {
3699
- "class" : "NewElementRequestBody",
3700
- "isOwnAnchor" : true,
3701
- "anchorScopeGUID" : "optional GUID of search scope",
3702
- "parentGUID" : "xxx",
3703
- "parentRelationshipTypeName" : "CollectionMembership",
3704
- "parentAtEnd1": true,
3705
- "properties": {
3706
- "class" : "AgreementProperties",
3707
- "qualifiedName": "Agreement::Add agreement name here",
3708
- "name" : "display name",
3709
- "description" : "Add description of the agreement here",
3710
- "identifier" : "Add agreement identifier here",
3711
- "additionalProperties": {
3712
- "property1Name" : "property1Value",
3713
- "property2Name" : "property2Value"
3714
- }
3715
- },
3716
- "externalSourceGUID": "add guid here",
3717
- "externalSourceName": "add qualified name here",
3718
- "effectiveTime" : "{{$isoTimestamp}}",
3719
- "forLineage" : false,
3720
- "forDuplicateProcessing" : false,
3721
- "initialStatus" : "ACTIVE"
3722
- }
3723
-
3724
- The valid values for initialStatus are: DRAFT, PREPARED, PROPOSED, APPROVED, REJECTED, APPROVED_CONCEPT,
3725
- UNDER_DEVELOPMENT, DEVELOPMENT_COMPLETE, APPROVED_FOR_DEPLOYMENT, ACTIVE, DISABLED, DEPRECATED,
3726
- OTHER. If using OTHER, set the userDefinedStatus with the status value you want. If not specified, will
3727
- default to ACTIVE.
3728
- """
2985
+ body))
3729
2986
 
3730
- return asyncio.get_event_loop().run_until_complete(
3731
- self._async_create_agreement(body))
3732
2987
 
2988
+ #
3733
2989
 
3734
2990
  @dynamic_catch
3735
- async def _async_create_data_sharing_agreement(self, body: dict | NewElementRequestBody) -> str:
3736
- """ Create a new collection that represents a data sharing agreement.
2991
+ async def _async_create_agreement(self, body: dict | NewElementRequestBody) -> str:
2992
+ """ Create a new collection that represents an agreement.
3737
2993
  Async version.
3738
2994
 
3739
2995
  Parameters
3740
2996
  ----------
3741
2997
  body: dict | NewElementRequestBody
3742
- A structure representing the details of the data sharing agreement to create.
2998
+ A structure representing the details of the agreement to create.
3743
2999
 
3744
3000
  Returns
3745
3001
  -------
@@ -3772,19 +3028,18 @@ class CollectionManager(Client2):
3772
3028
  "qualifiedName": "Agreement::Add agreement name here",
3773
3029
  "name" : "display name",
3774
3030
  "description" : "Add description of the agreement here",
3775
- "userDefinedStatus" : "NEW",
3776
3031
  "identifier" : "Add agreement identifier here",
3777
3032
  "additionalProperties": {
3778
3033
  "property1Name" : "property1Value",
3779
3034
  "property2Name" : "property2Value"
3780
3035
  }
3781
3036
  },
3782
- "initialStatus" : "ACTIVE",
3783
3037
  "externalSourceGUID": "add guid here",
3784
3038
  "externalSourceName": "add qualified name here",
3785
3039
  "effectiveTime" : "{{$isoTimestamp}}",
3786
3040
  "forLineage" : false,
3787
- "forDuplicateProcessing" : false
3041
+ "forDuplicateProcessing" : false,
3042
+ "initialStatus" : "ACTIVE"
3788
3043
  }
3789
3044
 
3790
3045
  The valid values for initialStatus are: DRAFT, PREPARED, PROPOSED, APPROVED, REJECTED, APPROVED_CONCEPT,
@@ -3792,43 +3047,17 @@ class CollectionManager(Client2):
3792
3047
  OTHER. If using OTHER, set the userDefinedStatus with the status value you want. If not specified, will
3793
3048
  default to ACTIVE.
3794
3049
  """
3795
- try:
3796
- if isinstance(body, NewElementRequestBody):
3797
- if body.properties.class_ == "AgreementProperties":
3798
- validated_body = body
3799
- else:
3800
- raise PyegeriaInvalidParameterException(additional_info=
3801
- {"reason": "unexpected property class name"})
3802
-
3803
- elif isinstance(body, dict):
3804
- if body.get("properties", {}).get("class", "") == "AgreementProperties":
3805
- validated_body = self._new_element_request_adapter.validate_python(body)
3806
- else:
3807
- raise PyegeriaInvalidParameterException(additional_info=
3808
- {"reason": "unexpected property class name"})
3809
-
3810
- else:
3811
- raise TypeError("Invalid parameter type")
3812
-
3813
- except ValidationError as e:
3814
- logger.error(f"Validation error: {e}")
3815
- raise ValidationError(e)
3816
-
3817
- url = f"{self.collection_command_root}/data-sharing-agreement"
3818
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3819
- logger.info(json_body)
3820
- resp = await self._async_make_request("POST", url, json_body, is_json=True)
3821
- logger.info(f"Create collection with GUID: {resp.json().get('guid')}")
3822
- return resp.json().get("guid", NO_GUID_RETURNED)
3050
+ url = f"{self.collection_command_root}"
3051
+ return await self._async_create_element_body_request(url, "AgreementProperties", body)
3823
3052
 
3824
3053
  @dynamic_catch
3825
- def create_data_sharing_agreement(self, body: dict | NewElementRequestBody = None) -> str:
3826
- """ Create a new collection that represents a digital product.
3054
+ def create_agreement(self, body: dict | NewElementRequestBody = None) -> str:
3055
+ """ Create a new collection that represents an agreement..
3827
3056
 
3828
3057
  Parameters
3829
3058
  ----------
3830
3059
  body: dict | NewElementRequestBody
3831
- A structure representing the details of the digital product to create.
3060
+ A structure representing the details of the agreement to create.
3832
3061
 
3833
3062
  Returns
3834
3063
  -------
@@ -3857,19 +3086,11 @@ class CollectionManager(Client2):
3857
3086
  "parentRelationshipTypeName" : "CollectionMembership",
3858
3087
  "parentAtEnd1": true,
3859
3088
  "properties": {
3860
- "class" : "DigitalProductProperties",
3861
- "qualifiedName": "DigitalProduct::Add product name here",
3862
- "name" : "Product contents",
3863
- "description" : "Add description of product and its expected usage here",
3864
- "identifier" : "Add product identifier here",
3865
- "productName" : "Add product name here",
3866
- "category" : "Periodic Delta",
3867
- "maturity" : "Add valid value here",
3868
- "serviceLife" : "Add the estimated lifetime of the product",
3869
- "introductionDate" : "date",
3870
- "nextVersionDate": "date",
3871
- "withdrawDate": "date",
3872
- "currentVersion": "V0.1",
3089
+ "class" : "AgreementProperties",
3090
+ "qualifiedName": "Agreement::Add agreement name here",
3091
+ "name" : "display name",
3092
+ "description" : "Add description of the agreement here",
3093
+ "identifier" : "Add agreement identifier here",
3873
3094
  "additionalProperties": {
3874
3095
  "property1Name" : "property1Value",
3875
3096
  "property2Name" : "property2Value"
@@ -3890,12 +3111,148 @@ class CollectionManager(Client2):
3890
3111
  """
3891
3112
 
3892
3113
  return asyncio.get_event_loop().run_until_complete(
3893
- self._async_create_data_sharing_agreement(body))
3114
+ self._async_create_agreement(body))
3894
3115
 
3116
+ #
3117
+ # @dynamic_catch
3118
+ # async def _async_create_data_sharing_agreement(self, body: dict | NewElementRequestBody) -> str:
3119
+ # """ Create a new collection that represents a data sharing agreement.
3120
+ # Async version.
3121
+ #
3122
+ # Parameters
3123
+ # ----------
3124
+ # body: dict | NewElementRequestBody
3125
+ # A structure representing the details of the data sharing agreement to create.
3126
+ #
3127
+ # Returns
3128
+ # -------
3129
+ # str - the guid of the created collection
3130
+ #
3131
+ # Raises
3132
+ # ------
3133
+ # PyegeriaException
3134
+ # If the client passes incorrect parameters on the request - such as bad URLs or invalid values
3135
+ # ValidationError
3136
+ # Raised by the pydantic validator if the body does not conform to the NewElementRequestBody.
3137
+ # NotAuthorizedException
3138
+ # The principle specified by the user_id does not have authorization for the requested action
3139
+ #
3140
+ # Notes
3141
+ # -----
3142
+ # Note: the three dates: introductionDate, nextVersionDate and withdrawDate must
3143
+ # be valid dates if specified, otherwise you will get a 400 error response.
3144
+ #
3145
+ # JSON Structure looks like:
3146
+ # {
3147
+ # "class" : "NewElementRequestBody",
3148
+ # "isOwnAnchor" : true,
3149
+ # "anchorScopeGUID" : "optional GUID of search scope",
3150
+ # "parentGUID" : "xxx",
3151
+ # "parentRelationshipTypeName" : "CollectionMembership",
3152
+ # "parentAtEnd1": true,
3153
+ # "properties": {
3154
+ # "class" : "AgreementProperties",
3155
+ # "qualifiedName": "Agreement::Add agreement name here",
3156
+ # "name" : "display name",
3157
+ # "description" : "Add description of the agreement here",
3158
+ # "userDefinedStatus" : "NEW",
3159
+ # "identifier" : "Add agreement identifier here",
3160
+ # "additionalProperties": {
3161
+ # "property1Name" : "property1Value",
3162
+ # "property2Name" : "property2Value"
3163
+ # }
3164
+ # },
3165
+ # "initialStatus" : "ACTIVE",
3166
+ # "externalSourceGUID": "add guid here",
3167
+ # "externalSourceName": "add qualified name here",
3168
+ # "effectiveTime" : "{{$isoTimestamp}}",
3169
+ # "forLineage" : false,
3170
+ # "forDuplicateProcessing" : false
3171
+ # }
3172
+ #
3173
+ # The valid values for initialStatus are: DRAFT, PREPARED, PROPOSED, APPROVED, REJECTED, APPROVED_CONCEPT,
3174
+ # UNDER_DEVELOPMENT, DEVELOPMENT_COMPLETE, APPROVED_FOR_DEPLOYMENT, ACTIVE, DISABLED, DEPRECATED,
3175
+ # OTHER. If using OTHER, set the userDefinedStatus with the status value you want. If not specified, will
3176
+ # default to ACTIVE.
3177
+ # """
3178
+ #
3179
+ # url = f"{self.collection_command_root}/data-sharing-agreement"
3180
+ # return await self._async_create_element_body_request(url, "AgreementProperties", body)
3181
+ #
3182
+ # @dynamic_catch
3183
+ # def create_data_sharing_agreement(self, body: dict | NewElementRequestBody = None) -> str:
3184
+ # """ Create a new collection that represents a digital product.
3185
+ #
3186
+ # Parameters
3187
+ # ----------
3188
+ # body: dict | NewElementRequestBody
3189
+ # A structure representing the details of the digital product to create.
3190
+ #
3191
+ # Returns
3192
+ # -------
3193
+ # str - the guid of the created collection
3194
+ #
3195
+ # Raises
3196
+ # ------
3197
+ # PyegeriaException
3198
+ # If the client passes incorrect parameters on the request - such as bad URLs or invalid values
3199
+ # ValidationError
3200
+ # Raised by the pydantic validator if the body does not conform to the NewElementRequestBody.
3201
+ # NotAuthorizedException
3202
+ # The principle specified by the user_id does not have authorization for the requested action
3203
+ #
3204
+ # Notes
3205
+ # -----
3206
+ # Note: the three dates: introductionDate, nextVersionDate and withdrawDate must
3207
+ # be valid dates if specified, otherwise you will get a 400 error response.
3208
+ #
3209
+ # JSON Structure looks like:
3210
+ # {
3211
+ # "class" : "NewElementRequestBody",
3212
+ # "isOwnAnchor" : true,
3213
+ # "anchorScopeGUID" : "optional GUID of search scope",
3214
+ # "parentGUID" : "xxx",
3215
+ # "parentRelationshipTypeName" : "CollectionMembership",
3216
+ # "parentAtEnd1": true,
3217
+ # "properties": {
3218
+ # "class" : "DigitalProductProperties",
3219
+ # "qualifiedName": "DigitalProduct::Add product name here",
3220
+ # "name" : "Product contents",
3221
+ # "description" : "Add description of product and its expected usage here",
3222
+ # "identifier" : "Add product identifier here",
3223
+ # "productName" : "Add product name here",
3224
+ # "category" : "Periodic Delta",
3225
+ # "maturity" : "Add valid value here",
3226
+ # "serviceLife" : "Add the estimated lifetime of the product",
3227
+ # "introductionDate" : "date",
3228
+ # "nextVersionDate": "date",
3229
+ # "withdrawDate": "date",
3230
+ # "currentVersion": "V0.1",
3231
+ # "additionalProperties": {
3232
+ # "property1Name" : "property1Value",
3233
+ # "property2Name" : "property2Value"
3234
+ # }
3235
+ # },
3236
+ # "externalSourceGUID": "add guid here",
3237
+ # "externalSourceName": "add qualified name here",
3238
+ # "effectiveTime" : "{{$isoTimestamp}}",
3239
+ # "forLineage" : false,
3240
+ # "forDuplicateProcessing" : false,
3241
+ # "initialStatus" : "ACTIVE"
3242
+ # }
3243
+ #
3244
+ # The valid values for initialStatus are: DRAFT, PREPARED, PROPOSED, APPROVED, REJECTED, APPROVED_CONCEPT,
3245
+ # UNDER_DEVELOPMENT, DEVELOPMENT_COMPLETE, APPROVED_FOR_DEPLOYMENT, ACTIVE, DISABLED, DEPRECATED,
3246
+ # OTHER. If using OTHER, set the userDefinedStatus with the status value you want. If not specified, will
3247
+ # default to ACTIVE.
3248
+ # """
3249
+ #
3250
+ # return asyncio.get_event_loop().run_until_complete(
3251
+ # self._async_create_data_sharing_agreement(body))
3252
+ #
3895
3253
 
3896
3254
  @dynamic_catch
3897
- async def _async_update_agreement(self, agreement_guid: str, body: dict | UpdateElementRequestBody,
3898
- merge_update: bool = True) -> None:
3255
+ async def _async_update_agreement(self, agreement_guid: str, body: dict | UpdateElementRequestBody) -> None:
3899
3256
  """ Update the properties of an agreement.
3900
3257
  Collections: https://egeria-project.org/concepts/collection
3901
3258
 
@@ -3948,43 +3305,11 @@ class CollectionManager(Client2):
3948
3305
  "forDuplicateProcessing" : false
3949
3306
  }
3950
3307
  """
3951
-
3952
- try:
3953
- if isinstance(body, NewElementRequestBody):
3954
- if body.properties.class_ == "AgreementProperties":
3955
- validated_body = body
3956
- else:
3957
- raise PyegeriaInvalidParameterException(additional_info =
3958
- {"reason" : "unexpected property class name"})
3959
-
3960
- elif isinstance(body, dict):
3961
- if body.get("properties", {}).get("class", "") == "AgreementProperties":
3962
- validated_body = self._update_element_request_adapter.validate_python(body)
3963
- else:
3964
- raise PyegeriaInvalidParameterException(additional_info =
3965
- {"reason" : "unexpected property class name"})
3966
- else:
3967
- raise TypeError("Invalid parameter type")
3968
-
3969
- except ValidationError as e:
3970
- logger.error(f"Validation error: {e}")
3971
- raise ValidationError(e)
3972
-
3973
- merge_update_s = str(merge_update).lower()
3974
-
3975
- url = (f"{self.collection_command_root}/{agreement_guid}/update?"
3976
- f"replaceAllProperties={merge_update_s}")
3977
-
3978
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3979
-
3980
- await self._async_make_request("POST", url, json_body)
3981
-
3982
- logger.info(f"Successfully updated {agreement_guid} with {json_body}")
3983
-
3308
+ url = (f"{self.collection_command_root}/{agreement_guid}/update")
3309
+ await self._async_update_element_body_request(url, AGREEMENT_PROPERTIES_LIST,body)
3984
3310
 
3985
3311
  @dynamic_catch
3986
- def update_agreement(self, agreement_guid: str, body: dict | UpdateElementRequestBody,
3987
- merge_update: bool = True) -> None:
3312
+ def update_agreement(self, agreement_guid: str, body: dict | UpdateElementRequestBody) -> None:
3988
3313
  """ Update the properties of an agreement.
3989
3314
  Collections: https://egeria-project.org/concepts/collection
3990
3315
 
@@ -4038,68 +3363,20 @@ class CollectionManager(Client2):
4038
3363
  """
4039
3364
 
4040
3365
  return asyncio.get_event_loop().run_until_complete(
4041
- self._async_update_agreement(agreement_guid, body, merge_update))
4042
-
4043
-
4044
- @dynamic_catch
4045
- async def _async_update_agreement_status(self, agreement_guid: str, body: dict | UpdateStatusRequestBody):
4046
- """Update the status of an agreement. Async version.
4047
-
4048
- Parameters
4049
- ----------
4050
- agreement_guid: str
4051
- The guid of the collection to update.
4052
- body: dict | UpdateStatusRequestBody
4053
- A structure representing the details of the collection to create.
4054
-
4055
- Returns
4056
- -------
4057
- Nothing
4058
-
4059
- Raises
4060
- ------
4061
- InvalidParameterException
4062
- If the client passes incorrect parameters on the request - such as bad URLs or invalid values
4063
- PropertyServerException
4064
- Raised by the server when an issue arises in processing a valid request
4065
- NotAuthorizedException
4066
- The principle specified by the user_id does not have authorization for the requested action
4067
-
4068
- Notes
4069
- -----
4070
- JSON Structure looks like:
4071
- {
4072
- "class": "UpdateStatusRequestBody",
4073
- "status": "APPROVED",
4074
- "externalSourceGUID": "add guid here",
4075
- "externalSourceName": "add qualified name here",
4076
- "effectiveTime": "{{$isoTimestamp}}",
4077
- "forLineage": false,
4078
- "forDuplicateProcessing": false
4079
- }
4080
- """
4081
- try:
4082
- if isinstance(body, UpdateStatusRequestBody):
4083
- validated_body = body
4084
- elif isinstance(body, dict):
4085
- validated_body = self._update_status_request_adapter.validate_python(body)
3366
+ self._async_update_agreement(agreement_guid, body))
4086
3367
 
4087
- except ValidationError as e:
4088
- logger.error(f"Validation error: {e}")
4089
- raise ValidationError(e)
4090
3368
 
4091
- url = f"{self.collection_command_root}/{agreement_guid}/update-status"
4092
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
4093
- await self._async_make_request("POST", url, json_body)
4094
- logger.info(f"Successfully updated {agreement_guid} with {json_body}")
4095
3369
 
4096
3370
  @dynamic_catch
4097
- def update_agreement_status(self, agreement_guid: str, body: dict | UpdateStatusRequestBody):
3371
+ def update_agreement_status(self, agreement_guid: str, status: str = None,
3372
+ body: dict | UpdateStatusRequestBody = None):
4098
3373
  """Update the status of an agreement.
4099
3374
  Parameters
4100
3375
  ----------
4101
3376
  agreement_guid: str
4102
3377
  The guid of the collection to update.
3378
+ status: str, optional
3379
+ The new lifecycle status for the collection. Ignored, if the body is provided.
4103
3380
  body: dict | UpdateStatusRequestBody
4104
3381
  A structure representing the details of the collection to create.
4105
3382
 
@@ -4130,7 +3407,7 @@ class CollectionManager(Client2):
4130
3407
  }
4131
3408
  """
4132
3409
  loop = asyncio.get_event_loop()
4133
- loop.run_until_complete(self._async_update_collection_status(agreement_guid, body))
3410
+ loop.run_until_complete(self._async_update_collection_status(agreement_guid, status,body))
4134
3411
 
4135
3412
 
4136
3413
 
@@ -4183,37 +3460,11 @@ class CollectionManager(Client2):
4183
3460
  }
4184
3461
 
4185
3462
  """
4186
- try:
4187
- if isinstance(body, NewRelationshipRequestBody):
4188
- if body.properties.class_ == "AgreementActorProperties":
4189
- validated_body = body
4190
- else:
4191
- raise PyegeriaInvalidParameterException(additional_info=
4192
- {"reason": "unexpected property class name"})
4193
-
4194
- elif isinstance(body, dict):
4195
- if body.get("properties", {}).get("class", "") == "AgreementActorProperties":
4196
- validated_body = self._new_relationship_request_adapter.validate_python(body)
4197
- else:
4198
- raise PyegeriaInvalidParameterException(additional_info=
4199
- {"reason": "unexpected property class name"})
4200
- else:
4201
- validated_body = None
4202
-
4203
- except ValidationError as e:
4204
- logger.error(f"Validation error: {e}")
4205
- raise ValidationError(e)
4206
-
4207
3463
  url = (
4208
3464
  f"{self.platform_url}/servers/"
4209
3465
  f"{self.view_server}/api/open-metadata/collection-manager/collections/agreements/"
4210
3466
  f"{agreement_guid}/agreement-actors/{actor_guid}/attach")
4211
-
4212
- if validated_body:
4213
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
4214
- await self._async_make_request("POST", url, json_body)
4215
- else:
4216
- await self._async_make_request("POST", url)
3467
+ await self._async_new_relationship_request(url, "AgreementActorProperties",body)
4217
3468
  logger.info(f"Attached digital product manager {agreement_guid} -> {actor_guid}")
4218
3469
 
4219
3470
 
@@ -4312,28 +3563,11 @@ class CollectionManager(Client2):
4312
3563
 
4313
3564
  """
4314
3565
 
4315
- try:
4316
- if isinstance(body, DeleteRequestBody):
4317
- validated_body = body
4318
- elif isinstance(body, dict):
4319
- validated_body = self._delete_request_adapter.validate_python(body)
4320
- else:
4321
- validated_body = None
4322
-
4323
- except ValidationError as e:
4324
- logger.error(f"Validation error: {e}")
4325
- raise ValidationError(e)
4326
-
4327
3566
  url = (
4328
3567
  f"{self.platform_url}/servers/"
4329
3568
  f"{self.view_server}/api/open-metadata/collection-manager/collections/agreements/"
4330
3569
  f"{agreement_guid}/agreement-actors/{actor_guid}/detach")
4331
-
4332
- if validated_body:
4333
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
4334
- await self._async_make_request("POST", url, json_body)
4335
- else:
4336
- await self._async_make_request("POST", url)
3570
+ self._async_delete_request(url, body)
4337
3571
  logger.info(f"Detached digital product manager {agreement_guid} -> {actor_guid}")
4338
3572
 
4339
3573
 
@@ -4388,7 +3622,7 @@ class CollectionManager(Client2):
4388
3622
 
4389
3623
  @dynamic_catch
4390
3624
  async def _async_link_agreement_item(self, agreement_guid: str, agreement_item_guid: str,
4391
- body: dict = None) -> None:
3625
+ body: dict| NewRelationshipRequestBody = None) -> None:
4392
3626
  """ Attach an agreement to an element referenced in its definition. The agreement item element is of type
4393
3627
  'Referenceable' to allow the agreement to refer to many things. Request body is optional. Async version.
4394
3628
 
@@ -4398,7 +3632,7 @@ class CollectionManager(Client2):
4398
3632
  The guid of the agreement to update.
4399
3633
  agreement_item_guid: str
4400
3634
  The guid of the element to attach.
4401
- body: dict, optional, default = None
3635
+ body: dict | NewRelationshipRequestBody, optional, default = None
4402
3636
  A dict representing the details of the relationship.
4403
3637
 
4404
3638
  Returns
@@ -4416,9 +3650,8 @@ class CollectionManager(Client2):
4416
3650
 
4417
3651
  Notes
4418
3652
  _____
4419
-
4420
3653
  {
4421
- "class" : "RelationshipRequestBody",
3654
+ "class" : "NewRelationshipRequestBody",
4422
3655
  "externalSourceGUID": "add guid here",
4423
3656
  "externalSourceName": "add qualified name here",
4424
3657
  "effectiveTime" : "{{$isoTimestamp}}",
@@ -4437,6 +3670,10 @@ class CollectionManager(Client2):
4437
3670
  "property1Name" : "property1Value",
4438
3671
  "property2Name" : "property2Value"
4439
3672
  },
3673
+ "entitlements" : {
3674
+ "property1Name" : "property1Value",
3675
+ "property2Name" : "property2Value"
3676
+ },
4440
3677
  "usageMeasurements" : {
4441
3678
  "property1Name" : "property1Value",
4442
3679
  "property2Name" : "property2Value"
@@ -4446,15 +3683,11 @@ class CollectionManager(Client2):
4446
3683
  }
4447
3684
  }
4448
3685
 
4449
- """
4450
-
3686
+ """
4451
3687
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections/"
4452
3688
  f"agreements/{agreement_guid}/agreement-items/{agreement_item_guid}/attach")
4453
3689
 
4454
- if body:
4455
- await self._async_make_request("POST", url, body)
4456
- else:
4457
- await self._async_make_request("POST", url)
3690
+ await self._async_new_relationship_request(url, "AgreementItemProperties", body)
4458
3691
  logger.info(f"Attached agreement item {agreement_item_guid} to {agreement_guid}")
4459
3692
 
4460
3693
 
@@ -4523,7 +3756,7 @@ class CollectionManager(Client2):
4523
3756
 
4524
3757
  @dynamic_catch
4525
3758
  async def _async_detach_agreement_item(self, agreement_guid: str, agreement_item_guid: str,
4526
- body: dict = None) -> None:
3759
+ body: dict | DeleteRequestBody = None) -> None:
4527
3760
  """Detach an agreement item from an agreement. Request body is optional. Async version.
4528
3761
 
4529
3762
  Parameters
@@ -4532,8 +3765,8 @@ class CollectionManager(Client2):
4532
3765
  The guid of the agreement to link.
4533
3766
  agreement_item_guid: str
4534
3767
  The guid of the element to attach.
4535
- body: dict, optional, default = None
4536
- A dict representing the details of the relationship.
3768
+ body: dict | DeleteRequestBody, optional, default = None
3769
+ A structure representing the details of the relationship.
4537
3770
 
4538
3771
  Returns
4539
3772
  -------
@@ -4551,25 +3784,20 @@ class CollectionManager(Client2):
4551
3784
  Notes
4552
3785
  _____
4553
3786
  {
4554
- "class" : "MetadataSourceRequestBody",
3787
+ "class": "DeleteRequestBody",
4555
3788
  "externalSourceGUID": "add guid here",
4556
3789
  "externalSourceName": "add qualified name here",
4557
- "effectiveTime" : "{{$isoTimestamp}}",
4558
- "forLineage" : false,
4559
- "forDuplicateProcessing" : false
3790
+ "effectiveTime": "{{$isoTimestamp}}",
3791
+ "forLineage": false,
3792
+ "forDuplicateProcessing": false
4560
3793
  }
4561
3794
 
4562
3795
  """
4563
-
4564
3796
  url = (
4565
3797
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections"
4566
3798
  f"/agreements"
4567
3799
  f"{agreement_guid}/agreement-items/{agreement_item_guid}/detach")
4568
-
4569
- if body:
4570
- await self._async_make_request("POST", url, body)
4571
- else:
4572
- await self._async_make_request("POST", url)
3800
+ await self._async_delete_request(url, body)
4573
3801
  logger.info(f"Detached agreement item {agreement_item_guid} from {agreement_guid}")
4574
3802
 
4575
3803
 
@@ -4615,7 +3843,8 @@ class CollectionManager(Client2):
4615
3843
 
4616
3844
 
4617
3845
  @dynamic_catch
4618
- async def _async_link_contract(self, agreement_guid: str, external_ref_guid: str, body: dict = None) -> None:
3846
+ async def _async_link_contract(self, agreement_guid: str, external_ref_guid: str,
3847
+ body: dict | NewRelationshipRequestBody = None) -> None:
4619
3848
  """ Attach an agreement to an external reference element that describes the location of the contract
4620
3849
  documents.
4621
3850
  Request body is optional. Async version.
@@ -4626,8 +3855,8 @@ class CollectionManager(Client2):
4626
3855
  The guid of the agreement to update.
4627
3856
  external_ref_guid: str
4628
3857
  The guid of the external reference to attach.
4629
- body: dict, optional, default = None
4630
- A dict representing the details of the relationship.
3858
+ body: dict | NewRelationshipRequestBody, optional, default = None
3859
+ A structure representing the details of the relationship.
4631
3860
 
4632
3861
  Returns
4633
3862
  -------
@@ -4664,17 +3893,12 @@ class CollectionManager(Client2):
4664
3893
  }
4665
3894
 
4666
3895
  """
4667
-
4668
3896
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections/"
4669
3897
  f"agreements/{agreement_guid}/contract-links/{external_ref_guid}/attach")
3898
+ await self._async_new_relationship_request(url, "ContractLinkProperties", body)
3899
+ logger.info(f"Attached agreement {agreement_guid} to contract {external_ref_guid}")
4670
3900
 
4671
- if body:
4672
- await self._async_make_request("POST", url, body)
4673
- else:
4674
- await self._async_make_request("POST", url)
4675
- logger.info(f"Attached agreemenbt {agreement_guid} to contract {external_ref_guid}")
4676
-
4677
-
3901
+ @dynamic_catch
4678
3902
  def link_contract(self, agreement_guid: str, external_ref_guid: str, body: dict = None) -> None:
4679
3903
  """ Attach an agreement to an external reference element that describes the location of the contract
4680
3904
  documents.
@@ -4769,16 +3993,11 @@ class CollectionManager(Client2):
4769
3993
 
4770
3994
  url = (
4771
3995
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections"
4772
- f"/agreements"
4773
- f"{agreement_guid}/contract-links/{external_ref_guid}/detach")
4774
-
4775
- if body:
4776
- await self._async_make_request("POST", url, body)
4777
- else:
4778
- await self._async_make_request("POST", url)
3996
+ f"/agreements/{agreement_guid}/contract-links/{external_ref_guid}/detach")
3997
+ await self._async_delete_request(url, body)
4779
3998
  logger.info(f"Detached contract: {external_ref_guid} from {agreement_guid}")
4780
3999
 
4781
-
4000
+ @dynamic_catch
4782
4001
  def detach_contract(self, agreement_guid: str, external_ref_guid: str, body: dict = None) -> None:
4783
4002
  """Detach an external reference to a contract, from an agreement. Request body is optional.
4784
4003
 
@@ -4825,13 +4044,13 @@ class CollectionManager(Client2):
4825
4044
 
4826
4045
 
4827
4046
  @dynamic_catch
4828
- async def _async_create_digital_subscription(self, body: dict) -> str:
4047
+ async def _async_create_digital_subscription(self, body: dict | NewElementRequestBody) -> str:
4829
4048
  """Create a new collection that represents a type of agreement called a digital_subscription. Async version.
4830
4049
 
4831
4050
  Parameters
4832
4051
  ----------
4833
- body: dict
4834
- A dict representing the details of the collection to create.
4052
+ body | NewElementRequewstBody: dict
4053
+ A structure representing the details of the collection to create.
4835
4054
 
4836
4055
  Returns
4837
4056
  -------
@@ -4923,13 +4142,8 @@ class CollectionManager(Client2):
4923
4142
  "forDuplicateProcessing" : false
4924
4143
  }
4925
4144
  """
4926
-
4927
4145
  url = f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections"
4928
-
4929
- resp = await self._async_make_request("POST", url, body_slimmer(body))
4930
- guid = resp.json().get('guid', NO_GUID_RETURNED)
4931
- logger.info(f"Create collection with GUID: {guid}")
4932
- return guid
4146
+ return await self._async_create_element_body_request(url, "DigitalSubscriptionProperties", body)
4933
4147
 
4934
4148
 
4935
4149
  def create_digital_subscription(self, body: dict) -> str:
@@ -5005,19 +4219,16 @@ class CollectionManager(Client2):
5005
4219
 
5006
4220
 
5007
4221
  @dynamic_catch
5008
- async def _async_update_digital_subscription(self, digital_subscription_guid: str, body: dict,
5009
- replace_all_props: bool = False, ):
4222
+ async def _async_update_digital_subscription(self, digital_subscription_guid: str,
4223
+ body: dict | UpdateElementRequestBody) -> None:
5010
4224
  """Update the properties of the digital_subscription collection. Async version.
5011
4225
 
5012
4226
  Parameters
5013
4227
  ----------
5014
4228
  digital_subscription_guid: str
5015
4229
  The guid of the digital_subscription to update.
5016
- body: dict
5017
- A dict representing the details of the collection to create.
5018
- replace_all_props: bool, optional, defaults to False
5019
- Whether to replace all properties in the collection.
5020
-
4230
+ body: dict | UpdateElementRequestBody
4231
+ A structure representing the details of the collection to create.
5021
4232
 
5022
4233
  Returns
5023
4234
  -------
@@ -5061,17 +4272,13 @@ class CollectionManager(Client2):
5061
4272
  "forDuplicateProcessing" : false
5062
4273
  }
5063
4274
  """
5064
-
5065
- replace_all_props_s = str(replace_all_props).lower()
5066
4275
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections/"
5067
- f"{digital_subscription_guid}/update?replaceAllProperties={replace_all_props_s}")
5068
-
5069
- await self._async_make_request("POST", url, body)
4276
+ f"{digital_subscription_guid}/update")
4277
+ await self._async_update_element_body_request(url,["DigitalSubscriptionProperties"], body )
5070
4278
  logger.info(f"Updated digital subscription {digital_subscription_guid}")
5071
4279
 
5072
-
5073
- def update_digital_subscription(self, digital_subscription_guid: str, body: dict,
5074
- replace_all_props: bool = False, ):
4280
+ @dynamic_catch
4281
+ def update_digital_subscription(self, digital_subscription_guid: str, body: dict,):
5075
4282
  """Update the properties of the DigitalProduct classification attached to a collection.
5076
4283
 
5077
4284
  Parameters
@@ -5124,19 +4331,22 @@ class CollectionManager(Client2):
5124
4331
  """
5125
4332
  loop = asyncio.get_event_loop()
5126
4333
  loop.run_until_complete(
5127
- self._async_update_digital_subscription(digital_subscription_guid, body, replace_all_props))
4334
+ self._async_update_digital_subscription(digital_subscription_guid, body))
5128
4335
 
5129
4336
 
5130
4337
  @dynamic_catch
5131
- async def _async_update_digital_subscription_status(self, digital_subscription_guid: str, body: dict):
5132
- """Update the status of an digital_subscription collection. Async version.
4338
+ async def _async_update_digital_subscription_status(self, digital_subscription_guid: str, status: str = None,
4339
+ body: dict | UpdateStatusRequestBody = None)-> None:
4340
+ """Update the status of a digital_subscription collection. Async version.
5133
4341
 
5134
4342
  Parameters
5135
4343
  ----------
5136
4344
  digital_subscription_guid: str
5137
4345
  The guid of the digital product collection to update.
5138
- body: dict
5139
- A dict representing the details of the collection to create.
4346
+ status: str, optional
4347
+ The new status of the digital_subscription collection. Will be used only if body is not provided.
4348
+ body: dict | UpdateStatusRequestBody, optional, defaults to None
4349
+ A structure representing the details of the collection to create.
5140
4350
 
5141
4351
  Returns
5142
4352
  -------
@@ -5154,27 +4364,26 @@ class CollectionManager(Client2):
5154
4364
  Notes
5155
4365
  -----
5156
4366
  JSON Structure looks like:
5157
- {
5158
- "class": "AgreementStatusRequestBody",
5159
- "status": "APPROVED",
5160
- "externalSourceGUID": "add guid here",
5161
- "externalSourceName": "add qualified name here",
5162
- "effectiveTime": "{{$isoTimestamp}}",
5163
- "forLineage": false,
5164
- "forDuplicateProcessing": false
5165
- }
4367
+ {
4368
+ "class": "UpdateStatusRequestBody",
4369
+ "status": "APPROVED",
4370
+ "externalSourceGUID": "add guid here",
4371
+ "externalSourceName": "add qualified name here",
4372
+ "effectiveTime": "{{$isoTimestamp}}",
4373
+ "forLineage": false,
4374
+ "forDuplicateProcessing": false
4375
+ }
5166
4376
  """
5167
-
5168
4377
  url = (
5169
4378
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections"
5170
4379
  f"/agreements/"
5171
4380
  f"{digital_subscription_guid}/update-status")
5172
-
5173
- await self._async_make_request("POST", url, body)
4381
+ await self._async_update_status_request(url, status, body)
5174
4382
  logger.info(f"Updated status for DigitalProduct {digital_subscription_guid}")
5175
4383
 
5176
-
5177
- def update_digital_subscription_status(self, digital_subscription_guid: str, body: dict):
4384
+ @dynamic_catch
4385
+ def update_digital_subscription_status(self, digital_subscription_guid: str,
4386
+ body: dict | UpdateStatusRequestBody = None,):
5178
4387
  """Update the status of an digital_subscription collection. Async version.
5179
4388
 
5180
4389
  Parameters
@@ -5216,7 +4425,8 @@ class CollectionManager(Client2):
5216
4425
 
5217
4426
 
5218
4427
  @dynamic_catch
5219
- async def _async_link_subscriber(self, subscriber_guid: str, subscription_guid: str, body: dict = None):
4428
+ async def _async_link_subscriber(self, subscriber_guid: str, subscription_guid: str,
4429
+ body: dict | NewRelationshipRequestBody = None)-> None:
5220
4430
  """ Attach a subscriber to a subscription. The subscriber is of type 'Referenceable' to allow digital
5221
4431
  products, team or business capabilities to be the subscriber. The subscription is an element of type
5222
4432
  DigitalSubscription.
@@ -5228,8 +4438,8 @@ class CollectionManager(Client2):
5228
4438
  The unique identifier of the subscriber.
5229
4439
  subscription_guid: str
5230
4440
  The identifier of the subscription.
5231
- body: dict, optional, default = None
5232
- A dict representing the details of the relationship.
4441
+ body: dict | NewRelationshipRequestBody, optional, default = None
4442
+ A structure representing the details of the relationship.
5233
4443
 
5234
4444
  Returns
5235
4445
  -------
@@ -5248,7 +4458,7 @@ class CollectionManager(Client2):
5248
4458
  -----
5249
4459
  JSON Structure looks like:
5250
4460
  {
5251
- "class" : "RelationshipRequestBody",
4461
+ "class" : "NewRelationshipRequestBody",
5252
4462
  "externalSourceGUID": "add guid here",
5253
4463
  "externalSourceName": "add qualified name here",
5254
4464
  "effectiveTime" : "{{$isoTimestamp}}",
@@ -5262,19 +4472,16 @@ class CollectionManager(Client2):
5262
4472
  }
5263
4473
  }
5264
4474
  """
5265
-
5266
4475
  url = (
5267
4476
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections"
5268
4477
  f"/subscribers/"
5269
4478
  f"{subscriber_guid}/subscriptions/{subscription_guid}/attach")
5270
- if body:
5271
- await self._async_make_request("POST", url, body)
5272
- else:
5273
- await self._async_make_request("POST", url)
4479
+ await self._async_new_relationship_request(url, "DigitalSubscriberProperties", body)
5274
4480
  logger.info(f"Linking subscriber {subscriber_guid} to subscription {subscription_guid}")
5275
4481
 
5276
-
5277
- def link_subscriber(self, subscriber_guid: str, subscription_guid: str, body: dict = None):
4482
+ @dynamic_catch
4483
+ def link_subscriber(self, subscriber_guid: str, subscription_guid: str,
4484
+ body: dict | NewRelationshipRequestBody = None):
5278
4485
  """ Attach a subscriber to a subscription. The subscriber is of type 'Referenceable' to allow digital
5279
4486
  products, team or business capabilities to be the subscriber. The subscription is an element of type
5280
4487
  DigitalSubscription.
@@ -5325,7 +4532,8 @@ class CollectionManager(Client2):
5325
4532
 
5326
4533
 
5327
4534
  @dynamic_catch
5328
- async def _async_detach_subscriber(self, subscriber_guid: str, subscription_guid: str, body: dict = None):
4535
+ async def _async_detach_subscriber(self, subscriber_guid: str, subscription_guid: str,
4536
+ body: dict | DeleteRequestBody = None) -> None:
5329
4537
  """ Detach a subscriber from a subscription Request body is optional. Async version.
5330
4538
 
5331
4539
  Parameters
@@ -5334,8 +4542,8 @@ class CollectionManager(Client2):
5334
4542
  The unique identifier of the subscriber.
5335
4543
  subscription_guid: str
5336
4544
  The unique identifier of the subscription.
5337
- body: dict, optional, default = None
5338
- A dict representing the details of the relationship.
4545
+ body: dict | DeleteRequestBody, optional, default = None
4546
+ A structure representing the details of the relationship.
5339
4547
 
5340
4548
  Returns
5341
4549
  -------
@@ -5362,19 +4570,15 @@ class CollectionManager(Client2):
5362
4570
  "forDuplicateProcessing": false
5363
4571
  }
5364
4572
  """
5365
-
5366
4573
  url = (
5367
4574
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections"
5368
4575
  f"/agreements/"
5369
4576
  f"{subscriber_guid}/agreement-actors/{subscription_guid}/detach")
5370
- if body:
5371
- await self._async_make_request("POST", url, body)
5372
- else:
5373
- await self._async_make_request("POST", url)
4577
+ await self._async_delete_request(url, body)
5374
4578
  logger.info(f"Detached subscriber {subscriber_guid} from subscription {subscription_guid}")
5375
4579
 
5376
4580
 
5377
- def detach_subscriber(self, subscriber_guid: str, subscription_guid: str, body: dict = None):
4581
+ def detach_subscriber(self, subscriber_guid: str, subscription_guid: str, body: dict | DeleteRequestBody= None):
5378
4582
  """ Detach a subscriber from a subscription. Request body is optional.
5379
4583
 
5380
4584
  Parameters
@@ -5420,8 +4624,8 @@ class CollectionManager(Client2):
5420
4624
 
5421
4625
 
5422
4626
  @dynamic_catch
5423
- async def _async_attach_collection(self, parent_guid: str, collection_guid: str, body: dict = None,
5424
- make_anchor: bool = False):
4627
+ async def _async_attach_collection(self, parent_guid: str, collection_guid: str,
4628
+ body: dict | NewRelationshipRequestBody= None):
5425
4629
  """ Connect an existing collection to an element using the ResourceList relationship (0019).
5426
4630
  Async version.
5427
4631
 
@@ -5431,10 +4635,8 @@ class CollectionManager(Client2):
5431
4635
  The unique identifier of the parent to attach to.
5432
4636
  collection_guid: str
5433
4637
  The identifier of the collection being attached.
5434
- body: dict, optional, default = None
5435
- A dict representing the details of the relationship.
5436
- make_anchor: bool, optional, default = False
5437
- Indicates if the collection should be anchored to the element.
4638
+ body: dict | NewRelationshipRequestBody, optional, default = None
4639
+ A structure representing the details of the relationship.
5438
4640
 
5439
4641
  Returns
5440
4642
  -------
@@ -5454,7 +4656,7 @@ class CollectionManager(Client2):
5454
4656
  JSON Structure looks like:
5455
4657
 
5456
4658
  {
5457
- "class" : "RelationshipRequestBody",
4659
+ "class" : "NewRelationshipRequestBody",
5458
4660
  "properties": {
5459
4661
  "class": "ResourceListProperties",
5460
4662
  "resourceUse": "Add valid value here",
@@ -5477,16 +4679,13 @@ class CollectionManager(Client2):
5477
4679
  url = (
5478
4680
  f"{self.platform_url}/servers/"
5479
4681
  f"{self.view_server}/api/open-metadata/collection-manager/metadata-elements/"
5480
- f"{parent_guid}/collections/{collection_guid}/attach?makeAchor={make_anchor}")
5481
- if body:
5482
- await self._async_make_request("POST", url, body)
5483
- else:
5484
- await self._async_make_request("POST", url)
4682
+ f"{parent_guid}/collections/{collection_guid}/attach")
4683
+ await self._async_new_relationship_request(url, "ResourceListProperties", body)
5485
4684
  logger.info(f"Attached {collection_guid} to {parent_guid}")
5486
4685
 
5487
-
5488
- def attach_collection(self, parent_guid: str, collection_guid: str, body: dict = None,
5489
- make_anchor: bool = False):
4686
+ @dynamic_catch
4687
+ def attach_collection(self, parent_guid: str, collection_guid: str,
4688
+ body: dict | NewRelationshipRequestBody = None):
5490
4689
  """ Connect an existing collection to an element using the ResourceList relationship (0019).
5491
4690
 
5492
4691
  Parameters
@@ -5537,11 +4736,12 @@ class CollectionManager(Client2):
5537
4736
  }
5538
4737
  """
5539
4738
  loop = asyncio.get_event_loop()
5540
- loop.run_until_complete(self._async_attach_collection(parent_guid, collection_guid, body, make_anchor))
4739
+ loop.run_until_complete(self._async_attach_collection(parent_guid, collection_guid, body))
5541
4740
 
5542
4741
 
5543
4742
  @dynamic_catch
5544
- async def _async_detach_collection(self, parent_guid: str, collection_guid: str, body: dict = None):
4743
+ async def _async_detach_collection(self, parent_guid: str, collection_guid: str,
4744
+ body: dict | DeleteRequestBody = None):
5545
4745
  """ Detach an existing collection from an element. If the collection is anchored to the element,
5546
4746
  it is delete.
5547
4747
  Async version.
@@ -5552,8 +4752,8 @@ class CollectionManager(Client2):
5552
4752
  The unique identifier of the parent to detach from.
5553
4753
  collection_guid: str
5554
4754
  The identifier of the collection being detached.
5555
- body: dict, optional, default = None
5556
- A dict representing the details of the relationship.
4755
+ body: dict | DeleteRequestBody, optional, default = None
4756
+ A structure representing the details of the relationship.
5557
4757
 
5558
4758
 
5559
4759
  Returns
@@ -5573,27 +4773,25 @@ class CollectionManager(Client2):
5573
4773
  -----
5574
4774
  JSON Structure looks like:
5575
4775
  {
5576
- "class": "MetadataSourceRequestBody",
4776
+ "class": "DeleteRequestBody",
5577
4777
  "externalSourceGUID": "add guid here",
5578
4778
  "externalSourceName": "add qualified name here",
5579
4779
  "effectiveTime": "{{$isoTimestamp}}",
5580
4780
  "forLineage": false,
5581
4781
  "forDuplicateProcessing": false
5582
4782
  }
5583
- """
5584
4783
 
4784
+ """
5585
4785
  url = (
5586
4786
  f"{self.platform_url}/servers/"
5587
4787
  f"{self.view_server}/api/open-metadata/collection-manager/metadata-elements/"
5588
4788
  f"{parent_guid}/collections/{collection_guid}/detach")
5589
- if body:
5590
- await self._async_make_request("POST", url, body)
5591
- else:
5592
- await self._async_make_request("POST", url)
4789
+ await self._async_delete_request(url, body)
5593
4790
  logger.info(f"Detached collection {collection_guid} from {parent_guid}")
5594
4791
 
5595
4792
 
5596
- def detach_collection(self, parent_guid: str, collection_guid: str, body: dict = None):
4793
+ def detach_collection(self, parent_guid: str, collection_guid: str,
4794
+ body: dict | DeleteRequestBody = None):
5597
4795
  """ Detach an existing collection from an element. If the collection is anchored to the element,
5598
4796
  it is delete.
5599
4797
 
@@ -5636,7 +4834,7 @@ class CollectionManager(Client2):
5636
4834
 
5637
4835
 
5638
4836
  @dynamic_catch
5639
- async def _async_delete_collection(self, collection_guid: str, body: dict = None,
4837
+ async def _async_delete_collection(self, collection_guid: str, body: dict | DeleteRequestBody= None,
5640
4838
  cascade: bool = False) -> None:
5641
4839
  """Delete a collection. It is detected from all parent elements. If members are anchored to the collection
5642
4840
  then they are also deleted. Async version
@@ -5650,8 +4848,8 @@ class CollectionManager(Client2):
5650
4848
  cascade: bool, optional, defaults to True
5651
4849
  If true, a cascade delete is performed.
5652
4850
 
5653
- body: dict, optional, default = None
5654
- A dict representing the details of the relationship.
4851
+ body: dict | DeleteRequestBody, optional, default = None
4852
+ A structure representing the details of the relationship.
5655
4853
 
5656
4854
  Returns
5657
4855
  -------
@@ -5670,26 +4868,23 @@ class CollectionManager(Client2):
5670
4868
  _____
5671
4869
  JSON Structure looks like:
5672
4870
  {
5673
- "class" : "MetadataSourceRequestBody",
4871
+ "class": "DeleteRequestBody",
5674
4872
  "externalSourceGUID": "add guid here",
5675
4873
  "externalSourceName": "add qualified name here",
5676
- "effectiveTime" : "{{$isoTimestamp}}",
5677
- "forLineage" : false,
5678
- "forDuplicateProcessing" : false
4874
+ "effectiveTime": "{{$isoTimestamp}}",
4875
+ "forLineage": false,
4876
+ "forDuplicateProcessing": false
5679
4877
  }
5680
4878
 
5681
4879
 
5682
4880
  """
5683
- cascade_s = str(cascade).lower()
5684
- url = f"{self.collection_command_root}/{collection_guid}/delete?cascadedDelete={cascade_s}"
5685
- if body is None:
5686
- body = {"class": "NullRequestBody"}
5687
-
5688
- await self._async_make_request("POST", url, body)
4881
+ url = f"{self.collection_command_root}/{collection_guid}/delete"
4882
+ await self._async_delete_request(url, body, cascade)
5689
4883
  logger.info(f"Deleted collection {collection_guid} with cascade {cascade}")
5690
4884
 
5691
4885
 
5692
- def delete_collection(self, collection_guid: str, body: dict = None, cascade: bool = False) -> None:
4886
+ def delete_collection(self, collection_guid: str, body: dict | DeleteRequestBody = None,
4887
+ cascade: bool = False) -> None:
5693
4888
  """Delete a collection. It is detected from all parent elements. If members are anchored to the collection
5694
4889
  then they are also deleted.
5695
4890
 
@@ -5701,7 +4896,7 @@ class CollectionManager(Client2):
5701
4896
  cascade: bool, optional, defaults to True
5702
4897
  If true, a cascade delete is performed.
5703
4898
 
5704
- body: dict, optional, default = None
4899
+ body: dict DeleteRequestBodyt, optional, default = None
5705
4900
  A dict representing the details of the relationship.
5706
4901
 
5707
4902
  Returns
@@ -5720,14 +4915,7 @@ class CollectionManager(Client2):
5720
4915
  Notes
5721
4916
  _____
5722
4917
  JSON Structure looks like:
5723
- {
5724
- "class" : "MetadataSourceRequestBody",
5725
- "externalSourceGUID": "add guid here",
5726
- "externalSourceName": "add qualified name here",
5727
- "effectiveTime" : "{{$isoTimestamp}}",
5728
- "forLineage" : false,
5729
- "forDuplicateProcessing" : false
5730
- }
4918
+
5731
4919
 
5732
4920
 
5733
4921
  """
@@ -5736,7 +4924,8 @@ class CollectionManager(Client2):
5736
4924
 
5737
4925
 
5738
4926
  @dynamic_catch
5739
- async def _async_add_to_collection(self, collection_guid: str, element_guid: str, body: dict = None, ) -> None:
4927
+ async def _async_add_to_collection(self, collection_guid: str, element_guid: str,
4928
+ body: dict | NewRelationshipRequestBody = None, ) -> None:
5740
4929
  """Add an element to a collection. The request body is optional. Async version.
5741
4930
 
5742
4931
  Parameters
@@ -5745,12 +4934,9 @@ class CollectionManager(Client2):
5745
4934
  identity of the collection to return members for.
5746
4935
  element_guid: str
5747
4936
  Effective time of the query. If not specified will default to any time.
5748
- body: dict, optional, defaults to None
4937
+ body: dict NewRelationshipRequestBody, optional, defaults to None
5749
4938
  The body of the request to add to the collection. See notes.
5750
4939
 
5751
- The name of the server to use.
5752
-
5753
-
5754
4940
  Returns
5755
4941
  -------
5756
4942
  None
@@ -5768,7 +4954,7 @@ class CollectionManager(Client2):
5768
4954
  Notes
5769
4955
  -----
5770
4956
  Example body:
5771
- { "class": "RelationshipRequestBody",
4957
+ { "class": "NewRelationshipRequestBody",
5772
4958
  "properties" : {
5773
4959
  "class" : "CollectionMembershipProperties",
5774
4960
  "membershipRationale": "xxx",
@@ -5795,12 +4981,12 @@ class CollectionManager(Client2):
5795
4981
 
5796
4982
  url = (f"{self.collection_command_root}/{collection_guid}/members/"
5797
4983
  f"{element_guid}/attach")
5798
- body_s = body_slimmer(body)
5799
- await self._async_make_request("POST", url, body_s)
4984
+ await self._async_new_relationship_request(url, "CollectionMembershipProperties", body)
5800
4985
  logger.info(f"Added {element_guid} to {collection_guid}")
5801
4986
 
5802
4987
 
5803
- def add_to_collection(self, collection_guid: str, element_guid: str, body: dict = None, ) -> None:
4988
+ def add_to_collection(self, collection_guid: str, element_guid: str,
4989
+ body: dict | NewRelationshipRequestBody= None, ) -> None:
5804
4990
  """Add an element to a collection. The request body is optional.
5805
4991
 
5806
4992
  Parameters
@@ -5861,8 +5047,8 @@ class CollectionManager(Client2):
5861
5047
 
5862
5048
 
5863
5049
  @dynamic_catch
5864
- async def _async_update_collection_membership(self, collection_guid: str, element_guid: str, body: dict = None,
5865
- replace_all_props: bool = False, ) -> None:
5050
+ async def _async_update_collection_membership_prop(self, collection_guid: str, element_guid: str, body: dict = None,
5051
+ ) -> None:
5866
5052
  """Update an element's membership to a collection. Async version.
5867
5053
 
5868
5054
  Parameters
@@ -5920,16 +5106,15 @@ class CollectionManager(Client2):
5920
5106
  }
5921
5107
  """
5922
5108
 
5923
- replace_all_props_s = str(replace_all_props).lower()
5924
5109
  url = (f"{self.collection_command_root}/{collection_guid}/members/"
5925
- f"{element_guid}/update?replaceAllProperties={replace_all_props_s}")
5926
- body_s = body_slimmer(body)
5927
- await self._async_make_request("POST", url, body_s)
5110
+ f"{element_guid}/update")
5111
+ await self._async_update_relationship_request(url, "CollectionMembershipProperties", body )
5928
5112
  logger.info(f"Updated membership for collection {collection_guid}")
5929
5113
 
5930
5114
 
5931
- def update_collection_membership(self, collection_guid: str, element_guid: str, body: dict = None,
5932
- replace_all_props: bool = False, ) -> None:
5115
+ def update_collection_membership_prop(self, collection_guid: str, element_guid: str,
5116
+ body: dict | UpdateRelationshipRequestBody= None,
5117
+ ) -> None:
5933
5118
  """Update an element's membership to a collection.
5934
5119
 
5935
5120
  Parameters
@@ -5988,12 +5173,12 @@ class CollectionManager(Client2):
5988
5173
  """
5989
5174
  loop = asyncio.get_event_loop()
5990
5175
  loop.run_until_complete(
5991
- self._async_update_collection_membership(collection_guid, element_guid, body, replace_all_props))
5176
+ self._async_update_collection_membership(collection_guid, element_guid, body))
5992
5177
 
5993
5178
 
5994
5179
  @dynamic_catch
5995
5180
  async def _async_remove_from_collection(self, collection_guid: str, element_guid: str,
5996
- body: dict = None) -> None:
5181
+ body: dict | DeleteRequestBody = None) -> None:
5997
5182
  """Remove an element from a collection. Async version.
5998
5183
 
5999
5184
  Parameters
@@ -6002,7 +5187,7 @@ class CollectionManager(Client2):
6002
5187
  identity of the collection to return members for.
6003
5188
  element_guid: str
6004
5189
  Effective time of the query. If not specified will default to any time.
6005
- body: dict, optional, defaults to None
5190
+ body: dict | DeleteRequestBody, optional, defaults to None
6006
5191
  The body of the request to add to the collection. See notes.
6007
5192
 
6008
5193
  Returns
@@ -6022,7 +5207,7 @@ class CollectionManager(Client2):
6022
5207
  Notes
6023
5208
  -----
6024
5209
  {
6025
- "class" : "MetadataSourceRequestBody",
5210
+ "class" : "DeleteRequestBody",
6026
5211
  "externalSourceGUID": "add guid here",
6027
5212
  "externalSourceName": "add qualified name here",
6028
5213
  "effectiveTime" : "{{$isoTimestamp}}",
@@ -6034,13 +5219,12 @@ class CollectionManager(Client2):
6034
5219
 
6035
5220
  url = (f"{self.collection_command_root}/{collection_guid}/members/"
6036
5221
  f"{element_guid}/detach")
6037
- if body is None:
6038
- body = {"class": "NullRequestBody"}
6039
- await self._async_make_request("POST", url, body)
5222
+ await self._async_delete_collection(url, body)
6040
5223
  logger.info(f"Removed member {element_guid} from collection {collection_guid}")
6041
5224
 
6042
5225
 
6043
- def remove_from_collection(self, collection_guid: str, element_guid: str, body: dict = None) -> None:
5226
+ def remove_from_collection(self, collection_guid: str, element_guid: str,
5227
+ body: dict | DeleteRequestBody= None) -> None:
6044
5228
  """Remove an element from a collection. Async version.
6045
5229
 
6046
5230
  Parameters
@@ -6225,7 +5409,7 @@ class CollectionManager(Client2):
6225
5409
  output_formats = select_output_format_set(output_format_set, output_format)
6226
5410
  if isinstance(output_format_set, dict):
6227
5411
  output_formats = get_output_format_type_match(output_format_set, output_format)
6228
- # If no output_format was set, then use the classification_name to lookup the output format
5412
+ # If no output_format was set, then use the initial_classifications to lookup the output format
6229
5413
  elif classification_name:
6230
5414
  output_formats = select_output_format_set(classification_name, output_format)
6231
5415
  else: