Files
mlflow--mlflow/tests/data/test_artifact_dataset_sources.py
2026-07-13 13:22:34 +08:00

138 lines
5.6 KiB
Python

import json
import os
from unittest import mock
import pytest
from mlflow.data.dataset_source_registry import get_dataset_source_from_json, resolve_dataset_source
from mlflow.data.filesystem_dataset_source import FileSystemDatasetSource
from mlflow.store.artifact.s3_artifact_repo import S3ArtifactRepository
@pytest.mark.parametrize(
("source_uri", "source_type", "source_class_name"),
[
("/tmp/path/to/my/local/file.txt", "local", "LocalArtifactDatasetSource"),
("file:///tmp/path/to/my/local/directory", "local", "LocalArtifactDatasetSource"),
("s3://mybucket/path/to/my/file.txt", "s3", "S3ArtifactDatasetSource"),
("gs://mybucket/path/to/my/dir", "gs", "GCSArtifactDatasetSource"),
("wasbs://user@host.blob.core.windows.net/dir", "wasbs", "AzureBlobArtifactDatasetSource"),
("ftp://mysite.com/path/to/my/file.txt", "ftp", "FTPArtifactDatasetSource"),
("sftp://mysite.com/path/to/my/dir", "sftp", "SFTPArtifactDatasetSource"),
("hdfs://host_name:8020/hdfs/path/to/my/file.txt", "hdfs", "HdfsArtifactDatasetSource"),
("viewfs://host_name:8020/path/to/my/dir", "viewfs", "HdfsArtifactDatasetSource"),
],
)
def test_expected_artifact_dataset_sources_are_registered_and_resolvable(
source_uri, source_type, source_class_name
):
dataset_source = resolve_dataset_source(source_uri)
assert isinstance(dataset_source, FileSystemDatasetSource)
assert dataset_source._get_source_type() == source_type
assert type(dataset_source).__name__ == source_class_name
assert type(dataset_source).__qualname__ == source_class_name
assert dataset_source.uri == source_uri
@pytest.mark.parametrize(
("source_uri", "source_type"),
[
("/tmp/path/to/my/local/file.txt", "local"),
("file:///tmp/path/to/my/local/directory", "local"),
("s3://mybucket/path/to/my/file.txt", "s3"),
("gs://mybucket/path/to/my/dir", "gs"),
("wasbs://user@host.blob.core.windows.net/dir", "wasbs"),
("ftp://mysite.com/path/to/my/file.txt", "ftp"),
("sftp://mysite.com/path/to/my/dir", "sftp"),
("hdfs://host_name:8020/hdfs/path/to/my/file.txt", "hdfs"),
("viewfs://host_name:8020/path/to/my/dir", "viewfs"),
],
)
def test_to_and_from_json(source_uri, source_type):
dataset_source = resolve_dataset_source(source_uri)
assert dataset_source._get_source_type() == source_type
source_json = dataset_source.to_json()
parsed_source_json = json.loads(source_json)
assert parsed_source_json["uri"] == source_uri
reloaded_source = get_dataset_source_from_json(
source_json, source_type=dataset_source._get_source_type()
)
assert isinstance(reloaded_source, FileSystemDatasetSource)
assert type(dataset_source) == type(reloaded_source)
assert reloaded_source.uri == dataset_source.uri
@pytest.mark.parametrize(
("source_uri", "source_type"),
[
("/tmp/path/to/my/local/file.txt", "local"),
("file:///tmp/path/to/my/local/directory", "local"),
("s3://mybucket/path/to/my/file.txt", "s3"),
("gs://mybucket/path/to/my/dir", "gs"),
("wasbs://user@host.blob.core.windows.net/dir", "wasbs"),
("ftp://mysite.com/path/to/my/file.txt", "ftp"),
("sftp://mysite.com/path/to/my/dir", "sftp"),
("hdfs://host_name:8020/hdfs/path/to/my/file.txt", "hdfs"),
("viewfs://host_name:8020/path/to/my/dir", "viewfs"),
],
)
def test_load_makes_expected_mlflow_artifacts_download_call(source_uri, source_type, tmp_path):
dataset_source = resolve_dataset_source(source_uri)
assert dataset_source._get_source_type() == source_type
with mock.patch("mlflow.artifacts.download_artifacts") as download_imp_mock:
dataset_source.load()
download_imp_mock.assert_called_once_with(artifact_uri=source_uri, dst_path=None)
with mock.patch("mlflow.artifacts.download_artifacts") as download_imp_mock:
dataset_source.load(dst_path=str(tmp_path))
download_imp_mock.assert_called_once_with(artifact_uri=source_uri, dst_path=str(tmp_path))
@pytest.mark.parametrize("dst_path", [None, "dst"])
def test_local_load(dst_path, tmp_path):
if dst_path is not None:
dst_path = str(tmp_path / dst_path)
# Test string file paths
file_path = str(tmp_path / "myfile.txt")
with open(file_path, "w") as f:
f.write("text")
file_dataset_source = resolve_dataset_source(file_path)
assert file_dataset_source._get_source_type() == "local"
assert file_dataset_source.load(dst_path=dst_path) == dst_path or file_path
with open(file_path) as f:
assert f.read() == "text"
# Test directory paths with pathlib.Path
dir_path = tmp_path / "mydir"
os.makedirs(dir_path)
dir_dataset_source = resolve_dataset_source(dir_path)
assert file_dataset_source._get_source_type() == "local"
assert dir_dataset_source.load() == dst_path or str(dir_path)
@pytest.mark.parametrize("dst_path", [None, "dst"])
def test_s3_load(mock_s3_bucket, dst_path, tmp_path):
if dst_path is not None:
dst_path = str(tmp_path / dst_path)
file_path = str(tmp_path / "myfile.txt")
with open(file_path, "w") as f:
f.write("text")
S3ArtifactRepository(f"s3://{mock_s3_bucket}").log_artifact(file_path)
s3_source_uri = f"s3://{mock_s3_bucket}/myfile.txt"
s3_dataset_source = resolve_dataset_source(s3_source_uri)
assert s3_dataset_source._get_source_type() == "s3"
downloaded_source = s3_dataset_source.load(dst_path=dst_path)
if dst_path is not None:
assert downloaded_source == os.path.join(dst_path, "myfile.txt")
with open(downloaded_source) as f:
assert f.read() == "text"