3
3
import os .path as opath
4
4
import shutil
5
5
import subprocess
6
+ import sys
6
7
7
8
from codegen .datatypes import build_datatype_py , write_datatype_py
8
9
from codegen .compatibility import (
26
27
get_data_validator_instance ,
27
28
)
28
29
29
- # Target Python version for code formatting with Black.
30
- # Must be one of the values listed in pyproject.toml.
31
- BLACK_TARGET_VERSIONS = "py38 py39 py310 py311 py312"
32
-
33
30
34
31
# Import notes
35
32
# ------------
39
36
# helpers that are only needed during code generation should reside in the
40
37
# codegen/ package, and helpers used both during code generation and at
41
38
# runtime should reside in the _plotly_utils/ package.
42
- # ----------------------------------------------------------------------------
39
+
43
40
def preprocess_schema (plotly_schema ):
44
41
"""
45
42
Central location to make changes to schema before it's seen by the
46
43
PlotlyNode classes
47
44
"""
48
45
49
46
# Update template
50
- # ---------------
51
47
layout = plotly_schema ["layout" ]["layoutAttributes" ]
52
48
53
49
# Create codegen-friendly template scheme
@@ -89,33 +85,41 @@ def preprocess_schema(plotly_schema):
89
85
items ["colorscale" ] = items .pop ("concentrationscales" )
90
86
91
87
92
- def perform_codegen (reformat = True ):
93
- # Set root codegen output directory
94
- # ---------------------------------
95
- # (relative to project root)
96
- abs_file_path = opath .realpath (__file__ )
97
- project_root = opath .dirname (opath .dirname (abs_file_path ))
98
- outdir = opath .join (project_root , "plotly" )
88
+ def make_paths (outdir ):
89
+ """Make various paths needed for formatting and linting."""
90
+
91
+ validators_dir = opath .join (outdir , "validators" )
92
+ graph_objs_dir = opath .join (outdir , "graph_objs" )
93
+ graph_objects_path = opath .join (outdir , "graph_objects" , "__init__.py" )
94
+ return validators_dir , graph_objs_dir , graph_objects_path
95
+
96
+
97
+ def lint_code (outdir ):
98
+ """Check Python code using settings in pyproject.toml."""
99
+
100
+ subprocess .call (["ruff" , "check" , * make_paths (outdir )])
101
+
102
+
103
+ def reformat_code (outdir ):
104
+ """Reformat Python code using settings in pyproject.toml."""
105
+
106
+ subprocess .call (["ruff" , "format" , * make_paths (outdir )])
107
+
108
+
109
+ def perform_codegen (outdir , noformat = False ):
110
+ """Generate code (and possibly reformat)."""
111
+
112
+ # Get paths
113
+ validators_dir , graph_objs_dir , graph_objects_path = make_paths (outdir )
99
114
100
115
# Delete prior codegen output
101
- # ---------------------------
102
- validators_pkgdir = opath .join (outdir , "validators" )
103
- if opath .exists (validators_pkgdir ):
104
- shutil .rmtree (validators_pkgdir )
105
-
106
- graph_objs_pkgdir = opath .join (outdir , "graph_objs" )
107
- if opath .exists (graph_objs_pkgdir ):
108
- shutil .rmtree (graph_objs_pkgdir )
109
-
110
- # plotly/datatypes is not used anymore, but was at one point so we'll
111
- # still delete it if we find it in case a developer is upgrading from an
112
- # older version
113
- datatypes_pkgdir = opath .join (outdir , "datatypes" )
114
- if opath .exists (datatypes_pkgdir ):
115
- shutil .rmtree (datatypes_pkgdir )
116
+ if opath .exists (validators_dir ):
117
+ shutil .rmtree (validators_dir )
118
+ if opath .exists (graph_objs_dir ):
119
+ shutil .rmtree (graph_objs_dir )
116
120
117
121
# Load plotly schema
118
- # ------------------
122
+ project_root = opath . dirname ( outdir )
119
123
plot_schema_path = opath .join (
120
124
project_root , "codegen" , "resources" , "plot-schema.json"
121
125
)
@@ -124,19 +128,17 @@ def perform_codegen(reformat=True):
124
128
plotly_schema = json .load (f )
125
129
126
130
# Preprocess Schema
127
- # -----------------
128
131
preprocess_schema (plotly_schema )
129
132
130
133
# Build node lists
131
- # ----------------
132
- # ### TraceNode ###
134
+ # TraceNode
133
135
base_traces_node = TraceNode (plotly_schema )
134
136
compound_trace_nodes = PlotlyNode .get_all_compound_datatype_nodes (
135
137
plotly_schema , TraceNode
136
138
)
137
139
all_trace_nodes = PlotlyNode .get_all_datatype_nodes (plotly_schema , TraceNode )
138
140
139
- # ### LayoutNode ###
141
+ # LayoutNode
140
142
compound_layout_nodes = PlotlyNode .get_all_compound_datatype_nodes (
141
143
plotly_schema , LayoutNode
142
144
)
@@ -155,14 +157,14 @@ def perform_codegen(reformat=True):
155
157
if node .is_array_element and node .has_child ("xref" ) and node .has_child ("yref" )
156
158
]
157
159
158
- # ### FrameNode ###
160
+ # FrameNode
159
161
compound_frame_nodes = PlotlyNode .get_all_compound_datatype_nodes (
160
162
plotly_schema , FrameNode
161
163
)
162
164
frame_node = compound_frame_nodes [0 ]
163
165
all_frame_nodes = PlotlyNode .get_all_datatype_nodes (plotly_schema , FrameNode )
164
166
165
- # ### All nodes ###
167
+ # All nodes
166
168
all_datatype_nodes = all_trace_nodes + all_layout_nodes + all_frame_nodes
167
169
168
170
all_compound_nodes = [
@@ -172,37 +174,34 @@ def perform_codegen(reformat=True):
172
174
]
173
175
174
176
# Write out validators
175
- # --------------------
176
- # # ### Layout ###
177
+
178
+ # # Layout
177
179
for node in all_layout_nodes :
178
180
write_validator_py (outdir , node )
179
181
180
- # ### Trace ###
182
+ # Trace
181
183
for node in all_trace_nodes :
182
184
write_validator_py (outdir , node )
183
185
184
- # ### Frames ###
186
+ # Frames
185
187
for node in all_frame_nodes :
186
188
write_validator_py (outdir , node )
187
189
188
- # ### Data (traces) validator ###
190
+ # Data (traces) validator
189
191
write_data_validator_py (outdir , base_traces_node )
190
192
191
193
# Alls
192
- # ----
193
194
alls = {}
194
195
195
196
# Write out datatypes
196
- # -------------------
197
197
for node in all_compound_nodes :
198
198
write_datatype_py (outdir , node )
199
199
200
- # ### Deprecated ###
200
+ # Deprecated
201
201
# These are deprecated legacy datatypes like graph_objs.Marker
202
202
write_deprecated_datatypes (outdir )
203
203
204
204
# Write figure class to graph_objs
205
- # --------------------------------
206
205
data_validator = get_data_validator_instance (base_traces_node )
207
206
layout_validator = layout_node .get_validator_instance ()
208
207
frame_validator = frame_node .get_validator_instance ()
@@ -218,8 +217,7 @@ def perform_codegen(reformat=True):
218
217
)
219
218
220
219
# Write validator __init__.py files
221
- # ---------------------------------
222
- # ### Write __init__.py files for each validator package ###
220
+ # Write __init__.py files for each validator package
223
221
validator_rel_class_imports = {}
224
222
for node in all_datatype_nodes :
225
223
if node .is_mapped :
@@ -239,7 +237,6 @@ def perform_codegen(reformat=True):
239
237
write_init_py (validators_pkg , path_parts , [], rel_classes )
240
238
241
239
# Write datatype __init__.py files
242
- # --------------------------------
243
240
datatype_rel_class_imports = {}
244
241
datatype_rel_module_imports = {}
245
242
@@ -257,16 +254,16 @@ def perform_codegen(reformat=True):
257
254
f".{ node .name_undercase } "
258
255
)
259
256
260
- # ### Write plotly/graph_objs/graph_objs.py ###
261
- # This if for backward compatibility. It just imports everything from
257
+ # Write plotly/graph_objs/graph_objs.py
258
+ # This is for backward compatibility. It just imports everything from
262
259
# graph_objs/__init__.py
263
260
write_graph_objs_graph_objs (outdir )
264
261
265
- # ### Add Figure and FigureWidget ###
262
+ # Add Figure and FigureWidget
266
263
root_datatype_imports = datatype_rel_class_imports [()]
267
264
root_datatype_imports .append ("._figure.Figure" )
268
265
269
- # ### Add deprecations ###
266
+ # Add deprecations
270
267
for dep_clas in DEPRECATED_DATATYPES :
271
268
root_datatype_imports .append (f"._deprecations.{ dep_clas } " )
272
269
@@ -302,14 +299,14 @@ def __getattr__(import_name):
302
299
303
300
return orig_getattr(import_name)
304
301
"""
305
- # ### __all__ ###
302
+ # __all__
306
303
for path_parts , class_names in alls .items ():
307
304
if path_parts and class_names :
308
305
filepath = opath .join (outdir , "graph_objs" , * path_parts , "__init__.py" )
309
306
with open (filepath , "at" ) as f :
310
307
f .write (f"\n __all__ = { class_names } " )
311
308
312
- # ### Output datatype __init__.py files ###
309
+ # Output datatype __init__.py files
313
310
graph_objs_pkg = opath .join (outdir , "graph_objs" )
314
311
for path_parts in datatype_rel_class_imports :
315
312
rel_classes = sorted (datatype_rel_class_imports [path_parts ])
@@ -320,7 +317,7 @@ def __getattr__(import_name):
320
317
init_extra = ""
321
318
write_init_py (graph_objs_pkg , path_parts , rel_modules , rel_classes , init_extra )
322
319
323
- # ### Output graph_objects.py alias
320
+ # Output graph_objects.py alias
324
321
graph_objects_rel_classes = [
325
322
"..graph_objs." + rel_path .split ("." )[- 1 ]
326
323
for rel_path in datatype_rel_class_imports [()]
@@ -335,22 +332,19 @@ def __getattr__(import_name):
335
332
graph_objects_rel_classes ,
336
333
init_extra = optional_figure_widget_import ,
337
334
)
338
- graph_objects_path = opath .join (outdir , "graph_objects" , "__init__.py" )
339
335
os .makedirs (opath .join (outdir , "graph_objects" ), exist_ok = True )
340
336
with open (graph_objects_path , "wt" ) as f :
341
337
f .write (graph_objects_init_source )
342
338
343
- # ### Run black code formatter on output directories ###
344
- if reformat :
345
- target_version = [
346
- f"--target-version={ v } " for v in BLACK_TARGET_VERSIONS .split ()
347
- ]
348
- subprocess .call (["black" , * target_version , validators_pkgdir ])
349
- subprocess .call (["black" , * target_version , graph_objs_pkgdir ])
350
- subprocess .call (["black" , * target_version , graph_objects_path ])
351
- else :
339
+ # Run black code formatter on output directories
340
+ if noformat :
352
341
print ("skipping reformatting" )
342
+ else :
343
+ reformat_code (outdir )
353
344
354
345
355
346
if __name__ == "__main__" :
356
- perform_codegen ()
347
+ if len (sys .argv ) != 2 :
348
+ print ("Usage: codegen [dirname]" , file = sys .stderr )
349
+ sys .exit (1 )
350
+ perform_codegen (sys .argv [1 ])
0 commit comments