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,16 +85,22 @@ 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 lint_code ():
89
+ """Check Python code using settings in pyproject.toml."""
90
+
91
+ subprocess .call (["ruff" , "check" , "." ])
92
+
93
+
94
+ def reformat_code (outdir ):
95
+ """Reformat Python code using settings in pyproject.toml."""
96
+
97
+ subprocess .call (["ruff" , "format" , outdir ])
98
+
99
+
100
+ def perform_codegen (outdir , noformat = False ):
101
+ """Generate code (and possibly reformat)."""
99
102
100
103
# Delete prior codegen output
101
- # ---------------------------
102
104
validators_pkgdir = opath .join (outdir , "validators" )
103
105
if opath .exists (validators_pkgdir ):
104
106
shutil .rmtree (validators_pkgdir )
@@ -115,7 +117,7 @@ def perform_codegen(reformat=True):
115
117
shutil .rmtree (datatypes_pkgdir )
116
118
117
119
# Load plotly schema
118
- # ------------------
120
+ project_root = opath . dirname ( outdir )
119
121
plot_schema_path = opath .join (
120
122
project_root , "codegen" , "resources" , "plot-schema.json"
121
123
)
@@ -124,19 +126,17 @@ def perform_codegen(reformat=True):
124
126
plotly_schema = json .load (f )
125
127
126
128
# Preprocess Schema
127
- # -----------------
128
129
preprocess_schema (plotly_schema )
129
130
130
131
# Build node lists
131
- # ----------------
132
- # ### TraceNode ###
132
+ # TraceNode
133
133
base_traces_node = TraceNode (plotly_schema )
134
134
compound_trace_nodes = PlotlyNode .get_all_compound_datatype_nodes (
135
135
plotly_schema , TraceNode
136
136
)
137
137
all_trace_nodes = PlotlyNode .get_all_datatype_nodes (plotly_schema , TraceNode )
138
138
139
- # ### LayoutNode ###
139
+ # LayoutNode
140
140
compound_layout_nodes = PlotlyNode .get_all_compound_datatype_nodes (
141
141
plotly_schema , LayoutNode
142
142
)
@@ -155,14 +155,14 @@ def perform_codegen(reformat=True):
155
155
if node .is_array_element and node .has_child ("xref" ) and node .has_child ("yref" )
156
156
]
157
157
158
- # ### FrameNode ###
158
+ # FrameNode
159
159
compound_frame_nodes = PlotlyNode .get_all_compound_datatype_nodes (
160
160
plotly_schema , FrameNode
161
161
)
162
162
frame_node = compound_frame_nodes [0 ]
163
163
all_frame_nodes = PlotlyNode .get_all_datatype_nodes (plotly_schema , FrameNode )
164
164
165
- # ### All nodes ###
165
+ # All nodes
166
166
all_datatype_nodes = all_trace_nodes + all_layout_nodes + all_frame_nodes
167
167
168
168
all_compound_nodes = [
@@ -172,37 +172,34 @@ def perform_codegen(reformat=True):
172
172
]
173
173
174
174
# Write out validators
175
- # --------------------
176
- # # ### Layout ###
175
+
176
+ # # Layout
177
177
for node in all_layout_nodes :
178
178
write_validator_py (outdir , node )
179
179
180
- # ### Trace ###
180
+ # Trace
181
181
for node in all_trace_nodes :
182
182
write_validator_py (outdir , node )
183
183
184
- # ### Frames ###
184
+ # Frames
185
185
for node in all_frame_nodes :
186
186
write_validator_py (outdir , node )
187
187
188
- # ### Data (traces) validator ###
188
+ # Data (traces) validator
189
189
write_data_validator_py (outdir , base_traces_node )
190
190
191
191
# Alls
192
- # ----
193
192
alls = {}
194
193
195
194
# Write out datatypes
196
- # -------------------
197
195
for node in all_compound_nodes :
198
196
write_datatype_py (outdir , node )
199
197
200
- # ### Deprecated ###
198
+ # Deprecated
201
199
# These are deprecated legacy datatypes like graph_objs.Marker
202
200
write_deprecated_datatypes (outdir )
203
201
204
202
# Write figure class to graph_objs
205
- # --------------------------------
206
203
data_validator = get_data_validator_instance (base_traces_node )
207
204
layout_validator = layout_node .get_validator_instance ()
208
205
frame_validator = frame_node .get_validator_instance ()
@@ -218,8 +215,7 @@ def perform_codegen(reformat=True):
218
215
)
219
216
220
217
# Write validator __init__.py files
221
- # ---------------------------------
222
- # ### Write __init__.py files for each validator package ###
218
+ # Write __init__.py files for each validator package
223
219
validator_rel_class_imports = {}
224
220
for node in all_datatype_nodes :
225
221
if node .is_mapped :
@@ -239,7 +235,6 @@ def perform_codegen(reformat=True):
239
235
write_init_py (validators_pkg , path_parts , [], rel_classes )
240
236
241
237
# Write datatype __init__.py files
242
- # --------------------------------
243
238
datatype_rel_class_imports = {}
244
239
datatype_rel_module_imports = {}
245
240
@@ -257,16 +252,16 @@ def perform_codegen(reformat=True):
257
252
f".{ node .name_undercase } "
258
253
)
259
254
260
- # ### Write plotly/graph_objs/graph_objs.py ###
261
- # This if for backward compatibility. It just imports everything from
255
+ # Write plotly/graph_objs/graph_objs.py
256
+ # This is for backward compatibility. It just imports everything from
262
257
# graph_objs/__init__.py
263
258
write_graph_objs_graph_objs (outdir )
264
259
265
- # ### Add Figure and FigureWidget ###
260
+ # Add Figure and FigureWidget
266
261
root_datatype_imports = datatype_rel_class_imports [()]
267
262
root_datatype_imports .append ("._figure.Figure" )
268
263
269
- # ### Add deprecations ###
264
+ # Add deprecations
270
265
for dep_clas in DEPRECATED_DATATYPES :
271
266
root_datatype_imports .append (f"._deprecations.{ dep_clas } " )
272
267
@@ -302,14 +297,14 @@ def __getattr__(import_name):
302
297
303
298
return orig_getattr(import_name)
304
299
"""
305
- # ### __all__ ###
300
+ # __all__
306
301
for path_parts , class_names in alls .items ():
307
302
if path_parts and class_names :
308
303
filepath = opath .join (outdir , "graph_objs" , * path_parts , "__init__.py" )
309
304
with open (filepath , "at" ) as f :
310
305
f .write (f"\n __all__ = { class_names } " )
311
306
312
- # ### Output datatype __init__.py files ###
307
+ # Output datatype __init__.py files
313
308
graph_objs_pkg = opath .join (outdir , "graph_objs" )
314
309
for path_parts in datatype_rel_class_imports :
315
310
rel_classes = sorted (datatype_rel_class_imports [path_parts ])
@@ -320,7 +315,7 @@ def __getattr__(import_name):
320
315
init_extra = ""
321
316
write_init_py (graph_objs_pkg , path_parts , rel_modules , rel_classes , init_extra )
322
317
323
- # ### Output graph_objects.py alias
318
+ # Output graph_objects.py alias
324
319
graph_objects_rel_classes = [
325
320
"..graph_objs." + rel_path .split ("." )[- 1 ]
326
321
for rel_path in datatype_rel_class_imports [()]
@@ -340,17 +335,15 @@ def __getattr__(import_name):
340
335
with open (graph_objects_path , "wt" ) as f :
341
336
f .write (graph_objects_init_source )
342
337
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 :
338
+ # Run black code formatter on output directories
339
+ if noformat :
352
340
print ("skipping reformatting" )
341
+ else :
342
+ reformat_code (outdir )
353
343
354
344
355
345
if __name__ == "__main__" :
356
- perform_codegen ()
346
+ if len (sys .argv ) != 2 :
347
+ print ("Usage: codegen [dirname]" , file = sys .stderr )
348
+ sys .exit (1 )
349
+ perform_codegen (sys .argv [1 ])
0 commit comments