Replace utils/jay_diff.py with jaydiff package from jayfield/jaypy
Remove the local copy of jay_diff and its tests/data; switch all four import sites to `jaydiff.diff.diff_full` / `jaydiff.merge.merge_full` from the shared Gitea package (http://192.168.22.90:3001/jayfield/jaypy). Add the package as a VCS dependency in requirements.txt. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,7 +17,7 @@ import json
|
|||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from utils.jay_diff import jay_merge_full
|
from jaydiff.merge import merge_full as jay_merge_full
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
|||||||
+1
-1
@@ -56,7 +56,7 @@ from server import log_config, network, we_connect
|
|||||||
from carconnectivity.errors import AuthenticationError, TemporaryAuthenticationError
|
from carconnectivity.errors import AuthenticationError, TemporaryAuthenticationError
|
||||||
from server.data_model import ALL_DOMAINS, collect_snapshot, apply_procedural
|
from server.data_model import ALL_DOMAINS, collect_snapshot, apply_procedural
|
||||||
from server.storage_helpers import auto_out_path, load_last_24h_records, load_store, save_store
|
from server.storage_helpers import auto_out_path, load_last_24h_records, load_store, save_store
|
||||||
from utils.jay_diff import jay_diff_full
|
from jaydiff.diff import diff_full as jay_diff_full
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@ from PyQt5.QtWidgets import (
|
|||||||
|
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
|
|
||||||
from utils.jay_diff import jay_merge_full
|
from jaydiff.merge import merge_full as jay_merge_full
|
||||||
|
|
||||||
pg.setConfigOption("background", "#12121e")
|
pg.setConfigOption("background", "#12121e")
|
||||||
pg.setConfigOption("foreground", "#aaaacc")
|
pg.setConfigOption("foreground", "#aaaacc")
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
carconnectivity
|
carconnectivity
|
||||||
carconnectivity-connector-volkswagen
|
carconnectivity-connector-volkswagen
|
||||||
|
jaydiff @ git+http://192.168.22.90:3001/jayfield/jaypy.git
|
||||||
PyQt5
|
PyQt5
|
||||||
pyqtgraph
|
pyqtgraph
|
||||||
pytest
|
pytest
|
||||||
+1
-1
@@ -3,7 +3,7 @@ import logging
|
|||||||
import socket
|
import socket
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from utils.jay_diff import jay_diff_full
|
from jaydiff.diff import diff_full as jay_diff_full
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,293 +0,0 @@
|
|||||||
{
|
|
||||||
"meta": {
|
|
||||||
"vin": "WVWZZZE1ZMP010760",
|
|
||||||
"created_at": "2026-05-26T11:37:05.156831+00:00",
|
|
||||||
"interval_seconds": 30
|
|
||||||
},
|
|
||||||
"records": [
|
|
||||||
{
|
|
||||||
"ts": "2026-05-26T11:37:08.127749+00:00",
|
|
||||||
"charging": {
|
|
||||||
"chargingStatus": {
|
|
||||||
"chargingState": "ChargingState.CHARGE_PURPOSE_REACHED_CONSERVATION",
|
|
||||||
"chargePower": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remainingChargingTimeToComplete": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
},
|
|
||||||
"chargeType": "ChargeType.AC"
|
|
||||||
},
|
|
||||||
"batteryStatus": {
|
|
||||||
"currentSOC": {
|
|
||||||
"value": 80,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"cruisingRangeElectric": {
|
|
||||||
"value": 280,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chargingSettings": {
|
|
||||||
"targetSOC": {
|
|
||||||
"value": 80,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maxChargeCurrentAC": "MaximumChargeCurrent.MAXIMUM",
|
|
||||||
"autoUnlockPlugWhenCharged": "UnlockPlugState.OFF"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"plugConnectionState": "PlugConnectionState.CONNECTED",
|
|
||||||
"plugLockState": "PlugLockState.LOCKED",
|
|
||||||
"externalPower": "ExternalPower.READY"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"measurements": {
|
|
||||||
"odometerStatus": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67419,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rangeStatus": {
|
|
||||||
"electricRange": {
|
|
||||||
"value": 280,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"totalRange": {
|
|
||||||
"value": 280,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureBatteryStatus": {
|
|
||||||
"temperatureHvBatteryMax": {
|
|
||||||
"value": 23.5,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperatureHvBatteryMin": {
|
|
||||||
"value": 22.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"climatisationStatus": {
|
|
||||||
"climatisationState": "ClimatizationState.OFF",
|
|
||||||
"remainingClimatisationTime": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisationSettings": {
|
|
||||||
"targetTemperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"unitInCar": "UnitInCar.CELSIUS"
|
|
||||||
},
|
|
||||||
"windowHeatingStatus": {
|
|
||||||
"front": "WindowHeatingState.OFF",
|
|
||||||
"rear": "WindowHeatingState.OFF"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"access": {
|
|
||||||
"accessStatus": {
|
|
||||||
"overallStatus": "OverallState.SAFE",
|
|
||||||
"doors": {
|
|
||||||
"bonnet": {
|
|
||||||
"lockState": "LockState.UNKNOWN",
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"trunk": {
|
|
||||||
"lockState": "LockState.LOCKED",
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"rearRight": {
|
|
||||||
"lockState": "LockState.LOCKED",
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"rearLeft": {
|
|
||||||
"lockState": "LockState.LOCKED",
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"frontRight": {
|
|
||||||
"lockState": "LockState.LOCKED",
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"frontLeft": {
|
|
||||||
"lockState": "LockState.LOCKED",
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"windows": {
|
|
||||||
"sunRoof": {
|
|
||||||
"openState": "OpenState.UNSUPPORTED"
|
|
||||||
},
|
|
||||||
"roofCover": {
|
|
||||||
"openState": "OpenState.UNSUPPORTED"
|
|
||||||
},
|
|
||||||
"sunRoofRear": {
|
|
||||||
"openState": "OpenState.UNSUPPORTED"
|
|
||||||
},
|
|
||||||
"frontLeft": {
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"frontRight": {
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"rearLeft": {
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"rearRight": {
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ts": "2026-05-26T11:37:43.660250+00:00",
|
|
||||||
"charging": {
|
|
||||||
"chargingStatus": {
|
|
||||||
"chargingState": "ChargingState.CHARGE_PURPOSE_REACHED_CONSERVATION",
|
|
||||||
"chargePower": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remainingChargingTimeToComplete": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
},
|
|
||||||
"chargeType": "ChargeType.AC"
|
|
||||||
},
|
|
||||||
"batteryStatus": {
|
|
||||||
"currentSOC": {
|
|
||||||
"value": 80,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"cruisingRangeElectric": {
|
|
||||||
"value": 280,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chargingSettings": {
|
|
||||||
"targetSOC": {
|
|
||||||
"value": 80,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maxChargeCurrentAC": "MaximumChargeCurrent.MAXIMUM",
|
|
||||||
"autoUnlockPlugWhenCharged": "UnlockPlugState.OFF"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"plugConnectionState": "PlugConnectionState.CONNECTED",
|
|
||||||
"plugLockState": "PlugLockState.LOCKED",
|
|
||||||
"externalPower": "ExternalPower.READY"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"measurements": {
|
|
||||||
"odometerStatus": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67419,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rangeStatus": {
|
|
||||||
"electricRange": {
|
|
||||||
"value": 280,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"totalRange": {
|
|
||||||
"value": 280,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureBatteryStatus": {
|
|
||||||
"temperatureHvBatteryMax": {
|
|
||||||
"value": 23.5,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperatureHvBatteryMin": {
|
|
||||||
"value": 22.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"climatisationStatus": {
|
|
||||||
"climatisationState": "ClimatizationState.OFF",
|
|
||||||
"remainingClimatisationTime": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisationSettings": {
|
|
||||||
"targetTemperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"unitInCar": "UnitInCar.CELSIUS"
|
|
||||||
},
|
|
||||||
"windowHeatingStatus": {
|
|
||||||
"front": "WindowHeatingState.OFF",
|
|
||||||
"rear": "WindowHeatingState.OFF"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"access": {
|
|
||||||
"accessStatus": {
|
|
||||||
"overallStatus": "OverallState.SAFE",
|
|
||||||
"doors": {
|
|
||||||
"bonnet": {
|
|
||||||
"lockState": "LockState.UNKNOWN",
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"trunk": {
|
|
||||||
"lockState": "LockState.LOCKED",
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"rearRight": {
|
|
||||||
"lockState": "LockState.LOCKED",
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"rearLeft": {
|
|
||||||
"lockState": "LockState.LOCKED",
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"frontRight": {
|
|
||||||
"lockState": "LockState.LOCKED",
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"frontLeft": {
|
|
||||||
"lockState": "LockState.LOCKED",
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"windows": {
|
|
||||||
"sunRoof": {
|
|
||||||
"openState": "OpenState.UNSUPPORTED"
|
|
||||||
},
|
|
||||||
"roofCover": {
|
|
||||||
"openState": "OpenState.UNSUPPORTED"
|
|
||||||
},
|
|
||||||
"sunRoofRear": {
|
|
||||||
"openState": "OpenState.UNSUPPORTED"
|
|
||||||
},
|
|
||||||
"frontLeft": {
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"frontRight": {
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"rearLeft": {
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
},
|
|
||||||
"rearRight": {
|
|
||||||
"openState": "OpenState.CLOSED"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,485 +0,0 @@
|
|||||||
{
|
|
||||||
"meta": {
|
|
||||||
"vin": "WVWZZZE1ZMP010760",
|
|
||||||
"created_at": "2026-05-27T05:53:07.953894+00:00",
|
|
||||||
"interval_seconds": 30
|
|
||||||
},
|
|
||||||
"records": [
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T05:53:08.103087+00:00",
|
|
||||||
"charging": {
|
|
||||||
"chargingStatus": {
|
|
||||||
"chargingState": "off",
|
|
||||||
"chargeType": "invalid",
|
|
||||||
"chargePower": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remainingChargingTimeToComplete": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"batteryStatus": {
|
|
||||||
"currentSOC": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"cruisingRangeElectric": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chargingSettings": {
|
|
||||||
"targetSOC": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maxChargeCurrentAC": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"autoUnlockPlugWhenCharged": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"plugConnectionState": "disconnected",
|
|
||||||
"plugLockState": "unlocked",
|
|
||||||
"externalPower": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"measurements": {
|
|
||||||
"odometerStatus": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rangeStatus": {
|
|
||||||
"electricRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"totalRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureBatteryStatus": {
|
|
||||||
"temperatureHvBatteryMax": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperatureHvBatteryMin": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureOutsideStatus": {
|
|
||||||
"temperatureOutside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"readiness": {
|
|
||||||
"readinessStatus": {
|
|
||||||
"connectionState": {
|
|
||||||
"isOnline": false,
|
|
||||||
"isActive": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"climatisationStatus": {
|
|
||||||
"climatisationState": "off",
|
|
||||||
"remainingClimatisationTime": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisationSettings": {
|
|
||||||
"targetTemperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parking": {
|
|
||||||
"parkingPosition": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"access": {
|
|
||||||
"accessStatus": {
|
|
||||||
"overallStatus": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T05:53:38.257550+00:00",
|
|
||||||
"charging": {
|
|
||||||
"chargingStatus": {
|
|
||||||
"chargingState": "off",
|
|
||||||
"chargeType": "invalid",
|
|
||||||
"chargePower": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remainingChargingTimeToComplete": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"batteryStatus": {
|
|
||||||
"currentSOC": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"cruisingRangeElectric": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chargingSettings": {
|
|
||||||
"targetSOC": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maxChargeCurrentAC": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"autoUnlockPlugWhenCharged": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"plugConnectionState": "disconnected",
|
|
||||||
"plugLockState": "unlocked",
|
|
||||||
"externalPower": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"measurements": {
|
|
||||||
"odometerStatus": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rangeStatus": {
|
|
||||||
"electricRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"totalRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureBatteryStatus": {
|
|
||||||
"temperatureHvBatteryMax": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperatureHvBatteryMin": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureOutsideStatus": {
|
|
||||||
"temperatureOutside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"readiness": {
|
|
||||||
"readinessStatus": {
|
|
||||||
"connectionState": {
|
|
||||||
"isOnline": false,
|
|
||||||
"isActive": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"climatisationStatus": {
|
|
||||||
"climatisationState": "off",
|
|
||||||
"remainingClimatisationTime": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisationSettings": {
|
|
||||||
"targetTemperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parking": {
|
|
||||||
"parkingPosition": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"access": {
|
|
||||||
"accessStatus": {
|
|
||||||
"overallStatus": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T05:54:08.438969+00:00",
|
|
||||||
"charging": {
|
|
||||||
"chargingStatus": {
|
|
||||||
"chargingState": "off",
|
|
||||||
"chargeType": "invalid",
|
|
||||||
"chargePower": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remainingChargingTimeToComplete": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"batteryStatus": {
|
|
||||||
"currentSOC": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"cruisingRangeElectric": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chargingSettings": {
|
|
||||||
"targetSOC": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maxChargeCurrentAC": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"autoUnlockPlugWhenCharged": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"plugConnectionState": "disconnected",
|
|
||||||
"plugLockState": "unlocked",
|
|
||||||
"externalPower": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"measurements": {
|
|
||||||
"odometerStatus": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rangeStatus": {
|
|
||||||
"electricRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"totalRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureBatteryStatus": {
|
|
||||||
"temperatureHvBatteryMax": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperatureHvBatteryMin": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureOutsideStatus": {
|
|
||||||
"temperatureOutside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"readiness": {
|
|
||||||
"readinessStatus": {
|
|
||||||
"connectionState": {
|
|
||||||
"isOnline": false,
|
|
||||||
"isActive": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"climatisationStatus": {
|
|
||||||
"climatisationState": "off",
|
|
||||||
"remainingClimatisationTime": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisationSettings": {
|
|
||||||
"targetTemperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parking": {
|
|
||||||
"parkingPosition": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"access": {
|
|
||||||
"accessStatus": {
|
|
||||||
"overallStatus": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T05:54:38.603661+00:00",
|
|
||||||
"charging": {
|
|
||||||
"chargingStatus": {
|
|
||||||
"chargingState": "off",
|
|
||||||
"chargeType": "invalid",
|
|
||||||
"chargePower": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remainingChargingTimeToComplete": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"batteryStatus": {
|
|
||||||
"currentSOC": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"cruisingRangeElectric": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chargingSettings": {
|
|
||||||
"targetSOC": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maxChargeCurrentAC": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"autoUnlockPlugWhenCharged": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"plugConnectionState": "disconnected",
|
|
||||||
"plugLockState": "unlocked",
|
|
||||||
"externalPower": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"measurements": {
|
|
||||||
"odometerStatus": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rangeStatus": {
|
|
||||||
"electricRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"totalRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureBatteryStatus": {
|
|
||||||
"temperatureHvBatteryMax": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperatureHvBatteryMin": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureOutsideStatus": {
|
|
||||||
"temperatureOutside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"readiness": {
|
|
||||||
"readinessStatus": {
|
|
||||||
"connectionState": {
|
|
||||||
"isOnline": false,
|
|
||||||
"isActive": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"climatisationStatus": {
|
|
||||||
"climatisationState": "off",
|
|
||||||
"remainingClimatisationTime": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisationSettings": {
|
|
||||||
"targetTemperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parking": {
|
|
||||||
"parkingPosition": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"access": {
|
|
||||||
"accessStatus": {
|
|
||||||
"overallStatus": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
{
|
|
||||||
"meta": {
|
|
||||||
"vin": "WVWZZZE1ZMP010760",
|
|
||||||
"created_at": "2026-05-27T05:55:03.027525+00:00",
|
|
||||||
"interval_seconds": 30
|
|
||||||
},
|
|
||||||
"records": [
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T05:55:03.219238+00:00",
|
|
||||||
"charging": {
|
|
||||||
"chargingStatus": {
|
|
||||||
"chargingState": "off",
|
|
||||||
"chargeType": "invalid",
|
|
||||||
"chargePower": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remainingChargingTimeToComplete": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"batteryStatus": {
|
|
||||||
"currentSOC": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"cruisingRangeElectric": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chargingSettings": {
|
|
||||||
"targetSOC": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maxChargeCurrentAC": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"autoUnlockPlugWhenCharged": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"plugConnectionState": "disconnected",
|
|
||||||
"plugLockState": "unlocked",
|
|
||||||
"externalPower": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"measurements": {
|
|
||||||
"odometerStatus": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rangeStatus": {
|
|
||||||
"electricRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"totalRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureBatteryStatus": {
|
|
||||||
"temperatureHvBatteryMax": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperatureHvBatteryMin": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureOutsideStatus": {
|
|
||||||
"temperatureOutside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"readiness": {
|
|
||||||
"readinessStatus": {
|
|
||||||
"connectionState": {
|
|
||||||
"isOnline": false,
|
|
||||||
"isActive": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"climatisationStatus": {
|
|
||||||
"climatisationState": "off",
|
|
||||||
"remainingClimatisationTime": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisationSettings": {
|
|
||||||
"targetTemperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parking": {
|
|
||||||
"parkingPosition": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"access": {
|
|
||||||
"accessStatus": {
|
|
||||||
"overallStatus": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
{
|
|
||||||
"meta": {
|
|
||||||
"vin": "WVWZZZE1ZMP010760",
|
|
||||||
"created_at": "2026-05-27T06:17:18.385566+00:00",
|
|
||||||
"interval_seconds": 30
|
|
||||||
},
|
|
||||||
"records": [
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T06:17:18.554491+00:00",
|
|
||||||
"charging": {
|
|
||||||
"chargingStatus": {
|
|
||||||
"chargingState": "off",
|
|
||||||
"chargeType": "invalid",
|
|
||||||
"chargePower": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remainingChargingTimeToComplete": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"batteryStatus": {
|
|
||||||
"currentSOC": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"cruisingRangeElectric": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chargingSettings": {
|
|
||||||
"targetSOC": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maxChargeCurrentAC": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"autoUnlockPlugWhenCharged": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"plugConnectionState": "disconnected",
|
|
||||||
"plugLockState": "unlocked",
|
|
||||||
"externalPower": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"measurements": {
|
|
||||||
"odometerStatus": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rangeStatus": {
|
|
||||||
"electricRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"totalRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureBatteryStatus": {
|
|
||||||
"temperatureHvBatteryMax": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperatureHvBatteryMin": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureOutsideStatus": {
|
|
||||||
"temperatureOutside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vehicle": {
|
|
||||||
"vehicle": {
|
|
||||||
"state": "unknown vehicle state"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"connectivity": {
|
|
||||||
"connection": {
|
|
||||||
"state": "reachable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"climatisationStatus": {
|
|
||||||
"climatisationState": "off",
|
|
||||||
"remainingClimatisationTime": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisationSettings": {
|
|
||||||
"targetTemperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"position": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"doors": {
|
|
||||||
"doors": {
|
|
||||||
"overallState": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
{
|
|
||||||
"meta": {
|
|
||||||
"vin": "WVWZZZE1ZMP010760",
|
|
||||||
"created_at": "2026-05-27T06:18:28.783719+00:00",
|
|
||||||
"interval_seconds": 30
|
|
||||||
},
|
|
||||||
"records": [
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T06:18:28.981339+00:00",
|
|
||||||
"charging": {
|
|
||||||
"chargingStatus": {
|
|
||||||
"chargingState": "off",
|
|
||||||
"chargeType": "invalid",
|
|
||||||
"chargePower": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remainingChargingTimeToComplete": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"batteryStatus": {
|
|
||||||
"currentSOC": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"cruisingRangeElectric": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chargingSettings": {
|
|
||||||
"targetSOC": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maxChargeCurrentAC": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"autoUnlockPlugWhenCharged": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"plugConnectionState": "disconnected",
|
|
||||||
"plugLockState": "unlocked",
|
|
||||||
"externalPower": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"measurements": {
|
|
||||||
"odometerStatus": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rangeStatus": {
|
|
||||||
"electricRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"totalRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureBatteryStatus": {
|
|
||||||
"temperatureHvBatteryMax": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperatureHvBatteryMin": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureOutsideStatus": {
|
|
||||||
"temperatureOutside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vehicle": {
|
|
||||||
"vehicle": {
|
|
||||||
"state": "unknown vehicle state"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"connectivity": {
|
|
||||||
"connection": {
|
|
||||||
"state": "reachable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"climatisationStatus": {
|
|
||||||
"climatisationState": "off",
|
|
||||||
"remainingClimatisationTime": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisationSettings": {
|
|
||||||
"targetTemperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"position": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"doors": {
|
|
||||||
"doors": {
|
|
||||||
"overallState": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
{
|
|
||||||
"meta": {
|
|
||||||
"vin": "WVWZZZE1ZMP010760",
|
|
||||||
"created_at": "2026-05-27T06:21:01.933728+00:00",
|
|
||||||
"interval_seconds": 30
|
|
||||||
},
|
|
||||||
"records": [
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T06:21:02.150738+00:00",
|
|
||||||
"charging": {
|
|
||||||
"chargingStatus": {
|
|
||||||
"chargingState": "off",
|
|
||||||
"chargeType": "invalid",
|
|
||||||
"chargePower": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remainingChargingTimeToComplete": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"batteryStatus": {
|
|
||||||
"currentSOC": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"cruisingRangeElectric": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chargingSettings": {
|
|
||||||
"targetSOC": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maxChargeCurrentAC": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"autoUnlockPlugWhenCharged": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"plugConnectionState": "disconnected",
|
|
||||||
"plugLockState": "unlocked",
|
|
||||||
"externalPower": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"measurements": {
|
|
||||||
"odometerStatus": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rangeStatus": {
|
|
||||||
"electricRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"totalRange": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureBatteryStatus": {
|
|
||||||
"temperatureHvBatteryMax": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperatureHvBatteryMin": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"temperatureOutsideStatus": {
|
|
||||||
"temperatureOutside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vehicle": {
|
|
||||||
"vehicle": {
|
|
||||||
"state": "unknown vehicle state"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"connectivity": {
|
|
||||||
"connection": {
|
|
||||||
"state": "reachable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"climatisationStatus": {
|
|
||||||
"climatisationState": "off",
|
|
||||||
"remainingClimatisationTime": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisationSettings": {
|
|
||||||
"targetTemperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"position": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"doors": {
|
|
||||||
"doors": {
|
|
||||||
"overallState": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
{
|
|
||||||
"meta": {
|
|
||||||
"vin": "WVWZZZE1ZMP010760",
|
|
||||||
"created_at": "2026-05-27T06:33:08.561803+00:00",
|
|
||||||
"interval_seconds": 30
|
|
||||||
},
|
|
||||||
"records": [
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T06:33:08.745827+00:00",
|
|
||||||
"charging": {
|
|
||||||
"chargingStatus": {
|
|
||||||
"chargingState": "off",
|
|
||||||
"chargeType": "invalid",
|
|
||||||
"chargePower": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remainingChargingTimeToComplete": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"batteryStatus": {
|
|
||||||
"currentSOC": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"cruisingRangeElectric": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chargingSettings": {
|
|
||||||
"targetSOC": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maxChargeCurrentAC": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"autoUnlockPlugWhenCharged": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"plugConnectionState": "disconnected",
|
|
||||||
"plugLockState": "unlocked",
|
|
||||||
"externalPower": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"electric_system": {
|
|
||||||
"electric_system": {
|
|
||||||
"range": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"range_full": {
|
|
||||||
"value": 360.3448275862069,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"battery": {
|
|
||||||
"temperature_max": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperature_min": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"odometer": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"temperature_outside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vehicle": {
|
|
||||||
"vehicle": {
|
|
||||||
"state": "unknown vehicle state"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"connectivity": {
|
|
||||||
"connectivity": {
|
|
||||||
"state": "reachable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"climatisationStatus": {
|
|
||||||
"climatisationState": "off",
|
|
||||||
"remainingClimatisationTime": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"climatisationSettings": {
|
|
||||||
"targetTemperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"position": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"doors": {
|
|
||||||
"doors": {
|
|
||||||
"overallState": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,627 +0,0 @@
|
|||||||
{
|
|
||||||
"meta": {
|
|
||||||
"vin": "WVWZZZE1ZMP010760",
|
|
||||||
"created_at": "2026-05-27T09:31:50.175248+00:00",
|
|
||||||
"interval_seconds": 30
|
|
||||||
},
|
|
||||||
"records": [
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T09:31:50.333801+00:00",
|
|
||||||
"charging": {
|
|
||||||
"state": "off",
|
|
||||||
"type": "invalid",
|
|
||||||
"power": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remain": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"target_level": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maximum_current": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"auto_unlock": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"connection_state": "disconnected",
|
|
||||||
"lock_state": "unlocked",
|
|
||||||
"external_power": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"electric_drive": {
|
|
||||||
"range": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"range_full": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"battery": {
|
|
||||||
"soc": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"temperature_max": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperature_min": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"odometer": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vehicle": {
|
|
||||||
"state": "unknown vehicle state"
|
|
||||||
},
|
|
||||||
"connectivity": {
|
|
||||||
"state": "reachable"
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"state": "off",
|
|
||||||
"remain": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"target_temperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"temperature_outside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
},
|
|
||||||
"doors": {
|
|
||||||
"doors": {
|
|
||||||
"overallState": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T09:32:20.484182+00:00",
|
|
||||||
"charging": {
|
|
||||||
"state": "off",
|
|
||||||
"type": "invalid",
|
|
||||||
"power": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remain": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"target_level": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maximum_current": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"auto_unlock": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"connection_state": "disconnected",
|
|
||||||
"lock_state": "unlocked",
|
|
||||||
"external_power": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"electric_drive": {
|
|
||||||
"range": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"range_full": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"battery": {
|
|
||||||
"soc": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"temperature_max": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperature_min": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"odometer": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vehicle": {
|
|
||||||
"state": "unknown vehicle state"
|
|
||||||
},
|
|
||||||
"connectivity": {
|
|
||||||
"state": "reachable"
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"state": "off",
|
|
||||||
"remain": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"target_temperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"temperature_outside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
},
|
|
||||||
"doors": {
|
|
||||||
"doors": {
|
|
||||||
"overallState": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T09:32:50.642394+00:00",
|
|
||||||
"charging": {
|
|
||||||
"state": "off",
|
|
||||||
"type": "invalid",
|
|
||||||
"power": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remain": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"target_level": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maximum_current": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"auto_unlock": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"connection_state": "disconnected",
|
|
||||||
"lock_state": "unlocked",
|
|
||||||
"external_power": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"electric_drive": {
|
|
||||||
"range": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"range_full": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"battery": {
|
|
||||||
"soc": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"temperature_max": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperature_min": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"odometer": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vehicle": {
|
|
||||||
"state": "unknown vehicle state"
|
|
||||||
},
|
|
||||||
"connectivity": {
|
|
||||||
"state": "reachable"
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"state": "off",
|
|
||||||
"remain": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"target_temperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"temperature_outside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
},
|
|
||||||
"doors": {
|
|
||||||
"doors": {
|
|
||||||
"overallState": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T09:33:20.808989+00:00",
|
|
||||||
"charging": {
|
|
||||||
"state": "off",
|
|
||||||
"type": "invalid",
|
|
||||||
"power": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remain": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"target_level": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maximum_current": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"auto_unlock": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"connection_state": "disconnected",
|
|
||||||
"lock_state": "unlocked",
|
|
||||||
"external_power": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"electric_drive": {
|
|
||||||
"range": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"range_full": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"battery": {
|
|
||||||
"soc": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"temperature_max": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperature_min": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"odometer": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vehicle": {
|
|
||||||
"state": "unknown vehicle state"
|
|
||||||
},
|
|
||||||
"connectivity": {
|
|
||||||
"state": "reachable"
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"state": "off",
|
|
||||||
"remain": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"target_temperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"temperature_outside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
},
|
|
||||||
"doors": {
|
|
||||||
"doors": {
|
|
||||||
"overallState": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T09:33:50.960434+00:00",
|
|
||||||
"charging": {
|
|
||||||
"state": "off",
|
|
||||||
"type": "invalid",
|
|
||||||
"power": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remain": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"target_level": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maximum_current": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"auto_unlock": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"connection_state": "disconnected",
|
|
||||||
"lock_state": "unlocked",
|
|
||||||
"external_power": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"electric_drive": {
|
|
||||||
"range": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"range_full": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"battery": {
|
|
||||||
"soc": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"temperature_max": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperature_min": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"odometer": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vehicle": {
|
|
||||||
"state": "unknown vehicle state"
|
|
||||||
},
|
|
||||||
"connectivity": {
|
|
||||||
"state": "reachable"
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"state": "off",
|
|
||||||
"remain": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"target_temperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"temperature_outside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
},
|
|
||||||
"doors": {
|
|
||||||
"doors": {
|
|
||||||
"overallState": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ts": "2026-05-27T09:34:21.107584+00:00",
|
|
||||||
"charging": {
|
|
||||||
"state": "off",
|
|
||||||
"type": "invalid",
|
|
||||||
"power": {
|
|
||||||
"value": 0.0,
|
|
||||||
"unit": "kW"
|
|
||||||
},
|
|
||||||
"remain": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"target_level": {
|
|
||||||
"value": 80.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"maximum_current": {
|
|
||||||
"value": 16.0,
|
|
||||||
"unit": "A"
|
|
||||||
},
|
|
||||||
"auto_unlock": "False"
|
|
||||||
},
|
|
||||||
"plugStatus": {
|
|
||||||
"connection_state": "disconnected",
|
|
||||||
"lock_state": "unlocked",
|
|
||||||
"external_power": "unavailable"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"electric_drive": {
|
|
||||||
"range": {
|
|
||||||
"value": 209.0,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"range_full": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
},
|
|
||||||
"battery": {
|
|
||||||
"soc": {
|
|
||||||
"value": 58.0,
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
"temperature_max": {
|
|
||||||
"value": 295.15,
|
|
||||||
"unit": "degC"
|
|
||||||
},
|
|
||||||
"temperature_min": {
|
|
||||||
"value": 294.15,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"odometer": {
|
|
||||||
"odometer": {
|
|
||||||
"value": 67489.0,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vehicle": {
|
|
||||||
"state": "unknown vehicle state"
|
|
||||||
},
|
|
||||||
"connectivity": {
|
|
||||||
"state": "reachable"
|
|
||||||
},
|
|
||||||
"climatisation": {
|
|
||||||
"state": "off",
|
|
||||||
"remain": {
|
|
||||||
"value": 0,
|
|
||||||
"unit": "min"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"target_temperature": {
|
|
||||||
"value": 21.0,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"temperature_outside": {
|
|
||||||
"value": null,
|
|
||||||
"unit": "degC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"lat": null,
|
|
||||||
"lon": null
|
|
||||||
},
|
|
||||||
"doors": {
|
|
||||||
"doors": {
|
|
||||||
"overallState": "None",
|
|
||||||
"doors": {},
|
|
||||||
"windows": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"procedural": {
|
|
||||||
"range_at_100": {
|
|
||||||
"value": 360.3,
|
|
||||||
"unit": "km"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,532 +0,0 @@
|
|||||||
"""Tests for utils/jay_diff.py."""
|
|
||||||
import pytest
|
|
||||||
from copy import deepcopy
|
|
||||||
|
|
||||||
from utils.jay_diff import (
|
|
||||||
jay_diff_add, jay_diff_del, jay_diff_upd, jay_diff_upd_add,
|
|
||||||
jay_diff_full, jay_merge_add, jay_merge_delete, jay_merge_update, jay_merge_full,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# ── jay_diff_add ──────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
class TestJayDiffAdd:
|
|
||||||
def test_add_to_empty(self):
|
|
||||||
assert jay_diff_add({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}) \
|
|
||||||
== {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
def test_no_new_keys(self):
|
|
||||||
assert jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) == {}
|
|
||||||
|
|
||||||
def test_old_has_extra_keys(self):
|
|
||||||
assert jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi', 'd': 'icecream'},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}) == {}
|
|
||||||
|
|
||||||
def test_one_new_key(self):
|
|
||||||
assert jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
||||||
{'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}) == {'d': 'icecream'}
|
|
||||||
|
|
||||||
def test_new_key_among_overlap(self):
|
|
||||||
assert jay_diff_add({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) == {'b': 'fries'}
|
|
||||||
|
|
||||||
def test_nested_new_key(self):
|
|
||||||
assert jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}},
|
|
||||||
{'c': {'f': 'coffee'}}) == {'c': {'f': 'coffee'}}
|
|
||||||
|
|
||||||
def test_nested_no_new_keys(self):
|
|
||||||
assert jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}) == {}
|
|
||||||
|
|
||||||
|
|
||||||
# ── jay_diff_del ──────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
class TestJayDiffDel:
|
|
||||||
def test_one_deleted_key(self):
|
|
||||||
assert jay_diff_del({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) == {'d': 'icecream'}
|
|
||||||
|
|
||||||
def test_no_deleted_keys_same_values(self):
|
|
||||||
assert jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': 'coke'},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) == {}
|
|
||||||
|
|
||||||
def test_no_deleted_keys_different_values(self):
|
|
||||||
assert jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': 'coke'},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}) == {}
|
|
||||||
|
|
||||||
def test_key_absent_from_new(self):
|
|
||||||
assert jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
||||||
{'a': 'hamburger', 'b': 'fries'}) == {'c': 'pepsi'}
|
|
||||||
|
|
||||||
def test_nested_deleted_key(self):
|
|
||||||
# 'c' is absent from _new → None signals "delete entire key"
|
|
||||||
assert jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hamburger', 'b': 'fries'}) == {'c': None}
|
|
||||||
|
|
||||||
def test_nested_partial_delete(self):
|
|
||||||
assert jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'c': {'e': 'coke'}}) == {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}
|
|
||||||
|
|
||||||
def test_nested_no_delete_different_value(self):
|
|
||||||
assert jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}) == {}
|
|
||||||
|
|
||||||
|
|
||||||
# ── jay_diff_upd ──────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
class TestJayDiffUpd:
|
|
||||||
def test_multiple_updates(self):
|
|
||||||
assert jay_diff_upd({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hotdog', 'b': 'potatoes'}) == {'a': 'hotdog', 'b': 'potatoes'}
|
|
||||||
|
|
||||||
def test_nested_update(self):
|
|
||||||
assert jay_diff_upd({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'c': {'e': 'pepsi'}}) == {'c': {'e': 'pepsi'}}
|
|
||||||
|
|
||||||
def test_one_update(self):
|
|
||||||
assert jay_diff_upd({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hotdog', 'b': 'fries'}) == {'a': 'hotdog'}
|
|
||||||
|
|
||||||
def test_no_update_new_key_ignored(self):
|
|
||||||
assert jay_diff_upd({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
||||||
{'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}) == {'c': 'coke'}
|
|
||||||
|
|
||||||
def test_nested_no_update_new_subkey_ignored(self):
|
|
||||||
assert jay_diff_upd({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}},
|
|
||||||
{'c': {'f': 'coffee'}}) == {}
|
|
||||||
|
|
||||||
def test_nested_update_one_of_two(self):
|
|
||||||
assert jay_diff_upd({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}) \
|
|
||||||
== {'c': {'e': 'pepsi'}}
|
|
||||||
|
|
||||||
|
|
||||||
# ── jay_diff_upd_add ──────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
class TestJayDiffUpdAdd:
|
|
||||||
def test_update_and_add(self):
|
|
||||||
assert jay_diff_upd_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hotdog', 'b': 'potatoes', 'd': 'icecream'}) \
|
|
||||||
== {'a': 'hotdog', 'b': 'potatoes', 'd': 'icecream'}
|
|
||||||
|
|
||||||
def test_nested_update_and_add(self):
|
|
||||||
assert jay_diff_upd_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}, 'b': 'potatoes'}) \
|
|
||||||
== {'b': 'potatoes', 'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}}
|
|
||||||
|
|
||||||
def test_update_only(self):
|
|
||||||
assert jay_diff_upd_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hotdog', 'b': 'fries'}) == {'a': 'hotdog'}
|
|
||||||
|
|
||||||
def test_nested_update_and_new_subkey(self):
|
|
||||||
assert jay_diff_upd_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': {'e': 'pepsi', 'f': 'coffee', 'h': 'cake'}}) \
|
|
||||||
== {'c': {'e': 'pepsi', 'h': 'cake'}}
|
|
||||||
|
|
||||||
def test_add_new_top_and_update(self):
|
|
||||||
assert jay_diff_upd_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
||||||
{'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}) \
|
|
||||||
== {'c': 'coke', 'd': 'icecream'}
|
|
||||||
|
|
||||||
def test_identical(self):
|
|
||||||
assert jay_diff_upd_add({'a': 'hamburger', 'b': 'fries'},
|
|
||||||
{'a': 'hamburger', 'b': 'fries'}) == {}
|
|
||||||
|
|
||||||
|
|
||||||
# ── jay_diff_full (combine_upd_add=False) ─────────────────────────────────────
|
|
||||||
|
|
||||||
class TestJayDiffFullSeparate:
|
|
||||||
F = False
|
|
||||||
|
|
||||||
def test_add_all(self):
|
|
||||||
assert jay_diff_full({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, self.F) \
|
|
||||||
== {'add': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}}
|
|
||||||
|
|
||||||
def test_update_one(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, self.F) \
|
|
||||||
== {'update': {'c': 'coke'}}
|
|
||||||
|
|
||||||
def test_delete_one(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi', 'd': 'icecream'},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, self.F) \
|
|
||||||
== {'delete': {'d': 'icecream'}}
|
|
||||||
|
|
||||||
def test_add_delete_update(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
||||||
{'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}, self.F) \
|
|
||||||
== {'add': {'d': 'icecream'}, 'delete': {'b': 'fries'}, 'update': {'c': 'coke'}}
|
|
||||||
|
|
||||||
def test_identical(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, self.F) == {}
|
|
||||||
|
|
||||||
def test_delete_nested(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hamburger', 'b': 'fries'}, self.F) \
|
|
||||||
== {'delete': {'c': None}}
|
|
||||||
|
|
||||||
def test_nested_partial_delete(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}, self.F) \
|
|
||||||
== {'delete': {'c': {'e': 'coke'}}}
|
|
||||||
|
|
||||||
def test_update_and_delete(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hotdog', 'b': 'potatoes'}, self.F) \
|
|
||||||
== {'delete': {'c': None}, 'update': {'a': 'hotdog', 'b': 'potatoes'}}
|
|
||||||
|
|
||||||
def test_nested_add_delete_update(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hotdog', 'b': 'potatoes', 'd': 'icecream'}, self.F) \
|
|
||||||
== {'add': {'d': 'icecream'}, 'delete': {'c': None}, 'update': {'a': 'hotdog', 'b': 'potatoes'}}
|
|
||||||
|
|
||||||
|
|
||||||
# ── jay_diff_full (combine_upd_add=True) ──────────────────────────────────────
|
|
||||||
|
|
||||||
class TestJayDiffFullCombined:
|
|
||||||
T = True
|
|
||||||
|
|
||||||
def test_add_all(self):
|
|
||||||
assert jay_diff_full({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, self.T) \
|
|
||||||
== {'update_add': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}}
|
|
||||||
|
|
||||||
def test_update_one(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, self.T) \
|
|
||||||
== {'update_add': {'c': 'coke'}}
|
|
||||||
|
|
||||||
def test_delete_one(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi', 'd': 'icecream'},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, self.T) \
|
|
||||||
== {'delete': {'d': 'icecream'}}
|
|
||||||
|
|
||||||
def test_delete_and_update_add(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
||||||
{'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}, self.T) \
|
|
||||||
== {'delete': {'b': 'fries'}, 'update_add': {'c': 'coke', 'd': 'icecream'}}
|
|
||||||
|
|
||||||
def test_identical(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, self.T) == {}
|
|
||||||
|
|
||||||
def test_delete_nested(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hamburger', 'b': 'fries'}, self.T) \
|
|
||||||
== {'delete': {'c': None}}
|
|
||||||
|
|
||||||
def test_update_and_delete_nested(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hotdog', 'b': 'potatoes'}, self.T) \
|
|
||||||
== {'delete': {'c': None}, 'update_add': {'a': 'hotdog', 'b': 'potatoes'}}
|
|
||||||
|
|
||||||
def test_nested_update_add_and_delete(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}, 'b': 'potatoes'}, self.T) \
|
|
||||||
== {'delete': {'a': 'hamburger', 'c': {'f': 'coffee'}},
|
|
||||||
'update_add': {'b': 'potatoes', 'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}}}
|
|
||||||
|
|
||||||
def test_nested_add_subkey(self):
|
|
||||||
assert jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'a': 'hamburger', 'b': 'fries', 'c': {'e': 'pepsi', 'f': 'coffee', 'h': 'cake'}}, self.T) \
|
|
||||||
== {'update_add': {'c': {'e': 'pepsi', 'h': 'cake'}}}
|
|
||||||
|
|
||||||
|
|
||||||
# ── jay_merge_* ───────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
class TestJayMerge:
|
|
||||||
def test_merge_add_to_empty(self):
|
|
||||||
assert jay_merge_add({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}) \
|
|
||||||
== {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
def test_merge_add_new_key(self):
|
|
||||||
assert jay_merge_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'d': 'icecream'}) \
|
|
||||||
== {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}, 'd': 'icecream'}
|
|
||||||
|
|
||||||
def test_merge_add_existing_unchanged(self):
|
|
||||||
assert jay_merge_add({'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}, 'd': 'icecream'},
|
|
||||||
{'d': 'icecream'}) \
|
|
||||||
== {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}, 'd': 'icecream'}
|
|
||||||
|
|
||||||
def test_merge_delete_top_key(self):
|
|
||||||
assert jay_merge_delete({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}, 'd': 'icecream'},
|
|
||||||
{'d': 'icecream'}) \
|
|
||||||
== {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
def test_merge_delete_nested_key(self):
|
|
||||||
assert jay_merge_delete({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'c': {'f': 'coffee'}}) \
|
|
||||||
== {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}
|
|
||||||
|
|
||||||
def test_merge_delete_nested_leaves_sibling(self):
|
|
||||||
assert jay_merge_delete({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'c': {'e': 'coke'}}) \
|
|
||||||
== {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}
|
|
||||||
|
|
||||||
|
|
||||||
class TestJayMergeFull:
|
|
||||||
def test_passthrough_when_old_empty(self):
|
|
||||||
assert jay_merge_full({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}) \
|
|
||||||
== {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
def test_empty_diff_unchanged(self):
|
|
||||||
assert jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {}) \
|
|
||||||
== {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}
|
|
||||||
|
|
||||||
def test_update(self):
|
|
||||||
assert jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {'update': {'c': 'pepsi'}}) \
|
|
||||||
== {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}
|
|
||||||
|
|
||||||
def test_update_add(self):
|
|
||||||
assert jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'update_add': {'c': 'coke'}}) \
|
|
||||||
== {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}
|
|
||||||
|
|
||||||
def test_delete(self):
|
|
||||||
assert jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi', 'd': 'icecream'},
|
|
||||||
{'delete': {'d': 'icecream'}}) \
|
|
||||||
== {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}
|
|
||||||
|
|
||||||
def test_add_delete_update_combined(self):
|
|
||||||
assert jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'},
|
|
||||||
{'add': {'d': 'icecream'}, 'delete': {'b': 'fries'}, 'update': {'c': 'coke'}}) \
|
|
||||||
== {'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}
|
|
||||||
|
|
||||||
def test_nested_update_and_delete(self):
|
|
||||||
assert jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}},
|
|
||||||
'update': {'c': {'e': 'pepsi'}}}) \
|
|
||||||
== {'c': {'e': 'pepsi'}}
|
|
||||||
|
|
||||||
def test_update_add_new_subkey(self):
|
|
||||||
assert jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}},
|
|
||||||
{'update_add': {'c': {'e': 'pepsi', 'h': 'cake'}}}) \
|
|
||||||
== {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'pepsi', 'f': 'coffee', 'h': 'cake'}}
|
|
||||||
|
|
||||||
def test_real_world_snapshot_update(self):
|
|
||||||
old = {'charging': {
|
|
||||||
'batteryStatus': {'value': {'carCapturedTimestamp': '2024-10-19T05:34:34Z', 'cruisingRangeElectric_km': 192}},
|
|
||||||
'chargingStatus': {'value': {'carCapturedTimestamp': '2024-10-19T05:34:34Z'}},
|
|
||||||
'chargingSettings': {'value': {'carCapturedTimestamp': '2024-10-19T05:34:30Z'}},
|
|
||||||
'plugStatus': {'value': {'carCapturedTimestamp': '2024-10-19T05:34:29Z'}}}}
|
|
||||||
update = {'charging': {
|
|
||||||
'batteryStatus': {'value': {'carCapturedTimestamp': '2024-10-19T05:35:46Z', 'cruisingRangeElectric_km': 191}},
|
|
||||||
'chargingStatus': {'value': {'carCapturedTimestamp': '2024-10-19T05:35:46Z'}}}}
|
|
||||||
add = {'charging': {'batteryStatus': {'value': {'currentSOC_pct': 55}}},
|
|
||||||
'fuelStatus': {'rangeStatus': {'value': {'primaryEngine': {'currentSOC_pct': 55}}}},
|
|
||||||
'measurements': {'fuelLevelStatus': {'value': {'currentSOC_pct': 55}}}}
|
|
||||||
delete = {'charging': {
|
|
||||||
'chargingSettings': {'value': {'carCapturedTimestamp': '2024-10-19T05:34:30Z'}},
|
|
||||||
'plugStatus': {'value': {'carCapturedTimestamp': '2024-10-19T05:34:29Z'}}}}
|
|
||||||
result = jay_merge_full(old, {'update': update, 'add': add, 'delete': delete})
|
|
||||||
assert result == old
|
|
||||||
|
|
||||||
|
|
||||||
# ── Corner cases: data types ───────────────────────────────────────────────────
|
|
||||||
|
|
||||||
class TestNumericAndScalarTypes:
|
|
||||||
def test_diff_int_value_changed(self):
|
|
||||||
assert jay_diff_upd({'a': 1, 'b': 2}, {'a': 1, 'b': 3}) == {'b': 3}
|
|
||||||
|
|
||||||
def test_diff_float_value_changed(self):
|
|
||||||
assert jay_diff_upd({'a': 1.0}, {'a': 1.1}) == {'a': 1.1}
|
|
||||||
|
|
||||||
def test_diff_int_unchanged(self):
|
|
||||||
assert jay_diff_upd({'a': 42}, {'a': 42}) == {}
|
|
||||||
|
|
||||||
def test_diff_bool_changed(self):
|
|
||||||
assert jay_diff_upd({'a': True}, {'a': False}) == {'a': False}
|
|
||||||
|
|
||||||
def test_diff_bool_false_to_true(self):
|
|
||||||
assert jay_diff_upd({'online': False}, {'online': True}) == {'online': True}
|
|
||||||
|
|
||||||
def test_diff_none_value_changed(self):
|
|
||||||
assert jay_diff_upd({'a': None}, {'a': 'something'}) == {'a': 'something'}
|
|
||||||
|
|
||||||
def test_diff_value_to_none(self):
|
|
||||||
assert jay_diff_upd({'a': 'something'}, {'a': None}) == {'a': None}
|
|
||||||
|
|
||||||
def test_diff_list_unchanged(self):
|
|
||||||
assert jay_diff_upd({'a': [1, 2, 3]}, {'a': [1, 2, 3]}) == {}
|
|
||||||
|
|
||||||
def test_diff_list_changed(self):
|
|
||||||
assert jay_diff_upd({'a': [1, 2]}, {'a': [1, 2, 3]}) == {'a': [1, 2, 3]}
|
|
||||||
|
|
||||||
def test_add_numeric_key(self):
|
|
||||||
assert jay_diff_add({'a': 1}, {'a': 1, 'b': 2}) == {'b': 2}
|
|
||||||
|
|
||||||
def test_full_combined_numeric(self):
|
|
||||||
old = {'soc': 80, 'range': 300, 'temp': 22.5}
|
|
||||||
new = {'soc': 75, 'range': 280, 'temp': 22.5}
|
|
||||||
diff = jay_diff_full(old, new)
|
|
||||||
assert diff == {'update_add': {'soc': 75, 'range': 280}}
|
|
||||||
|
|
||||||
def test_merge_numeric_update(self):
|
|
||||||
assert jay_merge_full({'soc': 80, 'range': 300}, {'update_add': {'soc': 75}}) \
|
|
||||||
== {'soc': 75, 'range': 300}
|
|
||||||
|
|
||||||
|
|
||||||
# ── Corner cases: type changes (dict ↔ scalar) ────────────────────────────────
|
|
||||||
|
|
||||||
class TestTypeChanges:
|
|
||||||
def test_dict_replaced_by_scalar_in_diff(self):
|
|
||||||
# A key that was a dict becomes a scalar — upd treats the whole value as changed
|
|
||||||
old = {'a': {'b': 'c'}}
|
|
||||||
new = {'a': 'flat'}
|
|
||||||
diff = jay_diff_upd(old, new)
|
|
||||||
assert diff == {'a': 'flat'}
|
|
||||||
|
|
||||||
def test_merge_dict_to_scalar(self):
|
|
||||||
old = {'a': {'b': 'c'}, 'x': 1}
|
|
||||||
diff = {'update_add': {'a': 'flat'}}
|
|
||||||
result = jay_merge_full(old, diff)
|
|
||||||
assert result == {'a': 'flat', 'x': 1}
|
|
||||||
|
|
||||||
def test_diff_full_dict_to_scalar_combined(self):
|
|
||||||
old = {'status': {'value': 42}}
|
|
||||||
new = {'status': 'unknown'}
|
|
||||||
diff = jay_diff_full(old, new)
|
|
||||||
result = jay_merge_full(deepcopy(old), diff)
|
|
||||||
assert result == new
|
|
||||||
|
|
||||||
def test_diff_add_new_nested_structure(self):
|
|
||||||
# Key absent in old, present as dict in new — treated as addition
|
|
||||||
old = {'a': 1}
|
|
||||||
new = {'a': 1, 'b': {'c': 2}}
|
|
||||||
diff = jay_diff_add(old, new)
|
|
||||||
assert diff == {'b': {'c': 2}}
|
|
||||||
|
|
||||||
|
|
||||||
# ── Corner cases: completely different structures ─────────────────────────────
|
|
||||||
|
|
||||||
class TestCompletelyDifferentStructure:
|
|
||||||
def test_all_keys_replaced(self):
|
|
||||||
old = {'a': 1, 'b': 2}
|
|
||||||
new = {'x': 10, 'y': 20}
|
|
||||||
diff = jay_diff_full(old, new)
|
|
||||||
assert diff == {'update_add': {'x': 10, 'y': 20}, 'delete': {'a': 1, 'b': 2}}
|
|
||||||
|
|
||||||
def test_all_keys_replaced_deep(self):
|
|
||||||
old = {'charging': {'state': 'charging', 'power': 11}}
|
|
||||||
new = {'electric_drive': {'range': 300, 'soc': 80}}
|
|
||||||
diff = jay_diff_full(old, new)
|
|
||||||
assert diff == {
|
|
||||||
'update_add': {'electric_drive': {'range': 300, 'soc': 80}},
|
|
||||||
'delete': {'charging': None},
|
|
||||||
}
|
|
||||||
|
|
||||||
def test_merge_round_trip_all_keys_replaced(self):
|
|
||||||
old = {'a': 1, 'b': 2}
|
|
||||||
new = {'x': 10, 'y': 20}
|
|
||||||
diff = jay_diff_full(old, new)
|
|
||||||
result = jay_merge_full(deepcopy(old), diff)
|
|
||||||
assert result == new
|
|
||||||
|
|
||||||
def test_diff_disjoint_no_update(self):
|
|
||||||
# No shared keys → no updates, only add/delete
|
|
||||||
old = {'a': 1}
|
|
||||||
new = {'b': 2}
|
|
||||||
diff = jay_diff_upd(old, new)
|
|
||||||
assert diff == {}
|
|
||||||
|
|
||||||
def test_diff_disjoint_add(self):
|
|
||||||
assert jay_diff_add({'a': 1}, {'b': 2}) == {'b': 2}
|
|
||||||
|
|
||||||
def test_diff_disjoint_del(self):
|
|
||||||
assert jay_diff_del({'a': 1}, {'b': 2}) == {'a': 1}
|
|
||||||
|
|
||||||
|
|
||||||
# ── Corner cases: empty containers ────────────────────────────────────────────
|
|
||||||
|
|
||||||
class TestEmptyContainers:
|
|
||||||
def test_diff_both_empty(self):
|
|
||||||
assert jay_diff_full({}, {}) == {}
|
|
||||||
|
|
||||||
def test_diff_old_empty_new_has_data(self):
|
|
||||||
diff = jay_diff_full({}, {'a': 1})
|
|
||||||
assert diff == {'update_add': {'a': 1}}
|
|
||||||
|
|
||||||
def test_diff_new_empty_old_has_data(self):
|
|
||||||
diff = jay_diff_full({'a': 1}, {})
|
|
||||||
assert diff == {'delete': {'a': 1}}
|
|
||||||
|
|
||||||
def test_merge_delete_all_keys(self):
|
|
||||||
result = jay_merge_full({'a': 1, 'b': 2}, {'delete': {'a': 1, 'b': 2}})
|
|
||||||
assert result == {}
|
|
||||||
|
|
||||||
def test_delete_empty_dict_value(self):
|
|
||||||
# Deleting a key whose value is {} — should not recurse (fixed bug)
|
|
||||||
result = jay_merge_delete({'a': 'keep', 'b': {}}, {'b': {}})
|
|
||||||
assert result == {'a': 'keep'}
|
|
||||||
|
|
||||||
def test_diff_nested_empty_dict(self):
|
|
||||||
old = {'a': {'b': 'c'}}
|
|
||||||
new = {'a': {}}
|
|
||||||
diff = jay_diff_del(old, new)
|
|
||||||
assert diff == {'a': {'b': 'c'}}
|
|
||||||
|
|
||||||
def test_empty_dict_preserved_after_delete_all_subkeys(self):
|
|
||||||
# When new has an empty dict at a location, the key must survive with {}
|
|
||||||
# (not be pruned away). This would break if merge incorrectly prunes empty dicts.
|
|
||||||
old = {'x': {'p': 1, 'q': 2}}
|
|
||||||
new = {'x': {}}
|
|
||||||
diff = jay_diff_full(old, new)
|
|
||||||
result = jay_merge_full(deepcopy(old), diff)
|
|
||||||
assert result == new # 'x' must remain as {}
|
|
||||||
|
|
||||||
|
|
||||||
# ── Corner cases: deep nesting ────────────────────────────────────────────────
|
|
||||||
|
|
||||||
class TestDeepNesting:
|
|
||||||
def test_diff_three_levels(self):
|
|
||||||
old = {'l1': {'l2': {'l3': 'old'}}}
|
|
||||||
new = {'l1': {'l2': {'l3': 'new'}}}
|
|
||||||
assert jay_diff_upd(old, new) == {'l1': {'l2': {'l3': 'new'}}}
|
|
||||||
|
|
||||||
def test_merge_three_levels(self):
|
|
||||||
old = {'l1': {'l2': {'l3': 'old', 'keep': 'yes'}}}
|
|
||||||
diff = {'update_add': {'l1': {'l2': {'l3': 'new'}}}}
|
|
||||||
result = jay_merge_full(deepcopy(old), diff)
|
|
||||||
assert result == {'l1': {'l2': {'l3': 'new', 'keep': 'yes'}}}
|
|
||||||
|
|
||||||
def test_diff_full_three_levels(self):
|
|
||||||
old = {'a': {'b': {'c': {'d': 'deep'}}}}
|
|
||||||
new = {'a': {'b': {'c': {'d': 'deeper'}}}}
|
|
||||||
diff = jay_diff_full(old, new)
|
|
||||||
result = jay_merge_full(deepcopy(old), diff)
|
|
||||||
assert result == new
|
|
||||||
|
|
||||||
|
|
||||||
# ── Round-trip: merge(old, diff(old, new)) == new ────────────────────────────
|
|
||||||
|
|
||||||
class TestRoundTrip:
|
|
||||||
"""Verify that applying a diff to old always produces new."""
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("old,new", [
|
|
||||||
({'a': 1}, {'a': 2}),
|
|
||||||
({'a': 1, 'b': 2}, {'b': 3, 'c': 4}),
|
|
||||||
({'x': {'y': 'old'}}, {'x': {'y': 'new', 'z': 'added'}}),
|
|
||||||
({'a': {'b': 1}, 'c': 2}, {'a': {'b': 1}, 'd': 3}),
|
|
||||||
({'soc': 80, 'range': 300}, {'soc': 60, 'range': 240, 'temp': 25}),
|
|
||||||
({'a': True, 'b': None}, {'a': False, 'c': 42}),
|
|
||||||
({'l1': {'l2': {'v': 1}}}, {'l1': {'l2': {'v': 2}}}),
|
|
||||||
({}, {'a': 1}),
|
|
||||||
({'a': 1}, {}),
|
|
||||||
])
|
|
||||||
def test_round_trip_combined(self, old, new):
|
|
||||||
diff = jay_diff_full(deepcopy(old), deepcopy(new), combine_upd_add=True)
|
|
||||||
result = jay_merge_full(deepcopy(old), diff)
|
|
||||||
assert result == new
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("old,new", [
|
|
||||||
({'a': 1}, {'a': 2}),
|
|
||||||
({'a': 1, 'b': 2}, {'b': 3, 'c': 4}),
|
|
||||||
({'x': {'y': 'old'}}, {'x': {'y': 'new', 'z': 'added'}}),
|
|
||||||
({}, {'a': 1}),
|
|
||||||
({'a': 1}, {}),
|
|
||||||
])
|
|
||||||
def test_round_trip_separate(self, old, new):
|
|
||||||
diff = jay_diff_full(deepcopy(old), deepcopy(new), combine_upd_add=False)
|
|
||||||
result = jay_merge_full(deepcopy(old), diff)
|
|
||||||
assert result == new
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
"""
|
|
||||||
Round-trip tests for jay_diff using real snapshot records from ./tests/data/.
|
|
||||||
|
|
||||||
For every pair of consecutive records (within a file and across adjacent files)
|
|
||||||
we verify:
|
|
||||||
jay_merge_full(a, jay_diff_full(a, b)) == b
|
|
||||||
|
|
||||||
We also verify that diffing identical records produces an empty diff, and that
|
|
||||||
applying an empty diff is a no-op.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import json
|
|
||||||
import pathlib
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from utils.jay_diff import jay_diff_full, jay_merge_full
|
|
||||||
|
|
||||||
DATA_DIR = pathlib.Path(__file__).parent / "data"
|
|
||||||
|
|
||||||
|
|
||||||
def _load_all_records() -> list[dict]:
|
|
||||||
"""Return all records from all data files, sorted by timestamp."""
|
|
||||||
records: list[dict] = []
|
|
||||||
for path in sorted(DATA_DIR.glob("*.json")):
|
|
||||||
store = json.loads(path.read_text())
|
|
||||||
records.extend(store.get("records", []))
|
|
||||||
records.sort(key=lambda r: r.get("ts", ""))
|
|
||||||
return records
|
|
||||||
|
|
||||||
|
|
||||||
ALL_RECORDS = _load_all_records()
|
|
||||||
CONSECUTIVE_PAIRS = list(zip(ALL_RECORDS, ALL_RECORDS[1:]))
|
|
||||||
|
|
||||||
|
|
||||||
class TestRealDataRoundTrip:
|
|
||||||
"""Diff+merge of every consecutive snapshot pair must reconstruct the target."""
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("pair_index", range(len(CONSECUTIVE_PAIRS)))
|
|
||||||
def test_consecutive_round_trip(self, pair_index: int) -> None:
|
|
||||||
a, b = CONSECUTIVE_PAIRS[pair_index]
|
|
||||||
diff = jay_diff_full(a, b)
|
|
||||||
result = jay_merge_full(a, diff)
|
|
||||||
assert result == b, (
|
|
||||||
f"Round-trip failed for pair #{pair_index} "
|
|
||||||
f"(ts: {a.get('ts')} → {b.get('ts')})"
|
|
||||||
)
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("pair_index", range(len(CONSECUTIVE_PAIRS)))
|
|
||||||
def test_diff_of_identical_is_empty(self, pair_index: int) -> None:
|
|
||||||
a, _ = CONSECUTIVE_PAIRS[pair_index]
|
|
||||||
assert jay_diff_full(a, a) == {}
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("pair_index", range(len(CONSECUTIVE_PAIRS)))
|
|
||||||
def test_empty_diff_is_noop(self, pair_index: int) -> None:
|
|
||||||
a, _ = CONSECUTIVE_PAIRS[pair_index]
|
|
||||||
assert jay_merge_full(a, {}) == a
|
|
||||||
|
|
||||||
|
|
||||||
class TestRealDataProperties:
|
|
||||||
"""Structural invariants on the real snapshot data."""
|
|
||||||
|
|
||||||
def test_data_dir_has_files(self) -> None:
|
|
||||||
assert len(list(DATA_DIR.glob("*.json"))) > 0, "No JSON files in tests/data/"
|
|
||||||
|
|
||||||
def test_all_records_have_timestamp(self) -> None:
|
|
||||||
for rec in ALL_RECORDS:
|
|
||||||
assert "ts" in rec, f"Record missing 'ts': {list(rec.keys())}"
|
|
||||||
|
|
||||||
def test_records_are_sorted(self) -> None:
|
|
||||||
ts_list = [r["ts"] for r in ALL_RECORDS]
|
|
||||||
assert ts_list == sorted(ts_list), "Records are not in ascending timestamp order"
|
|
||||||
|
|
||||||
def test_total_record_count(self) -> None:
|
|
||||||
assert len(ALL_RECORDS) > 100, (
|
|
||||||
f"Expected >100 records across all files, got {len(ALL_RECORDS)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_diff_size_smaller_than_full_snapshot(self) -> None:
|
|
||||||
"""Diffs between similar consecutive records should usually be smaller."""
|
|
||||||
savings = 0
|
|
||||||
for a, b in CONSECUTIVE_PAIRS:
|
|
||||||
diff = jay_diff_full(a, b)
|
|
||||||
if diff: # skip identical pairs
|
|
||||||
diff_len = len(json.dumps(diff))
|
|
||||||
full_len = len(json.dumps(b))
|
|
||||||
if diff_len < full_len:
|
|
||||||
savings += 1
|
|
||||||
ratio = savings / len(CONSECUTIVE_PAIRS) if CONSECUTIVE_PAIRS else 1.0
|
|
||||||
assert ratio > 0.5, (
|
|
||||||
f"Expected diffs to be smaller than full snapshots for >50% of pairs, "
|
|
||||||
f"got {ratio:.0%}"
|
|
||||||
)
|
|
||||||
@@ -1,590 +0,0 @@
|
|||||||
from copy import deepcopy
|
|
||||||
|
|
||||||
|
|
||||||
def jay_diff_rev(_old, _new):
|
|
||||||
delta = {}
|
|
||||||
if not isinstance(_old, dict):
|
|
||||||
return delta
|
|
||||||
for k in _new.keys():
|
|
||||||
if k in _old:
|
|
||||||
if isinstance(_new[k], dict):
|
|
||||||
res = jay_diff_rev(_old[k], _new[k])
|
|
||||||
if len(res.keys()):
|
|
||||||
delta[k] = res
|
|
||||||
else:
|
|
||||||
_old[k] = _new[k]
|
|
||||||
delta[k] = _new[k]
|
|
||||||
|
|
||||||
return delta
|
|
||||||
|
|
||||||
|
|
||||||
def jay_diff_add(_old, _new):
|
|
||||||
__old = deepcopy(_old)
|
|
||||||
delta = jay_diff_rev(__old, _new)
|
|
||||||
return delta
|
|
||||||
|
|
||||||
|
|
||||||
def jay_diff_del(_old, _new):
|
|
||||||
delta = {}
|
|
||||||
for k in _old:
|
|
||||||
if k in _new:
|
|
||||||
if isinstance(_old[k], dict) and isinstance(_new[k], dict):
|
|
||||||
sub = jay_diff_del(_old[k], _new[k])
|
|
||||||
if sub:
|
|
||||||
delta[k] = sub
|
|
||||||
else:
|
|
||||||
# key absent from _new: None signals "delete entire key" for dicts
|
|
||||||
delta[k] = None if isinstance(_old[k], dict) else _old[k]
|
|
||||||
return delta
|
|
||||||
|
|
||||||
|
|
||||||
def jay_diff_upd(_old, _new, add_if_not_exist=False):
|
|
||||||
delta = {}
|
|
||||||
for k in _new.keys():
|
|
||||||
if k in _old:
|
|
||||||
if isinstance(_new[k], dict):
|
|
||||||
res = jay_diff_upd(_old[k], _new[k], add_if_not_exist)
|
|
||||||
if len(res.keys()):
|
|
||||||
delta[k] = res
|
|
||||||
elif _new[k] != _old[k]:
|
|
||||||
delta[k] = _new[k]
|
|
||||||
elif add_if_not_exist:
|
|
||||||
delta[k] = _new[k]
|
|
||||||
|
|
||||||
return delta
|
|
||||||
|
|
||||||
|
|
||||||
def jay_diff_upd_add(_old, _new):
|
|
||||||
return jay_diff_upd(_old, _new, add_if_not_exist=True)
|
|
||||||
|
|
||||||
|
|
||||||
def jay_diff_full(_old, _new, combine_upd_add=True):
|
|
||||||
diff = {}
|
|
||||||
if combine_upd_add:
|
|
||||||
res = jay_diff_upd_add(_old, _new)
|
|
||||||
if len(res.keys()):
|
|
||||||
diff['update_add'] = res
|
|
||||||
res = jay_diff_del(_old, _new)
|
|
||||||
if len(res.keys()):
|
|
||||||
diff['delete'] = res
|
|
||||||
else:
|
|
||||||
res = jay_diff_upd(_old, _new)
|
|
||||||
if len(res.keys()):
|
|
||||||
diff['update'] = res
|
|
||||||
res = jay_diff_add(_old, _new)
|
|
||||||
if len(res.keys()):
|
|
||||||
diff['add'] = res
|
|
||||||
res = jay_diff_del(_old, _new)
|
|
||||||
if len(res.keys()):
|
|
||||||
diff['delete'] = res
|
|
||||||
|
|
||||||
return diff
|
|
||||||
|
|
||||||
|
|
||||||
def jay_merge_update(_old, _new):
|
|
||||||
for k, v in _new.items():
|
|
||||||
if isinstance(v, dict):
|
|
||||||
r = jay_merge_update(_old.get(k, {}), v)
|
|
||||||
_old[k] = r
|
|
||||||
else:
|
|
||||||
if isinstance(_old, dict):
|
|
||||||
_old[k] = _new[k]
|
|
||||||
else:
|
|
||||||
_old = _new
|
|
||||||
return _old
|
|
||||||
|
|
||||||
|
|
||||||
def jay_merge_add(_old, _new):
|
|
||||||
for k, v in _new.items():
|
|
||||||
if isinstance(v, dict):
|
|
||||||
r = jay_merge_add(_old.get(k, {}), v)
|
|
||||||
if k in _old:
|
|
||||||
_old[k].update(r)
|
|
||||||
else:
|
|
||||||
_old[k] = r
|
|
||||||
else:
|
|
||||||
_old[k] = _new[k]
|
|
||||||
return _old
|
|
||||||
|
|
||||||
|
|
||||||
def jay_merge_delete(_old, _new):
|
|
||||||
for k, v in list(_new.items()):
|
|
||||||
if isinstance(v, dict) and v:
|
|
||||||
if k in _old and isinstance(_old[k], dict):
|
|
||||||
jay_merge_delete(_old[k], v)
|
|
||||||
else:
|
|
||||||
if k in _old:
|
|
||||||
del _old[k]
|
|
||||||
return _old
|
|
||||||
|
|
||||||
|
|
||||||
def jay_merge_full(_old, _diff):
|
|
||||||
_is_diff = False
|
|
||||||
res = _old
|
|
||||||
if "update" in _diff:
|
|
||||||
res = jay_merge_update(res, _diff['update'])
|
|
||||||
_is_diff = True
|
|
||||||
if "update_add" in _diff:
|
|
||||||
res = jay_merge_update(res, _diff['update_add'])
|
|
||||||
_is_diff = True
|
|
||||||
if "add" in _diff:
|
|
||||||
res = jay_merge_add(res, _diff['add'])
|
|
||||||
_is_diff = True
|
|
||||||
if "delete" in _diff:
|
|
||||||
res = jay_merge_delete(res, _diff['delete'])
|
|
||||||
_is_diff = True
|
|
||||||
|
|
||||||
if not _is_diff and not _old:
|
|
||||||
res = _diff
|
|
||||||
|
|
||||||
return res
|
|
||||||
|
|
||||||
def _legacy_assertions() -> None:
|
|
||||||
result = jay_diff_add({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'})
|
|
||||||
assert result == {}
|
|
||||||
|
|
||||||
result = jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'})
|
|
||||||
assert result == {}
|
|
||||||
|
|
||||||
result = jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'd': 'icecream', 'c': 'coke'})
|
|
||||||
assert result == {'d':'icecream'}
|
|
||||||
|
|
||||||
result = jay_diff_add({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'})
|
|
||||||
assert result == {'b':'fries'}
|
|
||||||
|
|
||||||
result = jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}, {'c': {'f': 'coffee'}})
|
|
||||||
assert result == {'c': {'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}})
|
|
||||||
assert result == {}
|
|
||||||
|
|
||||||
result = jay_diff_del({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'})
|
|
||||||
assert result == {'d':'icecream'}
|
|
||||||
|
|
||||||
result = jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'})
|
|
||||||
assert result == {}
|
|
||||||
|
|
||||||
result = jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'})
|
|
||||||
assert result == {}
|
|
||||||
|
|
||||||
result = jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries'})
|
|
||||||
assert result == {'c':'pepsi'}
|
|
||||||
|
|
||||||
result = jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'})
|
|
||||||
assert result == {}
|
|
||||||
|
|
||||||
result = jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a': 'hamburger', 'b': 'fries'})
|
|
||||||
assert result == {'c': None}
|
|
||||||
|
|
||||||
result = jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'coke'}})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_diff_del({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}})
|
|
||||||
assert result == {}
|
|
||||||
|
|
||||||
result = jay_diff_upd({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'potatoes'})
|
|
||||||
assert result == {'a':'hotdog', 'b':'potatoes'}
|
|
||||||
|
|
||||||
result = jay_diff_upd({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'pepsi'}})
|
|
||||||
assert result == {'c': {'e': 'pepsi'}}
|
|
||||||
|
|
||||||
result = jay_diff_upd({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'fries'})
|
|
||||||
assert result == {'a':'hotdog'}
|
|
||||||
|
|
||||||
result = jay_diff_upd({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'd': 'icecream', 'c': 'coke'})
|
|
||||||
assert result == {'c':'coke'}
|
|
||||||
|
|
||||||
result = jay_diff_upd({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'})
|
|
||||||
assert result == {'c':'coke'}
|
|
||||||
|
|
||||||
result = jay_diff_upd({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}, {'c': {'f': 'coffee'}})
|
|
||||||
assert result == {}
|
|
||||||
|
|
||||||
result = jay_diff_upd({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}})
|
|
||||||
assert result == {'c': {'e': 'pepsi'}}
|
|
||||||
|
|
||||||
# Update/add
|
|
||||||
result = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'potatoes', 'd': 'icecream'})
|
|
||||||
assert result == {'a':'hotdog', 'b':'potatoes', 'd': 'icecream'}
|
|
||||||
|
|
||||||
result = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}, 'b':'potatoes'})
|
|
||||||
assert result == {'b':'potatoes', 'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}}
|
|
||||||
|
|
||||||
result = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'fries'})
|
|
||||||
assert result == {'a':'hotdog'}
|
|
||||||
|
|
||||||
result = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}})
|
|
||||||
assert result == {'c': {'e': 'pepsi'}}
|
|
||||||
|
|
||||||
#####################
|
|
||||||
result = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'potatoes'})
|
|
||||||
assert result == {'a':'hotdog', 'b':'potatoes'}
|
|
||||||
|
|
||||||
result = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'pepsi'}})
|
|
||||||
assert result == {'c': {'e': 'pepsi'}}
|
|
||||||
|
|
||||||
result = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'fries'})
|
|
||||||
assert result == {'a':'hotdog'}
|
|
||||||
|
|
||||||
result = jay_diff_upd_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'd': 'icecream', 'c': 'coke'})
|
|
||||||
assert result == {'c': 'coke', 'd': 'icecream'}
|
|
||||||
|
|
||||||
result = jay_diff_upd_add({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'})
|
|
||||||
assert result == {'b': 'fries', 'c': 'coke'}
|
|
||||||
|
|
||||||
result = jay_diff_upd_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}, {'c': {'f': 'coffee'}})
|
|
||||||
assert result == {'c': {'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}})
|
|
||||||
assert result == {'c': {'e': 'pepsi'}}
|
|
||||||
|
|
||||||
result = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee', 'h': 'cake'}})
|
|
||||||
assert result == {'c': {'e': 'pepsi', 'h': 'cake'}}
|
|
||||||
|
|
||||||
# jay_diff_full
|
|
||||||
combine_upd_add = False
|
|
||||||
|
|
||||||
result = jay_diff_full({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, combine_upd_add)
|
|
||||||
assert result == {'add': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add)
|
|
||||||
assert result == {'update': {'c': 'coke'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'d': 'icecream'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}, combine_upd_add)
|
|
||||||
assert result == {'add': {'d': 'icecream'}, 'delete': {'b': 'fries'}, 'update': {'c': 'coke'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add)
|
|
||||||
assert result == {'add': {'b': 'fries'}, 'delete': {'d': 'icecream'}, 'update': {'c': 'coke'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}, {'c': {'f': 'coffee'}}, combine_upd_add)
|
|
||||||
assert result == {'add': {'c': {'f': 'coffee'}}, 'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add)
|
|
||||||
assert result == {'add': {'b': 'fries'}, 'delete': {'d': 'icecream'}, 'update': {'c': 'coke'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add)
|
|
||||||
assert result == {}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, combine_upd_add)
|
|
||||||
assert result == {'update': {'c': 'pepsi'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'c': 'pepsi'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add)
|
|
||||||
assert result == {'update': {'c': 'coke'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a': 'hamburger', 'b': 'fries'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'c': None}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'c': {'e': 'coke'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'coke'}}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'potatoes'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'c': None}, 'update': {'a': 'hotdog', 'b': 'potatoes'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'pepsi'}}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}, 'update': {'c': {'e': 'pepsi'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'fries'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'c': None}, 'update': {'a': 'hotdog'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}, combine_upd_add)
|
|
||||||
assert result == {'update': {'c': {'e': 'pepsi'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'potatoes', 'd': 'icecream'}, combine_upd_add)
|
|
||||||
assert result == {'add': {'d': 'icecream'}, 'delete': {'c': None}, 'update': {'a': 'hotdog', 'b': 'potatoes'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}, 'b':'potatoes'}, combine_upd_add)
|
|
||||||
assert result == {'add': {'c': {'g': 'tea', 'h': 'cake'}}, 'delete': {'a': 'hamburger', 'c': {'f': 'coffee'}}, 'update': {'b': 'potatoes', 'c': {'e': 'pepsi'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'fries'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'c': None}, 'update': {'a': 'hotdog'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}, combine_upd_add)
|
|
||||||
assert result == {'update': {'c': {'e': 'pepsi'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee', 'h': 'cake'}}, combine_upd_add)
|
|
||||||
assert result == {'add': {'c': {'h': 'cake'}}, 'update': {'c': {'e': 'pepsi'}}}
|
|
||||||
|
|
||||||
# ToDo: jay_diff_full
|
|
||||||
combine_upd_add = True
|
|
||||||
|
|
||||||
result = jay_diff_full({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, combine_upd_add)
|
|
||||||
assert result == {'update_add': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add)
|
|
||||||
assert result == {'update_add': {'c': 'coke'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'d': 'icecream'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'b': 'fries'}, 'update_add': {'c': 'coke', 'd': 'icecream'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'d': 'icecream'}, 'update_add': {'b': 'fries', 'c': 'coke'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}, {'c': {'f': 'coffee'}}, combine_upd_add)
|
|
||||||
assert result == {'update_add': {'c': {'f': 'coffee'}}, 'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'d': 'icecream'}, 'update_add': {'b': 'fries', 'c': 'coke'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add)
|
|
||||||
assert result == {}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, combine_upd_add)
|
|
||||||
assert result == {'update_add': {'c': 'pepsi'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'c': 'pepsi'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add)
|
|
||||||
assert result == {'update_add': {'c': 'coke'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a': 'hamburger', 'b': 'fries'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'c': None}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'c': {'e': 'coke'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'coke'}}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'potatoes'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'c': None}, 'update_add': {'a': 'hotdog', 'b': 'potatoes'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'pepsi'}}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}, 'update_add': {'c': {'e': 'pepsi'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'fries'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'c': None}, 'update_add': {'a': 'hotdog'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}, combine_upd_add)
|
|
||||||
assert result == {'update_add': {'c': {'e': 'pepsi'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'potatoes', 'd': 'icecream'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'c': None}, 'update_add': {'a': 'hotdog', 'b': 'potatoes', 'd': 'icecream'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}, 'b':'potatoes'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'a': 'hamburger', 'c': {'f': 'coffee'}}, 'update_add': {'b': 'potatoes', 'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'fries'}, combine_upd_add)
|
|
||||||
assert result == {'delete': {'c': None}, 'update_add': {'a': 'hotdog'}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}, combine_upd_add)
|
|
||||||
assert result == {'update_add': {'c': {'e': 'pepsi'}}}
|
|
||||||
|
|
||||||
result = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee', 'h': 'cake'}}, combine_upd_add)
|
|
||||||
assert result == {'update_add': {'c': {'e': 'pepsi', 'h': 'cake'}}}
|
|
||||||
|
|
||||||
# Merge
|
|
||||||
result = jay_merge_add({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_merge_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'d': 'icecream'})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}, 'd':'icecream'}
|
|
||||||
|
|
||||||
result = jay_merge_add({'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}, {'d': 'icecream'})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'f': 'coffee'}, 'd':'icecream'}
|
|
||||||
|
|
||||||
result = jay_merge_add({'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}, 'd': 'icecream'}, {'d': 'icecream'})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'f': 'coffee'}, 'd':'icecream'}
|
|
||||||
|
|
||||||
result = jay_merge_delete({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}, 'd': 'icecream'}, {'d': 'icecream'})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_merge_delete({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'f': 'coffee'}})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'e': 'coke'}}
|
|
||||||
|
|
||||||
result = jay_merge_delete({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'coke'}})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'f': 'coffee'}}
|
|
||||||
|
|
||||||
# jay_merge_full
|
|
||||||
# the no-jaydiff case
|
|
||||||
result = jay_merge_full({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
# combine_upd_add = False
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'add': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {'update': {'c': 'pepsi'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi', 'd': 'icecream'}, {'delete': {'d': 'icecream'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'add': {'d': 'icecream'}, 'delete': {'b': 'fries'}, 'update': {'c': 'coke'}})
|
|
||||||
assert result == {'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'add': {'b': 'fries'}, 'delete': {'d': 'icecream'}, 'update': {'c': 'coke'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}, {'add': {'c': {'f': 'coffee'}}, 'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}})
|
|
||||||
assert result == {'c': {'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'add': {'b': 'fries'}, 'delete': {'d': 'icecream'}, 'update': {'c': 'coke'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {'update': {'c': 'pepsi'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'delete': {'c': 'pepsi'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'update': {'c': 'coke'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'c': None}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'c': {'e': 'coke'}}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}})
|
|
||||||
assert result == {'c': {'e': 'coke'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'c': None}, 'update': {'a': 'hotdog', 'b': 'potatoes'}})
|
|
||||||
assert result == {'a':'hotdog', 'b':'potatoes'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}, 'update': {'c': {'e': 'pepsi'}}})
|
|
||||||
assert result == {'c': {'e': 'pepsi'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'c': None}, 'update': {'a': 'hotdog'}})
|
|
||||||
assert result == {'a':'hotdog', 'b':'fries'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'update': {'c': {'e': 'pepsi'}}})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'add': {'d': 'icecream'}, 'delete': {'c': None}, 'update': {'a': 'hotdog', 'b': 'potatoes'}})
|
|
||||||
assert result == {'a':'hotdog', 'b':'potatoes', 'd': 'icecream'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'add': {'c': {'g': 'tea', 'h': 'cake'}}, 'delete': {'a': 'hamburger', 'c': {'f': 'coffee'}}, 'update': {'b': 'potatoes', 'c': {'e': 'pepsi'}}})
|
|
||||||
assert result == {'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}, 'b':'potatoes'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'c': None}, 'update': {'a': 'hotdog'}})
|
|
||||||
assert result == {'a':'hotdog', 'b':'fries'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'update': {'c': {'e': 'pepsi'}}})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'add': {'c': {'h': 'cake'}}, 'update': {'c': {'e': 'pepsi'}}})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee', 'h': 'cake'}}
|
|
||||||
|
|
||||||
# ToDo: jay_merge_full
|
|
||||||
# combine_upd_add = True
|
|
||||||
|
|
||||||
result = jay_merge_full({}, {'update_add': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'update_add': {'c': 'coke'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi', 'd': 'icecream'}, {'delete': {'d': 'icecream'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'delete': {'b': 'fries'}, 'update_add': {'c': 'coke', 'd': 'icecream'}})
|
|
||||||
assert result == {'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'delete': {'d': 'icecream'}, 'update_add': {'b': 'fries', 'c': 'coke'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}, {'update_add': {'c': {'f': 'coffee'}}, 'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}})
|
|
||||||
assert result == {'c': {'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'delete': {'d': 'icecream'}, 'update_add': {'b': 'fries', 'c': 'coke'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {'update_add': {'c': 'pepsi'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'delete': {'c': 'pepsi'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'update_add': {'c': 'coke'}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'c': None}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'c': {'e': 'coke'}}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}})
|
|
||||||
assert result == {'c': {'e': 'coke'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'c': None}, 'update_add': {'a': 'hotdog', 'b': 'potatoes'}})
|
|
||||||
assert result == {'a':'hotdog', 'b':'potatoes'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}, 'update_add': {'c': {'e': 'pepsi'}}})
|
|
||||||
assert result == {'c': {'e': 'pepsi'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'c': None}, 'update_add': {'a': 'hotdog'}})
|
|
||||||
assert result == {'a':'hotdog', 'b':'fries'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'update_add': {'c': {'e': 'pepsi'}}})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'c': None}, 'update_add': {'a': 'hotdog', 'b': 'potatoes', 'd': 'icecream'}})
|
|
||||||
assert result == {'a':'hotdog', 'b':'potatoes', 'd': 'icecream'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'a': 'hamburger', 'c': {'f': 'coffee'}}, 'update_add': {'b': 'potatoes', 'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}}})
|
|
||||||
assert result == {'b':'potatoes', 'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'delete': {'c': None}, 'update_add': {'a': 'hotdog'}})
|
|
||||||
assert result == {'a':'hotdog', 'b':'fries'}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'update_add': {'c': {'e': 'pepsi'}}})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'update_add': {'c': {'e': 'pepsi', 'h': 'cake'}}})
|
|
||||||
assert result == {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee', 'h': 'cake'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({}, {'add': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}
|
|
||||||
|
|
||||||
result = jay_merge_full({}, {'add': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': {'coffee': {'h': 'black'}}}}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': {'coffee': {'h': 'black'}}}}
|
|
||||||
|
|
||||||
result = jay_merge_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': {'coffee': {'h': 'black'}}}}, {'add': {'c': {'f': {'coffee': {'j': 'sugar'}}}}})
|
|
||||||
assert result == {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': {'coffee': {'h': 'black', 'j': 'sugar'}}}}
|
|
||||||
|
|
||||||
old = {'charging': {
|
|
||||||
'batteryStatus': {'value': {'carCapturedTimestamp': '2024-10-19T05:34:34Z', 'cruisingRangeElectric_km': 192}},
|
|
||||||
'chargingStatus': {'value': {'carCapturedTimestamp': '2024-10-19T05:34:34Z'}},
|
|
||||||
'chargingSettings': {'value': {'carCapturedTimestamp': '2024-10-19T05:34:30Z'}},
|
|
||||||
'plugStatus': {'value': {'carCapturedTimestamp': '2024-10-19T05:34:29Z'}}}}
|
|
||||||
update = {'charging': {
|
|
||||||
'batteryStatus': {'value': {'carCapturedTimestamp': '2024-10-19T05:35:46Z', 'cruisingRangeElectric_km': 191}},
|
|
||||||
'chargingStatus': {'value': {'carCapturedTimestamp': '2024-10-19T05:35:46Z'}}}}
|
|
||||||
add = {'charging': {
|
|
||||||
'batteryStatus': {'value': {'currentSOC_pct': 55}}},
|
|
||||||
'fuelStatus': {'rangeStatus': {'value': {'primaryEngine': {'currentSOC_pct': 55}}}},
|
|
||||||
'measurements': {'fuelLevelStatus': {'value': {'currentSOC_pct': 55}}}}
|
|
||||||
|
|
||||||
delete = {'charging': {
|
|
||||||
'chargingSettings': {'value': {'carCapturedTimestamp': '2024-10-19T05:34:30Z'}},
|
|
||||||
'plugStatus': {'value': {'carCapturedTimestamp': '2024-10-19T05:34:29Z'}}}}
|
|
||||||
|
|
||||||
result = jay_merge_full(old, {'update':update, 'add':add, 'delete':delete})
|
|
||||||
assert result == old
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
_legacy_assertions()
|
|
||||||
Reference in New Issue
Block a user