Skip to content

Commit

Permalink
Modernize Python (#135)
Browse files Browse the repository at this point in the history
Run pyupgrade and flynt to use f strings as well as other Python 3.7+
language features
  • Loading branch information
justinchuby committed Sep 28, 2022
1 parent e25c5a6 commit e45e2bd
Show file tree
Hide file tree
Showing 18 changed files with 103 additions and 111 deletions.
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
# -- Options for Sphinx Gallery ----------------------------------------------

intersphinx_mapping = {
"python": ("https://docs.python.org/{.major}".format(sys.version_info), None),
"python": (f"https://docs.python.org/{sys.version_info.major}", None),
"matplotlib": ("https://matplotlib.org/", None),
"numpy": ("https://docs.scipy.org/doc/numpy/", None),
"onnxruntime": ("https://onnxruntime.ai/docs/api/python/", None),
Expand All @@ -71,6 +71,6 @@
"gallery_dirs": ["auto_examples"],
"capture_repr": ("_repr_html_", "__repr__"),
"ignore_repr_types": r"matplotlib.text|matplotlib.axes",
"filename_pattern": re.escape(os.sep) + "[0-9]*_?plot_",
"filename_pattern": f"{re.escape(os.sep)}[0-9]*_?plot_",
"within_subsection_order": sphinx_gallery.sorting.FileNameSortKey,
}
5 changes: 2 additions & 3 deletions docs/test/test_documentation_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@ def do_test_folder(self, folder):
st = err.decode("ascii", errors="ignore")
if len(st) > 0 and "Traceback" in st:
raise RuntimeError( # pylint: disable=W0707
"Example '{}' (cmd: {} - exec_prefix="
"'{}') failed due to\n{}"
"".format(name, cmds, sys.exec_prefix, st)
f"Example '{name}' (cmd: {cmds} - exec_prefix='{sys.exec_prefix}') "
f"failed due to\n{st}"
)
tested += 1
if tested == 0:
Expand Down
2 changes: 1 addition & 1 deletion onnxscript/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def convert_file(script):
def to_single_model_proto(model, input_py_file: str, output_onnx_file: Optional[str] = None):
if not output_onnx_file:
prefix, _ = os.path.splitext(input_py_file)
output_onnx_file = prefix + ".onnx"
output_onnx_file = f"{prefix}.onnx"

fnlist = convert_file(input_py_file)

Expand Down
6 changes: 3 additions & 3 deletions onnxscript/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def get_loop_var(for_stmt, converter):
def used_vars(expr):
"""Return set of all variables used in an expression."""
if isinstance(expr, ast.Name):
return set([expr.id])
return {expr.id}
if isinstance(expr, ast.Call):
# Neither the callee-expression, nor keyword arguments are visited
# Only args counts towards used_vars
Expand Down Expand Up @@ -115,7 +115,7 @@ def visitBlock(block, live_out):
curr = live_out
while curr != prev:
prev = curr
curr = visitBlock(stmt.body, prev).difference(set([p_loop_var]))
curr = visitBlock(stmt.body, prev).difference({p_loop_var})
return curr
if isinstance(stmt, ast.While):
cond_vars = used_vars(stmt.test)
Expand Down Expand Up @@ -202,7 +202,7 @@ def visit(stmt, live_out):
if isinstance(stmt, ast.For):
# Analysis assumes loop may execute zero times. Results can be improved
# for loops that execute at least once.
loop_var_set = set([get_loop_var(stmt, converter)])
loop_var_set = {get_loop_var(stmt, converter)}
used_after_loop = live_out.difference(loop_var_set)
used_inside_loop = visitBlock(stmt.body, set()).difference(loop_var_set)
used_in_loop_header = used_vars(stmt.iter)
Expand Down
2 changes: 1 addition & 1 deletion onnxscript/autocast.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def cast(x, typeinfo):
if x.is_const() and typeinfo is not None:
# Scalar values are promoted to tensors of a type chosen as below:

tmp = converter.generate_unique_name(x.name + "_cast")
tmp = converter.generate_unique_name(f"{x.name}_cast")
converter.emit(
[tmp],
values.Op(converter.default_opset, "CastLike"),
Expand Down
4 changes: 2 additions & 2 deletions onnxscript/backend/onnx_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,11 +260,11 @@ def to_python(self):
for test in self.tests:
rows.append("xs = [")
for inp in test["inputs"]:
rows.append(textwrap.indent(repr(inp) + ",", " " * 2))
rows.append(textwrap.indent(f"{repr(inp)},", " " * 2))
rows.append("]")
rows.append("ys = [")
for out in test["outputs"]:
rows.append(textwrap.indent(repr(out) + ",", " " * 2))
rows.append(textwrap.indent(f"{repr(out)},", " " * 2))
rows.append("]")
rows.append("feeds = {n: x for n, x in zip(oinf.input_names, xs)}")
rows.append("got = oinf.run(feeds)")
Expand Down
89 changes: 42 additions & 47 deletions onnxscript/backend/onnx_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def _rename_variable(name):
# Handle graph/function input/output uniformly
name = name.name
if name in kwlist:
return "r_" + name
return f"r_{name}"
if name == "":
return None
return name
Expand All @@ -139,9 +139,9 @@ def _translate_type(onnx_type):
shape.append(d.dim_param)
if len(shape) == 0:
return name
return "%s[%s]" % (name, ",".join(shape))
return name + "[...]"
raise NotImplementedError("Unable to translate type %r into onnx-script type." % onnx_type)
return f"{name}[{','.join(shape)}]"
return f"{name}[...]"
raise NotImplementedError(f"Unable to translate type {onnx_type!r} into onnx-script type.")


def _translate_signature(inputs, outputs):
Expand All @@ -152,15 +152,15 @@ def _translate_signature(inputs, outputs):
def input_sig(inp: Union[ValueInfoProto, str]):
if isinstance(inp, ValueInfoProto):
# GraphProto inputs/outputs are ValueInfoProto
return _rename_variable(inp.name) + ": " + _translate_type(inp.type)
return f"{_rename_variable(inp.name)}: {_translate_type(inp.type)}"
else:
# FunctionProto inputs/outputs are just strings
return _rename_variable(inp)

result = "(" + ", ".join([input_sig(x) for x in inputs]) + ")"
result = f"({', '.join([input_sig(x) for x in inputs])})"
if outputs and isinstance(outputs[0], ValueInfoProto):
result += " -> (" + ", ".join([_translate_type(x.type) for x in outputs]) + ")"
return result + ":"
result += f" -> ({', '.join([_translate_type(x.type) for x in outputs])})"
return f"{result}:"


def _to_str(s):
Expand Down Expand Up @@ -188,7 +188,7 @@ def _attribute_value(attr):
return list(attr.ints)
if attr.strings:
return list(map(_to_str, attr.strings))
raise NotImplementedError("Unable to return a value for attribute %r." % attr)
raise NotImplementedError(f"Unable to return a value for attribute {attr!r}.")


def _python_make_node_name(domain, version, name, node=False):
Expand All @@ -197,8 +197,8 @@ def _python_make_node_name(domain, version, name, node=False):
version = 1
if not isinstance(version, int):
raise TypeError(
"version must be an integer not %r for domain=%r and name=%r."
% (version, domain, name)
f"version must be an integer not {version!r} for domain={domain!r} "
f"and name={name!r}."
)
if domain == "":
return "opset%d.%s" % (version, name)
Expand Down Expand Up @@ -244,8 +244,7 @@ def _python_make_node_graph(self, graph, opsets, indent=0, output_names=None):
if output_names is not None:
for fr, to in zip(graph.output, output_names):
code.append(
"%s%s = %s"
% (sindent, self._rename_variable(to), self._rename_variable(fr.name))
f"{sindent}{self._rename_variable(to)} = {self._rename_variable(fr.name)}"
)
final = "\n".join(code)
return final
Expand All @@ -255,20 +254,19 @@ def _python_make_node_make_attribute_str(self, node):
for at in node.attribute:
value = _attribute_value(at)
if isinstance(value, str):
attributes.append((at.name, "%r" % value))
attributes.append((at.name, f"{value!r}"))
continue
if isinstance(value, numpy.ndarray):
onnx_dtype = at.t.data_type
if len(value.shape) == 0:
text = 'make_tensor("value", %s, dims=[], vals=[%r])' "" % (
onnx_dtype,
value.tolist(),
text = (
f'make_tensor("value", {onnx_dtype}, dims=[], '
f"vals=[{value.tolist()!r}])"
)
else:
text = 'make_tensor("value", %s, dims=%r, vals=%r)' "" % (
onnx_dtype,
list(value.shape),
value.ravel().tolist(),
text = (
f'make_tensor("value", {onnx_dtype}, dims={list(value.shape)!r}, '
f"vals={value.ravel().tolist()!r})"
)
attributes.append((at.name, text))
continue
Expand All @@ -279,24 +277,24 @@ def _python_make_node_make_attribute_str(self, node):
text += f"{repr(name)}, {value.data_type}, {repr(list(value.dims))}"
text += f", {repr(metadata.location)}"
if metadata.offset:
text += ", offset=" + repr(metadata.offset)
text += f", offset={repr(metadata.offset)}"
if metadata.length:
text += ", length=" + repr(metadata.length)
text += f", length={repr(metadata.length)}"
attributes.append((at.name, text))
continue
attributes.append((at.name, repr(value)))

return ", ".join("%s=%s" % (k, v) for k, v in attributes)
return ", ".join(f"{k}={v}" for k, v in attributes)

def _python_make_node_if(self, node, opsets, indent=0):
"""
Translates a node If into python.
"""
sindent = " " * indent
code = ["%sif %s:" % (sindent, node.input[0])]
code = [f"{sindent}if {node.input[0]}:"]
if len(node.attribute) != 2:
raise RuntimeError(
"Node %r expected two attributes not %d." % (node.op_type, len(node.attribute))
f"Node {node.op_type!r} expected two attributes not {len(node.attribute)}."
)
atts = node.attribute
if atts[0].name == "else_branch":
Expand All @@ -308,7 +306,7 @@ def _python_make_node_if(self, node, opsets, indent=0):
then_branch, opsets, indent=indent + 1, output_names=node.output
)
)
code.append("%selse:" % sindent)
code.append(f"{sindent}else:")
code.append(
self._python_make_node_graph(
else_branch, opsets, indent=indent + 1, output_names=node.output
Expand All @@ -327,17 +325,17 @@ def _python_make_node_loop(self, node, opsets, indent=0):
# v_initial = node.input[2]
rows = []
if n_iter and not cond:
rows.append("%sfor %s in range(%s):" % (sindent, body.input[0].name, n_iter))
rows.append(f"{sindent}for {body.input[0].name} in range({n_iter}):")
elif not n_iter and cond:
rows.append("%swhile %s:" % (sindent, cond))
rows.append(f"{sindent}while {cond}:")
elif n_iter and cond:
rows.append("%sfor %s in range(%s):" % (sindent, body.input[0].name, n_iter))
rows.append("%s if not %s:" % (sindent, cond))
rows.append("%s break" % sindent)
rows.append(f"{sindent}for {body.input[0].name} in range({n_iter}):")
rows.append(f"{sindent} if not {cond}:")
rows.append(f"{sindent} break")
else:
raise RuntimeError(
"Unable to export loop type %r into python because there is no "
"stop condition." % (node.op_type,)
f"Unable to export loop type {node.op_type!r} into python because "
"there is no stop condition."
)
rows.append(
self._python_make_node_graph(
Expand Down Expand Up @@ -376,14 +374,14 @@ def _python_make_node(self, onnx_node, opsets, indent=0):
return self._python_make_node_loop(node, opsets, indent=indent)
if node.op_type == "Scan":
return self._python_make_node_scan(node, opsets, indent=indent)
raise RuntimeError("Unable to export node type %r into python." % (node.op_type,))
raise RuntimeError(f"Unable to export node type {node.op_type!r} into python.")
if any(
map(
lambda att: hasattr(att, "g") and att.g and att.g.ByteSize() > 0,
node.attribute,
)
):
raise RuntimeError("Unable to export node type %r into python." % node.op_type)
raise RuntimeError(f"Unable to export node type {node.op_type!r} into python.")
ops = {
"Add": "+",
"Sub": "-",
Expand All @@ -401,21 +399,20 @@ def _python_make_node(self, onnx_node, opsets, indent=0):
}
sindent = " " * indent
if self.use_operators and node.op_type in ops:
return "%s%s = %s" % (
sindent,
self._rename_variable(node.output[0]),
(" %s " % ops[node.op_type]).join(map(self.lookup, node.input)),
return (
f"{sindent}{self._rename_variable(node.output[0])} = "
f"{(' %s ' % ops[node.op_type]).join(map(self.lookup, node.input))}"
)
name = _python_make_node_name(
node.domain, opsets[node.domain], node.op_type, node=True
)
attributes_str = self._python_make_node_make_attribute_str(node)
if len(node.input) > 0 and len(attributes_str) > 0:
attributes_str = ", " + attributes_str
attributes_str = f", {attributes_str}"
output_names = []
for i, o in enumerate(node.output):
if o in ("", None):
output_names.append("_%d" % i)
output_names.append(f"_{i}")
else:
output_names.append(self._rename_variable(o))

Expand Down Expand Up @@ -543,13 +540,11 @@ def rename_variable(name):

final += "\n"
if "\nreturn" in final:
raise SyntaxError("The produced code is wrong.\n%s" % final)
raise SyntaxError(f"The produced code is wrong.\n{final}")
if clean_code:
cleaned_code = autopep8.fix_code(final, options=autopep_options)
if "\nreturn" in cleaned_code:
raise SyntaxError(
"The cleaned code is wrong.\n%s\n------%s" % (final, cleaned_code)
)
raise SyntaxError(f"The cleaned code is wrong.\n{final}\n------{cleaned_code}")
return cleaned_code
return final

Expand Down Expand Up @@ -599,7 +594,7 @@ def export2python(
model_onnx = onnx.load(model_onnx)

if not isinstance(model_onnx, (ModelProto, FunctionProto)):
raise TypeError("The function expects a ModelProto not %r." % type(model_onnx))
raise TypeError(f"The function expects a ModelProto not {type(model_onnx)!r}.")
code = export_template(
model_onnx,
template=_template_python,
Expand Down

0 comments on commit e45e2bd

Please sign in to comment.