Coverage for documents/plugins/base.py: 71%

38 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-10 09:07 +0000

1import abc 

2from pathlib import Path 

3from typing import Final 

4 

5from documents.data_models import ConsumableDocument 

6from documents.data_models import DocumentMetadataOverrides 

7from documents.plugins.helpers import ProgressManager 

8 

9 

10class StopConsumeTaskError(Exception): 

11 """ 

12 A plugin setup or run may raise this to exit the asynchronous consume task. 

13 

14 Most likely, this means it has created one or more new tasks to execute instead, 

15 such as when a barcode has been used to create new documents 

16 """ 

17 

18 def __init__(self, message: str) -> None: 

19 self.message = message 

20 super().__init__(message) 

21 

22 

23class ConsumeTaskPlugin(abc.ABC): 

24 """ 

25 Defines the interface for a plugin for the document consume task 

26 Meanings as per RFC2119 (https://datatracker.ietf.org/doc/html/rfc2119) 

27 

28 Plugin Implementation 

29 

30 The plugin SHALL implement property able_to_run and methods setup, run and cleanup. 

31 The plugin property able_to_run SHALL return True if the plugin is able to run, given the conditions, settings and document information. 

32 The plugin property able_to_run MAY be hardcoded to return True. 

33 The plugin setup SHOULD perform any resource creation or additional initialization needed to run the document. 

34 The plugin setup MAY be a non-operation. 

35 The plugin cleanup SHOULD perform resource cleanup, including in the event of an error. 

36 The plugin cleanup MAY be a non-operation. 

37 The plugin run SHALL perform any operations against the document or system state required for the plugin. 

38 The plugin run MAY update the document metadata. 

39 The plugin run MAY return an informational message. 

40 The plugin run MAY raise StopConsumeTaskError to cease any further operations against the document. 

41 

42 Plugin Manager Implementation 

43 

44 The plugin manager SHALL provide the plugin with the input document, document metadata, progress manager and a created temporary directory. 

45 The plugin manager SHALL execute the plugin setup, run and cleanup, in that order IF the plugin property able_to_run is True. 

46 The plugin manager SHOULD log the return message of executing a plugin's run. 

47 The plugin manager SHALL always execute the plugin cleanup, IF the plugin property able_to_run is True. 

48 The plugin manager SHALL cease calling plugins and exit the task IF a plugin raises StopConsumeTaskError. 

49 The plugin manager SHOULD return the StopConsumeTaskError message IF a plugin raises StopConsumeTaskError. 

50 """ 

51 

52 NAME: str = "ConsumeTaskPlugin" 

53 

54 def __init__( 

55 self, 

56 input_doc: ConsumableDocument, 

57 metadata: DocumentMetadataOverrides, 

58 status_mgr: ProgressManager, 

59 base_tmp_dir: Path, 

60 task_id: str, 

61 ) -> None: 

62 super().__init__() 

63 self.input_doc = input_doc 

64 self.metadata = metadata 

65 self.base_tmp_dir: Final = base_tmp_dir 

66 self.status_mgr = status_mgr 

67 self.task_id: Final = task_id 

68 

69 @property 

70 @abc.abstractmethod 

71 def able_to_run(self) -> bool: 

72 """ 

73 Return True if the conditions are met for the plugin to run, False otherwise 

74 

75 If False, setup(), run() and cleanup() will not be called 

76 """ 

77 

78 @abc.abstractmethod 

79 def setup(self) -> None: 

80 """ 

81 Allows the plugin to perform any additional setup it may need, such as creating 

82 a temporary directory, copying a file somewhere, etc. 

83 

84 Executed before run() 

85 

86 In general, this should be the "light" work, not the bulk of processing 

87 """ 

88 

89 @abc.abstractmethod 

90 def run(self) -> str | None: 

91 """ 

92 The bulk of plugin processing, this does whatever action the plugin is for. 

93 

94 Executed after setup() and before cleanup() 

95 """ 

96 

97 @abc.abstractmethod 

98 def cleanup(self) -> None: 

99 """ 

100 Allows the plugin to execute any cleanup it may require 

101 

102 Executed after run(), even in the case of error 

103 """ 

104 

105 

106class AlwaysRunPluginMixin(ConsumeTaskPlugin): 

107 """ 

108 A plugin which is always able to run 

109 """ 

110 

111 @property 

112 def able_to_run(self) -> bool: 

113 return True 

114 

115 

116class NoSetupPluginMixin(ConsumeTaskPlugin): 

117 """ 

118 A plugin which requires no setup 

119 """ 

120 

121 def setup(self) -> None: 

122 pass 

123 

124 

125class NoCleanupPluginMixin(ConsumeTaskPlugin): 

126 """ 

127 A plugin which needs to clean up no files 

128 """ 

129 

130 def cleanup(self) -> None: 

131 pass