Skip to content

Commit d5aa46f

Browse files
committed
Add support for config files
1 parent de09029 commit d5aa46f

9 files changed

+167
-22
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ Non-collectable elements are various sub-elements to collectable elements.
99

1010
### Added
1111

12+
#### Workspace
13+
14+
* Various improvements to template classes
15+
* Support project config files
16+
1217
#### XML - Data type elements
1318

1419
* ArgumentDataPrototype | ARGUMENT-DATA-PROTOTYPE

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ It also has some support for parsing AUTOSAR XML files.
1414
3. Currently, only the categories mentioned below are supported. If you want a full API, wait for v0.6.0:
1515
* Data Types
1616
* Constants
17+
* Port Interfaces
1718

1819
## Major design changes
1920

@@ -53,6 +54,7 @@ For currently supported XML elements, see the [CHANGELOG](CHANGELOG.md) file.
5354

5455
* Python 3.10+
5556
* lxml
57+
* tomli (Python 3.10 only, tomli is built-in for Python 3.11)
5658
* [cfile](https://github.com/cogu/cfile) v0.3.2+
5759

5860
## Installation
@@ -237,7 +239,7 @@ None
237239
InactiveActive_T: <class 'autosar.xml.element.ImplementationDataType'>
238240
```
239241

240-
Here's a more fleshed out example, tt adds a `TEXTTABLE` CompuMethod and saves everything to an ARXML file. It also demonstrates how you control the XML schema version
242+
Here's a more fleshed out example, it adds a `TEXTTABLE` CompuMethod and saves everything to an ARXML file. It also demonstrates how you control the XML schema version
241243
when saving the file.
242244

243245
```python

examples/xml/template/config.toml

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
[namespace.Default]
3+
BaseType = "/DataTypes/BaseTypes"
4+
ImplementationDataType = "DataTypes/ImplementationDataTypes"
5+
CompuMethod = "DataTypes/CompuMethods"
6+
DataConstraint = "DataTypes/DataConstrs"
7+
ComponentType = "/ComponentTypes"
8+
ModeDeclaration = "/ModeDclrGroups"
9+
PortInterface = "/PortInterfaces"
10+
base_ref = "/"
11+
12+
[namespace.AUTOSAR_Platform]
13+
BaseType = "BaseTypes"
14+
CompuMethod = "CompuMethods"
15+
DataConstraint = "DataConstrs"
16+
ImplementationDataType = "ImplementationDataTypes"
17+
18+
[document.AUTOSAR_Platform]
19+
packages = "/AUTOSAR_Platform"
20+
21+
[document.PortInterfaces]
22+
packages=["/ModeDclrGroups", "/PortInterfaces"]
23+
24+
[document.DataTypes]
25+
packages = "/DataTypes"
26+
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""
2+
Generate ARXML from template classes using local config file.
3+
"""
4+
5+
import os
6+
from demo_system import platform, datatype, portinterface
7+
import autosar.xml.workspace as ar_workspace
8+
9+
10+
def apply_platform_types(workspace: ar_workspace.Workspace):
11+
"""
12+
Applies platform templates
13+
"""
14+
workspace.apply(platform.ImplementationTypes.boolean)
15+
workspace.apply(platform.ImplementationTypes.uint8)
16+
workspace.apply(platform.ImplementationTypes.uint16)
17+
workspace.apply(platform.ImplementationTypes.uint32)
18+
workspace.apply(platform.ImplementationTypes.uint64)
19+
20+
21+
def apply_data_types(workspace: ar_workspace.Workspace):
22+
"""
23+
Applies data type templates
24+
"""
25+
workspace.apply(datatype.InactiveActive_T)
26+
27+
28+
def apply_portinterfaces(workspace: ar_workspace.Workspace):
29+
"""
30+
Applies mode templates
31+
"""
32+
workspace.apply(portinterface.EcuM_CurrentMode)
33+
workspace.apply(portinterface.NvMService_I)
34+
35+
36+
def main():
37+
"""Main"""
38+
config_file_path = os.path.join(os.path.dirname(__file__), "config.toml")
39+
document_root = os.path.join(os.path.dirname(__file__), "generated")
40+
workspace = ar_workspace.Workspace(config_file_path, document_root=document_root)
41+
apply_platform_types(workspace)
42+
apply_data_types(workspace)
43+
apply_portinterfaces(workspace)
44+
workspace.write_documents()
45+
print("Done")
46+
47+
48+
if __name__ == "__main__":
49+
main()

examples/xml/template/generate_xml.py examples/xml/template/generate_xml_without_config.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""
2-
Generate ARXML from template classes
2+
Generate ARXML from template classes without using config file.
3+
Instead we programatically create namespaces and documents
34
"""
45

56
import os

requirements.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
lxml
1+
lxml
2+
tomli >= 1.1.0 ; python_version < "3.11"

run_examples.cmd

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ python examples\xml\port_interface\parameter_interface.py
1313
python examples\xml\port_interface\sender_receiver_interface.py
1414
python examples\xml\port_interface\client_server_interface.py
1515
python examples\xml\port_interface\mode_switch_interface.py
16+
python examples\xml\template\generate_xml_using_config.py
17+
python examples\xml\template\generate_xml_without_config.py
1618
python examples\generator\data_types\gen_type_defs_scalar.py
1719
python examples\generator\data_types\gen_type_defs_array.py
1820
python examples\generator\data_types\gen_type_defs_record.py

src/autosar/xml/document.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def __init__(self, packages: list[ar_element.Package] | None = None, schema_vers
3333
self.file_info_comment = None # .FILE-INFO-COMMENT
3434
self.admin_data = None # .ADMIN-DATA
3535
self.introduction = None # .INTRODUCTION
36-
self.packages = [] # .PACKAGES
36+
self.packages: list[ar_element.Package] = [] # .PACKAGES
3737
self._package_map = {} # internal package map
3838
if packages is not None:
3939
for package in packages:

src/autosar/xml/workspace.py

+76-18
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,35 @@
22
AUTOSAR XML Workspace
33
"""
44
import posixpath
5+
import os
56
from typing import Any
67
import autosar.base as ar_base
78
import autosar.xml.element as ar_element
89
import autosar.xml.enumeration as ar_enum
910
import autosar.xml.template as ar_template
1011
import autosar.xml.document as ar_document
1112
from autosar.xml.writer import Writer
13+
try:
14+
import tomllib
15+
except ModuleNotFoundError:
16+
import tomli as tomllib
17+
18+
19+
class DocumentConfig:
20+
"""
21+
Internal class used during document creation
22+
"""
23+
24+
def __init__(self, file_path: str, package_refs: list[str] | str | None = None) -> None:
25+
self.document = ar_document.Document()
26+
self.file_path = file_path
27+
self.package_refs: list[str] = []
28+
if isinstance(package_refs, str):
29+
self.package_refs.append(package_refs)
30+
else:
31+
for package_ref in package_refs:
32+
assert isinstance(package_ref, str)
33+
self.package_refs.append(package_ref)
1234

1335

1436
class Namespace:
@@ -35,11 +57,14 @@ class Workspace:
3557
Workspace
3658
"""
3759

38-
def __init__(self, config_file_path: str | None = None) -> None:
60+
def __init__(self, config_file_path: str | None = None, document_root: str | None = None) -> None:
3961
self.namespaces: dict[str, Namespace] = {}
4062
self.packages: list[ar_element.Package] = []
4163
self._package_map: dict[str, ar_element.Package] = {}
42-
self.documents: list[tuple(ar_document.Document, str)] = []
64+
self.documents: list[DocumentConfig] = []
65+
self.document_root = document_root
66+
if config_file_path is not None:
67+
self.load_config(config_file_path)
4368

4469
def create_namespace(self, name: str, package_map: dict[str, str], base_ref: str | None = None) -> None:
4570
"""
@@ -138,35 +163,68 @@ def apply(self, template: Any, **kwargs) -> Any:
138163
else:
139164
raise NotImplementedError(f"Unknown template type: {str(type(template))}")
140165

141-
def create_document(self, file_path: str, packages: str | list[str]) -> ar_document.Document:
166+
def create_document(self, file_path: str, packages: str | list[str] | None = None) -> None:
142167
"""
143168
Creates a new document object and appends one or more packages to it.
144169
Use the write_documents method to write documents to file system
145170
"""
146-
document = ar_document.Document()
147-
if isinstance(packages, str):
148-
package = self.find(packages)
149-
if package is None:
150-
raise ValueError(f"Invalid package reference: '{packages}'")
151-
document.append(package)
152-
else:
153-
for package_ref in packages:
154-
package = self.find(package_ref)
155-
if package is None:
156-
raise ValueError(f"Invalid package reference: '{package_ref}'")
157-
document.append(package)
158-
self.documents.append((document, file_path))
159-
return document
171+
self.documents.append(DocumentConfig(file_path, packages))
172+
173+
def set_document_root(self, directory: str) -> None:
174+
"""
175+
Sets root directory where documents are written
176+
"""
177+
self.document_root = directory
160178

161179
def write_documents(self, scehema_version=ar_base.DEFAULT_SCHEMA_VERSION) -> None:
162180
"""
163181
Writes all documents to file system
164182
"""
165183
writer = Writer()
166-
for (document, file_path) in self.documents:
184+
for document_config in self.documents:
185+
document = document_config.document
186+
file_path = document_config.file_path
187+
package_refs = document_config.package_refs
167188
document.schema_version = scehema_version
189+
for package_ref in package_refs:
190+
package = self.find(package_ref)
191+
if package is not None:
192+
if not isinstance(package, ar_element.Package):
193+
raise ValueError(f"'{package_ref}' does not reference a package element")
194+
document.append(package)
195+
if self.document_root is not None:
196+
file_path = os.path.join(self.document_root, file_path)
168197
writer.write_file(document, file_path)
169198

199+
def load_config(self, file_path: str) -> None:
200+
"""
201+
Loads (.toml) config file into workspace
202+
"""
203+
with open(file_path, "rb") as fp: # pylint: disable=C0103
204+
config = tomllib.load(fp)
205+
namespace = config.get("namespace", None)
206+
if namespace is not None:
207+
for name, ns_config in namespace.items():
208+
self._create_namespace_from_config(name, ns_config)
209+
document = config.get("document", None)
210+
if document is not None:
211+
for name, doc_config in document.items():
212+
self._create_document_from_config(name, doc_config)
213+
214+
def _create_namespace_from_config(self, name: str, config: dict):
215+
base_ref = None
216+
package_map = {}
217+
for key, value in config.items():
218+
if key == "base_ref":
219+
base_ref = value
220+
else:
221+
package_map[key] = value
222+
self.create_namespace(name, package_map, base_ref)
223+
224+
def _create_document_from_config(self, name: str, config: str | list[str]):
225+
file_name = f"{name}.arxml"
226+
self.create_document(file_name, config.get("packages", None))
227+
170228
def _apply_element_template(self, template: ar_template.ElementTemplate, kwargs: dict) -> ar_element.ARElement:
171229
"""
172230
Wrapper for element templates.

0 commit comments

Comments
 (0)