Skip to content

Commit 6bacb4b

Browse files
authored
ODSC-50649/raise ValueError when inference_python_version cannot be resolved (#496)
1 parent 63da499 commit 6bacb4b

File tree

4 files changed

+58
-40
lines changed

4 files changed

+58
-40
lines changed

ads/model/artifact.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,9 @@ def prepare_runtime_yaml(
273273
or runtime_info.model_deployment.inference_conda_env.inference_python_version.strip()
274274
== ""
275275
):
276-
warnings.warn(
277-
"Cannot automatically detect the inference python version. `inference_python_version` must be provided."
276+
raise ValueError(
277+
"Cannot automatically detect the inference python version. "
278+
"`inference_python_version` must be provided."
278279
)
279280
runtime_file_path = os.path.join(self.artifact_dir, "runtime.yaml")
280281
if os.path.exists(runtime_file_path) and not force_overwrite:

ads/model/generic_model.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -966,17 +966,20 @@ def prepare(
966966
auth=self.auth,
967967
local_copy_dir=self.local_copy_dir,
968968
)
969-
self.runtime_info = self.model_artifact.prepare_runtime_yaml(
970-
inference_conda_env=self.properties.inference_conda_env,
971-
inference_python_version=self.properties.inference_python_version,
972-
training_conda_env=self.properties.training_conda_env,
973-
training_python_version=self.properties.training_python_version,
974-
force_overwrite=force_overwrite,
975-
namespace=namespace,
976-
bucketname=DEFAULT_CONDA_BUCKET_NAME,
977-
auth=self.auth,
978-
ignore_conda_error=self.ignore_conda_error,
979-
)
969+
try:
970+
self.runtime_info = self.model_artifact.prepare_runtime_yaml(
971+
inference_conda_env=self.properties.inference_conda_env,
972+
inference_python_version=self.properties.inference_python_version,
973+
training_conda_env=self.properties.training_conda_env,
974+
training_python_version=self.properties.training_python_version,
975+
force_overwrite=force_overwrite,
976+
namespace=namespace,
977+
bucketname=DEFAULT_CONDA_BUCKET_NAME,
978+
auth=self.auth,
979+
ignore_conda_error=self.ignore_conda_error,
980+
)
981+
except ValueError as e:
982+
raise e
980983

981984
self._summary_status.update_status(
982985
detail="Generated runtime.yaml", status=ModelState.DONE.value

ads/model/runtime/env_info.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def from_slug(
106106
env_path, python_version = service_pack_slug_mapping[env_slug]
107107
else:
108108
warnings.warn(
109-
"The {env_slug} is not a service pack. Use `from_path` method by passing in the object storage path."
109+
f"The {env_slug} is not a service pack. Use `from_path` method by passing in the object storage path."
110110
)
111111

112112
return cls._populate_env_info(
@@ -157,9 +157,13 @@ def from_path(cls, env_path: str, auth: dict = None) -> "EnvInfo":
157157
).fetch_metadata_of_object()
158158
python_version = metadata_json.get("python", None)
159159
env_slug = metadata_json.get("slug", None)
160+
if not python_version:
161+
raise ValueError(
162+
f"The manifest metadata of {env_path} doesn't contains inforamtion for python version."
163+
)
160164
except Exception as e:
161-
logging.warning(e)
162-
logging.warning(
165+
logging.debug(e)
166+
logging.debug(
163167
"python version and slug are not found from the manifest metadata."
164168
)
165169

@@ -227,7 +231,7 @@ def _populate_env_info(
227231
)
228232

229233
@classmethod
230-
def _validate_dict(cls,obj_dict: Dict) -> bool:
234+
def _validate_dict(cls, obj_dict: Dict) -> bool:
231235
"""Validate the content in the dictionary format from the yaml file.
232236
233237
Parameters

tests/unitary/with_extras/model/test_generic_model.py

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,36 +6,38 @@
66
"""Unit tests for model frameworks. Includes tests for:
77
- GenericModel
88
"""
9+
import glob
910
import os
1011
import random
1112
import shutil
12-
from copy import copy
13-
import glob
1413
import tempfile
14+
from copy import copy
1515
from unittest.mock import MagicMock, PropertyMock, patch
16+
from zipfile import ZipFile
1617

18+
import numpy as np
1719
import pandas as pd
1820
import pytest
1921
import yaml
20-
import numpy as np
22+
from joblib import dump
23+
from oci.data_science.models.model_provenance import ModelProvenance
24+
from sklearn.datasets import load_iris
25+
from sklearn.ensemble import RandomForestClassifier
26+
from sklearn.model_selection import train_test_split
27+
2128
from ads.common import utils
22-
from ads.config import (
23-
JOB_RUN_COMPARTMENT_OCID,
24-
NB_SESSION_COMPARTMENT_OCID,
25-
)
29+
from ads.common.object_storage_details import ObjectStorageDetails
30+
from ads.config import JOB_RUN_COMPARTMENT_OCID, NB_SESSION_COMPARTMENT_OCID
2631
from ads.model.artifact import ModelArtifact
32+
from ads.model.datascience_model import DataScienceModel, OCIDataScienceModel
2733
from ads.model.deployment import (
28-
DEFAULT_POLL_INTERVAL,
29-
DEFAULT_WAIT_TIME,
3034
ModelDeployer,
3135
ModelDeployment,
36+
ModelDeploymentContainerRuntime,
37+
ModelDeploymentInfrastructure,
3238
ModelDeploymentProperties,
3339
)
3440
from ads.model.deployment.common.utils import State as ModelDeploymentState
35-
from ads.model.deployment import (
36-
ModelDeploymentInfrastructure,
37-
ModelDeploymentContainerRuntime,
38-
)
3941
from ads.model.generic_model import (
4042
_ATTRIBUTES_TO_SHOW_,
4143
GenericModel,
@@ -45,14 +47,6 @@
4547
)
4648
from ads.model.model_properties import ModelProperties
4749
from ads.model.runtime.runtime_info import RuntimeInfo
48-
from ads.model.datascience_model import DataScienceModel, OCIDataScienceModel
49-
from joblib import dump
50-
from oci.data_science.models.model_provenance import ModelProvenance
51-
from sklearn.datasets import load_iris
52-
from sklearn.ensemble import RandomForestClassifier
53-
from sklearn.model_selection import train_test_split
54-
from zipfile import ZipFile
55-
from ads.model.deployment.common.utils import State
5650

5751
try:
5852
from yaml import CDumper as dumper
@@ -279,6 +273,21 @@ def test_prepare_fail(self, mock_handle_model_file_name):
279273
"oci://service-conda-packs@ociodscdev/service_pack/cpu/General_Machine_Learning_for_CPUs/1.0/mlcpuv1"
280274
)
281275

276+
@patch.object(
277+
ObjectStorageDetails,
278+
"fetch_metadata_of_object",
279+
side_effect=Exception("Connection Error."),
280+
)
281+
def test_prepare_fail_missing_python_version_field(
282+
self, mock_fetch_metadata_of_object
283+
):
284+
"""Ensures that prepare method fails in case if python version not provided and cannot be resolved automatically."""
285+
with pytest.raises(
286+
ValueError,
287+
match="Cannot automatically detect the inference python version. `inference_python_version` must be provided.",
288+
):
289+
self.generic_model.prepare(inference_conda_env=INFERENCE_CONDA_ENV)
290+
282291
@patch("ads.model.runtime.env_info.get_service_packs")
283292
@patch("ads.common.auth.default_signer")
284293
def test_prepare_both_conda_env(self, mock_signer, mock_get_service_packs):
@@ -332,7 +341,8 @@ def test_prepare_both_conda_env(self, mock_signer, mock_get_service_packs):
332341
def test_prepare_with_custom_scorepy(self, mock_signer):
333342
"""Test prepare a trained model with custom score.py."""
334343
self.generic_model.prepare(
335-
INFERENCE_CONDA_ENV,
344+
inference_conda_env=INFERENCE_CONDA_ENV,
345+
inference_python_version=DEFAULT_PYTHON_VERSION,
336346
model_file_name="fake_model_name",
337347
score_py_uri=f"{os.path.dirname(os.path.abspath(__file__))}/test_files/custom_score.py",
338348
)
@@ -467,11 +477,11 @@ def test_save_not_reload(
467477

468478
def test_set_model_input_serializer(self):
469479
"""Tests set_model_input_serializer() with different input types."""
480+
from ads.model.serde.common import SERDE
470481
from ads.model.serde.model_input import (
471482
CloudpickleModelInputSERDE,
472483
JsonModelInputSERDE,
473484
)
474-
from ads.model.serde.common import SERDE
475485

476486
generic_model = GenericModel(estimator=self.clr, artifact_dir="fake_folder")
477487
# set by passing str

0 commit comments

Comments
 (0)