aas-http-client 0.3.2__tar.gz → 0.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of aas-http-client might be problematic. Click here for more details.

Files changed (21) hide show
  1. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/PKG-INFO +1 -1
  2. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/aas_http_client/client.py +32 -9
  3. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/aas_http_client/wrapper/sdk_wrapper.py +19 -1
  4. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/aas_http_client.egg-info/PKG-INFO +1 -1
  5. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/pyproject.toml +1 -1
  6. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/tests/test_client.py +189 -17
  7. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/tests/test_wrapper.py +222 -21
  8. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/LICENSE +0 -0
  9. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/README.md +0 -0
  10. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/aas_http_client/__init__.py +0 -0
  11. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/aas_http_client/core/encoder.py +0 -0
  12. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/aas_http_client/core/version_check.py +0 -0
  13. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/aas_http_client/demo/demo_process.py +0 -0
  14. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/aas_http_client/demo/logging_handler.py +0 -0
  15. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/aas_http_client/utilities/__init__.py +0 -0
  16. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/aas_http_client/utilities/model_builder.py +0 -0
  17. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/aas_http_client.egg-info/SOURCES.txt +0 -0
  18. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/aas_http_client.egg-info/dependency_links.txt +0 -0
  19. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/aas_http_client.egg-info/requires.txt +0 -0
  20. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/aas_http_client.egg-info/top_level.txt +0 -0
  21. {aas_http_client-0.3.2 → aas_http_client-0.3.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aas-http-client
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Generic python HTTP client for communication with various types of AAS servers
5
5
  Author-email: Daniel Klein <daniel.klein@em.ag>
6
6
  License: # :em engineering methods AG Software License
@@ -4,6 +4,7 @@ import json
4
4
  import logging
5
5
  import time
6
6
  from pathlib import Path
7
+ from typing import Any
7
8
 
8
9
  import basyx.aas.adapter.json
9
10
  import basyx.aas.adapter.json.json_serialization as js
@@ -26,7 +27,7 @@ STATUS_CODE_404 = 404
26
27
  HEADERS = {"Content-Type": "application/json"}
27
28
 
28
29
 
29
- def log_response_errors(response: Response):
30
+ def log_response_errors(response: Response): # noqa: C901
30
31
  """Create error messages from the response and log them.
31
32
 
32
33
  :param response: response
@@ -74,7 +75,6 @@ class AasHttpClient(BaseModel):
74
75
 
75
76
  base_url: str = "http://javaaasserver:5060/"
76
77
  username: str | None = None
77
- _password: str | None = PrivateAttr(default=None)
78
78
  https_proxy: str | None = None
79
79
  http_proxy: str | None = None
80
80
  time_out: int = 200
@@ -87,13 +87,11 @@ class AasHttpClient(BaseModel):
87
87
 
88
88
  :param password: password
89
89
  """
90
- self._password = password
91
-
92
90
  if self.base_url.endswith("/"):
93
91
  self.base_url = self.base_url[:-1]
94
92
 
95
93
  self._session = requests.Session()
96
- self._session.auth = HTTPBasicAuth(self.username, self._password)
94
+ self._session.auth = HTTPBasicAuth(self.username, password)
97
95
  self._session.verify = self.ssl_verify
98
96
 
99
97
  if self.https_proxy:
@@ -561,6 +559,32 @@ class AasHttpClient(BaseModel):
561
559
 
562
560
  return True
563
561
 
562
+ def patch_submodel_element_by_path_value_only_submodel_repo(self, submodel_id: str, submodel_element_path: str, value: str) -> bool:
563
+ """Updates the value of an existing SubmodelElement.
564
+
565
+ :param submodel_id: Encoded ID of the Submodel to update submodel element for
566
+ :param submodel_element_path: Path of the Submodel element to update
567
+ :param value: Submodel element value to update as string
568
+ :return: True if the patch was successful, False otherwise
569
+ """
570
+ decoded_submodel_id: str = decode_base_64(submodel_id)
571
+
572
+ url = f"{self.base_url}/submodels/{decoded_submodel_id}/submodel-elements/{submodel_element_path}/$value"
573
+
574
+ try:
575
+ response = self._session.patch(url, headers=HEADERS, json=value, timeout=self.time_out)
576
+ logger.debug(f"Call REST API url '{response.url}'")
577
+
578
+ if response.status_code != STATUS_CODE_204:
579
+ log_response_errors(response)
580
+ return False
581
+
582
+ except requests.exceptions.RequestException as e:
583
+ logger.error(f"Error call REST API: {e}")
584
+ return False
585
+
586
+ return True
587
+
564
588
 
565
589
  # endregion
566
590
 
@@ -633,12 +657,11 @@ def create_client_by_config(config_file: Path, password: str = "") -> AasHttpCli
633
657
  return _create_client(config_string, password)
634
658
 
635
659
 
636
- def _create_client(config_string: str, password) -> AasHttpClient | None:
660
+ def _create_client(config_string: str, password: str) -> AasHttpClient | None:
637
661
  try:
638
- connection_settings = AasHttpClient.model_validate_json(config_string)
639
- client = AasHttpClient(**connection_settings.model_dump())
662
+ client = AasHttpClient.model_validate_json(config_string)
640
663
  except ValidationError as ve:
641
- raise ValidationError(f"Invalid BaSyx server connection file: {ve}") from ve
664
+ raise ValidationError(f"Invalid BaSyx server configuration file: {ve}") from ve
642
665
 
643
666
  logger.info(
644
667
  f"Using server configuration: '{client.base_url}' | "
@@ -275,10 +275,28 @@ class SdkWrapper:
275
275
  :return: Submodel element object or None if an error occurred
276
276
  """
277
277
  content: dict = self._client.get_submodel_element_by_path_submodel_repo(submodel_id, submodel_element_path)
278
+ print(content)
278
279
  return _to_object(content)
279
280
 
281
+ def patch_submodel_element_by_path_value_only_submodel_repo(self, submodel_id: str, submodel_element_path: str, value: str) -> bool:
282
+ """Updates the value of an existing SubmodelElement.
283
+
284
+ :param submodel_id: Encoded ID of the Submodel to update submodel element for
285
+ :param submodel_element_path: Path of the Submodel element to update
286
+ :param value: Submodel element value to update as string
287
+ :return: True if the patch was successful, False otherwise
288
+ """
289
+ return self._client.patch_submodel_element_by_path_value_only_submodel_repo(submodel_id, submodel_element_path, value)
290
+
291
+ # endregion
292
+
293
+ def get_client(self) -> AasHttpClient:
294
+ """Returns the underlying AAS HTTP client.
295
+
296
+ :return: The AAS HTTP client instance.
297
+ """
298
+ return self._client
280
299
 
281
- # endregion
282
300
 
283
301
  # region utils
284
302
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aas-http-client
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Generic python HTTP client for communication with various types of AAS servers
5
5
  Author-email: Daniel Klein <daniel.klein@em.ag>
6
6
  License: # :em engineering methods AG Software License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "aas-http-client"
7
- version = "0.3.2"
7
+ version = "0.3.4"
8
8
  description = "Generic python HTTP client for communication with various types of AAS servers"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -13,9 +13,13 @@ PYTHON_SERVER_PORTS = [8080, 80]
13
13
  CONFIG_FILES = [
14
14
  "./tests/server_configs/test_dotnet_server_config.json",
15
15
  "./tests/server_configs/test_java_server_config.json",
16
- "./tests/server_configs/test_python_server_config.json",
16
+ "./tests/server_configs/test_python_server_config.json"
17
17
  ]
18
18
 
19
+ # CONFIG_FILES = [
20
+ # "./tests/server_configs/test_dotnet_server_config_local.json",
21
+ # ]
22
+
19
23
  @pytest.fixture(params=CONFIG_FILES, scope="module")
20
24
  def client(request) -> AasHttpClient:
21
25
  try:
@@ -35,9 +39,24 @@ def client(request) -> AasHttpClient:
35
39
  return client
36
40
 
37
41
  @pytest.fixture(scope="module")
38
- def shared_sme() -> model.Property:
42
+ def shared_sme_string() -> model.Property:
43
+ # create a Submodel
44
+ return model_builder.create_base_submodel_element_Property("sme_property_string", model.datatypes.String, "Sample String Value")
45
+
46
+ @pytest.fixture(scope="module")
47
+ def shared_sme_bool() -> model.Property:
39
48
  # create a Submodel
40
- return model_builder.create_base_submodel_element_Property("sme_http_client_unit_tests", model.datatypes.String, "Sample Value")
49
+ return model_builder.create_base_submodel_element_Property("sme_property_bool", model.datatypes.Boolean, True)
50
+
51
+ @pytest.fixture(scope="module")
52
+ def shared_sme_int() -> model.Property:
53
+ # create a Submodel
54
+ return model_builder.create_base_submodel_element_Property("sme_property_int", model.datatypes.Integer, 262)
55
+
56
+ @pytest.fixture(scope="module")
57
+ def shared_sme_float() -> model.Property:
58
+ # create a Submodel
59
+ return model_builder.create_base_submodel_element_Property("sme_property_float", model.datatypes.Float, 262.3)
41
60
 
42
61
  @pytest.fixture(scope="module")
43
62
  def shared_sm() -> model.Submodel:
@@ -277,7 +296,7 @@ def test_012_patch_submodel_by_id(client: AasHttpClient, shared_sm: model.Submod
277
296
  # NOTE: Basyx java and python server do not provide this endpoint
278
297
  assert not result
279
298
  else:
280
- assert result
299
+ assert result is True
281
300
 
282
301
  get_result = client.get_submodel_by_id(shared_sm.id)
283
302
  assert get_result is not None
@@ -334,7 +353,7 @@ def test_014_put_submodels_by_id(client: AasHttpClient, shared_sm: model.Submode
334
353
 
335
354
  result = client.put_submodels_by_id(shared_sm.id, sm_data)
336
355
 
337
- assert result
356
+ assert result is True
338
357
 
339
358
  get_result = client.get_submodel_by_id(shared_sm.id)
340
359
  assert get_result is not None
@@ -356,33 +375,186 @@ def test_015_get_all_submodel_elements_submodel_repository(client: AasHttpClient
356
375
  assert submodel_elements is not None
357
376
  assert len(submodel_elements.get("result", [])) == 0
358
377
 
359
- def test_016_post_submodel_element_submodel_repo(client: AasHttpClient, shared_sm: model.Submodel, shared_sme: model.Property):
360
- sme_data_string = json.dumps(shared_sme, cls=basyx.aas.adapter.json.AASToJsonEncoder)
378
+ def test_016a_post_submodel_element_submodel_repo(client: AasHttpClient, shared_sm: model.Submodel, shared_sme_string: model.Property):
379
+ sme_data_string = json.dumps(shared_sme_string, cls=basyx.aas.adapter.json.AASToJsonEncoder)
361
380
  sme_data = json.loads(sme_data_string)
362
381
 
363
382
  result = client.post_submodel_element_submodel_repo(shared_sm.id, sme_data)
364
383
 
365
384
  assert result is not None
366
- assert result.get("idShort", "") == shared_sme.id_short
367
- assert result.get("description", {})[0].get("text", "") == shared_sme.description.get("en", "")
368
- assert result.get("displayName", {})[0].get("text", "") == shared_sme.display_name.get("en", "")
385
+ assert result.get("idShort", "") == shared_sme_string.id_short
386
+ assert result.get("description", {})[0].get("text", "") == shared_sme_string.description.get("en", "")
387
+ assert result.get("displayName", {})[0].get("text", "") == shared_sme_string.display_name.get("en", "")
388
+ assert result.get("value", "") == shared_sme_string.value
369
389
 
370
390
  get_result = client.get_all_submodel_elements_submodel_repository(shared_sm.id)
371
391
 
372
392
  assert len(get_result.get("result", [])) == 1
373
393
 
374
- def test_017_get_submodel_element_by_path_submodel_repo(client: AasHttpClient, shared_sm: model.Submodel, shared_sme: model.Property):
375
- result = client.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme.id_short)
394
+ def test_016b_post_submodel_element_submodel_repo(client: AasHttpClient, shared_sm: model.Submodel, shared_sme_bool: model.Property):
395
+ sme_data_string = json.dumps(shared_sme_bool, cls=basyx.aas.adapter.json.AASToJsonEncoder)
396
+ sme_data = json.loads(sme_data_string)
397
+
398
+ result = client.post_submodel_element_submodel_repo(shared_sm.id, sme_data)
399
+
400
+ assert result is not None
401
+ assert result.get("idShort", "") == shared_sme_bool.id_short
402
+ assert result.get("description", {})[0].get("text", "") == shared_sme_bool.description.get("en", "")
403
+ assert result.get("displayName", {})[0].get("text", "") == shared_sme_bool.display_name.get("en", "")
404
+ assert json.loads(result.get("value", "").lower()) == shared_sme_bool.value
405
+
406
+ get_result = client.get_all_submodel_elements_submodel_repository(shared_sm.id)
407
+
408
+ assert len(get_result.get("result", [])) == 2
409
+
410
+ def test_016c_post_submodel_element_submodel_repo(client: AasHttpClient, shared_sm: model.Submodel, shared_sme_int: model.Property):
411
+ sme_data_string = json.dumps(shared_sme_int, cls=basyx.aas.adapter.json.AASToJsonEncoder)
412
+ sme_data = json.loads(sme_data_string)
413
+
414
+ result = client.post_submodel_element_submodel_repo(shared_sm.id, sme_data)
415
+
416
+ assert result is not None
417
+ assert result.get("idShort", "") == shared_sme_int.id_short
418
+ assert result.get("description", {})[0].get("text", "") == shared_sme_int.description.get("en", "")
419
+ assert result.get("displayName", {})[0].get("text", "") == shared_sme_int.display_name.get("en", "")
420
+ assert int(result.get("value", "")) == shared_sme_int.value
421
+
422
+ get_result = client.get_all_submodel_elements_submodel_repository(shared_sm.id)
423
+
424
+ assert len(get_result.get("result", [])) == 3
425
+
426
+ def test_016d_post_submodel_element_submodel_repo(client: AasHttpClient, shared_sm: model.Submodel, shared_sme_float: model.Property):
427
+ sme_data_string = json.dumps(shared_sme_float, cls=basyx.aas.adapter.json.AASToJsonEncoder)
428
+ sme_data = json.loads(sme_data_string)
429
+
430
+ result = client.post_submodel_element_submodel_repo(shared_sm.id, sme_data)
431
+
432
+ assert result is not None
433
+ assert result.get("idShort", "") == shared_sme_float.id_short
434
+ assert result.get("description", {})[0].get("text", "") == shared_sme_float.description.get("en", "")
435
+ assert result.get("displayName", {})[0].get("text", "") == shared_sme_float.display_name.get("en", "")
436
+ assert float(result.get("value", "")) == shared_sme_float.value
437
+
438
+ get_result = client.get_all_submodel_elements_submodel_repository(shared_sm.id)
439
+
440
+ assert len(get_result.get("result", [])) == 4
441
+
442
+ def test_017a_get_submodel_element_by_path_submodel_repo(client: AasHttpClient, shared_sm: model.Submodel, shared_sme_string: model.Property):
443
+ result = client.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_string.id_short)
444
+
445
+ assert result is not None
446
+ assert result.get("idShort", "") == shared_sme_string.id_short
447
+ assert result.get("description", {})[0].get("text", "") == shared_sme_string.description.get("en", "")
448
+ assert result.get("displayName", {})[0].get("text", "") == shared_sme_string.display_name.get("en", "")
449
+ assert result.get("value", "") == shared_sme_string.value
450
+
451
+ def test_017b_get_submodel_element_by_path_submodel_repo(client: AasHttpClient, shared_sm: model.Submodel, shared_sme_bool: model.Property):
452
+ result = client.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_bool.id_short)
453
+
454
+ assert result is not None
455
+ assert result.get("idShort", "") == shared_sme_bool.id_short
456
+ assert result.get("description", {})[0].get("text", "") == shared_sme_bool.description.get("en", "")
457
+ assert result.get("displayName", {})[0].get("text", "") == shared_sme_bool.display_name.get("en", "")
458
+ assert json.loads(result.get("value", "").lower()) == shared_sme_bool.value
459
+
460
+ def test_017c_get_submodel_element_by_path_submodel_repo(client: AasHttpClient, shared_sm: model.Submodel, shared_sme_int: model.Property):
461
+ result = client.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_int.id_short)
376
462
 
377
463
  assert result is not None
378
- assert result.get("idShort", "") == shared_sme.id_short
379
- assert result.get("description", {})[0].get("text", "") == shared_sme.description.get("en", "")
380
- assert result.get("displayName", {})[0].get("text", "") == shared_sme.display_name.get("en", "")
464
+ assert result.get("idShort", "") == shared_sme_int.id_short
465
+ assert result.get("description", {})[0].get("text", "") == shared_sme_int.description.get("en", "")
466
+ assert result.get("displayName", {})[0].get("text", "") == shared_sme_int.display_name.get("en", "")
467
+ assert int(result.get("value", "")) == shared_sme_int.value
468
+
469
+ def test_017d_get_submodel_element_by_path_submodel_repo(client: AasHttpClient, shared_sm: model.Submodel, shared_sme_float: model.Property):
470
+ result = client.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_float.id_short)
471
+
472
+ assert result is not None
473
+ assert result.get("idShort", "") == shared_sme_float.id_short
474
+ assert result.get("description", {})[0].get("text", "") == shared_sme_float.description.get("en", "")
475
+ assert result.get("displayName", {})[0].get("text", "") == shared_sme_float.display_name.get("en", "")
476
+ assert float(result.get("value", "")) == shared_sme_float.value
477
+
478
+ def test_018a_patch_submodel_element_by_path_value_only_submodel_repo(client: AasHttpClient, shared_sm: model.Submodel, shared_sme_string: model.Property):
479
+ new_value = "Patched String Value"
480
+ result = client.patch_submodel_element_by_path_value_only_submodel_repo(shared_sm.id, shared_sme_string.id_short, new_value)
481
+
482
+ parsed = urlparse(client.base_url)
483
+ if int(parsed.port) in PYTHON_SERVER_PORTS:
484
+ # NOTE: python server do not provide this endpoint
485
+ assert result is False
486
+ else:
487
+ assert result is True
488
+
489
+ get_result = client.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_string.id_short)
490
+
491
+ assert get_result is not None
492
+ assert get_result.get("idShort", "") == shared_sme_string.id_short
493
+ assert get_result.get("value", "") == new_value
494
+ assert get_result.get("description", {})[0].get("text", "") == shared_sme_string.description.get("en", "")
495
+ assert get_result.get("displayName", {})[0].get("text", "") == shared_sme_string.display_name.get("en", "")
496
+
497
+ def test_018b_patch_submodel_element_by_path_value_only_submodel_repo(client: AasHttpClient, shared_sm: model.Submodel, shared_sme_bool: model.Property):
498
+ new_value = "false"
499
+ result = client.patch_submodel_element_by_path_value_only_submodel_repo(shared_sm.id, shared_sme_bool.id_short, new_value)
500
+
501
+ parsed = urlparse(client.base_url)
502
+ if int(parsed.port) in PYTHON_SERVER_PORTS:
503
+ # NOTE: python server do not provide this endpoint
504
+ assert result is False
505
+ else:
506
+ assert result is True
507
+
508
+ get_result = client.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_bool.id_short)
509
+
510
+ assert get_result is not None
511
+ assert get_result.get("idShort", "") == shared_sme_bool.id_short
512
+ assert json.loads(get_result.get("value", "").lower()) == json.loads(new_value)
513
+ assert get_result.get("description", {})[0].get("text", "") == shared_sme_bool.description.get("en", "")
514
+ assert get_result.get("displayName", {})[0].get("text", "") == shared_sme_bool.display_name.get("en", "")
515
+
516
+ def test_018c_patch_submodel_element_by_path_value_only_submodel_repo(client: AasHttpClient, shared_sm: model.Submodel, shared_sme_int: model.Property):
517
+ new_value = "263"
518
+ result = client.patch_submodel_element_by_path_value_only_submodel_repo(shared_sm.id, shared_sme_int.id_short, new_value)
519
+
520
+ parsed = urlparse(client.base_url)
521
+ if int(parsed.port) in PYTHON_SERVER_PORTS:
522
+ # NOTE: python server do not provide this endpoint
523
+ assert result is False
524
+ else:
525
+ assert result is True
526
+
527
+ get_result = client.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_int.id_short)
528
+
529
+ assert get_result is not None
530
+ assert get_result.get("idShort", "") == shared_sme_int.id_short
531
+ assert int(get_result.get("value", "")) == int(new_value)
532
+ assert get_result.get("description", {})[0].get("text", "") == shared_sme_int.description.get("en", "")
533
+ assert get_result.get("displayName", {})[0].get("text", "") == shared_sme_int.display_name.get("en", "")
534
+
535
+ def test_018d_patch_submodel_element_by_path_value_only_submodel_repo(client: AasHttpClient, shared_sm: model.Submodel, shared_sme_float: model.Property):
536
+ new_value = "262.1"
537
+ result = client.patch_submodel_element_by_path_value_only_submodel_repo(shared_sm.id, shared_sme_float.id_short, new_value)
538
+
539
+ parsed = urlparse(client.base_url)
540
+ if int(parsed.port) in PYTHON_SERVER_PORTS:
541
+ # NOTE: python server do not provide this endpoint
542
+ assert result is False
543
+ else:
544
+ assert result is True
545
+
546
+ get_result = client.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_float.id_short)
547
+
548
+ assert get_result is not None
549
+ assert get_result.get("idShort", "") == shared_sme_float.id_short
550
+ assert float(get_result.get("value", "")) == float(new_value)
551
+ assert get_result.get("description", {})[0].get("text", "") == shared_sme_float.description.get("en", "")
552
+ assert get_result.get("displayName", {})[0].get("text", "") == shared_sme_float.display_name.get("en", "")
381
553
 
382
554
  def test_098_delete_asset_administration_shell_by_id(client: AasHttpClient, shared_aas: model.AssetAdministrationShell):
383
555
  result = client.delete_asset_administration_shell_by_id(shared_aas.id)
384
556
 
385
- assert result
557
+ assert result is True
386
558
 
387
559
  get_result = client.get_all_asset_administration_shells()
388
560
  assert get_result is not None
@@ -392,7 +564,7 @@ def test_098_delete_asset_administration_shell_by_id(client: AasHttpClient, shar
392
564
  def test_099_delete_submodel_by_id(client: AasHttpClient, shared_sm: model.Submodel):
393
565
  result = client.delete_submodel_by_id(shared_sm.id)
394
566
 
395
- assert result
567
+ assert result is True
396
568
 
397
569
  get_result = client.get_all_submodels()
398
570
  assert get_result is not None
@@ -4,6 +4,7 @@ from aas_http_client.wrapper.sdk_wrapper import create_wrapper_by_config, SdkWra
4
4
  from basyx.aas import model
5
5
  import aas_http_client.utilities.model_builder as model_builder
6
6
  from urllib.parse import urlparse
7
+ import json
7
8
 
8
9
  JAVA_SERVER_PORTS = [8075]
9
10
  PYTHON_SERVER_PORTS = [8080, 80]
@@ -15,6 +16,10 @@ CONFIG_FILES = [
15
16
  "./tests/server_configs/test_python_server_config.json"
16
17
  ]
17
18
 
19
+ # CONFIG_FILES = [
20
+ # "./tests/server_configs/test_dotnet_server_config_local.json",
21
+ # ]
22
+
18
23
  @pytest.fixture(params=CONFIG_FILES, scope="module")
19
24
  def wrapper(request) -> SdkWrapper:
20
25
  try:
@@ -34,9 +39,24 @@ def wrapper(request) -> SdkWrapper:
34
39
  return wrapper
35
40
 
36
41
  @pytest.fixture(scope="module")
37
- def shared_sme() -> model.Property:
42
+ def shared_sme_string() -> model.Property:
43
+ # create a Submodel
44
+ return model_builder.create_base_submodel_element_Property("sme_property_string", model.datatypes.String, "Sample String Value")
45
+
46
+ @pytest.fixture(scope="module")
47
+ def shared_sme_bool() -> model.Property:
48
+ # create a Submodel
49
+ return model_builder.create_base_submodel_element_Property("sme_property_bool", model.datatypes.Boolean, True)
50
+
51
+ @pytest.fixture(scope="module")
52
+ def shared_sme_int() -> model.Property:
53
+ # create a Submodel
54
+ return model_builder.create_base_submodel_element_Property("sme_property_int", model.datatypes.Integer, 262)
55
+
56
+ @pytest.fixture(scope="module")
57
+ def shared_sme_float() -> model.Property:
38
58
  # create a Submodel
39
- return model_builder.create_base_submodel_element_Property("sme_http_client_unit_tests", model.datatypes.String, "Sample Value")
59
+ return model_builder.create_base_submodel_element_Property("sme_property_float", model.datatypes.Float, 262.3)
40
60
 
41
61
  @pytest.fixture(scope="module")
42
62
  def shared_sm() -> model.Submodel:
@@ -70,6 +90,12 @@ def test_000b_create_wrapper_by_dict(wrapper: SdkWrapper):
70
90
  new_client: SdkWrapper = create_wrapper_by_dict(configuration=config_dict)
71
91
  assert new_client is not None
72
92
 
93
+ def test_000c_get_client(wrapper: SdkWrapper):
94
+ client = wrapper.get_client()
95
+ assert client is not None
96
+ root = client.get_root()
97
+ assert root is not None
98
+
73
99
  def test_001_connect(wrapper: SdkWrapper):
74
100
  assert wrapper is not None
75
101
 
@@ -307,42 +333,217 @@ def test_015_get_all_submodel_elements_submodel_repository(wrapper: SdkWrapper,
307
333
  assert submodel_elements is not None
308
334
  assert len(submodel_elements) == 0
309
335
 
310
- def test_016_post_submodel_element_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme: model.Property):
311
- submodel_element = wrapper.post_submodel_element_submodel_repo(shared_sm.id, shared_sme)
336
+ def test_016a_post_submodel_element_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_string: model.Property):
337
+ submodel_element = wrapper.post_submodel_element_submodel_repo(shared_sm.id, shared_sme_string)
312
338
 
313
339
  assert submodel_element is not None
314
340
 
315
- parsed = urlparse(wrapper.base_url)
316
- if int(parsed.port) in DOTNET_SERVER_PORTS:
317
- # NOTE: dotNet server provides a wrong representation of submodel elements
318
- return
319
-
320
341
  assert isinstance(submodel_element, model.Property)
342
+ property: model.Property = submodel_element
343
+ assert property.value == shared_sme_string.value
321
344
 
322
- assert submodel_element.id_short == shared_sme.id_short
323
- assert submodel_element.description.get("en", "") == shared_sme.description.get("en", "")
324
- assert submodel_element.display_name.get("en", "") == shared_sme.display_name.get("en", "")
345
+ assert submodel_element.id_short == shared_sme_string.id_short
346
+ assert submodel_element.description.get("en", "") == shared_sme_string.description.get("en", "")
347
+ assert submodel_element.display_name.get("en", "") == shared_sme_string.display_name.get("en", "")
348
+ assert submodel_element.value == shared_sme_string.value
325
349
 
326
350
  submodel_elements = wrapper.get_all_submodel_elements_submodel_repository(shared_sm.id)
327
351
 
328
352
  assert submodel_elements is not None
329
353
  assert len(submodel_elements) == 1
330
354
 
331
- def test_017_get_submodel_element_by_path_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme: model.Property):
332
- submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme.id_short)
355
+ def test_016b_post_submodel_element_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_bool: model.Property):
356
+ submodel_element = wrapper.post_submodel_element_submodel_repo(shared_sm.id, shared_sme_bool)
333
357
 
334
358
  assert submodel_element is not None
335
359
 
336
- parsed = urlparse(wrapper.base_url)
337
- if int(parsed.port) in DOTNET_SERVER_PORTS:
338
- # NOTE: dotNet server provides a wrong representation of submodel elements
339
- return
360
+ assert isinstance(submodel_element, model.Property)
361
+ property: model.Property = submodel_element
362
+ assert property.value == shared_sme_bool.value
363
+
364
+ assert submodel_element.id_short == shared_sme_bool.id_short
365
+ assert submodel_element.description.get("en", "") == shared_sme_bool.description.get("en", "")
366
+ assert submodel_element.display_name.get("en", "") == shared_sme_bool.display_name.get("en", "")
367
+ assert submodel_element.value == shared_sme_bool.value
368
+
369
+ submodel_elements = wrapper.get_all_submodel_elements_submodel_repository(shared_sm.id)
370
+
371
+ assert submodel_elements is not None
372
+ assert len(submodel_elements) == 2
373
+
374
+ def test_016c_post_submodel_element_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_int: model.Property):
375
+ submodel_element = wrapper.post_submodel_element_submodel_repo(shared_sm.id, shared_sme_int)
376
+
377
+ assert submodel_element is not None
340
378
 
341
379
  assert isinstance(submodel_element, model.Property)
380
+ property: model.Property = submodel_element
381
+ assert property.value == shared_sme_int.value
382
+
383
+ assert submodel_element.id_short == shared_sme_int.id_short
384
+ assert submodel_element.description.get("en", "") == shared_sme_int.description.get("en", "")
385
+ assert submodel_element.display_name.get("en", "") == shared_sme_int.display_name.get("en", "")
386
+ assert submodel_element.value == shared_sme_int.value
387
+
388
+ submodel_elements = wrapper.get_all_submodel_elements_submodel_repository(shared_sm.id)
389
+
390
+ assert submodel_elements is not None
391
+ assert len(submodel_elements) == 3
392
+
393
+ def test_016d_post_submodel_element_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_float: model.Property):
394
+ submodel_element = wrapper.post_submodel_element_submodel_repo(shared_sm.id, shared_sme_float)
395
+
396
+ assert submodel_element is not None
397
+
398
+ assert isinstance(submodel_element, model.Property)
399
+ property: model.Property = submodel_element
400
+ assert property.value == shared_sme_float.value
401
+
402
+ assert submodel_element.id_short == shared_sme_float.id_short
403
+ assert submodel_element.description.get("en", "") == shared_sme_float.description.get("en", "")
404
+ assert submodel_element.display_name.get("en", "") == shared_sme_float.display_name.get("en", "")
405
+ assert submodel_element.value == shared_sme_float.value
406
+
407
+ submodel_elements = wrapper.get_all_submodel_elements_submodel_repository(shared_sm.id)
408
+
409
+ assert submodel_elements is not None
410
+ assert len(submodel_elements) == 4
411
+
412
+ def test_017a_get_submodel_element_by_path_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_string: model.Property):
413
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_string.id_short)
414
+
415
+ assert submodel_element is not None
416
+
417
+ assert isinstance(submodel_element, model.Property)
418
+
419
+ assert submodel_element.id_short == shared_sme_string.id_short
420
+ assert submodel_element.description.get("en", "") == shared_sme_string.description.get("en", "")
421
+ assert submodel_element.display_name.get("en", "") == shared_sme_string.display_name.get("en", "")
422
+ assert submodel_element.value == shared_sme_string.value
423
+
424
+ def test_017b_get_submodel_element_by_path_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_bool: model.Property):
425
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_bool.id_short)
426
+
427
+ assert submodel_element is not None
428
+
429
+ assert isinstance(submodel_element, model.Property)
430
+
431
+ assert submodel_element.id_short == shared_sme_bool.id_short
432
+ assert submodel_element.description.get("en", "") == shared_sme_bool.description.get("en", "")
433
+ assert submodel_element.display_name.get("en", "") == shared_sme_bool.display_name.get("en", "")
434
+ assert submodel_element.value == shared_sme_bool.value
435
+
436
+ def test_017c_get_submodel_element_by_path_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_int: model.Property):
437
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_int.id_short)
438
+
439
+ assert submodel_element is not None
440
+
441
+ assert isinstance(submodel_element, model.Property)
442
+
443
+ assert submodel_element.id_short == shared_sme_int.id_short
444
+ assert submodel_element.description.get("en", "") == shared_sme_int.description.get("en", "")
445
+ assert submodel_element.display_name.get("en", "") == shared_sme_int.display_name.get("en", "")
446
+ assert submodel_element.value == shared_sme_int.value
447
+
448
+ def test_017d_get_submodel_element_by_path_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_float: model.Property):
449
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_float.id_short)
450
+
451
+ assert submodel_element is not None
452
+
453
+ assert isinstance(submodel_element, model.Property)
454
+
455
+ assert submodel_element.id_short == shared_sme_float.id_short
456
+ assert submodel_element.description.get("en", "") == shared_sme_float.description.get("en", "")
457
+ assert submodel_element.display_name.get("en", "") == shared_sme_float.display_name.get("en", "")
458
+ assert submodel_element.value == shared_sme_float.value
459
+
460
+ def test_018a_patch_submodel_element_by_path_value_only_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_string: model.Property):
461
+ new_value = "Patched String Value"
462
+ result = wrapper.patch_submodel_element_by_path_value_only_submodel_repo(shared_sm.id, shared_sme_string.id_short, new_value)
463
+
464
+ parsed = urlparse(wrapper.base_url)
465
+ if int(parsed.port) in PYTHON_SERVER_PORTS:
466
+ # NOTE: python server do not provide this endpoint
467
+ assert result is False
468
+ else:
469
+ assert result is True
470
+
471
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_string.id_short)
472
+
473
+ assert submodel_element is not None
474
+ assert submodel_element.id_short == shared_sme_string.id_short
475
+ assert submodel_element.description.get("en", "") == shared_sme_string.description.get("en", "")
476
+ assert submodel_element.display_name.get("en", "") == shared_sme_string.display_name.get("en", "")
477
+
478
+ assert isinstance(submodel_element, model.Property)
479
+ property: model.Property = submodel_element
480
+ assert property.value == new_value
481
+
482
+ def test_018b_patch_submodel_element_by_path_value_only_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_bool: model.Property):
483
+ new_value = "false"
484
+ result = wrapper.patch_submodel_element_by_path_value_only_submodel_repo(shared_sm.id, shared_sme_bool.id_short, new_value)
485
+
486
+ parsed = urlparse(wrapper.base_url)
487
+ if int(parsed.port) in PYTHON_SERVER_PORTS:
488
+ # NOTE: python server do not provide this endpoint
489
+ assert result is False
490
+ else:
491
+ assert result is True
492
+
493
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_bool.id_short)
494
+
495
+ assert submodel_element is not None
496
+ assert submodel_element.id_short == shared_sme_bool.id_short
497
+ assert submodel_element.description.get("en", "") == shared_sme_bool.description.get("en", "")
498
+ assert submodel_element.display_name.get("en", "") == shared_sme_bool.display_name.get("en", "")
499
+
500
+ assert isinstance(submodel_element, model.Property)
501
+ property: model.Property = submodel_element
502
+ assert property.value == json.loads(new_value)
503
+
504
+ def test_018c_patch_submodel_element_by_path_value_only_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_int: model.Property):
505
+ new_value = "263"
506
+ result = wrapper.patch_submodel_element_by_path_value_only_submodel_repo(shared_sm.id, shared_sme_int.id_short, new_value)
507
+
508
+ parsed = urlparse(wrapper.base_url)
509
+ if int(parsed.port) in PYTHON_SERVER_PORTS:
510
+ # NOTE: python server do not provide this endpoint
511
+ assert result is False
512
+ else:
513
+ assert result is True
514
+
515
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_int.id_short)
516
+
517
+ assert submodel_element is not None
518
+ assert submodel_element.id_short == shared_sme_int.id_short
519
+ assert submodel_element.description.get("en", "") == shared_sme_int.description.get("en", "")
520
+ assert submodel_element.display_name.get("en", "") == shared_sme_int.display_name.get("en", "")
521
+
522
+ assert isinstance(submodel_element, model.Property)
523
+ property: model.Property = submodel_element
524
+ assert property.value == int(new_value)
525
+
526
+ def test_018d_patch_submodel_element_by_path_value_only_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_float: model.Property):
527
+ new_value = "262.1"
528
+ result = wrapper.patch_submodel_element_by_path_value_only_submodel_repo(shared_sm.id, shared_sme_float.id_short, new_value)
529
+
530
+ parsed = urlparse(wrapper.base_url)
531
+ if int(parsed.port) in PYTHON_SERVER_PORTS:
532
+ # NOTE: python server do not provide this endpoint
533
+ assert result is False
534
+ else:
535
+ assert result is True
536
+
537
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_float.id_short)
538
+
539
+ assert submodel_element is not None
540
+ assert submodel_element.id_short == shared_sme_float.id_short
541
+ assert submodel_element.description.get("en", "") == shared_sme_float.description.get("en", "")
542
+ assert submodel_element.display_name.get("en", "") == shared_sme_float.display_name.get("en", "")
342
543
 
343
- assert submodel_element.id_short == shared_sme.id_short
344
- assert submodel_element.description.get("en", "") == shared_sme.description.get("en", "")
345
- assert submodel_element.display_name.get("en", "") == shared_sme.display_name.get("en", "")
544
+ assert isinstance(submodel_element, model.Property)
545
+ property: model.Property = submodel_element
546
+ assert property.value == float(new_value)
346
547
 
347
548
  def test_098_delete_asset_administration_shell_by_id(wrapper: SdkWrapper, shared_aas: model.AssetAdministrationShell):
348
549
  result = wrapper.delete_asset_administration_shell_by_id(shared_aas.id)
File without changes