diff --git a/src/batdetect2/cli/evaluate.py b/src/batdetect2/cli/evaluate.py index 369cd32..6635d75 100644 --- a/src/batdetect2/cli/evaluate.py +++ b/src/batdetect2/cli/evaluate.py @@ -43,11 +43,11 @@ def evaluate_command( from batdetect2.api_v2 import BatDetect2API from batdetect2.audio import AudioConfig from batdetect2.data import load_dataset_from_config - from batdetect2.evaluate import load_evaluation_config + from batdetect2.evaluate import EvaluationConfig from batdetect2.inference import InferenceConfig - from batdetect2.logging import load_logging_config + from batdetect2.logging import AppLoggingConfig from batdetect2.outputs import OutputsConfig - from batdetect2.targets import load_target_config + from batdetect2.targets import TargetConfig logger.info("Initiating evaluation process...") @@ -62,7 +62,7 @@ def evaluate_command( ) target_conf = ( - load_target_config(targets_config) + TargetConfig.load(targets_config) if targets_config is not None else None ) @@ -70,7 +70,7 @@ def evaluate_command( AudioConfig.load(audio_config) if audio_config is not None else None ) eval_conf = ( - load_evaluation_config(evaluation_config) + EvaluationConfig.load(evaluation_config) if evaluation_config is not None else None ) @@ -85,7 +85,7 @@ def evaluate_command( else None ) logging_conf = ( - load_logging_config(logging_config) + AppLoggingConfig.load(logging_config) if logging_config is not None else None ) diff --git a/src/batdetect2/cli/train.py b/src/batdetect2/cli/train.py index 91a73d7..543af20 100644 --- a/src/batdetect2/cli/train.py +++ b/src/batdetect2/cli/train.py @@ -53,19 +53,19 @@ def train_command( from batdetect2.audio import AudioConfig from batdetect2.config import BatDetect2Config from batdetect2.data import load_dataset_from_config - from batdetect2.evaluate import load_evaluation_config + from batdetect2.evaluate import EvaluationConfig from batdetect2.inference import InferenceConfig - from batdetect2.logging import load_logging_config + from batdetect2.logging import AppLoggingConfig from batdetect2.models import ModelConfig from batdetect2.outputs import OutputsConfig - from batdetect2.targets import load_target_config - from batdetect2.train import load_train_config + from batdetect2.targets import TargetConfig + from batdetect2.train import TrainingConfig logger.info("Initiating training process...") logger.info("Loading configuration...") target_conf = ( - load_target_config(targets_config) + TargetConfig.load(targets_config) if targets_config is not None else None ) @@ -73,7 +73,7 @@ def train_command( ModelConfig.load(model_config) if model_config is not None else None ) train_conf = ( - load_train_config(training_config) + TrainingConfig.load(training_config) if training_config is not None else None ) @@ -81,7 +81,7 @@ def train_command( AudioConfig.load(audio_config) if audio_config is not None else None ) eval_conf = ( - load_evaluation_config(evaluation_config) + EvaluationConfig.load(evaluation_config) if evaluation_config is not None else None ) @@ -96,7 +96,7 @@ def train_command( else None ) logging_conf = ( - load_logging_config(logging_config) + AppLoggingConfig.load(logging_config) if logging_config is not None else None ) diff --git a/src/batdetect2/config.py b/src/batdetect2/config.py index a0c9688..525f581 100644 --- a/src/batdetect2/config.py +++ b/src/batdetect2/config.py @@ -1,10 +1,9 @@ from typing import Literal from pydantic import Field -from soundevent.data import PathLike from batdetect2.audio import AudioConfig -from batdetect2.core.configs import BaseConfig, load_config +from batdetect2.core.configs import BaseConfig from batdetect2.evaluate.config import ( EvaluationConfig, get_default_eval_config, @@ -17,7 +16,6 @@ from batdetect2.train.config import TrainingConfig __all__ = [ "BatDetect2Config", - "load_full_config", "validate_config", ] @@ -41,10 +39,3 @@ def validate_config(config: dict | None) -> BatDetect2Config: return BatDetect2Config() return BatDetect2Config.model_validate(config) - - -def load_full_config( - path: PathLike, - field: str | None = None, -) -> BatDetect2Config: - return load_config(path, schema=BatDetect2Config, field=field) diff --git a/src/batdetect2/evaluate/__init__.py b/src/batdetect2/evaluate/__init__.py index 20ee7b4..09e7bb7 100644 --- a/src/batdetect2/evaluate/__init__.py +++ b/src/batdetect2/evaluate/__init__.py @@ -1,4 +1,4 @@ -from batdetect2.evaluate.config import EvaluationConfig, load_evaluation_config +from batdetect2.evaluate.config import EvaluationConfig from batdetect2.evaluate.evaluate import DEFAULT_EVAL_DIR, run_evaluate from batdetect2.evaluate.evaluator import Evaluator, build_evaluator from batdetect2.evaluate.results import save_evaluation_results @@ -27,7 +27,6 @@ __all__ = [ "TaskConfig", "build_evaluator", "build_task", - "load_evaluation_config", "run_evaluate", "save_evaluation_results", ] diff --git a/src/batdetect2/evaluate/config.py b/src/batdetect2/evaluate/config.py index 4bcf0b1..bc49a26 100644 --- a/src/batdetect2/evaluate/config.py +++ b/src/batdetect2/evaluate/config.py @@ -1,16 +1,14 @@ from typing import List from pydantic import Field -from soundevent import data -from batdetect2.core.configs import BaseConfig, load_config +from batdetect2.core.configs import BaseConfig from batdetect2.evaluate.tasks import TaskConfig from batdetect2.evaluate.tasks.classification import ClassificationTaskConfig from batdetect2.evaluate.tasks.detection import DetectionTaskConfig __all__ = [ "EvaluationConfig", - "load_evaluation_config", ] @@ -43,10 +41,3 @@ def get_default_eval_config() -> EvaluationConfig: ] } ) - - -def load_evaluation_config( - path: data.PathLike, - field: str | None = None, -) -> EvaluationConfig: - return load_config(path, schema=EvaluationConfig, field=field) diff --git a/src/batdetect2/logging.py b/src/batdetect2/logging.py index c21445b..e328d0d 100644 --- a/src/batdetect2/logging.py +++ b/src/batdetect2/logging.py @@ -26,7 +26,7 @@ from matplotlib.figure import Figure from pydantic import Field from soundevent import data -from batdetect2.core.configs import BaseConfig, load_config +from batdetect2.core.configs import BaseConfig DEFAULT_LOGS_DIR: Path = Path("outputs") / "logs" @@ -43,7 +43,6 @@ __all__ = [ "enable_logging", "get_image_logger", "get_table_logger", - "load_logging_config", ] @@ -106,13 +105,6 @@ class AppLoggingConfig(BaseConfig): inference: LoggerConfig = Field(default_factory=CSVLoggerConfig) -def load_logging_config( - path: data.PathLike, - field: str | None = None, -) -> AppLoggingConfig: - return load_config(path, schema=AppLoggingConfig, field=field) - - T = TypeVar("T", bound=LoggerConfig, contravariant=True) diff --git a/src/batdetect2/postprocess/__init__.py b/src/batdetect2/postprocess/__init__.py index b80fb60..69070a5 100644 --- a/src/batdetect2/postprocess/__init__.py +++ b/src/batdetect2/postprocess/__init__.py @@ -1,9 +1,6 @@ """Main entry point for the BatDetect2 Postprocessing pipeline.""" -from batdetect2.postprocess.config import ( - PostprocessConfig, - load_postprocess_config, -) +from batdetect2.postprocess.config import PostprocessConfig from batdetect2.postprocess.nms import non_max_suppression from batdetect2.postprocess.postprocessor import ( Postprocessor, @@ -30,6 +27,5 @@ __all__ = [ "Postprocessor", "PostprocessorProtocol", "build_postprocessor", - "load_postprocess_config", "non_max_suppression", ] diff --git a/src/batdetect2/postprocess/config.py b/src/batdetect2/postprocess/config.py index 69d25d9..0fa1db2 100644 --- a/src/batdetect2/postprocess/config.py +++ b/src/batdetect2/postprocess/config.py @@ -1,12 +1,10 @@ from pydantic import Field -from soundevent import data -from batdetect2.core.configs import BaseConfig, load_config +from batdetect2.core.configs import BaseConfig from batdetect2.postprocess.nms import NMS_KERNEL_SIZE __all__ = [ "PostprocessConfig", - "load_postprocess_config", ] DEFAULT_DETECTION_THRESHOLD = 0.01 @@ -51,42 +49,3 @@ class PostprocessConfig(BaseConfig): ge=0, ) top_k_per_sec: int = Field(default=TOP_K_PER_SEC, gt=0) - - -def load_postprocess_config( - path: data.PathLike, - field: str | None = None, -) -> PostprocessConfig: - """Load the postprocessing configuration from a file. - - Reads a configuration file (YAML) and validates it against the - `PostprocessConfig` schema, potentially extracting data from a nested - field. - - Parameters - ---------- - path : PathLike - Path to the configuration file. - field : str, optional - Dot-separated path to a nested section within the file containing the - postprocessing configuration (e.g., "inference.postprocessing"). - If None, the entire file content is used. - - Returns - ------- - PostprocessConfig - The loaded and validated postprocessing configuration object. - - Raises - ------ - FileNotFoundError - If the config file path does not exist. - yaml.YAMLError - If the file content is not valid YAML. - pydantic.ValidationError - If the loaded configuration data does not conform to the - `PostprocessConfig` schema. - KeyError, TypeError - If `field` specifies an invalid path within the loaded data. - """ - return load_config(path, schema=PostprocessConfig, field=field) diff --git a/src/batdetect2/preprocess/__init__.py b/src/batdetect2/preprocess/__init__.py index fe7fba8..dadf9c6 100644 --- a/src/batdetect2/preprocess/__init__.py +++ b/src/batdetect2/preprocess/__init__.py @@ -1,10 +1,7 @@ """Main entry point for the BatDetect2 preprocessing subsystem.""" from batdetect2.audio import TARGET_SAMPLERATE_HZ -from batdetect2.preprocess.config import ( - PreprocessingConfig, - load_preprocessing_config, -) +from batdetect2.preprocess.config import PreprocessingConfig from batdetect2.preprocess.preprocessor import Preprocessor, build_preprocessor from batdetect2.preprocess.spectrogram import MAX_FREQ, MIN_FREQ from batdetect2.preprocess.types import PreprocessorProtocol @@ -17,5 +14,4 @@ __all__ = [ "Preprocessor", "TARGET_SAMPLERATE_HZ", "build_preprocessor", - "load_preprocessing_config", ] diff --git a/src/batdetect2/preprocess/config.py b/src/batdetect2/preprocess/config.py index 086a640..d8b1d17 100644 --- a/src/batdetect2/preprocess/config.py +++ b/src/batdetect2/preprocess/config.py @@ -8,9 +8,8 @@ spectrogram ready for the detection model. from typing import List from pydantic import Field -from soundevent.data import PathLike -from batdetect2.core.configs import BaseConfig, load_config +from batdetect2.core.configs import BaseConfig from batdetect2.preprocess.audio import AudioTransform from batdetect2.preprocess.spectrogram import ( FrequencyConfig, @@ -22,7 +21,6 @@ from batdetect2.preprocess.spectrogram import ( ) __all__ = [ - "load_preprocessing_config", "AudioTransform", "PreprocessingConfig", ] @@ -71,26 +69,3 @@ class PreprocessingConfig(BaseConfig): frequencies: FrequencyConfig = Field(default_factory=FrequencyConfig) size: ResizeConfig = Field(default_factory=ResizeConfig) - - -def load_preprocessing_config( - path: PathLike, - field: str | None = None, -) -> PreprocessingConfig: - """Load a ``PreprocessingConfig`` from a YAML file. - - Parameters - ---------- - path : PathLike - Path to the YAML configuration file. - field : str, optional - If provided, read the config from a nested field within the - YAML document (e.g. ``"preprocessing"`` to read from a top-level - ``preprocessing:`` key). - - Returns - ------- - PreprocessingConfig - The deserialised preprocessing configuration. - """ - return load_config(path, schema=PreprocessingConfig, field=field) diff --git a/src/batdetect2/targets/__init__.py b/src/batdetect2/targets/__init__.py index 4c43633..c6f556e 100644 --- a/src/batdetect2/targets/__init__.py +++ b/src/batdetect2/targets/__init__.py @@ -6,7 +6,7 @@ from batdetect2.targets.classes import ( build_sound_event_encoder, get_class_names_from_config, ) -from batdetect2.targets.config import TargetConfig, load_target_config +from batdetect2.targets.config import TargetConfig from batdetect2.targets.rois import ( AnchorBBoxMapperConfig, ROIMapperConfig, @@ -56,6 +56,5 @@ __all__ = [ "get_class_names_from_config", "individual", "iterate_encoded_sound_events", - "load_target_config", "load_targets", ] diff --git a/src/batdetect2/targets/config.py b/src/batdetect2/targets/config.py index 8e70a61..9d3f0c5 100644 --- a/src/batdetect2/targets/config.py +++ b/src/batdetect2/targets/config.py @@ -2,9 +2,8 @@ from collections import Counter from typing import List from pydantic import Field, field_validator -from soundevent import data -from batdetect2.core.configs import BaseConfig, load_config +from batdetect2.core.configs import BaseConfig from batdetect2.targets.classes import ( DEFAULT_CLASSES, DEFAULT_DETECTION_CLASS, @@ -14,7 +13,6 @@ from batdetect2.targets.rois import AnchorBBoxMapperConfig, ROIMapperConfig __all__ = [ "TargetConfig", - "load_target_config", ] @@ -44,41 +42,3 @@ class TargetConfig(BaseConfig): f"{', '.join(duplicates)}" ) return v - - -def load_target_config( - path: data.PathLike, - field: str | None = None, -) -> TargetConfig: - """Load the unified target configuration from a file. - - Reads a configuration file (typically YAML) and validates it against the - `TargetConfig` schema, potentially extracting data from a nested field. - - Parameters - ---------- - path : data.PathLike - Path to the configuration file. - field : str, optional - Dot-separated path to a nested section within the file containing the - target configuration. If None, the entire file content is used. - - Returns - ------- - TargetConfig - The loaded and validated unified target configuration object. - - Raises - ------ - FileNotFoundError - If the config file path does not exist. - yaml.YAMLError - If the file content is not valid YAML. - pydantic.ValidationError - If the loaded configuration data does not conform to the - `TargetConfig` schema (including validation within nested configs - like `ClassesConfig`). - KeyError, TypeError - If `field` specifies an invalid path within the loaded data. - """ - return load_config(path=path, schema=TargetConfig, field=field) diff --git a/src/batdetect2/targets/targets.py b/src/batdetect2/targets/targets.py index f7a6dad..895a487 100644 --- a/src/batdetect2/targets/targets.py +++ b/src/batdetect2/targets/targets.py @@ -11,7 +11,7 @@ from batdetect2.targets.classes import ( build_sound_event_encoder, get_class_names_from_config, ) -from batdetect2.targets.config import TargetConfig, load_target_config +from batdetect2.targets.config import TargetConfig from batdetect2.targets.rois import ( AnchorBBoxMapperConfig, build_roi_mapper, @@ -276,13 +276,13 @@ def load_targets( ------ FileNotFoundError, yaml.YAMLError, pydantic.ValidationError, KeyError, TypeError - Errors raised during file loading, validation, or extraction via - `load_target_config`. + Errors raised during file loading or validation via + ``TargetConfig.load``. KeyError, ImportError, AttributeError, TypeError Errors raised during the build process by `Targets.from_config` (e.g., missing keys in registries, failed imports). """ - config = load_target_config( + config = TargetConfig.load( config_path, field=field, ) diff --git a/src/batdetect2/train/__init__.py b/src/batdetect2/train/__init__.py index 8590bac..72f3e77 100644 --- a/src/batdetect2/train/__init__.py +++ b/src/batdetect2/train/__init__.py @@ -1,5 +1,5 @@ from batdetect2.train.checkpoints import DEFAULT_CHECKPOINT_DIR -from batdetect2.train.config import TrainingConfig, load_train_config +from batdetect2.train.config import TrainingConfig from batdetect2.train.lightning import ( TrainingModule, load_model_from_checkpoint, @@ -12,6 +12,5 @@ __all__ = [ "TrainingModule", "build_trainer", "load_model_from_checkpoint", - "load_train_config", "run_train", ] diff --git a/src/batdetect2/train/augmentations.py b/src/batdetect2/train/augmentations.py index 41e860e..19a1e5f 100644 --- a/src/batdetect2/train/augmentations.py +++ b/src/batdetect2/train/augmentations.py @@ -15,7 +15,7 @@ from batdetect2.audio.clips import get_subclip_annotation from batdetect2.audio.loader import TARGET_SAMPLERATE_HZ from batdetect2.audio.types import AudioLoader from batdetect2.core.arrays import adjust_width -from batdetect2.core.configs import BaseConfig, load_config +from batdetect2.core.configs import BaseConfig from batdetect2.core.registries import ( ImportConfig, Registry, @@ -38,7 +38,6 @@ __all__ = [ "WarpConfig", "add_echo", "build_augmentations", - "load_augmentation_config", "mask_frequency", "mask_time", "mix_audio", @@ -686,13 +685,6 @@ def build_augmentations( return audio_augmentation, spectrogram_augmentation -def load_augmentation_config( - path: data.PathLike, field: str | None = None -) -> AugmentationsConfig: - """Load the augmentations configuration from a file.""" - return load_config(path, schema=AugmentationsConfig, field=field) - - class RandomAudioSource: def __init__( self, diff --git a/src/batdetect2/train/config.py b/src/batdetect2/train/config.py index 8822832..94584cb 100644 --- a/src/batdetect2/train/config.py +++ b/src/batdetect2/train/config.py @@ -1,7 +1,6 @@ from pydantic import Field -from soundevent import data -from batdetect2.core.configs import BaseConfig, load_config +from batdetect2.core.configs import BaseConfig from batdetect2.evaluate.config import EvaluationConfig from batdetect2.train.checkpoints import CheckpointConfig from batdetect2.train.dataset import TrainLoaderConfig, ValLoaderConfig @@ -15,7 +14,6 @@ from batdetect2.train.schedulers import ( __all__ = [ "TrainingConfig", - "load_train_config", ] @@ -52,10 +50,3 @@ class TrainingConfig(BaseConfig): labels: LabelConfig = Field(default_factory=LabelConfig) validation: EvaluationConfig = Field(default_factory=EvaluationConfig) checkpoints: CheckpointConfig = Field(default_factory=CheckpointConfig) - - -def load_train_config( - path: data.PathLike, - field: str | None = None, -) -> TrainingConfig: - return load_config(path, schema=TrainingConfig, field=field) diff --git a/tests/test_preprocessing/test_preprocessor.py b/tests/test_preprocessing/test_preprocessor.py index daf4395..35899d7 100644 --- a/tests/test_preprocessing/test_preprocessor.py +++ b/tests/test_preprocessing/test_preprocessor.py @@ -177,8 +177,6 @@ def test_preprocessor_with_fix_duration_audio_transform(): def test_preprocessor_yaml_roundtrip(tmp_path: pathlib.Path): """PreprocessingConfig serialised to YAML and reloaded should produce a functionally identical preprocessor.""" - from batdetect2.preprocess.config import load_preprocessing_config - config = PreprocessingConfig( stft=STFTConfig(window_duration=0.002, window_overlap=0.75), frequencies=FrequencyConfig(min_freq=10_000, max_freq=120_000), @@ -188,7 +186,7 @@ def test_preprocessor_yaml_roundtrip(tmp_path: pathlib.Path): yaml_path = tmp_path / "preprocess_config.yaml" yaml_path.write_text(config.to_yaml_string()) - loaded_config = load_preprocessing_config(yaml_path) + loaded_config = PreprocessingConfig.load(yaml_path) preprocessor = build_preprocessor( loaded_config, input_samplerate=SAMPLERATE diff --git a/tests/test_targets/test_targets.py b/tests/test_targets/test_targets.py index fad195b..c823cc5 100644 --- a/tests/test_targets/test_targets.py +++ b/tests/test_targets/test_targets.py @@ -3,7 +3,7 @@ from pathlib import Path from soundevent import data, terms -from batdetect2.targets import build_targets, load_target_config +from batdetect2.targets import TargetConfig, build_targets def test_can_override_default_roi_mapper_per_class( @@ -42,7 +42,7 @@ def test_can_override_default_roi_mapper_per_class( """ config_path = create_temp_yaml(yaml_content) - config = load_target_config(config_path) + config = TargetConfig.load(config_path) targets = build_targets(config) geometry = data.BoundingBox(coordinates=[0.1, 12_000, 0.2, 18_000]) @@ -105,7 +105,7 @@ def test_roi_is_recovered_roundtrip_even_with_overriders( """ config_path = create_temp_yaml(yaml_content) - config = load_target_config(config_path) + config = TargetConfig.load(config_path) targets = build_targets(config) geometry = data.BoundingBox(coordinates=[0.1, 12_000, 0.2, 18_000])