Refactor the file parsing methods for readability by moving the
_parse_header() and _parse_memreserves() calls from _parse_dt() to
_parse_file(). The header and memreserves are not part of the 'tree'
part of the devicetree; now that we have a dedicated _parse_file()
helper, it makes more sense to me to have them there.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Holy overloaded technical terms, Batman.
Here, 'property' and 'type' each mean two different things, which
we can distinguish like this:
- Property (capital P): dtlib.Property class, represents
a property in a devicetree node
- @property: a Python property
- type(): an "@property" in the Property class, that returns
a dtlib.Type value
- Type (capital T): dtlib.Type class, represents the devicetree
type of a Property value (dtlib.Type.BYTES, etc.)
The type() @property in the Property class currently has an 'int' as
its Python return type annotation. It really returns a dtlib.Type,
which is an int (since it's an IntEnum), but that's not the same thing
as an int.
Change this to Type to be clear that not just any int can be returned
by this @property.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Make attribute initialization order match the order that attributes
appear within the class docstring. Move the 'type' property definition
up by the constructor to make it more obvious that this 'attribute' is
a (Python) property. This is for readability.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Reorder attribute initialization to match the order that attributes
appear in the class level docstring. This is for readability.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Initialize all the public API interface related attributes within the
constructor instead of scattering them throughout the implementation
of the class, and make sure they all have type annotations.
Move all the parsing code away from the init routines and public API
down to the main parsing block.
This is for readability and paves the way for later changes that
affect the way initialization happens.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Calling Binding.__repr__() when the attribute Binding.path is None
would raise TypeError: expected str, bytes or os.PathLike object,
not NoneType.
Known bindings that may not have a path (Binding.path is None)
include bindings for properties such as 'compatible', 'reg', 'status'.
Signed-off-by: Chris Duf <chris@openmarl.org>
Co-authored-by: Gerard Marull-Paretas <gerard@teslabs.com>
Attempting to access the property Property.description
when Property.spec.description is None would raise
AttributeError: 'NoneType' object has no attribute 'strip'.
Known properties that may not have a description
(Property.spec.description is None):
- 'compatible' for nodes such as / /soc /soc/timer@e000e010 /leds /pwmleds
- 'reg' for nodes such as /soc/timer@e000e010
- 'status' for nodes such as /soc/timer@e000e010
- 'gpios' for nodes such as /leds/led_0 /buttons/button_0
- 'pwms' for nodes such as /pwmleds/pwm_led_0
This patch checks the PropertySpec.description attribute before calling
strip(): will return None, and not raise AttributeError.
Signed-off-by: Chris Duf <chris@openmarl.org>
Co-authored-by: Gerard Marull-Paretas <gerard@teslabs.com>
Attempting to access the Binding.description property
when the description is unavailable would raise KeyError: 'description'.
Known bindings that won't define a 'description' key in the
Binding.raw dictionary include the 'compatible' property's binding
of nodes such as /, /soc, /leds or /pwmleds.
Note that this may also occur when a proper YAML
binding file is available (e.g. pwmleds.yaml).
This patch simply substitutes the Binding.raw dictionary indexing
with the get() function: will return None and not raise KeyError.
Signed-off-by: Chris Duf <chris@openmarl.org>
Follow up to 5b5aa6ebba adding model name
and existence macros for all compatibles of a node that match an entry
in vendor prefixes.
Signed-off-by: Maureen Helm <maureen.helm@intel.com>
Attempts to define two nodes with the same name within a single set of
curly brackets should fail.
For example, this is invalid DTS according to dtc:
/ { foo {}; foo {}; };
By contrast, this is valid since the node named 'foo' appears twice in
two different sets of curly brackets:
/ { foo {}; };
/ { foo {}; };
Zephyr's dtlib currently does not error out on the invalid condition.
Now that Zephyr itself has been updated to not include such nodes (to
the best of my ability), we can fix this divergence from current dtc
behavior and add a regression test in dtlib.
Fixes: #49590
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
For a single bus that supports multiple protocols, e.g. I3C and I2C,
the single value "bus:" setting is no longer sufficient, as a I3C bus
cannot be matched to a device having "on-bus: I2C". This commit
extends the "bus:" setting so that it can accept a list of values.
This change allows corresponding devicetree macros to be generated
so that DT_ON_BUS() can work properly in this scenario.
Signed-off-by: Daniel Leung <daniel.leung@intel.com>
Remove a yaml monkeypatch. It is no longer needed since we support 3.6
or later on Zephyr v2.7 LTS and 3.8 or later on what will become v3.2.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Adds a new compat2vendor lookup table that maps compatibles to vendor
names, constructed from the vendor prefixes file. This approach is a
more scalable alternative to adding a vendor name property to devicetree
bindings, as was previously proposed.
Signed-off-by: Maureen Helm <maureen.helm@intel.com>
Allow for having array types (array, uint8-array, string-array) be const.
This would allow for something like:
properties:
reg-names:
const: ["foo", "bar"]
To be supported.
Renamed function _check_prop_type_and_default to _check_prop_by_type
as part of this change and Moved the check for 'const' types into
_check_prop_by_type as its similar to the prop_type check and it was
easier to implement in _check_prop_by_type as we already extract
prop_type from the option in that function.
Signed-off-by: Kumar Gala <galak@kernel.org>
Some callers need to be able to convert strings to tokens in the same
way edtlib does. Make this possible by exposing the internal helper
function used to do that under a suitable name.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
The error message emitted by _interrupt_parent() is wrong; it
mistakenly says:
node None has an 'interrupts' property, but [...]
This 'None' is appearing because the same routine overwrites the
'node' argument that the caller is asking about with node parents
until it hits the root, at which point root.parent is None.
Fix it by caching the original node and using that in the error
message instead.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Pin the types-PyYAML version to 6.0.7. Version 6.0.8 is causing CI
errors for other pull requests, so we need this in to get other PRs
moving.
Fixes: #46286
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
It can be useful to know what the index of a particular child is in
the list of nodes. Add a a helper for computing that and some test
cases.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Don't let a malformed devicetree escape as a DTError. Wrap it in an
EDTError instead, so callers can just rely on the edtlib APIs as is
generally expected.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
A GCC linemarker of the form:
# 1 "filename" 2 3 4
or so is not currently being handled, because the current regular
expression assumes the "flags" values (the numbers after "filename")
are limited to a single value. Tweak the regular expression to allow
for up to 4 flags, which is what GCC documents it may emit:
https://gcc.gnu.org/onlinedocs/gcc-10.2.0/cpp/Preprocessor-Output.html
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This adds some tests in test_edtlib.py and test.dts to check all
common possible combination of ranges property usage and handling
by edtlib.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
As described in IEEE Std 1275-1994, the PCIe bindings uses the ranges
property to describe the PCI I/O and memory regions.
Add parsing of this property in edtlib.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Currently all the *-names and *-cells properties are derived from the
name of the base <name>s property. This is a limitation because:
- It forces the base property name to be plural ending in -s
- It doesn't allow the english exception of plural words ending in -es
With this patch we add one additional property 'specifier-space' that
can be used to explicitly specify the base property name.
Signed-off-by: Carlo Caione <ccaione@baylibre.com>
Suggested-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Node names are subject to the rules in table 2.1 of the devicetree
specification v0.3, while properties are subject to rules in table
2.2. These rules mean that some property names are invalid node names.
However, the same regular expression is being used to validate the
names of nodes and properties in dtlib. This leads to invalid node
names being allowed to pass. Fix this issue by moving the node name
handling code to the Node constructor and checking against the
characters in table 2.1.
The test cases claim that the existing behavior matches dtc. I can't
reproduce that. I get errors when I use invalid characters (like "?")
in a node name. For example:
foo.dts:3.8-11: ERROR (node_name_chars): /node?: Bad character '?' in
node name
Try to make the dtlib error message reminiscent of that.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This is unused since the very beginning of the module's introduction.
It looks like it was abandoned in favor of the approach where each
token can have only one capturing group.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This became useless when _init_tokens() was refactored not to use
global variables (in "dtlib: use IntEnum for token IDs"), and the
linter is complaining about it now.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Similarly to what was done for dtlib, use f-strings in places where it
improves readability. Some places, e.g. __repr__ methods that
construct a string using something like
"<SomeType, {}>".format(", ".join(...))
are better left off as-is.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
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>
If the user passes None, set the internal attribute to an empty dict
instead. This lets us avoid some None checking and simplifies things
without changing semantics -- if the user *does* pass an empty dict,
the results are the same.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This is a common extension for YAML files. We don't have to allow it
in upstream zephyr, but we should allow downstream DTS_ROOTs to have
this ability.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Commit c4079e4be2
("scripts: rework edtlib warnings-turned-errors") was trying to abort
on unknown vendor prefix, but the error log is not fatal.
Fix it by using the same error handling function we use when aborting
due to deprecated property usage.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
There are way too many one-off vendor prefixes set up for individual
boards to bother tracking them in vendor-prefixes.txt. As a practical
matter, the compatible for the root node doesn't matter anyway. So
just relax our check for that node.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Create a "global" gen_defines.py option and edtlib.EDT constructor
kwarg that turns edtlib-specific warnings into errors. This applies to
edtlib-specific warnings only. Warnings that are just dupes of dtc
warnings are not affected.
Use it from twister to increase DT testing coverage in upstream zephyr.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
An unknown vendor prefix is now a warning. We augment the list of
vendor prefixes passed by the user with a grandfathered-in bunch from
Linux.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
As a first step towards being more forgiving on invalid inputs, allow
string-valued aliases properties that do not point to valid nodes when
the user requests permissiveness.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Modeled after dtc's --force option, the idea is this will try harder
and harder over time to produce an object despite malformed input.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
I made an alignment error in a dts binding, but the build was
successful. After some debugging I found the following warning
explaining the problem:
'/home/casper/src/zephyrproject/zephyr/dts/bindings/gpio/
gpio-keys.yaml' appears in binding directories but isn't valid
YAML: while parsing a block mapping
in "<unicode string>", line 11, column 8
did not find expected key
in "<unicode string>", line 18, column 9
I think this should be an error as there shouldn't be any invalid yaml.
Signed-off-by: Casper Meijn <casper@meijn.net>
Recent versions of mypy have learned that the yaml module has type
stubs and the tool is now erroring out when it discovers we import
yaml since the stubs are not involved.
This is breaking CI on unrelated patches; fix it following the
instructions here:
https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Error out on compatible properties with invalid values. The regular
expression used to validate them matches what's used in dt-schema.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Extend the steps taken in tox.ini by type checking the 'devicetree'
package. This will make it easier for callers to type-check code that
uses the low level DT module's public APIs, since they can rely on
the type checker a bit more.
It will also help avoid bugs by adding some type checking for future
changes to this module.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Mypy is complaining about this line for some reason I didn't have time
to figure out. Just shut it up for now; I'll look into this when I get
around to type annotating edtlib.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Now that all the other code it depends on is annotated, we can finish
up the type annotation of this module in the main DT class.
It's not worth it to try to annotate the private methods (the ones
that begin with '_'). Most of these are low level lexing helpers that
aren't particularly amenable to static type checking, because the type
of a token's value is often dependent on the token ID in ways that
static type annotations are not well equipped to capture.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
We'd like users of this API to know that DT.root is always a Node,
and not an Optional[Node].
However, although DT.__init__ throws an exception if the resulting DT
object would have no root node, static analysis can't tell that since
the root instance attribute starts out as None during initialization,
so checkers like mypy are convinced it's Optional[Node].
Since this is really OK, we'll quiet the type checker down by stashing
the instance attribute in self._root instead, and providing a root
property accessor that is annotated to return Node instead of
Optional[Node]. We can tell mypy to ignore what looks like a potential
None here to allow callers to treat the result as a Node.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
The documentation says DT.__init__ takes any iterable for the
include_path, but this leads to bad results when you pass it something
other than a 'real' sequence (list/tuple/etc), like a generator:
>>> dt = DT('/tmp/foo.dts', (x for x in ['a', 'b', 'c']))
>>> repr(dt)
"DT(filename='/tmp/foo.dts', include_path=<generator object ...>)"
Make a copy in list form just to avoid things like this.
Add a test for this and relax the regular expression in the existing
test case related to this.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Some of these are also tripping up a python 2 / python 3 warning
in mypy in the way that '{}'.format(b'foo') works, which we silence by
explicitly requesting the python 3 behavior.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>