Skip to content

Commit

Permalink
add type annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielT committed Aug 27, 2023
1 parent 0c24d04 commit c51a0d3
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 24 deletions.
162 changes: 162 additions & 0 deletions autosar_data.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
from .autosar_data import *
from typing import Dict, List, FrozenSet, Literal, TypeAlias, Tuple, Union

IncompatibleItemError: TypeAlias = Union[IncompatibleAttributeError, IncompatibleAttributeValueError, IncompatibleElementError]
ElementName: TypeAlias = str # ~5900 variants is too many to list here
AttributeName: TypeAlias = Literal["ACCESSKEY", "ALIGN", "ALLOW-BREAK", "ALT", "BASE", "BGCOLOR", "BINDING-TIME", "BLUEPRINT-VALUE", "BREAK", "CLASS", "COLNAME", "COLNUM", "COLOR", "COLS", "COLSEP", "COLWIDTH", "COORDS", "DEST", "EDIT-HEIGHT", "EDIT-WIDTH", "EDITFIT", "EDITSCALE", "ENUM-TABLE", "FILENAME", "FIT", "FLOAT", "FONT", "FRAME", "GENERATOR", "GID", "HEIGHT", "HELP-ENTRY", "HREF", "HTML-FIT", "HTML-HEIGHT", "HTML-SCALE", "HTML-WIDTH", "INDEX", "INTERVAL-TYPE", "ITEM-LABEL-POS", "KEEP-WITH-PREVIOUS", "L", "LEVEL", "MIME-TYPE", "MOREROWS", "NAME", "NAME-PATTERN", "NAMEEND", "NAMEST", "NOHREF", "NOTATION", "NOTE-TYPE", "ONBLUR", "ONCLICK", "ONDBLCLICK", "ONFOCUS", "ONKEYDOWN", "ONKEYPRESS", "ONKEYUP", "ONMOUSEDOWN", "ONMOUSEMOVE", "ONMOUSEOUT", "ONMOUSEOVER", "ONMOUSEUP", "ORIENT", "PGWIDE", "RESOLUTION-POLICY", "ROTATE", "ROWSEP", "S", "SCALE", "SD", "SHAPE", "SHORT-LABEL", "SHOW-CONTENT", "SHOW-RESOURCE-ALIAS-NAME", "SHOW-RESOURCE-CATEGORY", "SHOW-RESOURCE-LONG-NAME", "SHOW-RESOURCE-NUMBER", "SHOW-RESOURCE-PAGE", "SHOW-RESOURCE-SHORT-NAME", "SHOW-RESOURCE-TYPE", "SHOW-SEE", "SI", "SPANNAME", "STYLE", "T", "TABINDEX", "TABSTYLE", "TEX-RENDER", "TITLE", "TYPE", "UUID", "VALIDITY", "VALIGN", "VIEW", "WIDTH", "xml:space", "xmlns", "xmlns:xsi", "xsi:schemaLocation"]
EnumItem: TypeAlias = str # ~2500 variants is too many to list here
CharacterData: TypeAlias = Union[EnumItem, str, int, float]
ElementContent: TypeAlias = Union[Element, CharacterData]

class ArxmlFile:
filename: str
version: AutosarVersion
def check_version_compatibility(self, version: AutosarVersion) -> List[IncompatibleItemError]: ...
model: AutosarModel
elements_dfs: ArxmlFileElementsDfsIterator
def serialize(self) -> str: ...
xml_standalone: bool

class ArxmlFileElementsDfsIterator:
def __iter__(self) -> ArxmlFileElementsDfsIterator: ...
def __next__(self) -> Tuple[int, Element]: ...

class Attribute:
attrname: AttributeName
content: CharacterData

class AttributeIterator:
def __iter__(self) -> AttributeIterator: ...
def __next__(self) -> Attribute : ...

class AutosarDataError(Exception):
pass

class AutosarModel:
def create_file(self, filename: str, version: AutosarVersion) -> ArxmlFile: ...
def load_buffer(self, buffer: str, filename: str, strict: bool) -> Tuple[ArxmlFile, List[str]]: ...
def load_file(self, filename: str, strict: bool) -> Tuple[ArxmlFile, List[str]]: ...
def remove_file(self, arxmlfile: ArxmlFile) -> None: ...
def serialize_files(self) -> Dict[str, str]: ...
def write(self) -> None: ...
files: List[ArxmlFile]
root_element: Element
def get_element_by_path(self, autosar_path: str) -> Element: ...
elements_dfs: ElementsDfsIterator
def sort(self) -> None: ...
identifiable_elements: List[str]
def get_references_to(self, target_path: str) -> List[Element]: ...
def check_references(self) -> List[Element]: ...

class AutosarVersion:
def __new__(cls, verstring: str) -> AutosarVersion: ...
# this is the stupid result of method used by PyO3 to translate Rust enums
Autosar_4_0_1: AutosarVersion
Autosar_4_0_2: AutosarVersion
Autosar_4_0_3: AutosarVersion
Autosar_4_1_1: AutosarVersion
Autosar_4_1_2: AutosarVersion
Autosar_4_1_3: AutosarVersion
Autosar_4_2_1: AutosarVersion
Autosar_4_2_2: AutosarVersion
Autosar_4_3_0: AutosarVersion
Autosar_00042: AutosarVersion
Autosar_00043: AutosarVersion
Autosar_00044: AutosarVersion
Autosar_00045: AutosarVersion
Autosar_00046: AutosarVersion
Autosar_00047: AutosarVersion
Autosar_00048: AutosarVersion
Autosar_00049: AutosarVersion
Autosar_00050: AutosarVersion
Autosar_00051: AutosarVersion

class ContentType:
# this is the stupid result of method used by PyO3 to translate Rust enums
Elements: ContentType
CharacterData: ContentType
Mixed: ContentType

class Element:
def serialize(self) -> str: ...
parent: Element
element_name: ElementName
element_type: ElementType
item_name: str
is_identifiable: bool
is_reference: bool
path: str
model: AutosarModel
content_type: ContentType
def create_sub_element(self, element_name: ElementName) -> Element: ...
def create_sub_element_at(self, element_name: ElementName, position: int) -> Element: ...
def create_named_sub_element(self, element_name: ElementName, item_name: str) -> Element: ...
def create_named_sub_element_at(self, element_name: ElementName, item_name: str, position: int) -> Element: ...
def create_copied_sub_element(self, other: Element) -> Element: ...
def create_copied_sub_element_at(self, other: Element, position: int) -> Element: ...
def move_element_here(self, move_element: Element) -> Element: ...
def move_element_here_at(self, move_element: Element, position: int) -> Element: ...
def remove_sub_element(self, element: Element) -> None: ...
reference_target: Element
def get_sub_element(self, name_str: str) -> Element: ...
def get_sub_element_at(self, position: int) -> Element: ...
position: int
sub_elements: ElementsIterator
elements_dfs: ElementsDfsIterator
character_data: CharacterData
def remove_character_data(self) -> None: ...
def insert_character_content_item(self, chardata: str, position: int) -> None: ...
def remove_character_content_item(self, position: int) -> None: ...
content_item_count: int
content: ElementContentIterator
attributes: AttributeIterator
def attribute_value(self, attrname: AttributeName) -> CharacterData: ...
def set_attribute(self, attrname: AttributeName, chardata: CharacterData) -> None: ...
def set_attribute_string(self, attrname: AttributeName, value: str) -> None: ...
def remove_attribute(self, attrname: AttributeName) -> None: ...
def sort(self) -> None: ...
def list_valid_sub_elements(self) -> List[ValidSubElementInfo]: ...
file_membership: Tuple[bool, FrozenSet[ArxmlFile]]
def add_to_file(self, file: ArxmlFile) -> None: ...
def remove_from_file(self, file: ArxmlFile) -> None: ...
xml_path: str

class ElementContentIterator:
def __iter__(self) -> ElementContentIterator: ...
def __next__(self) -> ElementContent: ...

class ElementType:
is_named: bool
is_ref: bool
is_ordered: bool
splittable: int
def splittable_in(self, version: AutosarVersion) -> bool: ...
def reference_dest_value(self, target: ElementType) -> EnumItem: ...
def find_sub_element(self, target_name: ElementName, version: int) -> ElementType: ...

class ElementsDfsIterator:
def __iter__(self) -> ElementsDfsIterator: ...
def __next__(self) -> Tuple[int, Element]: ...

class ElementsIterator:
def __iter__(self) -> ElementsIterator: ...
def __next__(self) -> Element: ...

class IncompatibleAttributeError:
element: Element
attribute: AttributeName

class IncompatibleAttributeValueError:
element: Element
attribute: AttributeName
attribute_value: str

class IncompatibleElementError:
element: Element

class ValidSubElementInfo:
element_name: str
is_named: bool
is_allowed: bool

version: str
4 changes: 2 additions & 2 deletions test/arxmlfile_test.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from autosar_data import *
import pytest

def test_arxlfile_basic():
def test_arxlfile_basic() -> None:
model = AutosarModel()

file1 = model.create_file("filename1.arxml", AutosarVersion.Autosar_00051)
Expand Down Expand Up @@ -56,7 +56,7 @@ def test_arxlfile_basic():
print(file1.model)


def test_check_version_compatibility():
def test_check_version_compatibility() -> None:
model = AutosarModel()

file1 = model.create_file("filename", AutosarVersion.Autosar_00050)
Expand Down
33 changes: 17 additions & 16 deletions test/element_test.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from autosar_data import *
import pytest

def test_element_basic():
def test_element_basic() -> None:
model = AutosarModel()

# create some elements
Expand Down Expand Up @@ -37,13 +37,13 @@ def test_element_basic():
assert el_ar_packages.item_name is None
with pytest.raises(AutosarDataError):
print(el_ar_packages.path)

# the behavior of the element is determined by its element_type
assert el_ar_packages.is_identifiable == el_ar_packages.element_type.is_named
assert el_ar_packages.is_reference == el_ar_packages.element_type.is_ref
assert not el_ar_packages.element_type.is_ordered
assert el_ar_packages.element_type.splittable != 0

# Element has __str__ and __repr__
el_ar_packages_repr = el_ar_packages.__repr__()
assert not el_ar_packages_repr is None
Expand Down Expand Up @@ -79,7 +79,7 @@ def test_element_basic():
assert el_ar_package.xml_path == "/<AUTOSAR>/<AR-PACKAGES>/NewName"


def test_element_content():
def test_element_content() -> None:
model = AutosarModel()

# create some elements for the test
Expand All @@ -89,7 +89,7 @@ def test_element_content():
el_l2 = el_pkg1 \
.create_sub_element("DESC") \
.create_sub_element("L-2")

# different elements have different content types
assert el_pkg1.content_type == ContentType.Elements
assert el_short_name.content_type == ContentType.CharacterData
Expand All @@ -100,7 +100,7 @@ def test_element_content():
assert len([c for c in el_l2.content]) == 1
el_l2.create_sub_element("BR")
assert len([c for c in el_l2.content]) == 2

assert el_l2.content_item_count == 2

# check the content
Expand Down Expand Up @@ -129,7 +129,7 @@ def test_element_content():
.create_named_sub_element("AR-PACKAGE", "CanPkg") \
.create_sub_element("ELEMENTS") \
.create_named_sub_element("CAN-CLUSTER", "CanCluster")

# various character data elements have constraints, e.g the reference element can only contain an autosar path
# integers, or strings that do not look like paths cause an exception
with pytest.raises(AutosarDataError):
Expand All @@ -146,7 +146,7 @@ def test_element_content():
el_fibex_element_ref.set_attribute("DEST", "bla")
with pytest.raises(AutosarDataError):
el_fibex_element_ref.set_attribute("DEST", "default")

# in cases where the element name of the target is NOT a valid value in the "DEST" attribute
# the function reference_dest_value() can be used instead
destval = el_fibex_element_ref.element_type.reference_dest_value(el_can_cluster.element_type)
Expand Down Expand Up @@ -196,7 +196,7 @@ def test_element_content():
el_cse_code.character_data = "text"


def test_element_creation():
def test_element_creation() -> None:
model = AutosarModel()

# create an unnamed element
Expand Down Expand Up @@ -259,7 +259,7 @@ def test_element_creation():
# the element Autosar is not a valid sub element of ArPackage
with pytest.raises(AutosarDataError):
el_pkg1.create_sub_element_at("AUTOSAR", 1)

# it is possible to check which sub elements would be valid
# returns a list of tuples: (ElementName, is_named, currently_allowed)
vsi_list = el_pkg1.list_valid_sub_elements()
Expand All @@ -268,14 +268,14 @@ def test_element_creation():
allowed_elements = [vsi.element_name if vsi.is_allowed else None for vsi in vsi_list]
assert not "AUTOSAR" in allowed_elements
assert "CATEGORY" in allowed_elements

# remove an element
el_ar_packages.remove_sub_element(el_pkg3)
with pytest.raises(AutosarDataError):
invalid = el_pkg3.path
with pytest.raises(AutosarDataError):
invalid = el_pkg3.model
invalid2 = el_pkg3.model

# validate the resulting model
element_info = [x for x in model.root_element.elements_dfs]
# element info is a list of tuple(depth, element)
Expand All @@ -297,8 +297,9 @@ def test_element_creation():
assert element_info[11][1].item_name == "System"
assert element_info[12][1].element_name == "SHORT-NAME"
assert len(element_info) == 13

def test_element_attributes():


def test_element_attributes() -> None:
model = AutosarModel()
el_autosar = model.root_element

Expand Down Expand Up @@ -328,7 +329,7 @@ def test_element_attributes():
assert len([attr for attr in el_autosar.attributes]) == 4


def test_file_membership():
def test_file_membership() -> None:
model = AutosarModel()
file1 = model.create_file("file1", AutosarVersion.Autosar_00050)
file2 = model.create_file("file2", AutosarVersion.Autosar_00050)
Expand Down
8 changes: 4 additions & 4 deletions test/model_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import pytest
import os

def test_model_basic():
def test_model_basic() -> None:
model = AutosarModel()
# check that the object was created - model is not None
assert isinstance(model, AutosarModel)
Expand All @@ -12,7 +12,7 @@ def test_model_basic():
assert len(model.identifiable_elements) == 0


def test_model_files(tmp_path):
def test_model_files(tmp_path: str) -> None:
model = AutosarModel()

# create a file
Expand Down Expand Up @@ -68,7 +68,7 @@ def test_model_files(tmp_path):



def test_model_identifiables():
def test_model_identifiables() -> None:
model = AutosarModel()
# create some elements
el_elements = model.root_element \
Expand Down Expand Up @@ -108,7 +108,7 @@ def test_model_identifiables():
assert el_can_cluster_referrers[0] == el_fibex_element_ref


def test_model_misc():
def test_model_misc() -> None:
model = AutosarModel()
model2 = AutosarModel()

Expand Down
2 changes: 1 addition & 1 deletion test/test.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from autosar_data import *
import pytest

def test_others():
def test_others() -> None:
model = AutosarModel()

# content type - __str__ / __repr__
Expand Down
2 changes: 1 addition & 1 deletion test/version_test.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from autosar_data import *
import pytest

def test_version():
def test_version() -> None:
model = AutosarModel()

ver = AutosarVersion("AUTOSAR_4-0-1.xsd")
Expand Down

0 comments on commit c51a0d3

Please sign in to comment.