tsrkit-types 0.1.2__tar.gz → 0.1.3__tar.gz

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.
Files changed (47) hide show
  1. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/CHANGELOG.md +15 -0
  2. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/PKG-INFO +100 -20
  3. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/README.md +99 -19
  4. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/pyproject.toml +1 -1
  5. tsrkit_types-0.1.3/tests/test_bits.py +402 -0
  6. tsrkit_types-0.1.3/tests/test_bytearray.py +433 -0
  7. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tests/test_bytes.py +5 -0
  8. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tests/test_int.py +5 -0
  9. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tests/test_structs.py +20 -4
  10. tsrkit_types-0.1.3/tests/type_hints/test_struct_serde.py +22 -0
  11. tsrkit_types-0.1.3/tsrkit_types/__init__.py +95 -0
  12. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types/bits.py +39 -20
  13. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types/bool.py +4 -8
  14. tsrkit_types-0.1.3/tsrkit_types/bytearray.py +37 -0
  15. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types/bytes.py +22 -52
  16. tsrkit_types-0.1.3/tsrkit_types/bytes_common.py +68 -0
  17. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types/choice.py +4 -4
  18. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types/dictionary.py +1 -1
  19. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types/integers.py +17 -0
  20. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types/itf/codable.py +2 -1
  21. tsrkit_types-0.1.3/tsrkit_types/option.py +48 -0
  22. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types/sequences.py +3 -3
  23. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types/struct.py +16 -10
  24. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types.egg-info/PKG-INFO +100 -20
  25. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types.egg-info/SOURCES.txt +5 -0
  26. tsrkit_types-0.1.2/tsrkit_types/__init__.py +0 -76
  27. tsrkit_types-0.1.2/tsrkit_types/option.py +0 -30
  28. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/CONTRIBUTING.md +0 -0
  29. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/LICENSE +0 -0
  30. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/MANIFEST.in +0 -0
  31. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/pytest.ini +0 -0
  32. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/setup.cfg +0 -0
  33. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/setup.py +0 -0
  34. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tests/test_choices.py +0 -0
  35. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tests/test_containers.py +0 -0
  36. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tests/test_enums.py +0 -0
  37. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tests/test_integers.py +0 -0
  38. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tests/test_network.py +0 -0
  39. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tests/test_seq.py +0 -0
  40. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tests/test_strings.py +0 -0
  41. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tests/test_struct.py +0 -0
  42. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types/enum.py +0 -0
  43. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types/null.py +0 -0
  44. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types/string.py +0 -0
  45. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types.egg-info/dependency_links.txt +0 -0
  46. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types.egg-info/requires.txt +0 -0
  47. {tsrkit_types-0.1.2 → tsrkit_types-0.1.3}/tsrkit_types.egg-info/top_level.txt +0 -0
@@ -37,6 +37,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
37
37
  - Zero-dependency core library
38
38
  - Python 3.11+ support
39
39
 
40
+ ## [0.1.3] - 2025-01-03
41
+
42
+ ### Fixed
43
+ - **Option JSON handling**: Fixed `Option.from_json()` to properly handle `None` values by creating empty Options
44
+ - **Choice serialization**: Improved `Choice.encode_into()` to correctly identify choice variants using both key and type matching, fixing issues with duplicate keys (like in Option types)
45
+ - **Struct None handling**: Enhanced `struct.from_json()` to properly handle `None` values for Option and NullType fields without requiring explicit defaults
46
+
47
+ ### Added
48
+ - **Option JSON methods**: Added dedicated `to_json()` and `from_json()` methods to Option class for cleaner JSON serialization
49
+ - **Improved type hints**: Enhanced struct decorator to provide better IDE support and type hints for Codable interface methods
50
+
51
+ ### Changed
52
+ - **Choice from_json**: Simplified Choice.from_json() by moving Option-specific logic to Option class
53
+ - **Serialization robustness**: Made Choice encoding more reliable for complex type hierarchies
54
+
40
55
  ## [Unreleased]
41
56
 
42
57
  ### Planned
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tsrkit-types
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Performant Python Typings library for type-safe binary serialization, JSON encoding, and data validation with zero dependencies
5
5
  Author-email: chainscore-labs <hello@chainscore.finance>, prasad-kumkar <prasad@chainscore.finance>
6
6
  License-Expression: MIT
@@ -299,7 +299,9 @@ restored = StringToInt.from_json(json_data)
299
299
 
300
300
  ### Bytes Types
301
301
 
302
- #### Bytes (extension of Python in-built bytes)
302
+ The library provides two complementary byte array types: immutable `Bytes` (extending Python's built-in `bytes`) and mutable `ByteArray` (extending Python's `bytearray`). Both types share common functionality through a mixin architecture for bit conversion, JSON serialization, and binary encoding.
303
+
304
+ #### Bytes (Immutable - extension of Python bytes)
303
305
 
304
306
  ```python
305
307
  from tsrkit_types.bytes import Bytes
@@ -307,47 +309,115 @@ from tsrkit_types.bytes import Bytes
307
309
  # Creation
308
310
  data = Bytes(b"Hello, binary world!")
309
311
  data = Bytes([0x01, 0x02, 0x03, 0x04])
312
+ data = Bytes("48656c6c6f") # From hex string
310
313
 
311
- # Bytes <-> Bits Operations
312
- data.to_bits() # [True, False, True, ...]
313
- Bytes.from_bits([True, False, True, ...])
314
+ # Shared Operations (via BytesMixin)
315
+ bits = data.to_bits() # Convert to bit list [True, False, True, ...]
316
+ data2 = Bytes.from_bits(bits) # Create from bit list
314
317
 
315
- # Operations
318
+ # Properties
316
319
  length = len(data) # Byte length
317
320
  raw_bytes = bytes(data) # Convert to Python bytes
318
321
 
319
- # Encoding
322
+ # Encoding/Decoding
320
323
  encoded = data.encode() # [length][raw_bytes]
321
324
  decoded = Bytes.decode(encoded)
322
325
 
323
326
  # JSON serialization (hex encoded)
324
327
  json_str = data.to_json() # "48656c6c6f2c2062696e61727920776f726c6421"
325
328
  restored = Bytes.from_json(json_str)
329
+ restored2 = Bytes.from_json("0x48656c6c6f") # Supports 0x prefix
326
330
  ```
327
331
 
328
- #### Bit Arrays (Sequence of bool)
332
+ #### ByteArray (Mutable - extension of Python bytearray)
329
333
 
330
334
  ```python
331
- from tsrkit_types.bits import BitArray
335
+ from tsrkit_types.bytearray import ByteArray
332
336
 
333
337
  # Creation
334
- bits = BitArray([True, False, True, True, False])
335
- bits = BitArray.from_hex("1A3F") # From hex string
336
- bits = BitArray.from_int(42, 8) # From integer with bit width
338
+ data = ByteArray(b"Hello, binary world!")
339
+ data = ByteArray([0x01, 0x02, 0x03, 0x04])
340
+ data = ByteArray("48656c6c6f") # From hex string
341
+
342
+ # Mutable Operations
343
+ data.append(0xFF) # Add single byte
344
+ data.extend([0xAB, 0xCD]) # Add multiple bytes
345
+ data.insert(0, 0x00) # Insert byte at position
346
+ data.pop() # Remove and return last byte
347
+ data.remove(0xFF) # Remove first occurrence
348
+ data.clear() # Remove all bytes
349
+ data.reverse() # Reverse in-place
350
+
351
+ # Indexing and Slicing (mutable)
352
+ data[0] = 0x42 # Set byte at index
353
+ data[1:3] = [0x43, 0x44] # Set slice
354
+ del data[0] # Delete byte at index
355
+
356
+ # Shared Operations (via BytesMixin) - same as Bytes
357
+ bits = data.to_bits() # Convert to bit list
358
+ data2 = ByteArray.from_bits(bits) # Create from bit list
359
+
360
+ # Properties and Conversion
361
+ length = len(data) # Byte length
362
+ raw_bytes = bytes(data) # Convert to immutable bytes
363
+ immutable = Bytes(data) # Convert to immutable Bytes
364
+
365
+ # Encoding/Decoding (same interface as Bytes)
366
+ encoded = data.encode() # [length][raw_bytes]
367
+ decoded = ByteArray.decode(encoded)
368
+
369
+ # JSON serialization (same interface as Bytes)
370
+ json_str = data.to_json() # "48656c6c6f..."
371
+ restored = ByteArray.from_json(json_str)
372
+ ```
373
+
374
+ **Key Differences:**
375
+ - **Bytes**: Immutable, extends `bytes`, memory-efficient for read-only data
376
+ - **ByteArray**: Mutable, extends `bytearray`, suitable for dynamic byte manipulation
377
+ - **Shared Functionality**: Both support identical bit conversion, JSON serialization, and binary encoding through `BytesMixin`
378
+
379
+ **Common Features (Both Types):**
380
+ - Bit-level conversion with MSB/LSB support
381
+ - Hex string JSON serialization with 0x prefix support
382
+ - Efficient binary encoding with length prefix
383
+ - String representation and validation
384
+ - Memory-efficient operations
385
+
386
+ #### Bits (Bit Arrays - Sequence of bool)
387
+
388
+ ```python
389
+ from tsrkit_types.bits import Bits
390
+
391
+ # Creation
392
+ bits = Bits([True, False, True, True, False])
393
+ bits = Bits.from_hex("1A3F") # From hex string
394
+ bits = Bits.from_int(42, 8) # From integer with bit width
395
+
396
+ # Fixed-size parameterized bits
397
+ FixedBits = Bits[8] # Exactly 8 bits
398
+ fixed = FixedBits([True, False, True, True, False, False, True, False])
337
399
 
338
400
  # Operations
339
- bit_val = bits[0] # Get bit at index
340
- bits[1] = True # Set bit at index
341
- bits.append(False) # Add bit
342
- bits.extend([True, False]) # Add multiple bits
401
+ bit_val = bits[0] # Get bit at index
402
+ bits[1] = True # Set bit at index
403
+ bits.append(False) # Add bit
404
+ bits.extend([True, False]) # Add multiple bits
343
405
 
344
406
  # Conversion
345
- hex_str = bits.to_hex() # Convert to hex string
346
- int_val = bits.to_int() # Convert to integer
407
+ hex_str = bits.to_hex() # Convert to hex string
408
+ int_val = bits.to_int() # Convert to integer
409
+
410
+ # Bit order specification
411
+ bits_msb = Bits([True, False], bit_order="MSB") # Most significant bit first
412
+ bits_lsb = Bits([True, False], bit_order="LSB") # Least significant bit first
347
413
 
348
414
  # Encoding
349
- encoded = bits.encode() # [length][packed_bits]
350
- decoded = BitArray.decode(encoded)
415
+ encoded = bits.encode() # [length][packed_bits]
416
+ decoded = Bits.decode(encoded)
417
+
418
+ # JSON serialization
419
+ json_str = bits.to_json() # Hex string representation
420
+ restored = Bits.from_json(json_str)
351
421
  ```
352
422
 
353
423
  ### Enum (Extension of Python Enum, with Codable + JSON support)
@@ -558,6 +628,16 @@ buffer = bytearray(1024)
558
628
  offset = 0
559
629
  offset += value1.encode_into(buffer, offset)
560
630
  offset += value2.encode_into(buffer, offset)
631
+
632
+ # Choose appropriate byte type for your use case
633
+ # Use Bytes for immutable binary data (memory efficient, read-only)
634
+ config_data = Bytes(b"static configuration")
635
+
636
+ # Use ByteArray for dynamic binary buffers (mutable, growing data)
637
+ dynamic_buffer = ByteArray()
638
+ dynamic_buffer.extend([0x01, 0x02])
639
+ dynamic_buffer.append(0x03)
640
+ dynamic_buffer.insert(0, 0x00) # Result: [0x00, 0x01, 0x02, 0x03]
561
641
  ```
562
642
 
563
643
  ## Examples
@@ -258,7 +258,9 @@ restored = StringToInt.from_json(json_data)
258
258
 
259
259
  ### Bytes Types
260
260
 
261
- #### Bytes (extension of Python in-built bytes)
261
+ The library provides two complementary byte array types: immutable `Bytes` (extending Python's built-in `bytes`) and mutable `ByteArray` (extending Python's `bytearray`). Both types share common functionality through a mixin architecture for bit conversion, JSON serialization, and binary encoding.
262
+
263
+ #### Bytes (Immutable - extension of Python bytes)
262
264
 
263
265
  ```python
264
266
  from tsrkit_types.bytes import Bytes
@@ -266,47 +268,115 @@ from tsrkit_types.bytes import Bytes
266
268
  # Creation
267
269
  data = Bytes(b"Hello, binary world!")
268
270
  data = Bytes([0x01, 0x02, 0x03, 0x04])
271
+ data = Bytes("48656c6c6f") # From hex string
269
272
 
270
- # Bytes <-> Bits Operations
271
- data.to_bits() # [True, False, True, ...]
272
- Bytes.from_bits([True, False, True, ...])
273
+ # Shared Operations (via BytesMixin)
274
+ bits = data.to_bits() # Convert to bit list [True, False, True, ...]
275
+ data2 = Bytes.from_bits(bits) # Create from bit list
273
276
 
274
- # Operations
277
+ # Properties
275
278
  length = len(data) # Byte length
276
279
  raw_bytes = bytes(data) # Convert to Python bytes
277
280
 
278
- # Encoding
281
+ # Encoding/Decoding
279
282
  encoded = data.encode() # [length][raw_bytes]
280
283
  decoded = Bytes.decode(encoded)
281
284
 
282
285
  # JSON serialization (hex encoded)
283
286
  json_str = data.to_json() # "48656c6c6f2c2062696e61727920776f726c6421"
284
287
  restored = Bytes.from_json(json_str)
288
+ restored2 = Bytes.from_json("0x48656c6c6f") # Supports 0x prefix
285
289
  ```
286
290
 
287
- #### Bit Arrays (Sequence of bool)
291
+ #### ByteArray (Mutable - extension of Python bytearray)
288
292
 
289
293
  ```python
290
- from tsrkit_types.bits import BitArray
294
+ from tsrkit_types.bytearray import ByteArray
291
295
 
292
296
  # Creation
293
- bits = BitArray([True, False, True, True, False])
294
- bits = BitArray.from_hex("1A3F") # From hex string
295
- bits = BitArray.from_int(42, 8) # From integer with bit width
297
+ data = ByteArray(b"Hello, binary world!")
298
+ data = ByteArray([0x01, 0x02, 0x03, 0x04])
299
+ data = ByteArray("48656c6c6f") # From hex string
300
+
301
+ # Mutable Operations
302
+ data.append(0xFF) # Add single byte
303
+ data.extend([0xAB, 0xCD]) # Add multiple bytes
304
+ data.insert(0, 0x00) # Insert byte at position
305
+ data.pop() # Remove and return last byte
306
+ data.remove(0xFF) # Remove first occurrence
307
+ data.clear() # Remove all bytes
308
+ data.reverse() # Reverse in-place
309
+
310
+ # Indexing and Slicing (mutable)
311
+ data[0] = 0x42 # Set byte at index
312
+ data[1:3] = [0x43, 0x44] # Set slice
313
+ del data[0] # Delete byte at index
314
+
315
+ # Shared Operations (via BytesMixin) - same as Bytes
316
+ bits = data.to_bits() # Convert to bit list
317
+ data2 = ByteArray.from_bits(bits) # Create from bit list
318
+
319
+ # Properties and Conversion
320
+ length = len(data) # Byte length
321
+ raw_bytes = bytes(data) # Convert to immutable bytes
322
+ immutable = Bytes(data) # Convert to immutable Bytes
323
+
324
+ # Encoding/Decoding (same interface as Bytes)
325
+ encoded = data.encode() # [length][raw_bytes]
326
+ decoded = ByteArray.decode(encoded)
327
+
328
+ # JSON serialization (same interface as Bytes)
329
+ json_str = data.to_json() # "48656c6c6f..."
330
+ restored = ByteArray.from_json(json_str)
331
+ ```
332
+
333
+ **Key Differences:**
334
+ - **Bytes**: Immutable, extends `bytes`, memory-efficient for read-only data
335
+ - **ByteArray**: Mutable, extends `bytearray`, suitable for dynamic byte manipulation
336
+ - **Shared Functionality**: Both support identical bit conversion, JSON serialization, and binary encoding through `BytesMixin`
337
+
338
+ **Common Features (Both Types):**
339
+ - Bit-level conversion with MSB/LSB support
340
+ - Hex string JSON serialization with 0x prefix support
341
+ - Efficient binary encoding with length prefix
342
+ - String representation and validation
343
+ - Memory-efficient operations
344
+
345
+ #### Bits (Bit Arrays - Sequence of bool)
346
+
347
+ ```python
348
+ from tsrkit_types.bits import Bits
349
+
350
+ # Creation
351
+ bits = Bits([True, False, True, True, False])
352
+ bits = Bits.from_hex("1A3F") # From hex string
353
+ bits = Bits.from_int(42, 8) # From integer with bit width
354
+
355
+ # Fixed-size parameterized bits
356
+ FixedBits = Bits[8] # Exactly 8 bits
357
+ fixed = FixedBits([True, False, True, True, False, False, True, False])
296
358
 
297
359
  # Operations
298
- bit_val = bits[0] # Get bit at index
299
- bits[1] = True # Set bit at index
300
- bits.append(False) # Add bit
301
- bits.extend([True, False]) # Add multiple bits
360
+ bit_val = bits[0] # Get bit at index
361
+ bits[1] = True # Set bit at index
362
+ bits.append(False) # Add bit
363
+ bits.extend([True, False]) # Add multiple bits
302
364
 
303
365
  # Conversion
304
- hex_str = bits.to_hex() # Convert to hex string
305
- int_val = bits.to_int() # Convert to integer
366
+ hex_str = bits.to_hex() # Convert to hex string
367
+ int_val = bits.to_int() # Convert to integer
368
+
369
+ # Bit order specification
370
+ bits_msb = Bits([True, False], bit_order="MSB") # Most significant bit first
371
+ bits_lsb = Bits([True, False], bit_order="LSB") # Least significant bit first
306
372
 
307
373
  # Encoding
308
- encoded = bits.encode() # [length][packed_bits]
309
- decoded = BitArray.decode(encoded)
374
+ encoded = bits.encode() # [length][packed_bits]
375
+ decoded = Bits.decode(encoded)
376
+
377
+ # JSON serialization
378
+ json_str = bits.to_json() # Hex string representation
379
+ restored = Bits.from_json(json_str)
310
380
  ```
311
381
 
312
382
  ### Enum (Extension of Python Enum, with Codable + JSON support)
@@ -517,6 +587,16 @@ buffer = bytearray(1024)
517
587
  offset = 0
518
588
  offset += value1.encode_into(buffer, offset)
519
589
  offset += value2.encode_into(buffer, offset)
590
+
591
+ # Choose appropriate byte type for your use case
592
+ # Use Bytes for immutable binary data (memory efficient, read-only)
593
+ config_data = Bytes(b"static configuration")
594
+
595
+ # Use ByteArray for dynamic binary buffers (mutable, growing data)
596
+ dynamic_buffer = ByteArray()
597
+ dynamic_buffer.extend([0x01, 0x02])
598
+ dynamic_buffer.append(0x03)
599
+ dynamic_buffer.insert(0, 0x00) # Result: [0x00, 0x01, 0x02, 0x03]
520
600
  ```
521
601
 
522
602
  ## Examples
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tsrkit-types"
3
- version = "0.1.2"
3
+ version = "0.1.3"
4
4
  description = "Performant Python Typings library for type-safe binary serialization, JSON encoding, and data validation with zero dependencies"
5
5
  authors = [
6
6
  {name = "chainscore-labs", email = "hello@chainscore.finance"},