Files
2026-07-13 13:22:34 +08:00

258 lines
9.2 KiB
Python

import json
import numpy as np
import pandas as pd
import pytest
import mlflow.data
from mlflow.data.code_dataset_source import CodeDatasetSource
from mlflow.data.evaluation_dataset import EvaluationDataset
from mlflow.data.filesystem_dataset_source import FileSystemDatasetSource
from mlflow.data.numpy_dataset import NumpyDataset
from mlflow.data.pyfunc_dataset_mixin import PyFuncInputsOutputs
from mlflow.data.schema import TensorDatasetSchema
from mlflow.types.utils import _infer_schema
from tests.resources.data.dataset_source import SampleDatasetSource
def test_conversion_to_json():
source_uri = "test:/my/test/uri"
source = SampleDatasetSource._resolve(source_uri)
dataset = NumpyDataset(features=np.array([1, 2, 3]), source=source, name="testname")
dataset_json = dataset.to_json()
parsed_json = json.loads(dataset_json)
assert parsed_json.keys() <= {"name", "digest", "source", "source_type", "schema", "profile"}
assert parsed_json["name"] == dataset.name
assert parsed_json["digest"] == dataset.digest
assert parsed_json["source"] == dataset.source.to_json()
assert parsed_json["source_type"] == dataset.source._get_source_type()
assert parsed_json["profile"] == json.dumps(dataset.profile)
parsed_schema = json.loads(parsed_json["schema"])
assert TensorDatasetSchema.from_dict(parsed_schema) == dataset.schema
@pytest.mark.parametrize(
("features", "targets"),
[
(
{
"a": np.array([1, 2, 3]),
"b": np.array([[4, 5]]),
},
{
"c": np.array([1]),
"d": np.array([[[2]]]),
},
),
(
np.array([1, 2, 3]),
{
"c": np.array([1]),
"d": np.array([[[2]]]),
},
),
(
{
"a": np.array([1, 2, 3]),
"b": np.array([[4, 5]]),
},
np.array([1, 2, 3]),
),
],
)
def test_conversion_to_json_with_multi_tensor_features_and_targets(features, targets):
source_uri = "test:/my/test/uri"
source = SampleDatasetSource._resolve(source_uri)
dataset = NumpyDataset(features=features, targets=targets, source=source)
dataset_json = dataset.to_json()
parsed_json = json.loads(dataset_json)
assert parsed_json.keys() <= {"name", "digest", "source", "source_type", "schema", "profile"}
assert parsed_json["name"] == dataset.name
assert parsed_json["digest"] == dataset.digest
assert parsed_json["source"] == dataset.source.to_json()
assert parsed_json["source_type"] == dataset.source._get_source_type()
assert parsed_json["profile"] == json.dumps(dataset.profile)
parsed_schema = json.loads(parsed_json["schema"])
assert TensorDatasetSchema.from_dict(parsed_schema) == dataset.schema
@pytest.mark.parametrize(
("features", "targets"),
[
(
{
"a": np.array([1, 2, 3]),
"b": np.array([[4, 5]]),
},
{
"c": np.array([1]),
"d": np.array([[[2]]]),
},
),
(
np.array([1, 2, 3]),
{
"c": np.array([1]),
"d": np.array([[[2]]]),
},
),
(
{
"a": np.array([1, 2, 3]),
"b": np.array([[4, 5]]),
},
np.array([1, 2, 3]),
),
],
)
def test_schema_and_profile_with_multi_tensor_features_and_targets(features, targets):
source_uri = "test:/my/test/uri"
source = SampleDatasetSource._resolve(source_uri)
dataset = NumpyDataset(features=features, targets=targets, source=source)
assert isinstance(dataset.schema, TensorDatasetSchema)
assert dataset.schema.features == _infer_schema(features)
assert dataset.schema.targets == _infer_schema(targets)
if isinstance(features, dict):
assert {
"features_shape": {key: array.shape for key, array in features.items()},
"features_size": {key: array.size for key, array in features.items()},
"features_nbytes": {key: array.nbytes for key, array in features.items()},
}.items() <= dataset.profile.items()
else:
assert {
"features_shape": features.shape,
"features_size": features.size,
"features_nbytes": features.nbytes,
}.items() <= dataset.profile.items()
if isinstance(targets, dict):
assert {
"targets_shape": {key: array.shape for key, array in targets.items()},
"targets_size": {key: array.size for key, array in targets.items()},
"targets_nbytes": {key: array.nbytes for key, array in targets.items()},
}.items() <= dataset.profile.items()
else:
assert {
"targets_shape": targets.shape,
"targets_size": targets.size,
"targets_nbytes": targets.nbytes,
}.items() <= dataset.profile.items()
def test_digest_property_has_expected_value():
source_uri = "test:/my/test/uri"
source = SampleDatasetSource._resolve(source_uri)
features = np.array([1, 2, 3])
targets = np.array([4, 5, 6])
dataset_with_features = NumpyDataset(features=features, source=source, name="testname")
assert dataset_with_features.digest == dataset_with_features._compute_digest()
assert dataset_with_features.digest == "fdf1765f"
dataset_with_features_and_targets = NumpyDataset(
features=features, targets=targets, source=source, name="testname"
)
assert (
dataset_with_features_and_targets.digest
== dataset_with_features_and_targets._compute_digest()
)
assert dataset_with_features_and_targets.digest == "1387de76"
def test_features_property():
source_uri = "test:/my/test/uri"
source = SampleDatasetSource._resolve(source_uri)
features = np.array([1, 2, 3])
dataset = NumpyDataset(features=features, source=source, name="testname")
assert np.array_equal(dataset.features, features)
def test_targets_property():
source_uri = "test:/my/test/uri"
source = SampleDatasetSource._resolve(source_uri)
features = np.array([1, 2, 3])
targets = np.array([4, 5, 6])
dataset_with_targets = NumpyDataset(
features=features, targets=targets, source=source, name="testname"
)
assert np.array_equal(dataset_with_targets.targets, targets)
dataset_without_targets = NumpyDataset(features=features, source=source, name="testname")
assert dataset_without_targets.targets is None
def test_to_pyfunc():
source_uri = "test:/my/test/uri"
source = SampleDatasetSource._resolve(source_uri)
features = np.array([1, 2, 3])
dataset = NumpyDataset(features=features, source=source, name="testname")
assert isinstance(dataset.to_pyfunc(), PyFuncInputsOutputs)
def test_to_evaluation_dataset():
source_uri = "test:/my/test/uri"
source = SampleDatasetSource._resolve(source_uri)
features = np.array([[1, 2], [3, 4]])
targets = np.array([0, 1])
dataset = NumpyDataset(features=features, targets=targets, source=source, name="testname")
evaluation_dataset = dataset.to_evaluation_dataset()
assert isinstance(evaluation_dataset, EvaluationDataset)
assert np.array_equal(evaluation_dataset.features_data, features)
assert np.array_equal(evaluation_dataset.labels_data, targets)
def test_from_numpy_features_only(tmp_path):
features = np.array([1, 2, 3])
path = tmp_path / "temp.csv"
pd.DataFrame(features).to_csv(path)
mlflow_features = mlflow.data.from_numpy(features, source=path)
assert isinstance(mlflow_features, NumpyDataset)
assert np.array_equal(mlflow_features.features, features)
assert mlflow_features.schema == TensorDatasetSchema(features=_infer_schema(features))
assert mlflow_features.profile == {
"features_shape": features.shape,
"features_size": features.size,
"features_nbytes": features.nbytes,
}
assert isinstance(mlflow_features.source, FileSystemDatasetSource)
def test_from_numpy_features_and_targets(tmp_path):
features = np.array([[1, 2, 3], [3, 2, 1], [2, 3, 1]])
targets = np.array([4, 5, 6])
path = tmp_path / "temp.csv"
pd.DataFrame(features).to_csv(path)
mlflow_ds = mlflow.data.from_numpy(features, targets=targets, source=path)
assert isinstance(mlflow_ds, NumpyDataset)
assert np.array_equal(mlflow_ds.features, features)
assert np.array_equal(mlflow_ds.targets, targets)
assert mlflow_ds.schema == TensorDatasetSchema(
features=_infer_schema(features), targets=_infer_schema(targets)
)
assert mlflow_ds.profile == {
"features_shape": features.shape,
"features_size": features.size,
"features_nbytes": features.nbytes,
"targets_shape": targets.shape,
"targets_size": targets.size,
"targets_nbytes": targets.nbytes,
}
assert isinstance(mlflow_ds.source, FileSystemDatasetSource)
def test_from_numpy_no_source_specified():
features = np.array([1, 2, 3])
mlflow_features = mlflow.data.from_numpy(features)
assert isinstance(mlflow_features, NumpyDataset)
assert isinstance(mlflow_features.source, CodeDatasetSource)
assert "mlflow.source.name" in mlflow_features.source.to_json()