shellsmith 0.1.0__tar.gz → 0.2.1__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 (37) hide show
  1. {shellsmith-0.1.0/src/shellsmith.egg-info → shellsmith-0.2.1}/PKG-INFO +7 -1
  2. {shellsmith-0.1.0 → shellsmith-0.2.1}/README.md +4 -0
  3. {shellsmith-0.1.0 → shellsmith-0.2.1}/pyproject.toml +5 -1
  4. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/__init__.py +1 -1
  5. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/cli/commands/__init__.py +1 -0
  6. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/cli/commands/info.py +10 -5
  7. shellsmith-0.2.1/src/shellsmith/cli/commands/sme.py +13 -0
  8. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/cli/main.py +22 -4
  9. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/cli/parser.py +35 -1
  10. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/config.py +5 -1
  11. shellsmith-0.2.1/src/shellsmith/neo4j.py +115 -0
  12. {shellsmith-0.1.0 → shellsmith-0.2.1/src/shellsmith.egg-info}/PKG-INFO +7 -1
  13. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith.egg-info/SOURCES.txt +3 -0
  14. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith.egg-info/requires.txt +3 -0
  15. shellsmith-0.2.1/tests/test_neo4j.py +138 -0
  16. {shellsmith-0.1.0 → shellsmith-0.2.1}/LICENSE +0 -0
  17. {shellsmith-0.1.0 → shellsmith-0.2.1}/setup.cfg +0 -0
  18. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/__main__.py +0 -0
  19. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/cli/__init__.py +0 -0
  20. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/cli/commands/nuke.py +0 -0
  21. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/cli/commands/shell.py +0 -0
  22. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/cli/commands/submodel.py +0 -0
  23. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/cli/commands/upload.py +0 -0
  24. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/crud/__init__.py +0 -0
  25. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/crud/shells.py +0 -0
  26. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/crud/submodels.py +0 -0
  27. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/services.py +0 -0
  28. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/upload.py +0 -0
  29. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith/utils.py +0 -0
  30. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith.egg-info/dependency_links.txt +0 -0
  31. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith.egg-info/entry_points.txt +0 -0
  32. {shellsmith-0.1.0 → shellsmith-0.2.1}/src/shellsmith.egg-info/top_level.txt +0 -0
  33. {shellsmith-0.1.0 → shellsmith-0.2.1}/tests/test_cli.py +0 -0
  34. {shellsmith-0.1.0 → shellsmith-0.2.1}/tests/test_cli_integration.py +0 -0
  35. {shellsmith-0.1.0 → shellsmith-0.2.1}/tests/test_crud.py +0 -0
  36. {shellsmith-0.1.0 → shellsmith-0.2.1}/tests/test_upload.py +0 -0
  37. {shellsmith-0.1.0 → shellsmith-0.2.1}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shellsmith
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Summary: A Python toolkit and CLI for managing Asset Administration Shells
5
5
  Author-email: Peter Stein <peterstein@dfki.de>
6
6
  License: MIT License
@@ -41,6 +41,8 @@ Requires-Dist: isort; extra == "test"
41
41
  Requires-Dist: pytest; extra == "test"
42
42
  Requires-Dist: pytest-cov; extra == "test"
43
43
  Requires-Dist: pytest-dotenv; extra == "test"
44
+ Provides-Extra: neo4j
45
+ Requires-Dist: neo4j; extra == "neo4j"
44
46
  Dynamic: license-file
45
47
 
46
48
  [![Python Package](https://github.com/ptrstn/shellsmith/actions/workflows/python-package.yaml/badge.svg)](https://github.com/ptrstn/shellsmith/actions/workflows/python-package.yaml)
@@ -92,8 +94,12 @@ Common commands:
92
94
  ```bash
93
95
  aas info # Show all shells and submodels
94
96
  aas upload <file|folder> # Upload AAS file or folder
97
+
95
98
  aas shell delete <id> # Delete a shell
96
99
  aas submodel delete <id> # Delete a submodel
100
+
101
+ aas sme get <id> <path> # Get Submodel element value
102
+ aas sme patch <id> <path> <new_value> # Set Submodel element value
97
103
  ```
98
104
 
99
105
  Use `--cascade` or `--unlink` to control deletion behavior:
@@ -47,8 +47,12 @@ Common commands:
47
47
  ```bash
48
48
  aas info # Show all shells and submodels
49
49
  aas upload <file|folder> # Upload AAS file or folder
50
+
50
51
  aas shell delete <id> # Delete a shell
51
52
  aas submodel delete <id> # Delete a submodel
53
+
54
+ aas sme get <id> <path> # Get Submodel element value
55
+ aas sme patch <id> <path> <new_value> # Set Submodel element value
52
56
  ```
53
57
 
54
58
  Use `--cascade` or `--unlink` to control deletion behavior:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "shellsmith"
7
- version = "0.1.0"
7
+ version = "0.2.1"
8
8
  description = "A Python toolkit and CLI for managing Asset Administration Shells"
9
9
  authors = [{ name = "Peter Stein", email = "peterstein@dfki.de" }]
10
10
  license = { file = "LICENSE" }
@@ -29,6 +29,10 @@ test = [
29
29
  "pytest-dotenv",
30
30
  ]
31
31
 
32
+ neo4j = [
33
+ "neo4j",
34
+ ]
35
+
32
36
  [project.scripts]
33
37
  aas = "shellsmith.cli.main:main"
34
38
 
@@ -1,4 +1,4 @@
1
- __version__ = "0.1.0"
1
+ __version__ = "0.2.1"
2
2
 
3
3
  from .crud.shells import ( # noqa: F401
4
4
  delete_shell,
@@ -2,4 +2,5 @@ from .info import info # noqa: F401
2
2
  from .nuke import nuke # noqa: F401
3
3
  from .shell import shell_delete # noqa: F401
4
4
  from .submodel import submodel_delete # noqa: F401
5
+ from .sme import submodel_element_get, submodel_element_patch # noqa: F401
5
6
  from .upload import upload # noqa: F401
@@ -17,21 +17,25 @@ def print_unreferenced_submodels():
17
17
  print("⚠️ Unreferenced Submodels:")
18
18
  for submodel_id in submodel_ids:
19
19
  submodel = shellsmith.get_submodel(submodel_id)
20
- id_short = submodel["idShort"]
20
+ id_short = submodel.get("idShort", "<no idShort>")
21
21
  print(f"- {id_short} ({submodel_id})")
22
22
 
23
23
 
24
24
  def print_shells_tree():
25
25
  shells = shellsmith.get_shells()
26
26
  for shell in shells:
27
- print(f"{shell['idShort']}: {shell['id']}")
27
+ shell_id = shell['id']
28
+ shell_id_short = shell.get('idShort', "<no idShort>")
29
+ print(f"{shell_id_short}: {shell_id}")
28
30
 
29
- submodels = services.get_shell_submodels(shell["id"])
31
+ submodels = services.get_shell_submodels(shell_id)
30
32
 
31
33
  for i, submodel in enumerate(submodels):
32
34
  is_last = i == len(submodels) - 1
33
35
  prefix = "└──" if is_last else "├──"
34
- print(f"{prefix} {submodel['idShort']}: {submodel['id']}")
36
+ submodel_id = submodel['id']
37
+ submodel_id_short = submodel.get('idShort', "<no idShort>")
38
+ print(f"{prefix} {submodel_id}: {submodel_id_short}")
35
39
 
36
40
 
37
41
  def print_dangling_submodel_refs():
@@ -42,6 +46,7 @@ def print_dangling_submodel_refs():
42
46
  print("⚠️ Dangling Submodel References:")
43
47
  for shell_id, submodel_ids in dangling.items():
44
48
  shell = shellsmith.get_shell(shell_id)
45
- print(f"- {shell['idShort']}: {shell_id}")
49
+ shell_id_short = shell.get('idShort', "<no idShort>")
50
+ print(f"- {shell_id_short}: {shell_id}")
46
51
  for submodel_id in submodel_ids:
47
52
  print(f" └── {submodel_id}")
@@ -0,0 +1,13 @@
1
+ import shellsmith
2
+
3
+
4
+ def submodel_element_get(submodel_id: str, id_short_path: str):
5
+ print(f"{submodel_id} -> {id_short_path}:")
6
+ element = shellsmith.get_submodel_element(submodel_id, id_short_path)
7
+ value = element.get("value")
8
+ print(value)
9
+
10
+
11
+ def submodel_element_patch(submodel_id: str, id_short_path: str, value: str):
12
+ shellsmith.patch_submodel_element_value(submodel_id, id_short_path, value)
13
+ print(f"✅ Updated '{id_short_path}' in Submodel '{submodel_id}'")
@@ -3,20 +3,28 @@ import requests
3
3
  from shellsmith import __version__, services
4
4
  from shellsmith.config import config
5
5
 
6
- from .commands import info, nuke, shell_delete, submodel_delete, upload
6
+ from .commands import (
7
+ info,
8
+ nuke,
9
+ shell_delete,
10
+ submodel_delete,
11
+ submodel_element_get,
12
+ submodel_element_patch,
13
+ upload,
14
+ )
7
15
  from .parser import build_parser
16
+ from ..utils import base64_decode, base64_encode
8
17
 
9
18
 
10
19
  def print_header():
11
20
  print("===============================================")
12
- print(f"Shellsmith - AAS Toolkit v{__version__}")
13
- print(f"Host: {config.host} ({services.health()})")
21
+ print(f" Shellsmith - AAS Toolkit v{__version__}")
22
+ print(f" Host: {config.host} ({services.health()})")
14
23
  print("===============================================")
15
24
  print()
16
25
 
17
26
 
18
27
  def main():
19
- print_header()
20
28
  parser = build_parser()
21
29
  args = parser.parse_args()
22
30
 
@@ -26,6 +34,12 @@ def main():
26
34
  "nuke": lambda _args: nuke(),
27
35
  "shell.delete": lambda _args: shell_delete(args.id, cascade=args.cascade),
28
36
  "submodel.delete": lambda _args: submodel_delete(args.id, unlink=args.unlink),
37
+ "sme.get": lambda _args: submodel_element_get(args.id, args.path),
38
+ "sme.patch": lambda _args: submodel_element_patch(
39
+ args.id, args.path, args.value
40
+ ),
41
+ "encode": lambda _args: print(base64_encode(args.id)),
42
+ "decode": lambda _args: print(base64_decode(args.value)),
29
43
  }
30
44
 
31
45
  try:
@@ -34,9 +48,13 @@ def main():
34
48
  key += f".{args.shell_command}"
35
49
  elif key == "submodel" and args.submodel_command:
36
50
  key += f".{args.submodel_command}"
51
+ elif key == "sme" and args.submodel_element_command:
52
+ key += f".{args.submodel_element_command}"
37
53
 
38
54
  handler = commands.get(key)
39
55
  if handler:
56
+ if key not in ("encode", "decode"):
57
+ print_header()
40
58
  handler(args)
41
59
  else:
42
60
  parser.print_help()
@@ -26,6 +26,7 @@ def build_parser():
26
26
  # ──────────────────────────── shell ─────────────────────────────
27
27
  shell_parser = subparsers.add_parser(
28
28
  "shell",
29
+ aliases=["sh"],
29
30
  help="Manage Asset Administration Shells",
30
31
  )
31
32
  shell_subparsers = shell_parser.add_subparsers(dest="shell_command")
@@ -42,7 +43,9 @@ def build_parser():
42
43
  )
43
44
 
44
45
  # ───────────────────────────── submodel ─────────────────────────────
45
- submodel_parser = subparsers.add_parser("submodel", help="Manage Submodels")
46
+ submodel_parser = subparsers.add_parser(
47
+ "submodel", aliases=["sm"], help="Manage Submodels"
48
+ )
46
49
  submodel_subparsers = submodel_parser.add_subparsers(dest="submodel_command")
47
50
  submodel_delete_parser = submodel_subparsers.add_parser(
48
51
  "delete",
@@ -60,4 +63,35 @@ def build_parser():
60
63
  help="Remove all Shell references to this Submodel",
61
64
  )
62
65
 
66
+ # ───────────────────── submodel-element ─────────────────────
67
+ sme_parser = subparsers.add_parser(
68
+ "submodel-element",
69
+ aliases=["sme"],
70
+ help="Manage Submodel Elements",
71
+ )
72
+ sme_subparsers = sme_parser.add_subparsers(dest="submodel_element_command")
73
+
74
+ sme_get_parser = sme_subparsers.add_parser(
75
+ "get",
76
+ help="Get value of a Submodel Element",
77
+ )
78
+ sme_get_parser.add_argument("id", type=str, help="Submodel ID")
79
+ sme_get_parser.add_argument("path", type=str, help="idShort path")
80
+
81
+ sme_patch_parser = sme_subparsers.add_parser(
82
+ "patch",
83
+ help="Patch value of a Submodel Element",
84
+ )
85
+ sme_patch_parser.add_argument("id", type=str, help="Submodel ID")
86
+ sme_patch_parser.add_argument("path", type=str, help="idShort path")
87
+ sme_patch_parser.add_argument("value", type=str, help="New value")
88
+
89
+ # ───────────────────────────── encode ─────────────────────────────
90
+ encode_parser = subparsers.add_parser("encode", help="Encode a string to base64")
91
+ encode_parser.add_argument("id", type=str, help="Text to encode")
92
+
93
+ # ───────────────────────────── decode ─────────────────────────────
94
+ decode_parser = subparsers.add_parser("decode", help="Decode a base64 string")
95
+ decode_parser.add_argument("value", type=str, help="Base64 string to decode")
96
+
63
97
  return parser
@@ -9,7 +9,11 @@ class Settings(BaseSettings):
9
9
  def host(self):
10
10
  return self.basyx_env_host
11
11
 
12
- model_config = SettingsConfigDict(env_file=".env", env_prefix="SHELLSMITH_")
12
+ model_config = SettingsConfigDict(
13
+ env_file=".env",
14
+ env_prefix="SHELLSMITH_",
15
+ extra="ignore",
16
+ )
13
17
 
14
18
 
15
19
  config = Settings()
@@ -0,0 +1,115 @@
1
+ from typing import Any, Dict, List, Optional
2
+
3
+ from neo4j import Driver, GraphDatabase
4
+
5
+ from shellsmith.config import config
6
+
7
+ _driver: Optional[Driver] = None
8
+
9
+
10
+ def get_driver() -> Driver:
11
+ global _driver
12
+ if _driver is None:
13
+ _driver = GraphDatabase.driver(config.neo4j_uri, auth=None)
14
+ return _driver
15
+
16
+
17
+ def close_driver():
18
+ global _driver
19
+ if _driver is not None:
20
+ _driver.close()
21
+ _driver = None
22
+
23
+
24
+ ##################
25
+ # Shells
26
+ ##################
27
+
28
+
29
+ def get_shells() -> List[Dict[str, Any]]:
30
+ query = """
31
+ MATCH (shell:AssetAdministrationShell)
32
+ RETURN shell;
33
+ """
34
+ with get_driver().session() as session:
35
+ result = session.run(query)
36
+ shells = [dict(record["shell"]) for record in result]
37
+ return shells
38
+
39
+
40
+ def get_shell(shell_id: str) -> Optional[Dict[str, Any]]:
41
+ query = """
42
+ MATCH (shell:AssetAdministrationShell {id: $shell_id})
43
+ RETURN shell;
44
+ """
45
+ with get_driver().session() as session:
46
+ result = session.run(query, shell_id=shell_id)
47
+ record = result.single()
48
+ return dict(record["shell"]) if record else None
49
+
50
+
51
+ ##################
52
+ # Submodels
53
+ ##################
54
+
55
+
56
+ def get_submodels() -> List[Dict[str, Any]]:
57
+ query = """
58
+ MATCH (submodel:Submodel)
59
+ RETURN submodel
60
+ """
61
+ with get_driver().session() as session:
62
+ result = session.run(query)
63
+ submodels = [dict(record["submodel"]) for record in result]
64
+ return submodels
65
+
66
+
67
+ def get_submodel(submodel_id: str) -> Dict[str, Any]:
68
+ query = """
69
+ MATCH (submodel:Submodel {id: $submodel_id})
70
+ RETURN submodel
71
+ """
72
+ with get_driver().session() as session:
73
+ result = session.run(query, submodel_id=submodel_id)
74
+ record = result.single()
75
+ return dict(record["submodel"]) if record else None
76
+
77
+
78
+ def get_submodel_elements(submodel_id: str) -> List[Dict[str, Any]]:
79
+ query = """
80
+ MATCH (sme:SubmodelElement {smId: $submodel_id})
81
+ RETURN sme;
82
+ """
83
+ with get_driver().session() as session:
84
+ result = session.run(query, submodel_id=submodel_id)
85
+ return [dict(record["sme"]) for record in result]
86
+
87
+
88
+ def get_submodel_element(
89
+ submodel_id: str, id_short_path: str
90
+ ) -> Optional[Dict[str, Any]]:
91
+ query = """
92
+ MATCH (sme:SubmodelElement {smId: $submodel_id, idShortPath: $id_short_path})
93
+ RETURN sme;
94
+ """
95
+ with get_driver().session() as session:
96
+ result = session.run(
97
+ query,
98
+ submodel_id=submodel_id,
99
+ id_short_path=id_short_path,
100
+ )
101
+ record = result.single()
102
+ return dict(record["sme"]) if record else None
103
+
104
+
105
+ def detach_delete_all():
106
+ """
107
+ Dangerous!
108
+ Deletes all nodes and relationships in the graph.
109
+ """
110
+ query = """
111
+ MATCH (n)
112
+ DETACH DELETE n;
113
+ """
114
+ with get_driver().session() as session:
115
+ session.run(query)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shellsmith
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Summary: A Python toolkit and CLI for managing Asset Administration Shells
5
5
  Author-email: Peter Stein <peterstein@dfki.de>
6
6
  License: MIT License
@@ -41,6 +41,8 @@ Requires-Dist: isort; extra == "test"
41
41
  Requires-Dist: pytest; extra == "test"
42
42
  Requires-Dist: pytest-cov; extra == "test"
43
43
  Requires-Dist: pytest-dotenv; extra == "test"
44
+ Provides-Extra: neo4j
45
+ Requires-Dist: neo4j; extra == "neo4j"
44
46
  Dynamic: license-file
45
47
 
46
48
  [![Python Package](https://github.com/ptrstn/shellsmith/actions/workflows/python-package.yaml/badge.svg)](https://github.com/ptrstn/shellsmith/actions/workflows/python-package.yaml)
@@ -92,8 +94,12 @@ Common commands:
92
94
  ```bash
93
95
  aas info # Show all shells and submodels
94
96
  aas upload <file|folder> # Upload AAS file or folder
97
+
95
98
  aas shell delete <id> # Delete a shell
96
99
  aas submodel delete <id> # Delete a submodel
100
+
101
+ aas sme get <id> <path> # Get Submodel element value
102
+ aas sme patch <id> <path> <new_value> # Set Submodel element value
97
103
  ```
98
104
 
99
105
  Use `--cascade` or `--unlink` to control deletion behavior:
@@ -4,6 +4,7 @@ pyproject.toml
4
4
  src/shellsmith/__init__.py
5
5
  src/shellsmith/__main__.py
6
6
  src/shellsmith/config.py
7
+ src/shellsmith/neo4j.py
7
8
  src/shellsmith/services.py
8
9
  src/shellsmith/upload.py
9
10
  src/shellsmith/utils.py
@@ -20,6 +21,7 @@ src/shellsmith/cli/commands/__init__.py
20
21
  src/shellsmith/cli/commands/info.py
21
22
  src/shellsmith/cli/commands/nuke.py
22
23
  src/shellsmith/cli/commands/shell.py
24
+ src/shellsmith/cli/commands/sme.py
23
25
  src/shellsmith/cli/commands/submodel.py
24
26
  src/shellsmith/cli/commands/upload.py
25
27
  src/shellsmith/crud/__init__.py
@@ -28,5 +30,6 @@ src/shellsmith/crud/submodels.py
28
30
  tests/test_cli.py
29
31
  tests/test_cli_integration.py
30
32
  tests/test_crud.py
33
+ tests/test_neo4j.py
31
34
  tests/test_upload.py
32
35
  tests/test_utils.py
@@ -1,6 +1,9 @@
1
1
  pydantic-settings
2
2
  requests
3
3
 
4
+ [neo4j]
5
+ neo4j
6
+
4
7
  [test]
5
8
  black
6
9
  flake8
@@ -0,0 +1,138 @@
1
+ import os
2
+ import time
3
+
4
+ import pytest
5
+
6
+ if not os.getenv("SHELLSMITH_NEO4J_ENABLED"):
7
+ pytest.skip(
8
+ reason="Skipping Neo4j tests. Set SHELLSMITH_NEO4J_ENABLED=1 to enable.",
9
+ allow_module_level=True,
10
+ )
11
+
12
+ from shellsmith import neo4j, services
13
+ from shellsmith.upload import upload_aas_folder
14
+
15
+
16
+ GRAPH_READY_TIMEOUT = 45 # seconds
17
+ EXPECTED_NODE_COUNT = 39
18
+ EXPECTED_SUBMODEL_ELEMENT_COUNT = 17 # or whatever your total is
19
+
20
+
21
+ def wait_for_graph_node_count(
22
+ expected_count: int = EXPECTED_NODE_COUNT,
23
+ timeout: int = GRAPH_READY_TIMEOUT,
24
+ ) -> (bool, int):
25
+ query = "MATCH (n) RETURN count(n) AS count"
26
+ start = time.time()
27
+
28
+ last_count = 0
29
+
30
+ while True:
31
+ try:
32
+ with neo4j.get_driver().session() as session:
33
+ result = session.run(query)
34
+ record = result.single()
35
+ count = record["count"]
36
+ last_count = count
37
+ if record and count == expected_count:
38
+ return True, last_count
39
+ except Exception: # noqa
40
+ pass # wait and retry
41
+
42
+ if time.time() - start > timeout:
43
+ return False, last_count
44
+
45
+ time.sleep(0.5)
46
+
47
+
48
+ def test_wait_for_graph():
49
+ # neo4j.detach_delete_all()
50
+ services.delete_all_shells()
51
+ services.delete_all_submodels()
52
+ success, count = wait_for_graph_node_count(0)
53
+ assert success, f"Graph was not fully destructed within timeout: {count}"
54
+
55
+ upload_aas_folder("aas")
56
+ success, count = wait_for_graph_node_count(39)
57
+ assert success, f"Graph was not fully built within timeout: {count}"
58
+ time.sleep(1)
59
+
60
+
61
+ def test_get_shells(semitrailer, workpiece_carrier_a1):
62
+ shells = neo4j.get_shells()
63
+ assert len(shells) == 2
64
+
65
+ shell_id_shorts = {shell["idShort"] for shell in shells}
66
+ shell_ids = {shell["id"] for shell in shells}
67
+ assert semitrailer.id in shell_ids
68
+ assert workpiece_carrier_a1.id in shell_ids
69
+ assert semitrailer.id_short in shell_id_shorts
70
+ assert workpiece_carrier_a1.id_short in shell_id_shorts
71
+
72
+
73
+ def test_get_shell(
74
+ semitrailer,
75
+ workpiece_carrier_a1,
76
+ ):
77
+ shell = neo4j.get_shell(semitrailer.id)
78
+ assert shell["id"] == semitrailer.id
79
+ assert shell["idShort"] == semitrailer.id_short
80
+
81
+ shell = neo4j.get_shell(workpiece_carrier_a1.id)
82
+ assert shell["id"] == workpiece_carrier_a1.id
83
+ assert shell["idShort"] == workpiece_carrier_a1.id_short
84
+
85
+
86
+ def test_get_submodels(semitrailer, workpiece_carrier_a1):
87
+ submodels = neo4j.get_submodels()
88
+ assert len(submodels) == 4
89
+
90
+
91
+ def test_get_submodel(
92
+ semitrailer,
93
+ workpiece_carrier_a1,
94
+ ):
95
+ submodel = neo4j.get_submodel(semitrailer.product_identification.id)
96
+ assert submodel["idShort"] == semitrailer.product_identification.id_short
97
+
98
+ submodel = neo4j.get_submodel(semitrailer.production_plan.id)
99
+ assert submodel["idShort"] == semitrailer.production_plan.id_short
100
+
101
+ submodel = neo4j.get_submodel(workpiece_carrier_a1.good_information.id)
102
+ assert submodel["idShort"] == workpiece_carrier_a1.good_information.id_short
103
+
104
+ submodel = neo4j.get_submodel(workpiece_carrier_a1.asset_location.id)
105
+ assert submodel["idShort"] == workpiece_carrier_a1.asset_location.id_short
106
+
107
+
108
+ def test_get_submodel_elements(semitrailer, workpiece_carrier_a1):
109
+ elements = neo4j.get_submodel_elements(semitrailer.product_identification.id)
110
+ assert len(elements) == 2
111
+ id_shorts = {el["idShort"] for el in elements}
112
+ assert "Identifier" in id_shorts
113
+ assert "ProductName" in id_shorts
114
+
115
+ elements = neo4j.get_submodel_elements(workpiece_carrier_a1.good_information.id)
116
+ assert len(elements) == 7
117
+ id_shorts = {el["idShort"] for el in elements}
118
+ assert "CurrentProduct" in id_shorts
119
+ assert "ListTransportableProducts" in id_shorts
120
+ assert "ProductName" in id_shorts
121
+
122
+
123
+ def test_get_submodel_element(semitrailer, workpiece_carrier_a1):
124
+ element = neo4j.get_submodel_element(
125
+ semitrailer.product_identification.id, "ProductName"
126
+ )
127
+ assert element["idShort"] == "ProductName"
128
+ assert element["value"] == "Semitrailer"
129
+
130
+ element = neo4j.get_submodel_element(
131
+ workpiece_carrier_a1.asset_location.id, "CurrentFences[0].FenceName"
132
+ )
133
+ assert element["idShort"] == "FenceName"
134
+ assert element["value"] == "TSN-Module"
135
+
136
+
137
+ def test_close_driver():
138
+ neo4j.close_driver()
File without changes
File without changes
File without changes