Skip to content

Commit

Permalink
Enable pylint
Browse files Browse the repository at this point in the history
Signed-off-by: Nathaniel Graff <[email protected]>
  • Loading branch information
nategraff-sifive committed Nov 4, 2019
1 parent 7e37b3b commit 693abe1
Show file tree
Hide file tree
Showing 8 changed files with 679 additions and 66 deletions.
11 changes: 8 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@

venv/bin/activate:
python3 -m venv venv
source venv/bin/activate && pip install --upgrade pip
source venv/bin/activate && pip install -r requirements.txt

.PHONY: virtualenv
virtualenv: venv/bin/activate
source venv/bin/activate && pip install --upgrade pip
source venv/bin/activate && pip install -r requirements.txt

.PHONY: test-types
test-types:
test-types: venv/bin/activate
source venv/bin/activate && mypy -m unittest
test: test-types

.PHONY: test-lint
test-lint: venv/bin/activate
source venv/bin/activate && pylint pydevicetree
test: test-lint

.PHONY: test
test: venv/bin/activate
source venv/bin/activate && python3 -m unittest
4 changes: 1 addition & 3 deletions pydevicetree/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
#!/usr/bin/env python3

from pydevicetree.ast import Devicetree
#!/usr/bin/env python3
69 changes: 35 additions & 34 deletions pydevicetree/ast/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import os
import re

from typing import List, Union, Optional, TypeVar, Type, Iterable, Callable, cast, Any, Pattern
from typing import List, Union, Optional, Iterable, Callable, cast, Any, Pattern

# These type names are just used in the constructors for these clasess
# These names are just used in the constructors for these clasess
ElementList = Iterable[Union['Node', 'Property', 'Directive']]
DirectiveOption = List[Any]

# Callback type signatures for Devicetree.match() and Devicetree.chosen()
# Callback isinstance signatures for Devicetree.match() and Devicetree.chosen()
MatchCallback = Optional[Callable[['Node'], None]]
ChosenCallback = Optional[Callable[['PropertyValues'], None]]

Expand All @@ -19,12 +19,12 @@ def formatLevel(level: int, s: str) -> str:
def wrapStrings(values: List[Any], formatHex: bool = False) -> List[Any]:
wrapped = []
for v in values:
if type(v) is str:
if isinstance(v, str):
if v[0] != '&':
wrapped.append("\"%s\"" % v)
else:
wrapped.append(v)
elif type(v) is int:
elif isinstance(v, int):
if formatHex:
wrapped.append("0x%x" % v)
else:
Expand All @@ -34,7 +34,7 @@ def wrapStrings(values: List[Any], formatHex: bool = False) -> List[Any]:
return wrapped

class PropertyValues:
def __init__(self, values: List[Any] = []):
def __init__(self, values: List[Any] = None):
self.values = values

def __repr__(self) -> str:
Expand All @@ -58,21 +58,20 @@ def __getitem__(self, key) -> Any:
def __eq__(self, other) -> bool:
if isinstance(other, PropertyValues):
return self.values == other.values
else:
return self.values == other
return self.values == other

class Bytestring(PropertyValues):
def __init__(self, bytelist: List[int] = []):
def __init__(self, bytelist: List[int] = None):
PropertyValues.__init__(self, bytearray(bytelist))

def __repr__(self) -> str:
return "<Bytestring " + str(self.values) + ">"

def to_dts(self, formatHex: bool = False) -> str:
return "[" + " ".join("%02x" % v for v in self.values) + "]";
return "[" + " ".join("%02x" % v for v in self.values) + "]"

class CellArray(PropertyValues):
def __init__(self, cells: List[Any] = []):
def __init__(self, cells: List[Any] = None):
PropertyValues.__init__(self, cells)

def __repr__(self) -> str:
Expand All @@ -82,7 +81,7 @@ def to_dts(self, formatHex: bool = False) -> str:
return "<" + " ".join(wrapStrings(self.values, formatHex)) + ">"

class StringList(PropertyValues):
def __init__(self, strings: List[str] = []):
def __init__(self, strings: List[str] = None):
PropertyValues.__init__(self, strings)

def __repr__(self) -> str:
Expand All @@ -104,17 +103,16 @@ def __str__(self) -> str:

def to_dts(self, level: int = 0) -> str:
if self.name in ["reg", "ranges"]:
value = self.values.to_dts(formatHex = True)
value = self.values.to_dts(formatHex=True)
else:
value = self.values.to_dts(formatHex = False)
value = self.values.to_dts(formatHex=False)

if value != "":
return formatLevel(level, "%s = %s;\n" % (self.name, value))
else:
return formatLevel(level, "%s;\n" % self.name)
return formatLevel(level, "%s;\n" % self.name)

class Directive:
def __init__(self, directive: str, options: DirectiveOption = []):
def __init__(self, directive: str, options: DirectiveOption = None):
self.directive = directive
self.options = options

Expand All @@ -127,13 +125,15 @@ def __str__(self) -> str:
def to_dts(self, level: int = 0) -> str:
if self.options:
return formatLevel(level, "%s %s;\n" % (self.directive, self.options))
else:
return formatLevel(level, "%s;\n" % self.directive)
return formatLevel(level, "%s;\n" % self.directive)

class Node:
def __init__(self, name: str, label: Optional[str] = None, address: Optional[str] = None, properties: List[Property] = [], directives: List[Directive] = [], children: List['Node'] = []):
# pylint: disable=too-many-arguments
def __init__(self, name: str, label: Optional[str] = None, address: Optional[str] = None,
properties: List[Property] = None, directives: List[Directive] = None,
children: List['Node'] = None):
self.name = name
self.parent = None # type: Optional['Node']
self.parent = None # isinstance: Optional['Node']

self.label = label
self.address = address
Expand All @@ -144,17 +144,17 @@ def __init__(self, name: str, label: Optional[str] = None, address: Optional[str
def __repr__(self) -> str:
if self.address:
return "<Node %s@%s>" % (self.name, self.address)
else:
return "<Node %s>" % self.name
return "<Node %s>" % self.name

def __str__(self) -> str:
return self.to_dts()

def to_dts(self, level: int = 0) -> str:
out = ""
if type(self.address) is int and self.label:
out += formatLevel(level, "%s: %s@%x {\n" % (self.label, self.name, cast(int, self.address)))
elif type(self.address) is int:
if isinstance(self.address, int) and self.label:
out += formatLevel(level,
"%s: %s@%x {\n" % (self.label, self.name, cast(int, self.address)))
elif isinstance(self.address, int):
out += formatLevel(level, "%s@%x {\n" % (self.name, cast(int, self.address)))
elif self.label:
out += formatLevel(level, "%s: %s {\n" % (self.label, self.name))
Expand Down Expand Up @@ -196,7 +196,7 @@ def address_cells(self):
cells = self.get_field("#address-cells")
if cells is not None:
return cells
elif self.parent is not None:
if self.parent is not None:
return self.parent.address_cells()
# No address cells found
return 0
Expand All @@ -205,26 +205,27 @@ def size_cells(self):
cells = self.get_field("#size-cells")
if cells is not None:
return cells
elif self.parent is not None:
if self.parent is not None:
return self.parent.size_cells()
# No size cells found
return 0

class Devicetree(Node):
def __init__(self, elements: ElementList = []):
def __init__(self, elements: ElementList = None):
properties = [] # type: List[Property]
directives = [] # type: List[Directive]
children = [] # type: List[Node]

for e in elements:
if type(e) is Node:
if isinstance(e, Node):
children.append(cast(Node, e))
elif type(e) is Property:
elif isinstance(e, Property):
properties.append(cast(Property, e))
elif type(e) is Directive:
elif isinstance(e, Directive):
directives.append(cast(Directive, e))

Node.__init__(self, name="", properties=properties, directives=directives, children=children)
Node.__init__(self, name="",
properties=properties, directives=directives, children=children)

def __repr__(self) -> str:
name = self.root().get_field("compatible")
Expand All @@ -244,6 +245,7 @@ def to_dts(self, level: int = 0) -> str:

@staticmethod
def parseFile(filename: str, followIncludes: bool = False) -> 'Devicetree':
# pylint: disable=import-outside-toplevel,cyclic-import
from pydevicetree.source import parseTree
with open(filename, 'r') as f:
contents = f.read()
Expand Down Expand Up @@ -288,4 +290,3 @@ def match_chosen(node: Node) -> bool:
return p.values

return None

2 changes: 1 addition & 1 deletion pydevicetree/source/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/env python3

from pydevicetree.source.parser import printTree, parseTree
from pydevicetree.source.parser import *
27 changes: 19 additions & 8 deletions pydevicetree/source/grammar.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,35 @@
label_creation = p.Combine(label + p.Literal(":"))
string = p.QuotedString(quoteChar='"')
stringlist = p.delimitedList(string)
node_path = p.Combine(p.Literal("/") + p.delimitedList(node_name, delim="/") + p.Optional(p.Literal("@") + unit_address))
reference = p.Combine(p.Literal("&") + ((p.Literal("{") + node_path("path") + p.Literal("}")) ^ label))
directive = p.QuotedString(quoteChar="/", unquoteResults=False).setResultsName("directive") + p.Optional(string ^ property_name ^ node_name ^ reference ^ (integer * 2)).setResultsName("option") + p.Literal(";").suppress()
node_path = p.Combine(p.Literal("/") + p.delimitedList(node_name, delim="/") + \
p.Optional(p.Literal("@") + unit_address))
reference = p.Combine(p.Literal("&") + \
((p.Literal("{") + node_path("path") + p.Literal("}")) ^ label))
directive = p.QuotedString(quoteChar="/", unquoteResults=False).setResultsName("directive") + \
p.Optional(string ^ property_name ^ node_name ^ reference ^ \
(integer * 2)).setResultsName("option") + p.Literal(";").suppress()

operator = p.oneOf("~ ! * / + - << >> < <= > >= == != & ^ | && ||")
arith_expr = p.Forward()
ternary_element = arith_expr ^ integer
ternary_expr = ternary_element + p.Literal("?") + ternary_element + p.Literal(":") + ternary_element
arith_expr = p.nestedExpr(content=(p.OneOrMore(operator ^ integer) ^ ternary_expr))

cell_array = p.Literal("<").suppress() + p.ZeroOrMore(integer ^ arith_expr ^ string ^ reference ^ label_creation) + p.Literal(">").suppress()
bytestring = p.Literal("[").suppress() + (p.OneOrMore(p.Word(p.hexnums, exact=2) ^ label_creation)) + p.Literal("]").suppress()
property_assignment = property_name("property_name") + p.Optional(p.Literal("=").suppress() + (cell_array ^ bytestring ^ stringlist)).setResultsName("value") + p.Literal(";").suppress()
cell_array = p.Literal("<").suppress() + \
p.ZeroOrMore(integer ^ arith_expr ^ string ^ reference ^ label_creation) + \
p.Literal(">").suppress()
bytestring = p.Literal("[").suppress() + \
(p.OneOrMore(p.Word(p.hexnums, exact=2) ^ label_creation)) + p.Literal("]").suppress()
property_assignment = property_name("property_name") + p.Optional(p.Literal("=").suppress() + \
(cell_array ^ bytestring ^ stringlist)).setResultsName("value") + p.Literal(";").suppress()

node_opener = p.Optional(label_creation) + node_name("node_name") + p.Optional(p.Literal("@").suppress() + unit_address("address")) + p.Literal("{").suppress()
node_opener = p.Optional(label_creation) + node_name("node_name") + \
p.Optional(p.Literal("@").suppress() + unit_address("address")) + p.Literal("{").suppress()
node_closer = p.Literal("}").suppress() + p.Literal(";").suppress()
node_definition = p.Forward()
node_definition << node_opener + p.ZeroOrMore(property_assignment ^ directive ^ node_definition) + node_closer
# pylint: disable=expression-not-assigned
node_definition << node_opener + p.ZeroOrMore(property_assignment ^ directive ^ node_definition) + \
node_closer

devicetree = p.ZeroOrMore(directive ^ node_definition)

Expand Down
36 changes: 19 additions & 17 deletions pydevicetree/source/parser.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
#!/usr/bin/env python3

from pydevicetree.source.grammar import *
from pydevicetree.ast.classes import *

from itertools import chain

from pydevicetree.source.grammar import *
from pydevicetree.ast import *

def transformNode(string, location, tokens):
properties = [e for e in tokens.asList() if type(e) is Property]
directives = [e for e in tokens.asList() if type(e) is Directive]
children = [e for e in tokens.asList() if type(e) is Node]
properties = [e for e in tokens.asList() if isinstance(e, Property)]
directives = [e for e in tokens.asList() if isinstance(e, Directive)]
children = [e for e in tokens.asList() if isinstance(e, Node)]

return Node(tokens.node_name, tokens.label, tokens.address, properties=properties, directives=directives, children=children)
return Node(tokens.node_name, tokens.label, tokens.address, properties=properties,
directives=directives, children=children)

def transformPropertyAssignment(string, location, tokens):
for v in tokens.value:
if type(v) is PropertyValues:
if isinstance(v, PropertyValues):
return Property(tokens.property_name, v)
if type(v) is CellArray:
if isinstance(v, CellArray):
return Property(tokens.property_name, v)
if type(v) is StringList:
if isinstance(v, StringList):
return Property(tokens.property_name, v)

return Property(tokens.property_name, PropertyValues([]))
Expand All @@ -29,10 +30,12 @@ def transformDirective(string, location, tokens):
def evaluateArithExpr(string, location, tokens):
flat_tokens = list(chain.from_iterable(tokens.asList()))
expr = " ".join(str(t) for t in flat_tokens)
# pylint: disable=eval-used
return eval(expr)

def transformTernary(string, location, tokens):
return eval(str(tokens[2]) +" if " + str(tokens[0]) + " else " + str(tokens[4]))
# pylint: disable=eval-used
return eval(str(tokens[2]) +" if " + str(tokens[0]) + " else " + str(tokens[4]))

def transformStringList(string, location, tokens):
return StringList(tokens.asList())
Expand Down Expand Up @@ -61,7 +64,7 @@ def printlevel(level, s):
print(" " * level + s)

for item in tree:
if type(item) is Node:
if isinstance(item, Node):
if item.address:
printlevel(level, "Node %s@%x" % (item.name, item.address))
else:
Expand All @@ -76,26 +79,26 @@ def printlevel(level, s):
printTree(item.properties, level=(level + 1))

printTree(item.children, level=(level + 1))
elif type(item) is Property:
elif isinstance(item, Property):
if item.values:
printlevel(level, "Property %s: %s" % (item.name, item.values))
else:
printlevel(level, "Property %s" % item.name)
elif type(item) is Directive:
elif isinstance(item, Directive):
if item.options:
printlevel(level, "Directive %s: %s" % (item.directive, item.options))
else:
printlevel(level, "Directive %s" % item.directive)

def parentNodes(tree, parent=None):
for item in tree:
if type(item) is Node:
if isinstance(item, Node):
item.parent = parent
parentNodes(item.children, item)

def recurseIncludeFiles(elements, pwd):
for e in elements:
if type(e) is Directive:
if isinstance(e, Directive):
if e.directive == "/include/":
# Prefix with current directory if path is not absolute
if e.options[0] != '/':
Expand Down Expand Up @@ -127,4 +130,3 @@ def parseTree(dts, pwd="", followIncludes=False):
else:
print("Please pass the devicetree source file as an argument")
sys.exit(1)

Loading

0 comments on commit 693abe1

Please sign in to comment.