Skip to content

Commit e213ee0

Browse files
authored
Improve remove_nones to handle nested data structures (#272)
1 parent ab04d52 commit e213ee0

File tree

2 files changed

+103
-6
lines changed

2 files changed

+103
-6
lines changed

ocpp/charge_point.py

+12-5
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,18 @@ def snake_to_camel_case(data):
7171

7272

7373
def remove_nones(dict_to_scan):
74-
dict_to_scan = {
75-
k: v for k, v in dict_to_scan.items()
76-
if v is not None
77-
}
78-
return dict_to_scan
74+
new_dict = {}
75+
for k, v in dict_to_scan.items():
76+
if isinstance(v, dict):
77+
v = remove_nones(v)
78+
if isinstance(v, list):
79+
new_list = []
80+
for item in v:
81+
new_list.append(remove_nones(item))
82+
v = new_list
83+
if v is not None:
84+
new_dict[k] = v
85+
return new_dict
7986

8087

8188
class ChargePoint:

tests/test_charge_point.py

+91-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
1+
from dataclasses import asdict
2+
13
import pytest
24
from ocpp.v20 import ChargePoint as cp
35
from ocpp.routing import on, create_route_map
6+
from ocpp.v16.call import BootNotificationPayload, MeterValuesPayload
47
from ocpp.v16.enums import Action
5-
from ocpp.charge_point import camel_to_snake_case, snake_to_camel_case
8+
from ocpp.v16.datatypes import MeterValue, SampledValue
9+
from ocpp.v201.call import SetNetworkProfilePayload
10+
from ocpp.v201.enums import (OCPPVersionType, OCPPTransportType,
11+
OCPPInterfaceType)
12+
from ocpp.v201.datatypes import NetworkConnectionProfileType
13+
from ocpp.charge_point import (
14+
camel_to_snake_case, snake_to_camel_case, remove_nones)
615

716

817
def test_getters_should_not_be_called_during_routemap_setup():
@@ -58,3 +67,84 @@ def test_camel_to_snake_case(test_input, expected):
5867
def test_snake_to_camel_case(test_input, expected):
5968
result = snake_to_camel_case(test_input)
6069
assert result == expected
70+
71+
72+
def test_remove_nones():
73+
expected_payload = {'charge_point_model': 'foo',
74+
'charge_point_vendor': 'bar'}
75+
76+
payload = BootNotificationPayload(
77+
charge_point_model='foo', charge_point_vendor='bar',
78+
charge_box_serial_number=None)
79+
payload = asdict(payload)
80+
81+
assert expected_payload == remove_nones(payload)
82+
83+
84+
def test_nested_remove_nones():
85+
expected_payload = {'configuration_slot': 1,
86+
'connection_data': {
87+
'ocpp_version': 'OCPP20', 'ocpp_transport': 'JSON',
88+
'ocpp_csms_url': 'wss://localhost:9000',
89+
'message_timeout': 60, 'security_profile': 1,
90+
'ocpp_interface': 'Wired0'}}
91+
92+
connection_data = NetworkConnectionProfileType(
93+
ocpp_version=OCPPVersionType.ocpp20,
94+
ocpp_transport=OCPPTransportType.json,
95+
ocpp_csms_url='wss://localhost:9000', message_timeout=60,
96+
security_profile=1, ocpp_interface=OCPPInterfaceType.wired0,
97+
vpn=None, apn=None)
98+
99+
payload = SetNetworkProfilePayload(configuration_slot=1,
100+
connection_data=connection_data)
101+
payload = asdict(payload)
102+
103+
assert expected_payload == remove_nones(payload)
104+
105+
106+
def test_nested_list_remove_nones():
107+
expected_payload = {
108+
'connector_id': 3,
109+
'meter_value': [{
110+
'timestamp': '2017-08-17T07:08:06.186748+00:00',
111+
'sampled_value': [
112+
{'value': '10', 'context': 'Sample.Periodic',
113+
'measurand': 'Power.Active.Import', 'unit': 'W'},
114+
{'value': '50000', 'context': 'Sample.Periodic',
115+
'measurand': 'Power.Active.Import', 'phase': 'L1',
116+
'unit': 'W'}]},
117+
{'timestamp': '2017-08-17T07:07:07.186748+00:00',
118+
'sampled_value': [
119+
{'value': '10', 'context': 'Sample.Periodic',
120+
'measurand': 'Power.Active.Import', 'unit': 'W'},
121+
{'value': '50000', 'context': 'Sample.Periodic',
122+
'measurand': 'Power.Active.Import', 'phase': 'L1',
123+
'unit': 'W'}]}],
124+
'transaction_id': 5}
125+
126+
payload = MeterValuesPayload(connector_id=3, meter_value=[
127+
MeterValue(timestamp='2017-08-17T07:08:06.186748+00:00',
128+
sampled_value=[
129+
SampledValue(value='10', context='Sample.Periodic',
130+
format=None,
131+
measurand='Power.Active.Import',
132+
phase=None, location=None, unit='W'),
133+
SampledValue(value='50000', context='Sample.Periodic',
134+
format=None,
135+
measurand='Power.Active.Import',
136+
phase='L1', location=None, unit='W')]),
137+
MeterValue(timestamp='2017-08-17T07:07:07.186748+00:00',
138+
sampled_value=[
139+
SampledValue(value='10', context='Sample.Periodic',
140+
format=None,
141+
measurand='Power.Active.Import',
142+
phase=None, location=None, unit='W'),
143+
SampledValue(value='50000', context='Sample.Periodic',
144+
format=None,
145+
measurand='Power.Active.Import',
146+
phase='L1', location=None, unit='W')])],
147+
transaction_id=5)
148+
149+
payload = asdict(payload)
150+
assert expected_payload == remove_nones(payload)

0 commit comments

Comments
 (0)