1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
|
import os.path as opath
from io import StringIO
import _plotly_utils.basevalidators
from codegen.utils import PlotlyNode, TraceNode, write_source_py
def build_validator_py(node: PlotlyNode):
"""
Build validator class source code string for a datatype PlotlyNode
Parameters
----------
node : PlotlyNode
The datatype node (node.is_datatype must evaluate to true) for which
to build the validator class
Returns
-------
str
String containing source code for the validator class definition
"""
# Validate inputs
# ---------------
assert node.is_datatype
# Initialize source code buffer
# -----------------------------
buffer = StringIO()
# Imports
# -------
# ### Import package of the validator's superclass ###
import_str = ".".join(node.name_base_validator.split(".")[:-1])
buffer.write(f"import {import_str }\n")
# Build Validator
# ---------------
# ### Get dict of validator's constructor params ###
params = node.get_validator_params()
# ### Write class definition ###
class_name = node.name_validator_class
superclass_name = node.name_base_validator
buffer.write(
f"""
class {class_name}({superclass_name}):
def __init__(self, plotly_name={params['plotly_name']},
parent_name={params['parent_name']},
**kwargs):"""
)
# ### Write constructor ###
buffer.write(
f"""
super({class_name}, self).__init__(plotly_name=plotly_name,
parent_name=parent_name"""
)
# Write out remaining constructor parameters
for attr_name, attr_val in params.items():
if attr_name in ["plotly_name", "parent_name"]:
# plotly_name and parent_name are already handled
continue
buffer.write(
f""",
{attr_name}=kwargs.pop('{attr_name}', {attr_val})"""
)
buffer.write(
f""",
**kwargs"""
)
buffer.write(")")
# ### Return buffer's string ###
return buffer.getvalue()
def write_validator_py(outdir, node: PlotlyNode):
"""
Build validator source code and write to a file
Parameters
----------
outdir : str
Root outdir in which the validators package should reside
node : PlotlyNode
The datatype node (node.is_datatype must evaluate to true) for which
to build a validator class
Returns
-------
None
"""
if node.is_mapped:
# No validator written for mapped nodes
# e.g. no validator for layout.titlefont since ths is mapped to
# layout.title.font
return
# Generate source code
# --------------------
validator_source = build_validator_py(node)
# Write file
# ----------
# filepath = opath.join(outdir, "validators", *node.parent_path_parts, "__init__.py")
filepath = opath.join(
outdir, "validators", *node.parent_path_parts, "_" + node.name_property + ".py"
)
write_source_py(validator_source, filepath, leading_newlines=2)
def build_data_validator_params(base_trace_node: TraceNode):
"""
Build a dict of constructor params for the DataValidator.
(This is the validator that inputs a list of traces)
Parameters
----------
base_trace_node : PlotlyNode
PlotlyNode that is the parent of all of the individual trace nodes
Returns
-------
dict
Mapping from property name to repr-string of property value.
"""
# Get list of trace nodes
# -----------------------
tracetype_nodes = base_trace_node.child_compound_datatypes
# Build class_map_repr string
# ---------------------------
# This is the repr-form of a dict from trace propert name string
# to the name of the trace datatype class in the graph_objs package.
buffer = StringIO()
buffer.write("{\n")
for i, tracetype_node in enumerate(tracetype_nodes):
sfx = "," if i < len(tracetype_nodes) else ""
trace_name = tracetype_node.name_property
trace_datatype_class = tracetype_node.name_datatype_class
buffer.write(
f"""
'{trace_name}': '{trace_datatype_class}'{sfx}"""
)
buffer.write(
"""
}"""
)
class_map_repr = buffer.getvalue()
# Build params dict
# -----------------
params = {
"class_strs_map": class_map_repr,
"plotly_name": repr("data"),
"parent_name": repr(""),
}
return params
def build_data_validator_py(base_trace_node: TraceNode):
"""
Build source code for the DataValidator
(this is the validator that inputs a list of traces)
Parameters
----------
base_trace_node : PlotlyNode
PlotlyNode that is the parent of all of the individual trace nodes
Returns
-------
str
Source code string for DataValidator class
"""
# Get constructor params
# ----------------------
params = build_data_validator_params(base_trace_node)
# Build source code
# -----------------
buffer = StringIO()
buffer.write(
f"""
import _plotly_utils.basevalidators
class DataValidator(_plotly_utils.basevalidators.BaseDataValidator):
def __init__(self, plotly_name={params['plotly_name']},
parent_name={params['parent_name']},
**kwargs):
super(DataValidator, self).__init__(class_strs_map={params['class_strs_map']},
plotly_name=plotly_name,
parent_name=parent_name,
**kwargs)"""
)
return buffer.getvalue()
def get_data_validator_instance(base_trace_node: TraceNode):
"""
Construct an instance of the DataValidator
(this is the validator that inputs a list of traces)
Parameters
----------
base_trace_node :
PlotlyNode that is the parent of all of the individual trace nodes
Returns
-------
BaseDataValidator
"""
# Build constructor params
# ------------------------
# We need to eval the values to convert out of the repr-form of the
# params. e.g. '3' -> 3
params = build_data_validator_params(base_trace_node)
eval_params = {k: eval(repr_val) for k, repr_val in params.items()}
# Build and return BaseDataValidator instance
# -------------------------------------------
return _plotly_utils.basevalidators.BaseDataValidator(**eval_params)
def write_data_validator_py(outdir, base_trace_node: TraceNode):
"""
Construct and write out the DataValidator
(this is the validator that inputs a list of traces)
Parameters
----------
outdir : str
Root outdir in which the top-level validators package should reside
base_trace_node : PlotlyNode
PlotlyNode that is the parent of all of the individual trace nodes
Returns
-------
None
"""
# Validate inputs
# ---------------
if base_trace_node.node_path:
raise ValueError(
"Expected root trace node.\n"
'Received node with path "%s"' % base_trace_node.path_str
)
# Build Source
# ------------
source = build_data_validator_py(base_trace_node)
# Write file
# ----------
# filepath = opath.join(outdir, "validators", "__init__.py")
filepath = opath.join(outdir, "validators", "_data.py")
write_source_py(source, filepath, leading_newlines=2)
|