From 1f9cba1e34452e0566d8617c76d7281b20514f17 Mon Sep 17 00:00:00 2001 From: Andrey Tatarinov Date: Wed, 29 Jul 2026 16:48:32 +0400 Subject: [PATCH] fix tests in vscode --- .vscode/settings.json | 6 ++-- libs/datapipe-app/tests/__init__.py | 0 libs/datapipe-cvat/tests/__init__.py | 0 .../tests/test_simple_project_example.py | 3 +- .../tests/test_pipeline.py | 14 ++++---- .../tests/test_pipeline_many_projects.py | 14 ++++---- libs/datapipe-ml/tests/conftest.py | 6 ++-- .../tests/helpers/checkpoint_kill9.py | 2 +- libs/datapipe-ml/tests/helpers/cloud_smoke.py | 2 +- .../tests/helpers/failure_injection.py | 11 +++--- .../tests/helpers/recovery_pipe_runner.py | 11 +++--- .../tests/helpers/training_recovery.py | 14 ++++---- .../helpers/training_recovery_tensorflow.py | 5 +-- .../tests/helpers/training_smoke.py | 35 +++++++++++++------ libs/datapipe-ml/tests/test_app_smoke.py | 2 +- .../datapipe-ml/tests/test_data_generation.py | 4 +-- .../datapipe-ml/tests/test_freeze_datasets.py | 2 +- .../tests/test_task_classification.py | 2 +- libs/datapipe-ml/tests/test_task_detection.py | 4 +-- libs/datapipe-ml/tests/test_task_keypoints.py | 4 +-- .../tests/test_task_segmentation.py | 2 +- .../test_task_training_local_checkpoint.py | 4 +-- .../tests/test_training_checkpoint_atomic.py | 20 ++++++----- .../tests/test_training_cloud_storage.py | 17 +++++---- ...st_training_recovery_real_architectures.py | 6 ++-- .../tests/test_training_recovery_sky_vast.py | 8 ++--- .../test_training_recovery_stale_lease.py | 4 +-- .../tests/test_training_sky_vast.py | 26 ++++++-------- pyproject.toml | 8 +++-- 29 files changed, 124 insertions(+), 112 deletions(-) create mode 100644 libs/datapipe-app/tests/__init__.py create mode 100644 libs/datapipe-cvat/tests/__init__.py diff --git a/.vscode/settings.json b/.vscode/settings.json index 4af85ef7d..0d39e833b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,6 @@ { - "python.testing.pytestArgs": [ - ".", - "--ignore=test_data" - ], + "python.testing.pytestArgs": [], + "python.testing.cwd": "${workspaceFolder}", "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, "python.analysis.extraPaths": [ diff --git a/libs/datapipe-app/tests/__init__.py b/libs/datapipe-app/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/libs/datapipe-cvat/tests/__init__.py b/libs/datapipe-cvat/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/libs/datapipe-cvat/tests/test_simple_project_example.py b/libs/datapipe-cvat/tests/test_simple_project_example.py index 61d020a6f..157904407 100644 --- a/libs/datapipe-cvat/tests/test_simple_project_example.py +++ b/libs/datapipe-cvat/tests/test_simple_project_example.py @@ -14,8 +14,7 @@ from datapipe_cvat.cvat_step import create_cvat_client from PIL import Image -from test_cvat_integration import _require_cvat - +from .test_cvat_integration import _require_cvat pytestmark = pytest.mark.cvat diff --git a/libs/datapipe-label-studio/tests/test_pipeline.py b/libs/datapipe-label-studio/tests/test_pipeline.py index e422d147e..407f49415 100644 --- a/libs/datapipe-label-studio/tests/test_pipeline.py +++ b/libs/datapipe-label-studio/tests/test_pipeline.py @@ -10,17 +10,17 @@ from datapipe.step.datatable_transform import DatatableTransformStep from datapipe.store.database import TableStoreDB from datapipe.types import data_to_index -from label_studio_sdk import LabelStudio -from pytest_cases import parametrize, parametrize_with_cases -from sqlalchemy.sql.schema import Column -from sqlalchemy.sql.sqltypes import JSON, String - from datapipe_label_studio.sdk_utils import get_project_by_title from datapipe_label_studio.upload_predictions_pipeline import ( LabelStudioUploadPredictions, ) from datapipe_label_studio.upload_tasks_pipeline import LabelStudioUploadTasks -from tests.ls_test_helpers import ( +from label_studio_sdk import LabelStudio +from pytest_cases import parametrize, parametrize_with_cases +from sqlalchemy.sql.schema import Column +from sqlalchemy.sql.sqltypes import JSON, String + +from .ls_test_helpers import ( DELETE_UNANNOTATED_TASKS_ONLY_ON_UPDATE, INCLUDE_PARAMS, INCLUDE_PREDICTIONS, @@ -30,7 +30,7 @@ convert_to_ls_input_data, wrapped_partial, ) -from tests.util import get_project_id, get_project_tasks, wait_until_label_studio_is_up +from .util import get_project_id, get_project_tasks, wait_until_label_studio_is_up def gen_data_df(): diff --git a/libs/datapipe-label-studio/tests/test_pipeline_many_projects.py b/libs/datapipe-label-studio/tests/test_pipeline_many_projects.py index 0733a69bc..28bdfe700 100644 --- a/libs/datapipe-label-studio/tests/test_pipeline_many_projects.py +++ b/libs/datapipe-label-studio/tests/test_pipeline_many_projects.py @@ -9,11 +9,6 @@ from datapipe.step.batch_transform import BatchTransform from datapipe.step.datatable_transform import DatatableTransformStep from datapipe.store.database import TableStoreDB -from label_studio_sdk import LabelStudio -from pytest_cases import parametrize, parametrize_with_cases -from sqlalchemy.sql.schema import Column -from sqlalchemy.sql.sqltypes import JSON, String - from datapipe_label_studio.create_projects_step import CreateLabelStudioProjects from datapipe_label_studio.sdk_utils import get_project_by_title from datapipe_label_studio.upload_predictions_pipeline import ( @@ -22,7 +17,12 @@ from datapipe_label_studio.upload_tasks_pipeline import ( LabelStudioUploadTasksToProjects, ) -from tests.ls_test_helpers import ( +from label_studio_sdk import LabelStudio +from pytest_cases import parametrize, parametrize_with_cases +from sqlalchemy.sql.schema import Column +from sqlalchemy.sql.sqltypes import JSON, String + +from .ls_test_helpers import ( DELETE_UNANNOTATED_TASKS_ONLY_ON_UPDATE, INCLUDE_PARAMS, INCLUDE_PREDICTIONS, @@ -32,7 +32,7 @@ convert_to_ls_input_data, wrapped_partial, ) -from tests.util import get_project_id, get_project_tasks, wait_until_label_studio_is_up +from .util import get_project_id, get_project_tasks, wait_until_label_studio_is_up def gen_ls_project_setting(): diff --git a/libs/datapipe-ml/tests/conftest.py b/libs/datapipe-ml/tests/conftest.py index 319209990..a1ee52d77 100644 --- a/libs/datapipe-ml/tests/conftest.py +++ b/libs/datapipe-ml/tests/conftest.py @@ -2,7 +2,7 @@ os.environ["SQLALCHEMY_WARN_20"] = "1" -from tests.helpers.test_env import load_test_env +from .helpers.test_env import load_test_env load_test_env() @@ -13,8 +13,8 @@ from sqlalchemy import Column, create_engine, text from sqlalchemy.sql.sqltypes import JSON, String -from tests.fixtures.smoke_data import SmokeDataset, make_smoke_dataset -from tests.helpers.dbconn import get_sqlite_dbconnstr +from .fixtures.smoke_data import SmokeDataset, make_smoke_dataset +from .helpers.dbconn import get_sqlite_dbconnstr @pytest.fixture( diff --git a/libs/datapipe-ml/tests/helpers/checkpoint_kill9.py b/libs/datapipe-ml/tests/helpers/checkpoint_kill9.py index bb8282a48..599040d4c 100644 --- a/libs/datapipe-ml/tests/helpers/checkpoint_kill9.py +++ b/libs/datapipe-ml/tests/helpers/checkpoint_kill9.py @@ -6,7 +6,7 @@ import time from pathlib import Path -from tests.helpers.checkpoint_fixtures import write_corrupt_zip_checkpoint, write_valid_zip_checkpoint +from .checkpoint_fixtures import write_corrupt_zip_checkpoint, write_valid_zip_checkpoint def _child_atomic_save_before_replace(checkpoint_path: str, ready_queue: mp.Queue) -> None: diff --git a/libs/datapipe-ml/tests/helpers/cloud_smoke.py b/libs/datapipe-ml/tests/helpers/cloud_smoke.py index a79c8e813..8e577390e 100644 --- a/libs/datapipe-ml/tests/helpers/cloud_smoke.py +++ b/libs/datapipe-ml/tests/helpers/cloud_smoke.py @@ -5,7 +5,7 @@ import pytest -from tests.helpers.training_smoke import ( +from .training_smoke import ( Workdir, classification_freeze_step, classification_train_step, diff --git a/libs/datapipe-ml/tests/helpers/failure_injection.py b/libs/datapipe-ml/tests/helpers/failure_injection.py index 901553655..778ad4767 100644 --- a/libs/datapipe-ml/tests/helpers/failure_injection.py +++ b/libs/datapipe-ml/tests/helpers/failure_injection.py @@ -7,22 +7,23 @@ from typing import TYPE_CHECKING import pytest - from datapipe_ml.frameworks.yolo.checkpoint_sync import max_completed_epoch_from_run_dir from datapipe_ml.training.sync import manifest_path_for_run, read_checkpoint_manifest -from tests.helpers.failure_injection_bootstrap import ( +from .failure_injection_bootstrap import ( FAIL_AFTER_EPOCH_ENV, FAIL_MODE_ENV, checkpoint_for_epoch_exists, configured_fail_after_epoch, configured_fail_mode, - install_training_failure_hooks as _install_training_failure_hooks, install_training_failure_hooks_direct, maybe_fail_after_epoch, run_dir_for_pipe_death_poll, run_training_with_failure_hooks, ) +from .failure_injection_bootstrap import ( + install_training_failure_hooks as _install_training_failure_hooks, +) if TYPE_CHECKING: from _pytest.monkeypatch import MonkeyPatch @@ -68,9 +69,7 @@ def _spawn_with_pipe_death(target, *args): # noqa: ANN001 except queue.Empty: if not p.is_alive(): p.join() - raise RuntimeError( - f"Training subprocess exited before returning a result. exitcode={p.exitcode}" - ) + raise RuntimeError(f"Training subprocess exited before returning a result. exitcode={p.exitcode}") run_dir = run_dir_for_pipe_death_poll() if fail_after is not None and run_dir and _pipe_death_checkpoint_ready(run_dir, fail_after): if p.is_alive(): diff --git a/libs/datapipe-ml/tests/helpers/recovery_pipe_runner.py b/libs/datapipe-ml/tests/helpers/recovery_pipe_runner.py index 2d54ff1f2..fb6bdf01b 100644 --- a/libs/datapipe-ml/tests/helpers/recovery_pipe_runner.py +++ b/libs/datapipe-ml/tests/helpers/recovery_pipe_runner.py @@ -28,15 +28,16 @@ def main(argv: list[str] | None = None) -> int: if args.phase == "train": _install_short_lease_status_manager() - from tests.helpers.failure_injection import install_pipe_death_hooks_direct - from tests.helpers.failure_injection_bootstrap import WORK_DIR_ENV - from tests.helpers.training_recovery import ( + from datapipe.compute import Pipeline, build_compute, run_steps + + from .failure_injection import install_pipe_death_hooks_direct + from .failure_injection_bootstrap import WORK_DIR_ENV + from .training_recovery import ( configure_recovery_steps, make_recovery_runtime, recovery_case_by_id, ) - from datapipe.compute import Pipeline, build_compute, run_steps - from tests.helpers.training_smoke import run_pipeline + from .training_smoke import run_pipeline os.environ[WORK_DIR_ENV] = str(workdir) diff --git a/libs/datapipe-ml/tests/helpers/training_recovery.py b/libs/datapipe-ml/tests/helpers/training_recovery.py index 97f54dd12..9ad6d41da 100644 --- a/libs/datapipe-ml/tests/helpers/training_recovery.py +++ b/libs/datapipe-ml/tests/helpers/training_recovery.py @@ -13,16 +13,16 @@ import pytest from datapipe.compute import Pipeline, PipelineStep, build_compute from datapipe.types import IndexDF - +from datapipe_ml.frameworks.yolo.checkpoint_sync import max_completed_epoch_from_run_dir from datapipe_ml.training.runs import active_lease from datapipe_ml.training.specs import TrainingResumeConfig, TrainingSyncConfig -from datapipe_ml.frameworks.yolo.checkpoint_sync import max_completed_epoch_from_run_dir from datapipe_ml.training.sync import ( manifest_path_for_run, read_checkpoint_manifest, verify_manifest_checkpoint, ) -from tests.helpers.training_smoke import ( + +from .training_smoke import ( SmokeRuntime, Workdir, detection_freeze_step, @@ -230,7 +230,7 @@ def real_recovery_cases() -> list: def recovery_case_by_id(case_id: str) -> RealRecoveryCase: if case_id in TENSORFLOW_RECOVERY_CASE_IDS: - from tests.helpers.training_recovery_tensorflow import recovery_tensorflow_case_by_id + from .training_recovery_tensorflow import recovery_tensorflow_case_by_id return recovery_tensorflow_case_by_id(case_id) for param in real_recovery_torch_cases(): @@ -242,7 +242,7 @@ def recovery_case_by_id(case_id: str) -> RealRecoveryCase: def recovery_extra_step_configure(case: RealRecoveryCase) -> dict[type, StepConfigureFn] | None: if case.id in TENSORFLOW_RECOVERY_CASE_IDS: - from tests.helpers.training_recovery_tensorflow import tensorflow_step_configure + from .training_recovery_tensorflow import tensorflow_step_configure return tensorflow_step_configure() return None @@ -330,7 +330,7 @@ def make_recovery_runtime( tmp_path: Path, case: RealRecoveryCase, *, working_dir: Workdir | None = None ) -> tuple[SmokeRuntime, list]: if case.id in TENSORFLOW_RECOVERY_CASE_IDS: - from tests.helpers.training_recovery_tensorflow import make_recovery_runtime as make_tf_recovery_runtime + from .training_recovery_tensorflow import make_recovery_runtime as make_tf_recovery_runtime return make_tf_recovery_runtime(tmp_path, case, working_dir=working_dir) workdir = working_dir if working_dir is not None else tmp_path @@ -499,7 +499,7 @@ def invoke_real_train_callable_for_backfill( step: RecoveryTrainStep, ) -> None: if case.id in TENSORFLOW_RECOVERY_CASE_IDS: - from tests.helpers.training_recovery_tensorflow import ( + from .training_recovery_tensorflow import ( invoke_real_train_callable_for_backfill as invoke_tf_backfill, ) diff --git a/libs/datapipe-ml/tests/helpers/training_recovery_tensorflow.py b/libs/datapipe-ml/tests/helpers/training_recovery_tensorflow.py index 65771eb24..9a1f9b75b 100644 --- a/libs/datapipe-ml/tests/helpers/training_recovery_tensorflow.py +++ b/libs/datapipe-ml/tests/helpers/training_recovery_tensorflow.py @@ -7,7 +7,7 @@ import pytest from datapipe.types import IndexDF -from tests.helpers.training_recovery import ( +from .training_recovery import ( TENSORFLOW_RECOVERY_CASE_IDS, RealRecoveryCase, RecoveryTrainStep, @@ -19,12 +19,13 @@ direct_train_kwargs, make_runtime, ) -from tests.helpers.training_smoke import Workdir, classification_freeze_step, classification_train_step +from .training_smoke import Workdir, classification_freeze_step, classification_train_step if TYPE_CHECKING: from datapipe_ml.frameworks.tensorflow.classification_runner import TF_ClassificationTrainingConfig from datapipe_ml.tasks.classification.train.tensorflow import Train_Tensorflow_ClassificationModel + def _configure_tf_configs(configs: list[TF_ClassificationTrainingConfig], epochs: int) -> None: for config in configs: config.epochs = epochs diff --git a/libs/datapipe-ml/tests/helpers/training_smoke.py b/libs/datapipe-ml/tests/helpers/training_smoke.py index 98cc4ac37..5bbab0343 100644 --- a/libs/datapipe-ml/tests/helpers/training_smoke.py +++ b/libs/datapipe-ml/tests/helpers/training_smoke.py @@ -8,7 +8,7 @@ from pathlib import Path, PurePosixPath from typing import Iterable -from tests.helpers.cloud_storage import ( +from .cloud_storage import ( assert_model_path_under_working_dir, assert_url_exists, is_cloud_url, @@ -18,8 +18,8 @@ Workdir = str | Path -import pandas as pd import fsspec +import pandas as pd from datapipe.compute import ( Catalog, Pipeline, @@ -33,6 +33,7 @@ from sklearn.model_selection import train_test_split from sqlalchemy import Column from sqlalchemy.sql.sqltypes import JSON, String + from .dbconn import get_sqlite_dbconnstr TESTS_DIR = Path(__file__).parents[1] @@ -232,7 +233,7 @@ def make_runtime( def make_cloud_runtime(tmp_path: Path, suffix: str, **kwargs) -> tuple[SmokeRuntime, str]: - from tests.helpers.cloud_storage import cloud_working_dir + from .cloud_storage import cloud_working_dir workdir = str(cloud_working_dir(suffix)) runtime = make_runtime(tmp_path, working_dir=workdir, **kwargs) @@ -455,7 +456,9 @@ def detection_freeze_step(workdir: Workdir): ) -def detection_train_step(workdir: Workdir, *, local_scratch: Path | None = None, filedir_fsspec_kwargs: dict | None = None): +def detection_train_step( + workdir: Workdir, *, local_scratch: Path | None = None, filedir_fsspec_kwargs: dict | None = None +): from datapipe_ml.tasks.detection.train.yolov8 import ( Train_YoloV8_DetectionModel, YoloV8_TrainingConfig, @@ -548,7 +551,9 @@ def detection_train_step_with_local_checkpoint( ) -def detection_train_step_with_augmentations(workdir: Workdir, *, local_scratch: Path | None = None, filedir_fsspec_kwargs: dict | None = None): +def detection_train_step_with_augmentations( + workdir: Workdir, *, local_scratch: Path | None = None, filedir_fsspec_kwargs: dict | None = None +): from datapipe_ml.tasks.detection.train.yolov8 import ( Train_YoloV8_DetectionModel, YoloV8_TrainingConfig, @@ -600,7 +605,9 @@ def detection_train_step_with_augmentations(workdir: Workdir, *, local_scratch: ) -def detection_yolov5_train_step(workdir: Workdir, *, local_scratch: Path | None = None, filedir_fsspec_kwargs: dict | None = None): +def detection_yolov5_train_step( + workdir: Workdir, *, local_scratch: Path | None = None, filedir_fsspec_kwargs: dict | None = None +): from datapipe_ml.tasks.detection.train.yolov5 import ( Train_YoloV5_DetectionModel, YoloV5_TrainingConfig, @@ -642,7 +649,9 @@ def detection_yolov5_train_step(workdir: Workdir, *, local_scratch: Path | None ) -def detection_yolov5_train_step_with_augmentations(workdir: Workdir, *, local_scratch: Path | None = None, filedir_fsspec_kwargs: dict | None = None): +def detection_yolov5_train_step_with_augmentations( + workdir: Workdir, *, local_scratch: Path | None = None, filedir_fsspec_kwargs: dict | None = None +): from datapipe_ml.tasks.detection.train.yolov5 import ( Train_YoloV5_DetectionModel, YoloV5_TrainingConfig, @@ -738,7 +747,9 @@ def segmentation_freeze_step(workdir: Workdir): ) -def segmentation_train_step(workdir: Workdir, *, local_scratch: Path | None = None, filedir_fsspec_kwargs: dict | None = None): +def segmentation_train_step( + workdir: Workdir, *, local_scratch: Path | None = None, filedir_fsspec_kwargs: dict | None = None +): from datapipe_ml.tasks.segmentation.train.yolov8 import ( Train_YoloV8_SegmentationModel, YoloV8_TrainingConfig, @@ -847,7 +858,9 @@ def keypoints_freeze_step(workdir: Workdir): ) -def keypoints_train_step(workdir: Workdir, *, local_scratch: Path | None = None, filedir_fsspec_kwargs: dict | None = None): +def keypoints_train_step( + workdir: Workdir, *, local_scratch: Path | None = None, filedir_fsspec_kwargs: dict | None = None +): from datapipe_ml.tasks.keypoints.train.yolov8 import ( Train_YoloV8_KeypointsModel, YoloV8_TrainingConfig, @@ -974,7 +987,9 @@ def classification_freeze_step(workdir: Workdir): ) -def classification_train_step(workdir: Workdir, *, local_scratch: Path | None = None, filedir_fsspec_kwargs: dict | None = None): +def classification_train_step( + workdir: Workdir, *, local_scratch: Path | None = None, filedir_fsspec_kwargs: dict | None = None +): from datapipe_ml.tasks.classification.train.tensorflow import ( TF_ClassificationTrainingConfig, Train_Tensorflow_ClassificationModel, diff --git a/libs/datapipe-ml/tests/test_app_smoke.py b/libs/datapipe-ml/tests/test_app_smoke.py index 8e12845da..d3da43815 100644 --- a/libs/datapipe-ml/tests/test_app_smoke.py +++ b/libs/datapipe-ml/tests/test_app_smoke.py @@ -5,7 +5,7 @@ from sqlalchemy import Column from sqlalchemy.sql.sqltypes import JSON, String -from tests.fixtures.smoke_data import ( +from .fixtures.smoke_data import ( SmokeDataset, define_ground_truth_for_classification, generate_smoke_data, diff --git a/libs/datapipe-ml/tests/test_data_generation.py b/libs/datapipe-ml/tests/test_data_generation.py index e4f1df475..13c2afbf0 100644 --- a/libs/datapipe-ml/tests/test_data_generation.py +++ b/libs/datapipe-ml/tests/test_data_generation.py @@ -2,12 +2,12 @@ import pandas as pd -from tests.fixtures.smoke_data import ( +from .fixtures.smoke_data import ( define_ground_truth_for_classification, generate_smoke_data, get_most_common_label, ) -from tests.utils import assert_columns_present, assert_no_nulls +from .utils import assert_columns_present, assert_no_nulls def test_smoke_dataset_has_aligned_tables(smoke_dataset): diff --git a/libs/datapipe-ml/tests/test_freeze_datasets.py b/libs/datapipe-ml/tests/test_freeze_datasets.py index 920c79bba..3bae277a5 100644 --- a/libs/datapipe-ml/tests/test_freeze_datasets.py +++ b/libs/datapipe-ml/tests/test_freeze_datasets.py @@ -2,7 +2,7 @@ import pytest -from tests.utils import assert_columns_present, assert_no_nulls +from .utils import assert_columns_present, assert_no_nulls def _require_datapipe_runtime(): diff --git a/libs/datapipe-ml/tests/test_task_classification.py b/libs/datapipe-ml/tests/test_task_classification.py index b6c1bdc11..62b843cd8 100644 --- a/libs/datapipe-ml/tests/test_task_classification.py +++ b/libs/datapipe-ml/tests/test_task_classification.py @@ -2,7 +2,7 @@ import pytest -from tests.helpers.training_smoke import ( +from .helpers.training_smoke import ( assert_completed_training_status_with_manifest, assert_metrics_have_values, assert_model_artifact, diff --git a/libs/datapipe-ml/tests/test_task_detection.py b/libs/datapipe-ml/tests/test_task_detection.py index 351104dfc..cec794e67 100644 --- a/libs/datapipe-ml/tests/test_task_detection.py +++ b/libs/datapipe-ml/tests/test_task_detection.py @@ -2,7 +2,7 @@ import pytest -from tests.helpers.training_smoke import ( +from .helpers.training_smoke import ( assert_completed_training_status_with_manifest, assert_metrics_have_values, assert_model_artifact, @@ -24,7 +24,7 @@ @pytest.mark.slow @pytest.mark.training def test_training_smoke_sqlite_driver_supports_ci_full_outer_join(tmp_path): - from tests.helpers.training_smoke import get_sqlite_dbconnstr + from .helpers.training_smoke import get_sqlite_dbconnstr assert get_sqlite_dbconnstr(tmp_path / "training_smoke.sqlite").startswith("sqlite") diff --git a/libs/datapipe-ml/tests/test_task_keypoints.py b/libs/datapipe-ml/tests/test_task_keypoints.py index 75c8c8458..5a7fb1439 100644 --- a/libs/datapipe-ml/tests/test_task_keypoints.py +++ b/libs/datapipe-ml/tests/test_task_keypoints.py @@ -5,7 +5,8 @@ from sqlalchemy import JSON, Column from sqlalchemy.sql.sqltypes import DateTime, Integer, String -from tests.helpers.training_smoke import ( +from .helpers.training_smoke import ( + SMOKE_DEVICE, assert_completed_training_status_with_manifest, assert_metrics_have_values, assert_model_artifact, @@ -16,7 +17,6 @@ keypoints_train_step, make_runtime, run_pipeline, - SMOKE_DEVICE, ) diff --git a/libs/datapipe-ml/tests/test_task_segmentation.py b/libs/datapipe-ml/tests/test_task_segmentation.py index 45768cf8a..4b9c1394c 100644 --- a/libs/datapipe-ml/tests/test_task_segmentation.py +++ b/libs/datapipe-ml/tests/test_task_segmentation.py @@ -2,7 +2,7 @@ import pytest -from tests.helpers.training_smoke import ( +from .helpers.training_smoke import ( assert_completed_training_status_with_manifest, assert_model_artifact, assert_table_has_rows, diff --git a/libs/datapipe-ml/tests/test_task_training_local_checkpoint.py b/libs/datapipe-ml/tests/test_task_training_local_checkpoint.py index 84b7a21bd..953acc1c9 100644 --- a/libs/datapipe-ml/tests/test_task_training_local_checkpoint.py +++ b/libs/datapipe-ml/tests/test_task_training_local_checkpoint.py @@ -2,8 +2,8 @@ import pytest -from tests.helpers.cloud_storage import assert_model_path_under_working_dir -from tests.helpers.training_smoke import ( +from .helpers.cloud_storage import assert_model_path_under_working_dir +from .helpers.training_smoke import ( assert_model_artifact, assert_training_uses_architecture_label, detection_freeze_step, diff --git a/libs/datapipe-ml/tests/test_training_checkpoint_atomic.py b/libs/datapipe-ml/tests/test_training_checkpoint_atomic.py index 5990e87f7..23071cd21 100644 --- a/libs/datapipe-ml/tests/test_training_checkpoint_atomic.py +++ b/libs/datapipe-ml/tests/test_training_checkpoint_atomic.py @@ -5,11 +5,11 @@ from pathlib import Path import pytest - from datapipe_ml.core.atomic_io import atomic_write_local from datapipe_ml.training.checkpoint_verify import is_zip_checkpoint_loadable -from tests.helpers.checkpoint_fixtures import write_corrupt_zip_checkpoint, write_valid_zip_checkpoint -from tests.helpers.checkpoint_kill9 import ( + +from .helpers.checkpoint_fixtures import write_corrupt_zip_checkpoint, write_valid_zip_checkpoint +from .helpers.checkpoint_kill9 import ( kill9_during_atomic_checkpoint_save, kill9_during_non_atomic_checkpoint_save, ) @@ -95,7 +95,10 @@ def test_tf_resume_falls_back_when_last_checkpoint_is_corrupt(tmp_path: Path) -> run_dir = tmp_path / "model-a" run_dir.mkdir() last = run_dir / "002__last.keras" - metric = run_dir / "001__train_precision_0.10_train_recall_0.20__val_precision_0.30_val_recall_0.40_val_f1_score_0.50.keras" + metric = ( + run_dir + / "001__train_precision_0.10_train_recall_0.20__val_precision_0.30_val_recall_0.40_val_f1_score_0.50.keras" + ) write_corrupt_zip_checkpoint(last) write_valid_zip_checkpoint(metric, label="metric") @@ -130,8 +133,8 @@ def test_tf_style_checkpoint_survives_kill9_before_replace(tmp_path: Path) -> No def test_torch_save_uses_atomic_checkpoint_io(tmp_path: Path) -> None: pytest.importorskip("torch") - from datapipe_ml.frameworks.yolo.checkpoint_io import atomic_yolo_checkpoint_io import torch + from datapipe_ml.frameworks.yolo.checkpoint_io import atomic_yolo_checkpoint_io target = tmp_path / "weights" / "epoch1.pt" target.parent.mkdir(parents=True) @@ -159,10 +162,11 @@ def test_ultralytics_write_bytes_uses_atomic_checkpoint_io(tmp_path: Path) -> No def test_atomic_yolo_checkpoint_io_restores_patches(tmp_path: Path) -> None: pytest.importorskip("torch") - from datapipe_ml.frameworks.yolo.checkpoint_io import atomic_yolo_checkpoint_io - import torch from pathlib import Path as StdPath + import torch + from datapipe_ml.frameworks.yolo.checkpoint_io import atomic_yolo_checkpoint_io + original_torch_save = torch.save original_write_bytes = StdPath.write_bytes with atomic_yolo_checkpoint_io(): @@ -174,8 +178,8 @@ def test_atomic_yolo_checkpoint_io_restores_patches(tmp_path: Path) -> None: def test_yolov5_style_checkpoint_names_use_atomic_torch_save(tmp_path: Path) -> None: pytest.importorskip("torch") - from datapipe_ml.frameworks.yolo.checkpoint_io import atomic_yolo_checkpoint_io import torch + from datapipe_ml.frameworks.yolo.checkpoint_io import atomic_yolo_checkpoint_io with atomic_yolo_checkpoint_io(): for name in ("last.pt", "best.pt", "epoch3.pt"): diff --git a/libs/datapipe-ml/tests/test_training_cloud_storage.py b/libs/datapipe-ml/tests/test_training_cloud_storage.py index cbc620423..7b214a1d1 100644 --- a/libs/datapipe-ml/tests/test_training_cloud_storage.py +++ b/libs/datapipe-ml/tests/test_training_cloud_storage.py @@ -3,19 +3,20 @@ import tempfile from pathlib import Path +import fsspec import pytest - from datapipe_ml.training.specs import TrainingResumeConfig from datapipe_ml.training.sync import write_checkpoint_manifest -from tests.helpers.checkpoint_fixtures import write_valid_zip_checkpoint -from tests.helpers.cloud_smoke import ( + +from .helpers.checkpoint_fixtures import write_valid_zip_checkpoint +from .helpers.cloud_smoke import ( CLOUD_SMOKE_CASE_PARAMS, cloud_smoke_artifact, cloud_smoke_runtime_kwargs, cloud_smoke_status_table, cloud_smoke_steps, ) -from tests.helpers.cloud_storage import ( +from .helpers.cloud_storage import ( assert_model_path_under_working_dir, assert_url_exists, cloud_working_dir, @@ -23,18 +24,18 @@ s3_base_url, upload_local_file, ) -from tests.helpers.failure_injection import ( +from .helpers.failure_injection import ( FAIL_AFTER_EPOCH_ENV, FAIL_MODE_ENV, training_failure_hooks, ) -from tests.helpers.training_recovery import ( +from .helpers.training_recovery import ( REAL_RECOVERY_CASE_PARAMS, assert_status_manifest, make_recovery_runtime, recovery_case_by_id, ) -from tests.helpers.training_smoke import ( +from .helpers.training_smoke import ( assert_completed_training_status_with_manifest, assert_model_artifact, assert_training_uses_architecture_label, @@ -45,8 +46,6 @@ run_pipeline, ) -import fsspec - pytestmark = [pytest.mark.cloud_storage, pytest.mark.service_e2e] diff --git a/libs/datapipe-ml/tests/test_training_recovery_real_architectures.py b/libs/datapipe-ml/tests/test_training_recovery_real_architectures.py index 44742c86c..48a01c649 100644 --- a/libs/datapipe-ml/tests/test_training_recovery_real_architectures.py +++ b/libs/datapipe-ml/tests/test_training_recovery_real_architectures.py @@ -2,12 +2,12 @@ import pytest -from tests.helpers.failure_injection import ( +from .helpers.failure_injection import ( FAIL_AFTER_EPOCH_ENV, FAIL_MODE_ENV, training_failure_hooks, ) -from tests.helpers.training_recovery import ( +from .helpers.training_recovery import ( REAL_RECOVERY_CASE_PARAMS, TENSORFLOW_RECOVERY_CASE_IDS, assert_status_manifest, @@ -22,7 +22,7 @@ wait_for_manifest, wait_for_running_status, ) -from tests.helpers.training_smoke import run_pipeline +from .helpers.training_smoke import run_pipeline pytestmark = [pytest.mark.slow, pytest.mark.training] diff --git a/libs/datapipe-ml/tests/test_training_recovery_sky_vast.py b/libs/datapipe-ml/tests/test_training_recovery_sky_vast.py index 78155741e..c1ca092fe 100644 --- a/libs/datapipe-ml/tests/test_training_recovery_sky_vast.py +++ b/libs/datapipe-ml/tests/test_training_recovery_sky_vast.py @@ -5,19 +5,19 @@ import pytest -from tests.helpers.failure_injection import ( +from .helpers.failure_injection import ( FAIL_AFTER_EPOCH_ENV, FAIL_MODE_ENV, patch_sky_vast_worker_entrypoint_for_failure_hooks, ) -from tests.helpers.training_recovery import ( +from .helpers.training_recovery import ( assert_status_manifest, configure_recovery_steps, make_recovery_runtime, recovery_case_by_id, ) -from tests.helpers.training_smoke import run_pipeline -from tests.test_training_sky_vast import _run_with_accelerator_candidates, _sky_vast_config, sky_vast_environment +from .helpers.training_smoke import run_pipeline +from .test_training_sky_vast import _run_with_accelerator_candidates, _sky_vast_config, sky_vast_environment pytestmark = [pytest.mark.slow, pytest.mark.training, pytest.mark.torch, pytest.mark.sky_vast] diff --git a/libs/datapipe-ml/tests/test_training_recovery_stale_lease.py b/libs/datapipe-ml/tests/test_training_recovery_stale_lease.py index ac2c7ffed..443b59b89 100644 --- a/libs/datapipe-ml/tests/test_training_recovery_stale_lease.py +++ b/libs/datapipe-ml/tests/test_training_recovery_stale_lease.py @@ -2,8 +2,8 @@ import pytest -from tests.helpers.failure_injection import FAIL_AFTER_EPOCH_ENV, FAIL_MODE_ENV -from tests.helpers.training_recovery import ( +from .helpers.failure_injection import FAIL_AFTER_EPOCH_ENV, FAIL_MODE_ENV +from .helpers.training_recovery import ( assert_stale_running_after_pipe_death, assert_status_manifest, model_rows, diff --git a/libs/datapipe-ml/tests/test_training_sky_vast.py b/libs/datapipe-ml/tests/test_training_sky_vast.py index 962f550ff..b9e2b0865 100644 --- a/libs/datapipe-ml/tests/test_training_sky_vast.py +++ b/libs/datapipe-ml/tests/test_training_sky_vast.py @@ -12,7 +12,6 @@ from typing import Any, Callable, Iterable import pytest - from datapipe_ml.training.sky_vast.serialization import ( dumps_to_text, loads_from_text, @@ -24,9 +23,9 @@ TrainingLaunchRequest, build_training_launcher, ) -from tests.helpers.training_smoke import assert_yolov8_training_artifacts -from tests.helpers.test_env import load_test_env +from .helpers.test_env import load_test_env +from .helpers.training_smoke import assert_yolov8_training_artifacts pytestmark = [pytest.mark.slow, pytest.mark.training] @@ -71,9 +70,7 @@ def _sky_vast_instance_type(offer: dict[str, Any]) -> str: query_ram_mb = int(os.getenv("DATAPIPE_ML_SKY_VAST_QUERY_RAM_MB", "1024")) offer_id = int(offer.get("id") or 0) cpu_token = int(offer.get("cpu_cores") or 1) * 1_000_000_000 + offer_id - return ( - f"{int(offer.get('num_gpus') or 1)}x-{str(offer['gpu_name']).replace(' ', '_')}-" f"{cpu_token}-{query_ram_mb}" - ) + return f"{int(offer.get('num_gpus') or 1)}x-{str(offer['gpu_name']).replace(' ', '_')}-{cpu_token}-{query_ram_mb}" def _write_live_sky_vast_catalog(sky_home: Path) -> None: @@ -164,7 +161,7 @@ def _write_sky_vast_patch(patch_dir: Path) -> None: def _apply_sky_vast_runtime_patches() -> None: - from tests.helpers import sky_vast_sitecustomize + from .helpers import sky_vast_sitecustomize sky_vast_sitecustomize._patch_sky_vast_launch() @@ -431,7 +428,9 @@ def _sky_vast_config( cluster_name=cluster_name, infra=infra, instance_type=instance_type, - accelerators="" if instance_type else (accelerators if accelerators is not None else os.getenv("DATAPIPE_ML_SKY_VAST_ACCELERATORS", "")), + accelerators="" + if instance_type + else (accelerators if accelerators is not None else os.getenv("DATAPIPE_ML_SKY_VAST_ACCELERATORS", "")), cpus=os.getenv("DATAPIPE_ML_SKY_VAST_CPUS", "1+"), memory=os.getenv("DATAPIPE_ML_SKY_VAST_MEMORY", "1+"), disk_size=os.getenv("DATAPIPE_ML_SKY_VAST_DISK_SIZE", "20GB"), @@ -602,7 +601,6 @@ def test_sky_vast_rewrites_remote_results_back_to_local_paths(tmp_path): def test_sky_vast_periodic_output_sync_copies_remote_outputs(tmp_path): import fsspec - from datapipe_ml.training.sky_vast.launcher import SkyVastTrainingLauncher from datapipe_ml.training.sync import PeriodicSyncScheduler @@ -633,7 +631,6 @@ def test_sky_vast_periodic_output_sync_copies_remote_outputs(tmp_path): def test_core_files_copy_tree_skips_copy_when_paths_are_same(): import fsspec - from datapipe_ml.core.files import copy_tree_between_fs fs = fsspec.filesystem("memory") @@ -649,7 +646,6 @@ def test_core_files_copy_tree_skips_copy_when_paths_are_same(): def test_core_files_parallel_copy_copies_tree(tmp_path): import fsspec - from datapipe_ml.core.files import copy_tree_between_fs src_fs = fsspec.filesystem("memory") @@ -711,8 +707,7 @@ def test_sky_vast_runtime_bootstrap_is_available(sky_vast_environment): def test_sky_vast_launches_minimal_worker_from_scratch(sky_vast_environment): if not _sky_vast_available(): pytest.skip( - "Set DATAPIPE_ML_RUN_SKY_VAST=1 and VAPI_API_KEY " - "(tests/.env.test.local or shell env) to run this test." + "Set DATAPIPE_ML_RUN_SKY_VAST=1 and VAPI_API_KEY (tests/.env.test.local or shell env) to run this test." ) if _sky_vast_all_candidates_are_cached(): pytest.skip("All US GPU offers on Vast were already marked bad in this test process.") @@ -726,13 +721,12 @@ def test_sky_vast_launches_minimal_worker_from_scratch(sky_vast_environment): def test_yolov8_detection_training_smoke_sky_vast(tmp_path, sky_vast_environment): if not _sky_vast_available(): pytest.skip( - "Set DATAPIPE_ML_RUN_SKY_VAST=1 and VAPI_API_KEY " - "(tests/.env.test.local or shell env) to run this test." + "Set DATAPIPE_ML_RUN_SKY_VAST=1 and VAPI_API_KEY (tests/.env.test.local or shell env) to run this test." ) if _sky_vast_all_candidates_are_cached(): pytest.skip("All US GPU offers on Vast were already marked bad in this test process.") - from tests.helpers.training_smoke import ( + from .helpers.training_smoke import ( assert_model_artifact, detection_freeze_step, detection_train_step, diff --git a/pyproject.toml b/pyproject.toml index 5430e0f86..0eae447ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,8 @@ follow_imports = "silent" namespace_packages = true [dependency-groups] -dev = [ - "ty>=0.0.65", -] +dev = ["ty>=0.0.65"] + +[tool.pytest.ini_options] +addopts = ["--import-mode=importlib"] +testpaths = ["libs"]