libscid 0.10.0__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- libscid/__init__.py +46 -0
- libscid/_arbiter.py +42 -0
- libscid/_cursor.py +290 -0
- libscid/_database.py +91 -0
- libscid/_database_filters.py +47 -0
- libscid/_database_search.py +440 -0
- libscid/_domain_support/__init__.py +1 -0
- libscid/_domain_support/_movetext_iteration.py +117 -0
- libscid/_filter.py +87 -0
- libscid/_game.py +93 -0
- libscid/_move_metadata.py +11 -0
- libscid/_nag.py +31 -0
- libscid/_native/__init__.py +25 -0
- libscid/_native/_base.py +122 -0
- libscid/_native/_bindings.py +419 -0
- libscid/_native/_constants.py +35 -0
- libscid/_native/_cursors.py +283 -0
- libscid/_native/_databases.py +371 -0
- libscid/_native/_errors.py +12 -0
- libscid/_native/_games.py +242 -0
- libscid/_native/_loader.py +57 -0
- libscid/_native/_primitives.py +176 -0
- libscid/_native/_text.py +13 -0
- libscid/_native/_types.py +40 -0
- libscid/_native/scid.dll +0 -0
- libscid/_pgn.py +16 -0
- libscid/_position.py +93 -0
- libscid-0.10.0.dist-info/METADATA +13 -0
- libscid-0.10.0.dist-info/RECORD +30 -0
- libscid-0.10.0.dist-info/WHEEL +4 -0
libscid/__init__.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Python bindings for libscid."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
from ._cursor import Cursor
|
|
6
|
+
from ._database import Database
|
|
7
|
+
from ._database_filters import DatabaseFilters
|
|
8
|
+
from ._database_search import DatabaseSearch, HeaderCriteria
|
|
9
|
+
from ._domain_support._movetext_iteration import (
|
|
10
|
+
MovetextEvent,
|
|
11
|
+
MovetextLineEnd,
|
|
12
|
+
MovetextLineStart,
|
|
13
|
+
MovetextMove,
|
|
14
|
+
)
|
|
15
|
+
from ._filter import Filter
|
|
16
|
+
from ._game import Game
|
|
17
|
+
from ._move_metadata import MoveMetadata
|
|
18
|
+
from ._nag import Nag
|
|
19
|
+
from ._native import LibScidError
|
|
20
|
+
from ._pgn import PgnOptions
|
|
21
|
+
from ._position import Position
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
__version__ = version("libscid")
|
|
25
|
+
except PackageNotFoundError:
|
|
26
|
+
__version__ = "0.0.0"
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"Cursor",
|
|
30
|
+
"Database",
|
|
31
|
+
"DatabaseFilters",
|
|
32
|
+
"DatabaseSearch",
|
|
33
|
+
"Filter",
|
|
34
|
+
"Game",
|
|
35
|
+
"HeaderCriteria",
|
|
36
|
+
"LibScidError",
|
|
37
|
+
"MoveMetadata",
|
|
38
|
+
"MovetextEvent",
|
|
39
|
+
"MovetextLineEnd",
|
|
40
|
+
"MovetextLineStart",
|
|
41
|
+
"MovetextMove",
|
|
42
|
+
"Nag",
|
|
43
|
+
"PgnOptions",
|
|
44
|
+
"Position",
|
|
45
|
+
"__version__",
|
|
46
|
+
]
|
libscid/_arbiter.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from ._cursor import Cursor
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class _PositionId:
|
|
12
|
+
board: str
|
|
13
|
+
side_to_move: str
|
|
14
|
+
castling: str
|
|
15
|
+
en_passant: str
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def from_fen(cls, fen: str) -> _PositionId:
|
|
19
|
+
board, side_to_move, castling, en_passant, *_ = fen.split()
|
|
20
|
+
return cls(board, side_to_move, castling, en_passant)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Arbiter:
|
|
24
|
+
def __init__(self, cursor: Cursor):
|
|
25
|
+
self._cursor = cursor
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def can_claim_fifty_move_rule(self) -> bool:
|
|
29
|
+
return self._cursor.position.halfmove_clock >= 100
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def can_claim_threefold_repetition(self) -> bool:
|
|
33
|
+
position_ids = self._path_position_ids()
|
|
34
|
+
return position_ids.count(position_ids[-1]) >= 3
|
|
35
|
+
|
|
36
|
+
def _path_position_ids(self) -> list[_PositionId]:
|
|
37
|
+
position = self._cursor._game.start_position
|
|
38
|
+
position_ids = [_PositionId.from_fen(position.fen)]
|
|
39
|
+
for move in self._cursor._path_move_uci():
|
|
40
|
+
position.apply_uci(move)
|
|
41
|
+
position_ids.append(_PositionId.from_fen(position.fen))
|
|
42
|
+
return position_ids
|
libscid/_cursor.py
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ctypes
|
|
4
|
+
from collections.abc import Iterator
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
from ._arbiter import Arbiter
|
|
8
|
+
from ._nag import Nag
|
|
9
|
+
from ._native import NativeLibrary
|
|
10
|
+
from ._position import Position
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from ._domain_support._movetext_iteration import MovetextEvent
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Cursor:
|
|
17
|
+
_native: NativeLibrary
|
|
18
|
+
_game: Any
|
|
19
|
+
_handle: ctypes.c_void_p
|
|
20
|
+
|
|
21
|
+
def __init__(self):
|
|
22
|
+
raise TypeError("Cursor objects are returned by libscid APIs")
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def _from_handle(
|
|
26
|
+
cls,
|
|
27
|
+
native: NativeLibrary,
|
|
28
|
+
game: Any,
|
|
29
|
+
handle: ctypes.c_void_p,
|
|
30
|
+
) -> Cursor:
|
|
31
|
+
cursor = cls.__new__(cls)
|
|
32
|
+
cursor._native = native
|
|
33
|
+
cursor._game = game
|
|
34
|
+
cursor._handle = handle
|
|
35
|
+
return cursor
|
|
36
|
+
|
|
37
|
+
def clone(self) -> Cursor:
|
|
38
|
+
return self._from_handle(
|
|
39
|
+
self._native,
|
|
40
|
+
self._game,
|
|
41
|
+
self._native.game_clone_cursor(self._game._handle, self._handle),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def next(self) -> Cursor | None:
|
|
45
|
+
return self._from_optional_handle(self._native.cursor_next(self._handle))
|
|
46
|
+
|
|
47
|
+
def previous(self) -> Cursor | None:
|
|
48
|
+
return self._from_optional_handle(self._native.cursor_previous(self._handle))
|
|
49
|
+
|
|
50
|
+
def to_game_start(self) -> Cursor:
|
|
51
|
+
return self._from_handle(
|
|
52
|
+
self._native,
|
|
53
|
+
self._game,
|
|
54
|
+
self._native.cursor_to_game_start(self._handle),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def to_game_end(self) -> Cursor:
|
|
58
|
+
return self._from_handle(
|
|
59
|
+
self._native,
|
|
60
|
+
self._game,
|
|
61
|
+
self._native.cursor_to_game_end(self._handle),
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
def to_main_line_offset(self, offset: int) -> Cursor | None:
|
|
65
|
+
return self._from_optional_handle(
|
|
66
|
+
self._native.cursor_to_main_line_offset(self._handle, offset)
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def enter_variation(self, index: int) -> Cursor | None:
|
|
70
|
+
return self._from_optional_handle(
|
|
71
|
+
self._native.cursor_enter_variation(self._handle, index)
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def exit_variation(self) -> Cursor | None:
|
|
75
|
+
return self._from_optional_handle(
|
|
76
|
+
self._native.cursor_exit_variation(self._handle)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def append_move(self, san: str | bytes) -> Cursor:
|
|
80
|
+
self._require_line_end("append_move")
|
|
81
|
+
return self._from_handle(
|
|
82
|
+
self._native,
|
|
83
|
+
self._game,
|
|
84
|
+
self._native.cursor_append_move(self._game._handle, self._handle, san),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def append_game(self, source_game: Any) -> Cursor:
|
|
88
|
+
self._require_line_end("append_game")
|
|
89
|
+
return self._from_handle(
|
|
90
|
+
self._native,
|
|
91
|
+
self._game,
|
|
92
|
+
self._native.cursor_append_game(
|
|
93
|
+
self._game._handle, self._handle, source_game._handle
|
|
94
|
+
),
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
def add_variation(self, preceding_comment: str | bytes = "") -> Cursor | None:
|
|
98
|
+
return self._from_optional_handle(
|
|
99
|
+
self._native.cursor_add_variation(
|
|
100
|
+
self._game._handle, self._handle, preceding_comment
|
|
101
|
+
)
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def remove_variation(self) -> Cursor | None:
|
|
105
|
+
return self._from_optional_handle(
|
|
106
|
+
self._native.cursor_remove_variation(self._game._handle, self._handle)
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
def promote_variation_to_first(self) -> Cursor | None:
|
|
110
|
+
return self._from_optional_handle(
|
|
111
|
+
self._native.cursor_promote_variation_to_first(
|
|
112
|
+
self._game._handle, self._handle
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def promote_variation_to_mainline(self) -> Cursor | None:
|
|
117
|
+
return self._from_optional_handle(
|
|
118
|
+
self._native.cursor_promote_variation_to_mainline(
|
|
119
|
+
self._game._handle, self._handle
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
def truncate(self) -> Cursor:
|
|
124
|
+
return self._from_handle(
|
|
125
|
+
self._native,
|
|
126
|
+
self._game,
|
|
127
|
+
self._native.cursor_truncate(self._game._handle, self._handle),
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
def truncate_before(self) -> Cursor:
|
|
131
|
+
return self._from_handle(
|
|
132
|
+
self._native,
|
|
133
|
+
self._game,
|
|
134
|
+
self._native.cursor_truncate_before(self._game._handle, self._handle),
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
def iter_movetext(self, *, variations: bool = True) -> Iterator[MovetextEvent]:
|
|
138
|
+
from ._domain_support._movetext_iteration import iter_movetext
|
|
139
|
+
|
|
140
|
+
return iter_movetext(self, variations=variations)
|
|
141
|
+
|
|
142
|
+
def _from_optional_handle(self, handle: ctypes.c_void_p | None) -> Cursor | None:
|
|
143
|
+
if handle is None:
|
|
144
|
+
return None
|
|
145
|
+
return self._from_handle(self._native, self._game, handle)
|
|
146
|
+
|
|
147
|
+
def _require_line_end(self, method: str) -> None:
|
|
148
|
+
if not self.is_line_end:
|
|
149
|
+
raise ValueError(f"{method} requires cursor at line end")
|
|
150
|
+
|
|
151
|
+
def _path_move_uci(self) -> tuple[str, ...]:
|
|
152
|
+
cursor = self.clone()
|
|
153
|
+
moves = []
|
|
154
|
+
while True:
|
|
155
|
+
move = cursor.previous_move_uci
|
|
156
|
+
if move is not None:
|
|
157
|
+
moves.append(move)
|
|
158
|
+
previous = cursor.previous()
|
|
159
|
+
if previous is None:
|
|
160
|
+
raise RuntimeError("Cursor previous move disappeared")
|
|
161
|
+
cursor = previous
|
|
162
|
+
continue
|
|
163
|
+
|
|
164
|
+
parent = cursor.exit_variation()
|
|
165
|
+
if parent is not None:
|
|
166
|
+
cursor = parent
|
|
167
|
+
continue
|
|
168
|
+
|
|
169
|
+
return tuple(reversed(moves))
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def arbiter(self) -> Arbiter:
|
|
173
|
+
return Arbiter(self)
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def previous_move_san(self) -> str | None:
|
|
177
|
+
if self.is_line_start:
|
|
178
|
+
return None
|
|
179
|
+
return self._native.cursor_previous_move_san(self._handle)
|
|
180
|
+
|
|
181
|
+
@property
|
|
182
|
+
def next_move_san(self) -> str | None:
|
|
183
|
+
if self.is_line_end:
|
|
184
|
+
return None
|
|
185
|
+
return self._native.cursor_next_move_san(self._handle)
|
|
186
|
+
|
|
187
|
+
@property
|
|
188
|
+
def previous_move_uci(self) -> str | None:
|
|
189
|
+
if self.is_line_start:
|
|
190
|
+
return None
|
|
191
|
+
return self._native.cursor_previous_move_uci(self._handle)
|
|
192
|
+
|
|
193
|
+
@property
|
|
194
|
+
def next_move_uci(self) -> str | None:
|
|
195
|
+
if self.is_line_end:
|
|
196
|
+
return None
|
|
197
|
+
return self._native.cursor_next_move_uci(self._handle)
|
|
198
|
+
|
|
199
|
+
@property
|
|
200
|
+
def previous_move_nags(self) -> tuple[Nag, ...] | None:
|
|
201
|
+
if self.is_line_start:
|
|
202
|
+
return None
|
|
203
|
+
return tuple(
|
|
204
|
+
Nag(code) for code in self._native.cursor_previous_move_nags(self._handle)
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def next_move_nags(self) -> tuple[Nag, ...] | None:
|
|
209
|
+
if self.is_line_end:
|
|
210
|
+
return None
|
|
211
|
+
return tuple(
|
|
212
|
+
Nag(code) for code in self._native.cursor_next_move_nags(self._handle)
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
@property
|
|
216
|
+
def comment(self) -> str | None:
|
|
217
|
+
if self.is_line_start:
|
|
218
|
+
return None
|
|
219
|
+
return self._native.cursor_comment(self._handle)
|
|
220
|
+
|
|
221
|
+
@property
|
|
222
|
+
def preceding_comment(self) -> str | None:
|
|
223
|
+
if not self.is_line_start:
|
|
224
|
+
return None
|
|
225
|
+
return self._native.cursor_comment(self._handle)
|
|
226
|
+
|
|
227
|
+
def set_comment(self, comment: str | bytes) -> None:
|
|
228
|
+
self._native.cursor_set_comment(self._game._handle, self._handle, comment)
|
|
229
|
+
|
|
230
|
+
def remove_comment(self) -> None:
|
|
231
|
+
self.set_comment("")
|
|
232
|
+
|
|
233
|
+
def add_nag(self, nag: Nag) -> bool:
|
|
234
|
+
return self._native.cursor_add_nag(self._game._handle, self._handle, nag.code)
|
|
235
|
+
|
|
236
|
+
def remove_move_nag(self) -> bool:
|
|
237
|
+
return self._native.cursor_remove_nag(
|
|
238
|
+
self._game._handle, self._handle, move_nag=True
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
def remove_position_nag(self) -> bool:
|
|
242
|
+
return self._native.cursor_remove_nag(
|
|
243
|
+
self._game._handle, self._handle, move_nag=False
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
def remove_nags(self) -> None:
|
|
247
|
+
self._native.cursor_remove_nags(self._game._handle, self._handle)
|
|
248
|
+
|
|
249
|
+
@property
|
|
250
|
+
def variation_count(self) -> int:
|
|
251
|
+
return self._native.cursor_variation_count(self._handle)
|
|
252
|
+
|
|
253
|
+
@property
|
|
254
|
+
def variation_depth(self) -> int:
|
|
255
|
+
return self._native.cursor_variation_depth(self._handle)
|
|
256
|
+
|
|
257
|
+
@property
|
|
258
|
+
def variation_index(self) -> int:
|
|
259
|
+
return self._native.cursor_variation_index(self._handle)
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def is_main_line(self) -> bool:
|
|
263
|
+
return self.variation_depth == 0
|
|
264
|
+
|
|
265
|
+
@property
|
|
266
|
+
def is_variation_line(self) -> bool:
|
|
267
|
+
return self.variation_depth > 0
|
|
268
|
+
|
|
269
|
+
@property
|
|
270
|
+
def is_line_start(self) -> bool:
|
|
271
|
+
return self._native.cursor_is_line_start(self._handle)
|
|
272
|
+
|
|
273
|
+
@property
|
|
274
|
+
def is_line_end(self) -> bool:
|
|
275
|
+
return self._native.cursor_is_line_end(self._handle)
|
|
276
|
+
|
|
277
|
+
@property
|
|
278
|
+
def position(self) -> Position:
|
|
279
|
+
return Position._from_handle(
|
|
280
|
+
self._native, self._native.cursor_position(self._handle)
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
def _dispose(self) -> None:
|
|
284
|
+
handle = getattr(self, "_handle", None)
|
|
285
|
+
if handle:
|
|
286
|
+
self._native.free_cursor(self._handle)
|
|
287
|
+
self._handle = ctypes.c_void_p()
|
|
288
|
+
|
|
289
|
+
def __del__(self) -> None:
|
|
290
|
+
self._dispose()
|
libscid/_database.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ctypes
|
|
4
|
+
import os
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
|
|
7
|
+
from ._database_filters import DatabaseFilters
|
|
8
|
+
from ._database_search import DatabaseSearch
|
|
9
|
+
from ._game import Game
|
|
10
|
+
from ._native import NativeLibrary, load_library
|
|
11
|
+
|
|
12
|
+
ProgressReportCallback = Callable[[int, int, str | None], None]
|
|
13
|
+
ShouldCancelFn = Callable[[], bool]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Database:
|
|
17
|
+
_native: NativeLibrary
|
|
18
|
+
_handle: ctypes.c_void_p
|
|
19
|
+
_filters: DatabaseFilters
|
|
20
|
+
_search: DatabaseSearch
|
|
21
|
+
|
|
22
|
+
def __init__(self):
|
|
23
|
+
raise TypeError("Database objects are returned by libscid APIs")
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def open_pgn_read_only(
|
|
27
|
+
cls,
|
|
28
|
+
path: str | os.PathLike[str],
|
|
29
|
+
progress_report_callback: ProgressReportCallback | None = None,
|
|
30
|
+
should_cancel: ShouldCancelFn | None = None,
|
|
31
|
+
) -> Database:
|
|
32
|
+
native = load_library()
|
|
33
|
+
return cls._from_handle(
|
|
34
|
+
native,
|
|
35
|
+
native.open_pgn_database_read_only(
|
|
36
|
+
path,
|
|
37
|
+
progress_report_callback=progress_report_callback,
|
|
38
|
+
should_cancel=should_cancel,
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def _from_handle(cls, native: NativeLibrary, handle: ctypes.c_void_p) -> Database:
|
|
44
|
+
database = cls.__new__(cls)
|
|
45
|
+
database._native = native
|
|
46
|
+
database._handle = handle
|
|
47
|
+
database._filters = DatabaseFilters._from_database(native, database)
|
|
48
|
+
database._search = DatabaseSearch._from_database(native, database)
|
|
49
|
+
return database
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def type(self) -> str:
|
|
53
|
+
return self._native.database_type(self._handle)
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def read_only(self) -> bool:
|
|
57
|
+
return self._native.database_read_only(self._handle)
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def game_count(self) -> int:
|
|
61
|
+
return self._native.database_game_count(self._handle)
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def filters(self) -> DatabaseFilters:
|
|
65
|
+
return self._filters
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def search(self) -> DatabaseSearch:
|
|
69
|
+
return self._search
|
|
70
|
+
|
|
71
|
+
def get_tag(self, index: int, name: str | bytes) -> str:
|
|
72
|
+
return self._native.database_game_tag(self._handle, index, name)
|
|
73
|
+
|
|
74
|
+
def get_game(self, index: int) -> Game:
|
|
75
|
+
return Game._from_handle(
|
|
76
|
+
self._native, self._native.database_game(self._handle, index)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def close(self) -> None:
|
|
80
|
+
handle = getattr(self, "_handle", None)
|
|
81
|
+
if handle:
|
|
82
|
+
self._native.close_database(handle)
|
|
83
|
+
|
|
84
|
+
def _dispose(self) -> None:
|
|
85
|
+
handle = getattr(self, "_handle", None)
|
|
86
|
+
if handle:
|
|
87
|
+
self._native.free_database(handle)
|
|
88
|
+
self._handle = ctypes.c_void_p()
|
|
89
|
+
|
|
90
|
+
def __del__(self) -> None:
|
|
91
|
+
self._dispose()
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from ._filter import Filter
|
|
6
|
+
from ._native import NativeLibrary
|
|
7
|
+
from ._native._constants import SCID_FILTER_ALL_GAMES, SCID_FILTER_PRIMARY
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from ._database import Database
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DatabaseFilters:
|
|
14
|
+
_native: NativeLibrary
|
|
15
|
+
_database: Database
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
raise TypeError("DatabaseFilters objects are returned by libscid APIs")
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def _from_database(
|
|
22
|
+
cls, native: NativeLibrary, database: Database
|
|
23
|
+
) -> DatabaseFilters:
|
|
24
|
+
filters = cls.__new__(cls)
|
|
25
|
+
filters._native = native
|
|
26
|
+
filters._database = database
|
|
27
|
+
return filters
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def all_games(self) -> Filter:
|
|
31
|
+
return Filter._from_id(
|
|
32
|
+
self._native, self._database, SCID_FILTER_ALL_GAMES, owned=False
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def primary(self) -> Filter:
|
|
37
|
+
return Filter._from_id(
|
|
38
|
+
self._native, self._database, SCID_FILTER_PRIMARY, owned=False
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def create(self) -> Filter:
|
|
42
|
+
return Filter._from_id(
|
|
43
|
+
self._native,
|
|
44
|
+
self._database,
|
|
45
|
+
self._native.database_filter_create(self._database._handle),
|
|
46
|
+
owned=True,
|
|
47
|
+
)
|