Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add forcedUpdate and missing overrideMetadata #236

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- add function to override the existing entity ([#232 ](https://github.com/RWTH-EBC/FiLiP/pull/232 ))
- fix: remove root slash from paths ([#251](https://github.com/RWTH-EBC/FiLiP/issues/251))
- fix: include headers in some requests ([#250](https://github.com/RWTH-EBC/FiLiP/issues/250))
- add: `forcedUpdate` and missing `overrideMetadata` in request parameters ([#236](https://github.com/RWTH-EBC/FiLiP/pull/236))
- feat: make context-entity more customizable ([#225](https://github.com/RWTH-EBC/FiLiP/issues/225))
- feat: add geojson support to context-entity ([#226](https://github.com/RWTH-EBC/FiLiP/issues/226))

Expand Down
153 changes: 113 additions & 40 deletions filip/clients/ngsi_v2/cb.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,12 +662,13 @@ def delete_entities(self, entities: List[ContextEntity]) -> None:
self.update(entities=entities_with_attributes, action_type="delete")

def update_or_append_entity_attributes(
self,
entity_id: str,
entity_type: str,
attrs: List[Union[NamedContextAttribute, Dict[str, ContextAttribute]]],
append_strict: bool = False,
):
self,
entity_id: str,
entity_type: str,
attrs: List[Union[NamedContextAttribute,
Dict[str, ContextAttribute]]],
append_strict: bool = False,
forcedUpdate: bool = False):
"""
The request payload is an object representing the attributes to
append or update. This corresponds to a 'POST' request if append is
Expand All @@ -691,7 +692,10 @@ def update_or_append_entity_attributes(
to that, in case some of the attributes in the payload
already exist in the entity, an error is returned.
More precisely this means a strict append procedure.

forcedUpdate: Update operation have to trigger any matching
subscription, no matter if there is an actual attribute
update or no instead of the default behavior, which is to
updated only if attribute is effectively updated.
Returns:
None

Expand All @@ -700,9 +704,14 @@ def update_or_append_entity_attributes(
headers = self.headers.copy()
params = {}
if entity_type:
params.update({"type": entity_type})
params.update({'type': entity_type})
options = []
if append_strict:
params.update({"options": "append"})
options.append("append")
if forcedUpdate:
options.append("forcedUpdate")
if options:
params.update({'options': ",".join(options)})

entity = ContextEntity(id=entity_id, type=entity_type)
entity.add_attributes(attrs)
Expand Down Expand Up @@ -806,10 +815,13 @@ def update_entity_attributes_key_value(self,
self.update_entity_key_value(entity=entity)

def update_existing_entity_attributes(
self,
entity_id: str,
entity_type: str,
attrs: List[Union[NamedContextAttribute, Dict[str, ContextAttribute]]],
self,
entity_id: str,
entity_type: str,
attrs: List[Union[NamedContextAttribute,
Dict[str, ContextAttribute]]],
forcedUpdate: bool = False,
override_metadata: bool = False
):
"""
The entity attributes are updated with the ones in the payload.
Expand All @@ -822,7 +834,13 @@ def update_existing_entity_attributes(
entity_type: Entity type, to avoid ambiguity in case there are
several entities with the same entity id.
attrs: List of attributes to update or to append

forcedUpdate: Update operation have to trigger any matching
subscription, no matter if there is an actual attribute
update or no instead of the default behavior, which is to
updated only if attribute is effectively updated.
override_metadata:
Bool,replace the existing metadata with the one provided in
the request
Returns:
None

Expand All @@ -834,6 +852,14 @@ def update_existing_entity_attributes(
entity = ContextEntity(id=entity_id, type=entity_type)
entity.add_attributes(attrs)

options = []
if override_metadata:
options.append("overrideMetadata")
if forcedUpdate:
options.append("forcedUpdate")
if options:
params.update({'options': ",".join(options)})

try:
res = self.patch(
url=url,
Expand Down Expand Up @@ -871,10 +897,12 @@ def override_entity(self, entity: ContextEntity):
attrs=entity.get_properties())

def replace_entity_attributes(
self,
entity_id: str,
entity_type: str,
attrs: List[Union[NamedContextAttribute, Dict[str, ContextAttribute]]],
self,
entity_id: str,
entity_type: str,
attrs: List[Union[NamedContextAttribute,
Dict[str, ContextAttribute]]],
forcedUpdate: bool = False
):
"""
The attributes previously existing in the entity are removed and
Expand All @@ -886,12 +914,21 @@ def replace_entity_attributes(
entity_type: Entity type, to avoid ambiguity in case there are
several entities with the same entity id.
attrs: List of attributes to add to the entity
forcedUpdate: Update operation have to trigger any matching
subscription, no matter if there is an actual attribute
update or no instead of the default behavior, which is to
updated only if attribute is effectively updated.
Returns:
None
"""
url = urljoin(self.base_url, f"v2/entities/{entity_id}/attrs")
headers = self.headers.copy()
params = {}
options = []
if forcedUpdate:
options.append("forcedUpdate")
if options:
params.update({'options': ",".join(options)})
if entity_type:
params.update({"type": entity_type})

Expand Down Expand Up @@ -964,15 +1001,15 @@ def get_attribute(
self.log_error(err=err, msg=msg)
raise

def update_entity_attribute(
self,
entity_id: str,
attr: Union[ContextAttribute, NamedContextAttribute],
*,
entity_type: str = None,
attr_name: str = None,
override_metadata: bool = True,
):
def update_entity_attribute(self,
entity_id: str,
attr: Union[ContextAttribute,
NamedContextAttribute],
*,
entity_type: str = None,
attr_name: str = None,
override_metadata: bool = True,
forcedUpdate: bool = False):
"""
Updates a specified attribute from an entity.

Expand All @@ -984,6 +1021,10 @@ def update_entity_attribute(
entity_type:
Entity type, to avoid ambiguity in case there are
several entities with the same entity id.
forcedUpdate: Update operation have to trigger any matching
subscription, no matter if there is an actual attribute
update or no instead of the default behavior, which is to
updated only if attribute is effectively updated.
attr_name:
Name of the attribute to be updated.
override_metadata:
Expand Down Expand Up @@ -1014,8 +1055,13 @@ def update_entity_attribute(
if entity_type:
params.update({"type": entity_type})
# set overrideMetadata option (we assure backwards compatibility here)
options = []
if override_metadata:
params.update({"options": "overrideMetadata"})
options.append("overrideMetadata")
if forcedUpdate:
options.append("forcedUpdate")
if options:
params.update({'options': ",".join(options)})
try:
res = self.put(
url=url,
Expand Down Expand Up @@ -1115,9 +1161,13 @@ def get_attribute_value(
self.log_error(err=err, msg=msg)
raise

def update_attribute_value(
self, *, entity_id: str, attr_name: str, value: Any, entity_type: str = None
):
def update_attribute_value(self, *,
entity_id: str,
attr_name: str,
value: Any,
entity_type: str = None,
forcedUpdate: bool = False
):
"""
Updates the value of a specified attribute of an entity

Expand All @@ -1128,14 +1178,23 @@ def update_attribute_value(
Example: temperature.
entity_type: Entity type, to avoid ambiguity in case there are
several entities with the same entity id.
forcedUpdate: Update operation have to trigger any matching
subscription, no matter if there is an actual attribute
update or no instead of the default behavior, which is to
updated only if attribute is effectively updated.
Returns:

"""
url = urljoin(self.base_url, f"v2/entities/{entity_id}/attrs/{attr_name}/value")
headers = self.headers.copy()
params = {}
if entity_type:
params.update({"type": entity_type})
params.update({'type': entity_type})
options = []
if forcedUpdate:
options.append("forcedUpdate")
if options:
params.update({'options': ",".join(options)})
try:
if not isinstance(value, (dict, list)):
headers.update({"Content-Type": "text/plain"})
Expand Down Expand Up @@ -1558,13 +1617,14 @@ def delete_registration(self, registration_id: str) -> None:
raise

# Batch operation API
def update(
self,
*,
entities: List[ContextEntity],
action_type: Union[ActionType, str],
update_format: str = None,
) -> None:
def update(self,
*,
entities: List[ContextEntity],
action_type: Union[ActionType, str],
update_format: str = None,
forcedUpdate: bool = False,
override_metadata: bool = False,
) -> None:
"""
This operation allows to create, update and/or delete several entities
in a single batch operation.
Expand Down Expand Up @@ -1596,7 +1656,13 @@ def update(
action to do: either append, appendStrict, update, delete,
or replace. "
update_format (str): Optional 'keyValues'

forcedUpdate: Update operation have to trigger any matching
subscription, no matter if there is an actual attribute
update or no instead of the default behavior, which is to
updated only if attribute is effectively updated.
override_metadata:
Bool, replace the existing metadata with the one provided in
the request
Returns:

"""
Expand All @@ -1605,6 +1671,13 @@ def update(
headers = self.headers.copy()
headers.update({"Content-Type": "application/json"})
params = {}
options = []
if override_metadata:
options.append("overrideMetadata")
if forcedUpdate:
options.append("forcedUpdate")
if options:
params.update({'options': ",".join(options)})
if update_format:
assert (
update_format == "keyValues"
Expand Down
Loading