prophecy-libs 2.0.0.dev6__tar.gz → 2.0.0.dev7__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 (137) hide show
  1. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/PKG-INFO +1 -1
  2. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/componentruns/component_runs_dao.py +13 -11
  3. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/evolutions/delta_metrics_storage_initializer.py +1 -1
  4. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/in_memory_store.py +226 -171
  5. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/package.py +28 -0
  6. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/pipelineruns/pipeline_run_service.py +50 -48
  7. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/schemas/em.py +41 -2
  8. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/schemas/external.py +8 -0
  9. prophecy-libs-2.0.0.dev7/prophecy/executionmetrics/workflow_parser.py +151 -0
  10. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/pipeline_monitoring.py +4 -38
  11. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/utils.py +84 -33
  12. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy_libs.egg-info/PKG-INFO +1 -1
  13. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy_libs.egg-info/SOURCES.txt +1 -0
  14. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/setup.py +1 -1
  15. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/README.md +0 -0
  16. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/__init__.py +0 -0
  17. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/config/__init__.py +0 -0
  18. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/config/config_base.py +0 -0
  19. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/config/config_base_test.py +0 -0
  20. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/config/utils.py +0 -0
  21. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/__init__.py +0 -0
  22. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/componentruns/__init__.py +0 -0
  23. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/componentruns/component_run_service.py +0 -0
  24. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/evolutions/__init__.py +0 -0
  25. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/evolutions/hive_parquet_storage_initializer.py +0 -0
  26. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/evolutions/metrics_storage_initializer.py +0 -0
  27. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/evolutions/models.py +0 -0
  28. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/evolutions/package.py +0 -0
  29. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/execution_metrics_handler.py +0 -0
  30. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/interims/__init__.py +0 -0
  31. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/interims/delta_interims.py +0 -0
  32. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/interims/hive_parquet_interims.py +0 -0
  33. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/interims/interims_table.py +0 -0
  34. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/logging_spark_session.py +0 -0
  35. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/models.py +0 -0
  36. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/pipelineruns/__init__.py +0 -0
  37. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/pipelineruns/pipeline_runs_dao.py +0 -0
  38. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/schemas/__init__.py +0 -0
  39. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/utils/__init__.py +0 -0
  40. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/utils/common.py +0 -0
  41. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/utils/constants.py +0 -0
  42. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/utils/external.py +0 -0
  43. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/utils/interim_store.py +0 -0
  44. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/executionmetrics/zip_file.py +0 -0
  45. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/jsonrpc/__init__.py +0 -0
  46. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/jsonrpc/models.py +0 -0
  47. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/libs/__init__.py +0 -0
  48. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/libs/uc_shared_utils.py +0 -0
  49. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/libs/utils.py +0 -0
  50. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/lookups/LookupsBase.py +0 -0
  51. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/lookups/LookupsNative.py +0 -0
  52. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/lookups/__init__.py +0 -0
  53. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/random_data_creator.py +0 -0
  54. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/streaming/__init__.py +0 -0
  55. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/streaming/delta_lake_utils.py +0 -0
  56. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/test/__init__.py +0 -0
  57. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/test/base_test_case.py +0 -0
  58. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/test/utils.py +0 -0
  59. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/udfs/__init__.py +0 -0
  60. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/udfs/rest_api_udf.py +0 -0
  61. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/udfs/sample_udf.py +0 -0
  62. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/udfs/scala_udf_wrapper.py +0 -0
  63. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/__init__.py +0 -0
  64. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/constants.py +0 -0
  65. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/data_profiler.py +0 -0
  66. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/datasampleloader.py +0 -0
  67. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/diff.py +0 -0
  68. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/dill/__diff.py +0 -0
  69. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/dill/__init__.py +0 -0
  70. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/dill/_dill.py +0 -0
  71. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/dill/_objects.py +0 -0
  72. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/dill/_shims.py +0 -0
  73. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/dill/detect.py +0 -0
  74. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/dill/logger.py +0 -0
  75. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/dill/objtypes.py +0 -0
  76. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/dill/pointers.py +0 -0
  77. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/dill/session.py +0 -0
  78. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/dill/settings.py +0 -0
  79. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/dill/source.py +0 -0
  80. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/dill/temp.py +0 -0
  81. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/__init__.py +0 -0
  82. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/__main__.py +0 -0
  83. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/cli.py +0 -0
  84. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/config.py +0 -0
  85. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/custom_typing.py +0 -0
  86. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/decode/__init__.py +0 -0
  87. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/decode/codes.py +0 -0
  88. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/documentor.py +0 -0
  89. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/exceptions.py +0 -0
  90. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/factory.py +0 -0
  91. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/generator.py +0 -0
  92. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/__init__.py +0 -0
  93. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/address/__init__.py +0 -0
  94. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/address/en/__init__.py +0 -0
  95. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/address/en_US/__init__.py +0 -0
  96. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/date_time/__init__.py +0 -0
  97. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/date_time/en_US/__init__.py +0 -0
  98. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/internet/__init__.py +0 -0
  99. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/internet/en_US/__init__.py +0 -0
  100. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/misc/__init__.py +0 -0
  101. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/misc/en_US/__init__.py +0 -0
  102. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/person/__init__.py +0 -0
  103. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/person/en_US/__init__.py +0 -0
  104. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/phone_number/__init__.py +0 -0
  105. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/phone_number/en_US/__init__.py +0 -0
  106. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/python/__init__.py +0 -0
  107. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/providers/python/en_US/__init__.py +0 -0
  108. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/proxy.py +0 -0
  109. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/utils/__init__.py +0 -0
  110. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/utils/checksums.py +0 -0
  111. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/utils/datasets.py +0 -0
  112. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/utils/decorators.py +0 -0
  113. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/utils/distribution.py +0 -0
  114. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/utils/loading.py +0 -0
  115. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/faker/utils/text.py +0 -0
  116. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/functions.py +0 -0
  117. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/gems_utils.py +0 -0
  118. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/httpclient.py +0 -0
  119. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/initial_python_code.py +0 -0
  120. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/json_rpc_layer.py +0 -0
  121. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/metagem_utils.py +0 -0
  122. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/monitoring_utils.py +0 -0
  123. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/request_processor.py +0 -0
  124. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/secrets.py +0 -0
  125. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/synthetic_data_generator.py +0 -0
  126. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/transpiler/__init__.py +0 -0
  127. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/transpiler/abi_base.py +0 -0
  128. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/transpiler/abi_core_fcns.py +0 -0
  129. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/transpiler/abi_fcn_wrapper.py +0 -0
  130. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/transpiler/dataframe_fcns.py +0 -0
  131. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/transpiler/dml_schema.py +0 -0
  132. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy/utils/transpiler/fixed_file_schema.py +0 -0
  133. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy_libs.egg-info/dependency_links.txt +0 -0
  134. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy_libs.egg-info/not-zip-safe +0 -0
  135. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy_libs.egg-info/requires.txt +0 -0
  136. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/prophecy_libs.egg-info/top_level.txt +0 -0
  137. {prophecy-libs-2.0.0.dev6 → prophecy-libs-2.0.0.dev7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: prophecy-libs
3
- Version: 2.0.0.dev6
3
+ Version: 2.0.0.dev7
4
4
  Summary: Helper library for prophecy generated code
5
5
  Home-page: https://github.com/SimpleDataLabsInc/prophecy-python-libs
6
6
  Author: UNKNOWN
@@ -693,8 +693,8 @@ class ComponentRunsDAO(ExecutionMetricsDAO):
693
693
  def _row_to_component_runs_with_status(self, row: Row) -> ComponentRunsWithStatus:
694
694
  """Convert Row to ComponentRunsWithStatus."""
695
695
  base = self._row_to_component_runs(row)
696
- return ComponentRunsWithStatus(
697
- **base.__dict__, status=row[STATUS] if STATUS in row else None
696
+ return ComponentRunsWithStatus.from_component_runs(
697
+ base, row[STATUS] if STATUS in row else None
698
698
  )
699
699
 
700
700
  def _row_to_interim_response(self, row: Row) -> InterimResponse:
@@ -817,18 +817,20 @@ class ComponentRunsDAO(ExecutionMetricsDAO):
817
817
  """Convert Row exception to StoredSerializableException."""
818
818
  return StoredSerializableException(
819
819
  exception_type=exception_row[EXCEPTION_TYPE],
820
- msg=exception_row[MSG],
821
- cause_msg=exception_row[CAUSE_MSG],
820
+ message=exception_row[MSG],
821
+ cause_message=exception_row[CAUSE_MSG],
822
822
  stack_trace=exception_row[STACK_TRACE],
823
823
  time=exception_row[TIME],
824
824
  )
825
825
 
826
826
  def _convert_exception_to_row(self, exception: StoredSerializableException) -> Row:
827
827
  """Convert StoredSerializableException to Row."""
828
- return Row(
829
- exception_type=exception.exception_type,
830
- msg=exception.msg,
831
- cause_msg=exception.cause_msg,
832
- stack_trace=exception.stack_trace,
833
- time=exception.time,
834
- )
828
+ row_data = {
829
+ EXCEPTION_TYPE: exception.exception_type,
830
+ MSG: exception.message,
831
+ CAUSE_MSG: exception.cause_message,
832
+ STACK_TRACE: exception.stack_trace,
833
+ TIME: exception.time,
834
+ }
835
+
836
+ return Row(**row_data)
@@ -104,7 +104,7 @@ def base_location(spark: SparkSession, suffix: str) -> str:
104
104
  spark_delta_path_prefix = "spark.prophecy.delta.path.prefix"
105
105
  default_path = "/prophecy/metadata/executionmetrics"
106
106
  try:
107
- base_path = spark.conf.get(spark_delta_path_prefix)
107
+ base_path = spark.conf.get(spark_delta_path_prefix, default_path)
108
108
  except Exception as e:
109
109
  base_path = default_path
110
110
  return f"{base_path}{suffix}"
@@ -45,70 +45,16 @@ from prophecy.executionmetrics.evolutions.metrics_storage_initializer import (
45
45
  StorageMetadata,
46
46
  create_storage_metadata,
47
47
  )
48
- from prophecy.executionmetrics.utils.common import is_databricks_environment
48
+ from prophecy.executionmetrics.utils.common import is_databricks_environment, now_millis
49
49
  from prophecy.executionmetrics.utils.external import compress
50
-
51
-
52
- class HasProcessesConnectionsPorts(ABC):
53
- """Interface for objects with processes, connections and ports."""
54
-
55
- pass
56
-
57
-
58
- @dataclass
59
- class WorkflowNode:
60
- """Workflow node representation."""
61
-
62
- id: str
63
- component: str
64
- metadata: Dict[str, Any]
65
- ports: Dict[str, Any]
66
- properties: Dict[str, Any] = field(default_factory=dict)
67
-
68
-
69
- @dataclass
70
- class WorkflowEdge:
71
- """Workflow edge representation."""
72
-
73
- source: str
74
- source_port: str
75
- target: str
76
- target_port: str
77
-
78
-
79
- @dataclass
80
- class WorkflowGroup(WorkflowNode, HasProcessesConnectionsPorts):
81
- """Workflow group node."""
82
-
83
- processes: Dict[str, "WorkflowNode"] = field(default_factory=dict)
84
- connections: List["WorkflowEdge"] = field(default_factory=list)
85
-
86
-
87
- @dataclass
88
- class WorkflowGraph(HasProcessesConnectionsPorts):
89
- """Workflow graph representation."""
90
-
91
- processes: Dict[str, WorkflowNode]
92
- connections: List[WorkflowEdge]
93
- ports: Dict[str, Any] = field(default_factory=dict)
94
-
95
-
96
- def get_workflow_graph(code: Optional[Dict[str, str]]) -> Optional[WorkflowGraph]:
97
- """Extract workflow graph from code dictionary."""
98
- if not code:
99
- return None
100
-
101
- workflow_content = None
102
- for path, content in code.items():
103
- if path.endswith(".prophecy/workflow.latest.json"):
104
- workflow_content = content
105
- break
106
-
107
- if workflow_content:
108
- data = json.loads(workflow_content)
109
- return _parse_workflow_graph(data)
110
-
111
- return None
50
+ from prophecy.executionmetrics.workflow_parser import (
51
+ HasProcessesConnectionsPorts,
52
+ WorkflowEdge,
53
+ WorkflowGraph,
54
+ WorkflowGroup,
55
+ WorkflowNode,
56
+ get_workflow_graph,
57
+ )
112
58
 
113
59
 
114
60
  def get_slug_to_process_map(code: Optional[Dict[str, str]]) -> Optional[Dict[str, str]]:
@@ -134,61 +80,15 @@ def extract_slug_to_process_mapping(
134
80
  slug_to_process[current_slug] = node.id
135
81
 
136
82
  if isinstance(node, WorkflowGroup):
137
- for process_id, child_node in node.processes.items():
83
+ for _, child_node in node.processes.items():
138
84
  extract_from_node(child_node, current_slug)
139
85
 
140
- for process_id, node in processes.items():
86
+ for _, node in processes.items():
141
87
  extract_from_node(node)
142
88
 
143
89
  return slug_to_process
144
90
 
145
91
 
146
- def _parse_workflow_nodes(data: Dict[str, Any]) -> Dict[str, "WorkflowNode"]:
147
- processes = {}
148
- for proc_id, proc_data in data.get("processes", {}).items():
149
- if proc_data.get("component") == "Subgraph":
150
- node = WorkflowGroup(
151
- id=proc_id,
152
- component=proc_data.get("component"),
153
- metadata=proc_data.get("metadata", {}),
154
- ports=proc_data.get("ports", {}),
155
- properties=proc_data.get("properties", {}),
156
- processes=_parse_workflow_nodes(proc_data),
157
- connections=proc_data.get("connections", []),
158
- )
159
- else:
160
- node = WorkflowNode(
161
- id=proc_id,
162
- component=proc_data.get("component"),
163
- metadata=proc_data.get("metadata", {}),
164
- ports=proc_data.get("ports", {}),
165
- properties=proc_data.get("properties", {}),
166
- )
167
- processes[proc_id] = node
168
-
169
- return processes
170
-
171
-
172
- def _parse_workflow_graph(data: Dict[str, Any]) -> WorkflowGraph:
173
- """Parse workflow graph from dictionary."""
174
- processes = _parse_workflow_nodes(data)
175
-
176
- connections = []
177
- for conn_data in data.get("connections", []):
178
- connections.append(
179
- WorkflowEdge(
180
- source=conn_data["source"],
181
- source_port=conn_data["sourcePort"],
182
- target=conn_data["target"],
183
- target_port=conn_data["targetPort"],
184
- )
185
- )
186
-
187
- return WorkflowGraph(
188
- processes=processes, connections=connections, ports=data.get("ports", {})
189
- )
190
-
191
-
192
92
  class InMemoryStore:
193
93
  """
194
94
  In-memory store for pipeline execution metrics.
@@ -215,6 +115,7 @@ class InMemoryStore:
215
115
  self._status: str = PipelineStatus.STARTED
216
116
  self._fabric_uid: str = ""
217
117
  self._time_taken: Optional[int] = None
118
+ self._time_started: int = now_millis()
218
119
  self._rows_read: Optional[int] = None
219
120
  self._rows_written: Optional[int] = None
220
121
  self._run_type: str = ""
@@ -282,6 +183,7 @@ class InMemoryStore:
282
183
  )
283
184
 
284
185
  # Set pipeline execution state
186
+ self._time_started = now_millis()
285
187
  self._pipeline_uri = pipeline_uri
286
188
  self._job_uri = job_uri
287
189
  self._fabric_uid = fabric_uid
@@ -411,59 +313,208 @@ class InMemoryStore:
411
313
  collect_processes(graph.processes)
412
314
  return all_procs
413
315
 
316
+ def _all_connections(self) -> List[WorkflowEdge]:
317
+ graph = self._graph
318
+ all_conns = []
319
+ if not graph:
320
+ return all_conns
321
+
322
+ def collect_connections(
323
+ connections: List[WorkflowEdge], processes: Dict[str, WorkflowNode]
324
+ ):
325
+ all_conns.extend(connections)
326
+ # Check for subgraphs and collect their connections
327
+ for node in processes.values():
328
+ if isinstance(node, WorkflowGroup):
329
+ collect_connections(node.connections, node.processes)
330
+
331
+ collect_connections(graph.connections, graph.processes)
332
+ return all_conns
333
+
414
334
  def _extract_process_to_gem_map(self) -> Dict[str, GemProgress]:
415
335
  """Extract mapping from process ID to GemProgress."""
416
- if not self._graph or not self._processes:
336
+ graph = self._graph
337
+ processes = self._processes
338
+ if graph is None or processes is None:
417
339
  return {}
418
340
 
419
- process_to_gem = {}
420
-
421
- for proc_id, node in self._processes.items():
422
- # Extract gem information from node
423
- gem_name = node.metadata.get("slug", "")
424
- gem_type = node.component
425
-
426
- # Extract ports
427
- in_ports = [p["id"] for p in node.ports.get("inputs", [])]
428
- out_ports = [p["id"] for p in node.ports.get("outputs", [])]
429
-
430
- # Create input/output gem edges based on connections
431
- input_gems = []
432
- output_gems = []
433
-
434
- for edge in self._graph.connections:
435
- if edge.target == proc_id:
436
- source_node = self._processes.get(edge.source)
437
- if source_node:
438
- input_gems.append(
439
- GemEdge(
440
- gem_name=source_node.metadata.get("slug"),
441
- from_port=edge.source_port,
442
- to_port=edge.target_port,
341
+ slug_to_process_map = extract_slug_to_process_mapping(graph.processes)
342
+ process_to_slug_map = {v: k for k, v in slug_to_process_map.items()}
343
+
344
+ connections = self._all_connections()
345
+ target_port_to_connection_map = {c.target_port: c for c in connections}
346
+
347
+ # Group connections by source port
348
+ source_port_to_connection_multi_map: Dict[str, List[WorkflowEdge]] = {}
349
+ for conn in connections:
350
+ if conn.source_port not in source_port_to_connection_multi_map:
351
+ source_port_to_connection_multi_map[conn.source_port] = []
352
+ source_port_to_connection_multi_map[conn.source_port].append(conn)
353
+
354
+ def fetch_output_details(out_port: str) -> List[Tuple[str, str]]:
355
+ """
356
+ Fetch output details for a given output port.
357
+
358
+ Args:
359
+ out_port: The output port ID
360
+
361
+ Returns:
362
+ List of tuples (target process ID, target port ID)
363
+ """
364
+ connections_list = source_port_to_connection_multi_map.get(out_port, [])
365
+ target_connection_to_node = {
366
+ c: processes.get(c.target) for c in connections_list
367
+ }
368
+
369
+ result = []
370
+ for connection, node in target_connection_to_node.items():
371
+ if node and node.component == "Subgraph":
372
+ # Recursively fetch output details for subgraph
373
+ result.extend(fetch_output_details(connection.target_port))
374
+ elif node:
375
+ result.append((connection.target, connection.target_port))
376
+
377
+ return result
378
+
379
+ def fetch_input_details(in_port: str) -> Tuple[Optional[str], Optional[str]]:
380
+ """
381
+ Fetch input details for a given input port.
382
+
383
+ Args:
384
+ in_port: The input port ID
385
+
386
+ Returns:
387
+ Tuple of (source process ID, source port ID)
388
+ """
389
+ connection = target_port_to_connection_map.get(in_port)
390
+ if not connection:
391
+ return (None, None)
392
+
393
+ source_node = processes.get(connection.source)
394
+ if source_node and source_node.component == "Subgraph":
395
+ # Recursively fetch input details for subgraph
396
+ return fetch_input_details(connection.source_port)
397
+ else:
398
+ return (
399
+ connection.source if connection else None,
400
+ connection.source_port if connection else None,
401
+ )
402
+
403
+ def extract_process_to_gem_map_inner() -> Dict[str, GemProgress]:
404
+ """
405
+ Internal function to extract process to gem mapping.
406
+
407
+ Returns:
408
+ List of tuples (process ID, GemProgress)
409
+ """
410
+ result = {}
411
+
412
+ for process_id, current_process in processes.items():
413
+ gem_name = process_to_slug_map.get(
414
+ current_process.id
415
+ ) or current_process.metadata.get("slug", "")
416
+
417
+ out_ports = [port.slug for port in current_process.ports.outputs]
418
+ in_ports = [port.slug for port in current_process.ports.inputs]
419
+
420
+ # Get input process details
421
+ input_process_details = []
422
+ for current_process_in_port in current_process.ports.inputs:
423
+ input_process, source_port_id = fetch_input_details(
424
+ current_process_in_port.id
425
+ )
426
+ input_process_details.append(
427
+ (input_process, source_port_id, current_process_in_port.slug)
428
+ )
429
+
430
+ # Get output process details
431
+ output_process_details = []
432
+ for current_process_out_port in current_process.ports.outputs:
433
+ output_details = fetch_output_details(current_process_out_port.id)
434
+ for output_process, target_port_id in output_details:
435
+ output_process_details.append(
436
+ (
437
+ output_process,
438
+ current_process_out_port.slug,
439
+ target_port_id,
443
440
  )
444
441
  )
445
- elif edge.source == proc_id:
446
- target_node = self._processes.get(edge.target)
447
- if target_node:
448
- output_gems.append(
449
- GemEdge(
450
- gem_name=target_node.metadata.get("slug"),
451
- from_port=edge.source_port,
452
- to_port=edge.target_port,
453
- )
442
+
443
+ # Create input gem edges
444
+ input_gem_edges = []
445
+ for (
446
+ process_id_opt,
447
+ from_port_id_opt,
448
+ to_port_slug,
449
+ ) in input_process_details:
450
+ gem_name_opt = (
451
+ process_to_slug_map.get(process_id_opt)
452
+ if process_id_opt
453
+ else None
454
+ )
455
+ input_process = (
456
+ processes.get(process_id_opt) if process_id_opt else None
457
+ )
458
+
459
+ from_port_slug = None
460
+ if from_port_id_opt and input_process:
461
+ for port in input_process.ports.outputs:
462
+ if port.id == from_port_id_opt:
463
+ from_port_slug = port.slug
464
+ break
465
+
466
+ input_gem_edges.append(
467
+ GemEdge(
468
+ gem_name=gem_name_opt,
469
+ from_port=from_port_slug,
470
+ to_port=to_port_slug,
471
+ )
472
+ )
473
+
474
+ # Create output gem edges
475
+ output_gem_edges = []
476
+ for process_id, from_port_slug, to_port_id in output_process_details:
477
+ gem_name_opt = process_to_slug_map.get(process_id)
478
+ output_process = processes.get(process_id)
479
+
480
+ to_port_slug = None
481
+ if output_process:
482
+ for port in output_process.ports.inputs:
483
+ if port.id == to_port_id:
484
+ to_port_slug = port.slug
485
+ break
486
+
487
+ output_gem_edges.append(
488
+ GemEdge(
489
+ gem_name=gem_name_opt,
490
+ from_port=from_port_slug,
491
+ to_port=to_port_slug,
454
492
  )
493
+ )
455
494
 
456
- process_to_gem[proc_id] = GemProgress(
457
- gem_name=gem_name,
458
- process_id=proc_id,
459
- gem_type=gem_type,
460
- input_gems=input_gems,
461
- output_gems=output_gems,
462
- in_ports=in_ports,
463
- out_ports=out_ports,
464
- )
495
+ # Create GemProgress
496
+ gem_progress = GemProgress(
497
+ gem_name=gem_name,
498
+ process_id=current_process.id,
499
+ gem_type=current_process.component,
500
+ input_gems=input_gem_edges,
501
+ output_gems=output_gem_edges,
502
+ in_ports=in_ports,
503
+ out_ports=out_ports,
504
+ num_rows_output=None,
505
+ stdout=None,
506
+ stderr=None,
507
+ start_time=None,
508
+ end_time=None,
509
+ state=None,
510
+ exception=None,
511
+ )
465
512
 
466
- return process_to_gem
513
+ result[current_process.id] = gem_progress
514
+
515
+ return result
516
+
517
+ return extract_process_to_gem_map_inner()
467
518
 
468
519
  def update_run_uid(self, job_run_uid: str, task_run_uid: str) -> None:
469
520
  """Update job and task run UIDs."""
@@ -516,8 +567,8 @@ class InMemoryStore:
516
567
  def update_gem_progress(
517
568
  self,
518
569
  process: str,
519
- start_time: int,
520
- end_time: Optional[int],
570
+ start_time: str,
571
+ end_time: Optional[str],
521
572
  stdout: Optional[List[TimestampedOutput]],
522
573
  stderr: Optional[List[TimestampedOutput]],
523
574
  state: str,
@@ -530,13 +581,15 @@ class InMemoryStore:
530
581
 
531
582
  if process in self._process_to_gem_map:
532
583
  gem_progress = self._process_to_gem_map[process]
533
- # Update gem progress fields
534
- gem_progress.start_time = start_time
535
- gem_progress.end_time = end_time
536
- gem_progress.stdout = stdout
537
- gem_progress.stderr = stderr
538
- gem_progress.state = state
539
- gem_progress.exception = exception
584
+ updated_gem_progress = gem_progress.update_progress(
585
+ start_time=int(start_time),
586
+ end_time=int(end_time) if end_time else None,
587
+ stdout=stdout,
588
+ stderr=stderr,
589
+ state=state,
590
+ exception=exception,
591
+ )
592
+ self._process_to_gem_map[process] = updated_gem_progress
540
593
 
541
594
  def _update_connecting_gem_rows(
542
595
  self, interim_process: str, interim: LInterimContent
@@ -609,7 +662,9 @@ class InMemoryStore:
609
662
  gem.num_rows = num_records
610
663
 
611
664
  def offload(
612
- self, interim_details: List[Tuple[InterimKey, DataFrame]] = None
665
+ self,
666
+ pipeline_status: str,
667
+ interim_details: List[Tuple[InterimKey, DataFrame]] = None,
613
668
  ) -> Tuple[List["ComponentRuns"], List[str]]:
614
669
  """
615
670
  Offload metrics to persistent storage.
@@ -718,10 +773,10 @@ class InMemoryStore:
718
773
  job_uri=self._job_uri,
719
774
  job_run_uid=self._job_run_uid,
720
775
  task_run_uid=self._task_run_uid,
721
- status=self._status,
776
+ status=pipeline_status,
722
777
  submission_time=self._submission_time,
723
778
  fabric_uid=self._fabric_uid,
724
- time_taken=self._time_taken,
779
+ time_taken=now_millis() - self._time_started,
725
780
  rows_read=self._rows_read,
726
781
  rows_written=self._rows_written,
727
782
  run_type=self._run_type,
@@ -783,7 +838,7 @@ class InMemoryStore:
783
838
  component_name = node.metadata.get("slug", "")
784
839
  component_type = node.component
785
840
 
786
- interim_ports = [p["id"] for p in node.ports.get("outputs", [])]
841
+ interim_ports = [p.id for p in node.ports.outputs]
787
842
  gem_progress = (
788
843
  self._process_to_gem_map.get(process_id)
789
844
  if self._process_to_gem_map
@@ -832,11 +887,11 @@ class InMemoryStore:
832
887
  # Default interim details
833
888
  interim_subgraph = subgraph_name
834
889
  interim_node = node
835
- interim_ports = [p["id"] for p in node.ports.get("outputs", [])]
890
+ interim_ports = [p.id for p in node.ports.outputs]
836
891
 
837
892
  # Special handling for Target nodes
838
- if component_type == "Target" and node.ports.get("inputs"):
839
- first_input_port = node.ports["inputs"][0]["id"]
893
+ if component_type == "Target" and node.ports.inputs:
894
+ first_input_port = node.ports.inputs[0].id
840
895
  connection, parent_graph, target_subgraph = (
841
896
  self._fetch_target_component_source_port(
842
897
  target_port_connection_map,
@@ -316,6 +316,34 @@ class ComponentRunsWithStatus(ExecutionMetricsEntity):
316
316
  "branch": self.branch,
317
317
  }
318
318
 
319
+ @classmethod
320
+ def from_component_runs(
321
+ cls, component_run: ComponentRuns, status: Optional[str]
322
+ ) -> "ComponentRunsWithStatus":
323
+ return ComponentRunsWithStatus(
324
+ uid=component_run.uid,
325
+ component_uri=component_run.component_uri,
326
+ pipeline_run_uid=component_run.pipeline_run_uid,
327
+ pipeline_uri=component_run.pipeline_uri,
328
+ fabric_uid=component_run.fabric_uid,
329
+ component_name=component_run.component_name,
330
+ interim_component_name=component_run.interim_component_name,
331
+ component_type=component_run.component_type,
332
+ interim_out_port=component_run.interim_out_port,
333
+ interim_subgraph_name=component_run.interim_subgraph_name,
334
+ interim_process_id=component_run.interim_process_id,
335
+ created_by=component_run.created_by,
336
+ records=component_run.records,
337
+ bytes=component_run.bytes,
338
+ partitions=component_run.partitions,
339
+ created_at=component_run.created_at,
340
+ expired=component_run.expired,
341
+ status=status, # This will be set separately
342
+ job_uri=component_run.job_uri,
343
+ run_type=component_run.run_type,
344
+ branch=component_run.branch,
345
+ )
346
+
319
347
 
320
348
  @dataclass
321
349
  class ComponentRunsWithStatusAndInterims(ExecutionMetricsEntity):