pyegeria 5.4.0.20__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")
657
+ url = str(HttpUrl(f"{self.collection_command_root}/{collection_guid}"))
658
+ type = element_type if element_type else "Collection"
867
659
 
868
- url = f"{self.collection_command_root}/{collection_guid}"
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)
869
664
 
665
+ return response
870
666
 
871
- response = await self._async_make_request("POST", url,
872
- validated_body.model_dump_json())
873
667
 
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
-
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}")
1141
-
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)
1146
-
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
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)
1157
921
 
922
+ return response
1158
923
 
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
-
1351
+ ["ReferenceList"], body))
1755
1352
 
1756
-
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}"
@@ -2480,8 +2042,7 @@ class CollectionManager(Client2):
2480
2042
 
2481
2043
 
2482
2044
  @dynamic_catch
2483
- async def _async_update_collection(self, collection_guid: str, body: dict | NewElementRequestBody,
2484
- merge_update: bool = True) -> None:
2045
+ async def _async_update_collection(self, collection_guid: str, body: dict | UpdateElementRequestBody) -> None:
2485
2046
  """ Update the properties of a collection. Use the correct properties object (CollectionProperties,
2486
2047
  DigitalProductProperties, AgreementProperties, etc), that is appropriate for your element.
2487
2048
  Collections: https://egeria-project.org/concepts/collection
@@ -2492,7 +2053,7 @@ class CollectionManager(Client2):
2492
2053
  collection_guid: str
2493
2054
  The guid of the collection to update.
2494
2055
 
2495
- body: dict | NewElementRequestBody, optional
2056
+ body: dict | UpdateElementRequestBody, optional
2496
2057
  A dict or NewElementRequestBody representing the details of the collection to create. If supplied, this
2497
2058
  information will be used to create the collection and the other attributes will be ignored. The body is
2498
2059
  validated before being used.
@@ -2534,44 +2095,18 @@ class CollectionManager(Client2):
2534
2095
  }
2535
2096
  """
2536
2097
 
2537
- try:
2538
- if isinstance(body, NewElementRequestBody):
2539
- if body.properties.class_ in COLLECTION_PROPERTIES_LIST:
2540
- validated_body = body
2541
- else:
2542
- raise PyegeriaInvalidParameterException(additional_info =
2543
- {"reason" : "unexpected property class name"})
2544
-
2545
- elif isinstance(body, dict):
2546
- if body.get("properties", {}).get("class", "") in COLLECTION_PROPERTIES_LIST:
2547
- validated_body = self._new_element_request_adapter.validate_python(body)
2548
- else:
2549
- raise PyegeriaInvalidParameterException(additional_info =
2550
- {"reason" : "unexpected property class name"})
2551
- else:
2552
- raise TypeError("Invalid parameter type")
2553
-
2554
- except ValidationError as e:
2555
- logger.error(f"Validation error: {e}")
2556
- raise ValidationError(e)
2098
+ # try:
2557
2099
 
2558
- merge_update_s = str(merge_update).lower()
2100
+ url = (f"{self.collection_command_root}/{collection_guid}/update")
2101
+ await self._async_update_element_body_request(url, COLLECTION_PROPERTIES_LIST,body)
2559
2102
 
2560
- url = (f"{self.collection_command_root}/{collection_guid}/update?"
2561
- f"replaceAllProperties={merge_update_s}")
2562
2103
 
2563
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
2564
-
2565
- await self._async_make_request("POST", url, json_body)
2566
-
2567
- logger.info(f"Successfully updated {collection_guid} with {json_body}")
2568
2104
 
2569
2105
 
2570
2106
 
2571
2107
 
2572
2108
  @dynamic_catch
2573
- def update_collection(self, collection_guid: str, body: dict | NewElementRequestBody,
2574
- merge_update: bool = True) -> None:
2109
+ def update_collection(self, collection_guid: str, body: dict | NewElementRequestBody) -> None:
2575
2110
  """ Update the properties of a collection. Use the correct properties object (CollectionProperties,
2576
2111
  DigitalProductProperties, AgreementProperties, etc), that is appropriate for your element.
2577
2112
  Collections: https://egeria-project.org/concepts/collection
@@ -2624,7 +2159,7 @@ class CollectionManager(Client2):
2624
2159
  """
2625
2160
 
2626
2161
  return asyncio.get_event_loop().run_until_complete(
2627
- self._async_update_collection(collection_guid, body, merge_update))
2162
+ self._async_update_collection(collection_guid, body))
2628
2163
 
2629
2164
 
2630
2165
  @dynamic_catch
@@ -2695,32 +2230,9 @@ class CollectionManager(Client2):
2695
2230
  OTHER. If using OTHER, set the userDefinedStatus with the status value you want. If not specified, will
2696
2231
  default to ACTIVE.
2697
2232
  """
2698
-
2699
- if isinstance(body, NewElementRequestBody):
2700
- if body.properties.class_ == "DigitalProductProperties":
2701
- validated_body = body
2702
- else:
2703
- raise PyegeriaInvalidParameterException(additional_info=
2704
- {"reason": "unexpected property class name"})
2705
-
2706
- elif isinstance(body, dict):
2707
- if body.get("properties", {}).get("class", "") == "DigitalProductProperties":
2708
- validated_body = self._new_element_request_adapter.validate_python(body)
2709
- else:
2710
- raise PyegeriaInvalidParameterException(additional_info=
2711
- {"reason": "unexpected property class name"})
2712
-
2713
- else:
2714
- raise TypeError("Invalid parameter type")
2715
-
2716
-
2717
-
2718
2233
  url = f"{self.collection_command_root}"
2719
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
2720
- logger.info(json_body)
2721
- resp = await self._async_make_request("POST", url, json_body, is_json=True)
2722
- logger.info(f"Create collection with GUID: {resp.json().get('guid')}")
2723
- return resp.json().get("guid", NO_GUID_RETURNED)
2234
+ return await self._async_create_element_body_request(url, "DigitalProductProperties", body)
2235
+
2724
2236
 
2725
2237
  @dynamic_catch
2726
2238
  def create_digital_product(self, body: dict | NewElementRequestBody = None) -> str:
@@ -2795,8 +2307,7 @@ class CollectionManager(Client2):
2795
2307
 
2796
2308
 
2797
2309
  @dynamic_catch
2798
- async def _async_update_digital_product(self, collection_guid: str, body: dict | UpdateElementRequestBody,
2799
- merge_update: bool = True) -> None:
2310
+ async def _async_update_digital_product(self, collection_guid: str, body: dict | UpdateElementRequestBody) -> None:
2800
2311
  """ Update the properties of a digital product.
2801
2312
  Collections: https://egeria-project.org/concepts/collection
2802
2313
 
@@ -2860,37 +2371,8 @@ class CollectionManager(Client2):
2860
2371
  }
2861
2372
  """
2862
2373
 
2863
- try:
2864
- if isinstance(body, NewElementRequestBody):
2865
- if body.properties.class_ == "DigitalProductProperties":
2866
- validated_body = body
2867
- else:
2868
- raise PyegeriaInvalidParameterException(additional_info =
2869
- {"reason" : "unexpected property class name"})
2870
-
2871
- elif isinstance(body, dict):
2872
- if body.get("properties", {}).get("class", "") == "DigitalProductProperties":
2873
- validated_body = self._update_element_request_adapter.validate_python(body)
2874
- else:
2875
- raise PyegeriaInvalidParameterException(additional_info =
2876
- {"reason" : "unexpected property class name"})
2877
- else:
2878
- raise TypeError("Invalid parameter type")
2879
-
2880
- except ValidationError as e:
2881
- logger.error(f"Validation error: {e}")
2882
- raise ValidationError(e)
2883
-
2884
- merge_update_s = str(merge_update).lower()
2885
-
2886
- url = (f"{self.collection_command_root}/{collection_guid}/update?"
2887
- f"replaceAllProperties={merge_update_s}")
2888
-
2889
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
2890
-
2891
- await self._async_make_request("POST", url, json_body)
2892
-
2893
- 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 )
2894
2376
 
2895
2377
 
2896
2378
  @dynamic_catch
@@ -2963,15 +2445,19 @@ class CollectionManager(Client2):
2963
2445
 
2964
2446
 
2965
2447
  @dynamic_catch
2966
- 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):
2967
2450
  """Update the status of a collection. Async version.
2968
2451
 
2969
2452
  Parameters
2970
2453
  ----------
2971
2454
  collection_guid: str
2972
2455
  The guid of the collection to update.
2973
- body: dict | UpdateStatusRequestBody
2974
- 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.
2975
2461
 
2976
2462
  Returns
2977
2463
  -------
@@ -2999,31 +2485,24 @@ class CollectionManager(Client2):
2999
2485
  "forDuplicateProcessing": false
3000
2486
  }
3001
2487
  """
3002
- try:
3003
- if isinstance(body, UpdateStatusRequestBody):
3004
- validated_body = body
3005
- elif isinstance(body, dict):
3006
- validated_body = self._update_status_request_adapter.validate_python(body)
3007
-
3008
- except ValidationError as e:
3009
- logger.error(f"Validation error: {e}")
3010
- raise ValidationError(e)
3011
2488
 
3012
2489
  url = f"{self.collection_command_root}/{collection_guid}/update-status"
3013
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3014
- await self._async_make_request("POST", url, json_body)
3015
- logger.info(f"Successfully updated {collection_guid} with {json_body}")
2490
+ await self._async_update_status_request(url, status, body)
3016
2491
 
3017
2492
  @dynamic_catch
3018
- 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):
3019
2495
  """Update the status of a DigitalProduct collection.
3020
2496
 
3021
2497
  Parameters
3022
2498
  ----------
3023
2499
  collection_guid: str
3024
2500
  The guid of the collection to update.
3025
- body: dict | UpdateStatusRequestBody
3026
- 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.
3027
2506
 
3028
2507
  Returns
3029
2508
  -------
@@ -3052,19 +2531,23 @@ class CollectionManager(Client2):
3052
2531
  }
3053
2532
  """
3054
2533
  loop = asyncio.get_event_loop()
3055
- 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))
3056
2535
 
3057
2536
 
3058
2537
  @dynamic_catch
3059
- 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):
3060
2540
  """Update the status of a DigitalProduct collection.
3061
2541
 
3062
2542
  Parameters
3063
2543
  ----------
3064
2544
  digital_product_guid: str
3065
- The guid of the digital product collection to update.
3066
- body: dict | UpdateStatusRequestBody
3067
- 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.
3068
2551
 
3069
2552
  Returns
3070
2553
  -------
@@ -3093,7 +2576,7 @@ class CollectionManager(Client2):
3093
2576
  }
3094
2577
  """
3095
2578
  loop = asyncio.get_event_loop()
3096
- 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))
3097
2580
 
3098
2581
 
3099
2582
  @dynamic_catch
@@ -3144,28 +2627,11 @@ class CollectionManager(Client2):
3144
2627
  }
3145
2628
  }
3146
2629
  """
3147
- try:
3148
- if isinstance(body, NewRelationshipRequestBody):
3149
- validated_body = body
3150
- elif isinstance(body, dict):
3151
- validated_body = self._new_relationship_request_adapter.validate_python(body)
3152
- else:
3153
- validated_body = None
3154
-
3155
- except ValidationError as e:
3156
- logger.error(f"Validation error: {e}")
3157
- raise ValidationError(e)
3158
-
3159
-
3160
2630
  url = (
3161
2631
  f"{self.platform_url}/servers/"
3162
2632
  f"{self.view_server}/api/open-metadata/collection-manager/collections/digital-products/"
3163
2633
  f"{upstream_digital_prod_guid}/product-dependencies/{downstream_digital_prod_guid}/attach")
3164
- if validated_body:
3165
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3166
- await self._async_make_request("POST", url, json_body)
3167
- else:
3168
- await self._async_make_request("POST", url)
2634
+ await self._async_new_relationship_request(url, "InformationSupplyChainLinkProperties", body)
3169
2635
  logger.info(f"Linked {upstream_digital_prod_guid} -> {downstream_digital_prod_guid}")
3170
2636
 
3171
2637
 
@@ -3264,30 +2730,13 @@ class CollectionManager(Client2):
3264
2730
  }
3265
2731
 
3266
2732
  """
3267
- try:
3268
- if isinstance(body, DeleteRequestBody):
3269
- validated_body = body
3270
- elif isinstance(body, dict):
3271
- validated_body = self._delete_request_adapter.validate_python(body)
3272
- else:
3273
- validated_body = None
3274
-
3275
- except ValidationError as e:
3276
- logger.error(f"Validation error: {e}")
3277
- raise ValidationError(e)
3278
-
3279
2733
 
3280
2734
  url = (
3281
2735
  f"{self.platform_url}/servers/"
3282
2736
  f"{self.view_server}/api/open-metadata/collection-manager/collections/digital-products/"
3283
2737
  f"{upstream_digital_prod_guid}/product-dependencies/{downstream_digital_prod_guid}/detach")
3284
-
3285
- if validated_body:
3286
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3287
- await self._async_make_request("POST", url, json_body)
3288
- else:
3289
- await self._async_make_request("POST", url)
3290
- 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}")
3291
2740
 
3292
2741
 
3293
2742
  def detach_digital_product_dependency(self, upstream_digital_prod_guid: str, downstream_digital_prod_guid: str,
@@ -3383,30 +2832,12 @@ class CollectionManager(Client2):
3383
2832
  }
3384
2833
 
3385
2834
  """
3386
- try:
3387
- if isinstance(body, NewRelationshipRequestBody):
3388
- validated_body = body
3389
- elif isinstance(body, dict):
3390
- validated_body = self._new_relationship_request_adapter.validate_python(body)
3391
- else:
3392
- validated_body = None
3393
- raise PyegeriaInvalidParameterException(additional_info=
3394
- {"reason": "unexpected body type"})
3395
- except ValidationError as e:
3396
- logger.error(f"Validation error: {e}")
3397
- raise ValidationError(e)
3398
-
3399
2835
  url = (
3400
2836
  f"{self.platform_url}/servers/"
3401
2837
  f"{self.view_server}/api/open-metadata/collection-manager/collections/digital"
3402
2838
  f"-products/"
3403
2839
  f"{digital_prod_guid}/product-managers/{digital_prod_manager_guid}/attach")
3404
-
3405
- if validated_body:
3406
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3407
- await self._async_make_request("POST", url, json_body)
3408
- else:
3409
- await self._async_make_request("POST", url)
2840
+ await self._async_new_relationship_request(url, "AssignmentScopeProperties",body)
3410
2841
  logger.info(f"Attached digital product manager {digital_prod_guid} -> {digital_prod_manager_guid}")
3411
2842
 
3412
2843
 
@@ -3500,31 +2931,12 @@ class CollectionManager(Client2):
3500
2931
  }
3501
2932
 
3502
2933
  """
3503
- try:
3504
- if isinstance(body, DeleteRequestBody):
3505
- validated_body = body
3506
- elif isinstance(body, dict):
3507
- validated_body = self._delete_request_adapter.validate_python(body)
3508
- else:
3509
- validated_body = None
3510
- raise PyegeriaInvalidParameterException(additional_info=
3511
- {"reason": "unexpected body type"})
3512
- except ValidationError as e:
3513
- logger.error(f"Validation error: {e}")
3514
- raise ValidationError(e)
3515
-
3516
-
3517
2934
  url = (
3518
2935
  f"{self.platform_url}/servers/"
3519
2936
  f"{self.view_server}/api/open-metadata/collection-manager/collections/digital-products/"
3520
2937
  f"{digital_prod_guid}/product-dependencies/{digital_prod_manager_guid}/detach")
3521
-
3522
- if validated_body:
3523
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3524
- await self._async_make_request("POST", url, json_body)
3525
- else:
3526
- await self._async_make_request("POST", url)
3527
- 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}")
3528
2940
 
3529
2941
  @dynamic_catch
3530
2942
  def detach_product_manager(self, digital_prod_guid: str, digital_prod_manager_guid: str,
@@ -3566,177 +2978,24 @@ class CollectionManager(Client2):
3566
2978
  "forDuplicateProcessing": false
3567
2979
  }
3568
2980
 
3569
- """
3570
- loop = asyncio.get_event_loop()
3571
- loop.run_until_complete(
3572
- self._async_detach_product_manager(digital_prod_guid, digital_prod_manager_guid,
3573
- body))
3574
-
3575
-
3576
- #
3577
-
3578
- @dynamic_catch
3579
- async def _async_create_agreement(self, body: dict | NewElementRequestBody) -> str:
3580
- """ Create a new collection that represents an agreement.
3581
- Async version.
3582
-
3583
- Parameters
3584
- ----------
3585
- body: dict | NewElementRequestBody
3586
- A structure representing the details of the agreement to create.
3587
-
3588
- Returns
3589
- -------
3590
- str - the guid of the created collection
3591
-
3592
- Raises
3593
- ------
3594
- PyegeriaException
3595
- If the client passes incorrect parameters on the request - such as bad URLs or invalid values
3596
- ValidationError
3597
- Raised by the pydantic validator if the body does not conform to the NewElementRequestBody.
3598
- NotAuthorizedException
3599
- The principle specified by the user_id does not have authorization for the requested action
3600
-
3601
- Notes
3602
- -----
3603
- Note: the three dates: introductionDate, nextVersionDate and withdrawDate must
3604
- be valid dates if specified, otherwise you will get a 400 error response.
3605
-
3606
- JSON Structure looks like:
3607
- {
3608
- "class" : "NewElementRequestBody",
3609
- "isOwnAnchor" : true,
3610
- "anchorScopeGUID" : "optional GUID of search scope",
3611
- "parentGUID" : "xxx",
3612
- "parentRelationshipTypeName" : "CollectionMembership",
3613
- "parentAtEnd1": true,
3614
- "properties": {
3615
- "class" : "AgreementProperties",
3616
- "qualifiedName": "Agreement::Add agreement name here",
3617
- "name" : "display name",
3618
- "description" : "Add description of the agreement here",
3619
- "identifier" : "Add agreement identifier here",
3620
- "additionalProperties": {
3621
- "property1Name" : "property1Value",
3622
- "property2Name" : "property2Value"
3623
- }
3624
- },
3625
- "externalSourceGUID": "add guid here",
3626
- "externalSourceName": "add qualified name here",
3627
- "effectiveTime" : "{{$isoTimestamp}}",
3628
- "forLineage" : false,
3629
- "forDuplicateProcessing" : false,
3630
- "initialStatus" : "ACTIVE"
3631
- }
3632
-
3633
- The valid values for initialStatus are: DRAFT, PREPARED, PROPOSED, APPROVED, REJECTED, APPROVED_CONCEPT,
3634
- UNDER_DEVELOPMENT, DEVELOPMENT_COMPLETE, APPROVED_FOR_DEPLOYMENT, ACTIVE, DISABLED, DEPRECATED,
3635
- OTHER. If using OTHER, set the userDefinedStatus with the status value you want. If not specified, will
3636
- default to ACTIVE.
3637
- """
3638
- try:
3639
- if isinstance(body, NewElementRequestBody):
3640
- if body.properties.class_ == "AgreementProperties":
3641
- validated_body = body
3642
- else:
3643
- raise PyegeriaInvalidParameterException(additional_info=
3644
- {"reason": "unexpected property class name"})
3645
-
3646
- elif isinstance(body, dict):
3647
- if body.get("properties", {}).get("class", "") == "AgreementProperties":
3648
- validated_body = self._new_element_request_adapter.validate_python(body)
3649
- else:
3650
- raise PyegeriaInvalidParameterException(additional_info=
3651
- {"reason": "unexpected property class name"})
3652
-
3653
- else:
3654
- raise TypeError("Invalid parameter type")
3655
-
3656
- except ValidationError as e:
3657
- logger.error(f"Validation error: {e}")
3658
- raise ValidationError(e)
3659
-
3660
- url = f"{self.collection_command_root}"
3661
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3662
- logger.info(json_body)
3663
- resp = await self._async_make_request("POST", url, json_body, is_json=True)
3664
- logger.info(f"Create collection with GUID: {resp.json().get('guid')}")
3665
- return resp.json().get("guid", NO_GUID_RETURNED)
3666
-
3667
- @dynamic_catch
3668
- def create_agreement(self, body: dict | NewElementRequestBody = None) -> str:
3669
- """ Create a new collection that represents an agreement..
3670
-
3671
- Parameters
3672
- ----------
3673
- body: dict | NewElementRequestBody
3674
- A structure representing the details of the agreement to create.
3675
-
3676
- Returns
3677
- -------
3678
- str - the guid of the created collection
3679
-
3680
- Raises
3681
- ------
3682
- PyegeriaException
3683
- If the client passes incorrect parameters on the request - such as bad URLs or invalid values
3684
- ValidationError
3685
- Raised by the pydantic validator if the body does not conform to the NewElementRequestBody.
3686
- NotAuthorizedException
3687
- The principle specified by the user_id does not have authorization for the requested action
3688
-
3689
- Notes
3690
- -----
3691
- Note: the three dates: introductionDate, nextVersionDate and withdrawDate must
3692
- be valid dates if specified, otherwise you will get a 400 error response.
3693
-
3694
- JSON Structure looks like:
3695
- {
3696
- "class" : "NewElementRequestBody",
3697
- "isOwnAnchor" : true,
3698
- "anchorScopeGUID" : "optional GUID of search scope",
3699
- "parentGUID" : "xxx",
3700
- "parentRelationshipTypeName" : "CollectionMembership",
3701
- "parentAtEnd1": true,
3702
- "properties": {
3703
- "class" : "AgreementProperties",
3704
- "qualifiedName": "Agreement::Add agreement name here",
3705
- "name" : "display name",
3706
- "description" : "Add description of the agreement here",
3707
- "identifier" : "Add agreement identifier here",
3708
- "additionalProperties": {
3709
- "property1Name" : "property1Value",
3710
- "property2Name" : "property2Value"
3711
- }
3712
- },
3713
- "externalSourceGUID": "add guid here",
3714
- "externalSourceName": "add qualified name here",
3715
- "effectiveTime" : "{{$isoTimestamp}}",
3716
- "forLineage" : false,
3717
- "forDuplicateProcessing" : false,
3718
- "initialStatus" : "ACTIVE"
3719
- }
3720
-
3721
- The valid values for initialStatus are: DRAFT, PREPARED, PROPOSED, APPROVED, REJECTED, APPROVED_CONCEPT,
3722
- UNDER_DEVELOPMENT, DEVELOPMENT_COMPLETE, APPROVED_FOR_DEPLOYMENT, ACTIVE, DISABLED, DEPRECATED,
3723
- OTHER. If using OTHER, set the userDefinedStatus with the status value you want. If not specified, will
3724
- default to ACTIVE.
3725
- """
2981
+ """
2982
+ loop = asyncio.get_event_loop()
2983
+ loop.run_until_complete(
2984
+ self._async_detach_product_manager(digital_prod_guid, digital_prod_manager_guid,
2985
+ body))
3726
2986
 
3727
- return asyncio.get_event_loop().run_until_complete(
3728
- self._async_create_agreement(body))
3729
2987
 
2988
+ #
3730
2989
 
3731
2990
  @dynamic_catch
3732
- async def _async_create_data_sharing_agreement(self, body: dict | NewElementRequestBody) -> str:
3733
- """ 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.
3734
2993
  Async version.
3735
2994
 
3736
2995
  Parameters
3737
2996
  ----------
3738
2997
  body: dict | NewElementRequestBody
3739
- A structure representing the details of the data sharing agreement to create.
2998
+ A structure representing the details of the agreement to create.
3740
2999
 
3741
3000
  Returns
3742
3001
  -------
@@ -3769,19 +3028,18 @@ class CollectionManager(Client2):
3769
3028
  "qualifiedName": "Agreement::Add agreement name here",
3770
3029
  "name" : "display name",
3771
3030
  "description" : "Add description of the agreement here",
3772
- "userDefinedStatus" : "NEW",
3773
3031
  "identifier" : "Add agreement identifier here",
3774
3032
  "additionalProperties": {
3775
3033
  "property1Name" : "property1Value",
3776
3034
  "property2Name" : "property2Value"
3777
3035
  }
3778
3036
  },
3779
- "initialStatus" : "ACTIVE",
3780
3037
  "externalSourceGUID": "add guid here",
3781
3038
  "externalSourceName": "add qualified name here",
3782
3039
  "effectiveTime" : "{{$isoTimestamp}}",
3783
3040
  "forLineage" : false,
3784
- "forDuplicateProcessing" : false
3041
+ "forDuplicateProcessing" : false,
3042
+ "initialStatus" : "ACTIVE"
3785
3043
  }
3786
3044
 
3787
3045
  The valid values for initialStatus are: DRAFT, PREPARED, PROPOSED, APPROVED, REJECTED, APPROVED_CONCEPT,
@@ -3789,43 +3047,17 @@ class CollectionManager(Client2):
3789
3047
  OTHER. If using OTHER, set the userDefinedStatus with the status value you want. If not specified, will
3790
3048
  default to ACTIVE.
3791
3049
  """
3792
- try:
3793
- if isinstance(body, NewElementRequestBody):
3794
- if body.properties.class_ == "AgreementProperties":
3795
- validated_body = body
3796
- else:
3797
- raise PyegeriaInvalidParameterException(additional_info=
3798
- {"reason": "unexpected property class name"})
3799
-
3800
- elif isinstance(body, dict):
3801
- if body.get("properties", {}).get("class", "") == "AgreementProperties":
3802
- validated_body = self._new_element_request_adapter.validate_python(body)
3803
- else:
3804
- raise PyegeriaInvalidParameterException(additional_info=
3805
- {"reason": "unexpected property class name"})
3806
-
3807
- else:
3808
- raise TypeError("Invalid parameter type")
3809
-
3810
- except ValidationError as e:
3811
- logger.error(f"Validation error: {e}")
3812
- raise ValidationError(e)
3813
-
3814
- url = f"{self.collection_command_root}/data-sharing-agreement"
3815
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3816
- logger.info(json_body)
3817
- resp = await self._async_make_request("POST", url, json_body, is_json=True)
3818
- logger.info(f"Create collection with GUID: {resp.json().get('guid')}")
3819
- 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)
3820
3052
 
3821
3053
  @dynamic_catch
3822
- def create_data_sharing_agreement(self, body: dict | NewElementRequestBody = None) -> str:
3823
- """ 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..
3824
3056
 
3825
3057
  Parameters
3826
3058
  ----------
3827
3059
  body: dict | NewElementRequestBody
3828
- A structure representing the details of the digital product to create.
3060
+ A structure representing the details of the agreement to create.
3829
3061
 
3830
3062
  Returns
3831
3063
  -------
@@ -3854,19 +3086,11 @@ class CollectionManager(Client2):
3854
3086
  "parentRelationshipTypeName" : "CollectionMembership",
3855
3087
  "parentAtEnd1": true,
3856
3088
  "properties": {
3857
- "class" : "DigitalProductProperties",
3858
- "qualifiedName": "DigitalProduct::Add product name here",
3859
- "name" : "Product contents",
3860
- "description" : "Add description of product and its expected usage here",
3861
- "identifier" : "Add product identifier here",
3862
- "productName" : "Add product name here",
3863
- "category" : "Periodic Delta",
3864
- "maturity" : "Add valid value here",
3865
- "serviceLife" : "Add the estimated lifetime of the product",
3866
- "introductionDate" : "date",
3867
- "nextVersionDate": "date",
3868
- "withdrawDate": "date",
3869
- "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",
3870
3094
  "additionalProperties": {
3871
3095
  "property1Name" : "property1Value",
3872
3096
  "property2Name" : "property2Value"
@@ -3887,12 +3111,148 @@ class CollectionManager(Client2):
3887
3111
  """
3888
3112
 
3889
3113
  return asyncio.get_event_loop().run_until_complete(
3890
- self._async_create_data_sharing_agreement(body))
3114
+ self._async_create_agreement(body))
3891
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
+ #
3892
3253
 
3893
3254
  @dynamic_catch
3894
- async def _async_update_agreement(self, agreement_guid: str, body: dict | UpdateElementRequestBody,
3895
- merge_update: bool = True) -> None:
3255
+ async def _async_update_agreement(self, agreement_guid: str, body: dict | UpdateElementRequestBody) -> None:
3896
3256
  """ Update the properties of an agreement.
3897
3257
  Collections: https://egeria-project.org/concepts/collection
3898
3258
 
@@ -3945,43 +3305,11 @@ class CollectionManager(Client2):
3945
3305
  "forDuplicateProcessing" : false
3946
3306
  }
3947
3307
  """
3948
-
3949
- try:
3950
- if isinstance(body, NewElementRequestBody):
3951
- if body.properties.class_ == "AgreementProperties":
3952
- validated_body = body
3953
- else:
3954
- raise PyegeriaInvalidParameterException(additional_info =
3955
- {"reason" : "unexpected property class name"})
3956
-
3957
- elif isinstance(body, dict):
3958
- if body.get("properties", {}).get("class", "") == "AgreementProperties":
3959
- validated_body = self._update_element_request_adapter.validate_python(body)
3960
- else:
3961
- raise PyegeriaInvalidParameterException(additional_info =
3962
- {"reason" : "unexpected property class name"})
3963
- else:
3964
- raise TypeError("Invalid parameter type")
3965
-
3966
- except ValidationError as e:
3967
- logger.error(f"Validation error: {e}")
3968
- raise ValidationError(e)
3969
-
3970
- merge_update_s = str(merge_update).lower()
3971
-
3972
- url = (f"{self.collection_command_root}/{agreement_guid}/update?"
3973
- f"replaceAllProperties={merge_update_s}")
3974
-
3975
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3976
-
3977
- await self._async_make_request("POST", url, json_body)
3978
-
3979
- logger.info(f"Successfully updated {agreement_guid} with {json_body}")
3980
-
3308
+ url = (f"{self.collection_command_root}/{agreement_guid}/update")
3309
+ await self._async_update_element_body_request(url, AGREEMENT_PROPERTIES_LIST,body)
3981
3310
 
3982
3311
  @dynamic_catch
3983
- def update_agreement(self, agreement_guid: str, body: dict | UpdateElementRequestBody,
3984
- merge_update: bool = True) -> None:
3312
+ def update_agreement(self, agreement_guid: str, body: dict | UpdateElementRequestBody) -> None:
3985
3313
  """ Update the properties of an agreement.
3986
3314
  Collections: https://egeria-project.org/concepts/collection
3987
3315
 
@@ -4035,68 +3363,20 @@ class CollectionManager(Client2):
4035
3363
  """
4036
3364
 
4037
3365
  return asyncio.get_event_loop().run_until_complete(
4038
- self._async_update_agreement(agreement_guid, body, merge_update))
4039
-
4040
-
4041
- @dynamic_catch
4042
- async def _async_update_agreement_status(self, agreement_guid: str, body: dict | UpdateStatusRequestBody):
4043
- """Update the status of an agreement. Async version.
4044
-
4045
- Parameters
4046
- ----------
4047
- agreement_guid: str
4048
- The guid of the collection to update.
4049
- body: dict | UpdateStatusRequestBody
4050
- A structure representing the details of the collection to create.
4051
-
4052
- Returns
4053
- -------
4054
- Nothing
4055
-
4056
- Raises
4057
- ------
4058
- InvalidParameterException
4059
- If the client passes incorrect parameters on the request - such as bad URLs or invalid values
4060
- PropertyServerException
4061
- Raised by the server when an issue arises in processing a valid request
4062
- NotAuthorizedException
4063
- The principle specified by the user_id does not have authorization for the requested action
4064
-
4065
- Notes
4066
- -----
4067
- JSON Structure looks like:
4068
- {
4069
- "class": "UpdateStatusRequestBody",
4070
- "status": "APPROVED",
4071
- "externalSourceGUID": "add guid here",
4072
- "externalSourceName": "add qualified name here",
4073
- "effectiveTime": "{{$isoTimestamp}}",
4074
- "forLineage": false,
4075
- "forDuplicateProcessing": false
4076
- }
4077
- """
4078
- try:
4079
- if isinstance(body, UpdateStatusRequestBody):
4080
- validated_body = body
4081
- elif isinstance(body, dict):
4082
- validated_body = self._update_status_request_adapter.validate_python(body)
3366
+ self._async_update_agreement(agreement_guid, body))
4083
3367
 
4084
- except ValidationError as e:
4085
- logger.error(f"Validation error: {e}")
4086
- raise ValidationError(e)
4087
3368
 
4088
- url = f"{self.collection_command_root}/{agreement_guid}/update-status"
4089
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
4090
- await self._async_make_request("POST", url, json_body)
4091
- logger.info(f"Successfully updated {agreement_guid} with {json_body}")
4092
3369
 
4093
3370
  @dynamic_catch
4094
- 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):
4095
3373
  """Update the status of an agreement.
4096
3374
  Parameters
4097
3375
  ----------
4098
3376
  agreement_guid: str
4099
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.
4100
3380
  body: dict | UpdateStatusRequestBody
4101
3381
  A structure representing the details of the collection to create.
4102
3382
 
@@ -4127,7 +3407,7 @@ class CollectionManager(Client2):
4127
3407
  }
4128
3408
  """
4129
3409
  loop = asyncio.get_event_loop()
4130
- 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))
4131
3411
 
4132
3412
 
4133
3413
 
@@ -4180,37 +3460,11 @@ class CollectionManager(Client2):
4180
3460
  }
4181
3461
 
4182
3462
  """
4183
- try:
4184
- if isinstance(body, NewRelationshipRequestBody):
4185
- if body.properties.class_ == "AgreementActorProperties":
4186
- validated_body = body
4187
- else:
4188
- raise PyegeriaInvalidParameterException(additional_info=
4189
- {"reason": "unexpected property class name"})
4190
-
4191
- elif isinstance(body, dict):
4192
- if body.get("properties", {}).get("class", "") == "AgreementActorProperties":
4193
- validated_body = self._new_relationship_request_adapter.validate_python(body)
4194
- else:
4195
- raise PyegeriaInvalidParameterException(additional_info=
4196
- {"reason": "unexpected property class name"})
4197
- else:
4198
- validated_body = None
4199
-
4200
- except ValidationError as e:
4201
- logger.error(f"Validation error: {e}")
4202
- raise ValidationError(e)
4203
-
4204
3463
  url = (
4205
3464
  f"{self.platform_url}/servers/"
4206
3465
  f"{self.view_server}/api/open-metadata/collection-manager/collections/agreements/"
4207
3466
  f"{agreement_guid}/agreement-actors/{actor_guid}/attach")
4208
-
4209
- if validated_body:
4210
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
4211
- await self._async_make_request("POST", url, json_body)
4212
- else:
4213
- await self._async_make_request("POST", url)
3467
+ await self._async_new_relationship_request(url, "AgreementActorProperties",body)
4214
3468
  logger.info(f"Attached digital product manager {agreement_guid} -> {actor_guid}")
4215
3469
 
4216
3470
 
@@ -4309,28 +3563,11 @@ class CollectionManager(Client2):
4309
3563
 
4310
3564
  """
4311
3565
 
4312
- try:
4313
- if isinstance(body, DeleteRequestBody):
4314
- validated_body = body
4315
- elif isinstance(body, dict):
4316
- validated_body = self._delete_request_adapter.validate_python(body)
4317
- else:
4318
- validated_body = None
4319
-
4320
- except ValidationError as e:
4321
- logger.error(f"Validation error: {e}")
4322
- raise ValidationError(e)
4323
-
4324
3566
  url = (
4325
3567
  f"{self.platform_url}/servers/"
4326
3568
  f"{self.view_server}/api/open-metadata/collection-manager/collections/agreements/"
4327
3569
  f"{agreement_guid}/agreement-actors/{actor_guid}/detach")
4328
-
4329
- if validated_body:
4330
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
4331
- await self._async_make_request("POST", url, json_body)
4332
- else:
4333
- await self._async_make_request("POST", url)
3570
+ self._async_delete_request(url, body)
4334
3571
  logger.info(f"Detached digital product manager {agreement_guid} -> {actor_guid}")
4335
3572
 
4336
3573
 
@@ -4447,29 +3684,11 @@ class CollectionManager(Client2):
4447
3684
  }
4448
3685
 
4449
3686
  """
4450
- pass
4451
- # if isinstance(body,NewRelationshipRequestBody ):
4452
- # validated_body = body
4453
- # elif isinstance(body, dict):
4454
- # try:
4455
- # validated_body = (**body)
4456
- # except ValidationError as e:
4457
- # logger.error(f"Validation error: {e}")
4458
- # raise PyegeriaInvalidParameterException(f"Invalid body: {e}")
4459
- # elif body is None:
4460
- # validated_body = (
4461
- #
4462
- # )
4463
- # # else:
4464
- # raise PyegeriaInvalidParameterException(f"Invalid body type: {type(body)}")
4465
- # url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections/"
4466
- # f"agreements/{agreement_guid}/agreement-items/{agreement_item_guid}/attach")
4467
- #
4468
- # if body:
4469
- # await self._async_make_request("POST", url, body)
4470
- # else:
4471
- # await self._async_make_request("POST", url)
4472
- # logger.info(f"Attached agreement item {agreement_item_guid} to {agreement_guid}")
3687
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections/"
3688
+ f"agreements/{agreement_guid}/agreement-items/{agreement_item_guid}/attach")
3689
+
3690
+ await self._async_new_relationship_request(url, "AgreementItemProperties", body)
3691
+ logger.info(f"Attached agreement item {agreement_item_guid} to {agreement_guid}")
4473
3692
 
4474
3693
 
4475
3694
  def link_agreement_item(self, agreement_guid: str, agreement_item_guid: str, body: dict = None) -> None:
@@ -4537,7 +3756,7 @@ class CollectionManager(Client2):
4537
3756
 
4538
3757
  @dynamic_catch
4539
3758
  async def _async_detach_agreement_item(self, agreement_guid: str, agreement_item_guid: str,
4540
- body: dict = None) -> None:
3759
+ body: dict | DeleteRequestBody = None) -> None:
4541
3760
  """Detach an agreement item from an agreement. Request body is optional. Async version.
4542
3761
 
4543
3762
  Parameters
@@ -4546,8 +3765,8 @@ class CollectionManager(Client2):
4546
3765
  The guid of the agreement to link.
4547
3766
  agreement_item_guid: str
4548
3767
  The guid of the element to attach.
4549
- body: dict, optional, default = None
4550
- A dict representing the details of the relationship.
3768
+ body: dict | DeleteRequestBody, optional, default = None
3769
+ A structure representing the details of the relationship.
4551
3770
 
4552
3771
  Returns
4553
3772
  -------
@@ -4565,25 +3784,20 @@ class CollectionManager(Client2):
4565
3784
  Notes
4566
3785
  _____
4567
3786
  {
4568
- "class" : "MetadataSourceRequestBody",
3787
+ "class": "DeleteRequestBody",
4569
3788
  "externalSourceGUID": "add guid here",
4570
3789
  "externalSourceName": "add qualified name here",
4571
- "effectiveTime" : "{{$isoTimestamp}}",
4572
- "forLineage" : false,
4573
- "forDuplicateProcessing" : false
3790
+ "effectiveTime": "{{$isoTimestamp}}",
3791
+ "forLineage": false,
3792
+ "forDuplicateProcessing": false
4574
3793
  }
4575
3794
 
4576
3795
  """
4577
-
4578
3796
  url = (
4579
3797
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections"
4580
3798
  f"/agreements"
4581
3799
  f"{agreement_guid}/agreement-items/{agreement_item_guid}/detach")
4582
-
4583
- if body:
4584
- await self._async_make_request("POST", url, body)
4585
- else:
4586
- await self._async_make_request("POST", url)
3800
+ await self._async_delete_request(url, body)
4587
3801
  logger.info(f"Detached agreement item {agreement_item_guid} from {agreement_guid}")
4588
3802
 
4589
3803
 
@@ -4629,7 +3843,8 @@ class CollectionManager(Client2):
4629
3843
 
4630
3844
 
4631
3845
  @dynamic_catch
4632
- 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:
4633
3848
  """ Attach an agreement to an external reference element that describes the location of the contract
4634
3849
  documents.
4635
3850
  Request body is optional. Async version.
@@ -4640,8 +3855,8 @@ class CollectionManager(Client2):
4640
3855
  The guid of the agreement to update.
4641
3856
  external_ref_guid: str
4642
3857
  The guid of the external reference to attach.
4643
- body: dict, optional, default = None
4644
- A dict representing the details of the relationship.
3858
+ body: dict | NewRelationshipRequestBody, optional, default = None
3859
+ A structure representing the details of the relationship.
4645
3860
 
4646
3861
  Returns
4647
3862
  -------
@@ -4678,17 +3893,12 @@ class CollectionManager(Client2):
4678
3893
  }
4679
3894
 
4680
3895
  """
4681
-
4682
3896
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections/"
4683
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}")
4684
3900
 
4685
- if body:
4686
- await self._async_make_request("POST", url, body)
4687
- else:
4688
- await self._async_make_request("POST", url)
4689
- logger.info(f"Attached agreemenbt {agreement_guid} to contract {external_ref_guid}")
4690
-
4691
-
3901
+ @dynamic_catch
4692
3902
  def link_contract(self, agreement_guid: str, external_ref_guid: str, body: dict = None) -> None:
4693
3903
  """ Attach an agreement to an external reference element that describes the location of the contract
4694
3904
  documents.
@@ -4783,16 +3993,11 @@ class CollectionManager(Client2):
4783
3993
 
4784
3994
  url = (
4785
3995
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections"
4786
- f"/agreements"
4787
- f"{agreement_guid}/contract-links/{external_ref_guid}/detach")
4788
-
4789
- if body:
4790
- await self._async_make_request("POST", url, body)
4791
- else:
4792
- 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)
4793
3998
  logger.info(f"Detached contract: {external_ref_guid} from {agreement_guid}")
4794
3999
 
4795
-
4000
+ @dynamic_catch
4796
4001
  def detach_contract(self, agreement_guid: str, external_ref_guid: str, body: dict = None) -> None:
4797
4002
  """Detach an external reference to a contract, from an agreement. Request body is optional.
4798
4003
 
@@ -4839,13 +4044,13 @@ class CollectionManager(Client2):
4839
4044
 
4840
4045
 
4841
4046
  @dynamic_catch
4842
- async def _async_create_digital_subscription(self, body: dict) -> str:
4047
+ async def _async_create_digital_subscription(self, body: dict | NewElementRequestBody) -> str:
4843
4048
  """Create a new collection that represents a type of agreement called a digital_subscription. Async version.
4844
4049
 
4845
4050
  Parameters
4846
4051
  ----------
4847
- body: dict
4848
- 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.
4849
4054
 
4850
4055
  Returns
4851
4056
  -------
@@ -4937,13 +4142,8 @@ class CollectionManager(Client2):
4937
4142
  "forDuplicateProcessing" : false
4938
4143
  }
4939
4144
  """
4940
-
4941
4145
  url = f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections"
4942
-
4943
- resp = await self._async_make_request("POST", url, body_slimmer(body))
4944
- guid = resp.json().get('guid', NO_GUID_RETURNED)
4945
- logger.info(f"Create collection with GUID: {guid}")
4946
- return guid
4146
+ return await self._async_create_element_body_request(url, "DigitalSubscriptionProperties", body)
4947
4147
 
4948
4148
 
4949
4149
  def create_digital_subscription(self, body: dict) -> str:
@@ -5019,19 +4219,16 @@ class CollectionManager(Client2):
5019
4219
 
5020
4220
 
5021
4221
  @dynamic_catch
5022
- async def _async_update_digital_subscription(self, digital_subscription_guid: str, body: dict,
5023
- replace_all_props: bool = False, ):
4222
+ async def _async_update_digital_subscription(self, digital_subscription_guid: str,
4223
+ body: dict | UpdateElementRequestBody) -> None:
5024
4224
  """Update the properties of the digital_subscription collection. Async version.
5025
4225
 
5026
4226
  Parameters
5027
4227
  ----------
5028
4228
  digital_subscription_guid: str
5029
4229
  The guid of the digital_subscription to update.
5030
- body: dict
5031
- A dict representing the details of the collection to create.
5032
- replace_all_props: bool, optional, defaults to False
5033
- Whether to replace all properties in the collection.
5034
-
4230
+ body: dict | UpdateElementRequestBody
4231
+ A structure representing the details of the collection to create.
5035
4232
 
5036
4233
  Returns
5037
4234
  -------
@@ -5075,17 +4272,13 @@ class CollectionManager(Client2):
5075
4272
  "forDuplicateProcessing" : false
5076
4273
  }
5077
4274
  """
5078
-
5079
- replace_all_props_s = str(replace_all_props).lower()
5080
4275
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections/"
5081
- f"{digital_subscription_guid}/update?replaceAllProperties={replace_all_props_s}")
5082
-
5083
- 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 )
5084
4278
  logger.info(f"Updated digital subscription {digital_subscription_guid}")
5085
4279
 
5086
-
5087
- def update_digital_subscription(self, digital_subscription_guid: str, body: dict,
5088
- replace_all_props: bool = False, ):
4280
+ @dynamic_catch
4281
+ def update_digital_subscription(self, digital_subscription_guid: str, body: dict,):
5089
4282
  """Update the properties of the DigitalProduct classification attached to a collection.
5090
4283
 
5091
4284
  Parameters
@@ -5138,19 +4331,22 @@ class CollectionManager(Client2):
5138
4331
  """
5139
4332
  loop = asyncio.get_event_loop()
5140
4333
  loop.run_until_complete(
5141
- self._async_update_digital_subscription(digital_subscription_guid, body, replace_all_props))
4334
+ self._async_update_digital_subscription(digital_subscription_guid, body))
5142
4335
 
5143
4336
 
5144
4337
  @dynamic_catch
5145
- async def _async_update_digital_subscription_status(self, digital_subscription_guid: str, body: dict):
5146
- """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.
5147
4341
 
5148
4342
  Parameters
5149
4343
  ----------
5150
4344
  digital_subscription_guid: str
5151
4345
  The guid of the digital product collection to update.
5152
- body: dict
5153
- 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.
5154
4350
 
5155
4351
  Returns
5156
4352
  -------
@@ -5168,27 +4364,26 @@ class CollectionManager(Client2):
5168
4364
  Notes
5169
4365
  -----
5170
4366
  JSON Structure looks like:
5171
- {
5172
- "class": "AgreementStatusRequestBody",
5173
- "status": "APPROVED",
5174
- "externalSourceGUID": "add guid here",
5175
- "externalSourceName": "add qualified name here",
5176
- "effectiveTime": "{{$isoTimestamp}}",
5177
- "forLineage": false,
5178
- "forDuplicateProcessing": false
5179
- }
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
+ }
5180
4376
  """
5181
-
5182
4377
  url = (
5183
4378
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections"
5184
4379
  f"/agreements/"
5185
4380
  f"{digital_subscription_guid}/update-status")
5186
-
5187
- await self._async_make_request("POST", url, body)
4381
+ await self._async_update_status_request(url, status, body)
5188
4382
  logger.info(f"Updated status for DigitalProduct {digital_subscription_guid}")
5189
4383
 
5190
-
5191
- 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,):
5192
4387
  """Update the status of an digital_subscription collection. Async version.
5193
4388
 
5194
4389
  Parameters
@@ -5230,7 +4425,8 @@ class CollectionManager(Client2):
5230
4425
 
5231
4426
 
5232
4427
  @dynamic_catch
5233
- 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:
5234
4430
  """ Attach a subscriber to a subscription. The subscriber is of type 'Referenceable' to allow digital
5235
4431
  products, team or business capabilities to be the subscriber. The subscription is an element of type
5236
4432
  DigitalSubscription.
@@ -5242,8 +4438,8 @@ class CollectionManager(Client2):
5242
4438
  The unique identifier of the subscriber.
5243
4439
  subscription_guid: str
5244
4440
  The identifier of the subscription.
5245
- body: dict, optional, default = None
5246
- A dict representing the details of the relationship.
4441
+ body: dict | NewRelationshipRequestBody, optional, default = None
4442
+ A structure representing the details of the relationship.
5247
4443
 
5248
4444
  Returns
5249
4445
  -------
@@ -5262,7 +4458,7 @@ class CollectionManager(Client2):
5262
4458
  -----
5263
4459
  JSON Structure looks like:
5264
4460
  {
5265
- "class" : "RelationshipRequestBody",
4461
+ "class" : "NewRelationshipRequestBody",
5266
4462
  "externalSourceGUID": "add guid here",
5267
4463
  "externalSourceName": "add qualified name here",
5268
4464
  "effectiveTime" : "{{$isoTimestamp}}",
@@ -5276,19 +4472,16 @@ class CollectionManager(Client2):
5276
4472
  }
5277
4473
  }
5278
4474
  """
5279
-
5280
4475
  url = (
5281
4476
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections"
5282
4477
  f"/subscribers/"
5283
4478
  f"{subscriber_guid}/subscriptions/{subscription_guid}/attach")
5284
- if body:
5285
- await self._async_make_request("POST", url, body)
5286
- else:
5287
- await self._async_make_request("POST", url)
4479
+ await self._async_new_relationship_request(url, "DigitalSubscriberProperties", body)
5288
4480
  logger.info(f"Linking subscriber {subscriber_guid} to subscription {subscription_guid}")
5289
4481
 
5290
-
5291
- 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):
5292
4485
  """ Attach a subscriber to a subscription. The subscriber is of type 'Referenceable' to allow digital
5293
4486
  products, team or business capabilities to be the subscriber. The subscription is an element of type
5294
4487
  DigitalSubscription.
@@ -5339,7 +4532,8 @@ class CollectionManager(Client2):
5339
4532
 
5340
4533
 
5341
4534
  @dynamic_catch
5342
- 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:
5343
4537
  """ Detach a subscriber from a subscription Request body is optional. Async version.
5344
4538
 
5345
4539
  Parameters
@@ -5348,8 +4542,8 @@ class CollectionManager(Client2):
5348
4542
  The unique identifier of the subscriber.
5349
4543
  subscription_guid: str
5350
4544
  The unique identifier of the subscription.
5351
- body: dict, optional, default = None
5352
- A dict representing the details of the relationship.
4545
+ body: dict | DeleteRequestBody, optional, default = None
4546
+ A structure representing the details of the relationship.
5353
4547
 
5354
4548
  Returns
5355
4549
  -------
@@ -5376,19 +4570,15 @@ class CollectionManager(Client2):
5376
4570
  "forDuplicateProcessing": false
5377
4571
  }
5378
4572
  """
5379
-
5380
4573
  url = (
5381
4574
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/collection-manager/collections"
5382
4575
  f"/agreements/"
5383
4576
  f"{subscriber_guid}/agreement-actors/{subscription_guid}/detach")
5384
- if body:
5385
- await self._async_make_request("POST", url, body)
5386
- else:
5387
- await self._async_make_request("POST", url)
4577
+ await self._async_delete_request(url, body)
5388
4578
  logger.info(f"Detached subscriber {subscriber_guid} from subscription {subscription_guid}")
5389
4579
 
5390
4580
 
5391
- 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):
5392
4582
  """ Detach a subscriber from a subscription. Request body is optional.
5393
4583
 
5394
4584
  Parameters
@@ -5434,8 +4624,8 @@ class CollectionManager(Client2):
5434
4624
 
5435
4625
 
5436
4626
  @dynamic_catch
5437
- async def _async_attach_collection(self, parent_guid: str, collection_guid: str, body: dict = None,
5438
- make_anchor: bool = False):
4627
+ async def _async_attach_collection(self, parent_guid: str, collection_guid: str,
4628
+ body: dict | NewRelationshipRequestBody= None):
5439
4629
  """ Connect an existing collection to an element using the ResourceList relationship (0019).
5440
4630
  Async version.
5441
4631
 
@@ -5445,10 +4635,8 @@ class CollectionManager(Client2):
5445
4635
  The unique identifier of the parent to attach to.
5446
4636
  collection_guid: str
5447
4637
  The identifier of the collection being attached.
5448
- body: dict, optional, default = None
5449
- A dict representing the details of the relationship.
5450
- make_anchor: bool, optional, default = False
5451
- 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.
5452
4640
 
5453
4641
  Returns
5454
4642
  -------
@@ -5468,7 +4656,7 @@ class CollectionManager(Client2):
5468
4656
  JSON Structure looks like:
5469
4657
 
5470
4658
  {
5471
- "class" : "RelationshipRequestBody",
4659
+ "class" : "NewRelationshipRequestBody",
5472
4660
  "properties": {
5473
4661
  "class": "ResourceListProperties",
5474
4662
  "resourceUse": "Add valid value here",
@@ -5491,16 +4679,13 @@ class CollectionManager(Client2):
5491
4679
  url = (
5492
4680
  f"{self.platform_url}/servers/"
5493
4681
  f"{self.view_server}/api/open-metadata/collection-manager/metadata-elements/"
5494
- f"{parent_guid}/collections/{collection_guid}/attach?makeAchor={make_anchor}")
5495
- if body:
5496
- await self._async_make_request("POST", url, body)
5497
- else:
5498
- 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)
5499
4684
  logger.info(f"Attached {collection_guid} to {parent_guid}")
5500
4685
 
5501
-
5502
- def attach_collection(self, parent_guid: str, collection_guid: str, body: dict = None,
5503
- make_anchor: bool = False):
4686
+ @dynamic_catch
4687
+ def attach_collection(self, parent_guid: str, collection_guid: str,
4688
+ body: dict | NewRelationshipRequestBody = None):
5504
4689
  """ Connect an existing collection to an element using the ResourceList relationship (0019).
5505
4690
 
5506
4691
  Parameters
@@ -5551,11 +4736,12 @@ class CollectionManager(Client2):
5551
4736
  }
5552
4737
  """
5553
4738
  loop = asyncio.get_event_loop()
5554
- 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))
5555
4740
 
5556
4741
 
5557
4742
  @dynamic_catch
5558
- 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):
5559
4745
  """ Detach an existing collection from an element. If the collection is anchored to the element,
5560
4746
  it is delete.
5561
4747
  Async version.
@@ -5566,8 +4752,8 @@ class CollectionManager(Client2):
5566
4752
  The unique identifier of the parent to detach from.
5567
4753
  collection_guid: str
5568
4754
  The identifier of the collection being detached.
5569
- body: dict, optional, default = None
5570
- A dict representing the details of the relationship.
4755
+ body: dict | DeleteRequestBody, optional, default = None
4756
+ A structure representing the details of the relationship.
5571
4757
 
5572
4758
 
5573
4759
  Returns
@@ -5587,27 +4773,25 @@ class CollectionManager(Client2):
5587
4773
  -----
5588
4774
  JSON Structure looks like:
5589
4775
  {
5590
- "class": "MetadataSourceRequestBody",
4776
+ "class": "DeleteRequestBody",
5591
4777
  "externalSourceGUID": "add guid here",
5592
4778
  "externalSourceName": "add qualified name here",
5593
4779
  "effectiveTime": "{{$isoTimestamp}}",
5594
4780
  "forLineage": false,
5595
4781
  "forDuplicateProcessing": false
5596
4782
  }
5597
- """
5598
4783
 
4784
+ """
5599
4785
  url = (
5600
4786
  f"{self.platform_url}/servers/"
5601
4787
  f"{self.view_server}/api/open-metadata/collection-manager/metadata-elements/"
5602
4788
  f"{parent_guid}/collections/{collection_guid}/detach")
5603
- if body:
5604
- await self._async_make_request("POST", url, body)
5605
- else:
5606
- await self._async_make_request("POST", url)
4789
+ await self._async_delete_request(url, body)
5607
4790
  logger.info(f"Detached collection {collection_guid} from {parent_guid}")
5608
4791
 
5609
4792
 
5610
- 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):
5611
4795
  """ Detach an existing collection from an element. If the collection is anchored to the element,
5612
4796
  it is delete.
5613
4797
 
@@ -5650,7 +4834,7 @@ class CollectionManager(Client2):
5650
4834
 
5651
4835
 
5652
4836
  @dynamic_catch
5653
- 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,
5654
4838
  cascade: bool = False) -> None:
5655
4839
  """Delete a collection. It is detected from all parent elements. If members are anchored to the collection
5656
4840
  then they are also deleted. Async version
@@ -5664,8 +4848,8 @@ class CollectionManager(Client2):
5664
4848
  cascade: bool, optional, defaults to True
5665
4849
  If true, a cascade delete is performed.
5666
4850
 
5667
- body: dict, optional, default = None
5668
- A dict representing the details of the relationship.
4851
+ body: dict | DeleteRequestBody, optional, default = None
4852
+ A structure representing the details of the relationship.
5669
4853
 
5670
4854
  Returns
5671
4855
  -------
@@ -5684,26 +4868,23 @@ class CollectionManager(Client2):
5684
4868
  _____
5685
4869
  JSON Structure looks like:
5686
4870
  {
5687
- "class" : "MetadataSourceRequestBody",
4871
+ "class": "DeleteRequestBody",
5688
4872
  "externalSourceGUID": "add guid here",
5689
4873
  "externalSourceName": "add qualified name here",
5690
- "effectiveTime" : "{{$isoTimestamp}}",
5691
- "forLineage" : false,
5692
- "forDuplicateProcessing" : false
4874
+ "effectiveTime": "{{$isoTimestamp}}",
4875
+ "forLineage": false,
4876
+ "forDuplicateProcessing": false
5693
4877
  }
5694
4878
 
5695
4879
 
5696
4880
  """
5697
- cascade_s = str(cascade).lower()
5698
- url = f"{self.collection_command_root}/{collection_guid}/delete?cascadedDelete={cascade_s}"
5699
- if body is None:
5700
- body = {"class": "NullRequestBody"}
5701
-
5702
- 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)
5703
4883
  logger.info(f"Deleted collection {collection_guid} with cascade {cascade}")
5704
4884
 
5705
4885
 
5706
- 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:
5707
4888
  """Delete a collection. It is detected from all parent elements. If members are anchored to the collection
5708
4889
  then they are also deleted.
5709
4890
 
@@ -5715,7 +4896,7 @@ class CollectionManager(Client2):
5715
4896
  cascade: bool, optional, defaults to True
5716
4897
  If true, a cascade delete is performed.
5717
4898
 
5718
- body: dict, optional, default = None
4899
+ body: dict DeleteRequestBodyt, optional, default = None
5719
4900
  A dict representing the details of the relationship.
5720
4901
 
5721
4902
  Returns
@@ -5734,14 +4915,7 @@ class CollectionManager(Client2):
5734
4915
  Notes
5735
4916
  _____
5736
4917
  JSON Structure looks like:
5737
- {
5738
- "class" : "MetadataSourceRequestBody",
5739
- "externalSourceGUID": "add guid here",
5740
- "externalSourceName": "add qualified name here",
5741
- "effectiveTime" : "{{$isoTimestamp}}",
5742
- "forLineage" : false,
5743
- "forDuplicateProcessing" : false
5744
- }
4918
+
5745
4919
 
5746
4920
 
5747
4921
  """
@@ -5750,7 +4924,8 @@ class CollectionManager(Client2):
5750
4924
 
5751
4925
 
5752
4926
  @dynamic_catch
5753
- 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:
5754
4929
  """Add an element to a collection. The request body is optional. Async version.
5755
4930
 
5756
4931
  Parameters
@@ -5759,12 +4934,9 @@ class CollectionManager(Client2):
5759
4934
  identity of the collection to return members for.
5760
4935
  element_guid: str
5761
4936
  Effective time of the query. If not specified will default to any time.
5762
- body: dict, optional, defaults to None
4937
+ body: dict NewRelationshipRequestBody, optional, defaults to None
5763
4938
  The body of the request to add to the collection. See notes.
5764
4939
 
5765
- The name of the server to use.
5766
-
5767
-
5768
4940
  Returns
5769
4941
  -------
5770
4942
  None
@@ -5782,7 +4954,7 @@ class CollectionManager(Client2):
5782
4954
  Notes
5783
4955
  -----
5784
4956
  Example body:
5785
- { "class": "RelationshipRequestBody",
4957
+ { "class": "NewRelationshipRequestBody",
5786
4958
  "properties" : {
5787
4959
  "class" : "CollectionMembershipProperties",
5788
4960
  "membershipRationale": "xxx",
@@ -5809,12 +4981,12 @@ class CollectionManager(Client2):
5809
4981
 
5810
4982
  url = (f"{self.collection_command_root}/{collection_guid}/members/"
5811
4983
  f"{element_guid}/attach")
5812
- body_s = body_slimmer(body)
5813
- await self._async_make_request("POST", url, body_s)
4984
+ await self._async_new_relationship_request(url, "CollectionMembershipProperties", body)
5814
4985
  logger.info(f"Added {element_guid} to {collection_guid}")
5815
4986
 
5816
4987
 
5817
- 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:
5818
4990
  """Add an element to a collection. The request body is optional.
5819
4991
 
5820
4992
  Parameters
@@ -5875,8 +5047,8 @@ class CollectionManager(Client2):
5875
5047
 
5876
5048
 
5877
5049
  @dynamic_catch
5878
- async def _async_update_collection_membership(self, collection_guid: str, element_guid: str, body: dict = None,
5879
- 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:
5880
5052
  """Update an element's membership to a collection. Async version.
5881
5053
 
5882
5054
  Parameters
@@ -5934,16 +5106,15 @@ class CollectionManager(Client2):
5934
5106
  }
5935
5107
  """
5936
5108
 
5937
- replace_all_props_s = str(replace_all_props).lower()
5938
5109
  url = (f"{self.collection_command_root}/{collection_guid}/members/"
5939
- f"{element_guid}/update?replaceAllProperties={replace_all_props_s}")
5940
- body_s = body_slimmer(body)
5941
- await self._async_make_request("POST", url, body_s)
5110
+ f"{element_guid}/update")
5111
+ await self._async_update_relationship_request(url, "CollectionMembershipProperties", body )
5942
5112
  logger.info(f"Updated membership for collection {collection_guid}")
5943
5113
 
5944
5114
 
5945
- def update_collection_membership(self, collection_guid: str, element_guid: str, body: dict = None,
5946
- 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:
5947
5118
  """Update an element's membership to a collection.
5948
5119
 
5949
5120
  Parameters
@@ -6002,12 +5173,12 @@ class CollectionManager(Client2):
6002
5173
  """
6003
5174
  loop = asyncio.get_event_loop()
6004
5175
  loop.run_until_complete(
6005
- self._async_update_collection_membership(collection_guid, element_guid, body, replace_all_props))
5176
+ self._async_update_collection_membership(collection_guid, element_guid, body))
6006
5177
 
6007
5178
 
6008
5179
  @dynamic_catch
6009
5180
  async def _async_remove_from_collection(self, collection_guid: str, element_guid: str,
6010
- body: dict = None) -> None:
5181
+ body: dict | DeleteRequestBody = None) -> None:
6011
5182
  """Remove an element from a collection. Async version.
6012
5183
 
6013
5184
  Parameters
@@ -6016,7 +5187,7 @@ class CollectionManager(Client2):
6016
5187
  identity of the collection to return members for.
6017
5188
  element_guid: str
6018
5189
  Effective time of the query. If not specified will default to any time.
6019
- body: dict, optional, defaults to None
5190
+ body: dict | DeleteRequestBody, optional, defaults to None
6020
5191
  The body of the request to add to the collection. See notes.
6021
5192
 
6022
5193
  Returns
@@ -6036,7 +5207,7 @@ class CollectionManager(Client2):
6036
5207
  Notes
6037
5208
  -----
6038
5209
  {
6039
- "class" : "MetadataSourceRequestBody",
5210
+ "class" : "DeleteRequestBody",
6040
5211
  "externalSourceGUID": "add guid here",
6041
5212
  "externalSourceName": "add qualified name here",
6042
5213
  "effectiveTime" : "{{$isoTimestamp}}",
@@ -6048,13 +5219,12 @@ class CollectionManager(Client2):
6048
5219
 
6049
5220
  url = (f"{self.collection_command_root}/{collection_guid}/members/"
6050
5221
  f"{element_guid}/detach")
6051
- if body is None:
6052
- body = {"class": "NullRequestBody"}
6053
- await self._async_make_request("POST", url, body)
5222
+ await self._async_delete_collection(url, body)
6054
5223
  logger.info(f"Removed member {element_guid} from collection {collection_guid}")
6055
5224
 
6056
5225
 
6057
- 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:
6058
5228
  """Remove an element from a collection. Async version.
6059
5229
 
6060
5230
  Parameters
@@ -6239,7 +5409,7 @@ class CollectionManager(Client2):
6239
5409
  output_formats = select_output_format_set(output_format_set, output_format)
6240
5410
  if isinstance(output_format_set, dict):
6241
5411
  output_formats = get_output_format_type_match(output_format_set, output_format)
6242
- # 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
6243
5413
  elif classification_name:
6244
5414
  output_formats = select_output_format_set(classification_name, output_format)
6245
5415
  else: