fabricks 3.0.19__py3-none-any.whl → 4.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. fabricks/api/context.py +15 -3
  2. fabricks/api/notebooks/schedule.py +2 -3
  3. fabricks/api/parsers.py +2 -1
  4. fabricks/api/utils.py +3 -1
  5. fabricks/cdc/__init__.py +1 -2
  6. fabricks/cdc/base/__init__.py +1 -2
  7. fabricks/cdc/base/_types.py +5 -3
  8. fabricks/cdc/base/configurator.py +5 -0
  9. fabricks/cdc/base/generator.py +7 -3
  10. fabricks/cdc/base/merger.py +2 -0
  11. fabricks/cdc/base/processor.py +15 -0
  12. fabricks/cdc/templates/README.md +490 -0
  13. fabricks/cdc/templates/ctes/base.sql.jinja +1 -0
  14. fabricks/cdc/templates/ctes/current.sql.jinja +4 -0
  15. fabricks/cdc/templates/merges/scd1.sql.jinja +6 -0
  16. fabricks/cdc/templates/merges/scd2.sql.jinja +6 -0
  17. fabricks/cdc/templates/queries/context.sql.jinja +104 -96
  18. fabricks/cdc/templates/query.sql.jinja +1 -1
  19. fabricks/context/__init__.py +13 -1
  20. fabricks/context/config.py +13 -122
  21. fabricks/context/log.py +92 -1
  22. fabricks/context/runtime.py +35 -69
  23. fabricks/context/spark_session.py +4 -4
  24. fabricks/context/utils.py +26 -39
  25. fabricks/core/__init__.py +2 -2
  26. fabricks/core/dags/base.py +5 -5
  27. fabricks/core/dags/processor.py +2 -3
  28. fabricks/core/extenders.py +1 -1
  29. fabricks/core/job_schema.py +26 -16
  30. fabricks/core/jobs/__init__.py +1 -7
  31. fabricks/core/jobs/base/README.md +1545 -0
  32. fabricks/core/jobs/base/__init__.py +1 -8
  33. fabricks/core/jobs/base/checker.py +7 -7
  34. fabricks/core/jobs/base/configurator.py +142 -63
  35. fabricks/core/jobs/base/generator.py +38 -34
  36. fabricks/core/jobs/base/invoker.py +48 -63
  37. fabricks/core/jobs/base/processor.py +13 -28
  38. fabricks/core/jobs/bronze.py +88 -38
  39. fabricks/core/jobs/get_job.py +3 -6
  40. fabricks/core/jobs/get_job_conf.py +19 -68
  41. fabricks/core/jobs/get_jobs.py +10 -11
  42. fabricks/core/jobs/get_schedules.py +3 -17
  43. fabricks/core/jobs/gold.py +89 -47
  44. fabricks/core/jobs/silver.py +42 -22
  45. fabricks/core/masks.py +11 -8
  46. fabricks/core/parsers/__init__.py +0 -2
  47. fabricks/core/parsers/base.py +10 -10
  48. fabricks/core/parsers/decorator.py +1 -1
  49. fabricks/core/parsers/get_parser.py +4 -5
  50. fabricks/core/schedules/process.py +1 -4
  51. fabricks/core/steps/base.py +27 -17
  52. fabricks/core/steps/get_step.py +2 -4
  53. fabricks/core/steps/get_step_conf.py +3 -7
  54. fabricks/core/udfs.py +7 -7
  55. fabricks/core/views.py +2 -2
  56. fabricks/deploy/__init__.py +27 -16
  57. fabricks/deploy/masks.py +1 -1
  58. fabricks/deploy/notebooks.py +19 -16
  59. fabricks/deploy/schedules.py +1 -1
  60. fabricks/deploy/tables.py +66 -49
  61. fabricks/deploy/udfs.py +2 -2
  62. fabricks/deploy/views.py +15 -16
  63. fabricks/metastore/database.py +3 -3
  64. fabricks/metastore/table.py +103 -68
  65. fabricks/models/__init__.py +125 -0
  66. fabricks/models/common.py +79 -0
  67. fabricks/models/config.py +225 -0
  68. fabricks/models/dependency.py +50 -0
  69. fabricks/models/job.py +157 -0
  70. fabricks/models/path.py +17 -0
  71. fabricks/models/runtime.py +182 -0
  72. fabricks/models/schedule.py +21 -0
  73. fabricks/models/step.py +103 -0
  74. fabricks/models/table.py +77 -0
  75. fabricks/{core/jobs/get_job_id.py → models/utils.py} +2 -0
  76. fabricks/utils/helpers.py +6 -5
  77. fabricks/utils/log.py +25 -6
  78. fabricks/utils/path.py +265 -108
  79. fabricks/utils/pip.py +7 -7
  80. fabricks/utils/read/read.py +23 -22
  81. fabricks/utils/read/read_yaml.py +2 -2
  82. fabricks/utils/write/delta.py +4 -4
  83. fabricks/utils/write/stream.py +2 -2
  84. {fabricks-3.0.19.dist-info → fabricks-4.0.1.dist-info}/METADATA +9 -4
  85. {fabricks-3.0.19.dist-info → fabricks-4.0.1.dist-info}/RECORD +86 -83
  86. fabricks/context/_types.py +0 -139
  87. fabricks/context/helpers.py +0 -63
  88. fabricks/core/jobs/base/_types.py +0 -284
  89. fabricks/core/parsers/_types.py +0 -6
  90. fabricks/utils/fdict.py +0 -240
  91. fabricks/utils/pydantic.py +0 -94
  92. fabricks/utils/schema/__init__.py +0 -7
  93. fabricks/utils/schema/get_json_schema_for_type.py +0 -161
  94. fabricks/utils/schema/get_schema_for_type.py +0 -99
  95. {fabricks-3.0.19.dist-info → fabricks-4.0.1.dist-info}/WHEEL +0 -0
@@ -1,189 +1,197 @@
1
1
  /*
2
-
3
- ⚙️ BASE
2
+ {%- if cdc or mode %}
3
+ ⚙️ Base Configuration
4
4
  {%- if cdc %}
5
- cdc: {{ cdc }}
5
+ CDC Type: {{ cdc }}
6
6
  {%- endif %}
7
7
  {%- if mode %}
8
- mode: {{ mode }}
8
+ Mode: {{ mode }}
9
9
  {%- endif %}
10
-
11
- 🎯 SOURCE & TARTGET
10
+ {%- endif %}
11
+ {%- if format or src or tgt %}
12
+ 🎯 Source & Target
12
13
  {%- if format %}
13
- format: {{ format }}
14
+ Format: {{ format }}
14
15
  {%- endif %}
15
16
  {%- if src %}
16
- src: {{ src | truncate(100, killwords=True) }}
17
+ Source: {{ src | truncate(100, killwords=True) }}
17
18
  {%- endif %}
18
19
  {%- if tgt %}
19
- tgt: {{ tgt }}
20
- {%- endif %}
21
-
22
- 📊 CTE's
23
- {%- if slice %}
24
- 🗹 slice?
20
+ Target: {{ tgt }}
25
21
  {%- endif %}
26
- {%- if deduplicate %}
27
- 🗹 deduplicate?
28
22
  {%- endif %}
29
- {%- if advanced_deduplication %}
30
- 🗹 advanced deduplication?
23
+ {%- if slice or deduplicate_key or deduplicate_hash or rectify or correct_valid_from or advanced_deduplication or order_duplicate_by %}
24
+ 🔄 Applied Transformations
25
+ {%- if slice %}
26
+ ▸ Slice
31
27
  {%- endif %}
32
28
  {%- if deduplicate_key %}
33
- 🗹 deduplicate key?
29
+ Deduplicate Key
34
30
  {%- endif %}
35
31
  {%- if deduplicate_hash %}
36
- 🗹 deduplicate hash?
37
- {%- endif %}
38
- {%- if order_duplicate_by %}
39
- 🗹 order duplicate by?
32
+ Deduplicate Hash
40
33
  {%- endif %}
41
34
  {%- if rectify %}
42
- 🗹 rectify?
35
+ Rectify
43
36
  {%- endif %}
44
37
  {%- if correct_valid_from %}
45
- 🗹 correct valid from?
38
+ Correct Valid From
39
+ {%- endif %}
40
+ {%- if advanced_deduplication %}
41
+ ▸ Advanced Deduplication
46
42
  {%- endif %}
47
-
48
- 🔪 FILTERING
43
+ {%- if order_duplicate_by %}
44
+ Order Duplicate By
45
+ {%- endif %}
46
+ {%- endif %}
47
+ {%- if filter_where or update_where or slices or sources %}
48
+ 🔍 Filtering & Slicing
49
49
  {%- if filter_where %}
50
- filter where: {{ filter_where }}
50
+ Filter Where: {{ filter_where }}
51
51
  {%- endif %}
52
52
  {%- if update_where %}
53
- update where: {{ update_where }}
53
+ Update Where: {{ update_where }}
54
54
  {%- endif %}
55
55
  {%- if slices %}
56
- slices: {{ slices }}
56
+ Slices: {{ slices }}
57
57
  {%- endif %}
58
58
  {%- if sources %}
59
- sources: {{ sources }}
59
+ Sources: {{ sources }}
60
60
  {%- endif %}
61
-
62
- 🗑️ DELETES
61
+ {%- endif %}
62
+ {%- if delete_missing or soft_delete %}
63
+ 🗑️ Deletes
63
64
  {%- if delete_missing %}
64
- 🗹 delete missing?
65
+ Delete Missing ✓
65
66
  {%- endif %}
66
67
  {%- if soft_delete %}
67
- 🗹 soft delete?
68
+ Soft Delete ✓
69
+ {%- endif %}
68
70
  {%- endif %}
69
-
70
- DATA VALIDATION
71
- {%- if has_no_data %}
72
- has_data?
73
- {%- else %}
74
- 🗹 has data?
71
+ {%- if has_no_data is defined or has_rows is defined or has_source %}
72
+ Current State
73
+ {%- if has_no_data is defined %}
74
+ Data: {% if has_no_data %}✗{% else %}✓{% endif %}
75
75
  {%- endif %}
76
- {%- if has_rows %}
77
- 🗹 has rows?
78
- {%- else %}
79
- ☒ has rows?
76
+ {%- if has_rows is defined %}
77
+ Rows: {% if has_rows %}✓{% else %}✗{% endif %}
80
78
  {%- endif %}
81
79
  {%- if has_source %}
82
- 🗹 has source?
80
+ Source:
83
81
  {%- endif %}
84
-
85
- 🏷️ HAS FIELDS
82
+ {%- endif %}
83
+ {%- if has_metadata or has_timestamp or has_last_updated or has_key or has_hash or has_operation or has_identity or has_rescued_data or has_order_by %}
84
+ 🏷️ Found System Fields
86
85
  {%- if has_metadata %}
87
- 🗹 has metadata?
86
+ __metadata
88
87
  {%- endif %}
89
88
  {%- if has_timestamp %}
90
- 🗹 has timestamp?
89
+ __timestamp
91
90
  {%- endif %}
92
- {%- if has_identity %}
93
- 🗹 has identity?
91
+ {%- if has_last_updated %}
92
+ __last_updated
94
93
  {%- endif %}
95
94
  {%- if has_key %}
96
- 🗹 has key?
95
+ __key
97
96
  {%- endif %}
98
97
  {%- if has_hash %}
99
- 🗹 has hash?
98
+ __hash
100
99
  {%- endif %}
101
100
  {%- if has_operation %}
102
- 🗹 has operation?
101
+ __operation
103
102
  {%- endif %}
104
- {%- if has_order_by %}
105
- 🗹 has order by?
103
+ {%- if has_identity %}
104
+ __identity
106
105
  {%- endif %}
107
106
  {%- if has_rescued_data %}
108
- 🗹 has rescued data?
107
+ __rescued_data
109
108
  {%- endif %}
110
-
111
- ADD COLUMNS
109
+ {%- if has_order_by %}
110
+ Order By
111
+ {%- endif %}
112
+ {%- endif %}
113
+ {%- if add_metadata or add_timestamp or add_last_updated or add_key or add_hash or add_operation or add_source or add_calculated_columns %}
114
+ ➕ Added System Fields
112
115
  {%- if add_metadata %}
113
- 🗹 add metadata?
116
+ __metadata
114
117
  {%- endif %}
115
118
  {%- if add_timestamp %}
116
- 🗹 add timestamp?
119
+ __timestamp
120
+ {%- endif %}
121
+ {%- if add_last_updated %}
122
+ ▸ __last_updated
117
123
  {%- endif %}
118
124
  {%- if add_key %}
119
- 🗹 add key?
125
+ __key
120
126
  {%- endif %}
121
127
  {%- if add_hash %}
122
- 🗹 add hash?
128
+ __hash
123
129
  {%- endif %}
124
130
  {%- if add_operation %}
125
- add_operation: {{ add_operation }}
131
+ __operation = {{ add_operation }}
126
132
  {%- endif %}
127
133
  {%- if add_source %}
128
- add_source: {{ add_source }}
134
+ __source = {{ add_source }}
129
135
  {%- endif %}
130
136
  {%- if add_calculated_columns %}
131
- add_calculated_columns: {{ add_calculated_columns }}
137
+ Calculated = {{ add_calculated_columns }}
138
+ {%- endif %}
132
139
  {%- endif %}
133
-
134
- 🔄 EXTRA COLUMN OPERATIONs
140
+ {%- if all_except or all_overwrite or overwrite or cast %}
141
+ 🔧 Column Transformations
135
142
  {%- if all_except %}
136
- all_except: {{ all_except | join(", ") | truncate(100, killwords=True) }}
143
+ Exclude All Except: {{ all_except | join(", ") | truncate(100, killwords=True) }}
137
144
  {%- endif %}
138
145
  {%- if all_overwrite %}
139
- all_overwrite: {{ all_overwrite | join(", ") | truncate(100, killwords=True) }}
146
+ Overwrite All: {{ all_overwrite | join(", ") | truncate(100, killwords=True) }}
140
147
  {%- endif %}
141
148
  {%- if overwrite %}
142
- overwrite: {{ overwrite | join(", ") | truncate(100, killwords=True) }}
149
+ Overwrite: {{ overwrite | join(", ") | truncate(100, killwords=True) }}
143
150
  {%- endif %}
144
151
  {%- if cast %}
145
- cast: {{ cast | join(", ") | truncate(100, killwords=True) }}
152
+ Cast: {{ cast | join(", ") | truncate(100, killwords=True) }}
146
153
  {%- endif %}
147
-
148
- 👨‍👩‍👧 PARENTS
149
- {%- if parent_slice %}
150
- ☐ parent_slice: {{ parent_slice }}
151
154
  {%- endif %}
152
- {%- if parent_rectify %}
153
- parent_rectify: {{ parent_rectify }}
155
+ {%- if parent_slice or parent_deduplicate_key or parent_deduplicate_hash or parent_rectify or parent_cdc or parent_final %}
156
+ 🔗 CTE Lineage
157
+ {%- if parent_slice %}
158
+ ▸ parent_slice → {{ parent_slice }}
154
159
  {%- endif %}
155
160
  {%- if parent_deduplicate_key %}
156
- parent_deduplicate_key: {{ parent_deduplicate_key }}
161
+ parent_deduplicate_key {{ parent_deduplicate_key }}
157
162
  {%- endif %}
158
163
  {%- if parent_deduplicate_hash %}
159
- parent_deduplicate_hash: {{ parent_deduplicate_hash }}
164
+ parent_deduplicate_hash {{ parent_deduplicate_hash }}
165
+ {%- endif %}
166
+ {%- if parent_rectify %}
167
+ ▸ parent_rectify → {{ parent_rectify }}
160
168
  {%- endif %}
161
169
  {%- if parent_cdc %}
162
- parent_cdc: {{ parent_cdc }}
170
+ parent_cdc {{ parent_cdc }}
163
171
  {%- endif %}
164
172
  {%- if parent_final %}
165
- parent_final: {{ parent_final }}
173
+ parent_final {{ parent_final }}
166
174
  {%- endif %}
167
-
168
- 📦 LAYOUT
169
- {%- if columns %}
170
- ☐ columns: {{ columns | join(", ") | truncate(100, killwords=True) }}
175
+ {%- endif %}
176
+ {%- if keys or hashes or inputs or intermediates or outputs or columns %}
177
+ 📦 Columns
178
+ {%- if keys %}
179
+ ▸ Keys: {{ keys | join(", ") | truncate(100, killwords=True) }}
180
+ {%- endif %}
181
+ {%- if hashes %}
182
+ ▸ Hashes: {{ hashes | join(", ") | truncate(100, killwords=True) }}
171
183
  {%- endif %}
172
184
  {%- if inputs %}
173
- inputs: {{ inputs | join(", ") | truncate(100, killwords=True) }}
185
+ Inputs: {{ inputs | join(", ") | truncate(100, killwords=True) }}
174
186
  {%- endif %}
175
187
  {%- if intermediates %}
176
- intermediates: {{ intermediates | join(", ") | truncate(100, killwords=True) }}
188
+ Intermediates: {{ intermediates | join(", ") | truncate(100, killwords=True) }}
177
189
  {%- endif %}
178
190
  {%- if outputs %}
179
- outputs: {{ outputs | join(", ") | truncate(100, killwords=True) }}
191
+ Outputs: {{ outputs | join(", ") | truncate(100, killwords=True) }}
180
192
  {%- endif %}
181
- {%- if keys %}
182
- keys: {{ keys | join(", ") | truncate(100, killwords=True) }}
193
+ {%- if columns %}
194
+ All Columns: {{ columns | join(", ") | truncate(100, killwords=True) }}
183
195
  {%- endif %}
184
- {%- if hashes %}
185
- ☐ hashes: {{ hashes | join(", ") | truncate(100, killwords=True) }}
186
196
  {%- endif %}
187
-
188
197
  */
189
-
@@ -1,4 +1,4 @@
1
- {% include 'queries/context.sql.jinja' %}
1
+ {% if debugmode %} {% include 'queries/context.sql.jinja' %} {% endif %}
2
2
  {% include 'ctes/base.sql.jinja' %}
3
3
  {% if slice %} {% include 'ctes/slice.sql.jinja' %} {% endif %}
4
4
  {% if deduplicate_key %} {% include 'ctes/deduplicate_key.sql.jinja' %} {% endif %}
@@ -1,6 +1,8 @@
1
1
  from fabricks.context.config import (
2
+ CONFIG,
2
3
  IS_DEBUGMODE,
3
4
  IS_DEVMODE,
5
+ IS_FUNMODE,
4
6
  IS_JOB_CONFIG_FROM_YAML,
5
7
  LOGLEVEL,
6
8
  PATH_CONFIG,
@@ -30,22 +32,30 @@ from fabricks.context.runtime import (
30
32
  STEPS,
31
33
  TIMEZONE,
32
34
  VARIABLES,
35
+ Bronzes,
36
+ Golds,
37
+ Silvers,
38
+ Steps,
33
39
  )
34
40
  from fabricks.context.spark_session import DBUTILS, SPARK, build_spark_session, init_spark_session
35
41
  from fabricks.context.utils import pprint_runtime
36
42
 
37
43
  __all__ = [
38
44
  "BRONZE",
45
+ "Bronzes",
39
46
  "build_spark_session",
40
47
  "CATALOG",
41
48
  "CONF_RUNTIME",
49
+ "CONFIG",
42
50
  "DBUTILS",
43
51
  "FABRICKS_STORAGE_CREDENTIAL",
44
52
  "FABRICKS_STORAGE",
45
53
  "GOLD",
54
+ "Golds",
46
55
  "init_spark_session",
47
56
  "IS_DEBUGMODE",
48
57
  "IS_DEVMODE",
58
+ "IS_FUNMODE",
49
59
  "IS_JOB_CONFIG_FROM_YAML",
50
60
  "IS_TYPE_WIDENING",
51
61
  "IS_UNITY_CATALOG",
@@ -61,11 +71,13 @@ __all__ = [
61
71
  "PATH_UDFS",
62
72
  "PATH_VIEWS",
63
73
  "PATHS_RUNTIME",
64
- "pprint_runtime",
65
74
  "PATHS_STORAGE",
75
+ "pprint_runtime",
66
76
  "SECRET_SCOPE",
67
77
  "SILVER",
78
+ "Silvers",
68
79
  "SPARK",
80
+ "Steps",
69
81
  "STEPS",
70
82
  "TIMEZONE",
71
83
  "VARIABLES",
@@ -1,127 +1,18 @@
1
- import logging
2
- import os
3
1
  from typing import Final
4
2
 
5
- from fabricks.context.helpers import get_config_from_file
6
- from fabricks.utils.log import get_logger
7
- from fabricks.utils.path import Path
8
- from fabricks.utils.spark import spark
3
+ from fabricks.models.config import ConfigOptions
4
+ from fabricks.utils.path import GitPath
9
5
 
10
- logger, _ = get_logger("logs", level=logging.DEBUG)
11
- file_path, file_config, origin = get_config_from_file()
12
-
13
- if file_path:
14
- logger.debug(f"found {origin} config ({file_path})", extra={"label": "config"})
15
-
16
- # path to runtime
17
- runtime = os.environ.get("FABRICKS_RUNTIME", "none")
18
- runtime = None if runtime.lower() == "none" else runtime
19
- if runtime is None:
20
- if runtime := file_config.get("runtime"):
21
- assert file_path is not None
22
- runtime = file_path.joinpath(runtime)
23
- logger.debug(f"resolve runtime from {origin} file", extra={"label": "config"})
24
- else:
25
- logger.debug("resolve runtime from env", extra={"label": "config"})
26
-
27
- if runtime is None:
28
- if file_path is not None:
29
- runtime = file_path
30
- logger.debug(f"resolve runtime from {origin} file", extra={"label": "config"})
31
- else:
32
- raise ValueError(
33
- "could not resolve runtime (could not find pyproject.toml nor fabricksconfig.json nor FABRICKS_RUNTIME)"
34
- )
35
-
36
- path_runtime = Path(runtime, assume_git=True)
37
-
38
- # path to config
39
- config = os.environ.get("FABRICKS_CONFIG")
40
- if config is None:
41
- if config := file_config.get("config"):
42
- assert file_path is not None
43
- config = file_path.joinpath(config)
44
- logger.debug(f"resolve config from {origin} file", extra={"label": "config"})
45
- else:
46
- logger.debug("resolve config from env", extra={"label": "config"})
47
-
48
- if config is None:
49
- logger.debug("resolve config from default path", extra={"label": "config"})
50
- config = path_runtime.joinpath(
51
- "fabricks",
52
- f"conf.{spark.conf.get('spark.databricks.clusterUsageTags.clusterOwnerOrgId')}.yml",
53
- ).string
54
-
55
- path_config = Path(config, assume_git=True)
56
-
57
- # path to notebooks
58
- notebooks = os.environ.get("FABRICKS_NOTEBOOKS", "none")
59
- notebooks = None if notebooks.lower() == "none" else notebooks
60
- if notebooks is None:
61
- if notebooks := file_config.get("notebooks"):
62
- assert file_path is not None
63
- notebooks = file_path.joinpath(notebooks)
64
- logger.debug(f"resolve notebooks from {origin} file", extra={"label": "config"})
65
- else:
66
- logger.debug("resolve notebooks from env", extra={"label": "config"})
67
-
68
- if notebooks is None:
69
- logger.debug("resolve notebooks from default path", extra={"label": "config"})
70
- notebooks = path_runtime.joinpath("notebooks")
71
-
72
- path_notebooks = Path(str(notebooks), assume_git=True)
73
-
74
- # job config from yaml
75
- is_job_config_from_yaml = os.environ.get("FABRICKS_IS_JOB_CONFIG_FROM_YAML", None)
76
- if is_job_config_from_yaml is None:
77
- if is_job_config_from_yaml := file_config.get("job_config_from_yaml"):
78
- logger.debug(f"resolve job_config_from_yaml from {origin} file", extra={"label": "config"})
79
- else:
80
- logger.debug("resolve job_config_from_yaml from env", extra={"label": "config"})
81
-
82
- # debug mode
83
- is_debugmode = os.environ.get("FABRICKS_IS_DEBUGMODE", None)
84
- if is_debugmode is None:
85
- if is_debugmode := file_config.get("debugmode"):
86
- logger.debug(f"resolve debugmode from {origin} file", extra={"label": "config"})
87
- else:
88
- logger.debug("resolve debugmode from env", extra={"label": "config"})
89
-
90
- # dev mode
91
- is_devmode = os.environ.get("FABRICKS_IS_DEVMODE", None)
92
- if is_devmode is None:
93
- if is_devmode := file_config.get("devmode"):
94
- logger.debug(f"resolve devmode from {origin} file", extra={"label": "config"})
95
- else:
96
- logger.debug("resolve devmode from env", extra={"label": "config"})
97
-
98
- # log level
99
- loglevel = os.environ.get("FABRICKS_LOGLEVEL", None)
100
- if loglevel is None:
101
- if loglevel := file_config.get("loglevel"):
102
- logger.debug(f"resolve loglevel from {origin} file", extra={"label": "config"})
103
- else:
104
- logger.debug("resolve loglevel from env", extra={"label": "config"})
105
-
106
- loglevel = loglevel.upper() if loglevel else "INFO"
107
- if loglevel == "DEBUG":
108
- _loglevel = logging.DEBUG
109
- elif loglevel == "INFO":
110
- _loglevel = logging.INFO
111
- elif loglevel == "WARNING":
112
- _loglevel = logging.WARNING
113
- elif loglevel == "ERROR":
114
- _loglevel = logging.ERROR
115
- elif loglevel == "CRITICAL":
116
- _loglevel = logging.CRITICAL
117
- else:
118
- raise ValueError(f"could not resolve {loglevel} (DEBUG, INFO, WARNING, ERROR or CRITICAL)")
6
+ config = ConfigOptions()
119
7
 
120
8
  # Constants
121
- PATH_CONFIG: Final[Path] = path_config
122
- PATH_RUNTIME: Final[Path] = path_runtime
123
- PATH_NOTEBOOKS: Final[Path] = path_notebooks
124
- IS_JOB_CONFIG_FROM_YAML: Final[bool] = str(is_job_config_from_yaml).lower() in ("true", "1", "yes")
125
- IS_DEBUGMODE: Final[bool] = str(is_debugmode).lower() in ("true", "1", "yes")
126
- IS_DEVMODE: Final[bool] = str(is_devmode).lower() in ("true", "1", "yes")
127
- LOGLEVEL: Final[int] = _loglevel
9
+ CONFIG: Final[ConfigOptions] = config
10
+
11
+ PATH_CONFIG: Final[GitPath] = config.resolved_paths.config
12
+ PATH_RUNTIME: Final[GitPath] = config.resolved_paths.runtime
13
+ PATH_NOTEBOOKS: Final[GitPath] = config.resolved_paths.notebooks
14
+ IS_JOB_CONFIG_FROM_YAML: Final[bool] = config.job_config_from_yaml
15
+ IS_DEBUGMODE: Final[bool] = config.debugmode
16
+ IS_DEVMODE: Final[bool] = config.devmode
17
+ IS_FUNMODE: Final[bool] = config.funmode
18
+ LOGLEVEL: Final[int] = config.loglevel
fabricks/context/log.py CHANGED
@@ -1,10 +1,11 @@
1
1
  import json
2
2
  import logging
3
+ from datetime import datetime
3
4
  from typing import Final, Literal, Optional
4
5
 
5
6
  import requests
6
7
 
7
- from fabricks.context import IS_DEBUGMODE, LOGLEVEL, SECRET_SCOPE, TIMEZONE
8
+ from fabricks.context import IS_DEBUGMODE, IS_FUNMODE, LOGLEVEL, SECRET_SCOPE, TIMEZONE
8
9
  from fabricks.utils.log import get_logger
9
10
 
10
11
  logger, _ = get_logger(
@@ -18,6 +19,96 @@ logging.getLogger("SQLQueryContextLogger").setLevel(logging.CRITICAL)
18
19
 
19
20
  DEFAULT_LOGGER: Final[logging.Logger] = logger
20
21
 
22
+ if IS_FUNMODE:
23
+ # 🎄 Christmas Easter Egg 🎅
24
+ _now = datetime.now()
25
+ if _now.month == 12:
26
+ _day = _now.day
27
+ if _day <= 24:
28
+ _days_until = 25 - _day
29
+ if _days_until == 1:
30
+ DEFAULT_LOGGER.info("🎄 Ho ho ho! Only 1 day until Christmas! Happy data processing! 🎅")
31
+ elif _days_until <= 7:
32
+ DEFAULT_LOGGER.info(
33
+ f"🎄 'Tis the season! {_days_until} days until Christmas! May your pipelines run smoothly! 🎁"
34
+ )
35
+ else:
36
+ DEFAULT_LOGGER.info("🎄 Merry December! Wishing you bug-free data pipelines this holiday season! ⛄")
37
+ elif _day == 25:
38
+ DEFAULT_LOGGER.info("🎄🎅 MERRY CHRISTMAS! May all your queries be optimized and your data be clean! 🎁✨")
39
+ else:
40
+ DEFAULT_LOGGER.info("🎄 Happy Holidays! Hope you're enjoying the festive season between data runs! 🎉")
41
+
42
+ if _now.month == 10 and _now.day == 31:
43
+ DEFAULT_LOGGER.info("🎃👻 Happy Halloween! May your data be spooky good and your bugs be few! 🕸️🦇")
44
+
45
+ if _now.month == 7 and _now.day == 4:
46
+ DEFAULT_LOGGER.info("🎆🇺🇸 Happy 4th of July! Celebrate freedom with flawless data processing! 🎇🍔")
47
+
48
+ if _now.month == 1 and _now.day == 1:
49
+ DEFAULT_LOGGER.info("🎉 Happy New Year! Wishing you a year of successful data projects and clean code! 🥳🎆")
50
+
51
+ if _now.month == 2 and _now.day == 14:
52
+ DEFAULT_LOGGER.info(
53
+ "💖 Happy Valentine's Day! May your data relationships be strong and your joins be perfect! 🌹📊"
54
+ )
55
+
56
+ if _now.month == 3 and _now.day == 17:
57
+ DEFAULT_LOGGER.info(
58
+ "🍀 Happy St. Patrick's Day! Wishing you the luck of the Irish in all your data endeavors! 🌈☘️"
59
+ )
60
+
61
+ if _now.month == 6 and _now.day == 19:
62
+ DEFAULT_LOGGER.info(
63
+ "🌞 Happy Juneteenth! Celebrating freedom and the power of data to enlighten and empower! ✊🏿📈"
64
+ )
65
+
66
+ if _now.month == 11 and _now.day == 11:
67
+ DEFAULT_LOGGER.info(
68
+ "🦃 Happy Veterans Day! Honoring those who served while we serve up great data insights! 🇺🇸📊"
69
+ )
70
+
71
+ if _now.month == 5 and _now.day == 1:
72
+ DEFAULT_LOGGER.info("🌸 Happy May Day! Celebrating spring and the blossoming of new data opportunities! 🌷📈")
73
+
74
+ if _now.month == 5 and _now.day == 5:
75
+ DEFAULT_LOGGER.info("🎉 Happy Cinco de Mayo! Celebrating culture and the fiesta of data analytics! 🌮📊")
76
+
77
+ if _now.month == 5 and _now.day == 4:
78
+ DEFAULT_LOGGER.info(
79
+ "🌌 May the 4th be with you! Harness the force of data to conquer your analytics challenges! 🚀📊"
80
+ )
81
+
82
+ if _now.month == 8 and _now.day == 1:
83
+ DEFAULT_LOGGER.info(
84
+ "🏖️ Happy Swiss National Day! Celebrating precision and excellence in data, just like Swiss craftsmanship! 🇨🇭📈"
85
+ )
86
+
87
+ if _now.month == 7 and _now.day == 14:
88
+ DEFAULT_LOGGER.info(
89
+ "🎉 Happy Bastille Day! Celebrating liberty, equality, and the power of data to transform societies! 🇫🇷📊"
90
+ )
91
+
92
+ if _now.month == 7 and _now.day == 21:
93
+ DEFAULT_LOGGER.info(
94
+ "🚴 Happy Belgian National Day! Celebrating unity and the strength of data-driven decisions! 🇧🇪📈"
95
+ )
96
+
97
+ if _now.day > 27 and _now.day < 31:
98
+ DEFAULT_LOGGER.warning(
99
+ "⚠️ Warning: End of month is near! Make sure to finalize your data reports and close out any pending tasks! 📅✅"
100
+ )
101
+
102
+ if _now.weekday() == 4:
103
+ DEFAULT_LOGGER.warning(
104
+ "📅🚫 Please do not deploy on Fridays! Avoid end-of-week surprises in your data pipelines! 🚫📅"
105
+ )
106
+
107
+ if _now.weekday() == 0:
108
+ DEFAULT_LOGGER.info(
109
+ "☕ Happy Monday! Kickstart your week with fresh data insights and a strong cup of coffee! 📊☕"
110
+ )
111
+
21
112
 
22
113
  def send_message_to_channel(
23
114
  channel: str,