Coverage for graphica/core/plugin_types.py: 100.0%

79 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-12 16:38 +0000

1"""プラグイン API で共有する型。登録されたフックの記録と、失敗の表し方。""" 

2from dataclasses import dataclass 

3from enum import Enum 

4from typing import Any, Callable 

5 

6 

7class PluginHookKind(Enum): 

8 IMPORTER = "importer" 

9 EXPORTER = "exporter" 

10 PROCESSOR = "processor" 

11 ANALYZER = "analyzer" 

12 PANEL = "panel" 

13 PLOT_TYPE = "plot_type" 

14 FIT_FUNCTION = "fit_function" 

15 MENU_ACTION = "menu_action" 

16 RENDER_BACKEND = "render_backend" 

17 

18 

19@dataclass 

20class PluginRegistrationError: 

21 """register_xxx の1回の呼び出しが失敗したこと。""" 

22 plugin_name: str 

23 hook_kind: PluginHookKind 

24 message: str 

25 exception: Exception | None = None 

26 

27 

28@dataclass 

29class PluginMenuAction: 

30 text: str 

31 callback: Callable[..., Any] # (PluginContext) -> None 

32 shortcut: str | None 

33 plugin_name: str 

34 

35 

36@dataclass 

37class PluginImporter: 

38 extension: str # ピリオド付きの小文字(例: ".jdx") 

39 loader: Callable[[str], Any] # (パス) -> pandas.DataFrame 

40 name: str # エラー表示用(通常はプラグイン名) 

41 priority: int = 0 

42 

43 

44@dataclass 

45class PluginExporter: 

46 format_name: str 

47 extension: str # ピリオド付きの小文字 

48 writer: Callable[[Any, str], Any] # (matplotlib の Figure, 出力パス) -> None 

49 name: str 

50 

51 

52@dataclass 

53class PluginProcessor: 

54 name: str 

55 fn: Callable[[Any, dict[str, Any]], Any] # (Dataset, 入力値) -> Dataset。元の Dataset は変えない 

56 category: str 

57 param_schema: list[dict[str, Any]] # 入力フォームの定義(register_processor の説明を参照) 

58 plugin_name: str 

59 

60 

61@dataclass 

62class AnalysisResult: 

63 """ 

64 register_analyzer の fn が返す解析結果。どれも省略できる。 

65 

66 Attributes: 

67 table (pandas.DataFrame | None): 結果の表。CSV に保存できる形で表示する。 

68 annotations (list[dict] | None): 現在の軸に追加する注釈(Undo できる)。 

69 new_datasets (list[Dataset] | None): 追加するデータセット(Undo できる)。 

70 """ 

71 table: Any = None 

72 annotations: list[dict[str, Any]] | None = None 

73 new_datasets: list[Any] | None = None 

74 

75 

76@dataclass 

77class PluginAnalyzer: 

78 name: str 

79 fn: Callable[[Any, dict[str, Any]], Any] # (Dataset, 入力値) -> AnalysisResult 

80 output_kind: str # 表示上の分類だけ 

81 param_schema: list[dict[str, Any]] 

82 plugin_name: str 

83 

84 

85@dataclass 

86class PluginPanel: 

87 name: str 

88 widget_factory: Callable[..., Any] # (PluginContext) -> QWidget。タブごとに1回呼ぶ 

89 area: str # "right"/"left"/"top"/"bottom"。Qt への対応付けは GUI 側(core は Qt に依存しない) 

90 plugin_name: str 

91 

92 

93@dataclass 

94class PluginPlotType: 

95 type_name: str 

96 drawer: Callable[..., Any] # (Dataset, Axes, x, y) -> Artist | None 

97 requires_2d: bool # 予約(動作に影響しない) 

98 plugin_name: str 

99 

100 

101class RenderBackend: 

102 """描画バックエンドの型の予約。描画には未接続で、持つべきメソッドも未定。""" 

103 

104 

105@dataclass 

106class PluginRenderBackend: 

107 name: str 

108 backend: "RenderBackend" 

109 plugin_name: str 

110 

111 

112class PluginExecutionError(Exception): 

113 """プラグインのフックの実行時の失敗。文字列にするとプラグイン名が付くので、そのまま表示に使える。""" 

114 

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

116 self.plugin_name = plugin_name 

117 self.message = message 

118 super().__init__(f"[{plugin_name}] {message}")