omle-convert 0.1.0__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.

Potentially problematic release.


This version of omle-convert might be problematic. Click here for more details.

Files changed (42) hide show
  1. omle_convert/__init__.py +173 -0
  2. omle_convert/_common.py +1218 -0
  3. omle_convert/_version.py +24 -0
  4. omle_convert/catboost.py +525 -0
  5. omle_convert/cli.py +191 -0
  6. omle_convert/lightgbm.py +619 -0
  7. omle_convert/sklearn/__init__.py +519 -0
  8. omle_convert/sklearn/_anomaly_detection.py +356 -0
  9. omle_convert/sklearn/_builder.py +196 -0
  10. omle_convert/sklearn/_category_encoders.py +229 -0
  11. omle_convert/sklearn/_cluster.py +100 -0
  12. omle_convert/sklearn/_compose.py +146 -0
  13. omle_convert/sklearn/_decomposition.py +159 -0
  14. omle_convert/sklearn/_ensemble.py +385 -0
  15. omle_convert/sklearn/_estimators.py +210 -0
  16. omle_convert/sklearn/_impute.py +57 -0
  17. omle_convert/sklearn/_linear_model.py +82 -0
  18. omle_convert/sklearn/_multiclass.py +97 -0
  19. omle_convert/sklearn/_multioutput.py +235 -0
  20. omle_convert/sklearn/_naive_bayes.py +109 -0
  21. omle_convert/sklearn/_neighbors.py +97 -0
  22. omle_convert/sklearn/_neural_network.py +55 -0
  23. omle_convert/sklearn/_pipeline.py +122 -0
  24. omle_convert/sklearn/_preprocessing.py +476 -0
  25. omle_convert/sklearn/_selection.py +36 -0
  26. omle_convert/sklearn/_svm.py +117 -0
  27. omle_convert/sklearn/_text.py +141 -0
  28. omle_convert/sklearn/_transformers.py +278 -0
  29. omle_convert/sklearn/_tree.py +24 -0
  30. omle_convert/sklearn/_trees.py +306 -0
  31. omle_convert/sklearn/_xgboost_lgbm.py +85 -0
  32. omle_convert/spark/__init__.py +441 -0
  33. omle_convert/spark/_builder.py +252 -0
  34. omle_convert/spark/_reader.py +2222 -0
  35. omle_convert/spark/_sql_transforms.py +410 -0
  36. omle_convert/xgboost.py +715 -0
  37. omle_convert-0.1.0.dist-info/METADATA +297 -0
  38. omle_convert-0.1.0.dist-info/RECORD +42 -0
  39. omle_convert-0.1.0.dist-info/WHEEL +5 -0
  40. omle_convert-0.1.0.dist-info/entry_points.txt +2 -0
  41. omle_convert-0.1.0.dist-info/licenses/LICENSE +201 -0
  42. omle_convert-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,173 @@
1
+ """omle-convert: converters from popular ML frameworks to the OMLE format."""
2
+ from __future__ import annotations
3
+
4
+ from pathlib import Path
5
+
6
+ from omle_convert.catboost import from_catboost, from_catboost_file
7
+ from omle_convert.lightgbm import from_lightgbm, from_lightgbm_text
8
+ from omle_convert.sklearn import from_sklearn
9
+ from omle_convert.spark import from_spark, from_spark_live
10
+ from omle_convert.xgboost import from_xgboost, from_xgboost_json
11
+
12
+ __all__ = [
13
+ "to_omle",
14
+ "export_omle",
15
+ "from_xgboost", "from_xgboost_json",
16
+ "from_lightgbm", "from_lightgbm_text",
17
+ "from_sklearn",
18
+ "from_catboost", "from_catboost_file",
19
+ "from_spark", "from_spark_live",
20
+ ]
21
+ __version__ = "0.1.0"
22
+
23
+
24
+ def to_omle(model, **kwargs):
25
+ """Convert a model to OMLE format, auto-detecting the framework.
26
+
27
+ Accepts either a live model object or a file path (str/Path).
28
+
29
+ Supported objects:
30
+ - any sklearn BaseEstimator or Pipeline, including XGBClassifier and LGBMClassifier
31
+ - xgboost.Booster (raw booster, not wrapped in sklearn API)
32
+ - lightgbm.Booster (raw booster, not wrapped in sklearn API)
33
+
34
+ Supported file paths (by extension):
35
+ - ``.json`` → XGBoost JSON model
36
+ - ``.ubj`` → XGBoost binary (ubj)
37
+ - ``.bin`` / ``.txt`` → LightGBM text model
38
+ - directory → Spark saved model / saved pipeline (auto-detected)
39
+
40
+ Extra keyword arguments are forwarded to the underlying converter.
41
+ """
42
+ if isinstance(model, (str, Path)):
43
+ return _convert_from_path(model, **kwargs)
44
+ return _convert_object(model, **kwargs)
45
+
46
+
47
+ def export_omle(model, path, **kwargs) -> None:
48
+ """Export *model* to an OMLE file at *path*.
49
+
50
+ If *model* is already an ``OMLEModel`` it is saved directly.
51
+ Otherwise it is converted via ``to_omle`` first.
52
+ """
53
+ import omle
54
+ if not isinstance(model, omle.OMLEModel):
55
+ model = to_omle(model, **kwargs)
56
+ omle.save(model, path)
57
+
58
+
59
+
60
+ # Sample-data argument names differ by framework: the array-based converters take
61
+ # ``X`` (scikit-learn's convention), the PySpark ones take ``dataset``
62
+ # (``fit(dataset)`` / ``transform(dataset)``). Each is idiomatic where it is used,
63
+ # but the unified entry points auto-detect the framework, so requiring the caller
64
+ # to already know which spelling applies would defeat the point. Accept either
65
+ # here and forward whichever the resolved converter declares.
66
+ _SAMPLE_ALIASES = ("X", "dataset")
67
+
68
+
69
+ def _sample_kwarg(kwargs: dict, wanted: str) -> dict:
70
+ """Rename the sample-data kwarg to *wanted*.
71
+
72
+ The destination is named explicitly rather than discovered by inspecting the
73
+ target's signature: converters get monkey-patched in places (the test suite
74
+ wraps them for instrumentation), and a wrapper's ``(*args, **kwargs)``
75
+ signature would make introspection silently find nothing.
76
+ """
77
+ given = [k for k in _SAMPLE_ALIASES if k in kwargs]
78
+ if not given:
79
+ return kwargs
80
+ if len(given) > 1:
81
+ raise TypeError(
82
+ "Pass either 'X' or 'dataset' for sample data, not both."
83
+ )
84
+ if given[0] == wanted:
85
+ return kwargs
86
+ kwargs = dict(kwargs)
87
+ kwargs[wanted] = kwargs.pop(given[0])
88
+ return kwargs
89
+
90
+
91
+ def _convert_object(model, **kwargs):
92
+ """Dispatch a live model object to the right converter."""
93
+ module = type(model).__module__ or ""
94
+ cls_name = type(model).__name__
95
+
96
+ # sklearn (includes XGBClassifier, LGBMClassifier which are BaseEstimators)
97
+ try:
98
+ from sklearn.base import BaseEstimator
99
+ if isinstance(model, BaseEstimator):
100
+ return from_sklearn(model, **_sample_kwarg(kwargs, "X"))
101
+ except ImportError:
102
+ pass
103
+
104
+ # CatBoost (CatBoostClassifier/Regressor/CatBoost are not sklearn BaseEstimators
105
+ # when catboost is not installed alongside sklearn, but handle both cases)
106
+ if module.startswith("catboost"):
107
+ return from_catboost(model, **_sample_kwarg(kwargs, "X"))
108
+
109
+ # xgboost Booster (not a BaseEstimator)
110
+ if module.startswith("xgboost"):
111
+ return from_xgboost(model, **_sample_kwarg(kwargs, "X"))
112
+
113
+ # lightgbm Booster (not a BaseEstimator)
114
+ if module.startswith("lightgbm"):
115
+ return from_lightgbm(model, **_sample_kwarg(kwargs, "X"))
116
+
117
+ # live PySpark PipelineModel or single estimator
118
+ if module.startswith("pyspark"):
119
+ return from_spark_live(model, **_sample_kwarg(kwargs, "dataset"))
120
+
121
+ raise TypeError(
122
+ f"Cannot auto-detect converter for {cls_name} (module={module!r}). "
123
+ "Use a specific from_* function instead."
124
+ )
125
+
126
+
127
+ def _convert_from_path(path, **kwargs):
128
+ """Dispatch a file path to the right converter by extension / content."""
129
+ p = Path(path)
130
+
131
+ if p.is_dir():
132
+ return from_spark(str(p), **kwargs)
133
+
134
+ suffix = p.suffix.lower()
135
+
136
+ if suffix in {".bin", ".txt"}:
137
+ return from_lightgbm_text(str(p), **_sample_kwarg(kwargs, "X"))
138
+
139
+ if suffix in {".pkl", ".pickle", ".joblib"}:
140
+ try:
141
+ import joblib
142
+ obj = joblib.load(p)
143
+ except ImportError:
144
+ import pickle
145
+ with open(p, "rb") as f:
146
+ obj = pickle.load(f)
147
+ return _convert_object(obj, **kwargs)
148
+
149
+ if suffix == ".cbm":
150
+ return from_catboost_file(str(p), **_sample_kwarg(kwargs, "X"))
151
+
152
+ if suffix in {".json", ".ubj"}:
153
+ # Both frameworks use `.json`, so dispatch on a top-level key: CatBoost
154
+ # writes "oblivious_trees", XGBoost writes "learner".
155
+ #
156
+ # The whole file is scanned, not a fixed prefix: CatBoost emits
157
+ # "features_info" first and "oblivious_trees" only tens of kilobytes in,
158
+ # so a prefix peek misses it and silently routes to the wrong loader.
159
+ if suffix == ".json":
160
+ try:
161
+ raw = p.read_bytes()
162
+ if b'"oblivious_trees"' in raw:
163
+ return from_catboost_file(str(p), **_sample_kwarg(kwargs, "X"))
164
+ if b'"learner"' in raw or b'"objective"' in raw:
165
+ return from_xgboost_json(str(p), **_sample_kwarg(kwargs, "X"))
166
+ except Exception:
167
+ pass
168
+ return from_xgboost_json(str(p), **_sample_kwarg(kwargs, "X"))
169
+
170
+ raise ValueError(
171
+ f"Cannot auto-detect converter for path {str(p)!r} (suffix={suffix!r}). "
172
+ "Use a specific from_* function instead."
173
+ )