amulet-core 2.0a3__cp312-cp312-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.

Potentially problematic release.


This version of amulet-core might be problematic. Click here for more details.

Files changed (210) hide show
  1. amulet/__init__.cp312-win_amd64.pyd +0 -0
  2. amulet/__init__.pyi +30 -0
  3. amulet/__pyinstaller/__init__.py +2 -0
  4. amulet/__pyinstaller/hook-amulet.py +4 -0
  5. amulet/_init.py +28 -0
  6. amulet/_version.py +21 -0
  7. amulet/biome.cpp +36 -0
  8. amulet/biome.hpp +43 -0
  9. amulet/biome.pyi +77 -0
  10. amulet/block.cpp +435 -0
  11. amulet/block.hpp +119 -0
  12. amulet/block.pyi +273 -0
  13. amulet/block_entity.cpp +12 -0
  14. amulet/block_entity.hpp +56 -0
  15. amulet/block_entity.pyi +80 -0
  16. amulet/chunk.cpp +16 -0
  17. amulet/chunk.hpp +99 -0
  18. amulet/chunk.pyi +30 -0
  19. amulet/chunk_/components/biome.py +155 -0
  20. amulet/chunk_/components/block_entity.py +117 -0
  21. amulet/chunk_/components/entity.py +64 -0
  22. amulet/chunk_/components/height_2d.py +16 -0
  23. amulet/chunk_components.pyi +95 -0
  24. amulet/collections.pyi +37 -0
  25. amulet/data_types.py +29 -0
  26. amulet/entity.py +180 -0
  27. amulet/errors.py +63 -0
  28. amulet/game/__init__.py +7 -0
  29. amulet/game/_game.py +152 -0
  30. amulet/game/_universal/__init__.py +1 -0
  31. amulet/game/_universal/_biome.py +17 -0
  32. amulet/game/_universal/_block.py +47 -0
  33. amulet/game/_universal/_version.py +68 -0
  34. amulet/game/abc/__init__.py +22 -0
  35. amulet/game/abc/_block_specification.py +150 -0
  36. amulet/game/abc/biome.py +213 -0
  37. amulet/game/abc/block.py +331 -0
  38. amulet/game/abc/game_version_container.py +25 -0
  39. amulet/game/abc/json_interface.py +27 -0
  40. amulet/game/abc/version.py +44 -0
  41. amulet/game/bedrock/__init__.py +1 -0
  42. amulet/game/bedrock/_biome.py +35 -0
  43. amulet/game/bedrock/_block.py +42 -0
  44. amulet/game/bedrock/_version.py +165 -0
  45. amulet/game/java/__init__.py +2 -0
  46. amulet/game/java/_biome.py +35 -0
  47. amulet/game/java/_block.py +60 -0
  48. amulet/game/java/_version.py +176 -0
  49. amulet/game/translate/__init__.py +12 -0
  50. amulet/game/translate/_functions/__init__.py +15 -0
  51. amulet/game/translate/_functions/_code_functions/__init__.py +0 -0
  52. amulet/game/translate/_functions/_code_functions/_text.py +553 -0
  53. amulet/game/translate/_functions/_code_functions/banner_pattern.py +67 -0
  54. amulet/game/translate/_functions/_code_functions/bedrock_chest_connection.py +152 -0
  55. amulet/game/translate/_functions/_code_functions/bedrock_moving_block_pos.py +88 -0
  56. amulet/game/translate/_functions/_code_functions/bedrock_sign.py +152 -0
  57. amulet/game/translate/_functions/_code_functions/bedrock_skull_rotation.py +16 -0
  58. amulet/game/translate/_functions/_code_functions/custom_name.py +146 -0
  59. amulet/game/translate/_functions/_frozen.py +66 -0
  60. amulet/game/translate/_functions/_state.py +54 -0
  61. amulet/game/translate/_functions/_typing.py +98 -0
  62. amulet/game/translate/_functions/abc.py +116 -0
  63. amulet/game/translate/_functions/carry_nbt.py +160 -0
  64. amulet/game/translate/_functions/carry_properties.py +80 -0
  65. amulet/game/translate/_functions/code.py +143 -0
  66. amulet/game/translate/_functions/map_block_name.py +66 -0
  67. amulet/game/translate/_functions/map_nbt.py +111 -0
  68. amulet/game/translate/_functions/map_properties.py +93 -0
  69. amulet/game/translate/_functions/multiblock.py +112 -0
  70. amulet/game/translate/_functions/new_block.py +42 -0
  71. amulet/game/translate/_functions/new_entity.py +43 -0
  72. amulet/game/translate/_functions/new_nbt.py +206 -0
  73. amulet/game/translate/_functions/new_properties.py +64 -0
  74. amulet/game/translate/_functions/sequence.py +51 -0
  75. amulet/game/translate/_functions/walk_input_nbt.py +331 -0
  76. amulet/game/translate/_translator.py +433 -0
  77. amulet/item.py +75 -0
  78. amulet/level/__init__.pyi +27 -0
  79. amulet/level/_load.py +100 -0
  80. amulet/level/abc/__init__.py +12 -0
  81. amulet/level/abc/_chunk_handle.py +335 -0
  82. amulet/level/abc/_dimension.py +86 -0
  83. amulet/level/abc/_history/__init__.py +1 -0
  84. amulet/level/abc/_history/_cache.py +224 -0
  85. amulet/level/abc/_history/_history_manager.py +291 -0
  86. amulet/level/abc/_level/__init__.py +5 -0
  87. amulet/level/abc/_level/_compactable_level.py +10 -0
  88. amulet/level/abc/_level/_creatable_level.py +29 -0
  89. amulet/level/abc/_level/_disk_level.py +17 -0
  90. amulet/level/abc/_level/_level.py +453 -0
  91. amulet/level/abc/_level/_loadable_level.py +42 -0
  92. amulet/level/abc/_player_storage.py +7 -0
  93. amulet/level/abc/_raw_level.py +187 -0
  94. amulet/level/abc/_registry.py +40 -0
  95. amulet/level/bedrock/__init__.py +2 -0
  96. amulet/level/bedrock/_chunk_handle.py +19 -0
  97. amulet/level/bedrock/_dimension.py +22 -0
  98. amulet/level/bedrock/_level.py +187 -0
  99. amulet/level/bedrock/_raw/__init__.py +5 -0
  100. amulet/level/bedrock/_raw/_actor_counter.py +53 -0
  101. amulet/level/bedrock/_raw/_chunk.py +54 -0
  102. amulet/level/bedrock/_raw/_chunk_decode.py +668 -0
  103. amulet/level/bedrock/_raw/_chunk_encode.py +602 -0
  104. amulet/level/bedrock/_raw/_constant.py +9 -0
  105. amulet/level/bedrock/_raw/_dimension.py +343 -0
  106. amulet/level/bedrock/_raw/_level.py +463 -0
  107. amulet/level/bedrock/_raw/_level_dat.py +90 -0
  108. amulet/level/bedrock/_raw/_typing.py +6 -0
  109. amulet/level/bedrock/_raw/leveldb_chunk_versions.py +83 -0
  110. amulet/level/bedrock/chunk/__init__.py +1 -0
  111. amulet/level/bedrock/chunk/_chunk.py +126 -0
  112. amulet/level/bedrock/chunk/components/__init__.py +0 -0
  113. amulet/level/bedrock/chunk/components/chunk_version.py +12 -0
  114. amulet/level/bedrock/chunk/components/finalised_state.py +13 -0
  115. amulet/level/bedrock/chunk/components/raw_chunk.py +15 -0
  116. amulet/level/construction/__init__.py +0 -0
  117. amulet/level/java/__init__.pyi +21 -0
  118. amulet/level/java/_chunk_handle.py +17 -0
  119. amulet/level/java/_chunk_handle.pyi +15 -0
  120. amulet/level/java/_dimension.py +20 -0
  121. amulet/level/java/_dimension.pyi +13 -0
  122. amulet/level/java/_level.py +184 -0
  123. amulet/level/java/_level.pyi +120 -0
  124. amulet/level/java/_raw/__init__.pyi +19 -0
  125. amulet/level/java/_raw/_chunk.pyi +23 -0
  126. amulet/level/java/_raw/_chunk_decode.py +561 -0
  127. amulet/level/java/_raw/_chunk_encode.py +463 -0
  128. amulet/level/java/_raw/_constant.py +9 -0
  129. amulet/level/java/_raw/_constant.pyi +20 -0
  130. amulet/level/java/_raw/_data_pack/__init__.py +2 -0
  131. amulet/level/java/_raw/_data_pack/__init__.pyi +8 -0
  132. amulet/level/java/_raw/_data_pack/data_pack.py +241 -0
  133. amulet/level/java/_raw/_data_pack/data_pack.pyi +197 -0
  134. amulet/level/java/_raw/_data_pack/data_pack_manager.py +77 -0
  135. amulet/level/java/_raw/_data_pack/data_pack_manager.pyi +75 -0
  136. amulet/level/java/_raw/_dimension.py +86 -0
  137. amulet/level/java/_raw/_dimension.pyi +72 -0
  138. amulet/level/java/_raw/_level.py +507 -0
  139. amulet/level/java/_raw/_level.pyi +238 -0
  140. amulet/level/java/_raw/_typing.py +3 -0
  141. amulet/level/java/_raw/_typing.pyi +5 -0
  142. amulet/level/java/anvil/__init__.py +2 -0
  143. amulet/level/java/anvil/__init__.pyi +11 -0
  144. amulet/level/java/anvil/_dimension.py +170 -0
  145. amulet/level/java/anvil/_dimension.pyi +109 -0
  146. amulet/level/java/anvil/_region.py +421 -0
  147. amulet/level/java/anvil/_region.pyi +197 -0
  148. amulet/level/java/anvil/_sector_manager.py +223 -0
  149. amulet/level/java/anvil/_sector_manager.pyi +142 -0
  150. amulet/level/java/chunk.pyi +81 -0
  151. amulet/level/java/chunk_/_chunk.py +260 -0
  152. amulet/level/java/chunk_/components/inhabited_time.py +12 -0
  153. amulet/level/java/chunk_/components/last_update.py +12 -0
  154. amulet/level/java/chunk_/components/legacy_version.py +12 -0
  155. amulet/level/java/chunk_/components/light_populated.py +12 -0
  156. amulet/level/java/chunk_/components/named_height_2d.py +37 -0
  157. amulet/level/java/chunk_/components/status.py +11 -0
  158. amulet/level/java/chunk_/components/terrain_populated.py +12 -0
  159. amulet/level/java/chunk_components.pyi +22 -0
  160. amulet/level/java/long_array.pyi +38 -0
  161. amulet/level/java_forge/__init__.py +0 -0
  162. amulet/level/mcstructure/__init__.py +0 -0
  163. amulet/level/nbt/__init__.py +0 -0
  164. amulet/level/schematic/__init__.py +0 -0
  165. amulet/level/sponge_schematic/__init__.py +0 -0
  166. amulet/level/temporary_level/__init__.py +1 -0
  167. amulet/level/temporary_level/_level.py +16 -0
  168. amulet/palette/__init__.pyi +8 -0
  169. amulet/palette/biome_palette.pyi +45 -0
  170. amulet/palette/block_palette.pyi +45 -0
  171. amulet/player.py +64 -0
  172. amulet/py.typed +0 -0
  173. amulet/selection/__init__.py +2 -0
  174. amulet/selection/abstract_selection.py +342 -0
  175. amulet/selection/box.py +852 -0
  176. amulet/selection/group.py +481 -0
  177. amulet/utils/__init__.pyi +28 -0
  178. amulet/utils/call_spec/__init__.py +24 -0
  179. amulet/utils/call_spec/__init__.pyi +53 -0
  180. amulet/utils/call_spec/_call_spec.py +262 -0
  181. amulet/utils/call_spec/_call_spec.pyi +272 -0
  182. amulet/utils/format_utils.py +41 -0
  183. amulet/utils/generator.py +18 -0
  184. amulet/utils/matrix.py +243 -0
  185. amulet/utils/matrix.pyi +177 -0
  186. amulet/utils/numpy.pyi +11 -0
  187. amulet/utils/numpy_helpers.py +19 -0
  188. amulet/utils/shareable_lock.py +335 -0
  189. amulet/utils/shareable_lock.pyi +190 -0
  190. amulet/utils/signal/__init__.py +10 -0
  191. amulet/utils/signal/__init__.pyi +25 -0
  192. amulet/utils/signal/_signal.py +228 -0
  193. amulet/utils/signal/_signal.pyi +84 -0
  194. amulet/utils/task_manager.py +235 -0
  195. amulet/utils/task_manager.pyi +168 -0
  196. amulet/utils/typed_property.py +111 -0
  197. amulet/utils/typing.py +4 -0
  198. amulet/utils/typing.pyi +6 -0
  199. amulet/utils/weakref.py +70 -0
  200. amulet/utils/weakref.pyi +50 -0
  201. amulet/utils/world_utils.py +102 -0
  202. amulet/utils/world_utils.pyi +109 -0
  203. amulet/version.cpp +136 -0
  204. amulet/version.hpp +142 -0
  205. amulet/version.pyi +94 -0
  206. amulet_core-2.0a3.dist-info/METADATA +103 -0
  207. amulet_core-2.0a3.dist-info/RECORD +210 -0
  208. amulet_core-2.0a3.dist-info/WHEEL +5 -0
  209. amulet_core-2.0a3.dist-info/entry_points.txt +2 -0
  210. amulet_core-2.0a3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,335 @@
1
+ from typing import Callable, Iterator
2
+ from threading import Lock, Condition, get_ident
3
+ from contextlib import contextmanager
4
+ import time
5
+ import logging
6
+
7
+ from .task_manager import AbstractCancelManager, VoidCancelManager, TaskCancelled
8
+
9
+
10
+ log = logging.getLogger(__name__)
11
+
12
+
13
+ class LockNotAcquired(TaskCancelled):
14
+ """An exception raised if the lock was not acquired."""
15
+
16
+
17
+ class ShareableRLock:
18
+ """
19
+ This is a custom lock implementation that can be acquired in
20
+ 1) unique mode.
21
+ - This is the normal mode where only this thread can use the resource.
22
+ - All other acquires block until this releases it.
23
+ 2) shared mode.
24
+ - This allows multiple threads to acquire the resource at the same time.
25
+ - This is useful if multiple threads want to read a resource but not write to it.
26
+ - If the resource is locked in unique mode this will block
27
+ - Once locked in shared mode it
28
+
29
+ """
30
+
31
+ _state_lock: Lock
32
+ _state_condition: Condition
33
+ _blocking_threads: dict[
34
+ int, tuple[bool, bool]
35
+ ] # dict[thread_id, tuple[is_serial, is_blocking]]
36
+ _unique_thread: int | None
37
+ _unique_r_count: int
38
+ _shared_threads: dict[
39
+ int, int
40
+ ] # Map from thread id to the number of times it has been acquired in shared mode.
41
+
42
+ def __init__(self) -> None:
43
+ self._state_lock = Lock()
44
+ self._state_condition = Condition(self._state_lock)
45
+ self._blocking_threads = {}
46
+ self._unique_thread = None
47
+ self._unique_r_count = 0
48
+ self._shared_threads = {}
49
+
50
+ def _wait(
51
+ self,
52
+ exit_condition: Callable[[], bool],
53
+ blocking: bool = True,
54
+ timeout: float = -1,
55
+ task_manager: AbstractCancelManager = VoidCancelManager(),
56
+ ) -> bool:
57
+ """Wait until a condition is False.
58
+
59
+ :param exit_condition: The condition to check.
60
+ :param blocking: Should this block until the lock can be acquired. Default is True.
61
+ If false and the lock cannot be acquired on the first try, this returns False.
62
+ :param timeout: Maximum amount of time to block for. Has no effect is blocking is False. Default is forever.
63
+ :param task_manager: A custom object through which acquiring can be cancelled.
64
+ This effectively manually triggers timeout.
65
+ This is useful for GUIs so that the user can cancel an operation that may otherwise block for a while.
66
+ :return: True if the lock was acquired, otherwise False.
67
+ """
68
+ if task_manager.is_cancel_requested():
69
+ return False
70
+
71
+ if exit_condition():
72
+ # We don't need to wait
73
+ return True
74
+
75
+ if not blocking:
76
+ # Need to wait but told not to
77
+ return False
78
+
79
+ if timeout == -1:
80
+ # wait with no timeout
81
+ while not exit_condition():
82
+ if task_manager.is_cancel_requested():
83
+ return False
84
+ self._state_condition.wait()
85
+ return True
86
+
87
+ else:
88
+ # Wait with a timeout
89
+ end_time = time.time() + timeout
90
+ while not exit_condition():
91
+ if task_manager.is_cancel_requested():
92
+ return False
93
+ wait_time = end_time - time.time()
94
+ if wait_time > 0:
95
+ self._state_condition.wait(wait_time)
96
+ else:
97
+ return False
98
+ return True
99
+
100
+ def acquire_unique(
101
+ self,
102
+ blocking: bool = True,
103
+ timeout: float = -1,
104
+ task_manager: AbstractCancelManager = VoidCancelManager(),
105
+ ) -> bool:
106
+ """
107
+ Only use this if you know what you are doing. Consider using :meth:`unique` instead
108
+ Acquire the lock in unique mode. This is equivalent to threading.RLock.acquire
109
+ With improper use this can lead to a deadlock.
110
+ :param blocking: Should this block until the lock can be acquired. Default is True.
111
+ If false and the lock cannot be acquired on the first try, this returns False.
112
+ :param timeout: Maximum amount of time to block for. Has no effect is blocking is False. Default is forever.
113
+ :param task_manager: A custom object through which acquiring can be cancelled.
114
+ This effectively manually triggers timeout.
115
+ This is useful for GUIs so that the user can cancel an operation that may otherwise block for a while.
116
+ :return: True if the lock was acquired otherwise False.
117
+ """
118
+ with self._state_lock:
119
+ ident = get_ident()
120
+ if (
121
+ ident in self._shared_threads
122
+ and blocking
123
+ and timeout == -1
124
+ and any(
125
+ self._blocking_threads[thread_id][1]
126
+ for thread_id in self._blocking_threads
127
+ if thread_id in self._shared_threads
128
+ )
129
+ ):
130
+ logging.warning("Possible deadlock")
131
+
132
+ def on_cancel() -> None:
133
+ with self._state_lock:
134
+ self._state_condition.notify_all()
135
+
136
+ task_manager.register_on_cancel(on_cancel)
137
+
138
+ self._blocking_threads[ident] = (
139
+ True,
140
+ blocking
141
+ and timeout == -1
142
+ and isinstance(task_manager, VoidCancelManager),
143
+ )
144
+
145
+ def exit_condition() -> bool:
146
+ # The thread was the first to join
147
+ # The lock is not locked or is locked by this thread
148
+ can_exit = (
149
+ next(iter(self._blocking_threads)) == ident
150
+ and self._unique_thread in (None, ident)
151
+ and self._shared_threads.keys() in (set(), {ident})
152
+ )
153
+ if can_exit:
154
+ self._blocking_threads.pop(ident)
155
+ return can_exit
156
+
157
+ locked = self._wait(
158
+ exit_condition,
159
+ blocking,
160
+ timeout,
161
+ task_manager,
162
+ )
163
+
164
+ task_manager.unregister_on_cancel(on_cancel)
165
+
166
+ if locked:
167
+ # Lock it
168
+ self._unique_thread = ident
169
+ self._unique_r_count += 1
170
+ return True
171
+ else:
172
+ self._blocking_threads.pop(ident)
173
+ return False
174
+
175
+ def release_unique(self) -> None:
176
+ """
177
+ Only use this if you know what you are doing. Consider using :meth:`unique` instead
178
+ Release the unique hold on the lock. This must be called by the same thread that acquired it.
179
+ This must be called exactly the same number of times as :meth:`acquire_unique` was called.
180
+ """
181
+ with self._state_lock:
182
+ if self._unique_thread != get_ident():
183
+ raise RuntimeError("Lock released by a thread that does not own it.")
184
+
185
+ self._unique_r_count -= 1
186
+ if self._unique_r_count == 0:
187
+ self._unique_thread = None
188
+ # Let another thread continue
189
+ self._state_condition.notify_all()
190
+
191
+ def acquire_shared(
192
+ self,
193
+ blocking: bool = True,
194
+ timeout: float = -1,
195
+ task_manager: AbstractCancelManager = VoidCancelManager(),
196
+ ) -> bool:
197
+ """
198
+ Only use this if you know what you are doing. Consider using :meth:`shared` instead
199
+ Acquire the lock in shared mode.
200
+ :param blocking: Should this block until the lock can be acquired. Default is True.
201
+ If false and the lock cannot be acquired on the first try, this returns False.
202
+ :param timeout: Maximum amount of time to block for. Has no effect is blocking is False. Default is forever.
203
+ :param task_manager: A custom object through which acquiring can be cancelled.
204
+ This effectively manually triggers timeout.
205
+ This is useful for GUIs so that the user can cancel an operation that may otherwise block for a while.
206
+ :return: True if the lock was acquired otherwise False.
207
+ """
208
+ with self._state_lock:
209
+ ident = get_ident()
210
+
211
+ def exit_condition() -> bool:
212
+ if self._unique_thread == ident or ident in self._shared_threads:
213
+ # Lock is already acquired by this thread
214
+ self._blocking_threads.pop(ident)
215
+ return True
216
+ elif self._unique_thread is None:
217
+ # Is it not locked in unique mode
218
+ for thread_id, (is_serial, _) in self._blocking_threads.items():
219
+ if is_serial:
220
+ return False
221
+ elif thread_id == ident:
222
+ self._blocking_threads.pop(ident)
223
+ return True
224
+ return False
225
+
226
+ def on_cancel() -> None:
227
+ with self._state_lock:
228
+ self._state_condition.notify_all()
229
+
230
+ task_manager.register_on_cancel(on_cancel)
231
+
232
+ self._blocking_threads[ident] = (False, False)
233
+
234
+ locked = self._wait(exit_condition, blocking, timeout, task_manager)
235
+
236
+ task_manager.unregister_on_cancel(on_cancel)
237
+
238
+ if locked:
239
+ # Not unique locked or unique locked by the current thread
240
+ self._shared_threads.setdefault(ident, 0)
241
+ self._shared_threads[ident] += 1
242
+ return True
243
+ else:
244
+ self._blocking_threads.pop(ident)
245
+ return False
246
+
247
+ def release_shared(self) -> None:
248
+ """
249
+ Only use this if you know what you are doing. Consider using :meth:`shared` instead
250
+ Release the shared hold on the lock. This must be called by the same thread that acquired it.
251
+ This must be called exactly the same number of times as :meth:`acquire_shared` was called.
252
+ """
253
+ with self._state_lock:
254
+ ident = get_ident()
255
+ if ident not in self._shared_threads:
256
+ raise RuntimeError("Lock released by a thread that does not own it.")
257
+
258
+ self._shared_threads[ident] -= 1
259
+ if self._shared_threads[ident] == 0:
260
+ self._shared_threads.pop(ident)
261
+ self._state_condition.notify_all()
262
+
263
+ @contextmanager
264
+ def unique(
265
+ self,
266
+ blocking: bool = True,
267
+ timeout: float = -1,
268
+ task_manager: AbstractCancelManager = VoidCancelManager(),
269
+ ) -> Iterator[None]:
270
+ """
271
+ Acquire the lock in unique mode.
272
+ This is used as follows
273
+
274
+ >>> lock: ShareableRLock
275
+ >>> with lock.unique():
276
+ >>> # code with lock acquired
277
+ >>> # the lock will automatically be released here
278
+
279
+ This will block while all other threads using the resource finish
280
+ and once acquired block all other threads until the lock is released.
281
+
282
+ :param blocking: Should this block until the lock can be acquired. Default is True.
283
+ If false and the lock cannot be acquired on the first try, this returns False.
284
+ :param timeout: Maximum amount of time to block for. Has no effect is blocking is False. Default is forever.
285
+ :param task_manager: A custom object through which acquiring can be cancelled.
286
+ This effectively manually triggers timeout.
287
+ This is useful for GUIs so that the user can cancel an operation that may otherwise block for a while.
288
+ :return: None
289
+ :raises: LockNotAcquired if the lock could not be acquired.
290
+ """
291
+ if not self.acquire_unique(blocking, timeout, task_manager):
292
+ raise LockNotAcquired
293
+ try:
294
+ yield
295
+ finally:
296
+ self.release_unique()
297
+
298
+ @contextmanager
299
+ def shared(
300
+ self,
301
+ blocking: bool = True,
302
+ timeout: float = -1,
303
+ task_manager: AbstractCancelManager = VoidCancelManager(),
304
+ ) -> Iterator[None]:
305
+ """
306
+ Acquire the lock in shared mode.
307
+ This is used as follows
308
+
309
+ >>> lock: ShareableRLock
310
+ >>> with lock.shared():
311
+ >>> # code with lock acquired
312
+ >>> # the lock will automatically be released here
313
+
314
+ If the lock is acquired by a different thread in unique mode then this will block until it is finished.
315
+ If the lock is acquired in unique mode by this thread or by otherthreads in shared mode then this will acquire
316
+ the lock.
317
+
318
+ If another thread wants to acquire the lock in unique mode it will block until all threads have finished in
319
+ shared mode.
320
+
321
+ :param blocking: Should this block until the lock can be acquired. Default is True.
322
+ If false and the lock cannot be acquired on the first try, this returns False.
323
+ :param timeout: Maximum amount of time to block for. Has no effect is blocking is False. Default is forever.
324
+ :param task_manager: A custom object through which acquiring can be cancelled.
325
+ This effectively manually triggers timeout.
326
+ This is useful for GUIs so that the user can cancel an operation that may otherwise block for a while.
327
+ :return: None
328
+ :raises: LockNotAcquired if the lock could not be acquired.
329
+ """
330
+ if not self.acquire_shared(blocking, timeout, task_manager):
331
+ raise LockNotAcquired
332
+ try:
333
+ yield
334
+ finally:
335
+ self.release_shared()
@@ -0,0 +1,190 @@
1
+ from __future__ import annotations
2
+
3
+ import logging as logging
4
+ import time as time
5
+ from _thread import allocate_lock as Lock
6
+ from _thread import get_ident
7
+ from contextlib import contextmanager
8
+ from threading import Condition
9
+
10
+ import amulet.utils.task_manager
11
+ from amulet.utils.task_manager import (
12
+ AbstractCancelManager,
13
+ TaskCancelled,
14
+ VoidCancelManager,
15
+ )
16
+
17
+ __all__ = [
18
+ "AbstractCancelManager",
19
+ "Condition",
20
+ "Lock",
21
+ "LockNotAcquired",
22
+ "ShareableRLock",
23
+ "TaskCancelled",
24
+ "VoidCancelManager",
25
+ "contextmanager",
26
+ "get_ident",
27
+ "log",
28
+ "logging",
29
+ "time",
30
+ ]
31
+
32
+ class LockNotAcquired(amulet.utils.task_manager.TaskCancelled):
33
+ """
34
+ An exception raised if the lock was not acquired.
35
+ """
36
+
37
+ class ShareableRLock:
38
+ """
39
+
40
+ This is a custom lock implementation that can be acquired in
41
+ 1) unique mode.
42
+ - This is the normal mode where only this thread can use the resource.
43
+ - All other acquires block until this releases it.
44
+ 2) shared mode.
45
+ - This allows multiple threads to acquire the resource at the same time.
46
+ - This is useful if multiple threads want to read a resource but not write to it.
47
+ - If the resource is locked in unique mode this will block
48
+ - Once locked in shared mode it
49
+
50
+
51
+ """
52
+
53
+ @staticmethod
54
+ def shared(*args, **kwds) -> typing.Iterator[NoneType]:
55
+ """
56
+
57
+ Acquire the lock in shared mode.
58
+ This is used as follows
59
+
60
+ >>> lock: ShareableRLock
61
+ >>> with lock.shared():
62
+ >>> # code with lock acquired
63
+ >>> # the lock will automatically be released here
64
+
65
+ If the lock is acquired by a different thread in unique mode then this will block until it is finished.
66
+ If the lock is acquired in unique mode by this thread or by otherthreads in shared mode then this will acquire
67
+ the lock.
68
+
69
+ If another thread wants to acquire the lock in unique mode it will block until all threads have finished in
70
+ shared mode.
71
+
72
+ :param blocking: Should this block until the lock can be acquired. Default is True.
73
+ If false and the lock cannot be acquired on the first try, this returns False.
74
+ :param timeout: Maximum amount of time to block for. Has no effect is blocking is False. Default is forever.
75
+ :param task_manager: A custom object through which acquiring can be cancelled.
76
+ This effectively manually triggers timeout.
77
+ This is useful for GUIs so that the user can cancel an operation that may otherwise block for a while.
78
+ :return: None
79
+ :raises: LockNotAcquired if the lock could not be acquired.
80
+
81
+ """
82
+
83
+ @staticmethod
84
+ def unique(*args, **kwds) -> typing.Iterator[NoneType]:
85
+ """
86
+
87
+ Acquire the lock in unique mode.
88
+ This is used as follows
89
+
90
+ >>> lock: ShareableRLock
91
+ >>> with lock.unique():
92
+ >>> # code with lock acquired
93
+ >>> # the lock will automatically be released here
94
+
95
+ This will block while all other threads using the resource finish
96
+ and once acquired block all other threads until the lock is released.
97
+
98
+ :param blocking: Should this block until the lock can be acquired. Default is True.
99
+ If false and the lock cannot be acquired on the first try, this returns False.
100
+ :param timeout: Maximum amount of time to block for. Has no effect is blocking is False. Default is forever.
101
+ :param task_manager: A custom object through which acquiring can be cancelled.
102
+ This effectively manually triggers timeout.
103
+ This is useful for GUIs so that the user can cancel an operation that may otherwise block for a while.
104
+ :return: None
105
+ :raises: LockNotAcquired if the lock could not be acquired.
106
+
107
+ """
108
+
109
+ def __init__(self) -> None: ...
110
+ def _wait(
111
+ self,
112
+ exit_condition: typing.Callable[[], bool],
113
+ blocking: bool = True,
114
+ timeout: float = -1,
115
+ task_manager: amulet.utils.task_manager.AbstractCancelManager = ...,
116
+ ) -> bool:
117
+ """
118
+ Wait until a condition is False.
119
+
120
+ :param exit_condition: The condition to check.
121
+ :param blocking: Should this block until the lock can be acquired. Default is True.
122
+ If false and the lock cannot be acquired on the first try, this returns False.
123
+ :param timeout: Maximum amount of time to block for. Has no effect is blocking is False. Default is forever.
124
+ :param task_manager: A custom object through which acquiring can be cancelled.
125
+ This effectively manually triggers timeout.
126
+ This is useful for GUIs so that the user can cancel an operation that may otherwise block for a while.
127
+ :return: True if the lock was acquired, otherwise False.
128
+
129
+ """
130
+
131
+ def acquire_shared(
132
+ self,
133
+ blocking: bool = True,
134
+ timeout: float = -1,
135
+ task_manager: amulet.utils.task_manager.AbstractCancelManager = ...,
136
+ ) -> bool:
137
+ """
138
+
139
+ Only use this if you know what you are doing. Consider using :meth:`shared` instead
140
+ Acquire the lock in shared mode.
141
+ :param blocking: Should this block until the lock can be acquired. Default is True.
142
+ If false and the lock cannot be acquired on the first try, this returns False.
143
+ :param timeout: Maximum amount of time to block for. Has no effect is blocking is False. Default is forever.
144
+ :param task_manager: A custom object through which acquiring can be cancelled.
145
+ This effectively manually triggers timeout.
146
+ This is useful for GUIs so that the user can cancel an operation that may otherwise block for a while.
147
+ :return: True if the lock was acquired otherwise False.
148
+
149
+ """
150
+
151
+ def acquire_unique(
152
+ self,
153
+ blocking: bool = True,
154
+ timeout: float = -1,
155
+ task_manager: amulet.utils.task_manager.AbstractCancelManager = ...,
156
+ ) -> bool:
157
+ """
158
+
159
+ Only use this if you know what you are doing. Consider using :meth:`unique` instead
160
+ Acquire the lock in unique mode. This is equivalent to threading.RLock.acquire
161
+ With improper use this can lead to a deadlock.
162
+ :param blocking: Should this block until the lock can be acquired. Default is True.
163
+ If false and the lock cannot be acquired on the first try, this returns False.
164
+ :param timeout: Maximum amount of time to block for. Has no effect is blocking is False. Default is forever.
165
+ :param task_manager: A custom object through which acquiring can be cancelled.
166
+ This effectively manually triggers timeout.
167
+ This is useful for GUIs so that the user can cancel an operation that may otherwise block for a while.
168
+ :return: True if the lock was acquired otherwise False.
169
+
170
+ """
171
+
172
+ def release_shared(self) -> None:
173
+ """
174
+
175
+ Only use this if you know what you are doing. Consider using :meth:`shared` instead
176
+ Release the shared hold on the lock. This must be called by the same thread that acquired it.
177
+ This must be called exactly the same number of times as :meth:`acquire_shared` was called.
178
+
179
+ """
180
+
181
+ def release_unique(self) -> None:
182
+ """
183
+
184
+ Only use this if you know what you are doing. Consider using :meth:`unique` instead
185
+ Release the unique hold on the lock. This must be called by the same thread that acquired it.
186
+ This must be called exactly the same number of times as :meth:`acquire_unique` was called.
187
+
188
+ """
189
+
190
+ log: logging.Logger # value = <Logger amulet.utils.shareable_lock (INFO)>
@@ -0,0 +1,10 @@
1
+ from ._signal import (
2
+ Signal,
3
+ SignalInstance,
4
+ create_signal_instance,
5
+ SignalInstanceConstructor,
6
+ set_signal_instance_constructor,
7
+ get_fallback_signal_instance_constructor,
8
+ get_pyside6_signal_instance_constructor,
9
+ SignalInstanceCacheName,
10
+ )
@@ -0,0 +1,25 @@
1
+ from __future__ import annotations
2
+
3
+ from amulet.utils.signal._signal import (
4
+ Signal,
5
+ SignalInstance,
6
+ SignalInstanceConstructor,
7
+ create_signal_instance,
8
+ get_fallback_signal_instance_constructor,
9
+ get_pyside6_signal_instance_constructor,
10
+ set_signal_instance_constructor,
11
+ )
12
+
13
+ from . import _signal
14
+
15
+ __all__ = [
16
+ "Signal",
17
+ "SignalInstance",
18
+ "SignalInstanceCacheName",
19
+ "SignalInstanceConstructor",
20
+ "create_signal_instance",
21
+ "get_fallback_signal_instance_constructor",
22
+ "get_pyside6_signal_instance_constructor",
23
+ "set_signal_instance_constructor",
24
+ ]
25
+ SignalInstanceCacheName: str