File size: 6,118 Bytes
f1f433f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
from pathlib import Path
from typing import List

import yaml
from pydantic import ValidationError, parse_obj_as

from .Preset import Preset
from .PresetError import PresetError


class PresetManager:
    def __init__(
        self,
        preset_path: Path,
    ):
        self.presets = []
        self.last_modified_time = 0
        self.preset_path = preset_path

    def load_presets(self):
        """
        プリセットのYAMLファイルを読み込む

        Returns
        -------
        ret: List[Preset]
            プリセットのリスト
        """

        # 設定ファイルのタイムスタンプを確認
        try:
            _last_modified_time = self.preset_path.stat().st_mtime
            if _last_modified_time == self.last_modified_time:
                return self.presets
        except OSError:
            raise PresetError("プリセットの設定ファイルが見つかりません")

        with open(self.preset_path, mode="r", encoding="utf-8") as f:
            obj = yaml.safe_load(f)
            if obj is None:
                raise PresetError("プリセットの設定ファイルが空の内容です")

        try:
            _presets = parse_obj_as(List[Preset], obj)
        except ValidationError:
            raise PresetError("プリセットの設定ファイルにミスがあります")

        # idが一意か確認
        if len([preset.id for preset in _presets]) != len(
            {preset.id for preset in _presets}
        ):
            raise PresetError("プリセットのidに重複があります")

        self.presets = _presets
        self.last_modified_time = _last_modified_time
        return self.presets

    def add_preset(self, preset: Preset):
        """
        YAMLファイルに新規のプリセットを追加する

        Parameters
        ----------
        preset : Preset
            追加するプリセットを渡す

        Returns
        -------
        ret: int
            追加したプリセットのプリセットID
        """

        # 手動でファイルが更新されているかも知れないので、最新のYAMLファイルを読み直す
        self.load_presets()

        # IDが0未満、または存在するIDなら新しいIDを決定し、配列に追加
        if preset.id < 0 or preset.id in {preset.id for preset in self.presets}:
            preset.id = max([preset.id for preset in self.presets]) + 1
        self.presets.append(preset)

        # ファイルに書き込み
        try:
            with open(self.preset_path, mode="w", encoding="utf-8") as f:
                yaml.safe_dump(
                    [preset.dict() for preset in self.presets],
                    f,
                    allow_unicode=True,
                    sort_keys=False,
                )
        except Exception as err:
            self.presets.pop()
            if isinstance(err, FileNotFoundError):
                raise PresetError("プリセットの設定ファイルに書き込み失敗しました")
            else:
                raise err

        return preset.id

    def update_preset(self, preset: Preset):
        """
        YAMLファイルのプリセットを更新する

        Parameters
        ----------
        preset : Preset
            更新するプリセットを渡す

        Returns
        -------
        ret: int
            更新したプリセットのプリセットID
        """

        # 手動でファイルが更新されているかも知れないので、最新のYAMLファイルを読み直す
        self.load_presets()

        # IDが存在するか探索
        prev_preset = (-1, None)
        for i in range(len(self.presets)):
            if self.presets[i].id == preset.id:
                prev_preset = (i, self.presets[i])
                self.presets[i] = preset
                break
        else:
            raise PresetError("更新先のプリセットが存在しません")

        # ファイルに書き込み
        try:
            with open(self.preset_path, mode="w", encoding="utf-8") as f:
                yaml.safe_dump(
                    [preset.dict() for preset in self.presets],
                    f,
                    allow_unicode=True,
                    sort_keys=False,
                )
        except Exception as err:
            if prev_preset != (-1, None):
                self.presets[prev_preset[0]] = prev_preset[1]
            if isinstance(err, FileNotFoundError):
                raise PresetError("プリセットの設定ファイルに書き込み失敗しました")
            else:
                raise err

        return preset.id

    def delete_preset(self, id: int):
        """
        YAMLファイルのプリセットを削除する

        Parameters
        ----------
        id: int
            削除するプリセットのプリセットIDを渡す

        Returns
        -------
        ret: int
            削除したプリセットのプリセットID
        """

        # 手動でファイルが更新されているかも知れないので、最新のYAMLファイルを読み直す
        self.load_presets()

        # IDが存在するか探索
        buf = None
        buf_index = -1
        for i in range(len(self.presets)):
            if self.presets[i].id == id:
                buf = self.presets.pop(i)
                buf_index = i
                break
        else:
            raise PresetError("削除対象のプリセットが存在しません")

        # ファイルに書き込み
        try:
            with open(self.preset_path, mode="w", encoding="utf-8") as f:
                yaml.safe_dump(
                    [preset.dict() for preset in self.presets],
                    f,
                    allow_unicode=True,
                    sort_keys=False,
                )
        except FileNotFoundError:
            self.presets.insert(buf_index, buf)
            raise PresetError("プリセットの設定ファイルに書き込み失敗しました")

        return id