33import os .path as opath
44import shutil
55import subprocess
6+ import sys
67
78from codegen .datatypes import build_datatype_py , write_datatype_py
89from codegen .compatibility import (
2627 get_data_validator_instance ,
2728)
2829
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-
3330
3431# Import notes
3532# ------------
3936# helpers that are only needed during code generation should reside in the
4037# codegen/ package, and helpers used both during code generation and at
4138# runtime should reside in the _plotly_utils/ package.
42- # ----------------------------------------------------------------------------
39+
4340def preprocess_schema (plotly_schema ):
4441 """
4542 Central location to make changes to schema before it's seen by the
4643 PlotlyNode classes
4744 """
4845
4946 # Update template
50- # ---------------
5147 layout = plotly_schema ["layout" ]["layoutAttributes" ]
5248
5349 # Create codegen-friendly template scheme
@@ -89,16 +85,22 @@ def preprocess_schema(plotly_schema):
8985 items ["colorscale" ] = items .pop ("concentrationscales" )
9086
9187
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)."""
99102
100103 # Delete prior codegen output
101- # ---------------------------
102104 validators_pkgdir = opath .join (outdir , "validators" )
103105 if opath .exists (validators_pkgdir ):
104106 shutil .rmtree (validators_pkgdir )
@@ -115,7 +117,7 @@ def perform_codegen(reformat=True):
115117 shutil .rmtree (datatypes_pkgdir )
116118
117119 # Load plotly schema
118- # ------------------
120+ project_root = opath . dirname ( outdir )
119121 plot_schema_path = opath .join (
120122 project_root , "codegen" , "resources" , "plot-schema.json"
121123 )
@@ -124,19 +126,17 @@ def perform_codegen(reformat=True):
124126 plotly_schema = json .load (f )
125127
126128 # Preprocess Schema
127- # -----------------
128129 preprocess_schema (plotly_schema )
129130
130131 # Build node lists
131- # ----------------
132- # ### TraceNode ###
132+ # TraceNode
133133 base_traces_node = TraceNode (plotly_schema )
134134 compound_trace_nodes = PlotlyNode .get_all_compound_datatype_nodes (
135135 plotly_schema , TraceNode
136136 )
137137 all_trace_nodes = PlotlyNode .get_all_datatype_nodes (plotly_schema , TraceNode )
138138
139- # ### LayoutNode ###
139+ # LayoutNode
140140 compound_layout_nodes = PlotlyNode .get_all_compound_datatype_nodes (
141141 plotly_schema , LayoutNode
142142 )
@@ -155,14 +155,14 @@ def perform_codegen(reformat=True):
155155 if node .is_array_element and node .has_child ("xref" ) and node .has_child ("yref" )
156156 ]
157157
158- # ### FrameNode ###
158+ # FrameNode
159159 compound_frame_nodes = PlotlyNode .get_all_compound_datatype_nodes (
160160 plotly_schema , FrameNode
161161 )
162162 frame_node = compound_frame_nodes [0 ]
163163 all_frame_nodes = PlotlyNode .get_all_datatype_nodes (plotly_schema , FrameNode )
164164
165- # ### All nodes ###
165+ # All nodes
166166 all_datatype_nodes = all_trace_nodes + all_layout_nodes + all_frame_nodes
167167
168168 all_compound_nodes = [
@@ -172,37 +172,34 @@ def perform_codegen(reformat=True):
172172 ]
173173
174174 # Write out validators
175- # --------------------
176- # # ### Layout ###
175+
176+ # # Layout
177177 for node in all_layout_nodes :
178178 write_validator_py (outdir , node )
179179
180- # ### Trace ###
180+ # Trace
181181 for node in all_trace_nodes :
182182 write_validator_py (outdir , node )
183183
184- # ### Frames ###
184+ # Frames
185185 for node in all_frame_nodes :
186186 write_validator_py (outdir , node )
187187
188- # ### Data (traces) validator ###
188+ # Data (traces) validator
189189 write_data_validator_py (outdir , base_traces_node )
190190
191191 # Alls
192- # ----
193192 alls = {}
194193
195194 # Write out datatypes
196- # -------------------
197195 for node in all_compound_nodes :
198196 write_datatype_py (outdir , node )
199197
200- # ### Deprecated ###
198+ # Deprecated
201199 # These are deprecated legacy datatypes like graph_objs.Marker
202200 write_deprecated_datatypes (outdir )
203201
204202 # Write figure class to graph_objs
205- # --------------------------------
206203 data_validator = get_data_validator_instance (base_traces_node )
207204 layout_validator = layout_node .get_validator_instance ()
208205 frame_validator = frame_node .get_validator_instance ()
@@ -218,8 +215,7 @@ def perform_codegen(reformat=True):
218215 )
219216
220217 # Write validator __init__.py files
221- # ---------------------------------
222- # ### Write __init__.py files for each validator package ###
218+ # Write __init__.py files for each validator package
223219 validator_rel_class_imports = {}
224220 for node in all_datatype_nodes :
225221 if node .is_mapped :
@@ -239,7 +235,6 @@ def perform_codegen(reformat=True):
239235 write_init_py (validators_pkg , path_parts , [], rel_classes )
240236
241237 # Write datatype __init__.py files
242- # --------------------------------
243238 datatype_rel_class_imports = {}
244239 datatype_rel_module_imports = {}
245240
@@ -257,16 +252,16 @@ def perform_codegen(reformat=True):
257252 f".{ node .name_undercase } "
258253 )
259254
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
262257 # graph_objs/__init__.py
263258 write_graph_objs_graph_objs (outdir )
264259
265- # ### Add Figure and FigureWidget ###
260+ # Add Figure and FigureWidget
266261 root_datatype_imports = datatype_rel_class_imports [()]
267262 root_datatype_imports .append ("._figure.Figure" )
268263
269- # ### Add deprecations ###
264+ # Add deprecations
270265 for dep_clas in DEPRECATED_DATATYPES :
271266 root_datatype_imports .append (f"._deprecations.{ dep_clas } " )
272267
@@ -302,14 +297,14 @@ def __getattr__(import_name):
302297
303298 return orig_getattr(import_name)
304299"""
305- # ### __all__ ###
300+ # __all__
306301 for path_parts , class_names in alls .items ():
307302 if path_parts and class_names :
308303 filepath = opath .join (outdir , "graph_objs" , * path_parts , "__init__.py" )
309304 with open (filepath , "at" ) as f :
310305 f .write (f"\n __all__ = { class_names } " )
311306
312- # ### Output datatype __init__.py files ###
307+ # Output datatype __init__.py files
313308 graph_objs_pkg = opath .join (outdir , "graph_objs" )
314309 for path_parts in datatype_rel_class_imports :
315310 rel_classes = sorted (datatype_rel_class_imports [path_parts ])
@@ -320,7 +315,7 @@ def __getattr__(import_name):
320315 init_extra = ""
321316 write_init_py (graph_objs_pkg , path_parts , rel_modules , rel_classes , init_extra )
322317
323- # ### Output graph_objects.py alias
318+ # Output graph_objects.py alias
324319 graph_objects_rel_classes = [
325320 "..graph_objs." + rel_path .split ("." )[- 1 ]
326321 for rel_path in datatype_rel_class_imports [()]
@@ -340,17 +335,15 @@ def __getattr__(import_name):
340335 with open (graph_objects_path , "wt" ) as f :
341336 f .write (graph_objects_init_source )
342337
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 :
352340 print ("skipping reformatting" )
341+ else :
342+ reformat_code (outdir )
353343
354344
355345if __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