Skip to content
This repository was archived by the owner on Nov 14, 2025. It is now read-only.

Commit 0d989b0

Browse files
committed
Fixed issue #7. Refactored console printing
1 parent 515607c commit 0d989b0

7 files changed

Lines changed: 116 additions & 37 deletions

File tree

docs/source/generated/ngsildclient.utils.console.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
ngsildclient.utils.console
1+
ngsildclient.utils.console
22
==========================
33

44
.. automodule:: ngsildclient.utils.console
@@ -9,6 +9,14 @@ ngsildclient.utils.console
99

1010

1111

12+
.. rubric:: Functions
13+
14+
.. autosummary::
15+
16+
compute
17+
compute4
18+
example
19+
1220

1321

1422

src/ngsildclient/api/asyn/batch.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ def __init__(self, client: AsyncClient, url: str):
3737

3838
@rfc7807_error_handle_async
3939
async def _create(self, entities: Sequence[Entity]) -> BatchResult:
40-
r = await self._session.post(f"{self.url}/create/", content=json.dumps([e for e in entities], cls=NgsiEncoder))
40+
headers = {"Content-Type": "application/ld+json"}
41+
r = await self._session.post(
42+
f"{self.url}/create/", headers=headers, content=json.dumps([e for e in entities], cls=NgsiEncoder)
43+
)
4144
self._client.raise_for_status(r)
4245
if r.status_code == 201:
4346
success, errors = r.json(), []
@@ -57,9 +60,13 @@ async def create(self, entities: Sequence[Entity], batchsize: int = BATCHSIZE) -
5760

5861
@rfc7807_error_handle_async
5962
async def _upsert(self, entities: Sequence[Entity], opt: Literal["replace", "update"] = "replace") -> BatchResult:
63+
headers = {"Content-Type": "application/ld+json"}
6064
params = {"options": opt} if opt else {}
6165
r = await self._session.post(
62-
f"{self.url}/upsert/", content=json.dumps([e for e in entities], cls=NgsiEncoder), params=params
66+
f"{self.url}/upsert/",
67+
content=json.dumps([e for e in entities], cls=NgsiEncoder),
68+
headers=headers,
69+
params=params,
6370
)
6471
self._client.raise_for_status(r)
6572
if r.status_code == 201:
@@ -86,9 +93,13 @@ async def upsert(
8693

8794
@rfc7807_error_handle_async
8895
async def _update(self, entities: Sequence[Entity], opt: Literal["noOverwrite"] = None) -> BatchResult:
96+
headers = {"Content-Type": "application/ld+json"}
8997
params = {"options": opt} if opt else {}
9098
r = await self._session.post(
91-
f"{self.url}/update/", content=json.dumps([e for e in entities], cls=NgsiEncoder), params=params
99+
f"{self.url}/update/",
100+
content=json.dumps([e for e in entities], cls=NgsiEncoder),
101+
headers=headers,
102+
params=params,
92103
)
93104
self._client.raise_for_status(r)
94105
if r.status_code == 204:

src/ngsildclient/api/asyn/client.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,6 @@ def __init__(
141141
headers = {
142142
"User-Agent": self.useragent,
143143
"Accept": "application/ld+json",
144-
# "Content-Type": "application/ld+json",
145144
}
146145
if tenant is not None:
147146
headers["NGSILD-Tenant"] = tenant

src/ngsildclient/api/batch.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ def raise_for_status(self):
7474
if not self.ok:
7575
raise NgsiApiError(f"Error while processing batch {self.op} operation", self)
7676

77+
def __repr__(self):
78+
return f"op: {self.op}, success: {self.n_ok}, errors: {self.n_err}"
79+
7780
def __iadd__(self, r: BatchResult):
7881
self.success.extend(r.success)
7982
self.errors.extend(r.errors)

src/ngsildclient/api/client.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
from .follow import LinkFollower
3939
from .exceptions import *
4040
from ngsildclient.settings import globalsettings
41+
from ngsildclient.utils.console import Console, MsgLvl
4142

4243
logger = logging.getLogger(__name__)
4344

@@ -98,6 +99,7 @@ def __init__(
9899
ignore_errors: bool = False,
99100
proxy: str = None,
100101
custom_auth: AuthBase = None,
102+
verbose: bool = True,
101103
):
102104
"""Create a Client instance to interact with the Context Broker.
103105
@@ -160,7 +162,8 @@ def __init__(
160162
if proxy:
161163
self.session.proxies = {proxy}
162164

163-
logger.info("Connecting client ...")
165+
self.verbose = verbose
166+
self.console = Console(verbose)
164167

165168
self._entities = Entities(self, f"{self.url}/{ENDPOINT_ENTITIES}", f"{self.url}/{ENDPOINT_ALT_QUERY_ENTITIES}")
166169
self._batch = Batch(self, f"{self.url}/{ENDPOINT_BATCH}")
@@ -185,11 +188,9 @@ def __init__(
185188
status = self.is_connected(raise_for_disconnected=True)
186189
if status:
187190
self.broker = Broker(*self.guess_vendor())
188-
if is_interactive():
189-
print(self._welcome_message())
191+
self.console.print(self._welcome_message())
190192
else:
191-
if is_interactive():
192-
print(self._fail_message())
193+
self.console.print(self._fail_message())
193194

194195
def raise_for_status(self, r: Response):
195196
"""Raises an exception depending on the API response.
@@ -784,18 +785,17 @@ def _broker_version_java_spring(self) -> Optional[Tuple[Vendor, str]]:
784785
return None
785786
return vendor, version
786787
except Exception:
787-
if is_interactive():
788-
print("Java-Spring based Context Broker detected. Try to enable info endpoint.")
788+
self.console.print("Java-Spring based Context Broker detected. [orange]Try to enable info endpoint.")
789789
return None
790790

791791
def _welcome_message(self) -> str:
792-
return f"Connected to Context Broker at {self.hostname}:{self.port} | vendor={self.broker.vendor.value} | version={self.broker.version}"
792+
return f"[green]Connected[/] to Context Broker at [blue]{self.hostname}:{self.port}[/] | vendor=[blue]{self.broker.vendor.value}[/] | version=[blue]{self.broker.version}[/]"
793793

794794
def _fail_message(self) -> str:
795-
return f"Failed to connect to Context Broker at {self.hostname}:{self.port}"
795+
return f"[red]Failed[/] to connect to Context Broker at {self.hostname}:{self.port}"
796796

797797
def _warn_spring_message(self) -> str:
798-
return "Java-Spring based Context Broker detected. Info endpoint disabled."
798+
return "Java-Spring based Context Broker detected. [orange]Info endpoint disabled."
799799

800800
def _create_network(self, root: Entity, G: nx.Graph, nodecache: dict, edgecache: Set):
801801
source: Tuple = Urn.split(root.id)

src/ngsildclient/utils/console.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
#
1010
# Author: Fabien BATTELLO <fabien.battello@orange.com> et al.
1111

12+
import re
1213
import rich.console as console
1314
from rich.text import Text
14-
from typing import Literal
15+
from typing import Literal, Generator
1516

1617
from ngsildclient.utils import is_interactive
1718

@@ -21,16 +22,20 @@
2122
"""
2223

2324
MsgLvl = Literal["info", "success", "warning", "error"]
24-
2525
MAP_LEVEL_COLOR = {"info": None, "success": "green", "warning": "orange3", "error": "red3"}
26+
PATTERN_RICHSTYLE = re.compile(r"\[[^\]]+\]")
2627

2728

2829
class Console:
29-
def __init__(self):
30+
def __init__(self, verbose=True):
3031
self.console = console.Console() if is_interactive() else None
32+
self.verbose = verbose
3133

3234
def message(self, msg: str, *, color: str = None, level: MsgLvl = "info"):
33-
if self.console is None:
35+
if not self.verbose:
36+
return
37+
if not self.console:
38+
print(msg)
3439
return
3540
text = Text(msg)
3641
if level:
@@ -47,3 +52,11 @@ def warn(self):
4752

4853
def error(self):
4954
self.message(color="red")
55+
56+
def print(self, msg: str):
57+
if not self.verbose:
58+
return
59+
if not self.console:
60+
print(re.sub(PATTERN_RICHSTYLE, "", msg))
61+
return
62+
self.console.print(msg)

tests/test_batch.py

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,33 @@ def test_api_batch_single_create_ok(mocked_connected, requests_mock: Mocker):
4444
assert r.n_err == 0
4545
assert r.ratio == 1.0
4646

47+
4748
def test_api_batch_single_create_nok(mocked_connected, requests_mock: Mocker):
4849
requests_mock.post(
4950
"http://localhost:1026/ngsi-ld/v1/entityOperations/create/",
5051
request_headers={"Content-Type": "application/ld+json"},
5152
status_code=207,
52-
json={"success": [],
53+
json={
54+
"success": [],
5355
"errors": [
54-
{"entityId": "urn:ngsi-ld:RoomObserved:Room1", "error": {"type": "https://uri.etsi.org/ngsi-ld/errors/BadRequestData", "title": "entity already exists", "status": 400}},
55-
{'entityId': 'urn:ngsi-ld:RoomObserved:Room2', 'error': {'type': 'https://uri.etsi.org/ngsi-ld/errors/BadRequestData', 'title': 'entity already exists', 'status': 400}}
56-
]
57-
}
56+
{
57+
"entityId": "urn:ngsi-ld:RoomObserved:Room1",
58+
"error": {
59+
"type": "https://uri.etsi.org/ngsi-ld/errors/BadRequestData",
60+
"title": "entity already exists",
61+
"status": 400,
62+
},
63+
},
64+
{
65+
"entityId": "urn:ngsi-ld:RoomObserved:Room2",
66+
"error": {
67+
"type": "https://uri.etsi.org/ngsi-ld/errors/BadRequestData",
68+
"title": "entity already exists",
69+
"status": 400,
70+
},
71+
},
72+
],
73+
},
5874
)
5975
client = Client()
6076
room1 = Entity("RoomObserved", "Room1").prop("temperature", 21.7)
@@ -66,20 +82,45 @@ def test_api_batch_single_create_nok(mocked_connected, requests_mock: Mocker):
6682
assert r.n_err == 2
6783
assert r.ratio == 0.0
6884
assert r.errors == [
69-
{"entityId": "urn:ngsi-ld:RoomObserved:Room1", "error": {"type": "https://uri.etsi.org/ngsi-ld/errors/BadRequestData", "title": "entity already exists", "status": 400}},
70-
{'entityId': 'urn:ngsi-ld:RoomObserved:Room2', 'error': {'type': 'https://uri.etsi.org/ngsi-ld/errors/BadRequestData', 'title': 'entity already exists', 'status': 400}}
85+
{
86+
"entityId": "urn:ngsi-ld:RoomObserved:Room1",
87+
"error": {
88+
"type": "https://uri.etsi.org/ngsi-ld/errors/BadRequestData",
89+
"title": "entity already exists",
90+
"status": 400,
91+
},
92+
},
93+
{
94+
"entityId": "urn:ngsi-ld:RoomObserved:Room2",
95+
"error": {
96+
"type": "https://uri.etsi.org/ngsi-ld/errors/BadRequestData",
97+
"title": "entity already exists",
98+
"status": 400,
99+
},
100+
},
71101
]
72102

103+
73104
def test_api_batch_create_multi_ok(mocked_connected, requests_mock: Mocker):
74-
requests_mock.register_uri("POST", "http://localhost:1026/ngsi-ld/v1/entityOperations/create/",
75-
[{"status_code": 201, "json":[
76-
"urn:ngsi-ld:AirQualityObserved:RZ:Obsv4567",
77-
"urn:ngsi-ld:AirQualityObserved:RZ:Obsv4568",
78-
]},
79-
{"status_code": 201, "json":[
80-
"urn:ngsi-ld:AirQualityObserved:RZ:Obsv4569",
81-
]}
82-
])
105+
requests_mock.register_uri(
106+
"POST",
107+
"http://localhost:1026/ngsi-ld/v1/entityOperations/create/",
108+
[
109+
{
110+
"status_code": 201,
111+
"json": [
112+
"urn:ngsi-ld:AirQualityObserved:RZ:Obsv4567",
113+
"urn:ngsi-ld:AirQualityObserved:RZ:Obsv4568",
114+
],
115+
},
116+
{
117+
"status_code": 201,
118+
"json": [
119+
"urn:ngsi-ld:AirQualityObserved:RZ:Obsv4569",
120+
],
121+
},
122+
],
123+
)
83124
client = Client()
84125
sample2 = sample_entity.dup()
85126
sample3 = sample_entity.dup()
@@ -93,6 +134,7 @@ def test_api_batch_create_multi_ok(mocked_connected, requests_mock: Mocker):
93134
assert r.ratio == 1.0
94135
assert r.errors == []
95136

137+
96138
def test_api_batch_upsert_ok_201(mocked_connected, requests_mock):
97139
requests_mock.post(
98140
"http://localhost:1026/ngsi-ld/v1/entityOperations/upsert/",
@@ -122,11 +164,12 @@ def test_api_batch_upsert_ok_201(mocked_connected, requests_mock):
122164
"urn:ngsi-ld:AirQualityObserved:RZ:Obsv4569",
123165
]
124166

167+
125168
def test_api_batch_upsert_ok_204(mocked_connected, requests_mock):
126169
requests_mock.post(
127170
"http://localhost:1026/ngsi-ld/v1/entityOperations/upsert/",
128171
request_headers={"Content-Type": "application/ld+json"},
129-
status_code=204
172+
status_code=204,
130173
)
131174
client = Client()
132175
sample2 = sample_entity.dup()
@@ -146,6 +189,7 @@ def test_api_batch_upsert_ok_204(mocked_connected, requests_mock):
146189
"urn:ngsi-ld:AirQualityObserved:RZ:Obsv4569",
147190
]
148191

192+
149193
def test_api_batch_update_ok_204(mocked_connected, requests_mock):
150194
requests_mock.post(
151195
"http://localhost:1026/ngsi-ld/v1/entityOperations/update/",
@@ -175,6 +219,7 @@ def test_api_batch_update_ok_204(mocked_connected, requests_mock):
175219
"urn:ngsi-ld:AirQualityObserved:RZ:Obsv4569",
176220
]
177221

222+
178223
def test_api_batch_delete_ok_204(mocked_connected, requests_mock):
179224
requests_mock.post(
180225
"http://localhost:1026/ngsi-ld/v1/entityOperations/delete/",
@@ -202,4 +247,4 @@ def test_api_batch_delete_ok_204(mocked_connected, requests_mock):
202247
"urn:ngsi-ld:AirQualityObserved:RZ:Obsv4567",
203248
"urn:ngsi-ld:AirQualityObserved:RZ:Obsv4568",
204249
"urn:ngsi-ld:AirQualityObserved:RZ:Obsv4569",
205-
]
250+
]

0 commit comments

Comments
 (0)