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

1"""Abstract base class for configuration file management.""" 

2 

3from abc import ABC, abstractmethod 

4from pathlib import Path 

5from typing import TypedDict 

6 

7 

8class ProsemarkConfig(TypedDict, total=False): 

9 """Type definition for prosemark configuration values.""" 

10 

11 editor: str 

12 daily_dir: str 

13 binder_file: str 

14 

15 

16class ConfigPort(ABC): 

17 """Abstract base class for configuration file management. 

18 

19 Defines the contract for creating and managing prosemark configuration files. 

20 This abstract base class enables: 

21 

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 

27 

28 The MVP uses this for creating default .prosemark.yml configuration files 

29 during project initialization with standard YAML format and default values. 

30 

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

38 

39 """ 

40 

41 @abstractmethod 

42 def create_default_config(self, config_path: Path) -> None: 

43 """Create default .prosemark.yml configuration file. 

44 

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. 

49 

50 Args: 

51 config_path: Path where configuration file should be created 

52 

53 Raises: 

54 FilesystemError: If configuration file cannot be written 

55 NotImplementedError: If not implemented by a concrete subclass 

56 

57 """ 

58 msg = 'Subclasses must implement create_default_config()' # pragma: no cover 

59 raise NotImplementedError(msg) # pragma: no cover 

60 

61 @abstractmethod 

62 def config_exists(self, config_path: Path) -> bool: 

63 """Check if configuration file already exists. 

64 

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. 

68 

69 Args: 

70 config_path: Path to check for configuration file existence 

71 

72 Returns: 

73 True if configuration file exists, False otherwise 

74 

75 Raises: 

76 NotImplementedError: If not implemented by a concrete subclass 

77 

78 """ 

79 msg = 'Subclasses must implement config_exists()' # pragma: no cover 

80 raise NotImplementedError(msg) # pragma: no cover 

81 

82 @abstractmethod 

83 def get_default_config_values(self) -> ProsemarkConfig: 

84 """Return default configuration values as dictionary. 

85 

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. 

89 

90 Returns: 

91 Dictionary containing default configuration key-value pairs 

92 

93 Raises: 

94 NotImplementedError: If not implemented by a concrete subclass 

95 

96 """ 

97 msg = 'Subclasses must implement get_default_config_values()' # pragma: no cover 

98 raise NotImplementedError(msg) # pragma: no cover