protobin 0.0.41__tar.gz → 0.0.43__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.
- {protobin-0.0.41 → protobin-0.0.43}/PKG-INFO +1 -1
- {protobin-0.0.41 → protobin-0.0.43}/protobin/fields.py +22 -13
- {protobin-0.0.41 → protobin-0.0.43}/protobin/singleton.py +0 -1
- {protobin-0.0.41 → protobin-0.0.43}/pyproject.toml +1 -1
- {protobin-0.0.41 → protobin-0.0.43}/tests/tests.py +42 -2
- {protobin-0.0.41 → protobin-0.0.43}/.gitignore +0 -0
- {protobin-0.0.41 → protobin-0.0.43}/LICENSE.txt +0 -0
- {protobin-0.0.41 → protobin-0.0.43}/README.md +0 -0
- {protobin-0.0.41 → protobin-0.0.43}/protobin/__init__.py +0 -0
- {protobin-0.0.41 → protobin-0.0.43}/protobin/errors.py +0 -0
- {protobin-0.0.41 → protobin-0.0.43}/protobin/interfaces.py +0 -0
- {protobin-0.0.41 → protobin-0.0.43}/protobin/protocol.py +0 -0
- {protobin-0.0.41 → protobin-0.0.43}/tests/codec8.json +0 -0
- {protobin-0.0.41 → protobin-0.0.43}/tests/demo.json +0 -0
- {protobin-0.0.41 → protobin-0.0.43}/tests/demo.yaml +0 -0
- {protobin-0.0.41 → protobin-0.0.43}/tests/teltonika.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: protobin
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.43
|
|
4
4
|
Summary: Python library for encode and decode data in protobin format
|
|
5
5
|
Project-URL: Homepage, https://github.com/drmelectronic/protobin-python
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/drmelectronic/protobin-python/issues
|
|
@@ -106,7 +106,7 @@ class ArrayField(FieldBase):
|
|
|
106
106
|
|
|
107
107
|
def to_binary(self, val):
|
|
108
108
|
if not isinstance(val, (list, tuple)):
|
|
109
|
-
raise ValueError(f'Error in field
|
|
109
|
+
raise ValueError(f'Error in field ArrayField<{self.key}>, a array is expected but "{val}" is received, {type(val)}')
|
|
110
110
|
binary = b''
|
|
111
111
|
length = len(val)
|
|
112
112
|
binary += length.to_bytes(1, 'big')
|
|
@@ -135,7 +135,7 @@ class BitsField(FieldBase):
|
|
|
135
135
|
self.bytes = math.ceil(self.length / 8)
|
|
136
136
|
|
|
137
137
|
def __repr__(self):
|
|
138
|
-
return f'
|
|
138
|
+
return f'BitsField<key: {self.key}, length: {self.length}, bytes: {self.bytes}>'
|
|
139
139
|
|
|
140
140
|
def decode(self, binary):
|
|
141
141
|
self.ensure_length(binary)
|
|
@@ -215,7 +215,14 @@ class CharField(FieldBase):
|
|
|
215
215
|
def to_binary(self, val):
|
|
216
216
|
if val is None:
|
|
217
217
|
return bytes([0])
|
|
218
|
-
|
|
218
|
+
encoded = val[:self.bytes].encode('utf')
|
|
219
|
+
if self.bytes == 1 and len(encoded) > 1:
|
|
220
|
+
raise ValueError(f'{self} of one byte is possible to encode a utf-8 character')
|
|
221
|
+
i = 0
|
|
222
|
+
while len(encoded) > self.bytes:
|
|
223
|
+
i += 1
|
|
224
|
+
encoded = val[:self.bytes - i].encode('utf')
|
|
225
|
+
return (encoded + b' ' * self.bytes)[:self.bytes]
|
|
219
226
|
|
|
220
227
|
def from_binary(self, binary):
|
|
221
228
|
val = int.from_bytes(binary[:self.bytes], 'big', signed=False)
|
|
@@ -270,7 +277,7 @@ class DateTimeField(FieldBase):
|
|
|
270
277
|
if val is None:
|
|
271
278
|
return bytes([0] * 6)
|
|
272
279
|
elif not isinstance(val, datetime.datetime):
|
|
273
|
-
raise ValueError(f'Error in field
|
|
280
|
+
raise ValueError(f'Error in field DateTimeField<{self.key}>, a datetime is expected but "{val}" is received')
|
|
274
281
|
elif isinstance(val, str):
|
|
275
282
|
val = datetime.datetime.strptime(val, '%Y-%m-%d %H:%M:%S').date()
|
|
276
283
|
return bytes([
|
|
@@ -326,7 +333,7 @@ class FlagsField(FieldBase):
|
|
|
326
333
|
for k in self.keys:
|
|
327
334
|
val = data.get(k)
|
|
328
335
|
if val is None:
|
|
329
|
-
raise ValueError(f'Error in field
|
|
336
|
+
raise ValueError(f'Error in field FlagsField<{self.key}>, a boolean is expected but "None" is received')
|
|
330
337
|
bits += '1' if data[k] else '0'
|
|
331
338
|
return int(bits, 2).to_bytes(self.bytes, 'big', signed=False)
|
|
332
339
|
|
|
@@ -335,9 +342,11 @@ class FloatField(FieldBase):
|
|
|
335
342
|
|
|
336
343
|
def __init__(self, k, js):
|
|
337
344
|
super().__init__(k, js)
|
|
338
|
-
self.decimals = js
|
|
345
|
+
self.decimals = js.get('decimals', None)
|
|
339
346
|
if self.bytes == None:
|
|
340
|
-
raise ValueError(f'FloatField
|
|
347
|
+
raise ValueError(f'FloatField<{self.key}> needs to have bytes declared')
|
|
348
|
+
if self.decimals == None:
|
|
349
|
+
raise ValueError(f'FloatField<{self.key}> needs to have decimals declared')
|
|
341
350
|
|
|
342
351
|
def __repr__(self):
|
|
343
352
|
return f'FloatField<key: {self.key}, bytes: {self.bytes}, decimals: {self.decimals}>'
|
|
@@ -361,7 +370,7 @@ class IdField(FieldBase):
|
|
|
361
370
|
max_value = 256 ** self.bytes - 1
|
|
362
371
|
val = min(val, max_value)
|
|
363
372
|
if val < 0:
|
|
364
|
-
raise ValueError('
|
|
373
|
+
raise ValueError('IdField<{self.key}> does not allow negative values')
|
|
365
374
|
return int(val).to_bytes(self.bytes, 'big', signed=False)
|
|
366
375
|
|
|
367
376
|
def from_binary(self, binary):
|
|
@@ -401,7 +410,7 @@ class StringField(FieldBase):
|
|
|
401
410
|
try:
|
|
402
411
|
return binary.decode('utf')
|
|
403
412
|
except UnicodeEncodeError:
|
|
404
|
-
raise DecodeError(f"Can't decode string: {binary}")
|
|
413
|
+
raise DecodeError(f"{self}: Can't decode string: {binary}")
|
|
405
414
|
|
|
406
415
|
def split(self, binary):
|
|
407
416
|
if self.bytes:
|
|
@@ -441,10 +450,10 @@ class TimeField(FieldBase):
|
|
|
441
450
|
else:
|
|
442
451
|
val = datetime.datetime.strptime(val, '%H:%M').time()
|
|
443
452
|
except:
|
|
444
|
-
raise ValueError(f'Error in field
|
|
453
|
+
raise ValueError(f'Error in field TimeField<{self.key}>, a datetime or time is expected but "{val}" is received')
|
|
445
454
|
|
|
446
455
|
elif not isinstance(val, datetime.datetime) and not isinstance(val, datetime.time):
|
|
447
|
-
raise ValueError(f'Error in field
|
|
456
|
+
raise ValueError(f'Error in field TimeField<{self.key}>, a datetime or time is expected but "{val}" is received')
|
|
448
457
|
|
|
449
458
|
return bytes([
|
|
450
459
|
self.to_nible(val.hour),
|
|
@@ -495,11 +504,11 @@ class UnsignedField(FieldBase):
|
|
|
495
504
|
|
|
496
505
|
def to_binary(self, val):
|
|
497
506
|
if val is None:
|
|
498
|
-
raise ValueError(f'Error in field
|
|
507
|
+
raise ValueError(f'Error in field UnsignedField<{self.key}>, None is not allowed')
|
|
499
508
|
max_value = 256 ** self.bytes - 1
|
|
500
509
|
val = min(val, max_value)
|
|
501
510
|
if val < 0:
|
|
502
|
-
raise ValueError(f'Error in field
|
|
511
|
+
raise ValueError(f'Error in field UnsignedField<{self.key}>, positive integers expected but "{val}" is received')
|
|
503
512
|
return int(val).to_bytes(self.bytes, 'big', signed=False)
|
|
504
513
|
|
|
505
514
|
def from_binary(self, binary):
|
|
@@ -112,7 +112,7 @@ class BasicTest(unittest.TestCase):
|
|
|
112
112
|
},
|
|
113
113
|
'float': {
|
|
114
114
|
"header": "f",
|
|
115
|
-
"fields": {'test': {'bytes': 4, '
|
|
115
|
+
"fields": {'test': {'bytes': 4, 'type': 'float', 'decimals': 6}}
|
|
116
116
|
},
|
|
117
117
|
'id': {
|
|
118
118
|
"header": "i",
|
|
@@ -202,6 +202,13 @@ class BasicTest(unittest.TestCase):
|
|
|
202
202
|
h, recv = self.protocol.decode(binary)
|
|
203
203
|
self.assertEqual(data, recv)
|
|
204
204
|
|
|
205
|
+
def test_char_utf(self):
|
|
206
|
+
data = {'test': 'ñ'}
|
|
207
|
+
binary = self.protocol.encode(data, 'char')
|
|
208
|
+
print('binary', binary)
|
|
209
|
+
h, recv = self.protocol.decode(binary)
|
|
210
|
+
self.assertEqual(data, recv)
|
|
211
|
+
|
|
205
212
|
def test_char2(self):
|
|
206
213
|
data = {'test': 'FA', 'prueba': 'DO'}
|
|
207
214
|
binary = self.protocol.encode(data, 'char2')
|
|
@@ -215,6 +222,30 @@ class BasicTest(unittest.TestCase):
|
|
|
215
222
|
self.assertEqual(data_corregida, recv)
|
|
216
223
|
print(recv)
|
|
217
224
|
|
|
225
|
+
def test_char2_utf(self):
|
|
226
|
+
data = {'test': 'FA', 'prueba': 'ÑA'}
|
|
227
|
+
binary = self.protocol.encode(data, 'char2')
|
|
228
|
+
h, recv = self.protocol.decode(binary)
|
|
229
|
+
data['prueba'] = 'Ñ'
|
|
230
|
+
self.assertEqual(data, recv)
|
|
231
|
+
data = {'test': '', 'prueba': 'SÍ'}
|
|
232
|
+
binary = self.protocol.encode(data, 'char2')
|
|
233
|
+
print(binary)
|
|
234
|
+
h, recv = self.protocol.decode(binary)
|
|
235
|
+
data['prueba'] ='S '
|
|
236
|
+
data['test'] =' '
|
|
237
|
+
self.assertEqual(data, recv)
|
|
238
|
+
print(recv)
|
|
239
|
+
data = {'test': 'ÉL', 'prueba': 'NO'}
|
|
240
|
+
binary = self.protocol.encode(data, 'char2')
|
|
241
|
+
print(binary)
|
|
242
|
+
h, recv = self.protocol.decode(binary)
|
|
243
|
+
data['test'] ='É'
|
|
244
|
+
self.assertEqual(data, recv)
|
|
245
|
+
print(recv)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
|
|
218
249
|
def test_date(self):
|
|
219
250
|
data = {'test': datetime.date(2024, 9, 13)}
|
|
220
251
|
binary = self.protocol.encode(data, 'date')
|
|
@@ -273,6 +304,10 @@ class BasicTest(unittest.TestCase):
|
|
|
273
304
|
def test_float(self):
|
|
274
305
|
data = {'test': -11.659812}
|
|
275
306
|
binary = self.protocol.encode(data, 'float')
|
|
307
|
+
h, recv = self.protocol.decode(binary)
|
|
308
|
+
self.assertEqual(data, recv)
|
|
309
|
+
data = {'test': 0}
|
|
310
|
+
binary = self.protocol.encode(data, 'float')
|
|
276
311
|
print(binary)
|
|
277
312
|
h, recv = self.protocol.decode(binary)
|
|
278
313
|
self.assertEqual(data, recv)
|
|
@@ -340,6 +375,11 @@ class BasicTest(unittest.TestCase):
|
|
|
340
375
|
binary = self.protocol.encode(data, 'string')
|
|
341
376
|
h, recv = self.protocol.decode(binary)
|
|
342
377
|
self.assertEqual(data, recv)
|
|
378
|
+
data = {'test': 'ñandú'}
|
|
379
|
+
binary = self.protocol.encode(data, 'string')
|
|
380
|
+
h, recv = self.protocol.decode(binary)
|
|
381
|
+
print('binary', binary)
|
|
382
|
+
self.assertEqual(data, recv)
|
|
343
383
|
|
|
344
384
|
def test_timestamp(self):
|
|
345
385
|
data = {'test': datetime.datetime(2024, 9, 13, 15, 23, 51, 265981)}
|
|
@@ -810,4 +850,4 @@ report:
|
|
|
810
850
|
rasp = b'$=\t\x00\x02\x08\xfbh\xd6\xb9\xffG\xef\xf2\x00F\x02\x07FINAL \x01s\x91\xb0\x90\x96+\x00\x05\x02\xfbg\xe4\xf2\xffH!d\x00F\x02\x07UNIVERITARIA \x01s\x91\xb0\x90\xb6+\x00\x06\x03\xfbhL\x0b\xffH,`\x00F\x02\x07CARCAMO \x01s\x91\xb0\x90\xc0+\x00\x07\x04\xfbhh\xf6\xffH/D\x00F\x02\x072 DE MAYO \x01s\x91\xb0\x90\xc8+\x00\x08\x05\xfbh\x88\x04\xffH\x1d<\x00F\x02\x07PLAZA SAN MARTI\x01s\x91\xb0\x90\xd0+\x00\r\x04\xfbh\x9e\n\xffH\x0f7\x00F\x02\x0fABANCAY \x01s\x91\xb0\x90\xf9+\x00\x0e\x05\xfbh\x8e\x12\xffH\x19\xca\x00F\x02\x0fPLAZA SAN MARTI\x01s\x91\xb0\x91\x01+\x00\x0f\x06\xfbhn\x1e\xffH.\x8d\x00F\x02\x0f2 DE MAYO \x01s\x91\xb0\x91\t+\x00\x11\t\xfbg\xb7t\xffH$\xcb\x00F\x02\x0fTERMINAL \x01s\x91\xb0\x91\x1a+P'
|
|
811
851
|
self.assertEqual(binary, rasp)
|
|
812
852
|
h, recv = client.decode(binary)
|
|
813
|
-
print(recv)
|
|
853
|
+
print(recv)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|