tigerbeetle 0.16.54__py3-none-any.whl → 0.16.56__py3-none-any.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 tigerbeetle might be problematic. Click here for more details.

tigerbeetle/__init__.py CHANGED
@@ -1,3 +1,39 @@
1
1
  from .bindings import * # noqa
2
2
  from .client import ClientAsync, ClientSync, id, amount_max, configure_logging # noqa
3
3
  from .lib import IntegerOverflowError, NativeError
4
+
5
+ # Explicitly declare public exports:
6
+ __all__ = [
7
+ # from .client:
8
+ "ClientAsync",
9
+ "ClientSync",
10
+ "id",
11
+ "amount_max",
12
+ "configure_logging",
13
+ # from .lib:
14
+ "IntegerOverflowError",
15
+ "NativeError",
16
+ # from .bindings - everything treated as public:
17
+ "Operation",
18
+ "PacketStatus",
19
+ "InitStatus",
20
+ "ClientStatus",
21
+ "LogLevel",
22
+ "RegisterLogCallbackStatus",
23
+ "AccountFlags",
24
+ "TransferFlags",
25
+ "AccountFilterFlags",
26
+ "QueryFilterFlags",
27
+ "CreateAccountResult",
28
+ "CreateTransferResult",
29
+ "Account",
30
+ "Transfer",
31
+ "CreateAccountsResult",
32
+ "CreateTransfersResult",
33
+ "AccountFilter",
34
+ "AccountBalance",
35
+ "QueryFilter",
36
+ "InitParameters",
37
+ "AsyncStateMachineMixin",
38
+ "StateMachineMixin",
39
+ ]
tigerbeetle/bindings.py CHANGED
@@ -6,10 +6,21 @@ from __future__ import annotations
6
6
 
7
7
  import ctypes
8
8
  import enum
9
+ import sys
10
+ from dataclasses import dataclass
9
11
  from collections.abc import Callable # noqa: TCH003
10
12
  from typing import Any
13
+ if sys.version_info >= (3, 11):
14
+ from typing import Self
15
+ else:
16
+ from typing_extensions import Self
11
17
 
12
- from .lib import c_uint128, dataclass, tbclient, validate_uint
18
+ from .lib import c_uint128, tbclient, validate_uint
19
+
20
+ # Use slots=True if the version of Python is new enough (3.10+) to support it.
21
+ if sys.version_info >= (3, 10):
22
+ # mypy: ignore assignment (3.10+) and unused-ignore (pre 3.10)
23
+ dataclass = dataclass(slots=True) # type: ignore[assignment, unused-ignore]
13
24
 
14
25
 
15
26
  class Operation(enum.IntEnum):
@@ -236,13 +247,13 @@ class Transfer:
236
247
  @dataclass
237
248
  class CreateAccountsResult:
238
249
  index: int = 0
239
- result: CreateAccountResult = 0
250
+ result: CreateAccountResult = CreateAccountResult.OK
240
251
 
241
252
 
242
253
  @dataclass
243
254
  class CreateTransfersResult:
244
255
  index: int = 0
245
- result: CreateTransferResult = 0
256
+ result: CreateTransferResult = CreateTransferResult.OK
246
257
 
247
258
 
248
259
  @dataclass
@@ -282,7 +293,7 @@ class QueryFilter:
282
293
 
283
294
  class CPacket(ctypes.Structure):
284
295
  @classmethod
285
- def from_param(cls, obj):
296
+ def from_param(cls, obj: Any) -> Self:
286
297
  validate_uint(bits=32, name="data_size", number=obj.data_size)
287
298
  validate_uint(bits=16, name="user_tag", number=obj.user_tag)
288
299
  validate_uint(bits=8, name="operation", number=obj.operation)
@@ -309,7 +320,7 @@ CPacket._fields_ = [ # noqa: SLF001
309
320
 
310
321
  class CClient(ctypes.Structure):
311
322
  @classmethod
312
- def from_param(cls, obj):
323
+ def from_param(cls, obj: Any) -> Self:
313
324
  return cls(
314
325
  opaque=obj.opaque,
315
326
  )
@@ -321,7 +332,7 @@ CClient._fields_ = [ # noqa: SLF001
321
332
 
322
333
  class CAccount(ctypes.Structure):
323
334
  @classmethod
324
- def from_param(cls, obj):
335
+ def from_param(cls, obj: Any) -> Self:
325
336
  validate_uint(bits=128, name="id", number=obj.id)
326
337
  validate_uint(bits=128, name="debits_pending", number=obj.debits_pending)
327
338
  validate_uint(bits=128, name="debits_posted", number=obj.debits_posted)
@@ -349,7 +360,7 @@ class CAccount(ctypes.Structure):
349
360
  )
350
361
 
351
362
 
352
- def to_python(self):
363
+ def to_python(self) -> Account:
353
364
  return Account(
354
365
  id=self.id.to_python(),
355
366
  debits_pending=self.debits_pending.to_python(),
@@ -384,7 +395,7 @@ CAccount._fields_ = [ # noqa: SLF001
384
395
 
385
396
  class CTransfer(ctypes.Structure):
386
397
  @classmethod
387
- def from_param(cls, obj):
398
+ def from_param(cls, obj: Any) -> Self:
388
399
  validate_uint(bits=128, name="id", number=obj.id)
389
400
  validate_uint(bits=128, name="debit_account_id", number=obj.debit_account_id)
390
401
  validate_uint(bits=128, name="credit_account_id", number=obj.credit_account_id)
@@ -414,7 +425,7 @@ class CTransfer(ctypes.Structure):
414
425
  )
415
426
 
416
427
 
417
- def to_python(self):
428
+ def to_python(self) -> Transfer:
418
429
  return Transfer(
419
430
  id=self.id.to_python(),
420
431
  debit_account_id=self.debit_account_id.to_python(),
@@ -450,7 +461,7 @@ CTransfer._fields_ = [ # noqa: SLF001
450
461
 
451
462
  class CCreateAccountsResult(ctypes.Structure):
452
463
  @classmethod
453
- def from_param(cls, obj):
464
+ def from_param(cls, obj: Any) -> Self:
454
465
  validate_uint(bits=32, name="index", number=obj.index)
455
466
  return cls(
456
467
  index=obj.index,
@@ -458,7 +469,7 @@ class CCreateAccountsResult(ctypes.Structure):
458
469
  )
459
470
 
460
471
 
461
- def to_python(self):
472
+ def to_python(self) -> CreateAccountsResult:
462
473
  return CreateAccountsResult(
463
474
  index=self.index,
464
475
  result=CreateAccountResult(self.result),
@@ -472,7 +483,7 @@ CCreateAccountsResult._fields_ = [ # noqa: SLF001
472
483
 
473
484
  class CCreateTransfersResult(ctypes.Structure):
474
485
  @classmethod
475
- def from_param(cls, obj):
486
+ def from_param(cls, obj: Any) -> Self:
476
487
  validate_uint(bits=32, name="index", number=obj.index)
477
488
  return cls(
478
489
  index=obj.index,
@@ -480,7 +491,7 @@ class CCreateTransfersResult(ctypes.Structure):
480
491
  )
481
492
 
482
493
 
483
- def to_python(self):
494
+ def to_python(self) -> CreateTransfersResult:
484
495
  return CreateTransfersResult(
485
496
  index=self.index,
486
497
  result=CreateTransferResult(self.result),
@@ -494,7 +505,7 @@ CCreateTransfersResult._fields_ = [ # noqa: SLF001
494
505
 
495
506
  class CAccountFilter(ctypes.Structure):
496
507
  @classmethod
497
- def from_param(cls, obj):
508
+ def from_param(cls, obj: Any) -> Self:
498
509
  validate_uint(bits=128, name="account_id", number=obj.account_id)
499
510
  validate_uint(bits=128, name="user_data_128", number=obj.user_data_128)
500
511
  validate_uint(bits=64, name="user_data_64", number=obj.user_data_64)
@@ -516,7 +527,7 @@ class CAccountFilter(ctypes.Structure):
516
527
  )
517
528
 
518
529
 
519
- def to_python(self):
530
+ def to_python(self) -> AccountFilter:
520
531
  return AccountFilter(
521
532
  account_id=self.account_id.to_python(),
522
533
  user_data_128=self.user_data_128.to_python(),
@@ -545,7 +556,7 @@ CAccountFilter._fields_ = [ # noqa: SLF001
545
556
 
546
557
  class CAccountBalance(ctypes.Structure):
547
558
  @classmethod
548
- def from_param(cls, obj):
559
+ def from_param(cls, obj: Any) -> Self:
549
560
  validate_uint(bits=128, name="debits_pending", number=obj.debits_pending)
550
561
  validate_uint(bits=128, name="debits_posted", number=obj.debits_posted)
551
562
  validate_uint(bits=128, name="credits_pending", number=obj.credits_pending)
@@ -560,7 +571,7 @@ class CAccountBalance(ctypes.Structure):
560
571
  )
561
572
 
562
573
 
563
- def to_python(self):
574
+ def to_python(self) -> AccountBalance:
564
575
  return AccountBalance(
565
576
  debits_pending=self.debits_pending.to_python(),
566
577
  debits_posted=self.debits_posted.to_python(),
@@ -581,7 +592,7 @@ CAccountBalance._fields_ = [ # noqa: SLF001
581
592
 
582
593
  class CQueryFilter(ctypes.Structure):
583
594
  @classmethod
584
- def from_param(cls, obj):
595
+ def from_param(cls, obj: Any) -> Self:
585
596
  validate_uint(bits=128, name="user_data_128", number=obj.user_data_128)
586
597
  validate_uint(bits=64, name="user_data_64", number=obj.user_data_64)
587
598
  validate_uint(bits=32, name="user_data_32", number=obj.user_data_32)
@@ -603,7 +614,7 @@ class CQueryFilter(ctypes.Structure):
603
614
  )
604
615
 
605
616
 
606
- def to_python(self):
617
+ def to_python(self) -> QueryFilter:
607
618
  return QueryFilter(
608
619
  user_data_128=self.user_data_128.to_python(),
609
620
  user_data_64=self.user_data_64,
@@ -678,13 +689,13 @@ tb_client_submit.argtypes = [ctypes.POINTER(CClient), ctypes.POINTER(CPacket)]
678
689
  tb_client_register_log_callback = tbclient.tb_client_register_log_callback
679
690
  tb_client_register_log_callback.restype = RegisterLogCallbackStatus
680
691
  # Need to pass in None to clear - ctypes will error if argtypes is set.
681
- #tb_client_register_log_callback.argtypes = [LogHandler, ctypes.c_bool]
692
+ # tb_client_register_log_callback.argtypes = [LogHandler, ctypes.c_bool]
682
693
 
683
694
 
684
695
  class AsyncStateMachineMixin:
685
696
  _submit: Callable[[Operation, Any, Any, Any], Any]
686
697
  async def create_accounts(self, accounts: list[Account]) -> list[CreateAccountsResult]:
687
- return await self._submit(
698
+ return await self._submit( # type: ignore[no-any-return]
688
699
  Operation.CREATE_ACCOUNTS,
689
700
  accounts,
690
701
  CAccount,
@@ -692,7 +703,7 @@ class AsyncStateMachineMixin:
692
703
  )
693
704
 
694
705
  async def create_transfers(self, transfers: list[Transfer]) -> list[CreateTransfersResult]:
695
- return await self._submit(
706
+ return await self._submit( # type: ignore[no-any-return]
696
707
  Operation.CREATE_TRANSFERS,
697
708
  transfers,
698
709
  CTransfer,
@@ -700,7 +711,7 @@ class AsyncStateMachineMixin:
700
711
  )
701
712
 
702
713
  async def lookup_accounts(self, accounts: list[int]) -> list[Account]:
703
- return await self._submit(
714
+ return await self._submit( # type: ignore[no-any-return]
704
715
  Operation.LOOKUP_ACCOUNTS,
705
716
  accounts,
706
717
  c_uint128,
@@ -708,7 +719,7 @@ class AsyncStateMachineMixin:
708
719
  )
709
720
 
710
721
  async def lookup_transfers(self, transfers: list[int]) -> list[Transfer]:
711
- return await self._submit(
722
+ return await self._submit( # type: ignore[no-any-return]
712
723
  Operation.LOOKUP_TRANSFERS,
713
724
  transfers,
714
725
  c_uint128,
@@ -716,7 +727,7 @@ class AsyncStateMachineMixin:
716
727
  )
717
728
 
718
729
  async def get_account_transfers(self, filter: AccountFilter) -> list[Transfer]:
719
- return await self._submit(
730
+ return await self._submit( # type: ignore[no-any-return]
720
731
  Operation.GET_ACCOUNT_TRANSFERS,
721
732
  [filter],
722
733
  CAccountFilter,
@@ -724,7 +735,7 @@ class AsyncStateMachineMixin:
724
735
  )
725
736
 
726
737
  async def get_account_balances(self, filter: AccountFilter) -> list[AccountBalance]:
727
- return await self._submit(
738
+ return await self._submit( # type: ignore[no-any-return]
728
739
  Operation.GET_ACCOUNT_BALANCES,
729
740
  [filter],
730
741
  CAccountFilter,
@@ -732,7 +743,7 @@ class AsyncStateMachineMixin:
732
743
  )
733
744
 
734
745
  async def query_accounts(self, query_filter: QueryFilter) -> list[Account]:
735
- return await self._submit(
746
+ return await self._submit( # type: ignore[no-any-return]
736
747
  Operation.QUERY_ACCOUNTS,
737
748
  [query_filter],
738
749
  CQueryFilter,
@@ -740,7 +751,7 @@ class AsyncStateMachineMixin:
740
751
  )
741
752
 
742
753
  async def query_transfers(self, query_filter: QueryFilter) -> list[Transfer]:
743
- return await self._submit(
754
+ return await self._submit( # type: ignore[no-any-return]
744
755
  Operation.QUERY_TRANSFERS,
745
756
  [query_filter],
746
757
  CQueryFilter,
@@ -752,7 +763,7 @@ class AsyncStateMachineMixin:
752
763
  class StateMachineMixin:
753
764
  _submit: Callable[[Operation, Any, Any, Any], Any]
754
765
  def create_accounts(self, accounts: list[Account]) -> list[CreateAccountsResult]:
755
- return self._submit(
766
+ return self._submit( # type: ignore[no-any-return]
756
767
  Operation.CREATE_ACCOUNTS,
757
768
  accounts,
758
769
  CAccount,
@@ -760,7 +771,7 @@ class StateMachineMixin:
760
771
  )
761
772
 
762
773
  def create_transfers(self, transfers: list[Transfer]) -> list[CreateTransfersResult]:
763
- return self._submit(
774
+ return self._submit( # type: ignore[no-any-return]
764
775
  Operation.CREATE_TRANSFERS,
765
776
  transfers,
766
777
  CTransfer,
@@ -768,7 +779,7 @@ class StateMachineMixin:
768
779
  )
769
780
 
770
781
  def lookup_accounts(self, accounts: list[int]) -> list[Account]:
771
- return self._submit(
782
+ return self._submit( # type: ignore[no-any-return]
772
783
  Operation.LOOKUP_ACCOUNTS,
773
784
  accounts,
774
785
  c_uint128,
@@ -776,7 +787,7 @@ class StateMachineMixin:
776
787
  )
777
788
 
778
789
  def lookup_transfers(self, transfers: list[int]) -> list[Transfer]:
779
- return self._submit(
790
+ return self._submit( # type: ignore[no-any-return]
780
791
  Operation.LOOKUP_TRANSFERS,
781
792
  transfers,
782
793
  c_uint128,
@@ -784,7 +795,7 @@ class StateMachineMixin:
784
795
  )
785
796
 
786
797
  def get_account_transfers(self, filter: AccountFilter) -> list[Transfer]:
787
- return self._submit(
798
+ return self._submit( # type: ignore[no-any-return]
788
799
  Operation.GET_ACCOUNT_TRANSFERS,
789
800
  [filter],
790
801
  CAccountFilter,
@@ -792,7 +803,7 @@ class StateMachineMixin:
792
803
  )
793
804
 
794
805
  def get_account_balances(self, filter: AccountFilter) -> list[AccountBalance]:
795
- return self._submit(
806
+ return self._submit( # type: ignore[no-any-return]
796
807
  Operation.GET_ACCOUNT_BALANCES,
797
808
  [filter],
798
809
  CAccountFilter,
@@ -800,7 +811,7 @@ class StateMachineMixin:
800
811
  )
801
812
 
802
813
  def query_accounts(self, query_filter: QueryFilter) -> list[Account]:
803
- return self._submit(
814
+ return self._submit( # type: ignore[no-any-return]
804
815
  Operation.QUERY_ACCOUNTS,
805
816
  [query_filter],
806
817
  CQueryFilter,
@@ -808,7 +819,7 @@ class StateMachineMixin:
808
819
  )
809
820
 
810
821
  def query_transfers(self, query_filter: QueryFilter) -> list[Transfer]:
811
- return self._submit(
822
+ return self._submit( # type: ignore[no-any-return]
812
823
  Operation.QUERY_TRANSFERS,
813
824
  [query_filter],
814
825
  CQueryFilter,
tigerbeetle/client.py CHANGED
@@ -4,11 +4,16 @@ import asyncio
4
4
  import ctypes
5
5
  import logging
6
6
  import os
7
+ import sys
7
8
  import threading
8
9
  import time
9
10
  from collections.abc import Callable # noqa: TCH003
10
11
  from dataclasses import dataclass
11
12
  from typing import Any
13
+ if sys.version_info >= (3, 11):
14
+ from typing import Self
15
+ else:
16
+ from typing_extensions import Self
12
17
 
13
18
  from . import bindings
14
19
  from .lib import tb_assert, c_uint128
@@ -17,11 +22,11 @@ logger = logging.getLogger("tigerbeetle")
17
22
 
18
23
 
19
24
  class AtomicInteger:
20
- def __init__(self, value=0):
25
+ def __init__(self, value: int = 0) -> None:
21
26
  self._value = value
22
27
  self._lock = threading.Lock()
23
28
 
24
- def increment(self):
29
+ def increment(self) -> int:
25
30
  with self._lock:
26
31
  self._value += 1
27
32
  return self._value
@@ -45,30 +50,43 @@ class InflightPacket:
45
50
  operation: bindings.Operation
46
51
  c_event_type: Any
47
52
  c_result_type: Any
48
- on_completion: Callable | None
53
+ on_completion: Callable[[Self], None] | None
49
54
  on_completion_context: CompletionContextSync | CompletionContextAsync | None
50
55
 
56
+ class _IDGenerator:
57
+ """
58
+ Generator for Universally Unique and Sortable Identifiers as a 128-bit integers, based on ULIDs.
59
+
60
+ Keeps a monotonically increasing millisecond timestamp between calls to `.generate()`.
61
+ """
62
+ def __init__(self) -> None:
63
+ self._time_ms_last = time.time_ns() // (1000 * 1000)
64
+
65
+ def generate(self) -> int:
66
+ time_ms = time.time_ns() // (1000 * 1000)
67
+
68
+ # Ensure time_ms monotonically increases.
69
+ if time_ms <= self._time_ms_last:
70
+ time_ms = self._time_ms_last
71
+ else:
72
+ self._time_ms_last = time_ms
73
+
74
+ randomness = os.urandom(10)
75
+
76
+ return int.from_bytes(
77
+ time_ms.to_bytes(6, "big") + randomness,
78
+ "big",
79
+ )
80
+
81
+ # Module-level singleton instance.
82
+ _id_generator = _IDGenerator()
51
83
 
52
84
 
53
85
  def id() -> int:
54
86
  """
55
87
  Generates a Universally Unique and Sortable Identifier as a 128-bit integer. Based on ULIDs.
56
88
  """
57
- time_ms = time.time_ns() // (1000 * 1000)
58
-
59
- # Ensure time_ms monotonically increases.
60
- time_ms_last = getattr(id, "_time_ms_last", 0)
61
- if time_ms <= time_ms_last:
62
- time_ms = time_ms_last
63
- else:
64
- id._time_ms_last = time_ms
65
-
66
- randomness = os.urandom(10)
67
-
68
- return int.from_bytes(
69
- time_ms.to_bytes(6, "big") + randomness,
70
- "big",
71
- )
89
+ return _id_generator.generate()
72
90
 
73
91
 
74
92
  amount_max = (2 ** 128) - 1
@@ -137,15 +155,15 @@ class Client:
137
155
  c_event_type=c_event_type,
138
156
  c_result_type=c_result_type)
139
157
 
140
- def close(self):
158
+ def close(self) -> None:
141
159
  bindings.tb_client_deinit(ctypes.byref(self._client))
142
160
  tb_assert(self._client is not None)
143
161
  tb_assert(len(self._inflight_packets) == 0)
144
162
  del Client._clients[self._client_key]
145
163
 
146
164
  @staticmethod
147
- @bindings.OnCompletion
148
- def _c_on_completion(completion_ctx, packet, timestamp, bytes_ptr, len_):
165
+ @bindings.OnCompletion # type: ignore[misc]
166
+ def _c_on_completion(completion_ctx: int, packet: Any, timestamp: int, bytes_ptr: Any, len_: int) -> None:
149
167
  """
150
168
  Invoked in a separate thread
151
169
  """
@@ -156,7 +174,9 @@ class Client:
156
174
 
157
175
  if packet[0].status != bindings.PacketStatus.OK.value:
158
176
  inflight_packet.response = PacketError(repr(bindings.PacketStatus(packet[0].status)))
159
- tb_assert(inflight_packet.on_completion is not None)
177
+ if inflight_packet.on_completion is None:
178
+ # Can't use tb_assert here, as mypy complains later that it might be None.
179
+ raise TypeError("inflight_packet.on_completion not set")
160
180
  inflight_packet.on_completion(inflight_packet)
161
181
  return
162
182
 
@@ -174,22 +194,27 @@ class Client:
174
194
 
175
195
  inflight_packet.response = results
176
196
 
177
- tb_assert(inflight_packet.on_completion is not None)
197
+ if inflight_packet.on_completion is None:
198
+ # Can't use tb_assert here, as mypy complains later that it might be None.
199
+ raise TypeError("inflight_packet.on_completion not set")
200
+
178
201
  inflight_packet.on_completion(inflight_packet)
179
202
 
180
- def __enter__(self):
203
+ def __enter__(self) -> Self:
181
204
  return self
182
205
 
183
- def __exit__(self, exc_type, exc_val, exc_tb):
206
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
184
207
  self.close()
185
208
 
186
209
 
187
210
  class ClientSync(Client, bindings.StateMachineMixin):
188
- def _on_completion(self, inflight_packet):
211
+ def _on_completion(self, inflight_packet: InflightPacket) -> None:
212
+ if not isinstance(inflight_packet.on_completion_context, CompletionContextSync):
213
+ raise TypeError(repr(inflight_packet.on_completion_context))
189
214
  inflight_packet.on_completion_context.event.set()
190
215
 
191
216
  def _submit(self, operation: bindings.Operation, operations: list[Any],
192
- c_event_type: Any, c_result_type: Any):
217
+ c_event_type: Any, c_result_type: Any) -> Any:
193
218
  inflight_packet = self._acquire_packet(operation, operations, c_event_type, c_result_type)
194
219
  self._inflight_packets[inflight_packet.packet.user_data] = inflight_packet
195
220
 
@@ -212,22 +237,26 @@ class ClientSync(Client, bindings.StateMachineMixin):
212
237
 
213
238
 
214
239
  class ClientAsync(Client, bindings.AsyncStateMachineMixin):
215
- def _on_completion(self, inflight_packet):
240
+ def _on_completion(self, inflight_packet: InflightPacket) -> None:
216
241
  """
217
242
  Called by Client._c_on_completion, which itself is called from a different thread. Use
218
243
  `call_soon_threadsafe` to return to the thread of the event loop the request was invoked
219
244
  from, so _trigger_event() can trigger the async event and allow the client to progress.
220
245
  """
246
+ if not isinstance(inflight_packet.on_completion_context, CompletionContextAsync):
247
+ raise TypeError(repr(inflight_packet.on_completion_context))
221
248
  inflight_packet.on_completion_context.loop.call_soon_threadsafe(
222
249
  self._trigger_event,
223
250
  inflight_packet
224
251
  )
225
252
 
226
- def _trigger_event(self, inflight_packet):
253
+ def _trigger_event(self, inflight_packet:InflightPacket) -> None:
254
+ if not isinstance(inflight_packet.on_completion_context, CompletionContextAsync):
255
+ raise TypeError(repr(inflight_packet.on_completion_context))
227
256
  inflight_packet.on_completion_context.event.set()
228
257
 
229
258
  async def _submit(self, operation: bindings.Operation, operations: Any,
230
- c_event_type: Any, c_result_type: Any):
259
+ c_event_type: Any, c_result_type: Any) -> Any:
231
260
  inflight_packet = self._acquire_packet(operation, operations, c_event_type, c_result_type)
232
261
  self._inflight_packets[inflight_packet.packet.user_data] = inflight_packet
233
262
 
@@ -252,8 +281,8 @@ class ClientAsync(Client, bindings.AsyncStateMachineMixin):
252
281
  return inflight_packet.response
253
282
 
254
283
 
255
- @bindings.LogHandler
256
- def log_handler(level_zig, message_ptr, message_len):
284
+ @bindings.LogHandler # type: ignore[misc]
285
+ def log_handler(level_zig: bindings.LogLevel, message_ptr: Any, message_len: int) -> None:
257
286
  level_python = {
258
287
  bindings.LogLevel.ERR: logging.ERROR,
259
288
  bindings.LogLevel.WARN: logging.WARNING,
@@ -265,10 +294,15 @@ def log_handler(level_zig, message_ptr, message_len):
265
294
  tb_assert(bindings.tb_client_register_log_callback(log_handler, True) ==
266
295
  bindings.RegisterLogCallbackStatus.SUCCESS)
267
296
 
268
- def configure_logging(*, debug, log_handler=log_handler):
297
+
298
+ def configure_logging(
299
+ *,
300
+ debug: bool,
301
+ handler: Callable[[bindings.LogLevel, Any, int], None] = log_handler,
302
+ ) -> None:
269
303
  # First disable the existing log handler, before enabling the new one.
270
304
  tb_assert(bindings.tb_client_register_log_callback(None, debug) ==
271
305
  bindings.RegisterLogCallbackStatus.SUCCESS)
272
306
 
273
- tb_assert(bindings.tb_client_register_log_callback(log_handler, debug) ==
307
+ tb_assert(bindings.tb_client_register_log_callback(handler, debug) ==
274
308
  bindings.RegisterLogCallbackStatus.SUCCESS)
tigerbeetle/lib.py CHANGED
@@ -1,17 +1,23 @@
1
1
  import ctypes
2
- import dataclasses
3
2
  import platform
3
+ import sys
4
4
  from pathlib import Path
5
+ from typing import Any
6
+ if sys.version_info >= (3, 11):
7
+ from typing import Self
8
+ else:
9
+ from typing_extensions import Self
5
10
 
6
11
 
7
12
  class NativeError(Exception):
8
13
  pass
9
14
 
15
+
10
16
  class IntegerOverflowError(ValueError):
11
17
  pass
12
18
 
13
19
 
14
- def _load_tbclient():
20
+ def _load_tbclient() -> ctypes.CDLL:
15
21
  prefix = ""
16
22
  arch = ""
17
23
  system = ""
@@ -50,39 +56,35 @@ def _load_tbclient():
50
56
 
51
57
  source_path = Path(__file__)
52
58
  source_dir = source_path.parent
53
- library_path = source_dir / "lib" / f"{arch}-{system}{linux_libc}" / f"{prefix}tb_client{suffix}"
59
+ library_path = (
60
+ source_dir / "lib" / f"{arch}-{system}{linux_libc}" / f"{prefix}tb_client{suffix}"
61
+ )
54
62
  return ctypes.CDLL(str(library_path))
55
63
 
56
64
 
57
- def validate_uint(*, bits: int, name: str, number: int):
65
+ def validate_uint(*, bits: int, name: str, number: int) -> None:
58
66
  if number > 2**bits - 1:
59
67
  raise IntegerOverflowError(f"{name}=={number} is too large to fit in {bits} bits")
60
68
  if number < 0:
61
69
  raise IntegerOverflowError(f"{name}=={number} cannot be negative")
62
70
 
63
71
 
64
- class c_uint128(ctypes.Structure): # noqa: N801
65
- _fields_ = [("_low", ctypes.c_uint64), ("_high", ctypes.c_uint64)] # noqa: RUF012
72
+ class c_uint128(ctypes.Structure): # noqa: N801
73
+ _fields_ = [("_low", ctypes.c_uint64), ("_high", ctypes.c_uint64)] # noqa: RUF012
66
74
 
67
75
  @classmethod
68
- def from_param(cls, obj):
69
- return cls(_high=obj >> 64, _low=obj & 0xffffffffffffffff)
70
-
71
- def to_python(self):
72
- return self._high << 64 | self._low
76
+ def from_param(cls, obj: int) -> Self:
77
+ return cls(_high=obj >> 64, _low=obj & 0xFFFFFFFFFFFFFFFF)
73
78
 
79
+ def to_python(self) -> int:
80
+ return int(self._high << 64 | self._low)
74
81
 
75
- # Use slots=True if the version of Python is new enough (3.10+) to support it.
76
- try:
77
- dataclass = dataclasses.dataclass(slots=True)
78
- except TypeError:
79
- dataclass = dataclasses.dataclass()
80
-
81
- def tb_assert(value):
82
+ def tb_assert(value: Any) -> None:
82
83
  """
83
84
  Python's built-in assert can be silently disabled if Python is run with -O.
84
85
  """
85
86
  if not value:
86
87
  raise AssertionError()
87
88
 
89
+
88
90
  tbclient = _load_tbclient()
tigerbeetle/py.typed ADDED
File without changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tigerbeetle
3
- Version: 0.16.54
3
+ Version: 0.16.56
4
4
  Summary: The TigerBeetle client for Python.
5
5
  Project-URL: Homepage, https://github.com/tigerbeetle/tigerbeetle
6
6
  Project-URL: Issues, https://github.com/tigerbeetle/tigerbeetle/issues
@@ -67,7 +67,7 @@ features of TigerBeetle.
67
67
  * [Basic](/src/clients/python/samples/basic/): Create two accounts and transfer an amount between them.
68
68
  * [Two-Phase Transfer](/src/clients/python/samples/two-phase/): Create two accounts and start a pending transfer between
69
69
  them, then post the transfer.
70
- * [Many Two-Phase Transfers](/src/clients/python/samples/two-phase-many/): Create two accounts and start a number of pending transfer
70
+ * [Many Two-Phase Transfers](/src/clients/python/samples/two-phase-many/): Create two accounts and start a number of pending transfers
71
71
  between them, posting and voiding alternating transfers.
72
72
  ## Creating a Client
73
73
 
@@ -0,0 +1,15 @@
1
+ tigerbeetle/__init__.py,sha256=L9lyq47kzyZO0uXR455LXZTXWrt7yxfs-pFs8Mfv-r4,944
2
+ tigerbeetle/bindings.py,sha256=NSND7UuFpnd4TRBDA9aDJLRS115QNi3m0dVksekVlZg,28155
3
+ tigerbeetle/client.py,sha256=QaHWXeDvLYGia1IOUArR5rNShka9y3GwveFELCcoXwY,10967
4
+ tigerbeetle/lib.py,sha256=1Qln-Z4ZoCHJJ43sXlJJEs7-ZY5aZJjNNu7eISooAK8,2432
5
+ tigerbeetle/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ tigerbeetle/lib/aarch64-linux-gnu.2.27/libtb_client.so,sha256=qPbLSTvbDH49ePtGNuxciy9QYrd_LGSsRkMeEJNNa98,692104
7
+ tigerbeetle/lib/aarch64-linux-musl/libtb_client.so,sha256=BZ6a2nbclS4g0HU4495b9DipBefrLEMvZgUD0Jpi4Os,690384
8
+ tigerbeetle/lib/aarch64-macos/libtb_client.dylib,sha256=zEAJLzDJjIBhSG2tgWww39zq7Rl-Qsf5Q4lmD6UX2M8,700224
9
+ tigerbeetle/lib/x86_64-linux-gnu.2.27/libtb_client.so,sha256=EgoOoAELkFc-nHgHY-AlTViVO2Sx35EqF4RbFr5lMZY,815368
10
+ tigerbeetle/lib/x86_64-linux-musl/libtb_client.so,sha256=zoxZYw_eH0l2GriVIGr1c8_hdNk33TyVCKhbttYnKGM,813816
11
+ tigerbeetle/lib/x86_64-macos/libtb_client.dylib,sha256=KQaKRbtqzsIrzBcJxejIU0b8E9EaKzXgxz_MF7BpP98,792558
12
+ tigerbeetle/lib/x86_64-windows/tb_client.dll,sha256=dtB6y1LLLrI9swXI98MS8kKxjuMf0rHUXBauqXhkjMc,663552
13
+ tigerbeetle-0.16.56.dist-info/METADATA,sha256=70k1J6tzY0I04K4xqCKjDCAB8wYI3uict2-j79Ym3xg,23268
14
+ tigerbeetle-0.16.56.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
+ tigerbeetle-0.16.56.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- tigerbeetle/__init__.py,sha256=3cmov0HPkByJw1znLKoTqIuZUEeEQMEg1fflWY3ty9A,168
2
- tigerbeetle/bindings.py,sha256=syIRjAQQfoE15iGK6kxmJLToRdU2KWDY0nnu6u-t6xk,26978
3
- tigerbeetle/client.py,sha256=oGg1vAFqI8UZ5awI3sshZfxUdBsroUKwgp2rUa75lFc,9255
4
- tigerbeetle/lib.py,sha256=JKreDxdw_YejtH7F135_m6I6mNBSwjokaI6QicKm7cc,2425
5
- tigerbeetle/lib/aarch64-linux-gnu.2.27/libtb_client.so,sha256=xNAtANcQEmaIE-UyEvHtDUOHHUPbQIKCD9wZ0yWNZAw,692104
6
- tigerbeetle/lib/aarch64-linux-musl/libtb_client.so,sha256=5glgnm7FE-OO9XFhEtGncnErrUUfUw3l1MJ09RVN9-k,690384
7
- tigerbeetle/lib/aarch64-macos/libtb_client.dylib,sha256=ui8UzQVF-8pKKyTcJERpoA-K-HKSkoZbL05B4nhChnw,700224
8
- tigerbeetle/lib/x86_64-linux-gnu.2.27/libtb_client.so,sha256=Sei05ax48ZaZGwFrTxHZwTiV0y63izghAR928kSdwzE,815368
9
- tigerbeetle/lib/x86_64-linux-musl/libtb_client.so,sha256=WZcI2WFyJj32wjF1bWYNRBXdchSyYJKsKmvJccYgAcI,813816
10
- tigerbeetle/lib/x86_64-macos/libtb_client.dylib,sha256=AsRNVcxRfR8MNRk-vFol-ptwA3i6iz2scT4BAK7ykp0,792558
11
- tigerbeetle/lib/x86_64-windows/tb_client.dll,sha256=Wx0pyFh73tSyT_i3oEqX1qRe2OJyUpLYedBdT1m578M,663552
12
- tigerbeetle-0.16.54.dist-info/METADATA,sha256=U-ElpL8SddbwHPuNVMArgYyO2Tb5yF8k_zzg9egwFs8,23267
13
- tigerbeetle-0.16.54.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
14
- tigerbeetle-0.16.54.dist-info/RECORD,,