Skip to content

Commit 1cc6c2c

Browse files
committed
Added sample; added changelog.
1 parent cc8ee89 commit 1cc6c2c

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
* Added client-side filtering to many of the standard API (wherever sensibly applicable); These APIs `select`
4+
and `get_all` functions now feature optional `include` and `exclude` parameters which can be used to filter
5+
the results before being wrapped into Python objects; Added multiple matchers including a JSONPath matcher
6+
and a JMESPath matcher.
37
* Added `QueueListener` and `AsyncQueueListener` classes to the Notification 2.0 toolkit. These pre-defined
48
listener implementation append new notifications to standard queues that can be monitored/listened to which
59
makes Notification 2.0 solutions even simpler to implement.

samples/client_side_filtering.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import logging
2+
3+
from c8y_api.app import SimpleCumulocityApp
4+
from c8y_api.model import Device
5+
from c8y_api.model.matcher import field
6+
from util.testing_util import load_dotenv
7+
8+
logging.basicConfig(level=logging.DEBUG)
9+
10+
"""
11+
This example demonstrates how to use the client-side-filtering feature of the
12+
Python Cumulocity API.
13+
14+
Client-side filtering is _not_ part of the standard API, it is an extension
15+
which the Python API provides which _can_ be useful in _some_ use cases. It
16+
is important to understand, that client-side-filtering is somewhat a tool of
17+
last resort - it becomes necessary if server-side filtering is not sufficient.
18+
Python being Python already provides nice standard features for filtering the
19+
query results, e.g. via list comprehension or the `filter` function. However,
20+
sometimes it may appear easier for developers to define such a filter directly
21+
with the `select` or `get_all` function, for example in interactive scenarios.
22+
23+
Client-side filters are defined for the _raw_ JSON structure. Hence, when you
24+
want to use them you must be aware of Cumulocity's JSON data format.
25+
26+
Performance: Hi there, optimization kids! To put it bluntly - using this
27+
feature does most likely _not_ increase performance in any way. This is
28+
because the actual JSON parsing will happen in any case and this is the
29+
expensive part. So - all the illustrated methods below do only marginally
30+
differ in speeed.
31+
"""
32+
33+
load_dotenv() # load environment from a .env if present
34+
c8y = SimpleCumulocityApp()
35+
print("CumulocityApp initialized.")
36+
print(f"{c8y.base_url}, Tenant: {c8y.tenant_id}, User:{c8y.username}")
37+
38+
# Let's create a couple of devices with arbitrary names
39+
d1 = Device(c8y=c8y, type="c8y_TestDevice", name="Some Test Device").create()
40+
d2 = Device(c8y=c8y, type="c8y_TestDevice", name="Device #2").create()
41+
d3 = Device(c8y=c8y, type="c8y_TestDevice", name="Another Device").create()
42+
d4 = Device(c8y=c8y, type="c8y_TestDevice", name="Machine thingy").create()
43+
44+
print("All devices of type 'c8y_TestDevice':")
45+
for d in c8y.device_inventory.select(type='c8y_TestDevice'):
46+
print(f" - {d.name}")
47+
48+
# Option 1: filtering devices by name using Python filters
49+
# The following select statement will simply list "all" devices (there are
50+
# no DB filters) and subsequently filter the results using a standard Python
51+
# list comprehension:
52+
filtered_devices = [x for x in c8y.device_inventory.select(type='c8y_TestDevice') if 'Device' in x.name]
53+
# -> We will only have devices which are named "Device something"
54+
print("Option #1 result (needs to contain 'Device' string)")
55+
for d in filtered_devices:
56+
print(f" - {d.name}")
57+
58+
# Option 2: using the client-side filtering with JMESPath filters
59+
# The following statement will simply list "all" devices (there are no DB
60+
# filters) and subsequently filter the results using a JMESPath expression.
61+
# The JMESPath is matched against the unprocessed JSON, hence it is required
62+
# to understand Cumulocity's native JSON formats (but they are close to how
63+
# the Python API resembles it:
64+
filtered_devices_2 = c8y.device_inventory.get_all(type='c8y_TestDevice', include="contains(name, 'Device')")
65+
# -> We will only have devices which are named "Device something"
66+
print("Option #2 result (same thing):")
67+
for d in filtered_devices_2:
68+
print(f" - {d.name}")
69+
70+
# Option 3: the client-side filtering with Python filters
71+
# The following statement will simply list "all" devices (there are no DB
72+
# filters) and subsequently filter the results using Python matchers. There
73+
# is quite a list of predefined matchers (see c8y_api.model.matchers) and
74+
# custom ones are easy to define.
75+
filtered_devices_3 = c8y.device_inventory.get_all(
76+
type='c8y_TestDevice',
77+
include=field('name', '*Device*'),
78+
exclude=field('name', '*#*'))
79+
# -> We will only have devices which are named "Device something" but
80+
# without '#' anywhere in the name
81+
print("Option #3 result (Same, but no #)")
82+
for d in filtered_devices_3:
83+
print(f" - {d.name}")
84+
85+
86+
# cleanup
87+
d1.delete()
88+
d2.delete()
89+
d3.delete()
90+
d4.delete()

0 commit comments

Comments
 (0)