churnkit 0.76.0a3__py3-none-any.whl → 0.76.1a1__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 (28) hide show
  1. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/01_data_discovery.ipynb +5 -3
  2. {churnkit-0.76.0a3.dist-info → churnkit-0.76.1a1.dist-info}/METADATA +1 -1
  3. {churnkit-0.76.0a3.dist-info → churnkit-0.76.1a1.dist-info}/RECORD +28 -28
  4. customer_retention/__init__.py +1 -1
  5. customer_retention/analysis/notebook_progress.py +10 -1
  6. customer_retention/core/config/experiments.py +45 -0
  7. customer_retention/integrations/databricks_init.py +28 -1
  8. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/00_start_here.ipynb +0 -0
  9. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/01a_a_temporal_text_deep_dive.ipynb +0 -0
  10. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/01a_temporal_deep_dive.ipynb +0 -0
  11. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/01b_temporal_quality.ipynb +0 -0
  12. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/01c_temporal_patterns.ipynb +0 -0
  13. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/01d_event_aggregation.ipynb +0 -0
  14. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/02_column_deep_dive.ipynb +0 -0
  15. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/02a_text_columns_deep_dive.ipynb +0 -0
  16. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/03_quality_assessment.ipynb +0 -0
  17. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/04_relationship_analysis.ipynb +0 -0
  18. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/05_multi_dataset.ipynb +0 -0
  19. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/06_feature_opportunities.ipynb +0 -0
  20. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/07_modeling_readiness.ipynb +0 -0
  21. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/08_baseline_experiments.ipynb +0 -0
  22. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/09_business_alignment.ipynb +0 -0
  23. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/10_spec_generation.ipynb +0 -0
  24. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/11_scoring_validation.ipynb +0 -0
  25. {churnkit-0.76.0a3.data → churnkit-0.76.1a1.data}/data/share/churnkit/exploration_notebooks/12_view_documentation.ipynb +0 -0
  26. {churnkit-0.76.0a3.dist-info → churnkit-0.76.1a1.dist-info}/WHEEL +0 -0
  27. {churnkit-0.76.0a3.dist-info → churnkit-0.76.1a1.dist-info}/entry_points.txt +0 -0
  28. {churnkit-0.76.0a3.dist-info → churnkit-0.76.1a1.dist-info}/licenses/LICENSE +0 -0
@@ -137,10 +137,12 @@
137
137
  "# =============================================================================\n",
138
138
  "\n",
139
139
  "# DATA_PATH: Path to your data file (CSV, Parquet, or Delta)\n",
140
- "DATA_PATH = \"../tests/fixtures/customer_retention_retail.csv\"\n",
140
+ "DATA_PATH = \"../tests/fixtures/customer_emails.csv\"\n",
141
+ "# or databricks /Volumes/churnkit/landing/datasets/customer_emails.csv\n",
142
+ "\n",
141
143
  "\n",
142
144
  "# TARGET_COLUMN: Your prediction target (set to None for auto-detection)\n",
143
- "TARGET_COLUMN = \"unsubscribed\"\n",
145
+ "TARGET_COLUMN = None\n",
144
146
  "\n",
145
147
  "# ENTITY_COLUMN: Customer/user ID column (set to None for auto-detection)\n",
146
148
  "ENTITY_COLUMN = None\n",
@@ -169,7 +171,7 @@
169
171
  "#\n",
170
172
  "# EVENT-LEVEL (multiple rows per customer):\n",
171
173
  "# DATA_PATH = \"../tests/fixtures/customer_transactions.csv\"\n",
172
- "DATA_PATH = \"../tests/fixtures/customer_emails.csv\"\n",
174
+ "# DATA_PATH = \"../tests/fixtures/customer_emails.csv\"\n",
173
175
  "# =============================================================================\n",
174
176
  "\n",
175
177
  "# OUTPUT_DIR: All outputs go here (gitignored)\n",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: churnkit
3
- Version: 0.76.0a3
3
+ Version: 0.76.1a1
4
4
  Summary: Structured ML framework for customer churn prediction -- from exploration notebooks to production pipelines, locally or on Databricks.
5
5
  Project-URL: Homepage, https://github.com/aladjov/CR
6
6
  Project-URL: Documentation, https://github.com/aladjov/CR/wiki
@@ -1,9 +1,9 @@
1
- customer_retention/__init__.py,sha256=1f6U04yIo69jlaQhX87DCNUo8P9P2tRzDJCik5ELPE0,1406
1
+ customer_retention/__init__.py,sha256=fNqb1iL6Q95kXsIVQBbVJtV_NmNSWBtgbGZxRy7vuYM,1406
2
2
  customer_retention/cli.py,sha256=Wdl540cZgu_9mV-hWmTV9jD3S8QTDR8Ik-5hQXYCvmg,2466
3
3
  customer_retention/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  customer_retention/analysis/jupyter_save_hook.py,sha256=iiNFIL83yOPX8BGUjCE6Pt5Kc8X-2adtE1_NZTMUaZQ,947
5
5
  customer_retention/analysis/notebook_html_exporter.py,sha256=AMOTcD6nZncM4MPdVS1Kn4WF2YoaOoODMI2X48oEZ24,4491
6
- customer_retention/analysis/notebook_progress.py,sha256=aauU-0AXHraFf0M_91aSmZwI-HmZslaGnmu-Msw4xPM,2298
6
+ customer_retention/analysis/notebook_progress.py,sha256=Tm98ihaFQMXRAlEHTH89T23gLNZardzrCMC4svcoAUw,2463
7
7
  customer_retention/analysis/plotly_preprocessor.py,sha256=Bdd_9-AmfmJdrmm030wzgpLflbiszp9KhXPbw_F5Id0,5300
8
8
  customer_retention/analysis/auto_explorer/__init__.py,sha256=0isViyt62QvDkYc2oxOhsDQ9RNMqBq1ihvwEZgoLb_s,1572
9
9
  customer_retention/analysis/auto_explorer/exploration_manager.py,sha256=60ObVRhYwAWqHnLrkeJ6_oQjPvXOl4gkLutE66_k8uc,18028
@@ -84,7 +84,7 @@ customer_retention/core/components/components/transformer.py,sha256=saEO6cRzKitU
84
84
  customer_retention/core/components/components/validator.py,sha256=5IbUqPYhsvZBTRx0X3MKV2dvZrgTcI19MM9c5_9t2CU,1405
85
85
  customer_retention/core/config/__init__.py,sha256=VXNmwSFG3wY6Budh82WRj26X07WCQKgl-M9sVwx8eds,1587
86
86
  customer_retention/core/config/column_config.py,sha256=rmMJFV4wK66q-DDQAJXe0EuXdrWd_6bg8s81NQQ54_A,3051
87
- customer_retention/core/config/experiments.py,sha256=CCxFgzO4sHpuNu3W2UkAaOAqsoPkXTmdHupMaMs8PvM,3234
87
+ customer_retention/core/config/experiments.py,sha256=PQJwO1l8NjS9k_F6qOu0u0fTFcf_k--e6NIUMFBK1p4,4703
88
88
  customer_retention/core/config/pipeline_config.py,sha256=jriAcP-_UAlVTT_vVlWUPF97ieIguqlE5hrl9Ny0UiI,3675
89
89
  customer_retention/core/config/source_config.py,sha256=NnZUytq4NVvRVmp1ZtoFO_SiaIvSoJwkhw5WXy4Wi_c,2534
90
90
  customer_retention/core/utils/__init__.py,sha256=9b8SwZGiLP-glYwzcp-1aWCeTGIploAPokwITbUCneA,971
@@ -131,7 +131,7 @@ customer_retention/generators/spec_generator/generic_generator.py,sha256=I_glnOO
131
131
  customer_retention/generators/spec_generator/mlflow_pipeline_generator.py,sha256=LME87sjzP_MjOMA3NTxqRfOhCroUJAb40BAnSH4-I74,29866
132
132
  customer_retention/generators/spec_generator/pipeline_spec.py,sha256=c8v1SWgTdeGmNs96l1hOS0qx1B1ua0iwPhw1I5w9OIo,10705
133
133
  customer_retention/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
134
- customer_retention/integrations/databricks_init.py,sha256=Qte81tiF4MjDzX7o5dPNOKsY_IoVjVXtJoPUDtZ4kx0,5641
134
+ customer_retention/integrations/databricks_init.py,sha256=xQgCBhzx0DoGGGeocYX9Iu3H2dEl--bvA36T7_uF6TM,6526
135
135
  customer_retention/integrations/adapters/__init__.py,sha256=Fgdp0ESROTUHnOb2RN9Ubo0A4BdfoenOGuUz61lHz8g,583
136
136
  customer_retention/integrations/adapters/base.py,sha256=z6dVAowDKGogKsYGR7VMcLkS6VhcB9h4zgN1tilNYRg,254
137
137
  customer_retention/integrations/adapters/factory.py,sha256=CMsqOeDozADbWnk8fzktZvAyL1FEmUjDMvfDCpLDVaU,1202
@@ -277,27 +277,27 @@ customer_retention/transforms/artifact_store.py,sha256=FYLpDcv2N6-dUTX5RPEIK3aCW
277
277
  customer_retention/transforms/executor.py,sha256=oML5dCidxbW_q6YUkAwWcutYP6bIFB6IdD3BvemK45A,6304
278
278
  customer_retention/transforms/fitted.py,sha256=3pNvnae-P3t3bKMeZz1Bl0xww-feapIYdoeTY6aUtI8,3278
279
279
  customer_retention/transforms/ops.py,sha256=Xg2g9UOOudq_y9Hf3oWsjpqw3dEoykQR5pDSoyW8GX0,4294
280
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/00_start_here.ipynb,sha256=zCyhftEd3v9fc0Ta6wvA6b-9LcoGzRi8bS1tMZ3iu9w,21911
281
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/01_data_discovery.ipynb,sha256=up0X3oDJ5sAo1-tbqMyZj_f1h6D542G2uAxjVmtYCOI,46430
282
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/01a_a_temporal_text_deep_dive.ipynb,sha256=uai8T3iJSqOrabBQnVi8Z0k8zZGVgs_VVQWRHyXN8QU,33690
283
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/01a_temporal_deep_dive.ipynb,sha256=fC1ASNtvI8X1lAe-Lzcw3oX2cptDC-ymPeEtKKWhg20,67326
284
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/01b_temporal_quality.ipynb,sha256=RU5hxgrTVMZs1ytChVv1t49WpTO0Oj6B_Fu8g0xS0To,23039
285
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/01c_temporal_patterns.ipynb,sha256=ZGYfztP6JhOEwPmTYdC0l7w579fKXcNEJXq-PnCLc2I,153167
286
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/01d_event_aggregation.ipynb,sha256=-FT3SoBU0fhaZxGeTo-_UQl6riCrtoJaFnUg31opk64,63244
287
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/02_column_deep_dive.ipynb,sha256=mbP2LQWsXDyTsWg0bhrCBHEfHsEer_XOXRYV9f8JxAk,60250
288
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/02a_text_columns_deep_dive.ipynb,sha256=M9YN8yAjjuC6ZaUlc-rVqVLEkWd7Rc_GNILHS9qO3PU,29704
289
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/03_quality_assessment.ipynb,sha256=H49LLmn1PHbcbAvSQfteESRGk125QwkPI5qbLk3yZgc,68595
290
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/04_relationship_analysis.ipynb,sha256=Rr-B4-xg0ILuAIgztlZkiGJdTzLuNjOqBFxO8W4o9iU,78624
291
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/05_multi_dataset.ipynb,sha256=bBxkuZyTl1yZg4kMXO87WRjgZMhj_6hwLGX6m3XC270,62664
292
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/06_feature_opportunities.ipynb,sha256=cBJF5o4z3Z-dustQ4CVklnfTcQ8saG97tlgswWK9uWE,67409
293
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/07_modeling_readiness.ipynb,sha256=IiA04fyb-l097Glp3MtR03vPjQsZlS1Icg-hjEHa_Dg,28376
294
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/08_baseline_experiments.ipynb,sha256=KmjhnDf1JdpEiIcdfQ-ZFo_at6t9JRC30B6NmmvMBmg,34226
295
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/09_business_alignment.ipynb,sha256=tMNfGM7AH50N1ONzHhGW2HZLpQwraIxVzOiVnI-10X8,17214
296
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/10_spec_generation.ipynb,sha256=KeUdfL9Mvdi6023XpnfZ6oLEDNZaWiIHUfsAWig24mE,42847
297
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/11_scoring_validation.ipynb,sha256=5fi3eHMm03ZKZgdFAXMgydtZ3qX2TtR3L9bZS2MpWPE,49937
298
- churnkit-0.76.0a3.data/data/share/churnkit/exploration_notebooks/12_view_documentation.ipynb,sha256=aQF7CG8HxckqUKOKqnmZgMkSvfVzyO2LlYPrymLYjBY,4405
299
- churnkit-0.76.0a3.dist-info/METADATA,sha256=MYmaYdzvcZWtkAL6AtSWEBBAhluczHz_im33olePY3k,13005
300
- churnkit-0.76.0a3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
301
- churnkit-0.76.0a3.dist-info/entry_points.txt,sha256=swQFVe-jjgQSBJQNO2Ulkz2F5odaE-TsnlTor3HQBjw,70
302
- churnkit-0.76.0a3.dist-info/licenses/LICENSE,sha256=Bud8Oj25tnpoIuXCWW0xcSfmGPeEZAAHrDRoKdSYtZY,11344
303
- churnkit-0.76.0a3.dist-info/RECORD,,
280
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/00_start_here.ipynb,sha256=zCyhftEd3v9fc0Ta6wvA6b-9LcoGzRi8bS1tMZ3iu9w,21911
281
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/01_data_discovery.ipynb,sha256=EDhWyKM2stHtWg2bS8HdRMItZ6WtokWRyZ90_MjTPFQ,46500
282
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/01a_a_temporal_text_deep_dive.ipynb,sha256=uai8T3iJSqOrabBQnVi8Z0k8zZGVgs_VVQWRHyXN8QU,33690
283
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/01a_temporal_deep_dive.ipynb,sha256=fC1ASNtvI8X1lAe-Lzcw3oX2cptDC-ymPeEtKKWhg20,67326
284
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/01b_temporal_quality.ipynb,sha256=RU5hxgrTVMZs1ytChVv1t49WpTO0Oj6B_Fu8g0xS0To,23039
285
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/01c_temporal_patterns.ipynb,sha256=ZGYfztP6JhOEwPmTYdC0l7w579fKXcNEJXq-PnCLc2I,153167
286
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/01d_event_aggregation.ipynb,sha256=-FT3SoBU0fhaZxGeTo-_UQl6riCrtoJaFnUg31opk64,63244
287
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/02_column_deep_dive.ipynb,sha256=mbP2LQWsXDyTsWg0bhrCBHEfHsEer_XOXRYV9f8JxAk,60250
288
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/02a_text_columns_deep_dive.ipynb,sha256=M9YN8yAjjuC6ZaUlc-rVqVLEkWd7Rc_GNILHS9qO3PU,29704
289
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/03_quality_assessment.ipynb,sha256=H49LLmn1PHbcbAvSQfteESRGk125QwkPI5qbLk3yZgc,68595
290
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/04_relationship_analysis.ipynb,sha256=Rr-B4-xg0ILuAIgztlZkiGJdTzLuNjOqBFxO8W4o9iU,78624
291
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/05_multi_dataset.ipynb,sha256=bBxkuZyTl1yZg4kMXO87WRjgZMhj_6hwLGX6m3XC270,62664
292
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/06_feature_opportunities.ipynb,sha256=cBJF5o4z3Z-dustQ4CVklnfTcQ8saG97tlgswWK9uWE,67409
293
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/07_modeling_readiness.ipynb,sha256=IiA04fyb-l097Glp3MtR03vPjQsZlS1Icg-hjEHa_Dg,28376
294
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/08_baseline_experiments.ipynb,sha256=KmjhnDf1JdpEiIcdfQ-ZFo_at6t9JRC30B6NmmvMBmg,34226
295
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/09_business_alignment.ipynb,sha256=tMNfGM7AH50N1ONzHhGW2HZLpQwraIxVzOiVnI-10X8,17214
296
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/10_spec_generation.ipynb,sha256=KeUdfL9Mvdi6023XpnfZ6oLEDNZaWiIHUfsAWig24mE,42847
297
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/11_scoring_validation.ipynb,sha256=5fi3eHMm03ZKZgdFAXMgydtZ3qX2TtR3L9bZS2MpWPE,49937
298
+ churnkit-0.76.1a1.data/data/share/churnkit/exploration_notebooks/12_view_documentation.ipynb,sha256=aQF7CG8HxckqUKOKqnmZgMkSvfVzyO2LlYPrymLYjBY,4405
299
+ churnkit-0.76.1a1.dist-info/METADATA,sha256=CkjX1u5qlqFbTuNbtFC93u25moHVAf2TaxYJwFAMWZY,13005
300
+ churnkit-0.76.1a1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
301
+ churnkit-0.76.1a1.dist-info/entry_points.txt,sha256=swQFVe-jjgQSBJQNO2Ulkz2F5odaE-TsnlTor3HQBjw,70
302
+ churnkit-0.76.1a1.dist-info/licenses/LICENSE,sha256=Bud8Oj25tnpoIuXCWW0xcSfmGPeEZAAHrDRoKdSYtZY,11344
303
+ churnkit-0.76.1a1.dist-info/RECORD,,
@@ -17,7 +17,7 @@ Main module categories:
17
17
  llm_context, iteration)
18
18
  """
19
19
 
20
- __version__ = "0.76.0a3"
20
+ __version__ = "0.76.1a1"
21
21
 
22
22
  # Environment utilities (always available)
23
23
  from .core.compat import (
@@ -5,7 +5,16 @@ from pathlib import Path
5
5
  from typing import Optional
6
6
 
7
7
  from customer_retention.core.compat import is_databricks
8
- from customer_retention.core.config.experiments import get_notebook_experiments_dir
8
+ from customer_retention.core.config.experiments import get_notebook_experiments_dir, reload_config
9
+
10
+
11
+ def _ensure_databricks_config_loaded() -> None:
12
+ if not is_databricks():
13
+ return
14
+ reload_config()
15
+
16
+
17
+ _ensure_databricks_config_loaded()
9
18
 
10
19
 
11
20
  def track_and_export_previous(current_notebook: str) -> None:
@@ -1,7 +1,49 @@
1
+ import json
1
2
  import os
2
3
  from pathlib import Path
3
4
  from typing import Optional
4
5
 
6
+ _DATABRICKS_CONFIG_FILENAME = ".churnkit_config.json"
7
+
8
+
9
+ def _workspace_config_path(workspace_path: str) -> Path:
10
+ return Path(f"/Workspace/{workspace_path}") / _DATABRICKS_CONFIG_FILENAME
11
+
12
+
13
+ def _read_config_file(path: Path) -> dict | None:
14
+ try:
15
+ return json.loads(path.read_text()) if path.exists() else None
16
+ except (json.JSONDecodeError, OSError):
17
+ return None
18
+
19
+
20
+ def _load_persisted_databricks_config() -> dict | None:
21
+ if not os.environ.get("DATABRICKS_RUNTIME_VERSION"):
22
+ return None
23
+ workspace_path = os.environ.get("CR_WORKSPACE_PATH")
24
+ if workspace_path:
25
+ return _read_config_file(_workspace_config_path(workspace_path))
26
+ cwd = Path.cwd()
27
+ for _ in range(5):
28
+ result = _read_config_file(cwd / _DATABRICKS_CONFIG_FILENAME)
29
+ if result:
30
+ return result
31
+ if cwd.parent == cwd:
32
+ break
33
+ cwd = cwd.parent
34
+ return None
35
+
36
+
37
+ def persist_databricks_config(experiments_dir: str, catalog: str, schema: str, workspace_path: str | None = None) -> None:
38
+ if not workspace_path:
39
+ return
40
+ try:
41
+ _workspace_config_path(workspace_path).write_text(json.dumps({
42
+ "experiments_dir": experiments_dir, "catalog": catalog, "schema": schema,
43
+ }))
44
+ except OSError:
45
+ pass
46
+
5
47
 
6
48
  def _find_project_root() -> Path:
7
49
  path = Path(__file__).parent
@@ -17,6 +59,9 @@ def get_experiments_dir(default: Optional[str] = None) -> Path:
17
59
  return Path(os.environ["CR_EXPERIMENTS_DIR"])
18
60
  if default:
19
61
  return Path(default)
62
+ persisted = _load_persisted_databricks_config()
63
+ if persisted and "experiments_dir" in persisted:
64
+ return Path(persisted["experiments_dir"])
20
65
  return _find_project_root() / "experiments"
21
66
 
22
67
 
@@ -40,11 +40,14 @@ def databricks_init(
40
40
  _validate_databricks_environment()
41
41
  if workspace_path:
42
42
  workspace_path = _normalize_workspace_path(workspace_path)
43
+ _ensure_workspace_directory(workspace_path)
43
44
  _set_environment_variables(catalog, schema, workspace_path)
45
+ _persist_config(catalog, schema, workspace_path)
44
46
  resolved_experiment_name = experiment_name or _resolve_experiment_name_from_notebook_path()
45
47
  resolved_experiment_name = _make_absolute_experiment_path(resolved_experiment_name, workspace_path)
46
48
  _set_experiment_name_env_var(resolved_experiment_name)
47
49
  _reload_config_constants()
50
+ _setup_experiment_directories()
48
51
  _configure_mlflow_experiment(resolved_experiment_name)
49
52
  notebooks_copied: list[str] = []
50
53
  if copy_notebooks and workspace_path:
@@ -81,12 +84,27 @@ def _set_experiment_name_env_var(experiment_name: str) -> None:
81
84
  os.environ["CR_EXPERIMENT_NAME"] = experiment_name
82
85
 
83
86
 
87
+ def _persist_config(catalog: str, schema: str, workspace_path: str | None) -> None:
88
+ from customer_retention.core.config.experiments import persist_databricks_config
89
+
90
+ persist_databricks_config(f"/Volumes/{catalog}/{schema}/experiments", catalog, schema, workspace_path)
91
+
92
+
84
93
  def _reload_config_constants() -> None:
85
94
  from customer_retention.core.config.experiments import reload_config
86
95
 
87
96
  reload_config()
88
97
 
89
98
 
99
+ def _setup_experiment_directories() -> None:
100
+ from customer_retention.core.config.experiments import setup_experiments_structure
101
+
102
+ try:
103
+ setup_experiments_structure()
104
+ except OSError:
105
+ pass
106
+
107
+
90
108
  def _resolve_experiment_name_from_notebook_path() -> str:
91
109
  try:
92
110
  dbutils = _get_dbutils()
@@ -133,6 +151,13 @@ def _configure_mlflow_experiment(experiment_name: str) -> None:
133
151
  pass
134
152
 
135
153
 
154
+ def _ensure_workspace_directory(workspace_path: str) -> None:
155
+ try:
156
+ Path(f"/Workspace/{workspace_path}").mkdir(parents=True, exist_ok=True)
157
+ except OSError:
158
+ pass
159
+
160
+
136
161
  def _copy_exploration_notebooks(workspace_path: str) -> list[str]:
137
162
  from customer_retention.generators.notebook_generator.project_init import ProjectInitializer
138
163
 
@@ -154,7 +179,9 @@ def _copy_exploration_notebooks(workspace_path: str) -> list[str]:
154
179
 
155
180
 
156
181
  def _display_init_summary(result: DatabricksInitResult) -> None:
157
- print("ChurnKit Databricks Initialization Complete")
182
+ from customer_retention import __version__
183
+
184
+ print(f"ChurnKit v{__version__} Databricks Initialization Complete")
158
185
  print("=" * 45)
159
186
  print(f" Catalog: {result.catalog}")
160
187
  print(f" Schema: {result.schema}")