Как мне декодировать сообщение Avro в Python?
У меня проблемы с декодированием сообщения Avro в Python (3.6.11). Я пробовал как
avro
и
fastavro
пакеты. Поэтому я думаю, что проблема может заключаться в том, что я неправильно указываю байты.
Используя avro:
from avro.io import DatumReader, BinaryDecoder
import avro.schema
from io import BytesIO
schema = avro.schema.parse("""
{
"type": "record",
"name": "User",
"namespace": "example.avro",
"fields": [
{
"name": "name",
"type": "string"
},
{
"name": "favorite_number",
"type": [
"int",
"null"
]
},
{
"name": "favorite_color",
"type": [
"string",
"null"
]
}
]
}
""")
rb = BytesIO(b'{"name": "Alyssa", "favorite_number": 256}')
decoder = BinaryDecoder(rb)
reader = DatumReader(schema)
msg = reader.read(decoder)
print(msg)
Traceback (most recent call last):
File "main.py", line 36, in <module>
msg = reader.read(decoder)
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/avro/io.py", line 626, in read
return self.read_data(self.writers_schema, self.readers_schema, decoder)
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/avro/io.py", line 698, in read_data
return self.read_record(writers_schema, readers_schema, decoder)
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/avro/io.py", line 898, in read_record
field_val = self.read_data(field.type, readers_field.type, decoder)
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/avro/io.py", line 638, in read_data
return self.read_union(writers_schema, readers_schema, decoder)
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/avro/io.py", line 854, in read_union
index_of_schema = int(decoder.read_long())
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/avro/io.py", line 240, in read_long
b = ord(self.read(1))
TypeError: ord() expected a character, but string of length 0 found
Используйте fastavro:
from fastavro import schemaless_reader, parse_schema
from io import BytesIO
schema = parse_schema(
{
"type": "record",
"name": "User",
"namespace": "example.avro",
"fields": [
{
"name": "name",
"type": "string"
},
{
"name": "favorite_number",
"type": [
"int",
"null"
]
},
{
"name": "favorite_color",
"type": [
"string",
"null"
]
}
]
}
)
rb = BytesIO(b'{"name": "Alyssa", "favorite_number": 256}')
msg = schemaless_reader(rb, schema)
print(msg)
Traceback (most recent call last):
File "main.py", line 33, in <module>
msg = schemaless_reader(rb, schema)
File "fastavro/_read.pyx", line 969, in fastavro._read.schemaless_reader
File "fastavro/_read.pyx", line 981, in fastavro._read.schemaless_reader
File "fastavro/_read.pyx", line 652, in fastavro._read._read_data
File "fastavro/_read.pyx", line 510, in fastavro._read.read_record
File "fastavro/_read.pyx", line 644, in fastavro._read._read_data
File "fastavro/_read.pyx", line 429, in fastavro._read.read_union
File "fastavro/_read.pyx", line 200, in fastavro._read.read_long
StopIteration
Я не знаю, искажено ли сообщение, которое я кодирую, или проблема связана с самой кодировкой. Какие-либо предложения?
1 ответ
Решение
Я поговорю с fastavro, потому что это то, что я знаю лучше всего.
Твой
rb
переменная должна быть двоичным файлом avro, который вы пытаетесь прочитать (а не данными). Чтобы получить пример того, что это за двоичный файл, вы можете написать:
rb = BytesIO()
schemaless_writer(rb, schema, {"name": "Alyssa", "favorite_number": 256})
rb.getvalue() # b'\x0cAlyssa\x00\x80\x04\x02'
Затем вы можете сделать то, что пытаетесь, и прочитать полученный двоичный файл:
rb = BytesIO(b'\x0cAlyssa\x00\x80\x04\x02')
data = schemaless_reader(rb, schema)
# {'name': 'Alyssa', 'favorite_number': 256, 'favorite_color': None}