Skip to content

Commit 7be3a29

Browse files
authored
v0.7.0 (#8)
1 parent 6228d0e commit 7be3a29

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+5633
-1585
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
# Environs
2020
.env
2121
/.venv/
22-
poetry.lock
2322

2423
# Project
2524
/docs/*
25+
/mlruns/*
2626
/outputs/*
2727
!**/.gitkeep
2828

.pre-commit-config.yaml

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
default_language_version:
55
python: python3.12
66
repos:
7-
# commons
87
- repo: https://github.com/pre-commit/pre-commit-hooks
98
rev: v4.5.0
109
hooks:
@@ -17,22 +16,13 @@ repos:
1716
- id: end-of-file-fixer
1817
- id: mixed-line-ending
1918
- id: trailing-whitespace
20-
- repo: github.com/PyCQA/bandit
21-
rev: v1.7.7
22-
hooks:
23-
- id: bandit
24-
args: ["--configfile=pyproject.toml"]
25-
- repo: https://github.com/pre-commit/mirrors-mypy
26-
rev: v1.8.0
27-
hooks:
28-
- id: mypy
2919
- repo: https://github.com/astral-sh/ruff-pre-commit
30-
rev: v0.3.0
20+
rev: v0.3.3
3121
hooks:
3222
- id: ruff
3323
- id: ruff-format
3424
- repo: https://github.com/commitizen-tools/commitizen
35-
rev: v3.16.0
25+
rev: v3.18.3
3626
hooks:
3727
- id: commitizen
3828
- id: commitizen-branch

confs/promotion.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
job:
2+
KIND: PromotionJob

confs/tuning.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,3 @@ job:
66
targets:
77
KIND: ParquetReader
88
path: data/targets.parquet
9-
results:
10-
KIND: ParquetWriter
11-
path: outputs/results.parquet

mlops-python-package.code-workspace

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
"dchanco.vsc-invoke",
2525
"ms-python.mypy-type-checker",
2626
"ms-python.python",
27-
"ms-python.mypy-type-checker",
2827
"ms-python.vscode-pylance",
2928
]
3029
}
31-
}
30+
}

poetry.lock

Lines changed: 3532 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
[tool.poetry]
66
name = "bikes"
7-
version = "0.6.0"
7+
version = "0.7.0"
88
description = "Predict the number of bikes available."
9-
documentation = "https://fmind.github.io/mlops-python-package/"
109
repository = "https://github.com/fmind/mlops-python-package"
10+
documentation = "https://fmind.github.io/mlops-python-package/"
1111
authors = ["Médéric HURIER <github@fmind.dev>"]
1212
readme = "README.md"
1313
license = "CC BY"
@@ -23,60 +23,55 @@ bikes = 'bikes.scripts:main'
2323

2424
[tool.poetry.dependencies]
2525
python = "^3.12"
26-
codecarbon = "^2.3.4"
2726
loguru = "^0.7.2"
28-
mlflow-skinny = "^2.11.0"
27+
matplotlib = "^3.8.3"
28+
mlflow = "^2.11.0"
29+
numpy = "^1.26.4"
2930
omegaconf = "^2.3.0"
3031
pandas = "^2.2.1"
31-
pandera = "^0.18.0"
32+
pandera = "^0.18.3"
3233
plotly = "^5.19.0"
33-
pyarrow = "^15.0.0"
34-
pydantic = "^2.6.3"
34+
pyarrow = "^15.0.1"
35+
pydantic = "^2.6.4"
3536
pydantic-settings = "^2.2.1"
3637
scikit-learn = "^1.4.1"
37-
mlflow = "^2.11.0"
38-
39-
[tool.poetry.group.dev.dependencies]
40-
invoke = "^2.2.0"
41-
42-
[tool.poetry.group.docs.dependencies]
43-
pdoc = "^14.4.0"
4438

4539
[tool.poetry.group.checks.dependencies]
46-
bandit = "^1.7.7"
40+
bandit = "^1.7.8"
4741
coverage = "^7.4.3"
48-
mypy = "^1.8.0"
49-
pytest = "^8.0.2"
42+
mypy = "^1.9.0"
43+
pytest = "^8.1.1"
5044
pytest-cov = "^4.1.0"
5145
pytest-xdist = "^3.5.0"
52-
pandera = { extras = ["mypy"], version = "^0.18.0" }
53-
ruff = "^0.3.0"
46+
pandera = { extras = ["mypy"], version = "^0.18.3" }
47+
ruff = "^0.3.3"
5448

5549
[tool.poetry.group.commits.dependencies]
56-
commitizen = "^3.16.0"
50+
commitizen = "^3.18.3"
5751
pre-commit = "^3.6.2"
5852

59-
[tool.poetry.group.carbons.dependencies]
60-
dash = "^2.16.0"
61-
dash-bootstrap-components = "^1.5.0"
62-
fire = "^0.5.0"
53+
[tool.poetry.group.dev.dependencies]
54+
invoke = "^2.2.0"
55+
56+
[tool.poetry.group.docs.dependencies]
57+
pdoc = "^14.4.0"
6358

6459
[tool.poetry.group.notebooks.dependencies]
6560
ipykernel = "^6.29.3"
66-
nbformat = "^5.9.2"
61+
nbformat = "^5.10.2"
6762

6863
# CONFIGURATIONS
6964

7065
[tool.bandit]
71-
skips = ["B101"]
66+
targets = ["src"]
7267

7368
[tool.commitizen]
7469
name = "cz_conventional_commits"
7570
tag_format = "v$version"
7671
version_scheme = "pep440"
7772
version_provider = "poetry"
7873
changelog_start_rev = "v1.0.0"
79-
update_changelog_on_bump = true
74+
update_changelog_on_bump = false
8075
major_version_zero = true
8176

8277
[tool.coverage.run]
@@ -92,6 +87,9 @@ check_untyped_defs = true
9287
ignore_missing_imports = true
9388
plugins = ["pandera.mypy", "pydantic.mypy"]
9489

90+
[tool.pytest.ini_options]
91+
addopts = "--verbosity=2"
92+
9593
[tool.ruff]
9694
fix = true
9795
line-length = 100
@@ -100,9 +98,6 @@ target-version = "py312"
10098
[tool.ruff.format]
10199
docstring-code-format = true
102100

103-
[tool.ruff.lint]
104-
select = ["D"]
105-
106101
[tool.ruff.lint.pydocstyle]
107102
convention = "google"
108103

src/bikes/core/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Core components of the project."""

src/bikes/metrics.py renamed to src/bikes/core/metrics.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Evaluate model performance with metrics."""
1+
"""Evaluate model performances with metrics."""
22

33
# %% IMPORTS
44

@@ -8,19 +8,19 @@
88
import pydantic as pdt
99
from sklearn import metrics
1010

11-
from bikes import models, schemas
11+
from bikes.core import models, schemas
1212

1313
# %% METRICS
1414

1515

16-
class Metric(abc.ABC, pdt.BaseModel, strict=True):
17-
"""Base class for a metric.
16+
class Metric(abc.ABC, pdt.BaseModel, strict=True, frozen=True, extra="forbid"):
17+
"""Base class for a project metric.
1818
1919
Use metrics to evaluate model performance.
2020
e.g., accuracy, precision, recall, MAE, F1, ...
2121
22-
Attributes:
23-
name (str): name of the metric.
22+
Parameters:
23+
name (str): name of the metric for the reporting.
2424
"""
2525

2626
KIND: str
@@ -36,31 +36,31 @@ def score(self, targets: schemas.Targets, outputs: schemas.Outputs) -> float:
3636
outputs (schemas.Outputs): predicted values.
3737
3838
Returns:
39-
float: single result for the metric computation.
39+
float: single result from the metric computation.
4040
"""
4141

4242
def scorer(
4343
self, model: models.Model, inputs: schemas.Inputs, targets: schemas.Targets
4444
) -> float:
45-
"""Score the model outputs against the targets.
45+
"""Score the model outputs against targets.
4646
4747
Args:
4848
model (models.Model): model to evaluate.
4949
inputs (schemas.Inputs): model inputs values.
5050
targets (schemas.Targets): model expected values.
5151
5252
Returns:
53-
float: metric result.
53+
float: single result from the metric computation.
5454
"""
55-
outputs = model.predict(inputs=inputs) # prediction
55+
outputs = model.predict(inputs=inputs)
5656
score = self.score(targets=targets, outputs=outputs)
5757
return score
5858

5959

6060
class SklearnMetric(Metric):
6161
"""Compute metrics with sklearn.
6262
63-
Attributes:
63+
Parameters:
6464
name (str): name of the sklearn metric.
6565
greater_is_better (bool): maximize or minimize.
6666
"""

src/bikes/models.py renamed to src/bikes/core/models.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,20 @@
88
import pydantic as pdt
99
from sklearn import compose, ensemble, pipeline, preprocessing
1010

11-
from bikes import schemas
11+
from bikes.core import schemas
1212

1313
# %% TYPES
1414

15+
# Model params
1516
ParamKey = str
1617
ParamValue = T.Any
1718
Params = dict[ParamKey, ParamValue]
1819

1920
# %% MODELS
2021

2122

22-
class Model(abc.ABC, pdt.BaseModel, strict=True):
23-
"""Base class for a model.
23+
class Model(abc.ABC, pdt.BaseModel, strict=True, frozen=False, extra="forbid"):
24+
"""Base class for a project model.
2425
2526
Use a model to adapt AI/ML frameworks.
2627
e.g., to swap easily one model with another.
@@ -32,7 +33,7 @@ def get_params(self, deep: bool = True) -> Params:
3233
"""Get the model params.
3334
3435
Args:
35-
deep (bool, optional): ignored. Defaults to True.
36+
deep (bool, optional): ignored.
3637
3738
Returns:
3839
Params: internal model parameters.
@@ -62,7 +63,7 @@ def fit(self, inputs: schemas.Inputs, targets: schemas.Targets) -> T.Self:
6263
targets (schemas.Targets): model training targets.
6364
6465
Returns:
65-
Model: instance of the model.
66+
T.Self: instance of the model.
6667
"""
6768

6869
@abc.abstractmethod
@@ -76,11 +77,22 @@ def predict(self, inputs: schemas.Inputs) -> schemas.Outputs:
7677
schemas.Outputs: model prediction outputs.
7778
"""
7879

80+
def get_internal_model(self) -> T.Any:
81+
"""Return the internal model in the object.
82+
83+
Raises:
84+
NotImplementedError: method not implemented.
85+
86+
Returns:
87+
T.Any: any internal model (either empty or fitted).
88+
"""
89+
raise NotImplementedError()
90+
7991

8092
class BaselineSklearnModel(Model):
81-
"""Simple baseline model with sklearn.
93+
"""Simple baseline model based on scikit-learn.
8294
83-
Attributes:
95+
Parameters:
8496
max_depth (int): maximum depth of the random forest.
8597
n_estimators (int): number of estimators in the random forest.
8698
random_state (int, optional): random state of the machine learning pipeline.
@@ -142,12 +154,19 @@ def fit(self, inputs: schemas.Inputs, targets: schemas.Targets) -> "BaselineSkle
142154

143155
@T.override
144156
def predict(self, inputs: schemas.Inputs) -> schemas.Outputs:
145-
assert self._pipeline is not None, "Model should be fitted first!"
146-
prediction = self._pipeline.predict(inputs) # return an np.ndarray
157+
model = self.get_internal_model()
158+
prediction = model.predict(inputs)
147159
outputs = schemas.Outputs(
148160
{schemas.OutputsSchema.prediction: prediction}, index=inputs.index
149161
)
150162
return outputs
151163

164+
@T.override
165+
def get_internal_model(self) -> pipeline.Pipeline:
166+
model = self._pipeline
167+
if model is None:
168+
raise ValueError("Model is not fitted yet!")
169+
return model
170+
152171

153172
ModelKind = BaselineSklearnModel

0 commit comments

Comments
 (0)