prophecy-libs 2.0.6.dev99__tar.gz → 2.0.8.dev0__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 (140) hide show
  1. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/PKG-INFO +1 -1
  2. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/config/config_base.py +202 -4
  3. prophecy-libs-2.0.8.dev0/prophecy/config/utils.py +624 -0
  4. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy_libs.egg-info/PKG-INFO +1 -1
  5. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy_libs.egg-info/SOURCES.txt +0 -1
  6. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/setup.py +1 -1
  7. prophecy-libs-2.0.6.dev99/prophecy/config/config_base_test.py +0 -321
  8. prophecy-libs-2.0.6.dev99/prophecy/config/utils.py +0 -114
  9. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/README.md +0 -0
  10. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/__init__.py +0 -0
  11. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/config/__init__.py +0 -0
  12. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/dbxsless/__init__.py +0 -0
  13. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/dbxsless/dbx_serverless_helper.py +0 -0
  14. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/__init__.py +0 -0
  15. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/componentruns/__init__.py +0 -0
  16. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/componentruns/component_run_service.py +0 -0
  17. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/componentruns/component_runs_dao.py +0 -0
  18. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/evolutions/__init__.py +0 -0
  19. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/evolutions/delta_metrics_storage_initializer.py +0 -0
  20. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/evolutions/hive_parquet_storage_initializer.py +0 -0
  21. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/evolutions/metrics_storage_initializer.py +0 -0
  22. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/evolutions/models.py +0 -0
  23. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/evolutions/package.py +0 -0
  24. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/execution_metrics_handler.py +0 -0
  25. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/in_memory_store.py +0 -0
  26. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/interims/__init__.py +0 -0
  27. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/interims/delta_interims.py +0 -0
  28. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/interims/hive_parquet_interims.py +0 -0
  29. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/interims/interims_table.py +0 -0
  30. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/logging_spark_session.py +0 -0
  31. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/models.py +0 -0
  32. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/package.py +0 -0
  33. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/pipelineruns/__init__.py +0 -0
  34. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/pipelineruns/pipeline_run_service.py +0 -0
  35. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/pipelineruns/pipeline_runs_dao.py +0 -0
  36. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/schemas/__init__.py +0 -0
  37. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/schemas/em.py +0 -0
  38. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/schemas/external.py +0 -0
  39. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/utils/__init__.py +0 -0
  40. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/utils/common.py +0 -0
  41. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/utils/constants.py +0 -0
  42. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/utils/external.py +0 -0
  43. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/utils/interim_store.py +0 -0
  44. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/workflow_parser.py +0 -0
  45. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/executionmetrics/zip_file.py +0 -0
  46. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/jsonrpc/__init__.py +0 -0
  47. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/jsonrpc/models.py +0 -0
  48. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/libs/__init__.py +0 -0
  49. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/libs/uc_shared_utils.py +0 -0
  50. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/libs/utils.py +0 -0
  51. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/lookups/LookupsBase.py +0 -0
  52. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/lookups/LookupsNative.py +0 -0
  53. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/lookups/__init__.py +0 -0
  54. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/random_data_creator.py +0 -0
  55. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/streaming/__init__.py +0 -0
  56. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/streaming/delta_lake_utils.py +0 -0
  57. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/test/__init__.py +0 -0
  58. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/test/base_test_case.py +0 -0
  59. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/test/utils.py +0 -0
  60. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/udfs/__init__.py +0 -0
  61. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/udfs/rest_api_udf.py +0 -0
  62. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/udfs/sample_udf.py +0 -0
  63. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/udfs/scala_udf_wrapper.py +0 -0
  64. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/__init__.py +0 -0
  65. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/constants.py +0 -0
  66. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/data_profiler.py +0 -0
  67. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/datasampleloader.py +0 -0
  68. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/diff.py +0 -0
  69. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/dill/__diff.py +0 -0
  70. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/dill/__init__.py +0 -0
  71. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/dill/_dill.py +0 -0
  72. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/dill/_objects.py +0 -0
  73. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/dill/_shims.py +0 -0
  74. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/dill/detect.py +0 -0
  75. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/dill/logger.py +0 -0
  76. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/dill/objtypes.py +0 -0
  77. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/dill/pointers.py +0 -0
  78. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/dill/session.py +0 -0
  79. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/dill/settings.py +0 -0
  80. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/dill/source.py +0 -0
  81. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/dill/temp.py +0 -0
  82. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/__init__.py +0 -0
  83. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/__main__.py +0 -0
  84. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/cli.py +0 -0
  85. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/config.py +0 -0
  86. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/custom_typing.py +0 -0
  87. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/decode/__init__.py +0 -0
  88. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/decode/codes.py +0 -0
  89. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/documentor.py +0 -0
  90. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/exceptions.py +0 -0
  91. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/factory.py +0 -0
  92. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/generator.py +0 -0
  93. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/__init__.py +0 -0
  94. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/address/__init__.py +0 -0
  95. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/address/en/__init__.py +0 -0
  96. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/address/en_US/__init__.py +0 -0
  97. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/date_time/__init__.py +0 -0
  98. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/date_time/en_US/__init__.py +0 -0
  99. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/internet/__init__.py +0 -0
  100. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/internet/en_US/__init__.py +0 -0
  101. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/misc/__init__.py +0 -0
  102. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/misc/en_US/__init__.py +0 -0
  103. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/person/__init__.py +0 -0
  104. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/person/en_US/__init__.py +0 -0
  105. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/phone_number/__init__.py +0 -0
  106. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/phone_number/en_US/__init__.py +0 -0
  107. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/python/__init__.py +0 -0
  108. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/providers/python/en_US/__init__.py +0 -0
  109. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/proxy.py +0 -0
  110. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/utils/__init__.py +0 -0
  111. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/utils/checksums.py +0 -0
  112. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/utils/datasets.py +0 -0
  113. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/utils/decorators.py +0 -0
  114. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/utils/distribution.py +0 -0
  115. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/utils/loading.py +0 -0
  116. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/faker/utils/text.py +0 -0
  117. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/functions.py +0 -0
  118. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/gems_utils.py +0 -0
  119. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/httpclient.py +0 -0
  120. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/initial_python_code.py +0 -0
  121. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/json_rpc_layer.py +0 -0
  122. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/metagem_utils.py +0 -0
  123. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/monitoring_utils.py +0 -0
  124. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/pipeline_monitoring.py +0 -0
  125. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/request_processor.py +0 -0
  126. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/secrets.py +0 -0
  127. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/synthetic_data_generator.py +0 -0
  128. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/transpiler/__init__.py +0 -0
  129. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/transpiler/abi_base.py +0 -0
  130. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/transpiler/abi_core_fcns.py +0 -0
  131. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/transpiler/abi_fcn_wrapper.py +0 -0
  132. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/transpiler/dataframe_fcns.py +0 -0
  133. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/transpiler/dml_schema.py +0 -0
  134. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/transpiler/fixed_file_schema.py +0 -0
  135. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy/utils/utils.py +0 -0
  136. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy_libs.egg-info/dependency_links.txt +0 -0
  137. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy_libs.egg-info/not-zip-safe +0 -0
  138. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy_libs.egg-info/requires.txt +0 -0
  139. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/prophecy_libs.egg-info/top_level.txt +0 -0
  140. {prophecy-libs-2.0.6.dev99 → prophecy-libs-2.0.8.dev0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: prophecy-libs
3
- Version: 2.0.6.dev99
3
+ Version: 2.0.8.dev0
4
4
  Summary: Helper library for prophecy generated code
5
5
  Home-page: https://github.com/SimpleDataLabsInc/prophecy-python-libs
6
6
  Author: UNKNOWN
@@ -1,4 +1,5 @@
1
1
  # WARNING - Do not add import * in this module
2
+ from pyhocon import ConfigFactory, ConfigTree
2
3
  from pyspark import Row
3
4
  from pyspark.sql import SparkSession
4
5
  from functools import lru_cache
@@ -6,11 +7,68 @@ from datetime import datetime, date
6
7
  import os
7
8
  import logging
8
9
 
10
+ from prophecy.config.utils import ConfigurationRecord
11
+
9
12
  logger = logging.getLogger(__name__)
10
13
 
11
14
  is_serverless = bool(int(os.environ.get("DATABRICKS_SERVERLESS_MODE_ENABLED", "0")))
12
15
  logger.info(f'is_serverless is {is_serverless}')
13
16
 
17
+
18
+ class ProjectConfig:
19
+
20
+ @staticmethod
21
+ def get_merged_values(base_values, overridden_values):
22
+ def to_plain_dict(obj):
23
+ if isinstance(obj, dict):
24
+ return {k: to_plain_dict(v) for k, v in obj.items()}
25
+ elif isinstance(obj, list):
26
+ return [to_plain_dict(i) for i in obj]
27
+ else:
28
+ return obj
29
+ conf1 = ConfigFactory.from_dict(base_values)
30
+ conf2 = ConfigFactory.from_dict(overridden_values)
31
+
32
+ # Merge using pyhocon's built-in merge
33
+ return to_plain_dict(ConfigTree.merge_configs(conf1, conf2).as_plain_ordered_dict())
34
+
35
+ @staticmethod
36
+ def get_resolved_project_config_values(project_config_values, overridden_values):
37
+ merged_values = ProjectConfig.get_merged_values(project_config_values, overridden_values)
38
+ # Override with pipeline config values for fields that are present in config_values
39
+ for field_name, field_value in merged_values.items():
40
+ if field_name not in project_config_values:
41
+ # Delete those fields which are not in project config
42
+ del merged_values[field_name]
43
+ return merged_values
44
+
45
+ def __init__(self, config_schema: ConfigurationRecord, config_values: dict):
46
+ """
47
+ :param config_schema: The schema.json of ProjectConfig variables.
48
+ :param config_values: The final values as a dictionary. Same as <instance>.json.
49
+ """
50
+ self.config_schema = config_schema
51
+ self.config_values = config_values
52
+
53
+ def with_pipeline_overrides(self, overridden_values: dict):
54
+ self.config_values = self.get_resolved_values(overridden_values)
55
+ return self
56
+
57
+ def get_resolved_values(self, overridden_values: dict):
58
+ """
59
+ Resolve project configuration values by overriding project config values with pipeline config values
60
+ for fields that are present in config_values.
61
+
62
+ Args:
63
+ overridden_values: The project config values (project config)
64
+
65
+ Returns:
66
+ dict: Resolved configuration values where pipeline config overrides project config
67
+ for fields present in config_values, but project config values are kept
68
+ for fields not present in config_values
69
+ """
70
+ return ProjectConfig.get_resolved_project_config_values(self.config_values, overridden_values)
71
+
14
72
  class ConfigBase:
15
73
 
16
74
  class SecretValue:
@@ -195,11 +253,15 @@ class ConfigBase:
195
253
  else:
196
254
  return self.generate_object(override, cls)
197
255
 
198
- def generate_config_object(self, spark, value, cls):
256
+ def generate_config_object(self, spark, value, cls, project_config: ProjectConfig=None):
257
+ # `project_config` will only be passed for subgraphs. It won't be passed for normal records.
199
258
  if isinstance(value, list):
200
259
  return [self.generate_config_object(spark, x, cls) for x in value]
201
260
  elif isinstance(value, dict):
202
- return cls(**{**{"prophecy_spark": spark}, **value})
261
+ # No need to worry whether the generated code of the pipeline has the `prophecy_project_config` argument
262
+ # mentioned or not. **kwargs is present in all the calls class's __init__ methods. This will prevent throwing
263
+ # any exception.
264
+ return cls(**{**{"prophecy_spark": spark, "prophecy_project_config": project_config}, **value})
203
265
  return value
204
266
 
205
267
  def get_secret_config_object(self, spark, default, override, cls):
@@ -210,11 +272,12 @@ class ConfigBase:
210
272
  else:
211
273
  return self.get_config_object(spark, default, override, cls)
212
274
 
213
- def get_config_object(self, spark, default, override, cls):
275
+ def get_config_object(self, spark, default, override, cls, project_config: ProjectConfig=None):
276
+ # project_config will only be passed for Subgraphs. Won't be passed for normal records
214
277
  if override == None:
215
278
  return default
216
279
  else:
217
- return self.generate_config_object(spark, override, cls)
280
+ return self.generate_config_object(spark, override, cls, project_config)
218
281
 
219
282
  def to_dict(self):
220
283
  to_ignore = ["spark", "prophecy_spark", "jvm", "secret_manager"]
@@ -318,3 +381,138 @@ class ConfigBase:
318
381
  else:
319
382
  setattr(result, k, copy.deepcopy(v, memo))
320
383
  return result
384
+
385
+ def add_config_fields(self, config_record, config_values: dict):
386
+ """
387
+ Add configuration fields to this ConfigBase instance based on a ConfigurationRecord
388
+ and a dictionary of key-value pairs.
389
+
390
+ Args:
391
+ config_record: ConfigurationRecord object defining the schema
392
+ config_values: Dictionary with field names as keys and their values
393
+ """
394
+ from prophecy.config.utils import (
395
+ StringElement, IntElement, LongElement, ShortElement,
396
+ FloatElement, DoubleElement, BooleanElement, DateElement,
397
+ TimestampElement, ArrayElement, ConfigurationRecord, SecretElement,
398
+ EnumElement, LookupElement, ValueElement, TableNameElement,
399
+ ColumnNameElement, SparkColumnElement, SparkExpressionElement
400
+ )
401
+
402
+ def convert_value(value, data_element):
403
+ """Convert a value based on the DataElement type."""
404
+ element_type = data_element.get_name()
405
+
406
+ if element_type == "string":
407
+ return str(value) if value is not None else None
408
+ elif element_type == "spark_column":
409
+ return str(value) if value is not None else None
410
+ elif element_type == "spark_expression":
411
+ return str(value) if value is not None else None
412
+ elif element_type == "int":
413
+ return self.get_int_value(value)
414
+ elif element_type == "long":
415
+ return self.get_int_value(value) # Python doesn't distinguish int/long
416
+ elif element_type == "short":
417
+ return self.get_int_value(value) # Python doesn't distinguish int/short
418
+ elif element_type == "float":
419
+ return self.get_float_value(value)
420
+ elif element_type == "double":
421
+ return self.get_float_value(value) # Python doesn't distinguish float/double
422
+ elif element_type == "boolean":
423
+ return self.get_bool_value(value)
424
+ elif element_type == "date":
425
+ return self.get_date_value(value)
426
+ elif element_type == "timestamp":
427
+ return self.get_timestamp_value(value)
428
+ elif element_type == "array":
429
+ if isinstance(value, list):
430
+ return [convert_value(item, data_element.element_type) for item in value]
431
+ else:
432
+ return value
433
+ elif element_type == "record":
434
+ if isinstance(value, dict):
435
+ # Create a nested ConfigBase instance for record types
436
+ nested_config = type('NestedConfig', (ConfigBase,), {})()
437
+ nested_config.add_config_fields(data_element, value)
438
+ return nested_config
439
+ else:
440
+ return value
441
+ elif element_type == "enum":
442
+ # For enum, validate that the value is in the allowed values
443
+ if value in data_element.values:
444
+ return value
445
+ else:
446
+ raise ValueError(f"Value '{value}' is not in allowed enum values: {data_element.values}")
447
+ elif element_type == "secret":
448
+ # For secrets, create a SecretValue instance
449
+ if isinstance(value, dict):
450
+ return self.SecretValue(**value)
451
+ else:
452
+ return value
453
+ else:
454
+ # For unknown types, return as-is
455
+ return value
456
+
457
+ def process_fields(fields, values_dict):
458
+ """Process configuration fields recursively."""
459
+ for field in fields:
460
+ field_name = field.name
461
+ field_kind = field.kind
462
+
463
+ # Skip if field is not in the provided values and is optional
464
+ if field_name not in values_dict:
465
+ if field.optional:
466
+ continue
467
+ else:
468
+ raise ValueError(f"Required field '{field_name}' is missing from config values")
469
+
470
+ field_value = values_dict[field_name]
471
+
472
+ # Convert the value based on the field type
473
+ converted_value = convert_value(field_value, field_kind)
474
+
475
+ # Set the field on this ConfigBase instance
476
+ setattr(self, field_name, converted_value)
477
+
478
+ # Process the configuration record fields
479
+ if hasattr(config_record, 'fields'):
480
+ process_fields(config_record.fields, config_values)
481
+ else:
482
+ raise ValueError("ConfigurationRecord must have a 'fields' attribute")
483
+
484
+ def add_project_config(self, project_config: ProjectConfig, overridden_values: dict):
485
+ self.prophecy_project_config = project_config
486
+ if project_config is not None and hasattr(self, 'add_config_fields'):
487
+ # Merge project_config.config_values with overridden_values
488
+ # Start with project config values
489
+ merged_values = ProjectConfig.get_resolved_project_config_values(project_config.config_values, overridden_values)
490
+ # Call add_config_fields with the merged values
491
+ self.add_config_fields(project_config.config_schema, merged_values)
492
+
493
+ def add_project_config(self, overridden_values: dict):
494
+ # Assumption here is that the `prophecy_project_config` is already part of the class variable.
495
+ self.add_project_config(self.prophecy_project_config, overridden_values)
496
+
497
+ def update_project_conf_values(self, project_config: ProjectConfig, overridden_values):
498
+ if project_config is None:
499
+ return None
500
+ return project_config.with_pipeline_overrides(overridden_values)
501
+
502
+ def update_and_add_project_config(self, project_config: ProjectConfig=None, overridden_values: dict=None):
503
+ """
504
+ This will merge the overridden values with the project config values and then assign the new values along with
505
+ schema to `prophecy_project_config`.
506
+ :param project_config:
507
+ :param overridden_values:
508
+ :return:
509
+ """
510
+ self.prophecy_project_config = project_config
511
+ if project_config is not None:
512
+ if overridden_values is None:
513
+ self.add_config_fields(project_config.config_schema, config_values=project_config.config_values)
514
+ else:
515
+ # Merge project_config.config_values with overridden_values
516
+ # Start with project config values
517
+ merged_values = ProjectConfig.get_resolved_project_config_values(project_config.config_values, overridden_values)
518
+ self.add_config_fields(project_config.config_schema, merged_values)