testbench2robotframework 0.9.1a3__tar.gz → 0.9.2a2__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 (59) hide show
  1. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/PKG-INFO +1 -1
  2. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/__init__.py +1 -1
  3. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/model.py +39 -9
  4. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/result_writer.py +11 -0
  5. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/testbench2rf.py +25 -17
  6. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/utils.py +18 -51
  7. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/.gitignore +0 -0
  8. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/CreatePiPWheel.bat +0 -0
  9. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/CreatePiPWheel.sh +0 -0
  10. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/DEVELOPMENT.md +0 -0
  11. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/ExampleConfiguration/json_config.json +0 -0
  12. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/ExampleConfiguration/pyproject_example.toml +0 -0
  13. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/ExampleConfiguration/toml_config.toml +0 -0
  14. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/LICENSE +0 -0
  15. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/MANIFEST.in +0 -0
  16. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/README.md +0 -0
  17. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/README_old.md +0 -0
  18. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/atest/json_config_tests/1_tfs.robot +0 -0
  19. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/atest/robot/libs/json_config.py +0 -0
  20. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/atest/robot/libs/pyproject_config.py +0 -0
  21. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/atest/robot/resources/file_management.resource +0 -0
  22. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/atest/robot/resources/testbench2robotframework_cli.resource +0 -0
  23. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/atest/robot/rf_tests/cli_interface/write/json_config.robot +0 -0
  24. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/atest/robot/rf_tests/cli_interface/write/no_config_argument.robot +0 -0
  25. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/atest/robot/rf_tests/cli_interface/write/toml_config.robot +0 -0
  26. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/create_json_schema.py +0 -0
  27. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/images/LibrarySubdivision.PNG +0 -0
  28. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/images/Unbenannt.PNG +0 -0
  29. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/images/generated.png +0 -0
  30. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/images/libraries.PNG +0 -0
  31. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/images/resources.PNG +0 -0
  32. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/images/rfLibraryRootsTestBench.PNG +0 -0
  33. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/images/testbench_rfLibraryRegex.PNG +0 -0
  34. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/images/testbench_rfResourceRegex.PNG +0 -0
  35. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/images/testthemen.PNG +0 -0
  36. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/oldModel.py +0 -0
  37. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/pydantic_model.py +0 -0
  38. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/pyproject.toml +0 -0
  39. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/requirements.txt +0 -0
  40. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/robot.toml +0 -0
  41. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/tasks.py +0 -0
  42. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench-tools.zip +0 -0
  43. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/__main__.py +0 -0
  44. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/cli.py +0 -0
  45. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/config.py +0 -0
  46. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/execution_artifacts.py +0 -0
  47. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/html_parser.py +0 -0
  48. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/json_reader.py +0 -0
  49. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/json_writer.py +0 -0
  50. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/log.py +0 -0
  51. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/model_utils.py +0 -0
  52. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/robotframework2testbench.py +0 -0
  53. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/testbench2robotframework.py +0 -0
  54. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/testbench2robotframework/testsuite_write.py +0 -0
  55. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/tests/test_data/configurations/invalid_config.json +0 -0
  56. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/tests/test_data/configurations/valid_config.json +0 -0
  57. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/tests/test_missing_files.py +0 -0
  58. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/tests/test_robot_files_should_not_contain_invalid_characters.py +0 -0
  59. {testbench2robotframework-0.9.1a3 → testbench2robotframework-0.9.2a2}/tests/test_zip_file_generation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: testbench2robotframework
3
- Version: 0.9.1a3
3
+ Version: 0.9.2a2
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.1a3"
20
+ __version__ = "0.9.2a2"
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: openapi.yml
3
- # timestamp: 2025-11-24T08:45:38+00:00
3
+ # timestamp: 2025-12-15T08:54:07+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -505,7 +505,7 @@ class TOVResponse:
505
505
 
506
506
 
507
507
  @dataclass
508
- class OptionalLocalDateTime:
508
+ class OptionalLocalDate:
509
509
  optional: Optional[str] = None
510
510
 
511
511
 
@@ -993,6 +993,7 @@ class TestCaseSpecification(TestStructureSpecification):
993
993
  class TestStructureItemBaseInformation:
994
994
  key: str
995
995
  numbering: str
996
+ path: str
996
997
  parentKey: str
997
998
  name: str
998
999
  uniqueID: str
@@ -1128,6 +1129,7 @@ class TestThemeDetails:
1128
1129
  name: str
1129
1130
  uniqueID: str
1130
1131
  numbering: str
1132
+ path: str
1131
1133
  spec: TestThemeSpecification
1132
1134
  exec: Optional[TestThemeExecution] = None
1133
1135
 
@@ -1403,6 +1405,19 @@ class DefaultValue:
1403
1405
  valueType: ArgumentValueType
1404
1406
 
1405
1407
 
1408
+ @dataclass
1409
+ class SubdivisionDetails:
1410
+ key: str
1411
+ name: str
1412
+ uniqueID: str
1413
+ description: str
1414
+ path: str
1415
+ references: List[str]
1416
+ locker: Optional[UserReference] = None
1417
+ parentUniqueID: Optional[str] = None
1418
+ libraryKey: Optional[str] = None
1419
+
1420
+
1406
1421
  @dataclass
1407
1422
  class KeywordParameterForInsert:
1408
1423
  name: str
@@ -1767,6 +1782,20 @@ class KeywordForInsert:
1767
1782
  callType: Optional[KeywordCallType] = None
1768
1783
 
1769
1784
 
1785
+ @dataclass
1786
+ class SubdivisionForInsert:
1787
+ name: str
1788
+ parentKey: Optional[str] = None
1789
+ uid: Optional[str] = None
1790
+ description: Optional[RichTextInfo] = None
1791
+
1792
+
1793
+ @dataclass
1794
+ class SubdivisionForUpdate:
1795
+ name: Optional[str] = None
1796
+ description: Optional[RichTextInfo] = None
1797
+
1798
+
1770
1799
  @dataclass
1771
1800
  class KeywordDetailsForUpdate:
1772
1801
  name: Optional[str] = None
@@ -1782,7 +1811,7 @@ class SpecificationDetailsForUpdate:
1782
1811
  reviewer: Optional[OptionalUser] = None
1783
1812
  locker: Optional[OptionalUser] = None
1784
1813
  priority: Optional[Priority] = None
1785
- dueDate: Optional[OptionalLocalDateTime] = None
1814
+ dueDate: Optional[OptionalLocalDate] = None
1786
1815
  description: Optional[RichTextInfo] = None
1787
1816
  reviewComment: Optional[RichTextInfo] = None
1788
1817
 
@@ -1801,8 +1830,8 @@ class ProjectDetailsForUpdate:
1801
1830
  isVisibleToTester: Optional[bool] = None
1802
1831
  isTestingIntelligenceActive: Optional[bool] = None
1803
1832
  description: Optional[RichTextInfo] = None
1804
- startDate: Optional[OptionalLocalDateTime] = None
1805
- endDate: Optional[OptionalLocalDateTime] = None
1833
+ startDate: Optional[OptionalLocalDate] = None
1834
+ endDate: Optional[OptionalLocalDate] = None
1806
1835
  inspections: Optional[List[str]] = None
1807
1836
  variantsManagementEnabled: Optional[OperationalState] = None
1808
1837
 
@@ -1810,13 +1839,13 @@ class ProjectDetailsForUpdate:
1810
1839
  @dataclass
1811
1840
  class TOVForUpdate:
1812
1841
  name: Optional[str] = None
1813
- endDate: Optional[OptionalLocalDateTime] = None
1842
+ endDate: Optional[OptionalLocalDate] = None
1814
1843
  visible: Optional[bool] = None
1815
1844
  description: Optional[RichTextInfo] = None
1816
1845
  isBaseTov: Optional[bool] = None
1817
1846
  status: Optional[ProjectStatus] = None
1818
1847
  testingIntelligence: Optional[bool] = None
1819
- startDate: Optional[OptionalLocalDateTime] = None
1848
+ startDate: Optional[OptionalLocalDate] = None
1820
1849
  cloningVisibility: Optional[bool] = None
1821
1850
 
1822
1851
 
@@ -1824,6 +1853,7 @@ class TOVForUpdate:
1824
1853
  class TestCaseSetDetails:
1825
1854
  key: str
1826
1855
  numbering: str
1856
+ path: str
1827
1857
  uniqueID: str
1828
1858
  name: str
1829
1859
  spec: TestCaseSetSpecificationSummary
@@ -1848,9 +1878,9 @@ class TestCaseDetails:
1848
1878
  @dataclass
1849
1879
  class CycleForUpdate:
1850
1880
  name: Optional[str] = None
1851
- endDate: Optional[OptionalLocalDateTime] = None
1881
+ endDate: Optional[OptionalLocalDate] = None
1852
1882
  visible: Optional[bool] = None
1853
1883
  description: Optional[RichTextInfo] = None
1854
1884
  status: Optional[ProjectStatus] = None
1855
1885
  testingIntelligence: Optional[bool] = None
1856
- startDate: Optional[OptionalLocalDateTime] = None
1886
+ startDate: Optional[OptionalLocalDate] = None
@@ -117,6 +117,8 @@ class ResultWriter(ResultVisitor):
117
117
  self, keywords: list[KeywordCall], keyword_type: KeywordType
118
118
  ):
119
119
  for keyword in keywords:
120
+ if not keyword.spec:
121
+ continue
120
122
  if keyword.spec.keywordType == keyword_type:
121
123
  yield keyword
122
124
 
@@ -160,6 +162,13 @@ class ResultWriter(ResultVisitor):
160
162
  self._set_compound_keyword_execution_verdict(
161
163
  keyword, itb_test_case.testSequence
162
164
  )
165
+ textual_steps = list(
166
+ self._get_keywords_by_type(itb_test_case.testSequence, KeywordType.Textual)
167
+ )
168
+ for step in textual_steps:
169
+ if step.exec is None:
170
+ step.exec = from_dict(KeywordCallExecution, {})
171
+ step.exec.verdict = KeywordVerdict.Skipped
163
172
  self._set_itb_testcase_execution_result(itb_test_case, self.test_chain)
164
173
  self._set_itb_testcase_execution_comment(itb_test_case, self.test_chain)
165
174
  self._set_itb_testcase_references(itb_test_case, self.test_chain)
@@ -460,6 +469,8 @@ class ResultWriter(ResultVisitor):
460
469
  child.exec = from_dict(KeywordCallExecution, {})
461
470
  if child.spec.keywordType == KeywordType.Compound:
462
471
  self._set_compound_keyword_execution_verdict(child, test_steps)
472
+ if child.spec.keywordType == KeywordType.Textual:
473
+ child.exec.verdict = KeywordVerdict.Skipped
463
474
  if child.exec.verdict is KeywordVerdict.Fail:
464
475
  compound_keyword.exec.verdict = KeywordVerdict.Fail
465
476
  break
@@ -20,18 +20,22 @@ from robot.parsing.model.blocks import (
20
20
  from robot.parsing.model.statements import (
21
21
  Comment,
22
22
  EmptyLine,
23
- KeywordCall as RFKeywordCall,
24
23
  LibraryImport,
25
24
  Metadata,
26
25
  ResourceImport,
27
26
  SectionHeader,
28
27
  Setup,
29
28
  Statement,
30
- Tags as RFTags,
31
29
  Teardown,
32
30
  TestCaseName,
33
31
  VariablesImport,
34
32
  )
33
+ from robot.parsing.model.statements import (
34
+ KeywordCall as RFKeywordCall,
35
+ )
36
+ from robot.parsing.model.statements import (
37
+ Tags as RFTags,
38
+ )
35
39
 
36
40
  from testbench2robotframework.utils import robot_tag_from_udf
37
41
 
@@ -45,6 +49,8 @@ from .json_reader import TestCaseSet
45
49
  from .log import logger
46
50
  from .model import (
47
51
  KeywordCall as TBKeywordCall,
52
+ )
53
+ from .model import (
48
54
  KeywordDetails,
49
55
  KeywordType,
50
56
  ParameterEvaluationType,
@@ -825,21 +831,23 @@ class RobotSuiteFileBuilder:
825
831
  setting_section.body.extend(self._create_rf_resource_imports(subdivisions))
826
832
  setting_section.body.extend(self._create_rf_unknown_imports(subdivisions))
827
833
  setting_section_meta_data = self.test_case_set.metadata
828
- for md_name, md_expression in self.config.metadata.items():
829
- from .utils import safe_eval
830
- md_expression = re.sub(r"\$tcs", "tcs", md_expression)
831
- try:
832
- setting_section_meta_data[md_name] = safe_eval(
833
- md_expression, {"tcs": self.test_case_set.details}
834
- )
835
- except ValueError as ve:
836
- logger.warning(
837
- f"Value '{md_expression}' from the custom metadata setting could not be evaluated: {ve}"
838
- )
839
- except Exception as e:
840
- logger.error(
841
- f"Error while evaluating the custom metadata setting '{md_expression}': {e}"
842
- )
834
+ # for md_name, md_expression in self.config.metadata.items():
835
+ # try:
836
+ # md_expression = re.sub(r"\$tcs", "tcs", md_expression)
837
+ # for match in re.finditer(r"(\{[^}]*\})", md_expression):
838
+ # re.sub() = safe_eval(
839
+ # md_expression, {"tcs": self.test_case_set.details}
840
+ # )
841
+ # print(match.group(1))
842
+ # setting_section_meta_data[md_name] = str(md_expression)
843
+ # except ValueError as ve:
844
+ # logger.warning(
845
+ # f"Value '{md_expression}' from the custom metadata setting could not be evaluated: {ve}"
846
+ # )
847
+ # except Exception as e:
848
+ # logger.error(
849
+ # f"Error while evaluating the custom metadata setting '{md_expression}': {e}"
850
+ # )
843
851
  setting_section.body.extend(
844
852
  [
845
853
  create_meta_data(metadata_name, metadata_value)
@@ -1,11 +1,9 @@
1
- import ast
2
1
  import re
3
2
  import shutil
4
3
  import sys
5
4
  from pathlib import Path, PurePath
6
5
  from typing import Optional
7
6
  from zipfile import ZipFile
8
- from .log import logger
9
7
 
10
8
  from testbench2robotframework.model import (
11
9
  RootNode,
@@ -18,6 +16,8 @@ from testbench2robotframework.model import (
18
16
  UserDefinedField,
19
17
  )
20
18
 
19
+ from .log import logger
20
+
21
21
 
22
22
  def robot_tag_from_udf(udf: UserDefinedField) -> Optional[str]:
23
23
  if (udf.udfType == UDFType.Enumeration and udf.value) or (
@@ -97,55 +97,22 @@ class PathResolver:
97
97
  return index.zfill(max_length)
98
98
 
99
99
 
100
- def safe_eval(expr: str, names: dict):
101
- tree = ast.parse(expr, mode="eval")
102
- allowed_nodes = (
103
- ast.Expression,
104
- ast.Call,
105
- ast.Attribute,
106
- ast.Load,
107
- ast.Name,
108
- ast.ListComp,
109
- ast.GeneratorExp,
110
- ast.comprehension,
111
- ast.List,
112
- ast.Tuple,
113
- ast.Constant,
114
- ast.Subscript,
115
- ast.JoinedStr,
116
- ast.FormattedValue,
117
- ast.BinOp,
118
- ast.UnaryOp,
119
- ast.Compare,
120
- ast.BoolOp,
121
- ast.Eq,
122
- ast.NotEq,
123
- ast.Gt,
124
- ast.Lt,
125
- ast.GtE,
126
- ast.LtE,
127
- ast.In,
128
- ast.And,
129
- ast.Or,
130
- ast.Not,
131
- ast.Add,
132
- ast.Sub,
133
- ast.Mult,
134
- ast.Div,
135
- ast.Mod,
136
- ast.Store,
137
- ast.keyword,
138
- )
139
- for node in ast.walk(tree):
140
- if not isinstance(node, allowed_nodes):
141
- raise ValueError(f"Disallowed expression: {type(node).__name__}")
142
- if isinstance(node, ast.Attribute) and node.attr.startswith("_"):
143
- raise ValueError(f"Access to private attribute {node.attr} is not allowed")
144
- if isinstance(node, ast.Name) and node.id == "__import__":
145
- raise ValueError("Use of __import__ is forbidden")
146
-
147
- code = compile(tree, "<safe_eval>", "eval")
148
- return eval(code, {"__builtins__": {}}, names)
100
+ # def safe_eval(expr: str, names: dict):
101
+ # tree = ast.parse(expr, mode="eval")
102
+ # def resolve(node):
103
+ # if isinstance(node, ast.Name):
104
+ # if node.id not in names:
105
+ # raise ValueError(f"Unknown name: {node.id}")
106
+ # return names[node.id]
107
+ # if isinstance(node, ast.Attribute):
108
+ # if node.attr.startswith("_"):
109
+ # raise ValueError("Private attributes are forbidden")
110
+ # value = resolve(node.value)
111
+ # return getattr(value, node.attr)
112
+ # raise ValueError(f"Disallowed expression: {type(node).__name__}")
113
+ # if not isinstance(tree.body, (ast.Name, ast.Attribute)):
114
+ # raise ValueError("Only attribute access is allowed")
115
+ # return resolve(tree.body)
149
116
 
150
117
 
151
118
  def get_directory(json_report_path: Optional[str]) -> str: