2626import hashlib
2727import json
2828import os
29+ import re
2930import subprocess
3031import sys
3132import tempfile
@@ -39,6 +40,9 @@ def main() -> None:
3940 """Run the migration steps."""
4041 # Add a separation line like this one after each migration step.
4142 print ("=" * 72 )
43+ print ("Removing default `-vv` from pytest addopts..." )
44+ migrate_pytest_addopts_default ()
45+ print ("=" * 72 )
4246 print ()
4347
4448 if _manual_steps :
@@ -308,6 +312,75 @@ def read_cookiecutter_str_var(name: str) -> str | None:
308312 return value
309313
310314
315+ def migrate_pytest_addopts_default () -> None :
316+ """Remove the default ``-vv`` from pytest addopts in ``pyproject.toml``.
317+
318+ Earlier versions of the template set ``addopts = "-vv"`` under
319+ ``[tool.pytest.ini_options]``. For projects with many tests this
320+ default produces a wall of output that makes it hard to see the
321+ results from other, previous, sessions. The template no longer ships
322+ this default; this step removes the matching line from existing
323+ projects.
324+
325+ The function is a no-op when ``pyproject.toml`` does not exist, when
326+ the ``[tool.pytest.ini_options]`` section is missing, or when the
327+ section has no ``addopts`` line (already migrated). A manual step is
328+ emitted when ``addopts`` is present but no longer matches the
329+ template default, so the maintainer can decide whether to drop
330+ ``-vv`` from the customized value.
331+ """
332+ pyproject = Path ("pyproject.toml" )
333+ if not pyproject .exists ():
334+ print (f" Skipped { pyproject } : file not found" )
335+ return
336+
337+ try :
338+ content = pyproject .read_text (encoding = "utf-8" )
339+ except OSError as exc :
340+ manual_step (
341+ f"Failed to read { pyproject } : { exc } . Please remove "
342+ '`addopts = "-vv"` from `[tool.pytest.ini_options]` manually.'
343+ )
344+ return
345+
346+ pytest_section_match = re .search (
347+ r"(?ms)^\[tool\.pytest\.ini_options\]\n.*?(?=^\[|\Z)" ,
348+ content ,
349+ )
350+ if pytest_section_match is None :
351+ print (f" Skipped { pyproject } : no [tool.pytest.ini_options] section" )
352+ return
353+
354+ pytest_section = pytest_section_match .group (0 )
355+ addopts_match = re .search (r"^addopts\s*=.*$" , pytest_section , flags = re .MULTILINE )
356+ if addopts_match is None :
357+ print (f" Skipped { pyproject } : no addopts in [tool.pytest.ini_options]" )
358+ return
359+
360+ addopts_line = addopts_match .group (0 )
361+ if addopts_line != 'addopts = "-vv"' :
362+ manual_step (
363+ f"{ pyproject } has a customized `{ addopts_line } ` line under "
364+ "[tool.pytest.ini_options]; please drop `-vv` from it manually "
365+ "if appropriate."
366+ )
367+ return
368+
369+ new_content = content .replace (f"{ addopts_line } \n " , "" , 1 )
370+
371+ try :
372+ replace_file_atomically (pyproject , new_content )
373+ print (
374+ f" Updated { pyproject } : removed default `-vv` from "
375+ "[tool.pytest.ini_options]"
376+ )
377+ except OSError as exc :
378+ manual_step (
379+ f"Failed to update { pyproject } : { exc } . Please remove "
380+ '`addopts = "-vv"` from `[tool.pytest.ini_options]` manually.'
381+ )
382+
383+
311384def manual_step (message : str ) -> None :
312385 """Print a manual step message in yellow."""
313386 _manual_steps .append (message )
0 commit comments