Skip to content

Commit 35c3cd0

Browse files
committed
Fixup type hinting
1 parent 3f9d013 commit 35c3cd0

File tree

8 files changed

+84
-64
lines changed

8 files changed

+84
-64
lines changed

.github/workflows/build.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747

4848
- name: Install dependencies
4949
run: |
50-
python -m pip install pytest
50+
python -m pip install -r tests/requirements.txt
5151
sudo apt update
5252
sudo apt install libxml2-utils
5353
tests/schema/1685-2014/download_schema.sh
@@ -82,7 +82,7 @@ jobs:
8282

8383
- name: Install dependencies
8484
run: |
85-
python -m pip install pylint
85+
python -m pip install -r tests/requirements.txt
8686
8787
- name: Install
8888
run: |
@@ -104,7 +104,7 @@ jobs:
104104

105105
- name: Install dependencies
106106
run: |
107-
python -m pip install mypy
107+
python -m pip install -r tests/requirements.txt
108108
109109
- name: Install
110110
run: |

src/peakrdl_ipxact/__peakrdl__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class Exporter(ExporterSubcommandPlugin):
1717
short_desc = "Export the register model to IP-XACT"
1818

1919

20-
def add_exporter_arguments(self, arg_group: 'argparse.ArgumentParser') -> None:
20+
def add_exporter_arguments(self, arg_group: 'argparse._ActionsContainer') -> None:
2121
arg_group.add_argument(
2222
"--vendor",
2323
default="example.org",
@@ -73,9 +73,9 @@ def is_compatible(self, path: str) -> bool:
7373
with open(path, "r", encoding="utf-8") as f:
7474
if re.search(r"<(spirit|ipxact):component\b", f.read()):
7575
return True
76-
return False # type: ignore [unreachable]
76+
return False
7777

78-
def add_importer_arguments(self, arg_group: 'argparse.ArgumentParser') -> None:
78+
def add_importer_arguments(self, arg_group: 'argparse._ActionsContainer') -> None:
7979
arg_group.add_argument(
8080
"--remap-state",
8181
metavar="STATE",

src/peakrdl_ipxact/exporter.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ def supports_isPresent(self) -> bool:
3030

3131
#===============================================================================
3232
class IPXACTExporter:
33+
msg: 'MessageHandler'
34+
doc: minidom.Document
35+
3336
def __init__(self, **kwargs: Any) -> None:
3437
"""
3538
Constructor for the exporter object.
@@ -51,15 +54,13 @@ def __init__(self, **kwargs: Any) -> None:
5154
String to use for line breaks. Defaults to a newline (``\\n``).
5255
"""
5356

54-
self.msg = None # type: MessageHandler
5557

5658
self.vendor = kwargs.pop("vendor", None) or "example.org"
5759
self.library = kwargs.pop("library", None) or "mylibrary"
5860
self.version = kwargs.pop("version", None) or "1.0"
5961
self.standard = kwargs.pop("standard", None) or Standard.IEEE_1685_2014
6062
self.xml_indent = kwargs.pop("xml_indent", None) or " "
6163
self.xml_newline = kwargs.pop("xml_newline", None) or "\n"
62-
self.doc = None # type: minidom.Document
6364
self._max_width = None # type: Optional[int]
6465

6566
# Check for stray kwargs
@@ -222,7 +223,7 @@ def add_nameGroup(self, parent: minidom.Element, name: str, displayName: Optiona
222223
self.add_value(parent, self.ns + "description", description)
223224

224225
#---------------------------------------------------------------------------
225-
def add_registerData(self, parent: minidom.Element, node: RegNode) -> None:
226+
def add_registerData(self, parent: minidom.Element, node: AddressableNode) -> None:
226227
if self.standard == Standard.IEEE_1685_2009:
227228
# registers must all be listed before register files
228229
for child in node.children(skip_not_present=self.skip_not_present):
@@ -339,7 +340,7 @@ def add_registerFile(self, parent: minidom.Element, node: Union[RegfileNode, Add
339340
if self.standard.supports_isPresent and not node.get_property("ispresent"):
340341
self.add_value(registerFile, self.ns + "isPresent", "0")
341342

342-
if node.is_array:
343+
if node.array_dimensions:
343344
for dim in node.array_dimensions:
344345
self.add_value(registerFile, self.ns + "dim", "%d" % dim)
345346

@@ -350,6 +351,7 @@ def add_registerFile(self, parent: minidom.Element, node: Union[RegfileNode, Add
350351
if node.is_array:
351352
# For arrays, ipxact:range also defines the increment between indexes
352353
# Must use stride instead
354+
assert node.array_stride is not None
353355
self.add_value(registerFile, self.ns + "range", self.hex_str(node.array_stride))
354356
else:
355357
self.add_value(registerFile, self.ns + "range", self.hex_str(node.size))
@@ -377,7 +379,7 @@ def add_register(self, parent: minidom.Element, node: RegNode) -> None:
377379
if self.standard.supports_isPresent and not node.get_property("ispresent"):
378380
self.add_value(register, self.ns + "isPresent", "0")
379381

380-
if node.is_array:
382+
if node.array_dimensions:
381383
if node.array_stride != (node.get_property("regwidth") / 8):
382384
self.msg.fatal(
383385
"IP-XACT does not support register arrays whose stride is larger then the register's size",

src/peakrdl_ipxact/importer.py

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Optional, List, Dict, Any, Type, Union, Set
1+
from typing import Optional, List, Dict, Any, Type, Union, Set, TypeVar
22
import re
33

44
from xml.etree import ElementTree
@@ -10,6 +10,7 @@
1010

1111
from . import typemaps
1212

13+
CT = TypeVar("CT", bound=comp.Component)
1314

1415
# Expected IP-XACT namespaces. This parser is not strict about the exact version.
1516
VALID_NS_REGEXES = [
@@ -19,8 +20,9 @@
1920
]
2021

2122
class IPXACTImporter(RDLImporter):
23+
ns: str
2224

23-
def __init__(self, compiler: RDLCompiler):
25+
def __init__(self, compiler: RDLCompiler) -> None:
2426
"""
2527
Parameters
2628
----------
@@ -29,10 +31,9 @@ def __init__(self, compiler: RDLCompiler):
2931
"""
3032

3133
super().__init__(compiler)
32-
self.ns = None # type: str
3334
self._addressUnitBits = 8
3435
self._current_addressBlock_access = rdltypes.AccessType.rw
35-
self.remap_states_seen = set() # type: Set[str]
36+
self.remap_states_seen: Set[str] = set()
3637

3738
@property
3839
def src_ref(self) -> SourceRefBase:
@@ -58,18 +59,23 @@ def import_file(self, path: str, remap_state: Optional[str] = None) -> None:
5859

5960
tree = ElementTree.parse(path)
6061

61-
component = self.get_component(tree)
62+
component = self.get_component(tree) # type: ignore
6263

6364
memoryMaps = self.get_all_memoryMap(component)
6465

66+
comp_name = self.get_sanitized_element_name(component)
67+
if not comp_name:
68+
self.msg.fatal("component is missing required tag 'name'", self.src_ref)
69+
6570
for memoryMap in memoryMaps:
66-
comp_name = self.get_sanitized_element_name(component)
6771
self.import_memoryMap(memoryMap, comp_name, remap_state)
6872

6973

7074
def get_component(self, tree: ElementTree.ElementTree) -> ElementTree.Element:
7175
# Find <component> and determine namespace prefix
7276
root = tree.getroot()
77+
assert root is not None
78+
7379
if get_local_name(root) == "component":
7480
component = root
7581
namespace = get_namespace(root)
@@ -116,6 +122,8 @@ def get_all_address_blocks(self, memoryMap: ElementTree.Element, remap_state: Op
116122
memoryRemaps = memoryMap.findall(self.ns+"memoryRemap")
117123
for memoryRemap in memoryRemaps:
118124
this_remapState = memoryRemap.get(self.ns+"state")
125+
if this_remapState is None:
126+
continue
119127
self.remap_states_seen.add(this_remapState)
120128
if this_remapState == remap_state:
121129
remap_addressBlocks = memoryRemap.findall(self.ns+"addressBlock")
@@ -239,6 +247,8 @@ def parse_addressBlock(self, addressBlock: ElementTree.Element, name_prefix:str)
239247

240248
d = self.flatten_element_values(addressBlock)
241249
name = self.get_sanitized_element_name(addressBlock)
250+
if not name:
251+
self.msg.fatal("addressBlock is missing required tag 'name'", self.src_ref)
242252

243253
if d.get('usage', None) == "reserved":
244254
# 1685-2014 6.9.4.2-a.1.iii: defines the entire range of the
@@ -257,6 +267,7 @@ def parse_addressBlock(self, addressBlock: ElementTree.Element, name_prefix:str)
257267
# Create named component definition
258268
is_memory = d.get('usage', None) == "memory"
259269
type_name = name_prefix + name
270+
C_def: Union[comp.Mem, comp.Addrmap]
260271
if is_memory:
261272
C_def = self.create_mem_definition(type_name)
262273
else:
@@ -295,9 +306,9 @@ def parse_addressBlock(self, addressBlock: ElementTree.Element, name_prefix:str)
295306
if R:
296307
self.add_child(C_def, R)
297308
elif local_name == "registerFile" and not is_memory:
298-
R = self.parse_registerFile(child_el)
299-
if R:
300-
self.add_child(C_def, R)
309+
RF = self.parse_registerFile(child_el)
310+
if RF:
311+
self.add_child(C_def, RF)
301312
else:
302313
self.msg.error(
303314
"Invalid child element <%s> found in <%s:addressBlock>"
@@ -324,17 +335,19 @@ def parse_addressBlock(self, addressBlock: ElementTree.Element, name_prefix:str)
324335
# Also convert to an instance, since this will be instantiated into the
325336
# wrapper that represents the memoryMap
326337
if is_memory:
327-
C = self.instantiate_mem(
338+
assert isinstance(C_def, comp.Mem)
339+
mem = self.instantiate_mem(
328340
C_def,
329341
name, self.AU_to_bytes(d['baseAddress'])
330342
)
343+
return mem
331344
else:
332-
C = self.instantiate_addrmap(
345+
assert isinstance(C_def, comp.Addrmap)
346+
am = self.instantiate_addrmap(
333347
C_def,
334348
name, self.AU_to_bytes(d['baseAddress'])
335349
)
336-
337-
return C
350+
return am
338351

339352

340353
def parse_registerFile(self, registerFile: ElementTree.Element) -> Optional[comp.Regfile]:
@@ -361,6 +374,8 @@ def parse_registerFile(self, registerFile: ElementTree.Element) -> Optional[comp
361374

362375
d = self.flatten_element_values(registerFile)
363376
name = self.get_sanitized_element_name(registerFile)
377+
if not name:
378+
self.msg.fatal("registerFile is missing required tag 'name'", self.src_ref)
364379

365380
# Check for required values
366381
required = {'addressOffset', 'range'}
@@ -402,9 +417,9 @@ def parse_registerFile(self, registerFile: ElementTree.Element) -> Optional[comp
402417
if R:
403418
self.add_child(C, R)
404419
elif local_name == "registerFile":
405-
R = self.parse_registerFile(child_el)
406-
if R:
407-
self.add_child(C, R)
420+
RF = self.parse_registerFile(child_el)
421+
if RF:
422+
self.add_child(C, RF)
408423
else:
409424
self.msg.error(
410425
"Invalid child element <%s> found in <%s:registerFile>"
@@ -456,6 +471,8 @@ def parse_register(self, register: ElementTree.Element) -> Optional[comp.Reg]:
456471

457472
d = self.flatten_element_values(register)
458473
name = self.get_sanitized_element_name(register)
474+
if not name:
475+
self.msg.fatal("register is missing required tag 'name'", self.src_ref)
459476

460477
# Check for required values
461478
required = {'addressOffset', 'size'}
@@ -511,6 +528,8 @@ def parse_register(self, register: ElementTree.Element) -> Optional[comp.Reg]:
511528
if local_name == "field":
512529
# This XML element is a field
513530
field_name = self.get_sanitized_element_name(child_el)
531+
if not field_name:
532+
self.msg.fatal("field is missing required tag 'name'", self.src_ref)
514533
field_tuples.append((field_name, child_el))
515534
if field_name in field_names:
516535
field_name_collisions.add(field_name)
@@ -650,6 +669,7 @@ def parse_field(
650669
self.assign_property(C, "onwrite", d['modifiedWriteValue'])
651670

652671
if 'enum_el' in d:
672+
assert C.inst_name is not None
653673
enum_type = self.parse_enumeratedValues(d['enum_el'], C.inst_name + "_enum_t")
654674
self.assign_property(C, "encode", enum_type)
655675

@@ -700,7 +720,7 @@ def parse_integer(self, s: str) -> int:
700720
v *= multiplier[m.group(2).upper()]
701721
return v
702722

703-
m = re.fullmatch(r"\d*'h([0-9a-f]+)", s, re.I) # type: ignore [unreachable]
723+
m = re.fullmatch(r"\d*'h([0-9a-f]+)", s, re.I)
704724
if m:
705725
return int(m.group(1), 16)
706726

@@ -890,6 +910,8 @@ def parse_enumeratedValues(self, enumeratedValues: ElementTree.Element, type_nam
890910
d[local_name] = self.parse_integer(get_text(child))
891911

892912
name = self.get_sanitized_element_name(enumeratedValue)
913+
if not name:
914+
self.msg.fatal("enumeratedValue is missing required tag 'name'", self.src_ref)
893915

894916
# Check for required values
895917
required = {'value'}
@@ -946,23 +968,23 @@ def AU_to_bytes(self, au: int) -> int:
946968
return byte_units
947969

948970

949-
def memoryMap_vendorExtensions(self, vendorExtensions: ElementTree.Element, component: comp.Component) -> comp.Component:
971+
def memoryMap_vendorExtensions(self, vendorExtensions: ElementTree.Element, component: CT) -> CT:
950972
#pylint: disable=unused-argument
951973
return component
952974

953-
def addressBlock_vendorExtensions(self, vendorExtensions: ElementTree.Element, component: comp.Component) -> comp.Component:
975+
def addressBlock_vendorExtensions(self, vendorExtensions: ElementTree.Element, component: CT) -> CT:
954976
#pylint: disable=unused-argument
955977
return component
956978

957-
def registerFile_vendorExtensions(self, vendorExtensions: ElementTree.Element, component: comp.Component) -> comp.Component:
979+
def registerFile_vendorExtensions(self, vendorExtensions: ElementTree.Element, component: CT) -> CT:
958980
#pylint: disable=unused-argument
959981
return component
960982

961-
def register_vendorExtensions(self, vendorExtensions: ElementTree.Element, component: comp.Component) -> comp.Component:
983+
def register_vendorExtensions(self, vendorExtensions: ElementTree.Element, component: CT) -> CT:
962984
#pylint: disable=unused-argument
963985
return component
964986

965-
def field_vendorExtensions(self, vendorExtensions: ElementTree.Element, component: comp.Component) -> comp.Component:
987+
def field_vendorExtensions(self, vendorExtensions: ElementTree.Element, component: CT) -> CT:
966988
#pylint: disable=unused-argument
967989
return component
968990

src/peakrdl_ipxact/typemaps.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from typing import Optional
12
from systemrdl import rdltypes
23

34
# sw <--> ipxact:access
@@ -13,9 +14,9 @@ def access_from_sw(sw: rdltypes.AccessType) -> str:
1314
for sw_entry, access_entry in ACCESS_MAP:
1415
if sw == sw_entry:
1516
return access_entry
16-
return None
17+
raise RuntimeError("Impossible")
1718

18-
def sw_from_access(access: str) -> rdltypes.AccessType:
19+
def sw_from_access(access: str) -> Optional[rdltypes.AccessType]:
1920
for sw_entry, access_entry in ACCESS_MAP:
2021
if access == access_entry:
2122
return sw_entry
@@ -39,9 +40,9 @@ def mwv_from_onwrite(onwrite: rdltypes.OnWriteType) -> str:
3940
for onwrite_entry, mwv_entry in MWV_MAP:
4041
if onwrite == onwrite_entry:
4142
return mwv_entry
42-
return None
43+
raise RuntimeError("Impossible")
4344

44-
def onwrite_from_mwv(mwv: str) -> rdltypes.OnWriteType:
45+
def onwrite_from_mwv(mwv: str) -> Optional[rdltypes.OnWriteType]:
4546
for onwrite_entry, mwv_entry in MWV_MAP:
4647
if mwv == mwv_entry:
4748
return onwrite_entry
@@ -59,9 +60,9 @@ def readaction_from_onread(onread: rdltypes.OnReadType) -> str:
5960
for onread_entry, read_action_entry in READ_ACTION_MAP:
6061
if onread == onread_entry:
6162
return read_action_entry
62-
return None
63+
raise RuntimeError("Impossible")
6364

64-
def onread_from_readaction(readaction: str) -> rdltypes.OnReadType:
65+
def onread_from_readaction(readaction: str) -> Optional[rdltypes.OnReadType]:
6566
for onread_entry, read_action_entry in READ_ACTION_MAP:
6667
if readaction == read_action_entry:
6768
return onread_entry

tests/mypy.ini

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
[mypy]
2-
ignore_missing_imports = True
3-
strict_optional = False
2+
#ignore_missing_imports = True
3+
#strict_optional = False
44
disallow_incomplete_defs = True
55
disallow_untyped_defs = True
66
warn_unused_configs = True
77
warn_unused_ignores = True
88
warn_unreachable = True
9-
disallow_untyped_calls = False
9+
disallow_untyped_calls = True

tests/requirements.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pytest
2+
pylint
3+
mypy
4+
pytest-cov
5+
coveralls>=3.0.0

0 commit comments

Comments
 (0)