Coverage for src/prosemark/freewriting/ports/file_system.py: 100%
26 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-09-24 18:08 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-09-24 18:08 +0000
1"""File system port interface for freewriting feature.
3This module defines the port interface for file system operations
4required by the freewriting functionality.
5"""
7from __future__ import annotations
9from abc import ABC, abstractmethod
10from pathlib import Path
13class FileSystemPort(ABC):
14 """Port interface for file system operations.
16 This port defines the contract for low-level file operations
17 that the freewriting feature needs, including reading, writing,
18 and directory management.
19 """
21 @abstractmethod
22 def write_file(self, file_path: str, content: str, append: bool = False) -> None: # noqa: FBT001, FBT002
23 """Write content to file.
25 Args:
26 file_path: Target file path (should be absolute).
27 content: Content to write.
28 append: Whether to append (True) or overwrite (False).
30 Raises:
31 FileSystemError: If write operation fails.
33 """
35 @abstractmethod
36 def read_file(self, file_path: str) -> str:
37 """Read content from file.
39 Args:
40 file_path: Path to file to read.
42 Returns:
43 File content as string.
45 Raises:
46 FileSystemError: If read operation fails.
48 """
50 @abstractmethod
51 def file_exists(self, file_path: str) -> bool:
52 """Check if file exists.
54 Args:
55 file_path: Path to check.
57 Returns:
58 True if file exists, False otherwise.
60 """
62 @abstractmethod
63 def create_directory(self, directory_path: str, parents: bool = True) -> None: # noqa: FBT001, FBT002
64 """Create directory if it doesn't exist.
66 Args:
67 directory_path: Path to directory to create.
68 parents: Whether to create parent directories if they don't exist.
70 Raises:
71 FileSystemError: If directory creation fails.
73 """
75 @abstractmethod
76 def get_current_directory(self) -> str:
77 """Get current working directory.
79 Returns:
80 Absolute path to current directory.
82 """
84 @abstractmethod
85 def is_writable(self, directory_path: str) -> bool:
86 """Check if directory is writable.
88 Args:
89 directory_path: Directory to check.
91 Returns:
92 True if writable, False otherwise.
94 """
96 @abstractmethod
97 def get_absolute_path(self, path: str) -> str:
98 """Convert path to absolute path.
100 Args:
101 path: Path to convert (can be relative or absolute).
103 Returns:
104 Absolute path string.
106 """
108 @abstractmethod
109 def join_paths(self, *paths: str) -> str:
110 """Join multiple path components into a single path.
112 Args:
113 *paths: Path components to join.
115 Returns:
116 Joined path string.
118 """
120 @abstractmethod
121 def get_file_size(self, file_path: str) -> int:
122 """Get size of file in bytes.
124 Args:
125 file_path: Path to file.
127 Returns:
128 File size in bytes.
130 Raises:
131 FileSystemError: If file doesn't exist or size cannot be determined.
133 """
135 @abstractmethod
136 def backup_file(self, file_path: str, backup_suffix: str = '.bak') -> str:
137 """Create backup copy of file.
139 Args:
140 file_path: Path to file to backup.
141 backup_suffix: Suffix to add to backup file name.
143 Returns:
144 Path to backup file.
146 Raises:
147 FileSystemError: If backup creation fails.
149 """
151 @abstractmethod
152 def ensure_parent_directory(self, file_path: str) -> None:
153 """Ensure parent directory of file exists.
155 Args:
156 file_path: Path to file whose parent directory should exist.
158 Raises:
159 FileSystemError: If parent directory cannot be created.
161 """
163 @staticmethod
164 def resolve_path(path: str) -> Path: # pragma: no cover
165 """Resolve path to pathlib.Path object.
167 Args:
168 path: Path string to resolve.
170 Returns:
171 Resolved Path object.
173 """
174 return Path(path).resolve()