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

1# /////////////////////////////////////////////////////////////// 

2# BASE_UPLOADER - Abstract base uploader interface 

3# Project: ezcompiler 

4# /////////////////////////////////////////////////////////////// 

5 

6""" 

7Base uploader - Abstract base class for uploader implementations. 

8 

9This module defines the interface and common functionality for all uploaders, 

10providing validation and contract enforcement for upload operations. 

11 

12Note: Protocols layer should not perform logging directly. Logging is handled 

13by the service layer that orchestrates upload operations. 

14""" 

15 

16from __future__ import annotations 

17 

18# /////////////////////////////////////////////////////////////// 

19# IMPORTS 

20# /////////////////////////////////////////////////////////////// 

21# Standard library imports 

22from abc import ABC, abstractmethod 

23from pathlib import Path 

24from typing import Any 

25 

26# Local imports 

27from ..shared.exceptions import UploadError 

28 

29# /////////////////////////////////////////////////////////////// 

30# CLASSES 

31# /////////////////////////////////////////////////////////////// 

32 

33 

34class BaseUploader(ABC): 

35 """ 

36 Abstract base class for uploaders. 

37 

38 Defines the interface that all uploaders must implement and provides 

39 common functionality for upload operations and validation. 

40 

41 Attributes: 

42 _config: Configuration dictionary for the uploader 

43 

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 """ 

52 

53 # //////////////////////////////////////////////// 

54 # INITIALIZATION 

55 # //////////////////////////////////////////////// 

56 

57 def __init__(self, config: dict[str, Any] | None = None) -> None: 

58 """ 

59 Initialize the uploader with configuration. 

60 

61 Args: 

62 config: Configuration dictionary (default: None) 

63 

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() 

70 

71 # //////////////////////////////////////////////// 

72 # ABSTRACT METHODS 

73 # //////////////////////////////////////////////// 

74 

75 @abstractmethod 

76 def upload(self, source_path: Path, destination: str) -> None: 

77 """ 

78 Upload a file or directory to the destination. 

79 

80 Args: 

81 source_path: Path to the source file or directory 

82 destination: Destination path or URL 

83 

84 Raises: 

85 UploadError: If upload fails 

86 

87 Note: 

88 Subclasses must implement this method to define upload behavior. 

89 """ 

90 

91 @abstractmethod 

92 def get_uploader_name(self) -> str: 

93 """ 

94 Get the name of this uploader. 

95 

96 Returns: 

97 str: Human-readable name of the uploader 

98 

99 Note: 

100 Used for identification purposes. 

101 """ 

102 

103 # //////////////////////////////////////////////// 

104 # VALIDATION METHODS 

105 # //////////////////////////////////////////////// 

106 

107 def _validate_config(self) -> None: # noqa: B027 

108 """ 

109 Validate uploader configuration. 

110 

111 Base implementation does nothing. Subclasses should override this 

112 method to perform specific validation for their configuration. 

113 

114 Raises: 

115 UploadError: If configuration is invalid (in subclasses) 

116 

117 Note: 

118 This method is intentionally empty in the base class. 

119 """ 

120 # Base implementation intentionally empty - subclasses should override 

121 

122 def _validate_source_path(self, source_path: Path) -> None: 

123 """ 

124 Validate that the source path exists and is accessible. 

125 

126 Args: 

127 source_path: Path to validate 

128 

129 Raises: 

130 UploadError: If source path is invalid 

131 

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}")