-
Notifications
You must be signed in to change notification settings - Fork 14
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Describe the bug
When updating an entity in FIWARE with e.g. {"temperature": 0.0} the update is not done as the attribute model dump only considers "true" values:
prop = attr.model_dump()
for key, value in prop.items():
if value and value != "Property":
jsonnn[key] = value
To Reproduce
This is a minimal example producing the unexpected behaviour. I copied the update_entity_attribute
function from the cb.py
and adapted it minimally so it would work as a standalone.
import logging
import requests
from typing import Union
from urllib.parse import urljoin
from filip.clients.ngsi_ld.cb import ContextBrokerLDClient
from filip.models.ngsi_ld.context import ContextProperty, ContextRelationship, ContextLDEntity, NamedContextRelationship, NamedContextProperty
BASE_URL =<your-url>
ENTITY_ID = f"urn:ngsi-ld:Test:test001"
ENTITY_TYPE = "Test"
ATTR_NAME = "temperature"
class MinimalFiwareService:
def __init__(self, base_url: str):
self.base_url = base_url
self._url_version = "ngsi-ld/v1"
# if needed add session
self.cb_client = ContextBrokerLDClient(url=base_url)
def post_entity(self, entity: ContextLDEntity):
self.cb_client.post_entity(entity=entity)
def get_entity_attribute(self, entity_id: str, attr_name: str) -> dict:
return self.cb_client.get_entity(entity_id=entity_id, attrs=[attr_name], options='keyValues')
def delete_entity(self, entity_id: str):
self.cb_client.delete_entity_by_id(entity_id=entity_id)
def update_entity_attribute_base(
self,
entity_id: str,
attr: Union[
ContextProperty,
ContextRelationship,
NamedContextProperty,
NamedContextRelationship,
],
attr_name: str = None,
):
headers = self.cb_client.headers.copy()
url = urljoin(
self.base_url, f"{self._url_version}/entities/{entity_id}/attrs/{attr_name}"
)
jsonnn = {}
if isinstance(attr, list) or isinstance(attr, NamedContextProperty):
jsonnn = attr.model_dump(exclude={"name"}, exclude_none=True)
else:
prop = attr.model_dump()
for key, value in prop.items():
################
#### ISSUE #####
################
# If value is 0, it will not be included in the payload ###
if value and value != "Property":
jsonnn[key] = value
try:
res = self.cb_client.patch(url=url, headers=headers, json=jsonnn)
if res.ok:
pass
else:
print(f"Response: {res.status_code}, {res.text}\n Attribute properties: {prop}")
except requests.RequestException as err:
msg = f"Could not update attribute '{attr_name}' of entity {entity_id}"
print(msg)
def update_entity_attribute_adapted(
self,
entity_id: str,
attr: Union[
ContextProperty,
ContextRelationship,
NamedContextProperty,
NamedContextRelationship,
],
attr_name: str = None,
):
headers = self.cb_client.headers.copy()
url = urljoin(
self.base_url, f"{self._url_version}/entities/{entity_id}/attrs/{attr_name}"
)
jsonnn = {}
if isinstance(attr, list) or isinstance(attr, NamedContextProperty):
jsonnn = attr.model_dump(exclude={"name"}, exclude_none=True)
else:
prop = attr.model_dump()
for key, value in prop.items():
#################
#### CHANGE #####
#################
if value is not None and value != "Property":
jsonnn[key] = value
try:
res = self.cb_client.patch(url=url, headers=headers, json=jsonnn)
if res.ok:
pass
else:
res.raise_for_status()
except requests.RequestException as err:
msg = f"Could not update attribute '{attr_name}' of entity {entity_id}.\n{err}"
print(err)
if __name__ == "__main__":
service = MinimalFiwareService(base_url=BASE_URL)
initial_attributes = {
ATTR_NAME: ContextProperty(value=99.9)
}
test_entity = ContextLDEntity(id=ENTITY_ID, type=ENTITY_TYPE, **initial_attributes)
try:
service.post_entity(test_entity)
initial_state = service.get_entity_attribute(ENTITY_ID, ATTR_NAME)
print(f"Initial State:\n{initial_state}")
print("\nATTEMPTING UPDATE WITH BASE FUNCTION")
attribute_to_update = {
ATTR_NAME: ContextProperty(value=0.0)
}
attr_name, attr_value = list(attribute_to_update.items())[0]
try:
service.update_entity_attribute_base(
entity_id=ENTITY_ID,
attr=attr_value,
attr_name=ATTR_NAME
)
except requests.RequestException as err:
print(f"The base function threw an error: {err, err.args}")
state_after_base_update = service.get_entity_attribute(ENTITY_ID, ATTR_NAME)
print(f"\nState after update (base function):\n{state_after_base_update}")
print("\nATTEMPTING UPDATE WITH ADAPTED FUNCTION")
try:
service.update_entity_attribute_adapted(
entity_id=ENTITY_ID,
attr=attr_value,
attr_name=ATTR_NAME
)
state_after_adapted_update = service.get_entity_attribute(ENTITY_ID, ATTR_NAME)
print(f"State after update (adapted function):\n{state_after_adapted_update}")
except Exception as e:
print(f"The adapted function threw an unexpected error: {e}")
finally:
print("\nCLEANUP")
service.delete_entity(entity_id=ENTITY_ID)
print(f"Test entity {ENTITY_ID} deleted.")
Expected behavior
Expected output shows, that the base function can not handle values of 0, as they equal false.
Initial State:
id='urn:ngsi-ld:Test:test001' type='Test' @context=['https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld', 'https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.8.jsonld'] temperature=99.9
ATTEMPTING UPDATE WITH BASE FUNCTION
Response: 400, {"type":"https://uri.etsi.org/ngsi-ld/errors/BadRequestData","title":"Invalid Payload Body","detail":"Empty Object"}
Attribute properties: {'type': 'Property', 'value': 0.0, 'observedAt': None, 'createdAt': None, 'modifiedAt': None, 'UnitCode': None, 'datasetId': None}
State after update (base function):
id='urn:ngsi-ld:Test:test001' type='Test' @context=['https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld', 'https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.8.jsonld'] temperature=99.9
ATTEMPTING UPDATE WITH ADAPTED FUNCTION
State after update (adapted function):
id='urn:ngsi-ld:Test:test001' type='Test' @context=['https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld', 'https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.8.jsonld'] temperature=0
CLEANUP
Test entity urn:ngsi-ld:Test:test001 deleted.
Additional context
I am not sure if this is expected behaviour or a bug. If expected, you can close the issue.
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working