dtlib: use f-strings where it makes sense

The library was originally developed before Python 3.6 was the minimum
supported version. Use f-strings now that we can do that, as they tend
to be easier to read.

There are a few places where str.format() makes sense to preserve,
specifically where the same argument is used multiple times; leave
those alone.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This commit is contained in:
Martí Bolívar 2021-08-19 21:03:10 -07:00 committed by Anas Nashif
commit 66ee3d291c

View file

@ -159,7 +159,7 @@ class Node:
"""
s = "".join(label + ": " for label in self.labels)
s += "{} {{\n".format(self.name)
s += f"{self.name} {{\n"
for prop in self.props.values():
s += "\t" + str(prop) + "\n"
@ -176,8 +176,7 @@ class Node:
Returns some information about the Node instance. Called automatically
if the Node instance is evaluated.
"""
return "<Node {} in '{}'>" \
.format(self.path, self.dt.filename)
return f"<Node {self.path} in '{self.dt.filename}'>"
# See Property.type
class Type(enum.IntEnum):
@ -381,9 +380,9 @@ class Property:
try:
ret = self.value.decode("utf-8")[:-1] # Strip null
except UnicodeDecodeError:
_err("value of property '{}' ({!r}) on {} in {} is not valid UTF-8"
.format(self.name, self.value, self.node.path,
self.node.dt.filename))
_err(f"value of property '{self.name}' ({self.value!r}) "
f"on {self.node.path} in {self.node.dt.filename} "
"is not valid UTF-8")
return ret # The separate 'return' appeases the type checker.
@ -407,9 +406,9 @@ class Property:
try:
ret = self.value.decode("utf-8").split("\0")[:-1]
except UnicodeDecodeError:
_err("value of property '{}' ({!r}) on {} in {} is not valid UTF-8"
.format(self.name, self.value, self.node.path,
self.node.dt.filename))
_err(f"value of property '{self.name}' ({self.value!r}) "
f"on {self.node.path} in {self.node.dt.filename} "
"is not valid UTF-8")
return ret # The separate 'return' appeases the type checker.
@ -479,16 +478,16 @@ class Property:
try:
path = self.value.decode("utf-8")[:-1]
except UnicodeDecodeError:
_err("value of property '{}' ({!r}) on {} in {} is not valid UTF-8"
.format(self.name, self.value, self.node.path,
self.node.dt.filename))
_err(f"value of property '{self.name}' ({self.value!r}) "
f"on {self.node.path} in {self.node.dt.filename} "
"is not valid UTF-8")
try:
ret = self.node.dt.get_node(path)
except DTError:
_err("property '{}' on {} in {} points to the non-existent node "
"\"{}\"".format(self.name, self.node.path,
self.node.dt.filename, path))
_err(f"property '{self.name}' on {self.node.path} in "
f"{self.node.dt.filename} points to the non-existent node "
f'"{path}"')
return ret # The separate 'return' appeases the type checker.
@ -552,8 +551,7 @@ class Property:
if marker_type is _MarkerType.STRING:
# end - 1 to strip off the null terminator
s += ' "{}"'.format(_decode_and_escape(
self.value[pos:end - 1]))
s += f' "{_decode_and_escape(self.value[pos:end - 1])}"'
if end != len(self.value):
s += ","
elif marker_type is _MarkerType.PATH:
@ -564,7 +562,7 @@ class Property:
# <> or []
if marker_type is _MarkerType.LABEL:
s += " {}:".format(ref)
s += f" {ref}:"
elif marker_type is _MarkerType.PHANDLE:
s += " &" + ref
pos += 4
@ -578,9 +576,9 @@ class Property:
num = int.from_bytes(self.value[pos:pos + elm_size],
"big")
if elm_size == 1:
s += " {:02X}".format(num)
s += f" {num:02X}"
else:
s += " " + hex(num)
s += f" {hex(num)}"
pos += elm_size
@ -596,8 +594,8 @@ class Property:
def __repr__(self):
return "<Property '{}' at '{}' in '{}'>" \
.format(self.name, self.node.path, self.node.dt.filename)
return f"<Property '{self.name}' at '{self.node.path}' in " \
f"'{self.node.dt.filename}'>"
#
# Internal functions
@ -796,8 +794,8 @@ class DT:
# Path does not start with '/'. First component must be an alias.
alias, _, rest = path.partition("/")
if alias not in self.alias2node:
_err("no alias '{}' found -- did you forget the leading '/' in "
"the node path?".format(alias))
_err(f"no alias '{alias}' found -- did you forget the leading "
"'/' in the node path?")
return _root_and_path_to_node(self.alias2node[alias], rest, path)
@ -835,9 +833,8 @@ class DT:
for labels, address, offset in self.memreserves:
# List the labels in a consistent order to help with testing
for label in labels:
s += label + ": "
s += "/memreserve/ {:#018x} {:#018x};\n" \
.format(address, offset)
s += f"{label}: "
s += f"/memreserve/ {address:#018x} {offset:#018x};\n"
s += "\n"
return s + str(self.root)
@ -847,8 +844,8 @@ class DT:
Returns some information about the DT instance. Called automatically if
the DT instance is evaluated.
"""
return "DT(filename='{}', include_path={})" \
.format(self.filename, self._include_path)
return f"DT(filename='{self.filename}', " \
f"include_path={self._include_path})"
#
# Parsing
@ -1119,8 +1116,8 @@ class DT:
# Try again as a signed number, in case it's negative
prop.value += num.to_bytes(n_bytes, "big", signed=True)
except OverflowError:
self._parse_error("{} does not fit in {} bits"
.format(num, 8*n_bytes))
self._parse_error(
f"{num} does not fit in {8*n_bytes} bits")
def _parse_bytes(self, prop):
# Parses '[ ... ]'
@ -1178,8 +1175,7 @@ class DT:
f.seek(offset)
prop.value += f.read(size)
except OSError as e:
self._parse_error("could not read '{}': {}"
.format(filename, e))
self._parse_error(f"could not read '{filename}': {e}")
def _parse_value_labels(self, prop):
# _parse_assignment() helper for parsing labels before/after each
@ -1465,8 +1461,7 @@ class DT:
tok = self._next_token()
if tok.val != tok_val:
self._parse_error("expected '{}', not '{}'"
.format(tok_val, tok.val))
self._parse_error(f"expected '{tok_val}', not '{tok.val}'")
return tok
@ -1479,12 +1474,12 @@ class DT:
return tok.val
def _parse_error(self, s):
_err("{}:{} (column {}): parse error: {}".format(
self.filename, self._lineno,
# This works out for the first line of the file too, where rfind()
# returns -1
self._tok_i - self._file_contents.rfind("\n", 0, self._tok_i + 1),
s))
# This works out for the first line of the file too, where rfind()
# returns -1
column = self._tok_i - self._file_contents.rfind("\n", 0,
self._tok_i + 1)
_err(f"{self.filename}:{self._lineno} (column {column}): "
f"parse error: {s}")
def _enter_file(self, filename):
# Enters the /include/d file 'filename', remembering the position in
@ -1511,8 +1506,8 @@ class DT:
for i, parent in enumerate(self._filestack):
if filename == parent[0]:
self._parse_error("recursive /include/:\n" + " ->\n".join(
["{}:{}".format(parent[0], parent[1])
for parent in self._filestack[i:]] +
[f"{parent[0]}:{parent[1]}"
for parent in self._filestack[i:]] +
[filename]))
self.filename = f.name
@ -1546,7 +1541,7 @@ class DT:
# Path reference (&{/foo/bar})
path = s[1:-1]
if not path.startswith("/"):
_err("node path '{}' does not start with '/'".format(path))
_err(f"node path '{path}' does not start with '/'")
# Will raise DTError if the path doesn't exist
return _root_and_path_to_node(self.root, path, path)
@ -1558,7 +1553,7 @@ class DT:
if s in node.labels:
return node
_err("undefined node label '{}'".format(s))
_err(f"undefined node label '{s}'")
#
# Post-processing
@ -1575,8 +1570,8 @@ class DT:
phandle = node.props.get("phandle")
if phandle:
if len(phandle.value) != 4:
_err("{}: bad phandle length ({}), expected 4 bytes"
.format(node.path, len(phandle.value)))
_err(f"{node.path}: bad phandle length "
f"({len(phandle.value)}), expected 4 bytes")
is_self_referential = False
for marker in phandle._markers:
@ -1591,8 +1586,8 @@ class DT:
is_self_referential = True
break
_err("{}: {} refers to another node"
.format(node.path, phandle.name))
_err(f"{node.path}: {phandle.name} "
"refers to another node")
# Could put on else on the 'for' above too, but keep it
# somewhat readable
@ -1600,13 +1595,13 @@ class DT:
phandle_val = int.from_bytes(phandle.value, "big")
if phandle_val in {0, 0xFFFFFFFF}:
_err("{}: bad value {:#010x} for {}"
.format(node.path, phandle_val, phandle.name))
_err(f"{node.path}: bad value {phandle_val:#010x} "
f"for {phandle.name}")
if phandle_val in self.phandle2node:
_err("{}: duplicated phandle {:#x} (seen before at {})"
.format(node.path, phandle_val,
self.phandle2node[phandle_val].path))
_err(f"{node.path}: duplicated phandle {phandle_val:#x} "
"(seen before at "
f"{self.phandle2node[phandle_val].path})")
self.phandle2node[phandle_val] = node
@ -1649,7 +1644,7 @@ class DT:
try:
ref_node = self._ref2node(ref)
except DTError as e:
_err("{}: {}".format(prop.node.path, e))
_err(f"{prop.node.path}: {e}")
# For /omit-if-no-ref/
ref_node._is_referenced = True
@ -1681,8 +1676,8 @@ class DT:
if aliases:
for prop in aliases.props.values():
if not alias_re.match(prop.name):
_err("/aliases: alias property name '{}' should include "
"only characters from [0-9a-z-]".format(prop.name))
_err(f"/aliases: alias property name '{prop.name}' "
"should include only characters from [0-9a-z-]")
# Property.to_path() checks that the node exists, has
# the right type, etc. Swallow errors for invalid
@ -1739,21 +1734,20 @@ class DT:
strings = []
for thing in things:
if isinstance(thing, Node):
strings.append("on " + thing.path)
strings.append(f"on {thing.path}")
elif isinstance(thing, Property):
strings.append("on property '{}' of node {}"
.format(thing.name, thing.node.path))
strings.append(f"on property '{thing.name}' "
f"of node {thing.node.path}")
else:
# Label within property value
strings.append("in the value of property '{}' of node {}"
.format(thing[0].name,
thing[0].node.path))
strings.append("in the value of property "
f"'{thing[0].name}' of node "
f"{thing[0].node.path}")
# Give consistent error messages to help with testing
strings.sort()
_err("Label '{}' appears ".format(label) +
" and ".join(strings))
_err(f"Label '{label}' appears " + " and ".join(strings))
#
@ -1817,7 +1811,7 @@ class DT:
self._parse_error(e)
continue
self._parse_error("'{}' could not be found".format(filename))
self._parse_error(f"'{filename}' could not be found")
#
# Public functions
@ -1840,8 +1834,7 @@ def to_num(data: bytes, length: Optional[int] = None,
if length is not None:
_check_length_positive(length)
if len(data) != length:
_err("{!r} is {} bytes long, expected {}"
.format(data, len(data), length))
_err(f"{data!r} is {len(data)} bytes long, expected {length}")
return int.from_bytes(data, "big", signed=signed)
@ -1854,8 +1847,8 @@ def to_nums(data: bytes, length: int = 4, signed: bool = False) -> List[int]:
_check_length_positive(length)
if len(data) % length:
_err("{!r} is {} bytes long, expected a length that's a a multiple of {}"
.format(data, len(data), length))
_err(f"{data!r} is {len(data)} bytes long, "
f"expected a length that's a a multiple of {length}")
return [int.from_bytes(data[i:i + length], "big", signed=signed)
for i in range(0, len(data), length)]
@ -1866,8 +1859,7 @@ def to_nums(data: bytes, length: int = 4, signed: bool = False) -> List[int]:
def _check_is_bytes(data):
if not isinstance(data, bytes):
_err("'{}' has type '{}', expected 'bytes'"
.format(data, type(data).__name__))
_err(f"'{data}' has type '{type(data).__name__}', expected 'bytes'")
def _check_length_positive(length):
if length < 1:
@ -1905,8 +1897,8 @@ def _root_and_path_to_node(cur, path, fullpath):
continue
if component not in cur.nodes:
_err("component '{}' in path '{}' does not exist"
.format(component, fullpath))
_err(f"component '{component}' in path '{fullpath}' "
"does not exist")
cur = cur.nodes[component]