Skip to content

Commit

Permalink
Merging changes with master branch
Browse files Browse the repository at this point in the history
  • Loading branch information
RCX112 committed May 24, 2024
2 parents b0f14f0 + 84a4fe6 commit 49e6e6d
Show file tree
Hide file tree
Showing 19 changed files with 1,117 additions and 742 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
### v0.4.2
- update: allow duplicated name in device, check uniqueness of object_id ([#279](https://github.com/RWTH-EBC/FiLiP/pull/279))
- add: validation for JEXL based expression ([#260](https://github.com/RWTH-EBC/FiLiP/pull/260))
- add: tutorials for multi-entity ([#260](https://github.com/RWTH-EBC/FiLiP/pull/260))
- add: add ``update_entity_relationships`` to allow relationship update ([#271](https://github.com/RWTH-EBC/FiLiP/pull/271))
- add: flag to determine the deletion of registration when clearing the CB ([#267](https://github.com/RWTH-EBC/FiLiP/pull/267))
- fix: rework tutorials for pydantic v2 ([#259](https://github.com/RWTH-EBC/FiLiP/pull/259))
- fix: inconsistency of `entity_type` as required argument ([#188](https://github.com/RWTH-EBC/FiLiP/pull/188))

### v0.4.1
- fix: Session added as optional parameter to enable tls communication with clients ([#249](https://github.com/RWTH-EBC/FiLiP/pull/249))
Expand Down
45 changes: 31 additions & 14 deletions filip/clients/ngsi_v2/cb.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ def update_entity_relationships(self, entity: ContextEntity,
def delete_entity(
self,
entity_id: str,
entity_type: str,
entity_type: str= None,
delete_devices: bool = False,
iota_client: IoTAClient = None,
iota_url: AnyHttpUrl = settings.IOTA_URL,
Expand All @@ -648,7 +648,8 @@ def delete_entity(
entity_id:
Id of the entity to be deleted
entity_type:
several entities with the same entity id.
Entity type, to avoid ambiguity in case there are several
entities with the same entity id.
delete_devices:
If True, also delete all devices that reference this
entity (entity_id as entity_name)
Expand All @@ -664,8 +665,10 @@ def delete_entity(
"""
url = urljoin(self.base_url, f"v2/entities/{entity_id}")
headers = self.headers.copy()
params = {"type": entity_type}

if entity_type:
params = {'type': entity_type}
else:
params = None
try:
res = self.delete(url=url, params=params, headers=headers)
if res.ok:
Expand Down Expand Up @@ -695,10 +698,13 @@ def delete_entity(
headers=self.headers,
)

for device in iota_client_local.get_device_list(entity_names=[entity_id]):
if device.entity_type == entity_type:
for device in iota_client_local.get_device_list(
entity_names=[entity_id]):
if entity_type:
if device.entity_type == entity_type:
iota_client_local.delete_device(device_id=device.device_id)
else:
iota_client_local.delete_device(device_id=device.device_id)

iota_client_local.close()

def delete_entities(self, entities: List[ContextEntity]) -> None:
Expand Down Expand Up @@ -743,9 +749,9 @@ def delete_entities(self, entities: List[ContextEntity]) -> None:
def update_or_append_entity_attributes(
self,
entity_id: str,
entity_type: str,
attrs: List[Union[NamedContextAttribute,
Dict[str, ContextAttribute]]],
entity_type: str = None,
append_strict: bool = False,
forcedUpdate: bool = False):
"""
Expand Down Expand Up @@ -784,6 +790,9 @@ def update_or_append_entity_attributes(
params = {}
if entity_type:
params.update({'type': entity_type})
else:
entity_type = "dummy"

options = []
if append_strict:
options.append("append")
Expand Down Expand Up @@ -896,9 +905,9 @@ def update_entity_attributes_key_values(self,
def update_existing_entity_attributes(
self,
entity_id: str,
entity_type: str,
attrs: List[Union[NamedContextAttribute,
Dict[str, ContextAttribute]]],
entity_type: str = None,
forcedUpdate: bool = False,
override_metadata: bool = False
):
Expand Down Expand Up @@ -926,7 +935,11 @@ def update_existing_entity_attributes(
"""
url = urljoin(self.base_url, f"v2/entities/{entity_id}/attrs")
headers = self.headers.copy()
params = {"type": entity_type}
if entity_type:
params = {"type": entity_type}
else:
params = None
entity_type = "dummy"

entity = ContextEntity(id=entity_id, type=entity_type)
entity.add_attributes(attrs)
Expand Down Expand Up @@ -983,10 +996,10 @@ def override_entity(self,
def replace_entity_attributes(
self,
entity_id: str,
entity_type: str,
attrs: Union[List[Union[NamedContextAttribute,
Dict[str, ContextAttribute]]],
Dict],
entity_type: str = None,
forcedUpdate: bool = False,
key_values: bool = False,
):
Expand Down Expand Up @@ -1017,8 +1030,14 @@ def replace_entity_attributes(
headers = self.headers.copy()
params = {}
options = []
if entity_type:
params.update({"type": entity_type})
else:
entity_type = "dummy"

if forcedUpdate:
options.append("forcedUpdate")

if key_values:
options.append("keyValues")
assert isinstance(attrs, dict)
Expand All @@ -1031,8 +1050,6 @@ def replace_entity_attributes(
)
if options:
params.update({'options': ",".join(options)})
if entity_type:
params.update({"type": entity_type})

try:
res = self.put(
Expand Down Expand Up @@ -1890,8 +1907,8 @@ def post_command(
self,
*,
entity_id: str,
entity_type: str,
command: Union[Command, NamedCommand, Dict],
entity_type: str = None,
command_name: str = None,
) -> None:
"""
Expand Down
47 changes: 43 additions & 4 deletions filip/models/ngsi_v2/iot.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,7 @@ def validate_cbHost(cls, value):
Returns:
timezone
"""
if value is None:
return value
return str(value)
return str(value) if value else value
lazy: Optional[List[LazyDeviceAttribute]] = Field(
default=[],
desription="list of common lazy attributes of the device. For each "
Expand Down Expand Up @@ -440,6 +438,46 @@ def validate_device_attributes_expression(self):

return self

@model_validator(mode='after')
def validate_duplicated_device_attributes(self):
"""
Check whether device has identical attributes
Args:
self: dict of Device instance.
Returns:
The dict of Device instance after validation.
"""
for i, attr in enumerate(self.attributes):
for other_attr in self.attributes[:i] + self.attributes[i + 1:]:
if attr.model_dump() == other_attr.model_dump():
raise ValueError(f"Duplicated attributes found: {attr.name}")
return self

@model_validator(mode='after')
def validate_device_attributes_name_object_id(self):
"""
Validate the device regarding the behavior with devices attributes.
According to https://iotagent-node-lib.readthedocs.io/en/latest/api.html and
based on our best practice, following rules are checked
- name is required, but not necessarily unique
- object_id is not required, if given must be unique, i.e. not equal to any
existing object_id and name
Args:
self: dict of Device instance.
Returns:
The dict of Device instance after validation.
"""
for i, attr in enumerate(self.attributes):
for other_attr in self.attributes[:i] + self.attributes[i + 1:]:
if attr.object_id and other_attr.object_id and \
attr.object_id == other_attr.object_id:
raise ValueError(f"object_id {attr.object_id} is not unique")
if attr.object_id and attr.object_id == other_attr.name:
raise ValueError(f"object_id {attr.object_id} is not unique")
return self

def get_attribute(self, attribute_name: str) -> Union[DeviceAttribute,
LazyDeviceAttribute,
StaticDeviceAttribute,
Expand Down Expand Up @@ -481,7 +519,8 @@ def add_attribute(self,
"""
try:
if type(attribute) == DeviceAttribute:
if attribute in self.attributes:
if attribute.model_dump(exclude_none=True) in \
[attr.model_dump(exclude_none=True) for attr in self.attributes]:
raise ValueError

self.attributes.append(attribute)
Expand Down
78 changes: 76 additions & 2 deletions tests/clients/test_ngsi_v2_cb.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import paho.mqtt.client as mqtt
from datetime import datetime, timedelta

from urllib.parse import urlparse
import requests
from requests import RequestException
from filip.models.base import FiwareHeader
Expand Down Expand Up @@ -251,7 +251,7 @@ def test_entity_update(self):
1) append attribute
2) update existing attribute value
1) delete attribute
Returns:
"""
Expand Down Expand Up @@ -1526,6 +1526,80 @@ def test_send_receive_string(self):

self.client.delete_entity(entity_id="string_test", entity_type="test_type1")

def test_optional_entity_type(self):
"""
Test whether the entity type can be optional
"""
test_entity_id = "entity_type_test"
test_entity_type = "test1"
entity = ContextEntity(id=test_entity_id, type=test_entity_type)
entityAttr = NamedContextAttribute(name="data1", value="")
entity.add_attributes([entityAttr])
self.client.post_entity(entity=entity)

# test post_command
device_command = DeviceCommand(name='heater', type="Boolean")
device = Device(device_id='MyDevice',
entity_name='MyDevice',
entity_type='Thing',
protocol='IoTA-JSON',
transport='MQTT',
apikey=settings.FIWARE_SERVICEPATH.strip('/'),
commands=[device_command])
self.iotac.post_device(device=device)
test_command = NamedCommand(name='heater', value=True)
self.client.post_command(entity_id="MyDevice", command=test_command)

# update_or_append_entity_attributes
entityAttr.value = "value1"
attr_data2 = NamedContextAttribute(name="data2", value="value2")
self.client.update_or_append_entity_attributes(entity_id=test_entity_id,
attrs=[entityAttr,
attr_data2])

# update_existing_entity_attributes
self.client.update_existing_entity_attributes(entity_id=test_entity_id,
attrs=[entityAttr,
attr_data2])

# replace_entity_attributes
self.client.replace_entity_attributes(entity_id=test_entity_id,
attrs=[entityAttr, attr_data2])

# delete entity
self.client.delete_entity(entity_id=test_entity_id)

# another entity with the same id but different type
test_entity_id_2 = "entity_type_test"
test_entity_type_2 = "test2"
entity_2 = ContextEntity(id=test_entity_id_2, type=test_entity_type_2)
self.client.post_entity(entity=entity_2)
self.client.post_entity(entity=entity)

# update_or_append_entity_attributes
entityAttr.value = "value1"
attr_data2 = NamedContextAttribute(name="data2", value="value2")
with self.assertRaises(requests.HTTPError):
self.client.update_or_append_entity_attributes(
entity_id=test_entity_id,
attrs=[entityAttr, attr_data2])

# update_existing_entity_attributes
with self.assertRaises(requests.HTTPError):
self.client.update_existing_entity_attributes(
entity_id=test_entity_id,
attrs=[entityAttr, attr_data2])

# replace_entity_attributes
with self.assertRaises(requests.HTTPError):
self.client.replace_entity_attributes(
entity_id=test_entity_id,
attrs=[entityAttr, attr_data2])

# delete entity
with self.assertRaises(requests.HTTPError):
self.client.delete_entity(entity_id=test_entity_id)

def test_does_entity_exist(self):
_id = uuid.uuid4()

Expand Down
Loading

0 comments on commit 49e6e6d

Please sign in to comment.