aas-http-client 0.3.2__tar.gz → 0.3.3__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.
Files changed (21) hide show
  1. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/PKG-INFO +1 -1
  2. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/aas_http_client/client.py +29 -3
  3. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/aas_http_client/wrapper/sdk_wrapper.py +11 -0
  4. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/aas_http_client.egg-info/PKG-INFO +1 -1
  5. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/pyproject.toml +1 -1
  6. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/tests/test_client.py +189 -17
  7. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/tests/test_wrapper.py +216 -21
  8. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/LICENSE +0 -0
  9. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/README.md +0 -0
  10. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/aas_http_client/__init__.py +0 -0
  11. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/aas_http_client/core/encoder.py +0 -0
  12. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/aas_http_client/core/version_check.py +0 -0
  13. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/aas_http_client/demo/demo_process.py +0 -0
  14. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/aas_http_client/demo/logging_handler.py +0 -0
  15. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/aas_http_client/utilities/__init__.py +0 -0
  16. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/aas_http_client/utilities/model_builder.py +0 -0
  17. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/aas_http_client.egg-info/SOURCES.txt +0 -0
  18. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/aas_http_client.egg-info/dependency_links.txt +0 -0
  19. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/aas_http_client.egg-info/requires.txt +0 -0
  20. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/aas_http_client.egg-info/top_level.txt +0 -0
  21. {aas_http_client-0.3.2 → aas_http_client-0.3.3}/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.3
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
@@ -561,6 +562,32 @@ class AasHttpClient(BaseModel):
561
562
 
562
563
  return True
563
564
 
565
+ def patch_submodel_element_by_path_value_only_submodel_repo(self, submodel_id: str, submodel_element_path: str, value: str) -> bool:
566
+ """Updates the value of an existing SubmodelElement.
567
+
568
+ :param submodel_id: Encoded ID of the Submodel to update submodel element for
569
+ :param submodel_element_path: Path of the Submodel element to update
570
+ :param value: Submodel element value to update as string
571
+ :return: True if the patch was successful, False otherwise
572
+ """
573
+ decoded_submodel_id: str = decode_base_64(submodel_id)
574
+
575
+ url = f"{self.base_url}/submodels/{decoded_submodel_id}/submodel-elements/{submodel_element_path}/$value"
576
+
577
+ try:
578
+ response = self._session.patch(url, headers=HEADERS, json=value, timeout=self.time_out)
579
+ logger.debug(f"Call REST API url '{response.url}'")
580
+
581
+ if response.status_code != STATUS_CODE_204:
582
+ log_response_errors(response)
583
+ return False
584
+
585
+ except requests.exceptions.RequestException as e:
586
+ logger.error(f"Error call REST API: {e}")
587
+ return False
588
+
589
+ return True
590
+
564
591
 
565
592
  # endregion
566
593
 
@@ -635,8 +662,7 @@ def create_client_by_config(config_file: Path, password: str = "") -> AasHttpCli
635
662
 
636
663
  def _create_client(config_string: str, password) -> AasHttpClient | None:
637
664
  try:
638
- connection_settings = AasHttpClient.model_validate_json(config_string)
639
- client = AasHttpClient(**connection_settings.model_dump())
665
+ client = AasHttpClient.model_validate_json(config_string)
640
666
  except ValidationError as ve:
641
667
  raise ValidationError(f"Invalid BaSyx server connection file: {ve}") from ve
642
668
 
@@ -275,8 +275,19 @@ 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
+
280
291
 
281
292
  # endregion
282
293
 
@@ -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.3
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.3"
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:
@@ -307,42 +327,217 @@ def test_015_get_all_submodel_elements_submodel_repository(wrapper: SdkWrapper,
307
327
  assert submodel_elements is not None
308
328
  assert len(submodel_elements) == 0
309
329
 
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)
330
+ def test_016a_post_submodel_element_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_string: model.Property):
331
+ submodel_element = wrapper.post_submodel_element_submodel_repo(shared_sm.id, shared_sme_string)
312
332
 
313
333
  assert submodel_element is not None
314
334
 
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
335
  assert isinstance(submodel_element, model.Property)
336
+ property: model.Property = submodel_element
337
+ assert property.value == shared_sme_string.value
321
338
 
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", "")
339
+ assert submodel_element.id_short == shared_sme_string.id_short
340
+ assert submodel_element.description.get("en", "") == shared_sme_string.description.get("en", "")
341
+ assert submodel_element.display_name.get("en", "") == shared_sme_string.display_name.get("en", "")
342
+ assert submodel_element.value == shared_sme_string.value
325
343
 
326
344
  submodel_elements = wrapper.get_all_submodel_elements_submodel_repository(shared_sm.id)
327
345
 
328
346
  assert submodel_elements is not None
329
347
  assert len(submodel_elements) == 1
330
348
 
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)
349
+ def test_016b_post_submodel_element_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_bool: model.Property):
350
+ submodel_element = wrapper.post_submodel_element_submodel_repo(shared_sm.id, shared_sme_bool)
333
351
 
334
352
  assert submodel_element is not None
335
353
 
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
354
+ assert isinstance(submodel_element, model.Property)
355
+ property: model.Property = submodel_element
356
+ assert property.value == shared_sme_bool.value
357
+
358
+ assert submodel_element.id_short == shared_sme_bool.id_short
359
+ assert submodel_element.description.get("en", "") == shared_sme_bool.description.get("en", "")
360
+ assert submodel_element.display_name.get("en", "") == shared_sme_bool.display_name.get("en", "")
361
+ assert submodel_element.value == shared_sme_bool.value
362
+
363
+ submodel_elements = wrapper.get_all_submodel_elements_submodel_repository(shared_sm.id)
364
+
365
+ assert submodel_elements is not None
366
+ assert len(submodel_elements) == 2
367
+
368
+ def test_016c_post_submodel_element_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_int: model.Property):
369
+ submodel_element = wrapper.post_submodel_element_submodel_repo(shared_sm.id, shared_sme_int)
370
+
371
+ assert submodel_element is not None
372
+
373
+ assert isinstance(submodel_element, model.Property)
374
+ property: model.Property = submodel_element
375
+ assert property.value == shared_sme_int.value
376
+
377
+ assert submodel_element.id_short == shared_sme_int.id_short
378
+ assert submodel_element.description.get("en", "") == shared_sme_int.description.get("en", "")
379
+ assert submodel_element.display_name.get("en", "") == shared_sme_int.display_name.get("en", "")
380
+ assert submodel_element.value == shared_sme_int.value
381
+
382
+ submodel_elements = wrapper.get_all_submodel_elements_submodel_repository(shared_sm.id)
383
+
384
+ assert submodel_elements is not None
385
+ assert len(submodel_elements) == 3
386
+
387
+ def test_016d_post_submodel_element_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_float: model.Property):
388
+ submodel_element = wrapper.post_submodel_element_submodel_repo(shared_sm.id, shared_sme_float)
389
+
390
+ assert submodel_element is not None
391
+
392
+ assert isinstance(submodel_element, model.Property)
393
+ property: model.Property = submodel_element
394
+ assert property.value == shared_sme_float.value
395
+
396
+ assert submodel_element.id_short == shared_sme_float.id_short
397
+ assert submodel_element.description.get("en", "") == shared_sme_float.description.get("en", "")
398
+ assert submodel_element.display_name.get("en", "") == shared_sme_float.display_name.get("en", "")
399
+ assert submodel_element.value == shared_sme_float.value
400
+
401
+ submodel_elements = wrapper.get_all_submodel_elements_submodel_repository(shared_sm.id)
402
+
403
+ assert submodel_elements is not None
404
+ assert len(submodel_elements) == 4
405
+
406
+ def test_017a_get_submodel_element_by_path_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_string: model.Property):
407
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_string.id_short)
408
+
409
+ assert submodel_element is not None
410
+
411
+ assert isinstance(submodel_element, model.Property)
412
+
413
+ assert submodel_element.id_short == shared_sme_string.id_short
414
+ assert submodel_element.description.get("en", "") == shared_sme_string.description.get("en", "")
415
+ assert submodel_element.display_name.get("en", "") == shared_sme_string.display_name.get("en", "")
416
+ assert submodel_element.value == shared_sme_string.value
417
+
418
+ def test_017b_get_submodel_element_by_path_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_bool: model.Property):
419
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_bool.id_short)
420
+
421
+ assert submodel_element is not None
422
+
423
+ assert isinstance(submodel_element, model.Property)
424
+
425
+ assert submodel_element.id_short == shared_sme_bool.id_short
426
+ assert submodel_element.description.get("en", "") == shared_sme_bool.description.get("en", "")
427
+ assert submodel_element.display_name.get("en", "") == shared_sme_bool.display_name.get("en", "")
428
+ assert submodel_element.value == shared_sme_bool.value
429
+
430
+ def test_017c_get_submodel_element_by_path_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_int: model.Property):
431
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_int.id_short)
432
+
433
+ assert submodel_element is not None
340
434
 
341
435
  assert isinstance(submodel_element, model.Property)
342
436
 
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", "")
437
+ assert submodel_element.id_short == shared_sme_int.id_short
438
+ assert submodel_element.description.get("en", "") == shared_sme_int.description.get("en", "")
439
+ assert submodel_element.display_name.get("en", "") == shared_sme_int.display_name.get("en", "")
440
+ assert submodel_element.value == shared_sme_int.value
441
+
442
+ def test_017d_get_submodel_element_by_path_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_float: model.Property):
443
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_float.id_short)
444
+
445
+ assert submodel_element is not None
446
+
447
+ assert isinstance(submodel_element, model.Property)
448
+
449
+ assert submodel_element.id_short == shared_sme_float.id_short
450
+ assert submodel_element.description.get("en", "") == shared_sme_float.description.get("en", "")
451
+ assert submodel_element.display_name.get("en", "") == shared_sme_float.display_name.get("en", "")
452
+ assert submodel_element.value == shared_sme_float.value
453
+
454
+ def test_018a_patch_submodel_element_by_path_value_only_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_string: model.Property):
455
+ new_value = "Patched String Value"
456
+ result = wrapper.patch_submodel_element_by_path_value_only_submodel_repo(shared_sm.id, shared_sme_string.id_short, new_value)
457
+
458
+ parsed = urlparse(wrapper.base_url)
459
+ if int(parsed.port) in PYTHON_SERVER_PORTS:
460
+ # NOTE: python server do not provide this endpoint
461
+ assert result is False
462
+ else:
463
+ assert result is True
464
+
465
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_string.id_short)
466
+
467
+ assert submodel_element is not None
468
+ assert submodel_element.id_short == shared_sme_string.id_short
469
+ assert submodel_element.description.get("en", "") == shared_sme_string.description.get("en", "")
470
+ assert submodel_element.display_name.get("en", "") == shared_sme_string.display_name.get("en", "")
471
+
472
+ assert isinstance(submodel_element, model.Property)
473
+ property: model.Property = submodel_element
474
+ assert property.value == new_value
475
+
476
+ def test_018b_patch_submodel_element_by_path_value_only_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_bool: model.Property):
477
+ new_value = "false"
478
+ result = wrapper.patch_submodel_element_by_path_value_only_submodel_repo(shared_sm.id, shared_sme_bool.id_short, new_value)
479
+
480
+ parsed = urlparse(wrapper.base_url)
481
+ if int(parsed.port) in PYTHON_SERVER_PORTS:
482
+ # NOTE: python server do not provide this endpoint
483
+ assert result is False
484
+ else:
485
+ assert result is True
486
+
487
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_bool.id_short)
488
+
489
+ assert submodel_element is not None
490
+ assert submodel_element.id_short == shared_sme_bool.id_short
491
+ assert submodel_element.description.get("en", "") == shared_sme_bool.description.get("en", "")
492
+ assert submodel_element.display_name.get("en", "") == shared_sme_bool.display_name.get("en", "")
493
+
494
+ assert isinstance(submodel_element, model.Property)
495
+ property: model.Property = submodel_element
496
+ assert property.value == json.loads(new_value)
497
+
498
+ def test_018c_patch_submodel_element_by_path_value_only_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_int: model.Property):
499
+ new_value = "263"
500
+ result = wrapper.patch_submodel_element_by_path_value_only_submodel_repo(shared_sm.id, shared_sme_int.id_short, new_value)
501
+
502
+ parsed = urlparse(wrapper.base_url)
503
+ if int(parsed.port) in PYTHON_SERVER_PORTS:
504
+ # NOTE: python server do not provide this endpoint
505
+ assert result is False
506
+ else:
507
+ assert result is True
508
+
509
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_int.id_short)
510
+
511
+ assert submodel_element is not None
512
+ assert submodel_element.id_short == shared_sme_int.id_short
513
+ assert submodel_element.description.get("en", "") == shared_sme_int.description.get("en", "")
514
+ assert submodel_element.display_name.get("en", "") == shared_sme_int.display_name.get("en", "")
515
+
516
+ assert isinstance(submodel_element, model.Property)
517
+ property: model.Property = submodel_element
518
+ assert property.value == int(new_value)
519
+
520
+ def test_018d_patch_submodel_element_by_path_value_only_submodel_repo(wrapper: SdkWrapper, shared_sm: model.Submodel, shared_sme_float: model.Property):
521
+ new_value = "262.1"
522
+ result = wrapper.patch_submodel_element_by_path_value_only_submodel_repo(shared_sm.id, shared_sme_float.id_short, new_value)
523
+
524
+ parsed = urlparse(wrapper.base_url)
525
+ if int(parsed.port) in PYTHON_SERVER_PORTS:
526
+ # NOTE: python server do not provide this endpoint
527
+ assert result is False
528
+ else:
529
+ assert result is True
530
+
531
+ submodel_element = wrapper.get_submodel_element_by_path_submodel_repo(shared_sm.id, shared_sme_float.id_short)
532
+
533
+ assert submodel_element is not None
534
+ assert submodel_element.id_short == shared_sme_float.id_short
535
+ assert submodel_element.description.get("en", "") == shared_sme_float.description.get("en", "")
536
+ assert submodel_element.display_name.get("en", "") == shared_sme_float.display_name.get("en", "")
537
+
538
+ assert isinstance(submodel_element, model.Property)
539
+ property: model.Property = submodel_element
540
+ assert property.value == float(new_value)
346
541
 
347
542
  def test_098_delete_asset_administration_shell_by_id(wrapper: SdkWrapper, shared_aas: model.AssetAdministrationShell):
348
543
  result = wrapper.delete_asset_administration_shell_by_id(shared_aas.id)
File without changes