fusion-platform-python-sdk 1.14.7__tar.gz → 1.15.11__tar.gz

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.
Files changed (57) hide show
  1. {fusion_platform_python_sdk-1.14.7/fusion_platform_python_sdk.egg-info → fusion_platform_python_sdk-1.15.11}/PKG-INFO +1 -1
  2. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/__init__.py +3 -2
  3. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/command.py +10 -3
  4. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/model.py +73 -46
  5. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/organisation.py +1 -2
  6. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/process.py +15 -3
  7. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/process_execution.md +1 -0
  8. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/process_execution.py +1 -0
  9. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/service.md +4 -0
  10. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/service.py +17 -0
  11. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/translations.py +8 -6
  12. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11/fusion_platform_python_sdk.egg-info}/PKG-INFO +1 -1
  13. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/setup.py +1 -1
  14. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/tests/test_session.py +3 -5
  15. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/LICENSE.txt +0 -0
  16. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/MANIFEST.in +0 -0
  17. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/README.md +0 -0
  18. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/__main__.py +0 -0
  19. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/base.py +0 -0
  20. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/common/__init__.py +0 -0
  21. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/common/raise_thread.py +0 -0
  22. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/common/utilities.py +0 -0
  23. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/detailed_example.py +0 -0
  24. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/documentation.py +0 -0
  25. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/fusion_platform_sdk.pdf +0 -0
  26. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/glasgow.geojson +0 -0
  27. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/lake_district.geojson +0 -0
  28. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/localisations.py +0 -0
  29. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/localise.py +0 -0
  30. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/__init__.py +0 -0
  31. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/credit.md +0 -0
  32. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/credit.py +0 -0
  33. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/data.md +0 -0
  34. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/data.py +0 -0
  35. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/data_file.md +0 -0
  36. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/data_file.py +0 -0
  37. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/fields.py +0 -0
  38. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/organisation.md +0 -0
  39. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/process.md +0 -0
  40. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/process_service_execution.md +0 -0
  41. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/process_service_execution.py +0 -0
  42. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/process_service_execution_log.md +0 -0
  43. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/process_service_execution_log.py +0 -0
  44. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/user.md +0 -0
  45. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/models/user.py +0 -0
  46. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/quick_example.py +0 -0
  47. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform/session.py +0 -0
  48. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform_python_sdk.egg-info/SOURCES.txt +0 -0
  49. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform_python_sdk.egg-info/dependency_links.txt +0 -0
  50. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform_python_sdk.egg-info/entry_points.txt +0 -0
  51. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform_python_sdk.egg-info/requires.txt +0 -0
  52. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/fusion_platform_python_sdk.egg-info/top_level.txt +0 -0
  53. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/setup.cfg +0 -0
  54. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/tests/test_base.py +0 -0
  55. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/tests/test_command.py +0 -0
  56. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/tests/test_init.py +0 -0
  57. {fusion_platform_python_sdk-1.14.7 → fusion_platform_python_sdk-1.15.11}/tests/test_localise.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fusion-platform-python-sdk
3
- Version: 1.14.7
3
+ Version: 1.15.11
4
4
  Summary: Python SDK used to interact with the Fusion Platform(r)
5
5
  Home-page: https://github.com/d-cat-support/fusion-platform-python-sdk
6
6
  Author: Digital Content Analysis Technology Ltd
@@ -11,8 +11,8 @@ API, and this is defined within the corresponding OpenAPI 3.0 specification, whi
11
11
  """
12
12
 
13
13
  # Do not modify the following two lines as they are maintained by the version.sh script.
14
- __version__ = '1.14.7'
15
- __version_date__ = '2024-10-29T15:47:22Z'
14
+ __version__ = '1.15.11'
15
+ __version_date__ = '2024-12-13T13:48:29Z'
16
16
 
17
17
  # Exclude certain sub-modules from documentation.
18
18
  # @formatter:off
@@ -73,6 +73,7 @@ __pdoc__ = {
73
73
  'models.service.ServiceInputExpressionSchema': False,
74
74
  'models.service.ServiceOptionExpressionSchema': False,
75
75
  'models.service.ServiceValidationSchema': False,
76
+ 'models.service.ServiceOrganisationChargeExpressionSchema': False,
76
77
  'models.user.UserSchema.Meta': False,
77
78
  'models.user.UserSchema.opts': False,
78
79
  'models.user.UserOrganisationSchema': False,
@@ -305,7 +305,7 @@ class Command(Base):
305
305
  non_aggregator_digits = len(str(non_aggregator_count))
306
306
  non_aggregator_chains = process.chains if hasattr(process, Model._FIELD_CHAINS) else []
307
307
 
308
- self.__print(logging.INFO, i18n.t('command.define_storage', files=non_aggregator_count))
308
+ self.__print(logging.INFO, i18n.t('command.define_storage', slices=non_aggregator_count))
309
309
  progress_bar = tqdm(total=non_aggregator_count, ncols=100)
310
310
 
311
311
  for group_index in range(1, non_aggregator_count + 1):
@@ -896,7 +896,7 @@ class Command(Base):
896
896
  # Change the print and logging to the desired level.
897
897
  self._logger.setLevel(logging.CRITICAL)
898
898
 
899
- if arguments.verbose:
899
+ if arguments.debug:
900
900
  self.__print_level = logging.DEBUG
901
901
  else:
902
902
  self.__print_level = logging.INFO
@@ -979,6 +979,9 @@ class Command(Base):
979
979
 
980
980
  # Create the subparsers.
981
981
  subparsers = parser.add_subparsers(help=i18n.t('command.subparser'), dest='command')
982
+ parser.add_argument(i18n.t('command.version_short'), i18n.t('command.version_long'), help=i18n.t('command.version_help'), action='version',
983
+ version=i18n.t('command.version_content', version=fusion_platform.__version__, version_date=fusion_platform.__version_date__))
984
+
982
985
  subparsers.required = True
983
986
  parser_start = subparsers.add_parser(i18n.t('command.start.command'), help=i18n.t('command.start.help'))
984
987
  parser_define = subparsers.add_parser(i18n.t('command.define.command'), help=i18n.t('command.define.help'))
@@ -990,7 +993,7 @@ class Command(Base):
990
993
  default=Command._DEPLOYMENT_PRODUCTION_IRL)
991
994
  subparser.add_argument(i18n.t('command.email_short'), i18n.t('command.email_long'), help=i18n.t('command.email_help'))
992
995
  subparser.add_argument(i18n.t('command.organisation_short'), i18n.t('command.organisation_long'), help=i18n.t('command.organisation_help'))
993
- subparser.add_argument(i18n.t('command.verbose_short'), i18n.t('command.verbose_long'), help=i18n.t('command.verbose_help'), default=False,
996
+ subparser.add_argument(i18n.t('command.debug_short'), i18n.t('command.debug_long'), help=i18n.t('command.debug_help'), default=False,
994
997
  action="store_true")
995
998
 
996
999
  # Start arguments.
@@ -1416,3 +1419,7 @@ def main():
1416
1419
  Main entry point for command line.
1417
1420
  """
1418
1421
  Command().main()
1422
+
1423
+
1424
+ if __name__ == "__main__":
1425
+ main()
@@ -35,10 +35,15 @@ class Model(Base):
35
35
  # Define the standard template model paths. Override these with the correct paths.
36
36
  _PATH_CREATE = None
37
37
  _PATH_DELETE = None
38
+ _PATH_EDIT = None
38
39
  _PATH_GET = None
39
40
  _PATH_NEW = None
40
41
  _PATH_PATCH = None
41
42
 
43
+ # Define the expected model and list extras. Override these with the correct values.
44
+ _EXTRAS_MODEL = None
45
+ _EXTRAS_LIST = None
46
+
42
47
  # Useful fields and templates.
43
48
  _FIELD_AVAILABLE_DISPATCHERS = 'available_dispatchers'
44
49
  _FIELD_BOUNDS = 'bounds'
@@ -153,6 +158,27 @@ class Model(Base):
153
158
  self.__model = None
154
159
  self.__persisted = False
155
160
 
161
+ @classmethod
162
+ def _extract_extras(cls, response, extras=None):
163
+ """
164
+ Extracts the optional extras from the response. If the extras are not found, they are not loaded.
165
+
166
+ Args:
167
+ response: The response to be modified.
168
+ extras: The optional list of extras as tuples (key, attribute) to extract.
169
+
170
+ Returns:
171
+ The extracted extras.
172
+ """
173
+ extracted_extras = {}
174
+ model_extras = response.get(Model._RESPONSE_KEY_EXTRAS, {})
175
+
176
+ for key, attribute in (extras if extras is not None else []):
177
+ if (key is not None) and (attribute is not None):
178
+ extracted_extras[attribute] = model_extras.get(key)
179
+
180
+ return extracted_extras
181
+
156
182
  @property
157
183
  def attributes(self):
158
184
  """
@@ -308,9 +334,9 @@ class Model(Base):
308
334
  def get(self, **kwargs):
309
335
  """
310
336
  Gets the model object by loading it from the Fusion Platform<sup>&reg;</sup>. Uses the model's current id and base model id for the get unless explicit
311
- values are provided via keyword arguments. This assumes the model is obtained using a GET RESTful request, and that the model data is held with the expected
312
- dictionary key within the response. The model is then loaded using the supplied schema to obtain the corresponding Python representation of it, before
313
- loading it into the model as a set of read-only attributes.
337
+ values are provided via keyword arguments. Any expected extras are also added. This assumes the model is obtained using a GET RESTful request, and that the
338
+ model data is held with the expected dictionary key within the response. The model is then loaded using the supplied schema to obtain the corresponding
339
+ Python representation of it, before loading it into the model as a set of read-only attributes.
314
340
 
315
341
  Args:
316
342
  kwargs: Any explicit ids to be used.
@@ -431,7 +457,7 @@ class Model(Base):
431
457
  @classmethod
432
458
  def _model_from_api_id(cls, session, **kwargs):
433
459
  """
434
- Loads a model object with the given ids as keyword arguments from the Fusion Platform<sup>&reg;</sup>.
460
+ Loads a model object with the given ids as keyword arguments from the Fusion Platform<sup>&reg;</sup>. Any required extras are also added.
435
461
 
436
462
  Args:
437
463
  session: The linked session object for interfacing with the Fusion Platform<sup>&reg;</sup>.
@@ -455,7 +481,7 @@ class Model(Base):
455
481
  @classmethod
456
482
  def _models_from_api_ids(cls, session, ids):
457
483
  """
458
- Generates an iterator through a series of models using their ids. Each model is loaded using an id.
484
+ Generates an iterator through a series of models using their ids. Each model is loaded using an id. Any extras are optionally added.
459
485
 
460
486
  Args:
461
487
  session: The linked session object for interfacing with the Fusion Platform<sup>&reg;</sup>.
@@ -471,10 +497,10 @@ class Model(Base):
471
497
  return (cls._model_from_api_id(session, **id) for id in ids)
472
498
 
473
499
  @classmethod
474
- def _models_from_api_path(cls, session, path, items_per_request=24, reverse=False, filter=None, search=None, **kwargs):
500
+ def _models_from_api_path(cls, session, path, items_per_request=24, reverse=False, filter=None, search=None, load_extras=True, **kwargs):
475
501
  """
476
- Generates an iterator through a series of models using a path which returns a list of objects. Each model is loaded from the list. Since API lists are
477
- paged, the generator takes into account having to get subsequent pages of results.
502
+ Generates an iterator through a series of models using a path which returns a list of objects. Each model is loaded from the list with its expected extras.
503
+ Since API lists are paged, the generator takes into account having to get subsequent pages of results.
478
504
 
479
505
  Use the items per request, reverse and filter parameters to modify the set of results returned. The items per request parameter determines how many results
480
506
  are returned by each request to the API for a page of results, up to the maximum number of results available. The reverse parameter can be used to return
@@ -508,6 +534,7 @@ class Model(Base):
508
534
  reverse: Whether the list should be reversed or not. Default False.
509
535
  filter: The optional filter to be applied to the results. Default is no filter.
510
536
  search: The optional search term to be applied to the results. Default to no search term.
537
+ load_extras: Should the model extras be automatically loaded? Default True.
511
538
  kwargs: Any additional attributes which are to be set on each model which are not provided in each item from the path.
512
539
 
513
540
  Returns:
@@ -541,55 +568,40 @@ class Model(Base):
541
568
  Model._RESPONSE_KEY_LAST) is not None else {}
542
569
  finished = len(last) <= 0
543
570
 
544
- # Build the generator around all of the returned items, which must all have been persisted.
571
+ # Optionally extract the extras.
572
+ extracted_extras = cls._extract_extras(response, extras=cls._EXTRAS_LIST) if load_extras else {}
573
+
574
+ # Build the generator around all of the returned items, which must all have been persisted. Optional extras are added to each model.
545
575
  for item in response.get(Model._RESPONSE_KEY_LIST, []):
576
+ # Add the optional extras into the item.
577
+ for key, value in extracted_extras.items():
578
+ item[key] = value
579
+
580
+ # Build the model from the modified item dictionary.
546
581
  model = cls(session)
547
582
  model._set_model_from_response(item, **kwargs)
548
583
  model.__persisted = True
549
584
 
550
585
  yield model
551
586
 
552
- def _new(self, query_parameters=None, extras=None, **kwargs):
587
+ def _new(self, query_parameters=None, **kwargs):
553
588
  """
554
- Gets a new template model object by loading it from the Fusion Platform<sup>&reg;</sup>. The explicit base model id value should be provided via a keyword
555
- argument. This assumes the model is obtained using a GET RESTful request from the corresponding path, and that the model data is held with the expected
556
- dictionary key within the response. The template model is then loaded using the supplied schema to obtain the corresponding Python representation of it,
557
- before loading it into the model as a set of read-only attributes. If any extras are provided as a list of tuples (key, attribute), where key refers to the
558
- field in the extras, and attribute is the corresponding model attribute to be set from the field, then each is added to the model.
589
+ Gets a new template model object by loading it from the Fusion Platform<sup>&reg;</sup>. Any expected extras are also added. The explicit base model id
590
+ value should be provided via a keyword argument. This assumes the model is obtained using a GET RESTful request from the corresponding path, and that the
591
+ model data is held with the expected dictionary key within the response. The template model is then loaded using the supplied schema to obtain the
592
+ corresponding Python representation of it, before loading it into the model as a set of read-only attributes.
559
593
 
560
594
  Args:
561
595
  query_parameters: The optional query parameters as a dictionary.
562
- extras: The optional list of extras tuples (key, attribute) which should be added to the model.
563
596
  kwargs: Should include the base model id, if needed.
564
597
 
565
598
  Raises:
566
599
  RequestError: if the new fails.
567
600
  ModelError: if the model could not be loaded or validated from the Fusion Platform<sup>&reg;</sup>.
568
601
  """
569
- # Get the data.
570
- response = self._session.request(path=self._get_path(self.__class__._PATH_NEW, **kwargs), query_parameters=query_parameters)
571
602
 
572
- # Assume that the resulting model is held within the expected key within the resulting dictionary.
573
- if Model._RESPONSE_KEY_MODEL not in response:
574
- raise ModelError(i18n.t('models.model.failed_model_new_model'))
575
-
576
- # If any extras are required, extract them.
577
- if (Model._RESPONSE_KEY_EXTRAS not in response) and (extras is not None):
578
- raise ModelError(i18n.t('models.model.failed_model_new_extras'))
579
-
580
- modified_response = response.get(Model._RESPONSE_KEY_MODEL, {})
581
- model_extras = response.get(Model._RESPONSE_KEY_EXTRAS, {})
582
-
583
- for key, attribute in (extras if extras is not None else []):
584
- if (key is not None) and (attribute is not None):
585
- modified_response[attribute] = model_extras.get(key)
586
-
587
- # Add in the keyword arguments to the response so that they are set in the model as well.
588
- for key, value in kwargs.items():
589
- modified_response[key] = value
590
-
591
- # Load the response into the model. We ignore missing required fields and those which are None.
592
- self._set_model_from_response(modified_response, partial=True)
603
+ # Get and load the data, setting the extras as well.
604
+ self._send_and_load(self._get_path(self.__class__._PATH_NEW, **kwargs), partial=True, query_parameters=query_parameters, **kwargs)
593
605
 
594
606
  # The model is not persisted.
595
607
  self.__persisted = False
@@ -604,25 +616,40 @@ class Model(Base):
604
616
  """
605
617
  return self.__persisted
606
618
 
607
- def _send_and_load(self, path, method=Session.METHOD_GET, body=None, key=_RESPONSE_KEY_MODEL):
619
+ def _send_and_load(self, path, method=Session.METHOD_GET, body=None, key=_RESPONSE_KEY_MODEL, partial=False, query_parameters=None, **kwargs):
608
620
  """
609
- Sends the body to the path using the method and then loads the resulting model.
621
+ Sends the body to the path using the method and then loads the resulting model. Additional query parameters may be specified that should be added to the
622
+ model. Keyword arguments can be used to be added to the model, overriding any values that may have been retrieved.
610
623
 
611
624
  Args:
612
625
  path: The path to send the request to.
613
626
  method: The optional RESTful method for sending. Default is GET.
614
627
  body: The optional body to send. Default is None.
615
628
  key: The optional key to load the model from the response. Default is RESPONSE_KEY_MODEL.
629
+ partial: Skip validation of required fields which are missing? Default False.
630
+ query_parameters: The optional query parameters as a dictionary.
631
+ kwargs: Should include the base model id, if needed.
616
632
  """
617
633
  # Send the request.
618
- response = self._session.request(path=path, method=method, body=body)
634
+ response = self._session.request(path=path, query_parameters=query_parameters, method=method, body=body)
619
635
 
620
636
  # Assume that the resulting model is held within the expected key within the resulting dictionary.
621
637
  if key not in response:
622
638
  raise ModelError(i18n.t('models.model.failed_model_send_and_load'))
623
639
 
624
- # Load the response into the model.
625
- self._set_model_from_response(response.get(key, {}))
640
+ # If any extras are required, extract them and add them to the model.
641
+ modified_response = response.get(key, {}) if key is not None else response
642
+ extracted_extras = self.__class__._extract_extras(response, extras=self.__class__._EXTRAS_MODEL)
643
+
644
+ for key, value in extracted_extras.items():
645
+ modified_response[key] = value
646
+
647
+ # Add in the keyword arguments to the response so that they are set in the model as well.
648
+ for key, value in kwargs.items():
649
+ modified_response[key] = value
650
+
651
+ # Load the response into the model. Optionally ignore missing required fields and those which are None.
652
+ self._set_model_from_response(modified_response, partial=partial)
626
653
 
627
654
  def __setattr__(self, key, value):
628
655
  """
@@ -760,8 +787,8 @@ class Model(Base):
760
787
  def update(self, **kwargs):
761
788
  """
762
789
  Attempts to update the model object with the given values. For models which have not been persisted, the relevant fields are updated without validation,
763
- which will occur when the model is persisted. For models which have been persisted, the update is made via the Fusion Platform<sup>&reg;</sup>. All current model
764
- attributes are sent to the Fusion Platform<sup>&reg;</sup> which will automatically ignore any which are not allowed or are read-only.
790
+ which will occur when the model is persisted. For models which have been persisted, the update is made via the Fusion Platform<sup>&reg;</sup>. All current
791
+ model attributes are sent to the Fusion Platform<sup>&reg;</sup> which will automatically ignore any which are not allowed or are read-only.
765
792
 
766
793
  Args:
767
794
  kwargs: The model attributes which are to be patched.
@@ -301,8 +301,7 @@ class Organisation(Model):
301
301
  """
302
302
  # Get a new template for the process model using the service.
303
303
  process = Process(self._session)
304
- process._new(query_parameters={Model._get_id_name(Service.__name__): service.id},
305
- extras=[(self.__class__._FIELD_DISPATCHERS, self.__class__._FIELD_AVAILABLE_DISPATCHERS)], organisation_id=self.id, name=name)
304
+ process._new(query_parameters={Model._get_id_name(Service.__name__): service.id}, organisation_id=self.id, name=name)
306
305
 
307
306
  return process
308
307
 
@@ -228,7 +228,7 @@ class Option(Model):
228
228
  Returns:
229
229
  A string representation of the object.
230
230
  """
231
- return f"{self.title} ('{self.name}', {self.data_type}{', required' if self.required else ''}) = {self.value}: {self.description}"
231
+ return f"{self.title} ('{self.name}', {self.data_type}{' ' + str(self.constrained_values) if self.data_type == fusion_platform.DATA_TYPE_CONSTRAINED else ''}{', required' if self.required else ''}) = {self.value}: {self.description}"
232
232
 
233
233
 
234
234
  # Define a model class for an input which overrides the representation to display more relevant information.
@@ -319,6 +319,7 @@ class ProcessExecutionStatusSchema(Schema):
319
319
  group_count = fields.Integer(allow_none=True)
320
320
  job_status = fields.String(required=True)
321
321
  abort_reason = fields.String(allow_none=True)
322
+ exit_type = fields.String(allow_none=True)
322
323
  started_at = fields.DateTime(required=True)
323
324
  ended_at = fields.DateTime(allow_none=True)
324
325
  delete_warning_status = fields.String(required=True)
@@ -517,6 +518,10 @@ class Process(Model):
517
518
  _PATH_EXECUTIONS = f"{_PATH_BASE}/executions"
518
519
  _PATH_STOP = f"{_PATH_BASE}/stop"
519
520
 
521
+ # Define the expected model and list extras.
522
+ _EXTRAS_MODEL = [(Model._FIELD_DISPATCHERS, Model._FIELD_AVAILABLE_DISPATCHERS)]
523
+ _EXTRAS_LIST = [(Model._FIELD_DISPATCHERS, Model._FIELD_AVAILABLE_DISPATCHERS)]
524
+
520
525
  # Process status values.
521
526
  _PROCESS_STATUS_EXECUTE = 'execute'
522
527
  _PROCESS_STATUS_STOP = 'stop'
@@ -631,6 +636,12 @@ class Process(Model):
631
636
  modified_response = response.get(Model._RESPONSE_KEY_MODEL, {})
632
637
  modified_response['organisation_id'] = self.organisation_id
633
638
 
639
+ # Extract the extras.
640
+ extracted_extras = self.__class__._extract_extras(response, extras=self.__class__._EXTRAS_LIST)
641
+
642
+ for key, value in extracted_extras.items():
643
+ modified_response[key] = value
644
+
634
645
  # Load the response into the model. We ignore missing required fields and those which are None.
635
646
  process._set_model_from_response(modified_response, partial=True)
636
647
 
@@ -745,7 +756,8 @@ class Process(Model):
745
756
  RequestError: if any get fails.
746
757
  ModelError: if a model could not be loaded or validated from the Fusion Platform<sup>&reg;</sup>.
747
758
  """
748
- return ProcessExecution._models_from_api_path(self._session, self._get_path(self.__class__._PATH_EXECUTIONS), reverse=True) # Most recent first.
759
+ return ProcessExecution._models_from_api_path(self._session, self._get_path(self.__class__._PATH_EXECUTIONS), reverse=True,
760
+ load_extras=False) # Most recent first.
749
761
 
750
762
  def find_executions(self, id=None, group_id=None):
751
763
  """
@@ -766,7 +778,7 @@ class Process(Model):
766
778
  [(self.__class__._FIELD_ID, self.__class__._FILTER_MODIFIER_EQ, id), (self.__class__._FIELD_GROUP_ID, self.__class__._FILTER_MODIFIER_EQ, group_id)])
767
779
 
768
780
  # Build the partial find generator and execute it.
769
- find = partial(ProcessExecution._models_from_api_path, self._session, self._get_path(self.__class__._PATH_EXECUTIONS), filter=filter)
781
+ find = partial(ProcessExecution._models_from_api_path, self._session, self._get_path(self.__class__._PATH_EXECUTIONS), filter=filter, load_extras=False)
770
782
  return self.__class__._first_and_generator(find)
771
783
 
772
784
  @property
@@ -33,6 +33,7 @@
33
33
  * **stopped**: Has the execution been stopped by a user?
34
34
  * **abort**: Has the execution been aborted?
35
35
  * **abort_reason**: The reason for any abort of the execution.
36
+ * **exit_type**: The type of exit experienced by the execution.
36
37
  * **success**: Has the execution completed successfully?
37
38
  * **progress**: Percentage progress of the execution.
38
39
  * **delete_expiry**: When will the execution expire and therefore be deleted?
@@ -106,6 +106,7 @@ class ProcessExecutionSchema(Schema):
106
106
  stopped = fields.Boolean(required=True, metadata={'read_only': True}) # Changed to prevent this being updated.
107
107
  abort = fields.Boolean(required=True, metadata={'read_only': True}) # Changed to prevent this being updated.
108
108
  abort_reason = fields.String(allow_none=True, metadata={'read_only': True}) # Changed to prevent this being updated.
109
+ exit_type = fields.String(allow_none=True, metadata={'read_only': True}) # Changed to prevent this being updated.
109
110
  success = fields.Boolean(required=True, metadata={'read_only': True}) # Changed to prevent this being updated.
110
111
  progress = fields.Integer(required=True, metadata={'read_only': True}) # Changed to prevent this being updated.
111
112
  delete_expiry = fields.DateTime(required=True)
@@ -68,6 +68,10 @@
68
68
  * **charge_expression_platform**: The expression used to calculate the charge in FPUs levied for the platform.
69
69
  * **charge_expression_owner**: The expression used to calculate the charge in FPUs levied for the owner of the service.
70
70
  * **organisations**: The optional whitelist of organisations who can use this service.
71
+ * **organisation_charge_expressions**: For the whitelisted organisations, these provide the optional charge expressions to be applied.
72
+ * **id**: The owning organisation.
73
+ * **platform**: The expression used to calculate the charge in FPUs levied for the platform.
74
+ * **owner**: The expression used to calculate the charge in FPUs levied for the owner of the service.
71
75
  * **geographic_regions**: The optional list of geographic regions from which this service can be used.
72
76
  * **documentation_summary**: The documentation summary of the service.
73
77
  * **documentation_description**: The documentation description of the service.
@@ -184,6 +184,22 @@ class ServiceValidationSchema(Schema):
184
184
  ordered = True
185
185
 
186
186
 
187
+ class ServiceOrganisationChargeExpressionSchema(Schema):
188
+ """
189
+ Nested schema class for service organisation.
190
+ """
191
+ id = fields.UUID(required=True)
192
+ platform = fields.String(allow_none=True)
193
+ owner = fields.String(allow_none=True)
194
+
195
+ class Meta:
196
+ """
197
+ When loading an object, make sure we exclude any unknown fields, rather than raising an exception, and put fields in their definition order.
198
+ """
199
+ unknown = EXCLUDE
200
+ ordered = True
201
+
202
+
187
203
  class ServiceSchema(Schema):
188
204
  """
189
205
  Schema class for service model.
@@ -230,6 +246,7 @@ class ServiceSchema(Schema):
230
246
  charge_expression_owner = fields.String(allow_none=True) # Changed to optional.
231
247
 
232
248
  organisations = fields.List(fields.UUID(required=True), allow_none=True)
249
+ organisation_charge_expressions = fields.List(fields.Nested(ServiceOrganisationChargeExpressionSchema()), allow_none=True)
233
250
  geographic_regions = fields.List(fields.String(required=True), allow_none=True)
234
251
 
235
252
  # Removed creator.
@@ -48,7 +48,7 @@ i18n.add_translation('command.download_process', 'Downloading process \'%{proces
48
48
  i18n.add_translation('command.download_files', 'Downloading %{files} file(s)...', 'en')
49
49
  i18n.add_translation('command.download_executions', 'Gathering files for %{executions} execution(s)...', 'en')
50
50
  i18n.add_translation('command.download_execution', 'Downloading execution %{execution} to %{output}', 'en')
51
- i18n.add_translation('command.define_storage', 'Defining %{files} storage file(s)...', 'en')
51
+ i18n.add_translation('command.define_storage', 'Defining storage file(s) for %{slices} slice(s)...', 'en')
52
52
  i18n.add_translation('command.define_process', 'Defining \'%{process}\' (inputs %{inputs}, storage %{storage})', 'en')
53
53
  i18n.add_translation('command.define_inputs', 'Defining %{files} input file(s)...', 'en')
54
54
  i18n.add_translation('command.add_dispatcher', 'Add %{dispatcher} dispatcher?', 'en')
@@ -98,9 +98,13 @@ i18n.add_translation('command.start.definition_long', 'service_or_yaml', 'en')
98
98
  i18n.add_translation('command.start.help', 'starts a process', 'en')
99
99
  i18n.add_translation('command.start.command', 'start', 'en')
100
100
  i18n.add_translation('command.subparser', 'starts, defines or downloads a process', 'en')
101
- i18n.add_translation('command.verbose_help', 'show verbose output (default \'%%(default)s\')', 'en')
102
- i18n.add_translation('command.verbose_long', '--verbose', 'en')
103
- i18n.add_translation('command.verbose_short', '-v', 'en')
101
+ i18n.add_translation('command.version_content', '%%(prog)s %{version} (%{version_date})', 'en')
102
+ i18n.add_translation('command.version_help', 'show the version information and exit', 'en')
103
+ i18n.add_translation('command.version_long', '--version', 'en')
104
+ i18n.add_translation('command.version_short', '-v', 'en')
105
+ i18n.add_translation('command.debug_help', 'show debug output (default \'%%(default)s\')', 'en')
106
+ i18n.add_translation('command.debug_long', '--debug', 'en')
107
+ i18n.add_translation('command.debug_short', '-b', 'en')
104
108
  i18n.add_translation('command.organisation_help', 'the organisation to be used', 'en')
105
109
  i18n.add_translation('command.organisation_long', '--organisation', 'en')
106
110
  i18n.add_translation('command.organisation_short', '-g', 'en')
@@ -237,8 +241,6 @@ i18n.add_translation('models.fields.boolean.invalid', 'Not a valid boolean', 'en
237
241
  i18n.add_translation('models.model.update_empty_body', 'Update cannot be requested as there are no attributes to be used (read-only attributes have been removed)', 'en')
238
242
  i18n.add_translation('models.model.create_empty_body', 'Create cannot be requested as there are no attributes to be used (read-only attributes have been removed)', 'en')
239
243
  i18n.add_translation('models.model.failed_model_validation', 'Failed to validate model: %{message}', 'en')
240
- i18n.add_translation('models.model.failed_model_new_extras', 'Failed to get model extras from response', 'en')
241
- i18n.add_translation('models.model.failed_model_new_model', 'Failed to get model template from response', 'en')
242
244
  i18n.add_translation('models.model.failed_model_send_and_load', 'Failed to request and load model', 'en')
243
245
  i18n.add_translation('models.model.no_such_keys', 'No such keys %{keys}', 'en')
244
246
  i18n.add_translation('models.model.readonly_property', 'Property %{property} is read-only and cannot be set', 'en')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fusion-platform-python-sdk
3
- Version: 1.14.7
3
+ Version: 1.15.11
4
4
  Summary: Python SDK used to interact with the Fusion Platform(r)
5
5
  Home-page: https://github.com/d-cat-support/fusion-platform-python-sdk
6
6
  Author: Digital Content Analysis Technology Ltd
@@ -19,7 +19,7 @@ PACKAGE_DIR = pathlib.Path(__file__).parent
19
19
  # @formatter:off
20
20
  setup(
21
21
  name='fusion-platform-python-sdk',
22
- version='1.14.7',
22
+ version='1.15.11',
23
23
  description='Python SDK used to interact with the Fusion Platform(r)',
24
24
  long_description=(PACKAGE_DIR / 'README.md').read_text(),
25
25
  long_description_content_type='text/markdown',
@@ -61,17 +61,15 @@ class TestSession(CustomTestCase):
61
61
  """
62
62
 
63
63
  with tempfile.TemporaryDirectory() as dir:
64
- destination = os.path.join(dir, 'file.pdf')
64
+ destination = os.path.join(dir, 'file.html')
65
65
 
66
66
  session = Session()
67
67
 
68
68
  with pytest.raises(RequestError):
69
- session.download_file('https://www.d-cat.co.uk/rails/active_storage/blobs/rubbish/Water%20RA%20Webinar%20IoT%20September%202020.pdf?', destination)
69
+ session.download_file('https://www.d-cat.co.uk/.well-known/acme-challenge/test.html', destination)
70
70
 
71
71
  self.assertFalse(os.path.exists(destination))
72
- session.download_file(
73
- 'https://www.d-cat.co.uk/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBkUT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--8a6deba9596edd3e9f0c341d274ae1317da59bbc/Water%20RA%20Webinar%20IoT%20September%202020.pdf?',
74
- destination, self.download_callback)
72
+ session.download_file('https://www.d-cat.co.uk/home', destination, self.download_callback)
75
73
  self.assertTrue(os.path.exists(destination))
76
74
  self.assertIsNotNone(self._download_size)
77
75