@@ -282,7 +282,28 @@ def cmd_baseline(self) -> bool:
282282
283283 return success
284284
285- def cmd_clean (self ) -> bool :
285+ def cmd_precommit (self , extra_args : Optional [List [str ]] = None ) -> bool :
286+ """Run pre-commit hooks on all files."""
287+ self ._print_header ("Running Pre-commit Hooks" )
288+
289+ # Check if pre-commit is available
290+ if not self ._check_tool_available ("pre-commit" , ["pre-commit" , "--version" ]):
291+ return False
292+
293+ cmd = ["pre-commit" , "run" , "--all-files" ]
294+
295+ # Add any extra arguments
296+ if extra_args :
297+ cmd .extend (extra_args )
298+
299+ success = self ._run_command_with_confirmation (cmd )
300+
301+ if success :
302+ self ._print_success ("Pre-commit hooks completed successfully!" )
303+ else :
304+ self ._print_error ("Pre-commit hooks failed!" )
305+
306+ return success
286307 """Clean up test artifacts and cache files."""
287308 self ._print_header ("Cleaning Test Artifacts" )
288309
@@ -324,35 +345,112 @@ def cmd_clean(self) -> bool:
324345
325346 return True
326347
327- def cmd_precommit (self , extra_args : Optional [List [str ]] = None ) -> bool :
328- """Run pre-commit hooks on all files."""
329- # Check if pre-commit is available
330- if not self ._check_tool_available ("pre-commit" , ["pre-commit" , "--version" ]):
348+ def cmd_docs (
349+ self ,
350+ action : str = "build" ,
351+ port : int = 8000 ,
352+ clean : bool = True ,
353+ extra_args : Optional [List [str ]] = None ,
354+ ) -> bool :
355+ """Build or serve documentation."""
356+ # Check if mkdocs is available
357+ if not self ._check_tool_available ("mkdocs" , ["mkdocs" , "--version" ]):
331358 return False
332359
333- # Check if .pre-commit-config.yaml exists
334- precommit_config = self .project_root / ".pre-commit-config.yaml"
335- if not precommit_config .exists ():
336- self ._print_warning ("No .pre-commit-config.yaml found" )
337- self ._print_warning (
338- "Run 'pre-commit install' to set up hooks for this repository"
339- )
360+ # Check if new_docs directory exists
361+ docs_dir = self .project_root / "new_docs"
362+ if not docs_dir .exists ():
363+ self ._print_error ("new_docs directory not found!" )
340364 return False
341365
342- # Run pre-commit on all files
343- cmd = ["pre-commit" , "run" , "--all-files" ]
366+ if action == "build" :
367+ return self ._build_docs (clean , extra_args )
368+ if action == "serve" :
369+ return self ._serve_docs (port , extra_args )
370+ self ._print_error (f"Unknown docs action: { action } " )
371+ return False
344372
345- # Add any extra arguments passed through from CLI
373+ def _build_docs (self , clean : bool , extra_args : Optional [List [str ]] = None ) -> bool :
374+ """Build documentation."""
375+ self ._print_header ("Building Documentation" )
376+
377+ cmd = ["mkdocs" , "build" ]
378+ if clean :
379+ cmd .append ("--clean" )
380+
381+ # Add any extra arguments
346382 if extra_args :
347383 cmd .extend (extra_args )
348384
349- success = self ._run_command_with_confirmation (cmd )
385+ success = self ._run_command (cmd , cwd = self . project_root / "new_docs" )
350386
351387 if success :
352- self ._print_success ("Pre-commit hooks completed successfully!" )
388+ self ._print_success ("Documentation built successfully!" )
389+ site_dir = self .project_root / "new_docs" / "site"
390+ if site_dir .exists ():
391+ self ._print_success (f"Built site available at: { site_dir } " )
353392 else :
354- self ._print_warning ("Pre-commit hooks found issues (this is normal)" )
355- self ._print_warning ("Review the output above and fix any issues" )
393+ self ._print_error ("Documentation build failed!" )
394+
395+ return success
396+
397+ def _serve_docs (self , port : int , extra_args : Optional [List [str ]] = None ) -> bool :
398+ """Serve documentation locally."""
399+ self ._print_header (f"Serving Documentation on port { port } " )
400+
401+ cmd = ["mkdocs" , "serve" , "--dev-addr" , f"127.0.0.1:{ port } " ]
402+
403+ # Add any extra arguments
404+ if extra_args :
405+ cmd .extend (extra_args )
406+
407+ self ._print_success (
408+ f"Documentation will be available at: http://127.0.0.1:{ port } "
409+ )
410+ self ._print_warning ("Press Ctrl+C to stop the server" )
411+
412+ # For serve, we don't use confirmation since it's a long-running process
413+ return self ._run_command (cmd , cwd = self .project_root / "new_docs" )
414+
415+ def cmd_clean (self ) -> bool :
416+ """Clean up test artifacts and cache files."""
417+ self ._print_header ("Cleaning Test Artifacts" )
418+
419+ items_to_clean = self ._find_files_to_clean ()
420+
421+ if not items_to_clean :
422+ self ._print_success ("Nothing to clean!" )
423+ return True
424+
425+ self ._show_summary (
426+ items_to_clean , f"Items to be removed ({ len (items_to_clean )} total)"
427+ )
428+
429+ if not self ._confirm (
430+ f"Remove these { len (items_to_clean )} items?" , default = True
431+ ):
432+ self ._print_warning ("Clean operation cancelled" )
433+ return True
434+
435+ removed_count = 0
436+ for item in items_to_clean :
437+ try :
438+ if item .is_dir ():
439+ shutil .rmtree (item )
440+ else :
441+ item .unlink ()
442+ removed_count += 1
443+ if len (items_to_clean ) <= 10 : # Show individual items for small lists
444+ self ._print_success (
445+ f"Removed { item .relative_to (self .project_root )} "
446+ )
447+ except OSError as e :
448+ self ._print_error (f"Failed to remove { item } : { e } " )
449+
450+ if len (items_to_clean ) > 10 :
451+ self ._print_success (
452+ f"Successfully removed { removed_count } /{ len (items_to_clean )} items"
453+ )
356454
357455 return True
358456
@@ -615,6 +713,7 @@ def show_help(self) -> None:
615713 test Run pytest with matplotlib comparison
616714 baseline Generate baseline images for matplotlib tests
617715 benchmark Run performance benchmarks
716+ docs Build or serve documentation
618717 clean Clean up test artifacts
619718 precommit Run pre-commit hooks on all files
620719 help Show this help
@@ -633,13 +732,21 @@ def show_help(self) -> None:
633732 --save NAME Save benchmark results with custom name
634733 --with NAME Compare with specific baseline
635734
735+ Docs command options:
736+ build Build documentation (default action)
737+ serve Serve documentation locally
738+ --port PORT Port for serve command (default: 8000)
739+ --no-clean Skip --clean flag for build command
740+
636741Examples:
637742 ./dev test -n 4 # Run tests with 4 jobs
638743 ./dev test -k "test_basic" # Run only tests matching "test_basic"
639744 ./dev test --verbose -s # Pass pytest arguments directly
640745 ./dev benchmark run --save baseline # Run benchmarks and save as 'baseline'
641746 ./dev benchmark compare --with baseline # Compare with 'baseline'
642747 ./dev benchmark list # List available baselines
748+ ./dev docs build # Build documentation
749+ ./dev docs serve --port 8080 # Serve documentation on port 8080
643750 ./dev clean # Clean up test artifacts
644751 """
645752 print (help_text )
@@ -925,6 +1032,16 @@ def make_menu_item(title, command_text):
9251032 ),
9261033 "baseline" ,
9271034 ),
1035+ (
1036+ make_menu_item (
1037+ "📚 Build documentation" , "cd new_docs && mkdocs build --clean"
1038+ ),
1039+ "docs_build" ,
1040+ ),
1041+ (
1042+ make_menu_item ("🌐 Serve documentation" , "cd new_docs && mkdocs serve" ),
1043+ "docs_serve" ,
1044+ ),
9281045 (
9291046 make_menu_item (
9301047 "⚡ Run benchmarks" , "python -m pytest --benchmark-only"
@@ -967,6 +1084,10 @@ def make_menu_item(title, command_text):
9671084 self .cmd_clean ()
9681085 elif choice == "precommit" :
9691086 self .cmd_precommit ()
1087+ elif choice == "docs_build" :
1088+ self .cmd_docs ("build" , clean = True )
1089+ elif choice == "docs_serve" :
1090+ self .cmd_docs ("serve" , port = 8000 )
9701091 elif choice == "benchmark" :
9711092 self ._interactive_benchmark_menu ()
9721093 elif choice == "help" :
@@ -1080,6 +1201,24 @@ def main():
10801201 "--with" , dest = "compare_with" , type = str , help = "Compare with specific baseline"
10811202 )
10821203
1204+ # Docs command
1205+ docs_parser = subparsers .add_parser ("docs" , help = "Build or serve documentation" )
1206+ docs_parser .add_argument (
1207+ "action" ,
1208+ choices = ["build" , "serve" ],
1209+ default = "build" ,
1210+ nargs = "?" ,
1211+ help = "Documentation action (default: build)" ,
1212+ )
1213+ docs_parser .add_argument (
1214+ "--port" , type = int , default = 8000 , help = "Port for serve command (default: 8000)"
1215+ )
1216+ docs_parser .add_argument (
1217+ "--no-clean" ,
1218+ action = "store_true" ,
1219+ help = "Skip --clean flag for build command" ,
1220+ )
1221+
10831222 # Other commands
10841223 subparsers .add_parser (
10851224 "baseline" , help = "Generate baseline images for matplotlib tests"
@@ -1150,6 +1289,9 @@ def main():
11501289 baseline_name = getattr (args , "save" , None )
11511290 compare_with = getattr (args , "compare_with" , None )
11521291 success = dev .cmd_benchmark (args .action , baseline_name , compare_with )
1292+ elif args .command == "docs" :
1293+ clean = not getattr (args , "no_clean" , False )
1294+ success = dev .cmd_docs (args .action , args .port , clean , unknown_args )
11531295 elif args .command == "clean" :
11541296 success = dev .cmd_clean ()
11551297 elif args .command == "precommit" :
0 commit comments