openstef-models 4.2.2__tar.gz → 4.2.3__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 (162) hide show
  1. {openstef_models-4.2.2 → openstef_models-4.2.3}/PKG-INFO +2 -2
  2. {openstef_models-4.2.2 → openstef_models-4.2.3}/pyproject.toml +1 -1
  3. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/integrations/mlflow/mlflow_storage.py +44 -3
  4. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/forecasting/median_forecaster.py +4 -1
  5. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/utils/data_split.py +1 -1
  6. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/integrations/mlflow/test_mlflow_storage.py +20 -1
  7. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/forecasting/conftest.py +1 -1
  8. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/forecasting/test_median_forecaster.py +6 -1
  9. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/general/test_dimensionality_reducer.py +1 -1
  10. {openstef_models-4.2.2 → openstef_models-4.2.3}/.gitignore +0 -0
  11. {openstef_models-4.2.2 → openstef_models-4.2.3}/README.md +0 -0
  12. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/__init__.py +0 -0
  13. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/explainability/__init__.py +0 -0
  14. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/explainability/mixins.py +0 -0
  15. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/explainability/plotters/__init__.py +0 -0
  16. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/explainability/plotters/contributions_plotter.py +0 -0
  17. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/explainability/plotters/feature_importance_plotter.py +0 -0
  18. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/integrations/__init__.py +0 -0
  19. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/integrations/joblib/__init__.py +0 -0
  20. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/integrations/joblib/joblib_model_serializer.py +0 -0
  21. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/integrations/mlflow/__init__.py +0 -0
  22. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/integrations/mlflow/mlflow_storage_callback.py +0 -0
  23. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/integrations/optuna/__init__.py +0 -0
  24. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/integrations/optuna/tuner.py +0 -0
  25. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/mixins/__init__.py +0 -0
  26. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/mixins/callbacks.py +0 -0
  27. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/mixins/model_serializer.py +0 -0
  28. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/__init__.py +0 -0
  29. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/component_splitting/__init__.py +0 -0
  30. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/component_splitting/component_splitter.py +0 -0
  31. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/component_splitting/constant_component_splitter.py +0 -0
  32. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/component_splitting/linear_component_splitter.py +0 -0
  33. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/component_splitting/linear_component_splitter_model/linear_component_splitter_model.z +0 -0
  34. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/component_splitting/linear_component_splitter_model/linear_component_splitter_model.z.license +0 -0
  35. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/component_splitting_model.py +0 -0
  36. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/forecasting/__init__.py +0 -0
  37. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/forecasting/base_case_forecaster.py +0 -0
  38. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/forecasting/constant_quantile_forecaster.py +0 -0
  39. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/forecasting/flatliner_forecaster.py +0 -0
  40. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/forecasting/forecaster.py +0 -0
  41. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/forecasting/gblinear_forecaster.py +0 -0
  42. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/forecasting/lgbm_forecaster.py +0 -0
  43. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/forecasting/lgbmlinear_forecaster.py +0 -0
  44. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/forecasting/xgboost_forecaster.py +0 -0
  45. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/models/forecasting_model.py +0 -0
  46. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/presets/__init__.py +0 -0
  47. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/presets/forecasting_workflow.py +0 -0
  48. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/testing.py +0 -0
  49. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/__init__.py +0 -0
  50. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/energy_domain/__init__.py +0 -0
  51. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/energy_domain/wind_power_feature_adder.py +0 -0
  52. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/general/__init__.py +0 -0
  53. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/general/dimensionality_reducer.py +0 -0
  54. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/general/empty_feature_remover.py +0 -0
  55. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/general/flagger.py +0 -0
  56. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/general/imputer.py +0 -0
  57. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/general/nan_dropper.py +0 -0
  58. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/general/outlier_handler.py +0 -0
  59. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/general/sample_weighter.py +0 -0
  60. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/general/scaler.py +0 -0
  61. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/general/selector.py +0 -0
  62. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/general/shifter.py +0 -0
  63. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/postprocessing/__init__.py +0 -0
  64. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/postprocessing/confidence_interval_applicator.py +0 -0
  65. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/postprocessing/isotonic_quantile_calibrator.py +0 -0
  66. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/postprocessing/quantile_sorter.py +0 -0
  67. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/time_domain/__init__.py +0 -0
  68. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/time_domain/cyclic_features_adder.py +0 -0
  69. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/time_domain/datetime_features_adder.py +0 -0
  70. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/time_domain/holiday_features_adder.py +0 -0
  71. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/time_domain/lags_adder.py +0 -0
  72. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/time_domain/rolling_aggregates_adder.py +0 -0
  73. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/time_domain/versioned_lags_adder.py +0 -0
  74. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/validation/__init__.py +0 -0
  75. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/validation/completeness_checker.py +0 -0
  76. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/validation/flatline_checker.py +0 -0
  77. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/validation/input_consistency_checker.py +0 -0
  78. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/weather_domain/__init__.py +0 -0
  79. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/weather_domain/atmosphere_derived_features_adder.py +0 -0
  80. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/weather_domain/daylight_feature_adder.py +0 -0
  81. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/transforms/weather_domain/radiation_derived_features_adder.py +0 -0
  82. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/utils/__init__.py +0 -0
  83. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/utils/evaluation_functions.py +0 -0
  84. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/utils/feature_selection.py +0 -0
  85. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/utils/loss_functions.py +0 -0
  86. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/utils/multi_quantile_regressor.py +0 -0
  87. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/utils/xgboost.py +0 -0
  88. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/workflows/__init__.py +0 -0
  89. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/workflows/callbacks/__init__.py +0 -0
  90. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/workflows/callbacks/data_save.py +0 -0
  91. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/workflows/callbacks/model_performance_callback.py +0 -0
  92. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/workflows/custom_component_split_workflow.py +0 -0
  93. {openstef_models-4.2.2 → openstef_models-4.2.3}/src/openstef_models/workflows/custom_forecasting_workflow.py +0 -0
  94. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/__init__.py +0 -0
  95. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/integration/__init__.py +0 -0
  96. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/integration/test_integration.py +0 -0
  97. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/__init__.py +0 -0
  98. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/explainability/__init__.py +0 -0
  99. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/explainability/plotters/__init__.py +0 -0
  100. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/explainability/plotters/test_contributions_plotter.py +0 -0
  101. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/integrations/__init__.py +0 -0
  102. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/integrations/joblib/__init__.py +0 -0
  103. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/integrations/joblib/test_joblib_model_serializer.py +0 -0
  104. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/integrations/mlflow/__init__.py +0 -0
  105. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/integrations/mlflow/test_mlflow_storage_callback.py +0 -0
  106. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/integrations/optuna/__init__.py +0 -0
  107. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/integrations/optuna/test_tuner.py +0 -0
  108. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/__init__.py +0 -0
  109. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/component_splitting/__init__.py +0 -0
  110. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/component_splitting/test_constant_component_splitter.py +0 -0
  111. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/component_splitting/test_linear_component_splitter.py +0 -0
  112. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/forecasting/__init__.py +0 -0
  113. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/forecasting/test_base_case_forecaster.py +0 -0
  114. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/forecasting/test_constant_quantile_forecaster.py +0 -0
  115. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/forecasting/test_flatliner_forecaster.py +0 -0
  116. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/forecasting/test_gblinear_forecaster.py +0 -0
  117. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/forecasting/test_lgbm_forecaster.py +0 -0
  118. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/forecasting/test_lgbmlinear_forecaster.py +0 -0
  119. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/forecasting/test_xgboost_forecaster.py +0 -0
  120. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/models/test_forecasting_model.py +0 -0
  121. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/test_example.py +0 -0
  122. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/__init__.py +0 -0
  123. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/energy_domain/__init__.py +0 -0
  124. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/energy_domain/test_wind_power_feature_adder.py +0 -0
  125. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/general/__init__.py +0 -0
  126. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/general/test_empty_feature_remover.py +0 -0
  127. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/general/test_flagger.py +0 -0
  128. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/general/test_imputer.py +0 -0
  129. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/general/test_nan_dropper.py +0 -0
  130. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/general/test_outlier_handler.py +0 -0
  131. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/general/test_sample_weighter.py +0 -0
  132. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/general/test_scaler.py +0 -0
  133. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/general/test_selector.py +0 -0
  134. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/general/test_shifter.py +0 -0
  135. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/postprocessing/__init__.py +0 -0
  136. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/postprocessing/test_confidence_interval_applicator.py +0 -0
  137. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/postprocessing/test_isotonic_quantile_calibrator.py +0 -0
  138. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/postprocessing/test_quantile_sorter.py +0 -0
  139. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/time_domain/__init__.py +0 -0
  140. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/time_domain/test_cyclic_features_adder.py +0 -0
  141. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/time_domain/test_datetime_features_adder.py +0 -0
  142. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/time_domain/test_holiday_features_adder.py +0 -0
  143. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/time_domain/test_lags_adder.py +0 -0
  144. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/time_domain/test_rolling_aggregates_adder.py +0 -0
  145. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/time_domain/test_versioned_lags_adder.py +0 -0
  146. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/validation/__init__.py +0 -0
  147. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/validation/test_completeness_checker.py +0 -0
  148. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/validation/test_flatline_checker.py +0 -0
  149. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/validation/test_input_consistency_checker.py +0 -0
  150. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/weather_domain/__init__.py +0 -0
  151. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/weather_domain/test_atmosphere_derived_features_adder.py +0 -0
  152. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/weather_domain/test_daylight_feature_adder.py +0 -0
  153. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/transforms/weather_domain/test_radiation_derived_featuers_adder.py +0 -0
  154. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/utils/__init__.py +0 -0
  155. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/utils/test_data_split.py +0 -0
  156. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/utils/test_feature_selection.py +0 -0
  157. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/utils/test_loss_functions.py +0 -0
  158. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/utils/test_multi_quantile_regressor.py +0 -0
  159. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/workflows/__init__.py +0 -0
  160. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/workflows/callbacks/__init__.py +0 -0
  161. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/workflows/callbacks/test_model_performance_callback.py +0 -0
  162. {openstef_models-4.2.2 → openstef_models-4.2.3}/tests/unit/workflows/test_custom_forecasting_workflow.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: openstef-models
3
- Version: 4.2.2
3
+ Version: 4.2.3
4
4
  Summary: Core models for OpenSTEF
5
5
  Project-URL: Documentation, https://openstef.github.io/openstef/index.html
6
6
  Project-URL: Homepage, https://lfenergy.org/projects/openstef/
@@ -7,7 +7,7 @@ requires = [ "hatchling" ]
7
7
 
8
8
  [project]
9
9
  name = "openstef-models"
10
- version = "4.2.2"
10
+ version = "4.2.3"
11
11
  description = "Core models for OpenSTEF"
12
12
  readme = "README.md"
13
13
  keywords = [ "energy", "forecasting", "machinelearning" ]
@@ -22,7 +22,7 @@ from urllib.parse import urlparse
22
22
  from mlflow import MlflowClient
23
23
  from mlflow.entities import Metric, Param, Run
24
24
  from mlflow.exceptions import MlflowException
25
- from pydantic import Field, PrivateAttr
25
+ from pydantic import ConfigDict, Field, PrivateAttr
26
26
 
27
27
  from openstef_core.base_model import BaseConfig
28
28
  from openstef_core.exceptions import ModelNotFoundError
@@ -31,7 +31,7 @@ from openstef_models.integrations.joblib import JoblibModelSerializer
31
31
  from openstef_models.mixins import ModelIdentifier, ModelSerializer
32
32
 
33
33
 
34
- def normalize_tracking_uri(uri: str) -> str:
34
+ def normalize_tracking_uri(uri: str, exceptions: Sequence[str] = []) -> str:
35
35
  r"""Normalize a tracking URI to a file:/// URI when it refers to a local path.
36
36
 
37
37
  MLflow's model registry rejects bare Windows paths (e.g. ``D:\mlflow``) because
@@ -44,10 +44,13 @@ def normalize_tracking_uri(uri: str) -> str:
44
44
 
45
45
  Args:
46
46
  uri: Raw tracking URI string, may be a path or a proper URI.
47
+ exceptions: List of URI to treat as urls even if they have no scheme
47
48
 
48
49
  Returns:
49
50
  A ``file:///`` URI for local paths, or the original URI for remote schemes.
50
51
  """
52
+ if uri in exceptions:
53
+ return uri
51
54
  scheme = urlparse(uri).scheme
52
55
  # Empty scheme → relative/absolute POSIX path.
53
56
  # Single-letter scheme → Windows drive letter (e.g. "D" from "D:\\...").
@@ -63,9 +66,33 @@ class MLFlowStorage(BaseConfig):
63
66
  Handles creation, storage, and retrieval of MLflow runs including models,
64
67
  training data, metrics, and hyperparameters. Organizes artifacts locally
65
68
  before uploading to MLflow tracking server.
69
+
70
+ ``tracking_uri`` configures the Tracking backend that stores experiments and
71
+ runs. ``registry_uri`` optionally configures a separate Model Registry
72
+ backend; if it is omitted, MLflow uses the registry associated with the
73
+ tracking backend. ``artifact_location`` configures the artifact root for
74
+ experiments created by this instance.
75
+
76
+ Typical configurations:
77
+
78
+ tracking_uri="sqlite:///mlflow.db", # Local SQLite tracking backend with separate local artifacts
79
+ tracking_uri="https://mlflow.example.com", # Remote MLflow Tracking Server with S3 artifacts
80
+ tracking_uri="databricks", # Databricks MLflow Tracking Server with DBFS artifacts
81
+
82
+ A caller may provide ``client`` to use an already configured
83
+ :class:`mlflow.MlflowClient`. When supplied, it takes precedence over
84
+ ``tracking_uri`` and ``registry_uri`` and is excluded from serialized model
85
+ configuration.
66
86
  """
67
87
 
88
+ model_config = ConfigDict(arbitrary_types_allowed=True)
89
+
68
90
  tracking_uri: str = Field(default="./mlflow", description="MLflow tracking server URI.")
91
+ registry_uri: str | None = Field(default=None, description="MLflow tracking server URI.")
92
+
93
+ # Excluded from model_dump(), JSON serialization, and config persistence.
94
+ client: MlflowClient | None = Field(default=None, exclude=True, repr=False)
95
+
69
96
  local_artifacts_path: Path = Field(
70
97
  default=Path("./mlflow_artifacts_local"), description="Local path for storing MLflow artifacts before upload."
71
98
  )
@@ -86,6 +113,11 @@ class MLFlowStorage(BaseConfig):
86
113
 
87
114
  model_serializer: ModelSerializer = Field(default_factory=JoblibModelSerializer)
88
115
 
116
+ uri_exceptions: Sequence[str] = Field(
117
+ default=["databricks"],
118
+ description="List of URI treat as urls even if they have no scheme",
119
+ )
120
+
89
121
  _client: MlflowClient = PrivateAttr()
90
122
  _logger: logging.Logger = PrivateAttr(default=logging.getLogger(__name__))
91
123
 
@@ -95,8 +127,17 @@ class MLFlowStorage(BaseConfig):
95
127
  # Suppress MLflow's stdout messages (emoji URLs)
96
128
  os.environ.setdefault("MLFLOW_SUPPRESS_PRINTING_URL_TO_STDOUT", "true")
97
129
  os.environ.setdefault("MLFLOW_ENABLE_ARTIFACTS_PROGRESS_BAR", "false")
130
+
131
+ if self.client is not None:
132
+ self._client = self.client
133
+ return
134
+
98
135
  self.tracking_uri = normalize_tracking_uri(self.tracking_uri)
99
- self._client = MlflowClient(tracking_uri=self.tracking_uri)
136
+ self.registry_uri = normalize_tracking_uri(self.registry_uri) if self.registry_uri else None
137
+ self._client = MlflowClient(
138
+ tracking_uri=self.tracking_uri,
139
+ registry_uri=self.registry_uri,
140
+ )
100
141
 
101
142
  def create_run(
102
143
  self,
@@ -200,7 +200,10 @@ class MedianForecaster(Forecaster, ExplainableForecaster, ContributionsMixin):
200
200
  lag_df = input_data.reindex(new_index, fill_value=np.nan)[self._feature_names]
201
201
 
202
202
  # Convert the lag DataFrame to NumPy arrays for faster processing.
203
- lag_array = lag_df.to_numpy()
203
+ # Copy explicitly: pandas Copy-on-Write may hand back a read-only view of the
204
+ # DataFrame's underlying block, but the autoregressive loop below fills the
205
+ # array in place (via _fill_diagonal_with_median), so it must own a writable copy.
206
+ lag_array = lag_df.to_numpy(copy=True)
204
207
  # Initialize the prediction array with NaNs.
205
208
  prediction = np.full(lag_array.shape[0], np.nan)
206
209
 
@@ -201,7 +201,7 @@ def _get_extreme_days(
201
201
  raise TypeError("target_series must have a DatetimeIndex.")
202
202
 
203
203
  # Compute daily min and max once
204
- daily_agg: pd.DataFrame = target_series.resample("1D").agg(["min", "max"]) # type: ignore
204
+ daily_agg: pd.DataFrame = target_series.resample("1D").agg(["min", "max"])
205
205
  n_days = len(daily_agg)
206
206
  n_extremes = max(int(fraction * n_days), 2)
207
207
 
@@ -7,6 +7,7 @@ from __future__ import annotations
7
7
  from typing import TYPE_CHECKING, cast
8
8
 
9
9
  import pytest
10
+ from mlflow import MlflowClient
10
11
 
11
12
  from openstef_core.mixins import HyperParams, Stateful
12
13
  from openstef_models.integrations.mlflow import MLFlowStorage
@@ -49,6 +50,21 @@ def model_id() -> str:
49
50
  return "test_model_123"
50
51
 
51
52
 
53
+ def test_construct_from_mlflow(tmp_path: Path, model_id: str):
54
+ """Test that experiment_name_prefix is prepended to experiment names."""
55
+ # Arrange
56
+ mlflow_client = MlflowClient(tracking_uri=f"sqlite:///{tmp_path / 'mlflow.db'}")
57
+
58
+ # Act
59
+ storage = MLFlowStorage(
60
+ tracking_uri=f"sqlite:///{tmp_path / 'mlflow.db'}",
61
+ client=mlflow_client,
62
+ )
63
+
64
+ # Assert
65
+ assert storage._client is mlflow_client
66
+
67
+
52
68
  def test_create_run(storage: MLFlowStorage, model_id: str):
53
69
  """Test that create_run converts HyperParams to MLflow parameters."""
54
70
  # Arrange
@@ -194,12 +210,15 @@ def test_search_run__returns_matching_run(storage: MLFlowStorage, model_id: str)
194
210
  pytest.param("https://mlflow.example.com:5000", "https://mlflow.example.com:5000", id="https-port"),
195
211
  pytest.param("sqlite:///mlflow.db", "sqlite:///mlflow.db", id="sqlite"),
196
212
  pytest.param("postgresql://user:pass@host/db", "postgresql://user:pass@host/db", id="postgresql"),
213
+ pytest.param("databricks", "databricks", id="databricks"),
197
214
  ],
198
215
  )
199
216
  def test_normalize_tracking_uri(uri: str, expected: str):
200
217
  """Local paths become file:/// URIs; remote/database URIs pass through unchanged."""
201
218
  # Act
202
- result = normalize_tracking_uri(uri)
219
+ result = normalize_tracking_uri(
220
+ uri, exceptions=["databricks"]
221
+ ) # databricks is a special case that should not be normalized
203
222
 
204
223
  # Assert
205
224
  if expected == "file:///":
@@ -30,7 +30,7 @@ def sample_forecast_input_dataset() -> ForecastInputDataset:
30
30
  "feature2": feature_2,
31
31
  "feature3": feature_3,
32
32
  },
33
- index=pd.date_range(start=start_date, periods=num_samples, freq="1d"),
33
+ index=pd.date_range(start=start_date, periods=num_samples, freq="1D"),
34
34
  ),
35
35
  sample_interval=timedelta(days=1),
36
36
  target_column="load",
@@ -158,7 +158,12 @@ def test_median_handles_all_missing_data():
158
158
  {
159
159
  "quantile_P50": [],
160
160
  },
161
- index=pd.DatetimeIndex([], freq="h"),
161
+ # Slice `index` rather than building a bare `DatetimeIndex([], freq="h")` so the
162
+ # (empty) expected index shares its dtype resolution with the one produced by the
163
+ # real prediction pipeline (pandas infers datetime64 resolution from context, and
164
+ # an index with no data to infer from does not necessarily match one derived from
165
+ # actual timestamps).
166
+ index=index[:0],
162
167
  ),
163
168
  sample_interval=training_input_data.sample_interval,
164
169
  forecast_start=training_input_data.forecast_start,
@@ -33,7 +33,7 @@ def sample_forecast_input_dataset() -> TimeSeriesDataset:
33
33
  "feature2": feature_2,
34
34
  "feature3": feature_3,
35
35
  },
36
- index=pd.date_range(start=start_date, periods=num_samples, freq="1d"),
36
+ index=pd.date_range(start=start_date, periods=num_samples, freq="1D"),
37
37
  ),
38
38
  sample_interval=timedelta(days=1),
39
39
  )