Skip to content

Commit ab6aaf7

Browse files
ssikdar1WillAyd
authored andcommitted
Fix nested_to_record with None values in nested levels (pandas-dev#21164)
1 parent 9d61ab5 commit ab6aaf7

File tree

3 files changed

+58
-1
lines changed

3 files changed

+58
-1
lines changed

doc/source/whatsnew/v0.23.1.txt

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ I/O
9797

9898
- Bug in IO methods specifying ``compression='zip'`` which produced uncompressed zip archives (:issue:`17778`, :issue:`21144`)
9999
- Bug in :meth:`DataFrame.to_stata` which prevented exporting DataFrames to buffers and most file-like objects (:issue:`21041`)
100+
- Bug when :meth:`pandas.io.json.json_normalize` was called with ``None`` values in nested levels in JSON (:issue:`21158`)
100101
- Bug in :meth:`DataFrame.to_csv` and :meth:`Series.to_csv` causes encoding error when compression and encoding are specified (:issue:`21241`, :issue:`21118`)
101102
- Bug in :meth:`read_stata` and :class:`StataReader` which did not correctly decode utf-8 strings on Python 3 from Stata 14 files (dta version 118) (:issue:`21244`)
102103
-

pandas/io/json/normalize.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def nested_to_record(ds, prefix="", sep=".", level=0):
8080
if level != 0: # so we skip copying for top level, common case
8181
v = new_d.pop(k)
8282
new_d[newkey] = v
83-
if v is None: # pop the key if the value is None
83+
elif v is None: # pop the key if the value is None
8484
new_d.pop(k)
8585
continue
8686
else:

pandas/tests/io/json/test_normalize.py

+56
Original file line numberDiff line numberDiff line change
@@ -375,3 +375,59 @@ def test_nonetype_dropping(self):
375375
'info.last_updated': '26/05/2012'}]
376376

377377
assert result == expected
378+
379+
def test_nonetype_top_level_bottom_level(self):
380+
# GH21158: If inner level json has a key with a null value
381+
# make sure it doesnt do a new_d.pop twice and except
382+
data = {
383+
"id": None,
384+
"location": {
385+
"country": {
386+
"state": {
387+
"id": None,
388+
"town.info": {
389+
"id": None,
390+
"region": None,
391+
"x": 49.151580810546875,
392+
"y": -33.148521423339844,
393+
"z": 27.572303771972656}}}
394+
}
395+
}
396+
result = nested_to_record(data)
397+
expected = {
398+
'location.country.state.id': None,
399+
'location.country.state.town.info.id': None,
400+
'location.country.state.town.info.region': None,
401+
'location.country.state.town.info.x': 49.151580810546875,
402+
'location.country.state.town.info.y': -33.148521423339844,
403+
'location.country.state.town.info.z': 27.572303771972656}
404+
assert result == expected
405+
406+
def test_nonetype_multiple_levels(self):
407+
# GH21158: If inner level json has a key with a null value
408+
# make sure it doesnt do a new_d.pop twice and except
409+
data = {
410+
"id": None,
411+
"location": {
412+
"id": None,
413+
"country": {
414+
"id": None,
415+
"state": {
416+
"id": None,
417+
"town.info": {
418+
"region": None,
419+
"x": 49.151580810546875,
420+
"y": -33.148521423339844,
421+
"z": 27.572303771972656}}}
422+
}
423+
}
424+
result = nested_to_record(data)
425+
expected = {
426+
'location.id': None,
427+
'location.country.id': None,
428+
'location.country.state.id': None,
429+
'location.country.state.town.info.region': None,
430+
'location.country.state.town.info.x': 49.151580810546875,
431+
'location.country.state.town.info.y': -33.148521423339844,
432+
'location.country.state.town.info.z': 27.572303771972656}
433+
assert result == expected

0 commit comments

Comments
 (0)