Coverage for src / ezcompiler / adapters / base_uploader.py: 47.37%
15 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-27 06:49 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-27 06:49 +0000
1# ///////////////////////////////////////////////////////////////
2# BASE_UPLOADER - Abstract base uploader interface
3# Project: ezcompiler
4# ///////////////////////////////////////////////////////////////
6"""
7Base uploader - Abstract base class for uploader implementations.
9This module defines the interface and common functionality for all uploaders,
10providing validation and contract enforcement for upload operations.
12Note: Protocols layer should not perform logging directly. Logging is handled
13by the service layer that orchestrates upload operations.
14"""
16from __future__ import annotations
18# ///////////////////////////////////////////////////////////////
19# IMPORTS
20# ///////////////////////////////////////////////////////////////
21# Standard library imports
22from abc import ABC, abstractmethod
23from pathlib import Path
24from typing import Any
26# Local imports
27from ..shared.exceptions import UploadError
29# ///////////////////////////////////////////////////////////////
30# CLASSES
31# ///////////////////////////////////////////////////////////////
34class BaseUploader(ABC):
35 """
36 Abstract base class for uploaders.
38 Defines the interface that all uploaders must implement and provides
39 common functionality for upload operations and validation.
41 Attributes:
42 _config: Configuration dictionary for the uploader
44 Example:
45 >>> class MyUploader(BaseUploader):
46 ... def upload(self, source_path: Path, destination: str) -> None:
47 ... # Implementation
48 ... pass
49 ... def get_uploader_name(self) -> str:
50 ... return "My Uploader"
51 """
53 # ////////////////////////////////////////////////
54 # INITIALIZATION
55 # ////////////////////////////////////////////////
57 def __init__(self, config: dict[str, Any] | None = None) -> None:
58 """
59 Initialize the uploader with configuration.
61 Args:
62 config: Configuration dictionary (default: None)
64 Note:
65 Subclasses should call super().__init__(config) to initialize
66 configuration and validation.
67 """
68 self._config = config or {}
69 self._validate_config()
71 # ////////////////////////////////////////////////
72 # ABSTRACT METHODS
73 # ////////////////////////////////////////////////
75 @abstractmethod
76 def upload(self, source_path: Path, destination: str) -> None:
77 """
78 Upload a file or directory to the destination.
80 Args:
81 source_path: Path to the source file or directory
82 destination: Destination path or URL
84 Raises:
85 UploadError: If upload fails
87 Note:
88 Subclasses must implement this method to define upload behavior.
89 """
91 @abstractmethod
92 def get_uploader_name(self) -> str:
93 """
94 Get the name of this uploader.
96 Returns:
97 str: Human-readable name of the uploader
99 Note:
100 Used for identification purposes.
101 """
103 # ////////////////////////////////////////////////
104 # VALIDATION METHODS
105 # ////////////////////////////////////////////////
107 def _validate_config(self) -> None: # noqa: B027
108 """
109 Validate uploader configuration.
111 Base implementation does nothing. Subclasses should override this
112 method to perform specific validation for their configuration.
114 Raises:
115 UploadError: If configuration is invalid (in subclasses)
117 Note:
118 This method is intentionally empty in the base class.
119 """
120 # Base implementation intentionally empty - subclasses should override
122 def _validate_source_path(self, source_path: Path) -> None:
123 """
124 Validate that the source path exists and is accessible.
126 Args:
127 source_path: Path to validate
129 Raises:
130 UploadError: If source path is invalid
132 Note:
133 Validation is handled at protocol level to keep this port independent
134 from uploader utility helpers.
135 """
136 if not source_path.exists():
137 raise UploadError(f"Source path does not exist: {source_path}")
138 if not source_path.is_file() and not source_path.is_dir():
139 raise UploadError(f"Source path is not a file or directory: {source_path}")