protobin 0.0.6__tar.gz → 0.0.7__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: protobin
3
- Version: 0.0.6
3
+ Version: 0.0.7
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
@@ -27,9 +27,9 @@ class FieldBase:
27
27
  key: Union[str, List[str]]
28
28
  type: FieldEnum
29
29
 
30
- def __init__(self, js):
30
+ def __init__(self, k, js):
31
+ self.key = k
31
32
  self.type = js['type']
32
- self.key = js.get('key')
33
33
  self.bytes = js.get('bytes')
34
34
 
35
35
  def decode(self, binary):
@@ -88,8 +88,8 @@ class FieldBase:
88
88
  class FieldArray(FieldBase):
89
89
  length: int
90
90
 
91
- def __init__(self, js):
92
- super().__init__(js)
91
+ def __init__(self, k, js):
92
+ super().__init__(k, js)
93
93
  self.array = js['array']
94
94
 
95
95
  def decode(self, binary):
@@ -108,7 +108,7 @@ class FieldArray(FieldBase):
108
108
  length = len(val)
109
109
  binary += length.to_bytes(1, 'big')
110
110
  for i in range(length):
111
- fields = [FIELD_MAP[f['type']](f) for f in self.array]
111
+ fields = [FIELD_MAP[f['type']](k, f) for k, f in self.array.items()]
112
112
  for f in fields:
113
113
  binary += f.encode(val[i])
114
114
  return binary
@@ -117,7 +117,7 @@ class FieldArray(FieldBase):
117
117
  lista = []
118
118
  for i in range(self.length):
119
119
  data = {}
120
- fields = [FIELD_MAP[f['type']](f) for f in self.array]
120
+ fields = [FIELD_MAP[f['type']](k, f) for k, f in self.array.items()]
121
121
  for f in fields:
122
122
  val, binary = f.decode(binary)
123
123
  data[f.key] = val
@@ -128,8 +128,8 @@ class FieldArray(FieldBase):
128
128
  class FieldBits(FieldBase):
129
129
  length: int
130
130
 
131
- def __init__(self, js):
132
- super().__init__(js)
131
+ def __init__(self, k, js):
132
+ super().__init__(k, js)
133
133
  self.length = js.get('length', 0)
134
134
  self.bytes = math.ceil(self.length / 8)
135
135
 
@@ -177,10 +177,21 @@ class FieldBool(FieldBase):
177
177
  bytes = 1
178
178
 
179
179
  def to_binary(self, val):
180
- return bool(val).to_bytes(1, 'big', signed=False)
180
+ if val is None:
181
+ val = 2
182
+ else:
183
+ val = bool(val)
184
+
185
+ return val.to_bytes(1, 'big', signed=False)
181
186
 
182
187
  def from_binary(self, binary):
183
- return bool(int.from_bytes(binary, 'big', signed=False))
188
+ val = int.from_bytes(binary, 'big', signed=False)
189
+ if val == 0:
190
+ return False
191
+ elif val == 1:
192
+ return True
193
+ else:
194
+ return None
184
195
 
185
196
 
186
197
  class FieldChar(FieldBase):
@@ -197,8 +208,8 @@ class FieldChar(FieldBase):
197
208
 
198
209
  class FieldDate(FieldBase):
199
210
 
200
- def __init__(self, js):
201
- super().__init__(js)
211
+ def __init__(self, k, js):
212
+ super().__init__(k, js)
202
213
  self.bytes = 3
203
214
 
204
215
  def to_binary(self, val: datetime.datetime | str):
@@ -219,12 +230,16 @@ class FieldDate(FieldBase):
219
230
 
220
231
  class FieldDateTime(FieldBase):
221
232
 
222
- def __init__(self, js):
223
- super().__init__(js)
233
+ def __init__(self, k, js):
234
+ super().__init__(k, js)
224
235
  self.bytes = 6
225
236
 
226
237
  def to_binary(self, val: datetime.datetime | str):
227
- if isinstance(val, str):
238
+ if val is None:
239
+ val = datetime.datetime(2000, 1, 1)
240
+ elif not isinstance(val, datetime.datetime):
241
+ raise ValueError(f'Error en el campo "{self.key}" se espera un datetime pero se recibe {val}')
242
+ elif isinstance(val, str):
228
243
  val = datetime.datetime.strptime(val, '%Y-%m-%d %H:%M:%S').date()
229
244
  return bytes([
230
245
  self.to_nible(val.day),
@@ -246,12 +261,11 @@ class FieldDateTime(FieldBase):
246
261
 
247
262
 
248
263
  class FieldFlags(FieldBase):
249
- keys: List[str]
250
264
 
251
- def __init__(self, js):
252
- super().__init__(js)
253
- self.keys = js.get('keys')
254
- self.length = len(self.keys)
265
+ def __init__(self, k, js):
266
+ super().__init__(k, js)
267
+ self.key = self.key.split(',')
268
+ self.length = len(self.key)
255
269
  self.bytes = math.ceil(self.length / 8)
256
270
 
257
271
  def encode(self, data):
@@ -264,23 +278,23 @@ class FieldFlags(FieldBase):
264
278
  for b in bits:
265
279
  flags.append(b == '1')
266
280
  val = {}
267
- order = -len(self.keys)
268
- for k in self.keys:
281
+ order = -len(self.key)
282
+ for k in self.key:
269
283
  val[k] = flags[order]
270
284
  order += 1
271
285
  return val
272
286
 
273
287
  def to_binary(self, data):
274
- bits = '0' * (8 - (len(self.keys) % 8))
275
- for k in self.keys:
288
+ bits = '0' * (8 - (len(self.key) % 8))
289
+ for k in self.key:
276
290
  bits += '1' if data[k] else '0'
277
291
  return int(bits, 2).to_bytes(self.bytes, 'big', signed=False)
278
292
 
279
293
 
280
294
  class FieldFloat(FieldBase):
281
295
 
282
- def __init__(self, js):
283
- super().__init__(js)
296
+ def __init__(self, k, js):
297
+ super().__init__(k, js)
284
298
  self.decimals = js['decimals']
285
299
 
286
300
  def from_binary(self, binary):
@@ -327,8 +341,12 @@ class FieldTime(FieldBase):
327
341
 
328
342
  bytes = 2
329
343
 
330
- def to_binary(self, val: datetime.datetime | str):
331
- if isinstance(val, str):
344
+ def to_binary(self, val: datetime.datetime | datetime.time | str):
345
+ if val is None:
346
+ val = datetime.time(0, 0)
347
+ elif not isinstance(val, datetime.datetime) and not isinstance(val, datetime.time):
348
+ raise ValueError(f'Error en el campo "{self.key}" se espera un datetime o time pero se recibe {val}')
349
+ elif isinstance(val, str):
332
350
  val = datetime.datetime.strptime(val, '%H:%M').date()
333
351
  return bytes([
334
352
  self.to_nible(val.hour),
@@ -338,13 +356,15 @@ class FieldTime(FieldBase):
338
356
  def from_binary(self, binary):
339
357
  H, binary = self.get_nible(binary)
340
358
  M, binary = self.get_nible(binary)
359
+ if H == 0 and M == 0:
360
+ return None
341
361
  return datetime.time(H, M)
342
362
 
343
363
 
344
364
  class FieldTimestamp(FieldBase):
345
365
 
346
- def __init__(self, js):
347
- super().__init__(js)
366
+ def __init__(self, k, js):
367
+ super().__init__(k, js)
348
368
  self.bytes = 8
349
369
 
350
370
  def to_binary(self, val: datetime.datetime | str):
@@ -9,13 +9,14 @@ class Format:
9
9
 
10
10
  fields: [FieldBase]
11
11
 
12
- def __init__(self, fields: [object]):
12
+ def __init__(self, format: [object]):
13
13
  self.fields = []
14
- for f in fields:
15
- self.fields.append(FIELD_MAP[f['type']](f))
14
+ self.header = format['header']
15
+ for k, f in format['fields'].items():
16
+ self.fields.append(FIELD_MAP[f['type']](k, f))
16
17
 
17
18
  def encode(self, data):
18
- binary = b''
19
+ binary = self.header.encode('utf') + b'='
19
20
  for f in self.fields:
20
21
  binary += f.encode(data)
21
22
  return binary
@@ -24,11 +25,11 @@ class Format:
24
25
  data = {}
25
26
  for f in self.fields:
26
27
  val, binary = f.decode(binary)
27
- if f.key:
28
- data[f.key] = val
29
- else:
30
- for k in f.keys:
28
+ if isinstance(f.key, list):
29
+ for k in f.key:
31
30
  data[k] = val[k]
31
+ else:
32
+ data[f.key] = val
32
33
  return data
33
34
 
34
35
  def to_dict(self):
@@ -38,25 +39,31 @@ class Format:
38
39
  class Protocol:
39
40
 
40
41
  def __init__(self, file=None, js=None):
42
+ self.headers = {}
41
43
  if file:
42
44
  with open(file, 'r') as f:
43
45
  if 'json' in file:
44
46
  js = json.loads(f.read())
45
- self.formats = {}
46
- for k in js.keys():
47
- self.formats[k] = Format(js[k])
47
+ self.load_format(js)
48
48
  elif 'yaml' in file:
49
49
  js = yaml.full_load(f.read())
50
- self.formats = {}
51
- for k in js.keys():
52
- self.formats[k] = Format(js[k])
50
+ self.load_format(js)
51
+ else:
52
+ self.load_format(js)
53
53
 
54
+ def load_format(self, js):
55
+ self.formats = {}
56
+ for k in js.keys():
57
+ self.formats[k] = Format(js[k])
58
+ self.headers[js[k]['header']] = k
54
59
 
55
- def temp_format(self, k):
56
- return self.formats[k].to_dict()
60
+ def get_format(self, h):
61
+ return self.formats[self.headers[h.decode('utf')]]
57
62
 
58
63
  def encode(self, data, format):
59
64
  return self.formats[format].encode(data)
60
65
 
61
- def decode(self, binary, format):
62
- return self.formats[format].decode(binary)
66
+ def decode(self, binary):
67
+ h, binary = binary.split(b'=')
68
+ format = self.get_format(h)
69
+ return h.decode('utf'), format.decode(binary)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "protobin"
7
- version = "0.0.6"
7
+ version = "0.0.7"
8
8
  authors = [
9
9
  { name="Daniel Robles", email="drm.electronic@gmail.com" },
10
10
  ]
@@ -0,0 +1,30 @@
1
+ {
2
+ "login": {
3
+ "header": "T",
4
+ "fields": {
5
+ "serial": {"bytes": 0, "type": "string"}
6
+ }
7
+ },
8
+ "report": {
9
+ "header": "P",
10
+ "fields": {
11
+ "positions": {"bytes": 19, "type": "array", "array": {
12
+ "time": {"bytes": 6, "type": "datetime"},
13
+ "lng": {"bytes": 4, "type": "float", "decimals": 6},
14
+ "lat": {"bytes": 4, "type": "float", "decimals": 6},
15
+ "speed": {"bytes": 1, "type": "unsigned"},
16
+ "mark": {"bytes": 2, "type": "unsigned"},
17
+ "busstop": {"bytes": 2, "type": "unsigned"}}
18
+ },
19
+ "trip": {"bytes": 4, "type": "unsigned"},
20
+ "route": {"bytes": 1, "type": "unsigned"},
21
+ "direction": {"bytes": 1, "type": "bool"},
22
+ "state": {"bytes": 1, "type": "char"},
23
+ "sales": {"bytes": 3, "type": "unsigned"},
24
+ "events": {"bytes": 3, "type": "array", "array": {
25
+ "id": {"bytes": 2, "type": "unsigned"},
26
+ "value": {"bytes": 1, "type": "unsigned"}}
27
+ }
28
+ }
29
+ }
30
+ }
@@ -1,53 +1,55 @@
1
1
  report:
2
- positions:
3
- bytes: 19
4
- type: array
5
- array:
6
- time:
7
- bytes: 6
8
- type: datetime
9
- lng:
10
- bytes: 4
11
- decimals: 6
12
- type: float
13
- lat:
14
- bytes: 4
15
- decimals: 6
16
- type: float
17
- speed:
18
- bytes: 1
19
- type: unsigned
20
- mark:
21
- bytes: 2
22
- type: unsigned
23
- busstop:
24
- bytes: 2
25
- type: unsigned
26
- trip:
27
- bytes: 4
28
- type: unsigned
29
- route:
30
- bytes: 1
31
- type: unsigned
32
- direction:
33
- bytes: 1
34
- type: bool
35
- state:
36
- bytes: 1
37
- type: char
38
- sales:
39
- bytes: 3
40
- type: unsigned
41
- events:
42
- bytes: 3
43
- type: array
44
- array:
45
- id:
46
- bytes: 2
47
- type: unsigned
48
- value:
49
- bytes: 1
50
- type: unsigned
2
+ header: P
3
+ format:
4
+ positions:
5
+ bytes: 19
6
+ type: array
7
+ array:
8
+ time:
9
+ bytes: 6
10
+ type: datetime
11
+ lng:
12
+ bytes: 4
13
+ decimals: 6
14
+ type: float
15
+ lat:
16
+ bytes: 4
17
+ decimals: 6
18
+ type: float
19
+ speed:
20
+ bytes: 1
21
+ type: unsigned
22
+ mark:
23
+ bytes: 2
24
+ type: unsigned
25
+ busstop:
26
+ bytes: 2
27
+ type: unsigned
28
+ trip:
29
+ bytes: 4
30
+ type: unsigned
31
+ route:
32
+ bytes: 1
33
+ type: unsigned
34
+ direction:
35
+ bytes: 1
36
+ type: bool
37
+ state:
38
+ bytes: 1
39
+ type: char
40
+ sales:
41
+ bytes: 3
42
+ type: unsigned
43
+ events:
44
+ bytes: 3
45
+ type: array
46
+ array:
47
+ id:
48
+ bytes: 2
49
+ type: unsigned
50
+ value:
51
+ bytes: 1
52
+ type: unsigned
51
53
 
52
54
  ask_schedule:
53
55
  id:
@@ -62,73 +62,69 @@ DATA = {
62
62
  }
63
63
 
64
64
 
65
- class FormatTest(unittest.TestCase):
66
-
67
- def test_format_array(self):
68
- parser = Protocol(js={
69
- 'array': [{'key': 'test', 'bytes': 0, 'type': 'array', 'array': [
70
- {'key': 'test', 'bytes': 0, 'type': 'string'}
71
- ]}]
72
- })
73
-
74
- def test_format_bits(self):
75
- parser = Protocol(js={
76
- 'bits': [{'key': 'test', 'bytes': 2, 'type': 'bits'}],
77
- })
78
-
79
- def test_format_date(self):
80
-
81
- self.parser = Protocol(js={
82
- 'date': [{'key': 'test', 'bytes': 1, 'type': 'date'}],
83
- })
84
-
85
- def test_format_flags(self):
86
-
87
- self.parser = Protocol(js={
88
- 'flags': [{'keys': ['f1', 'f2', 'f3', 'f4'], 'bytes': 1, 'type': 'flags'}],
89
- })
90
-
91
- def test_format(self):
92
-
93
- self.parser = Protocol(js={
94
- 'array': [{'key': 'test', 'bytes': 0, 'type': 'array', 'array': [
95
- {'key': 'test', 'bytes': 0, 'type': 'string'}
96
- ]}],
97
- 'bits': [{'key': 'test', 'bytes': 2, 'type': 'bits'}],
98
- 'bool': [{'key': 'test', 'bytes': 1, 'type': 'bool'}],
99
- 'char': [{'key': 'test', 'bytes': 1, 'type': 'char'}],
100
- 'date': [{'key': 'test', 'bytes': 3, 'type': 'date'}],
101
- 'datetime': [{'key': 'test', 'bytes': 6, 'type': 'datetime'}],
102
- 'flags': [{'keys': ['f1', 'f2', 'f3', 'f4'], 'bytes': 1, 'type': 'flags'}],
103
- 'float': [{'key': 'test', 'bytes': 4, 'decimals': 6, 'type': 'float'}],
104
- 'signed': [{'key': 'test', 'bytes': 2, 'type': 'signed'}],
105
- 'string': [{'key': 'test', 'bytes': 0, 'type': 'string'}],
106
- 'time': [{'key': 'test', 'bytes': 1, 'type': 'time'}],
107
- 'timestamp': [{'key': 'test', 'bytes': 8, 'type': 'string'}],
108
- 'unsigned': [{'key': 'test', 'bytes': 3, 'type': 'unsigned'}]
109
- })
110
-
111
-
112
65
  class BasicTest(unittest.TestCase):
113
66
 
114
67
  def setUp(self):
115
68
  self.protocol = Protocol(js={
116
- 'array': [{'key': 'test', 'bytes': 0, 'type': 'array', 'array': [
117
- {'key': 'test', 'bytes': 0, 'type': 'string'}
118
- ]}],
119
- 'bits': [{'key': 'test', 'type': 'bits'}],
120
- 'bits_fixed': [{'key': 'test', 'type': 'bits', 'length': 7}],
121
- 'bool': [{'key': 'test', 'bytes': 1, 'type': 'bool'}],
122
- 'char': [{'key': 'test', 'bytes': 1, 'type': 'char'}],
123
- 'date': [{'key': 'test', 'bytes': 1, 'type': 'date'}],
124
- 'datetime': [{'key': 'test', 'bytes': 1, 'type': 'datetime'}],
125
- 'flags': [{'keys': ['f1', 'f2', 'f3', 'f4'], 'type': 'flags'}],
126
- 'float': [{'key': 'test', 'bytes': 4, 'decimals': 6, 'type': 'float'}],
127
- 'signed': [{'key': 'test', 'bytes': 2, 'type': 'signed'}],
128
- 'string': [{'key': 'test', 'bytes': 0, 'type': 'string'}],
129
- 'time': [{'key': 'test', 'bytes': 2, 'type': 'time'}],
130
- 'timestamp': [{'key': 'test', 'bytes': 8, 'type': 'timestamp'}],
131
- 'unsigned': [{'key': 'test', 'bytes': 3, 'type': 'unsigned'}]
69
+ 'array': {
70
+ "header": "A",
71
+ "fields": {
72
+ 'test': {'bytes': 0, 'type': 'array', 'array': {
73
+ 'test': {'bytes': 0, 'type': 'string'}
74
+ }}}
75
+ },
76
+ 'bits': {
77
+ "header": "B",
78
+ "fields": {'test': {'type': 'bits'}}
79
+ },
80
+ 'bits_fixed': {
81
+ "header": "b",
82
+ "fields": {'test': {'type': 'bits', 'length': 7}}
83
+ },
84
+ 'bool': {
85
+ "header": "BO",
86
+ "fields": {'test': {'bytes': 1, 'type': 'bool'}}
87
+ },
88
+ 'char': {
89
+ "header": "C",
90
+ "fields": {'test': {'bytes': 1, 'type': 'char'}}
91
+ },
92
+ 'date': {
93
+ "header": "D",
94
+ "fields": {'test': {'bytes': 1, 'type': 'date'}}
95
+ },
96
+ 'datetime': {
97
+ "header": "d",
98
+ "fields": {'test': {'bytes': 1, 'type': 'datetime'}}
99
+ },
100
+ 'flags': {
101
+ "header": "F",
102
+ "fields": {'f1,f2,f3,f4': {'type': 'flags'}}
103
+ },
104
+ 'float': {
105
+ "header": "f",
106
+ "fields": {'test': {'bytes': 4, 'decimals': 6, 'type': 'float'}}
107
+ },
108
+ 'signed': {
109
+ "header": "+",
110
+ "fields": {'test': {'bytes': 2, 'type': 'signed'}}
111
+ },
112
+ 'string': {
113
+ "header": "S",
114
+ "fields": {'test': {'bytes': 0, 'type': 'string'}}
115
+ },
116
+ 'time': {
117
+ "header": "T",
118
+ "fields": {'test': {'bytes': 2, 'type': 'time'}}
119
+ },
120
+ 'timestamp': {
121
+ "header": "TS",
122
+ "fields": {'test': {'bytes': 8, 'type': 'timestamp'}}
123
+ },
124
+ 'unsigned': {
125
+ "header": "u",
126
+ "fields": {'test': {'bytes': 3, 'type': 'unsigned'}}
127
+ }
132
128
  })
133
129
 
134
130
  def test_array(self):
@@ -138,7 +134,7 @@ class BasicTest(unittest.TestCase):
138
134
  {'test': 'otra más'}]
139
135
  }
140
136
  binary = self.protocol.encode(data, 'array')
141
- recv = self.protocol.decode(binary, 'array')
137
+ h, recv = self.protocol.decode(binary)
142
138
  self.assertEqual(data, recv)
143
139
  data = {'test': [
144
140
  {'test': 'texto2 de prueba'},
@@ -147,93 +143,120 @@ class BasicTest(unittest.TestCase):
147
143
  {'test': 'y una última'}]
148
144
  }
149
145
  binary = self.protocol.encode(data, 'array')
150
- recv = self.protocol.decode(binary, 'array')
146
+ h, recv = self.protocol.decode(binary)
151
147
  self.assertEqual(data, recv)
152
148
 
153
149
  def test_bits(self):
154
150
  data = {'test': [True, False, True, False, False] * 3}
155
151
  binary = self.protocol.encode(data, 'bits')
156
- recv = self.protocol.decode(binary, 'bits')
152
+ h, recv = self.protocol.decode(binary)
157
153
  self.assertEqual(data, recv)
158
154
  data = {'test': [True, False, True, False, False] * 5}
159
155
  binary = self.protocol.encode(data, 'bits')
160
- recv = self.protocol.decode(binary, 'bits')
156
+ h, recv = self.protocol.decode(binary)
161
157
  self.assertEqual(data, recv)
162
158
 
163
159
  def test_bits_fixed(self):
164
160
  data = {'test': [True, False, True, False, False, True, True]}
165
161
  binary = self.protocol.encode(data, 'bits_fixed')
166
- recv = self.protocol.decode(binary, 'bits_fixed')
162
+ h, recv = self.protocol.decode(binary)
167
163
  self.assertEqual(data, recv)
168
164
 
169
165
  def test_bool(self):
170
166
  data = {'test': False}
171
167
  binary = self.protocol.encode(data, 'bool')
172
- recv = self.protocol.decode(binary, 'bool')
168
+ h, recv = self.protocol.decode(binary)
169
+ self.assertEqual(data, recv)
170
+
171
+ def test_bool_none(self):
172
+ data = {'test': None}
173
+ binary = self.protocol.encode(data, 'bool')
174
+ h, recv = self.protocol.decode(binary)
173
175
  self.assertEqual(data, recv)
174
176
 
175
177
  def test_char(self):
176
178
  data = {'test': 'F'}
177
179
  binary = self.protocol.encode(data, 'char')
178
- recv = self.protocol.decode(binary, 'char')
180
+ h, recv = self.protocol.decode(binary)
179
181
  self.assertEqual(data, recv)
180
182
 
181
183
  def test_date(self):
182
184
  data = {'test': datetime.date(2024, 9, 13)}
183
185
  binary = self.protocol.encode(data, 'date')
184
- recv = self.protocol.decode(binary, 'date')
186
+ h, recv = self.protocol.decode(binary)
185
187
  self.assertEqual(data, recv)
186
188
 
187
189
  def test_datetime(self):
188
190
  data = {'test': datetime.datetime(2024, 9, 13, 15, 23, 51)}
189
191
  binary = self.protocol.encode(data, 'datetime')
190
- recv = self.protocol.decode(binary, 'datetime')
192
+ print('binary', binary)
193
+ h, recv = self.protocol.decode(binary)
194
+ print('recv', recv)
191
195
  self.assertEqual(data, recv)
192
196
 
197
+ def test_datetime_error_type(self):
198
+ data = {'test': []}
199
+ with self.assertRaises(ValueError) as er:
200
+ self.protocol.encode(data, 'datetime')
201
+
202
+ def test_datetime_none(self):
203
+ data = {'test': None}
204
+ binary = self.protocol.encode(data, 'datetime')
205
+ print('binary', binary)
206
+ h, recv = self.protocol.decode(binary)
207
+ print('recv', recv)
208
+ self.assertEqual(datetime.datetime(2000, 1, 1), recv['test'])
209
+
193
210
  def test_time(self):
194
211
  data = {'test': datetime.time(15, 23)}
195
212
  binary = self.protocol.encode(data, 'time')
196
- recv = self.protocol.decode(binary, 'time')
213
+ h, recv = self.protocol.decode(binary)
214
+ self.assertEqual(data, recv)
215
+
216
+ def test_time_none(self):
217
+ data = {'test': None}
218
+ binary = self.protocol.encode(data, 'time')
219
+ h, recv = self.protocol.decode(binary)
197
220
  self.assertEqual(data, recv)
198
221
 
199
222
  def test_flags(self):
200
223
  data = {'f1': True, 'f2': False, 'f3': False, 'f4': True}
201
224
  binary = self.protocol.encode(data, 'flags')
202
- recv = self.protocol.decode(binary, 'flags')
225
+ h, recv = self.protocol.decode(binary)
203
226
  self.assertEqual(data, recv)
204
227
 
205
228
  def test_float(self):
206
229
  data = {'test': -11.659812}
207
230
  binary = self.protocol.encode(data, 'float')
208
- recv = self.protocol.decode(binary, 'float')
231
+ h, recv = self.protocol.decode(binary)
209
232
  self.assertEqual(data, recv)
210
233
 
211
234
  def test_signed(self):
212
235
  data = {'test': -11812}
213
236
  binary = self.protocol.encode(data, 'signed')
214
- recv = self.protocol.decode(binary, 'signed')
237
+ h, recv = self.protocol.decode(binary)
215
238
  self.assertEqual(data, recv)
216
239
 
217
240
  def test_unsigned(self):
218
241
  data = {'test': 9811812}
219
242
  binary = self.protocol.encode(data, 'unsigned')
220
- recv = self.protocol.decode(binary, 'unsigned')
243
+ h, recv = self.protocol.decode(binary)
221
244
  self.assertEqual(data, recv)
222
245
 
223
246
  def test_string(self):
224
247
  data = {'test': 'texto de prueba'}
225
248
  binary = self.protocol.encode(data, 'string')
226
- recv = self.protocol.decode(binary, 'string')
249
+ h, recv = self.protocol.decode(binary)
227
250
  self.assertEqual(data, recv)
228
251
  data = {'test': 'otro texto de prueba más largo'}
229
252
  binary = self.protocol.encode(data, 'string')
230
- recv = self.protocol.decode(binary, 'string')
253
+ h, recv = self.protocol.decode(binary)
231
254
  self.assertEqual(data, recv)
232
255
 
233
256
  def test_timestamp(self):
234
257
  data = {'test': datetime.datetime(2024, 9, 13, 15, 23, 51, 265981)}
235
258
  binary = self.protocol.encode(data, 'timestamp')
236
- recv = self.protocol.decode(binary, 'timestamp')
259
+ h, recv = self.protocol.decode(binary)
237
260
  self.assertEqual(data, recv)
238
261
 
239
262
 
@@ -242,28 +265,31 @@ class AdvancedTest(unittest.TestCase):
242
265
  def test_file_json(self):
243
266
  protocol = Protocol(file='demo.json')
244
267
  binary = protocol.encode(DATA, 'report')
245
- recv = protocol.decode(binary, 'report')
268
+ h, recv = protocol.decode(binary)
246
269
  self.assertEqual(DATA, recv)
270
+ self.assertEqual(h, 'P')
247
271
 
248
- def test_file_yaml(self):
249
- protocol = Protocol(file='demo.yaml')
250
- binary = protocol.encode(DATA, 'report')
251
- recv = protocol.decode(binary, 'report')
252
- self.assertEqual(DATA, recv)
272
+ # def test_file_yaml(self):
273
+ # protocol = Protocol(file='demo.yaml')
274
+ # binary = protocol.encode(DATA, 'report')
275
+ # h, recv = protocol.decode(binary)
276
+ # self.assertEqual(h, 'P')
253
277
 
254
278
  def test_json(self):
255
- protocol = Protocol(js={'medida': [
256
- {'key': 'id', 'bytes': 1, 'type': 'unsigned'},
257
- {'key': 'nombre', 'type': 'string'},
258
- {'key': 'valor', 'bytes': 2, 'type': 'signed'}
259
- ]})
279
+ protocol = Protocol(js={'medida':
280
+ {'header': 'M',
281
+ 'fields': {
282
+ 'id': {'bytes': 1, 'type': 'unsigned'},
283
+ 'nombre': {'type': 'string'},
284
+ 'valor': {'bytes': 2, 'type': 'signed'}
285
+ }}})
260
286
  data = {'id': 2, 'nombre': 'Voltaje', 'valor': -20}
261
287
  binary = protocol.encode(data, 'medida')
262
- recv = protocol.decode(binary, 'medida')
288
+ h, recv = protocol.decode(binary)
263
289
  self.assertEqual(data, recv)
264
290
  data = {'id': 4, 'nombre': 'Corriente', 'valor': 240}
265
291
  binary = protocol.encode(data, 'medida')
266
- recv = protocol.decode(binary, 'medida')
292
+ h, recv = protocol.decode(binary)
267
293
  self.assertEqual(data, recv)
268
294
 
269
295
  def test_new_yaml(self):
@@ -319,8 +345,14 @@ class AdvancedTest(unittest.TestCase):
319
345
  type: unsigned
320
346
  """)
321
347
  js = json.dumps(ym, indent=2)
322
- print(js)
323
348
 
324
349
  def test_convert_json_to_yaml(self):
325
350
  protocol = Protocol(file='demo.json')
326
351
 
352
+ def test_login(self):
353
+ protocol = Protocol(file='demo.json')
354
+ data = {'serial': '15984316545'}
355
+ binary = protocol.encode(data, 'login')
356
+ header, recv = protocol.decode(binary)
357
+ self.assertEqual(data, recv)
358
+ self.assertEqual(header, 'T')
@@ -1,291 +0,0 @@
1
- {
2
- "ask_schedule1": {
3
- "id": [{"bytes": 4, "type": "unsigned"}],
4
- "inicio": [{"bytes": 6, "type": "datetime"}]},
5
-
6
- "fare": [
7
- {"key": "id", "bytes": 2, "type": "unsigned"},
8
- {"key": "color", "bytes": 7, "type": "string"},
9
- {"key": "orden", "bytes": 1, "type": "unsigned"},
10
- {"key": "nombre", "bytes": 13, "type": "string"},
11
- {"keys": ["activo", "reintegro"], "bytes": 1, "type": "flags"},
12
- {"keys": ["lunes", "martes", "miercoles", "jueves", "viernes", "sabado", "domingo", "feriado"], "bytes": 1, "type": "flags"},
13
- {"key": "ruta", "bytes": 2, "type": "unsigned"},
14
- {"key": "tarifa", "bytes": 2, "type": "float", "decimals": 2},
15
- {"key": "timestamp", "bytes": 6, "type": "datetime"}
16
- ],
17
- "command": [
18
- {"key": "comando", "bytes": 1, "type": "char"},
19
- {"key": "id", "bytes": 0, "type": "string"},
20
- {"key": "value", "bytes": 0, "type": "string"}
21
- ],
22
- "route_settings": [
23
- {"key": "id", "bytes": 2, "type": "unsigned"},
24
- {"key": "nombre", "bytes": 0, "type": "string"},
25
- {"key": "ruta", "bytes": 1, "type": "unsigned"},
26
- {"key": "tipo", "bytes": 0, "type": "string"},
27
- {"key": "data", "bytes": 0, "type": "string"},
28
- {"key": "timestamp", "bytes": 6, "type": "datetime"}
29
- ],
30
- "forward_datero": [
31
- {"key": "geocerca", "bytes": 2, "type": "unsigned"},
32
- {"key": "salida", "bytes": 4, "type": "unsigned"},
33
- {"key": "hora", "bytes": 6, "type": "datetime"},
34
- {"key": "dateros", "bytes": 0, "type": "array", "array": [
35
- {"key": "padron", "bytes": 2, "type": "unsigned"},
36
- {"key": "delta", "bytes": 1, "type": "unsigned"}
37
- ]}
38
- ],
39
- "backward_datero": [
40
- {"key": "geocerca", "bytes": 2, "type": "unsigned"},
41
- {"key": "i", "bytes": 1, "type": "unsigned"},
42
- {"key": "delta", "bytes": 1, "type": "unsigned"},
43
- {"key": "padron", "bytes": 2, "type": "unsigned"},
44
- {"key": "id", "bytes": 0, "type": "string"}
45
- ],
46
- "error": [
47
- {"key": "error", "bytes": 0, "type": "string"}
48
- ],
49
- "geocerca": [
50
- {"key": "id", "bytes": 2, "type": "unsigned"},
51
- {"key": "orden", "bytes": 1, "type": "unsigned"},
52
- {"key": "longitud", "bytes": 4, "type": "float", "decimals": 6},
53
- {"key": "latitud", "bytes": 4, "type": "float", "decimals": 6},
54
- {"key": "radio", "bytes": 2, "type": "unsigned"},
55
- {"key": "ruta", "bytes": 1, "type": "unsigned"},
56
- {"keys": ["lado", "control", "datear", "activo"], "bytes": 1, "type": "flags"},
57
- {"key": "nombre", "bytes": 15, "type": "string"},
58
- {"key": "timestamp", "bytes": 6, "type": "datetime"}
59
- ],
60
- "ask_trip": [
61
- {"key": "salida", "bytes": 4, "type": "unsigned"}
62
- ],
63
- "schedule": [
64
- {"key": "salida", "bytes": 4, "type": "unsigned"},
65
- {"key": "controles", "bytes": 0, "type": "array", "array": [
66
- {"key": "geocerca", "bytes": 2, "type": "unsigned"}
67
- ]}
68
- ],
69
- "ask_schedule": [
70
- {"key": "id", "bytes": 4, "type": "unsigned"},
71
- {"key": "inicio", "bytes": 6, "type": "datetime"},
72
- {"key": "controles", "bytes": 0, "type": "array", "array": [
73
- {"key": "geocerca", "bytes": 2, "type": "unsigned"},
74
- {"key": "tiempo", "bytes": 1, "type": "signed"},
75
- {"key": "volada", "bytes": 1, "type": "signed"}
76
- ]}
77
- ],
78
- "login": [
79
- {"key": "serial", "bytes": 0, "type": "string"}
80
- ],
81
- "new_ip": [
82
- {"key": "ip", "bytes": 0, "type": "string"}
83
- ],
84
- "login_device": [
85
- {"key": "id", "bytes": 2, "type": "unsigned"},
86
- {"key": "padron", "bytes": 2, "type": "unsigned"},
87
- {"key": "ruta", "bytes": 1, "type": "unsigned"},
88
- {"key": "lado", "bytes": 1, "type": "bool"},
89
- {"key": "geocerca", "bytes": 2, "type": "unsigned"},
90
- {"key": "estado", "bytes": 1, "type": "char"},
91
- {"key": "salida", "bytes": 4, "type": "unsigned"},
92
- {"key": "conductor", "bytes": 4, "type": "unsigned"},
93
- {"key": "orden", "bytes": 1, "type": "unsigned"},
94
- {"key": "logueado", "bytes": 1, "type": "bool"},
95
- {"key": "data", "bytes": 6, "type": "datetime"},
96
- {"key": "programada", "bytes": 2, "type": "time"}
97
- ],
98
- "start_sales": [
99
- {"key": "clave", "bytes": 0, "type": "string"},
100
- {"key": "dni", "bytes": 0, "type": "string"},
101
- {"key": "lado", "bytes": 1, "type": "bool"},
102
- {"key": "ruta", "bytes": 1, "type": "unsigned"},
103
- {"key": "unidad", "bytes": 2, "type": "unsigned"}
104
- ],
105
- "start_sales_response": [
106
- {"key": "error", "bytes": 1, "type": "bool"},
107
- {"key": "title", "bytes": 0, "type": "string"},
108
- {"key": "mensaje", "bytes": 0, "type": "string"},
109
- {"key": "sesiones", "bytes": 0, "type": "array", "array": [
110
- {"key": "id", "bytes": 4, "type": "unsigned"},
111
- {"key": "conductor_id", "bytes": 2, "type": "unsigned"},
112
- {"key": "conductor_codigo", "bytes": 0, "type": "string"},
113
- {"keys": ["activo", "castigado", "conductor", "vencido"], "bytes": 1, "type": "flags"},
114
- {"key": "ruta", "bytes": 1, "type": "unsigned"},
115
- {"key": "lado", "bytes": 1, "type": "bool"},
116
- {"key": "inicio", "bytes": 6, "type": "datetime"}
117
- ]}
118
- ],
119
- "finalize_sales": [
120
- {"key": "sesion", "bytes": 4, "type": "unsigned"},
121
- {"key": "unidad", "bytes": 2, "type": "unsigned"},
122
- {"key": "fin", "bytes": 6, "type": "datetime"},
123
- {"key": "produccion", "bytes": 4, "type": "unsigned"},
124
- {"key": "primero", "bytes": 4, "type": "unsigned"},
125
- {"key": "ultimo", "bytes": 4, "type": "unsigned"}
126
- ],
127
- "finalize_sales_response": [
128
- {"key": "error", "bytes": 1, "type": "bool"},
129
- {"key": "title", "bytes": 0, "type": "string"},
130
- {"key": "mensaje", "bytes": 0, "type": "string"},
131
- {"key": "id", "bytes": 4, "type": "unsigned"}
132
- ],
133
- "message": [
134
- {"key": "id", "bytes": 4, "type": "unsigned"},
135
- {"key": "texto", "bytes": 0, "type": "string"}
136
- ],
137
- "message_response": [
138
- {"key": "id", "bytes": 4, "type": "unsigned"},
139
- {"key": "read", "bytes": 1, "type": "bool"}
140
- ],
141
- "operation": [
142
- {"key": "id", "bytes": 0, "type": "string"},
143
- {"key": "section", "bytes": 0, "type": "string"},
144
- {"key": "key", "bytes": 0, "type": "string"},
145
- {"key": "value", "bytes": 0, "type": "string"}
146
- ],
147
- "operation_response": [
148
- {"key": "id", "bytes": 0, "type": "string"}
149
- ],
150
- "busstop": [
151
- {"key": "id", "bytes": 2, "type": "unsigned"},
152
- {"key": "orden", "bytes": 1, "type": "unsigned"},
153
- {"key": "longitud", "bytes": 4, "type": "float", "decimals": 6},
154
- {"key": "latitud", "bytes": 4, "type": "float", "decimals": 6},
155
- {"key": "radio", "bytes": 2, "type": "unsigned"},
156
- {"key": "ruta", "bytes": 1, "type": "unsigned"},
157
- {"keys": ["liquidar", "lado", "terminal", "activo"], "bytes": 1, "type": "flags"},
158
- {"key": "nombre", "bytes": 14, "type": "string"},
159
- {"key": "velocidad", "bytes": 1, "type": "unsigned"},
160
- {"key": "tarifas", "bytes": 0, "type": "array", "array": [
161
- {"key": "boleto", "bytes": 2, "type": "unsigned"},
162
- {"key": "fin", "bytes": 2, "type": "unsigned"}
163
- ]},
164
- {"key": "timestamp", "bytes": 6, "type": "datetime"}
165
- ],
166
- "parameter": [
167
- {"key": "id", "bytes": 0, "type": "string"},
168
- {"key": "nombre", "bytes": 0, "type": "string"},
169
- {"key": "valor", "bytes": 0, "type": "string"}
170
- ],
171
- "report": [
172
- {"key": "positions", "bytes": 19, "type": "array", "array": [
173
- {"key": "time", "bytes": 6, "type": "datetime"},
174
- {"key": "lng", "bytes": 4, "type": "float", "decimals": 6},
175
- {"key": "lat", "bytes": 4, "type": "float", "decimals": 6},
176
- {"key": "speed", "bytes": 1, "type": "unsigned"},
177
- {"key": "mark", "bytes": 2, "type": "unsigned"},
178
- {"key": "busstop", "bytes": 2, "type": "unsigned"}
179
- ]},
180
- {"key": "trip", "bytes": 4, "type": "unsigned"},
181
- {"key": "route", "bytes": 1, "type": "unsigned"},
182
- {"key": "direction", "bytes": 1, "type": "bool"},
183
- {"key": "state", "bytes": 1, "type": "char"},
184
- {"key": "sales", "bytes": 3, "type": "unsigned"},
185
- {"key": "events", "bytes": 3, "type": "array", "array": [
186
- {"key": "id", "bytes": 2, "type": "unsigned"},
187
- {"key": "value", "bytes": 1, "type": "unsigned"}
188
- ]}
189
- ],
190
- "report": {
191
- "positions": {"bytes": 19,"type": "array",
192
- "array": {
193
- "time": {"bytes": 6,"type": "datetime"},
194
- "lng": {"bytes": 4,"decimals": 6,"type": "float"},
195
- "lat": {"bytes": 4,"decimals": 6,"type": "float"},
196
- "speed": {"bytes": 1,"type": "unsigned"},
197
- "mark": {"bytes": 2,"type": "unsigned"},
198
- "busstop": {"bytes": 2,"type": "unsigned"}
199
- }
200
- },
201
- "trip": {"bytes": 4,"type": "unsigned"},
202
- "route": {"bytes": 1,"type": "unsigned"},
203
- "direction": {"bytes": 1,"type": "bool"},
204
- "state": {"bytes": 1,"type": "char"},
205
- "sales": {"bytes": 3,"type": "unsigned"},
206
- "events": {"bytes": 3,"type": "array",
207
- "array": {
208
- "id": {"bytes": 2,"type": "unsigned"},
209
- "value": {"bytes": 1,"type": "unsigned"}
210
- }
211
- }
212
- },
213
- "position_response": [
214
- {"key": "reportes", "bytes": 1, "type": "unsigned"},
215
- {"key": "ids", "bytes": 0, "type": "array", "array": [
216
- {"key": "id", "bytes": 2, "type": "unsigned"}
217
- ]}
218
- ],
219
- "route": [
220
- {"key": "id", "bytes": 2, "type": "unsigned"},
221
- {"key": "codigo", "bytes": 0, "type": "string"},
222
- {"key": "timestamp", "bytes": 6, "type": "datetime"}
223
- ],
224
- "trip": [
225
- {"key": "id", "bytes": 4, "type": "unsigned"},
226
- {"key": "ruta", "bytes": 1, "type": "unsigned"},
227
- {"key": "lado", "bytes": 1, "type": "bool"},
228
- {"key": "inicio", "bytes": 6, "type": "datetime"},
229
- {"key": "estado", "bytes": 1, "type": "char"},
230
- {"key": "frecuencia", "bytes": 1, "type": "unsigned"},
231
- {"key": "conductor", "bytes": 4, "type": "unsigned"},
232
- {"key": "geocerca", "bytes": 2, "type": "unsigned"},
233
- {"key": "controles", "bytes": 0, "type": "array", "array": [
234
- {"key": "geocerca", "bytes": 2, "type": "unsigned"},
235
- {"key": "tiempo", "bytes": 1, "type": "signed"},
236
- {"key": "volada", "bytes": 1, "type": "signed"}
237
- ]},
238
- {"key": "marcados", "bytes": 0, "type": "bits"}
239
- ],
240
- "settings": [
241
- {"key": "id", "bytes": 2, "type": "unsigned"},
242
- {"key": "nombre", "bytes": 0, "type": "string"},
243
- {"key": "tipo", "bytes": 0, "type": "string"},
244
- {"key": "data", "bytes": 0, "type": "string"},
245
- {"key": "timestamp", "bytes": 6, "type": "datetime"}
246
- ],
247
- "tickets": [
248
- {"key": "tickets", "bytes": 0, "type": "array", "array": [
249
- {"key": "boleto", "bytes": 2, "type": "unsigned"},
250
- {"key": "conductor", "bytes": 2, "type": "unsigned"},
251
- {"key": "correlativo", "bytes": 4, "type": "unsigned"},
252
- {"key": "dia", "bytes": 3, "type": "date"},
253
- {"key": "fin", "bytes": 2, "type": "unsigned"},
254
- {"key": "hora", "bytes": 6, "type": "datetime"},
255
- {"key": "inicio", "bytes": 4, "type": "unsigned"},
256
- {"key": "inspector", "bytes": 2, "type": "unsigned"},
257
- {"key": "medio_pago", "bytes": 1, "type": "unsigned"},
258
- {"key": "numero", "bytes": 4, "type": "unsigned"},
259
- {"key": "precio", "bytes": 2, "type": "unsigned"},
260
- {"key": "ruta", "bytes": 1, "type": "unsigned"},
261
- {"key": "sesion", "bytes": 4, "type": "unsigned"},
262
- {"key": "unidad", "bytes": 2, "type": "unsigned"},
263
- {"key": "tarjeta", "bytes": 0, "type": "string"}
264
- ]}
265
- ],
266
- "tickets_response": [
267
- {"key": "tickets", "bytes": 0, "type": "array", "array": [
268
- {"key": "correlativo", "bytes": 4, "type": "unsigned"},
269
- {"key": "id", "bytes": 0, "type": "string"}
270
- ]}
271
- ],
272
- "timestamp": [
273
- {"key": "timestamp", "bytes": 6, "type": "timestamp"}
274
- ],
275
- "timestamp_us": [
276
- {"key": "timestamp", "bytes": 8, "type": "timestamp"}
277
- ],
278
- "remaining_data": [
279
- {"key": "faltantes", "bytes": 4, "type": "unsigned"},
280
- {"key": "tabla", "bytes": 1, "type": "char"}
281
- ],
282
- "user_route": [
283
- {"key": "id", "bytes": 2, "type": "unsigned"},
284
- {"key": "celular", "bytes": 9, "type": "string"},
285
- {"key": "nombre", "bytes": 14, "type": "string"},
286
- {"key": "rutas", "bytes": 1, "type": "array", "array": [
287
- {"key": "ruta", "bytes": 1, "type": "unsigned"}
288
- ]},
289
- {"key": "timestamp", "bytes": 6, "type": "datetime"}
290
- ]
291
- }
File without changes
File without changes
File without changes
File without changes
File without changes