testbench2robotframework 0.9.2b5__tar.gz → 0.9.2b7__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 (61) hide show
  1. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/PKG-INFO +1 -1
  2. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/__init__.py +1 -1
  3. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/cli.py +11 -3
  4. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/model.py +1 -4
  5. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/model_utils.py +5 -26
  6. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/result_writer.py +1 -0
  7. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/robotframework2testbench.py +4 -0
  8. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/testbench2robotframework.py +7 -1
  9. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/utils.py +49 -0
  10. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/.gitignore +0 -0
  11. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/DEVELOPMENT.md +0 -0
  12. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/ExampleConfiguration/json_config.json +0 -0
  13. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/ExampleConfiguration/pyproject_example.toml +0 -0
  14. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/ExampleConfiguration/toml_config.toml +0 -0
  15. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/LICENSE +0 -0
  16. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/MANIFEST.in +0 -0
  17. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/README.md +0 -0
  18. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/README_old.md +0 -0
  19. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/atest/json_config_tests/1_tfs.robot +0 -0
  20. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/atest/robot/libs/json_config.py +0 -0
  21. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/atest/robot/libs/pyproject_config.py +0 -0
  22. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/atest/robot/resources/file_management.resource +0 -0
  23. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/atest/robot/resources/testbench2robotframework_cli.resource +0 -0
  24. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/atest/robot/rf_tests/cli_interface/write/json_config.robot +0 -0
  25. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/atest/robot/rf_tests/cli_interface/write/no_config_argument.robot +0 -0
  26. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/atest/robot/rf_tests/cli_interface/write/toml_config.robot +0 -0
  27. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/create_json_schema.py +0 -0
  28. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/docs/configuration/_category_.json +0 -0
  29. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/docs/configuration/cli_options.md +0 -0
  30. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/docs/configuration/overview.md +0 -0
  31. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/docs/configuration/pyproject_config.md +0 -0
  32. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/docs/getting_started/_category_.json +0 -0
  33. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/docs/getting_started/installation.md +0 -0
  34. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/docs/getting_started/quick_start.md +0 -0
  35. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/docs/intro.md +0 -0
  36. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/docs/usage/_category_.json +0 -0
  37. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/docs/usage/fetch_results.md +0 -0
  38. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/docs/usage/generate_tests.md +0 -0
  39. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/images/LibrarySubdivision.PNG +0 -0
  40. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/images/Unbenannt.PNG +0 -0
  41. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/images/generated.png +0 -0
  42. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/images/libraries.PNG +0 -0
  43. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/images/resources.PNG +0 -0
  44. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/images/rfLibraryRootsTestBench.PNG +0 -0
  45. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/images/testbench_rfLibraryRegex.PNG +0 -0
  46. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/images/testbench_rfResourceRegex.PNG +0 -0
  47. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/images/testthemen.PNG +0 -0
  48. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/pyproject.toml +0 -0
  49. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/requirements.txt +0 -0
  50. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/robot.toml +0 -0
  51. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/tasks.py +0 -0
  52. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench-tools.zip +0 -0
  53. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/__main__.py +0 -0
  54. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/config.py +0 -0
  55. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/execution_artifacts.py +0 -0
  56. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/html_parser.py +0 -0
  57. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/json_reader.py +0 -0
  58. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/json_writer.py +0 -0
  59. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/log.py +0 -0
  60. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/testbench2rf.py +0 -0
  61. {testbench2robotframework-0.9.2b5 → testbench2robotframework-0.9.2b7}/testbench2robotframework/testsuite_write.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: testbench2robotframework
3
- Version: 0.9.2b5
3
+ Version: 0.9.2b7
4
4
  Summary: Robot Framework Code Generator from Keyword-Driven Tests in imbus TestBench 3.0 and newer
5
5
  Author-email: imbus AG <support@imbus.de>
6
6
  Requires-Python: >= 3.10
@@ -17,4 +17,4 @@ suites and enhancing the TestBench report with execution results from Robot Fram
17
17
 
18
18
  from .testbench2robotframework import testbench2robotframework # noqa: F401
19
19
 
20
- __version__ = "0.9.2b5"
20
+ __version__ = "0.9.2b7"
@@ -21,10 +21,17 @@ from .config import (
21
21
  )
22
22
  from .json_reader import read_json
23
23
  from .testbench2robotframework import testbench2robotframework
24
+ from .utils import ALLOWED_SERVER_VERSIONS
24
25
 
25
- TESTBENCH2ROBOTFRAMEWORK_DESCRIPTION = """TestBench2RobotFramework converts a TestBench JSON-report
26
+ TESTBENCH2ROBOTFRAMEWORK_DESCRIPTION = (
27
+ """TestBench2RobotFramework converts a TestBench JSON-report
26
28
  to Robot Framework test suites and enhances the TestBench Report
27
- with the execution results provided by Robot Framework."""
29
+ with the execution results provided by Robot Framework. The version your TestBench report
30
+ was generated with must be compatible with the version of testbench2robotframework you are using.
31
+ Supported versions for this version of testbench2robotframework are: """
32
+ + ", ".join(ALLOWED_SERVER_VERSIONS)
33
+ + "."
34
+ )
28
35
  GENERATE_HELP = """Command to convert a TestBench JSON-report to Robot Framework test suites."""
29
36
  FETCH_HELP = """Command to fetch execution results from a Robot Framework result XML and
30
37
  to write the results to a TestBench JSON-report."""
@@ -56,7 +63,8 @@ def parse_subdivision_mapping(
56
63
  help="Writes the TestBench2RobotFramework, Robot Framework and Python version to console.",
57
64
  message=(
58
65
  f"TestBench2RobotFramework {__version__} with "
59
- f"Robot Framework {robot.version.get_full_version()}"
66
+ f"Robot Framework {robot.version.get_full_version()}. "
67
+ f"Compatible with TestBench server versions: {', '.join(ALLOWED_SERVER_VERSIONS)}."
60
68
  ),
61
69
  )
62
70
  @click.help_option("-h", "--help")
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: openapi.yml
3
- # timestamp: 2026-05-20T15:22:23+00:00
3
+ # timestamp: 2026-05-21T13:56:04+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1562,9 +1562,6 @@ class TestStructureTreeNode:
1562
1562
  class RootNode(TestStructureTreeNode):
1563
1563
  base: TestStructureItemBaseInformation
1564
1564
  filters: list[AttachedFilter]
1565
- spec: TestStructureItemSpecification | None = None
1566
- aut: TestStructureAutomation | None = None
1567
- exec: TestStructureItemExecution | None = None
1568
1565
 
1569
1566
 
1570
1567
  @dataclass
@@ -1,5 +1,4 @@
1
- import logging
2
- from dataclasses import MISSING, fields, is_dataclass
1
+ from dataclasses import fields, is_dataclass
3
2
  from enum import Enum
4
3
  from types import UnionType as TypesUnion
5
4
  from typing import Any, TypeVar, get_args, get_origin, get_type_hints
@@ -7,15 +6,13 @@ from typing import Union as TypingUnion
7
6
 
8
7
  T = TypeVar("T")
9
8
 
10
- logger = logging.getLogger(__name__)
11
-
12
9
  ERROR_NOT_A_DATACLASS = "The provided class '{dataclass}' is not a dataclass."
13
10
  ERROR_UNKNOWN_TYPE_HINT_ORIGIN = "Unknown type hint origin."
14
11
  ERROR_UNION_MISMATCH = "Value does not match any of the union types."
15
12
  ERROR_NOT_A_LIST = "Value is not of type list."
16
13
  ERROR_LIST_ARGUMENTS_MISMATCH = "List type hint must have exactly one argument, got {args}."
17
14
  ERROR_UNION_WITHOUT_ARGUMENTS = "Union type hint must have at least one argument."
18
- ERROR_MISSING_FIELDS = "Data dictionary for '{dataclass}' is missing mandatory fields: {fields}."
15
+ ERROR_TOO_MANY_DATA_FIELDS = "Data dictionary contains more fields than the dataclass has."
19
16
  ERROR_NONETYPE_DATA = "Data cannot be None."
20
17
 
21
18
 
@@ -39,35 +36,17 @@ def get_origin_from_type_hint(type_hint):
39
36
  raise ValueError(ERROR_UNKNOWN_TYPE_HINT_ORIGIN)
40
37
 
41
38
 
42
- def _has_default(cls_field) -> bool:
43
- return cls_field.default is not MISSING or cls_field.default_factory is not MISSING
44
-
45
-
46
39
  def from_dict(cls: type[T], data: dict) -> T:
47
40
  if not is_dataclass(cls):
48
41
  raise ValueError(ERROR_NOT_A_DATACLASS.format(dataclass=cls.__name__))
49
42
  if data is None:
50
43
  raise ValueError(ERROR_NONETYPE_DATA)
44
+ cls_dict = {}
51
45
  class_type_hints = get_type_hints(cls)
52
46
  class_fields = fields(cls)
53
- init_field_names = {f.name for f in class_fields if f.init}
54
- extra_keys = set(data.keys()) - init_field_names
55
- if extra_keys:
56
- logger.warning(
57
- "%s: ignoring unknown fields: %s", cls.__name__, ", ".join(sorted(extra_keys))
58
- )
59
- mandatory_fields = {f.name for f in class_fields if f.init and not _has_default(f)}
60
- missing_fields = mandatory_fields - set(data.keys())
61
- if missing_fields:
62
- raise ValueError(
63
- ERROR_MISSING_FIELDS.format(
64
- dataclass=cls.__name__, fields=", ".join(sorted(missing_fields))
65
- )
66
- )
67
- cls_dict = {}
47
+ if len(class_fields) < len(data):
48
+ raise ValueError(ERROR_TOO_MANY_DATA_FIELDS)
68
49
  for cls_field in class_fields:
69
- if not cls_field.init:
70
- continue
71
50
  if cls_field.name not in data:
72
51
  continue
73
52
  field_value = data.get(cls_field.name)
@@ -41,6 +41,7 @@ try:
41
41
  except ImportError:
42
42
  Group = None
43
43
 
44
+
44
45
  def _empty_keyword_call_execution() -> KeywordCallExecution:
45
46
  return KeywordCallExecution(
46
47
  verdict=KeywordVerdict.Undefined,
@@ -3,6 +3,8 @@ from pathlib import Path
3
3
 
4
4
  from robot.api import ExecutionResult
5
5
 
6
+ from testbench2robotframework.utils import perform_version_check
7
+
6
8
  from .config import Configuration
7
9
  from .log import logger, setup_logger
8
10
  from .result_writer import ResultWriter
@@ -18,6 +20,8 @@ def robot2testbench(
18
20
  sys.exit("Could not find json directory or zip file at the given path.")
19
21
  if not Path(robot_result_xml).exists():
20
22
  sys.exit("Robot result xml does not exist at the given path.")
23
+ perform_version_check(Path(json_input_report))
24
+
21
25
  configuration = Configuration.from_dict(config)
22
26
  setup_logger(configuration)
23
27
  logger.debug("Configuration loaded.")
@@ -7,10 +7,16 @@ from .json_reader import TestBenchJsonReader
7
7
  from .log import logger, setup_logger
8
8
  from .testbench2rf import create_test_suites
9
9
  from .testsuite_write import write_test_suites
10
- from .utils import PathResolver, extract_to_working_directory, is_zip_file
10
+ from .utils import (
11
+ PathResolver,
12
+ extract_to_working_directory,
13
+ is_zip_file,
14
+ perform_version_check,
15
+ )
11
16
 
12
17
 
13
18
  def testbench2robotframework(testbench_report: str, config: dict | Configuration):
19
+ perform_version_check(Path(testbench_report))
14
20
  configuration = Configuration.from_dict(config) if isinstance(config, dict) else config
15
21
  setup_logger(configuration)
16
22
  logger.debug("Configuration loaded.")
@@ -1,3 +1,4 @@
1
+ import json
1
2
  import re
2
3
  import shutil
3
4
  import sys
@@ -17,6 +18,54 @@ from testbench2robotframework.model import (
17
18
 
18
19
  from .log import logger
19
20
 
21
+ ALLOWED_SERVER_VERSIONS = ["4.0"]
22
+ ERROR_COULD_NOT_READ_VERSION = (
23
+ "Could not read TestBench report version. The report must be generated with one of the supported versions: "
24
+ + ", ".join(ALLOWED_SERVER_VERSIONS)
25
+ )
26
+ ERROR_INCOMPATIBLE_VERSION = (
27
+ "The version of testbench2robotframework is not compatible with the TestBench report version '{server_version}'. "
28
+ f"Supported versions are: {', '.join(ALLOWED_SERVER_VERSIONS)}. "
29
+ )
30
+
31
+
32
+ def perform_version_check(testbench_report: Path):
33
+ try:
34
+ manifest = read_manifest_json_from_testbench_report(testbench_report)
35
+ except Exception as e:
36
+ sys.exit(ERROR_COULD_NOT_READ_VERSION)
37
+ server_version = manifest.get("serverVersions", {}).get("version", None)
38
+ if not server_version:
39
+ sys.exit(ERROR_COULD_NOT_READ_VERSION)
40
+
41
+ if server_version not in ALLOWED_SERVER_VERSIONS:
42
+ sys.exit(ERROR_INCOMPATIBLE_VERSION.format(server_version=server_version))
43
+
44
+
45
+ def read_manifest_json_from_testbench_report(testbench_report: Path) -> dict:
46
+ if testbench_report.is_dir():
47
+ manifest = testbench_report / "manifest.json"
48
+ if not manifest.exists():
49
+ raise FileNotFoundError("manifest.json not found")
50
+ with open(manifest, "r", encoding="utf-8") as f:
51
+ return json.load(f)
52
+
53
+ # ZIP archive
54
+ elif testbench_report.suffix == ".zip":
55
+ with ZipFile(testbench_report) as zf:
56
+ try:
57
+ with zf.open("manifest.json") as f:
58
+ return json.load(f)
59
+ except KeyError:
60
+ raise FileNotFoundError("manifest.json not found in zip")
61
+
62
+ # Direct file
63
+ elif testbench_report.is_file() and testbench_report.name == "manifest.json":
64
+ with open(testbench_report, "r", encoding="utf-8") as f:
65
+ return json.load(f)
66
+ else:
67
+ raise FileNotFoundError(testbench_report)
68
+
20
69
 
21
70
  def robot_tag_from_udf(udf: UserDefinedField) -> str | None:
22
71
  if (udf.udfType == UDFType.Enumeration and udf.value) or (