Coverage for src/prosemark/ports/config_port.py: 100%
14 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"""Abstract base class for configuration file management."""
3from abc import ABC, abstractmethod
4from pathlib import Path
5from typing import TypedDict
8class ProsemarkConfig(TypedDict, total=False):
9 """Type definition for prosemark configuration values."""
11 editor: str
12 daily_dir: str
13 binder_file: str
16class ConfigPort(ABC):
17 """Abstract base class for configuration file management.
19 Defines the contract for creating and managing prosemark configuration files.
20 This abstract base class enables:
22 * Clean separation between business logic and configuration I/O
23 * Testable configuration operations through dependency injection
24 * Support for different configuration storage mechanisms
25 * Hexagonal architecture compliance by isolating configuration concerns
26 * Future extensibility to different configuration formats or sources
28 The MVP uses this for creating default .prosemark.yml configuration files
29 during project initialization with standard YAML format and default values.
31 Examples:
32 >>> class TestConfigPort(ConfigPort):
33 ... def create_default_config(self, config_path: Path) -> None:
34 ... # Test implementation
35 ... pass
36 >>> config = TestConfigPort()
37 >>> config.create_default_config(Path('.prosemark.yml'))
39 """
41 @abstractmethod
42 def create_default_config(self, config_path: Path) -> None:
43 """Create default .prosemark.yml configuration file.
45 Writes a new configuration file with default values for all
46 prosemark settings. The configuration includes editor settings,
47 file naming patterns, binder management markers, and other
48 project-specific defaults.
50 Args:
51 config_path: Path where configuration file should be created
53 Raises:
54 FilesystemError: If configuration file cannot be written
55 NotImplementedError: If not implemented by a concrete subclass
57 """
58 msg = 'Subclasses must implement create_default_config()' # pragma: no cover
59 raise NotImplementedError(msg) # pragma: no cover
61 @abstractmethod
62 def config_exists(self, config_path: Path) -> bool:
63 """Check if configuration file already exists.
65 Determines whether a prosemark configuration file is present
66 at the specified path. Used during project initialization to
67 detect existing projects and prevent conflicts.
69 Args:
70 config_path: Path to check for configuration file existence
72 Returns:
73 True if configuration file exists, False otherwise
75 Raises:
76 NotImplementedError: If not implemented by a concrete subclass
78 """
79 msg = 'Subclasses must implement config_exists()' # pragma: no cover
80 raise NotImplementedError(msg) # pragma: no cover
82 @abstractmethod
83 def get_default_config_values(self) -> ProsemarkConfig:
84 """Return default configuration values as dictionary.
86 Provides the standard default configuration values that would be
87 written to a new .prosemark.yml file. Useful for testing and
88 validation of configuration content.
90 Returns:
91 Dictionary containing default configuration key-value pairs
93 Raises:
94 NotImplementedError: If not implemented by a concrete subclass
96 """
97 msg = 'Subclasses must implement get_default_config_values()' # pragma: no cover
98 raise NotImplementedError(msg) # pragma: no cover