pybare 1.2.3__tar.gz → 1.2.4__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 (33) hide show
  1. {pybare-1.2.3/pybare.egg-info → pybare-1.2.4}/PKG-INFO +30 -6
  2. {pybare-1.2.3 → pybare-1.2.4}/README.md +2 -0
  3. pybare-1.2.4/bare/_examples/customer.bin +0 -0
  4. pybare-1.2.4/bare/_examples/employee.bin +0 -0
  5. pybare-1.2.4/bare/_examples/people.bin +0 -0
  6. pybare-1.2.4/bare/_examples/terminated.bin +1 -0
  7. {pybare-1.2.3 → pybare-1.2.4}/bare/barearray.py +11 -2
  8. {pybare-1.2.3 → pybare-1.2.4}/bare/barestruct.py +6 -5
  9. {pybare-1.2.3 → pybare-1.2.4}/bare/baretype.py +3 -6
  10. {pybare-1.2.3 → pybare-1.2.4}/bare/map.py +4 -1
  11. {pybare-1.2.3 → pybare-1.2.4}/bare/misc.py +5 -2
  12. {pybare-1.2.3 → pybare-1.2.4}/bare/test_barearray.py +30 -24
  13. {pybare-1.2.3 → pybare-1.2.4}/bare/test_barestruct.py +4 -0
  14. {pybare-1.2.3 → pybare-1.2.4}/bare/test_data.py +7 -7
  15. {pybare-1.2.3 → pybare-1.2.4}/bare/test_map.py +21 -17
  16. {pybare-1.2.3 → pybare-1.2.4}/bare/test_misc.py +9 -4
  17. pybare-1.2.4/bare/test_number.py +49 -0
  18. {pybare-1.2.3 → pybare-1.2.4}/bare/test_union.py +65 -40
  19. {pybare-1.2.3 → pybare-1.2.4}/bare/util.py +3 -3
  20. pybare-1.2.4/pyproject.toml +36 -0
  21. pybare-1.2.3/PKG-INFO +0 -99
  22. pybare-1.2.3/bare/test_number.py +0 -43
  23. pybare-1.2.3/pybare.egg-info/SOURCES.txt +0 -25
  24. pybare-1.2.3/pybare.egg-info/dependency_links.txt +0 -1
  25. pybare-1.2.3/pybare.egg-info/top_level.txt +0 -1
  26. pybare-1.2.3/setup.cfg +0 -4
  27. pybare-1.2.3/setup.py +0 -24
  28. {pybare-1.2.3 → pybare-1.2.4}/LICENSE +0 -0
  29. {pybare-1.2.3 → pybare-1.2.4}/bare/__init__.py +0 -0
  30. {pybare-1.2.3 → pybare-1.2.4}/bare/data.py +0 -0
  31. {pybare-1.2.3 → pybare-1.2.4}/bare/number.py +0 -0
  32. {pybare-1.2.3 → pybare-1.2.4}/bare/test_encoder.py +0 -0
  33. {pybare-1.2.3 → pybare-1.2.4}/bare/union.py +0 -0
@@ -1,18 +1,40 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pybare
3
- Version: 1.2.3
4
- Summary: A declarative implementation of BARE for Python
5
- Home-page: https://sr.ht/~chiefnoah/pybare/
6
- Author: Noah Pederson
7
- Author-email: noah@packetlost.dev
3
+ Version: 1.2.4
4
+ Summary: A BARE Encoding Library and Data Validation Library for Python.
5
+ Author-Email: Noah Pederson <noah@packetlost.dev>
6
+ License: Copyright 2020 Noah Pederson
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
9
+ this software and associated documentation files (the "Software"), to deal in
10
+ the Software without restriction, including without limitation the rights to
11
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12
+ of the Software, and to permit persons to whom the Software is furnished to do
13
+ so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ SOFTWARE.
25
+ Classifier: Development Status :: 4 - Beta
26
+ Classifier: Intended Audience :: Developers
8
27
  Classifier: Programming Language :: Python :: 3.10
9
28
  Classifier: Programming Language :: Python :: 3.11
10
29
  Classifier: Programming Language :: Python :: 3.12
11
30
  Classifier: License :: OSI Approved :: MIT License
12
31
  Classifier: Operating System :: OS Independent
32
+ Project-URL: Homepage, https://sr.ht/~chiefnoah/pybare/
33
+ Project-URL: Repository, https://git.sr.ht/~chiefnoah/pybare
34
+ Project-URL: Issues, https://todo.sr.ht/~chiefnoah/pybare
35
+ Project-URL: Changelog, https://git.sr.ht/~chiefnoah/pybare/tree/master/item/CHANGELOG.md
13
36
  Requires-Python: >=3.10
14
37
  Description-Content-Type: text/markdown
15
- License-File: LICENSE
16
38
 
17
39
  # PyBARE
18
40
  [![builds.sr.ht status](https://builds.sr.ht/~chiefnoah/pybare.svg)](https://builds.sr.ht/~chiefnoah/pybare?)
@@ -40,6 +62,8 @@ pip install pybare
40
62
  pybare fully implements all BARE types for both encoding and decoding. This
41
63
  includes reading multiple messages from the same `BinaryIO` stream.
42
64
 
65
+ It is well tested and in use on production systems.
66
+
43
67
  ## Gotchas
44
68
 
45
69
  We use "Array" / "array" instead of "List" / "list" to avoid conflicts with Python's
@@ -24,6 +24,8 @@ pip install pybare
24
24
  pybare fully implements all BARE types for both encoding and decoding. This
25
25
  includes reading multiple messages from the same `BinaryIO` stream.
26
26
 
27
+ It is well tested and in use on production systems.
28
+
27
29
  ## Gotchas
28
30
 
29
31
  We use "Array" / "array" instead of "List" / "list" to avoid conflicts with Python's
Binary file
Binary file
Binary file
@@ -0,0 +1 @@
1
+ 
@@ -1,8 +1,17 @@
1
1
  from __future__ import annotations
2
2
  import io
3
3
  from collections import UserList
4
- from typing import (Any, BinaryIO, ClassVar, Generic, Iterable, Optional, Type,
5
- TypeVar, _ProtocolMeta)
4
+ from typing import (
5
+ Any,
6
+ BinaryIO,
7
+ ClassVar,
8
+ Generic,
9
+ Iterable,
10
+ Optional,
11
+ Type,
12
+ TypeVar,
13
+ _ProtocolMeta,
14
+ )
6
15
 
7
16
  from .baretype import BAREType
8
17
  from .number import UInt
@@ -1,15 +1,17 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, BinaryIO, _ProtocolMeta, Type, Dict, TypeVar
3
+ import io
4
+ from typing import Any, BinaryIO, Dict, Type, TypeVar, _ProtocolMeta
4
5
 
5
- from .util import Field
6
6
  from .baretype import BAREType
7
+ from .util import Field
7
8
 
8
9
  __all__ = ["Struct", "struct"]
9
10
 
10
11
 
11
12
  T = TypeVar("T")
12
13
 
14
+
13
15
  class StructMeta(_ProtocolMeta, type):
14
16
  def __new__(cls, clsname, bases, clsdict):
15
17
  fields = {}
@@ -79,8 +81,6 @@ class Struct(BAREType, metaclass=StructMeta):
79
81
  )
80
82
 
81
83
  def pack(self: Struct) -> bytes:
82
- import io
83
-
84
84
  buf = io.BytesIO()
85
85
  for name, ty in self._fields.items():
86
86
  val = getattr(self, name)
@@ -121,7 +121,8 @@ class Struct(BAREType, metaclass=StructMeta):
121
121
  return True
122
122
  return NotImplemented
123
123
 
124
- def struct(**kwargs: Dict[str, BAREType[T]]) -> Type[Struct]:
124
+
125
+ def struct(**kwargs: Dict[str, Type[BAREType]]) -> Type[Struct]:
125
126
  """
126
127
  A function that defines and returnes an anonymous BARE `Struct` subclass with the
127
128
  provided `kwargs` as fields. The name of each kwarg becomes the field name, with the
@@ -7,17 +7,14 @@ T = TypeVar("T", covariant=True)
7
7
 
8
8
  class BAREType(Protocol, Generic[T]):
9
9
  @abstractmethod
10
- def __init__(self, *arg, **kwargs):
11
- ...
10
+ def __init__(self, *arg, **kwargs): ...
12
11
 
13
12
  @abstractmethod
14
- def pack(self) -> bytes:
15
- ...
13
+ def pack(self) -> bytes: ...
16
14
 
17
15
  @classmethod
18
16
  @abstractmethod
19
- def unpack(cls, fp: BinaryIO) -> BAREType:
20
- ...
17
+ def unpack(cls, fp: BinaryIO) -> BAREType: ...
21
18
 
22
19
  @classmethod
23
20
  @abstractmethod
@@ -115,7 +115,10 @@ class Map(BAREType[dict[K, V]], metaclass=MapMeta):
115
115
  return other._values == self._values
116
116
  try:
117
117
  for other_key, other_value in other.values():
118
- if other_key not in self._values and self._key_type(other_key) not in self._values:
118
+ if (
119
+ other_key not in self._values
120
+ and self._key_type(other_key) not in self._values
121
+ ):
119
122
  return False
120
123
  if other_value != self._values[other_key]:
121
124
  return False
@@ -60,7 +60,7 @@ class Enum(IntEnum, metaclass=EnumMeta):
60
60
  return False
61
61
 
62
62
 
63
- class Void:
63
+ class Void(BAREType[None]):
64
64
  """
65
65
  A Void type. It is similar to the `None` type, but is used to represent
66
66
  a BARE void type.
@@ -68,11 +68,14 @@ class Void:
68
68
  If should *generally* be used directly, but is also used implicitly in `option`.
69
69
  """
70
70
 
71
+ def __init__(self):
72
+ ...
73
+
71
74
  def pack(self) -> bytes:
72
75
  return bytes()
73
76
 
74
77
  @classmethod
75
- def unpack(cls, _: BinaryIO) -> Void:
78
+ def unpack(cls, fp: BinaryIO) -> Void:
76
79
  return cls()
77
80
 
78
81
  def __eq__(self, other: Any) -> bool:
@@ -5,11 +5,11 @@ import bare
5
5
  import pytest
6
6
  import io
7
7
 
8
+
8
9
  def test_2d_array_unsized():
9
- class InnerArray(Array, inner=UInt):
10
- ...
11
- class My2DArray(Array, inner=InnerArray):
12
- ...
10
+ class InnerArray(Array, inner=UInt): ...
11
+
12
+ class My2DArray(Array, inner=InnerArray): ...
13
13
 
14
14
  input = [[1, 2], [3, 4]]
15
15
  x = My2DArray(input)
@@ -18,6 +18,7 @@ def test_2d_array_unsized():
18
18
  assert x2 == x
19
19
  assert x2 == input
20
20
 
21
+
21
22
  def test_anonymous_array_unsized():
22
23
  AnonymousArray = array(UInt)
23
24
  input = [1, 2, 3]
@@ -27,6 +28,7 @@ def test_anonymous_array_unsized():
27
28
  assert x2 == x
28
29
  assert x2 == input
29
30
 
31
+
30
32
  def test_anonymous_array_sized():
31
33
  AnonymousArray = array(UInt, 3)
32
34
  input = [1, 2, 3]
@@ -41,9 +43,9 @@ def test_anonymous_array_sized():
41
43
  with pytest.raises(ValueError):
42
44
  AnonymousArray([1, 2, 3, 4])
43
45
 
46
+
44
47
  def test_array_sized():
45
- class MyArry(Array, inner=UInt, size=3):
46
- ...
48
+ class MyArry(Array, inner=UInt, size=3): ...
47
49
 
48
50
  input = [1, 2, 3]
49
51
  x = MyArry(input)
@@ -56,24 +58,28 @@ def test_array_sized():
56
58
  with pytest.raises(ValueError):
57
59
  MyArry([1, 2, 3, 4])
58
60
 
59
- @pytest.mark.parametrize('inner,data', [
60
- (bare.I8, [1, -1]),
61
- (bare.U8, [1, 5]),
62
- (bare.I16, [-1, 10000]),
63
- (bare.U16, [1, 100]),
64
- (bare.I32, [1, 100]),
65
- (bare.U32,[1, 100]),
66
- (bare.I64,[1, 100]),
67
- (bare.U64,[1, 100]),
68
- (bare.F32, [1.0, 2.0]),
69
- (bare.F64, [1.1, 2.2]),
70
- (bare.UInt, [1, 2, 3]),
71
- (bare.Int, [-1, 2, -3]),
72
- (bare.Str, ["Hello", "world"]),
73
- (bare.Bool, [False, True]),
74
- (bare.map(bare.Str, bare.Str), [{"Hello": "world"}, {"abc": "123"}]),
75
- (bare.union(bare.Str, bare.UInt), [bare.Str("hello"), bare.UInt(123)]),
76
- ])
61
+
62
+ @pytest.mark.parametrize(
63
+ "inner,data",
64
+ [
65
+ (bare.I8, [1, -1]),
66
+ (bare.U8, [1, 5]),
67
+ (bare.I16, [-1, 10000]),
68
+ (bare.U16, [1, 100]),
69
+ (bare.I32, [1, 100]),
70
+ (bare.U32, [1, 100]),
71
+ (bare.I64, [1, 100]),
72
+ (bare.U64, [1, 100]),
73
+ (bare.F32, [1.0, 2.0]),
74
+ (bare.F64, [1.1, 2.2]),
75
+ (bare.UInt, [1, 2, 3]),
76
+ (bare.Int, [-1, 2, -3]),
77
+ (bare.Str, ["Hello", "world"]),
78
+ (bare.Bool, [False, True]),
79
+ (bare.map(bare.Str, bare.Str), [{"Hello": "world"}, {"abc": "123"}]),
80
+ (bare.union(bare.Str, bare.UInt), [bare.Str("hello"), bare.UInt(123)]),
81
+ ],
82
+ )
77
83
  def test_all_types(inner: Type[BAREType], data: list):
78
84
  anon_array = array(inner)
79
85
  x = anon_array(data)
@@ -1,16 +1,19 @@
1
1
  import io
2
2
  from bare import Struct, UInt, Str, Field, struct
3
3
 
4
+
4
5
  def test_struct_basic():
5
6
  class MyStruct(Struct):
6
7
  a = Field(UInt)
7
8
  b = Field(Str)
8
9
  c: int
10
+
9
11
  x = MyStruct(a=123, b="Hello")
10
12
  b = x.pack()
11
13
  x2 = MyStruct.unpack(io.BytesIO(b))
12
14
  assert x == x2
13
15
 
16
+
14
17
  def test_nested_struct():
15
18
  class InnerStruct(Struct):
16
19
  i = Field(UInt)
@@ -23,6 +26,7 @@ def test_nested_struct():
23
26
  x2 = MyStruct.unpack(io.BytesIO(b))
24
27
  assert x == x2
25
28
 
29
+
26
30
  def test_anonymous_struct():
27
31
  MyStruct = struct(name=Str, age=UInt)
28
32
  x = MyStruct(name="Noah", age=27)
@@ -3,27 +3,27 @@ import io
3
3
 
4
4
 
5
5
  def test_data_sized():
6
- class SizedData(Data, size=5):
7
- ...
6
+ class SizedData(Data, size=5): ...
8
7
 
9
- x = SizedData(b'12345')
8
+ x = SizedData(b"12345")
10
9
  b = x.pack()
11
10
  assert len(b) == 5
12
11
  x2 = SizedData.unpack(io.BytesIO(b))
13
12
  assert x == x2
14
13
 
14
+
15
15
  def test_data_unsized():
16
- class SizedData(Data):
17
- ...
16
+ class SizedData(Data): ...
18
17
 
19
- x = SizedData(b'12345')
18
+ x = SizedData(b"12345")
20
19
  b = x.pack()
21
20
  assert len(b) == 6
22
21
  x2 = SizedData.unpack(io.BytesIO(b))
23
22
  assert x == x2
24
23
 
24
+
25
25
  def test_data_raw():
26
- x = Data(b'12345')
26
+ x = Data(b"12345")
27
27
  b = x.pack()
28
28
  assert len(b) == 6
29
29
  x2 = Data.unpack(io.BytesIO(b))
@@ -5,8 +5,8 @@ import io
5
5
  import pytest
6
6
 
7
7
 
8
- class MyMap(Map, key_type=Str, value_type=Int):
9
- ...
8
+ class MyMap(Map, key_type=Str, value_type=Int): ...
9
+
10
10
 
11
11
  def test_basic_map():
12
12
  x = MyMap({"Hello": 123, "abc": 456})
@@ -16,6 +16,7 @@ def test_basic_map():
16
16
  assert x["Hello"] == 123
17
17
  assert x["abc"] == 456
18
18
 
19
+
19
20
  def test_anonymous_map():
20
21
  MyMap = map(Str, Int)
21
22
  x = MyMap({"Hello": 123, "abc": 456})
@@ -25,37 +26,41 @@ def test_anonymous_map():
25
26
  assert x["Hello"] == 123
26
27
  assert x["abc"] == 456
27
28
 
29
+
28
30
  def test_nested_map():
29
31
  InnerMap = map(Str, Str)
30
- class NestedMap(Map, key_type=Str, value_type=InnerMap):
31
- ...
32
+
33
+ class NestedMap(Map, key_type=Str, value_type=InnerMap): ...
34
+
32
35
  x = NestedMap({"outer": {"hello": "world"}})
33
36
  b = x.pack()
34
37
  x2 = NestedMap.unpack(io.BytesIO(b))
35
38
  assert x == x2
36
39
 
40
+
37
41
  class MyEnum(bare.Enum):
38
42
  A = 1
39
43
  B = 2
40
44
 
45
+
41
46
  @pytest.mark.parametrize(
42
- 'key_type,value_type,data',
47
+ "key_type,value_type,data",
43
48
  [
44
49
  (Str, Str, {"hello": "world"}),
45
50
  (bare.UInt, bare.Int, {123: -123}),
46
- (bare.U8, bare.U8, {1:2}),
47
- (bare.I8, bare.I8, {1:-2}),
48
- (bare.U16, bare.U16, {1:2}),
49
- (bare.I16, bare.I16, {1:-2}),
50
- (bare.U32, bare.U32, {1:2}),
51
- (bare.I32, bare.I32, {1:-2}),
52
- (bare.U64, bare.U64, {1:2}),
53
- (bare.I64, bare.I64, {1:-2}),
54
- (bare.UInt, bare.UInt, {1:2}),
55
- (bare.Int, bare.Int, {1:-2}),
51
+ (bare.U8, bare.U8, {1: 2}),
52
+ (bare.I8, bare.I8, {1: -2}),
53
+ (bare.U16, bare.U16, {1: 2}),
54
+ (bare.I16, bare.I16, {1: -2}),
55
+ (bare.U32, bare.U32, {1: 2}),
56
+ (bare.I32, bare.I32, {1: -2}),
57
+ (bare.U64, bare.U64, {1: 2}),
58
+ (bare.I64, bare.I64, {1: -2}),
59
+ (bare.UInt, bare.UInt, {1: 2}),
60
+ (bare.Int, bare.Int, {1: -2}),
56
61
  (bare.Bool, bare.Bool, {True: False}),
57
62
  (bare.Bool, bare.Bool, {True: False}),
58
- ]
63
+ ],
59
64
  )
60
65
  def test_all_types(key_type, value_type, data):
61
66
  anon_map = map(key_type, value_type)
@@ -63,4 +68,3 @@ def test_all_types(key_type, value_type, data):
63
68
  b = x.pack()
64
69
  x2 = anon_map.unpack(io.BytesIO(b))
65
70
  assert x == x2
66
-
@@ -3,10 +3,12 @@ from bare import Enum, UInt, Void, Str
3
3
  import io
4
4
  import pytest
5
5
 
6
+
6
7
  class MyEnum(Enum):
7
8
  A = 1
8
9
  B = 2
9
10
 
11
+
10
12
  def test_enum_basic():
11
13
  b = MyEnum.A.pack()
12
14
  a = MyEnum.unpack(io.BytesIO(b))
@@ -16,15 +18,17 @@ def test_enum_basic():
16
18
  b = UInt(3).pack()
17
19
  MyEnum.unpack(io.BytesIO(b))
18
20
 
19
- class MyVoid(Void):
20
- ...
21
+
22
+ class MyVoid(Void): ...
23
+
21
24
 
22
25
  def test_custom_void():
23
26
  x = MyVoid()
24
27
  b = x.pack()
25
28
  x2 = MyVoid.unpack(io.BytesIO(b))
26
29
  assert x == x2
27
- assert b == b''
30
+ assert b == b""
31
+
28
32
 
29
33
  def test_void():
30
34
  x = Void()
@@ -33,9 +37,10 @@ def test_void():
33
37
  assert x == x2
34
38
  assert len(b) == 0
35
39
 
40
+
36
41
  def test_str():
37
42
  x = Str("Hello, world")
38
43
  b = x.pack()
39
44
  x2 = Str.unpack(io.BytesIO(b))
40
45
  assert x == x2
41
- assert b == b'\x0cHello, world'
46
+ assert b == b"\x0cHello, world"
@@ -0,0 +1,49 @@
1
+ import io
2
+ import bare
3
+ import pytest
4
+
5
+
6
+ @pytest.mark.parametrize(
7
+ "type_, good_values, bad_values",
8
+ [
9
+ (bare.UInt, [0, 1, 2**64 - 1], [-1, 2**64, 2**64 + 1]),
10
+ (
11
+ bare.Int,
12
+ [-(2**63), -(2**63) + 1, 0, 2**63, 2**63 - 1],
13
+ [-(2**63) - 1, 2**63 + 1],
14
+ ),
15
+ (bare.U8, [0, 1, 2**8 - 1], [-1, 2**8]),
16
+ (bare.I8, [-(2**7), 0, 2**7 - 1], [-(2**7) - 1, 2**7]),
17
+ (bare.U16, [0, 1, 2**16 - 1], [-1, 2**16]),
18
+ (bare.I16, [-(2**15), 0, 2**15 - 1], [-(2**15) - 1, 2**15]),
19
+ (bare.U32, [0, 1, 2**32 - 1], [-1, 2**32]),
20
+ (bare.I32, [-(2**31), 0, 2**31 - 1], [-(2**31) - 1, 2**31]),
21
+ (bare.U64, [0, 1, 2**64 - 1], [-1, 2**64]),
22
+ (bare.I64, [-(2**63), 0, 2**63 - 1], [-(2**63) - 1, 2**63]),
23
+ ],
24
+ )
25
+ def test_bounds(type_, good_values, bad_values):
26
+ for value in good_values:
27
+ x = type_(value)
28
+ b = x.pack()
29
+ x2 = type_.unpack(io.BytesIO(b))
30
+ assert x == x2
31
+ for value in bad_values:
32
+ with pytest.raises(TypeError):
33
+ type_(value)
34
+
35
+
36
+ def test_f32():
37
+ x = bare.F32(123.5)
38
+ b = x.pack()
39
+ assert len(b) == 4
40
+ x2 = bare.F32.unpack(io.BytesIO(b))
41
+ assert x == x2
42
+
43
+
44
+ def test_f64():
45
+ x = bare.F64(123.5)
46
+ b = x.pack()
47
+ assert len(b) == 8
48
+ x2 = bare.F64.unpack(io.BytesIO(b))
49
+ assert x == x2
@@ -3,98 +3,123 @@ import bare
3
3
  import io
4
4
  import pytest
5
5
 
6
- class MyUnion(Union, variants=(Str, Int)):
7
- ...
6
+
7
+ class MyUnion(Union, variants=(Str, Int)): ...
8
+
8
9
 
9
10
  def test_union_basic():
10
11
  x = MyUnion(Str("Hello"))
11
12
  b = x.pack()
12
- assert b == b'\x00\x05Hello'
13
+ assert b == b"\x00\x05Hello"
13
14
  x2 = MyUnion.unpack(io.BytesIO(b))
14
15
  assert x == x2
15
16
  with pytest.raises(TypeError):
16
17
  x = MyUnion(True)
17
18
  with pytest.raises(TypeError):
18
- MyUnion.unpack(io.BytesIO(b'\x02\x05Hello'))
19
+ MyUnion.unpack(io.BytesIO(b"\x02\x05Hello"))
19
20
 
20
21
  x = MyUnion(Int(16))
21
22
  b = x.pack()
22
- assert b == b'\x01\x20'
23
+ assert b == b"\x01\x20"
23
24
  x2 = MyUnion.unpack(io.BytesIO(b))
24
25
  assert x == x2
25
26
 
27
+
26
28
  def test_anonymous_union():
27
29
  MyUnion = union(Str, Int)
28
30
  x = MyUnion(Str("Hello"))
29
31
  b = x.pack()
30
- assert b == b'\x00\x05Hello'
32
+ assert b == b"\x00\x05Hello"
31
33
  x2 = MyUnion.unpack(io.BytesIO(b))
32
34
  assert x == x2
33
35
  with pytest.raises(TypeError):
34
36
  x = MyUnion(True)
35
37
 
38
+
36
39
  def test_explicit_discriminant_implicit_following():
37
- class MyUnion(Union, variants=(UnionVariant(Str, 4), Int)):
38
- ...
40
+ class MyUnion(Union, variants=(UnionVariant(Str, 4), Int)): ...
41
+
39
42
  x = MyUnion(Str("Hello"))
40
43
  b = x.pack()
41
- assert b == b'\x04\x05Hello'
44
+ assert b == b"\x04\x05Hello"
42
45
  x2 = MyUnion.unpack(io.BytesIO(b))
43
46
  assert x == x2
44
47
  with pytest.raises(TypeError):
45
48
  x = MyUnion(True)
46
49
  with pytest.raises(TypeError):
47
- MyUnion.unpack(io.BytesIO(b'\x02\x05Hello'))
50
+ MyUnion.unpack(io.BytesIO(b"\x02\x05Hello"))
48
51
 
49
52
  x = MyUnion(Int(16))
50
53
  b = x.pack()
51
- assert b == b'\x05\x20'
54
+ assert b == b"\x05\x20"
52
55
  x2 = MyUnion.unpack(io.BytesIO(b))
53
56
  assert x == x2
54
57
 
58
+
55
59
  def test_explicit_discriminant_all_cases():
56
- class MyUnion(Union, variants=(UnionVariant(Str, 4), UnionVariant(Int, 10))):
57
- ...
60
+ class MyUnion(Union, variants=(UnionVariant(Str, 4), UnionVariant(Int, 10))): ...
61
+
58
62
  x = MyUnion(Str("Hello"))
59
63
  b = x.pack()
60
- assert b == b'\x04\x05Hello'
64
+ assert b == b"\x04\x05Hello"
61
65
  x2 = MyUnion.unpack(io.BytesIO(b))
62
66
  assert x == x2
63
67
  with pytest.raises(TypeError):
64
68
  x = MyUnion(True)
65
69
  with pytest.raises(TypeError):
66
- MyUnion.unpack(io.BytesIO(b'\x02\x05Hello'))
70
+ MyUnion.unpack(io.BytesIO(b"\x02\x05Hello"))
67
71
 
68
72
  x = MyUnion(Int(16))
69
73
  b = x.pack()
70
- assert b == b'\x0a\x20'
74
+ assert b == b"\x0a\x20"
71
75
  x2 = MyUnion.unpack(io.BytesIO(b))
72
76
  assert x == x2
73
77
 
74
- class AllPrimativeTypes(Union, variants=(Str, Int, bare.UInt, bare.Bool, bare.F32,
75
- bare.F64, bare.U8, bare.I8, bare.U16, bare.I16,
76
- bare.U32, bare.I32, bare.U64, bare.I64,
77
- bare.Data, bare.Void)):
78
- ...
79
-
80
- @pytest.mark.parametrize('value,discriminant', [
81
- (Str("Hello"), 0),
82
- (Int(123), 1),
83
- (bare.UInt(123), 2),
84
- (bare.Bool(True), 3),
85
- (bare.F32(123.5), 4),
86
- (bare.F64(123.5), 5),
87
- (bare.U8(123), 6),
88
- (bare.I8(123), 7),
89
- (bare.U16(123), 8),
90
- (bare.I16(123), 9),
91
- (bare.U32(123), 10),
92
- (bare.I32(123), 11),
93
- (bare.U64(123), 12),
94
- (bare.I64(123), 13),
95
- (bare.Data(b'123'), 14),
96
- (bare.Void(), 15),
97
- ])
78
+
79
+ class AllPrimativeTypes(
80
+ Union,
81
+ variants=(
82
+ Str,
83
+ Int,
84
+ bare.UInt,
85
+ bare.Bool,
86
+ bare.F32,
87
+ bare.F64,
88
+ bare.U8,
89
+ bare.I8,
90
+ bare.U16,
91
+ bare.I16,
92
+ bare.U32,
93
+ bare.I32,
94
+ bare.U64,
95
+ bare.I64,
96
+ bare.Data,
97
+ bare.Void,
98
+ ),
99
+ ): ...
100
+
101
+
102
+ @pytest.mark.parametrize(
103
+ "value,discriminant",
104
+ [
105
+ (Str("Hello"), 0),
106
+ (Int(123), 1),
107
+ (bare.UInt(123), 2),
108
+ (bare.Bool(True), 3),
109
+ (bare.F32(123.5), 4),
110
+ (bare.F64(123.5), 5),
111
+ (bare.U8(123), 6),
112
+ (bare.I8(123), 7),
113
+ (bare.U16(123), 8),
114
+ (bare.I16(123), 9),
115
+ (bare.U32(123), 10),
116
+ (bare.I32(123), 11),
117
+ (bare.U64(123), 12),
118
+ (bare.I64(123), 13),
119
+ (bare.Data(b"123"), 14),
120
+ (bare.Void(), 15),
121
+ ],
122
+ )
98
123
  def test_union_all_primative_types(value, discriminant):
99
124
  x = AllPrimativeTypes(value)
100
125
  b = x.pack()
@@ -5,7 +5,7 @@ from .baretype import BAREType
5
5
  T = TypeVar("T", bound=BAREType)
6
6
 
7
7
 
8
- class Field(Generic[T]):
8
+ class Field:
9
9
  """
10
10
  A descriptor that assists with assigning/retrieving values from a BARE Struct.
11
11
  It is reponsible for performing type validation on assignment of struct fields.
@@ -21,9 +21,9 @@ class Field(Generic[T]):
21
21
 
22
22
  attr: str
23
23
  name: str
24
- ty: Type[BAREType[T]]
24
+ ty: Type[BAREType]
25
25
 
26
- def __init__(self, ty: Type[BAREType[T]], attr: str | None = None):
26
+ def __init__(self, ty: Type[BAREType], attr: str | None = None):
27
27
  # ignore the typing here because these will always be set when assigned to an
28
28
  # object
29
29
  self.attr = attr # type: ignore
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = [
3
+ "pdm-backend",
4
+ ]
5
+ build-backend = "pdm.backend"
6
+
7
+ [project]
8
+ name = "pybare"
9
+ version = "1.2.4"
10
+ description = "A BARE Encoding Library and Data Validation Library for Python."
11
+ dependencies = []
12
+ requires-python = ">= 3.10"
13
+ authors = [
14
+ { name = "Noah Pederson", email = "noah@packetlost.dev" },
15
+ ]
16
+ readme = "README.md"
17
+ classifiers = [
18
+ "Development Status :: 4 - Beta",
19
+ "Intended Audience :: Developers",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Operating System :: OS Independent",
25
+ ]
26
+
27
+ [project.license]
28
+ file = "LICENSE"
29
+
30
+ [project.urls]
31
+ Homepage = "https://sr.ht/~chiefnoah/pybare/"
32
+ Repository = "https://git.sr.ht/~chiefnoah/pybare"
33
+ Issues = "https://todo.sr.ht/~chiefnoah/pybare"
34
+ Changelog = "https://git.sr.ht/~chiefnoah/pybare/tree/master/item/CHANGELOG.md"
35
+
36
+ [tool]
pybare-1.2.3/PKG-INFO DELETED
@@ -1,99 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: pybare
3
- Version: 1.2.3
4
- Summary: A declarative implementation of BARE for Python
5
- Home-page: https://sr.ht/~chiefnoah/pybare/
6
- Author: Noah Pederson
7
- Author-email: noah@packetlost.dev
8
- Classifier: Programming Language :: Python :: 3.10
9
- Classifier: Programming Language :: Python :: 3.11
10
- Classifier: Programming Language :: Python :: 3.12
11
- Classifier: License :: OSI Approved :: MIT License
12
- Classifier: Operating System :: OS Independent
13
- Requires-Python: >=3.10
14
- Description-Content-Type: text/markdown
15
- License-File: LICENSE
16
-
17
- # PyBARE
18
- [![builds.sr.ht status](https://builds.sr.ht/~chiefnoah/pybare.svg)](https://builds.sr.ht/~chiefnoah/pybare?)
19
-
20
- A declarative implementation of the [BARE](https://baremessages.org/) message
21
- format for Python 3.10+
22
-
23
- ---
24
-
25
- pybare is a general purpose library for strongly typed primitives in Python that
26
- supports serializing to and from BARE messages.
27
-
28
- ```shell
29
- pip install pybare
30
- ```
31
-
32
- ## Goals
33
-
34
- * Provide a declarative structure for defining types
35
- * Validation on value updates
36
- * Support streaming messages
37
-
38
- ## Status
39
-
40
- pybare fully implements all BARE types for both encoding and decoding. This
41
- includes reading multiple messages from the same `BinaryIO` stream.
42
-
43
- ## Gotchas
44
-
45
- We use "Array" / "array" instead of "List" / "list" to avoid conflicts with Python's
46
- common builtin type of the same name.
47
-
48
- ## Examples
49
-
50
- An example that defines the types used as an example in the RFC may be found in
51
- [`example.py`](./example.py)
52
-
53
- pybare currently requires you define your structures by hand. Examples can be
54
- found in the
55
- [tests](https://git.sr.ht/~chiefnoah/pybare/tree/master/bare/test_encoder.py).
56
-
57
- ### Quickstart
58
-
59
- The general convention is type identifiers start with a *capital* letter and anonymous
60
- generating functions begin with a lowercase. This follows general "pythonic" style for
61
- classes vs functions.
62
-
63
- ```python
64
- from bare import Struct, map, Str, UInt, optional, data, array, Void, struct, U8
65
-
66
- # Alternatively, class Data(size=64): ...
67
- PubKey = data(64) # 512 bits
68
-
69
- class User(Struct):
70
- username = Field(Str)
71
- userid = Field(Int)
72
- email = Field(optional(Str))
73
- keys = Field(map(Str, PubKey))
74
- repos = Field(array(Str)) # variable length array
75
- # anonymous array and struct
76
- friends = Field(array(struct(name=Str, age=U8)))
77
-
78
-
79
- noah = User(username="chiefnoah", userid=1, email=Void(), keys={}, repos=[], friends=[])
80
- noah.username == 'chiefnoah'
81
- noah.username = 'someoneelse'
82
- noah.username == 'someoneelse'
83
- noah.userid == 1 # True
84
- noah.username = 1 # raise: bare.ValidationError
85
- noah.keys # {} (empty dict)
86
- noah.keys['my key'] = bytes(64) #\x00\x00...
87
- noah.keys['oops'] = bytes(1) # raise: bare.ValidationError
88
- noah.email == Void() # True
89
- noah.email = 12345 # raise: bare.ValidationError
90
- noah.pack() # \x00\x01 ... (binary data)
91
- ```
92
-
93
- Note, you **must** wrap the desired type in a `Field` to get its 'magic' behavior.
94
- Class or instance fields that are not wrapped in a `Field` will be ignored by the `pack`
95
- and `unpack` methods.
96
-
97
- ---
98
-
99
- To contribute, send patches to [~chiefnoah/inbox@lists.sr.ht](mailto:~chiefnoah/inbox@lists.sr.ht)
@@ -1,43 +0,0 @@
1
- import io
2
- import bare
3
- import pytest
4
-
5
-
6
- @pytest.mark.parametrize(
7
- "type_, good_values, bad_values",
8
- [
9
- (bare.UInt, [0, 1, 2**64-1], [-1, 2**64, 2**64+1]),
10
- (bare.Int, [-2**63, -(2**63)+1, 0, 2**63, 2**63-1], [-2**63-1, 2**63+1]),
11
- (bare.U8, [0, 1, 2**8-1], [-1, 2**8]),
12
- (bare.I8, [-2**7, 0, 2**7-1], [-2**7-1, 2**7]),
13
- (bare.U16, [0, 1, 2**16-1], [-1, 2**16]),
14
- (bare.I16, [-2**15, 0, 2**15-1], [-2**15-1, 2**15]),
15
- (bare.U32, [0, 1, 2**32-1], [-1, 2**32]),
16
- (bare.I32, [-2**31, 0, 2**31-1], [-2**31-1, 2**31]),
17
- (bare.U64, [0, 1, 2**64-1], [-1, 2**64]),
18
- (bare.I64, [-2**63, 0, 2**63-1], [-2**63-1, 2**63]),
19
- ]
20
- )
21
- def test_bounds(type_, good_values, bad_values):
22
- for value in good_values:
23
- x = type_(value)
24
- b = x.pack()
25
- x2 = type_.unpack(io.BytesIO(b))
26
- assert x == x2
27
- for value in bad_values:
28
- with pytest.raises(TypeError):
29
- type_(value)
30
-
31
- def test_f32():
32
- x = bare.F32(123.5)
33
- b = x.pack()
34
- assert len(b) == 4
35
- x2 = bare.F32.unpack(io.BytesIO(b))
36
- assert x == x2
37
-
38
- def test_f64():
39
- x = bare.F64(123.5)
40
- b = x.pack()
41
- assert len(b) == 8
42
- x2 = bare.F64.unpack(io.BytesIO(b))
43
- assert x == x2
@@ -1,25 +0,0 @@
1
- LICENSE
2
- README.md
3
- setup.py
4
- bare/__init__.py
5
- bare/barearray.py
6
- bare/barestruct.py
7
- bare/baretype.py
8
- bare/data.py
9
- bare/map.py
10
- bare/misc.py
11
- bare/number.py
12
- bare/test_barearray.py
13
- bare/test_barestruct.py
14
- bare/test_data.py
15
- bare/test_encoder.py
16
- bare/test_map.py
17
- bare/test_misc.py
18
- bare/test_number.py
19
- bare/test_union.py
20
- bare/union.py
21
- bare/util.py
22
- pybare.egg-info/PKG-INFO
23
- pybare.egg-info/SOURCES.txt
24
- pybare.egg-info/dependency_links.txt
25
- pybare.egg-info/top_level.txt
@@ -1 +0,0 @@
1
- bare
pybare-1.2.3/setup.cfg DELETED
@@ -1,4 +0,0 @@
1
- [egg_info]
2
- tag_build =
3
- tag_date = 0
4
-
pybare-1.2.3/setup.py DELETED
@@ -1,24 +0,0 @@
1
- import setuptools
2
-
3
- with open("README.md", "r") as fh:
4
- long_description = fh.read()
5
-
6
- setuptools.setup(
7
- name="pybare", # Replace with your own username
8
- version="1.2.3",
9
- author="Noah Pederson",
10
- author_email="noah@packetlost.dev",
11
- description="A declarative implementation of BARE for Python",
12
- long_description=long_description,
13
- long_description_content_type="text/markdown",
14
- url="https://sr.ht/~chiefnoah/pybare/",
15
- packages=setuptools.find_packages(),
16
- classifiers=[
17
- "Programming Language :: Python :: 3.10",
18
- "Programming Language :: Python :: 3.11",
19
- "Programming Language :: Python :: 3.12",
20
- "License :: OSI Approved :: MIT License",
21
- "Operating System :: OS Independent",
22
- ],
23
- python_requires=">=3.10",
24
- )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes