danielgtaylor / danielgtaylor/python-betterproto

Integer keys in maps are not parsed correctly from JSON

Aperta
#235 5 commenti 0 reazioni 0 assegnatari Vedi su GitHub
bug
Lingua principale
Python
Stelle
1.8k
Fork
234
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Descrizione

JSON requires that keys be represented as strings, however proto allows map keys to be any integral or string type. So when specifying a message with a JSON representation, integer keys must be represented as strings. These are not picked up by the `.from_json()` method, which just runs `json.loads(value)`.

Example:
The proto message
```
message MapTest {
map string_map = 1;
map int_map = 2;
}
```
with JSON example:
```json
{
"string_map": {
"hello": 2.3,
"there": 5.6
},
"int_map": {
"1": 7.9,
"2": 8.3
}
}
```
Would be parsed by better proto as
`MapTest(string_map={'hello': 2.3, 'there': 5.6}, int_map={'1': 7.9, '2': 8.3})`

To overcome this we just need to add a custom JSON decoder to the from_json method which looks for any keys which are integers.

An example implementation, adapted from this [link](https://stackoverflow.com/questions/45068797/how-to-convert-string-int-json-into-real-int-with-json-loads) would be:
```
class Decoder(json.JSONDecoder):
def decode(self, s):
result = super().decode(s) # result = super(Decoder, self).decode(s) for Python 2.x
return self._decode(result)

def _decode(self, o):
if isinstance(o, str):# or isinstance(o, unicode):
try:
return int(o)
except ValueError:
return o
elif isinstance(o, dict):
try:
return {int(k): self._decode(v) for k, v in o.items()}
except ValueError:
return {k: self._decode(v) for k, v in o.items()}
elif isinstance(o, list):
return [self._decode(v) for v in o]
else:
return o
```
We'd then run `json.loads(value, cls=Decoder)`

Guida per i contributori

Apri la guida per i contributori

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.