|
22 | 22 |
|
23 | 23 | import hashlib |
24 | 24 | import os |
25 | | -import re |
26 | 25 | import subprocess |
27 | 26 | import tempfile |
28 | 27 | from pathlib import Path |
29 | | -from typing import Final, SupportsIndex |
| 28 | +from typing import SupportsIndex |
30 | 29 |
|
31 | 30 |
|
32 | 31 | def main() -> None: |
33 | 32 | """Run the migration steps.""" |
34 | 33 | # Add a separation line like this one after each migration step. |
35 | 34 | print("=" * 72) |
36 | | - migrate_filterwarnings(Path("pyproject.toml")) |
37 | | - print( |
38 | | - "Renaming the deprecated mkdocstrings `import` to `inventories` in `mkdocs.yml`..." |
39 | | - ) |
40 | | - print("=" * 72) |
41 | | - replace_file_contents_atomically( |
42 | | - "mkdocs.yml", " import:", " inventories:" |
43 | | - ) |
44 | | - print("=" * 72) |
45 | | - print("Fixing wrongly located `paths` keys in mkdocs.yml...") |
46 | | - migrate_mkdocs_yaml(Path("mkdocs.yml")) |
47 | | - print("=" * 72) |
48 | 35 | print("Migration script finished. Remember to follow any manual instructions.") |
49 | 36 | print("=" * 72) |
50 | 37 |
|
51 | 38 |
|
52 | | -# pylint: disable-next=too-many-locals,too-many-statements,too-many-branches |
53 | | -def migrate_filterwarnings(path: Path) -> None: |
54 | | - """Migrate the filterwarnings configuration in pyproject.toml files.""" |
55 | | - print(f"Migrating from pytest addopts to filterwarnings in {path}...") |
56 | | - # Patterns to identify and clean existing addopts flags |
57 | | - addopts_re: Final = re.compile(r'^(\s*)addopts\s*=\s*"(.*)"') |
58 | | - filterwarnings_re: Final = re.compile(r"^(\s*)filterwarnings\s*=\s*(.*)") |
59 | | - w_flag_re: Final = re.compile(r"^-W=?(.*)$") |
60 | | - unwanted_flags: Final = { |
61 | | - "-W=all", |
62 | | - "-Werror", |
63 | | - "-Wdefault::DeprecationWarning", |
64 | | - "-Wdefault::PendingDeprecationWarning", |
65 | | - } |
66 | | - |
67 | | - text = path.read_text(encoding="utf-8") |
68 | | - lines = text.splitlines(keepends=True) |
69 | | - new_lines: list[str] = [] |
70 | | - modified = False |
71 | | - addopts_found = False |
72 | | - has_filterwarnings = False |
73 | | - has_w_flags = False |
74 | | - w_flags: list[str] = [] |
75 | | - |
76 | | - for line in lines: |
77 | | - filterwarnings_match = filterwarnings_re.match(line) |
78 | | - if filterwarnings_match: |
79 | | - has_filterwarnings = True |
80 | | - addopts_match = addopts_re.match(line) |
81 | | - if addopts_match and not modified: |
82 | | - addopts_found = True |
83 | | - indent, inner = addopts_match.group(1), addopts_match.group(2) |
84 | | - tokens = inner.split() |
85 | | - remaining_tokens: list[str] = [] |
86 | | - extra_specs: list[str] = [] |
87 | | - |
88 | | - for tok in tokens: |
89 | | - if tok in unwanted_flags: |
90 | | - # Discard it; it will be replaced by base_specs |
91 | | - continue |
92 | | - |
93 | | - w_match = w_flag_re.match(tok) |
94 | | - if w_match: |
95 | | - w_flags.append(tok) |
96 | | - has_w_flags = True |
97 | | - spec = w_match.group(1) |
98 | | - if spec: |
99 | | - # Convert this -W... into a filterwarnings spec |
100 | | - extra_specs.append(spec) |
101 | | - else: |
102 | | - # Keep any non -W token |
103 | | - remaining_tokens.append(tok) |
104 | | - |
105 | | - # Base filterwarnings specs to replace unwanted flags |
106 | | - base_specs = map( |
107 | | - str.strip, |
108 | | - r""" |
109 | | - "error", |
110 | | - "once::DeprecationWarning", |
111 | | - "once::PendingDeprecationWarning", |
112 | | - # We ignore warnings about protobuf gencode version being one version older |
113 | | - # than the current version, as this is supported by protobuf, and we expect to |
114 | | - # have such cases. If we go too far, we will get a proper error anyways. |
115 | | - # We use a raw string (single quotes) to avoid the need to escape special |
116 | | - # characters as this is a regex. |
117 | | - 'ignore:Protobuf gencode version .*exactly one major version older.*:UserWarning', |
118 | | - """.strip().splitlines(), |
119 | | - ) |
120 | | - |
121 | | - # Rebuild addopts line without unwanted flags |
122 | | - new_addopts_value = " ".join(remaining_tokens) |
123 | | - new_lines.append(f'{indent}addopts = "{new_addopts_value}"\n') |
124 | | - |
125 | | - # Build the filterwarnings block |
126 | | - new_lines.append(f"{indent}filterwarnings = [\n") |
127 | | - # This is fine, indent is defined only once, so even if it is a closure |
128 | | - # bound late, the value will always be the same. |
129 | | - # pylint: disable-next=cell-var-from-loop |
130 | | - new_lines.extend(map(lambda s: f"{indent} {s}\n", base_specs)) |
131 | | - for spec in extra_specs: |
132 | | - new_lines.append(f'{indent} "{spec}",\n') |
133 | | - new_lines.append(f"{indent}]\n") |
134 | | - |
135 | | - modified = True |
136 | | - else: |
137 | | - new_lines.append(line) |
138 | | - |
139 | | - if modified and not has_filterwarnings: |
140 | | - print(f"Updated {path} to use filterwarnings.") |
141 | | - path.write_text("".join(new_lines), encoding="utf-8") |
142 | | - return |
143 | | - |
144 | | - if has_filterwarnings and not has_w_flags: |
145 | | - print( |
146 | | - f"The file {path} already has a `filterwarnings` section and has no " |
147 | | - "-W flags in `addopts`, it is probably already migrated." |
148 | | - ) |
149 | | - elif has_filterwarnings and has_w_flags: |
150 | | - print( |
151 | | - f"The file {path} already has a `filterwarnings` section, but also " |
152 | | - f"has -W flags in `addopts` ({' '.join(w_flags)!r}), it looks like " |
153 | | - "it is half-migrated, you should probably migrate it manually. Avoid using -W " |
154 | | - "flags in `addopts` if there is a `filterwarnings` section." |
155 | | - ) |
156 | | - if not addopts_found: |
157 | | - print(f"No 'addopts' found in {path}.") |
158 | | - |
159 | | - manual_step( |
160 | | - f"No changes done to {path}. " |
161 | | - "Please double check no manual steps are required." |
162 | | - ) |
163 | | - |
164 | | - |
165 | | -def migrate_mkdocs_yaml(file_path: Path) -> None: |
166 | | - """Migrate the mkdocs.yml file to fix the `paths` key location.""" |
167 | | - if not file_path.is_file(): |
168 | | - manual_step(f"File {file_path} does not exist, skipping automatic migration.") |
169 | | - return |
170 | | - |
171 | | - python_section = " python:" |
172 | | - options_section = " options:" |
173 | | - bad_paths_config = " paths:" |
174 | | - |
175 | | - lines = file_path.read_text(encoding="utf-8").splitlines(keepends=True) |
176 | | - needs_migration = False |
177 | | - paths = "" |
178 | | - in_python = False |
179 | | - in_options = False |
180 | | - |
181 | | - # 1) Detect whether there's a python_section followed by options_section |
182 | | - # and then bad_paths_config in that block. |
183 | | - for line in lines: |
184 | | - if line.startswith(python_section): |
185 | | - in_python = True |
186 | | - in_options = False |
187 | | - continue |
188 | | - if in_python and line.startswith(options_section): |
189 | | - in_options = True |
190 | | - continue |
191 | | - if in_options and line.startswith(bad_paths_config): |
192 | | - needs_migration = True |
193 | | - paths = line[len(bad_paths_config) :].strip() |
194 | | - break |
195 | | - # If indentation drops back below python-level, stop looking in this block |
196 | | - if in_python and not line.startswith(" ") and not line.isspace(): |
197 | | - in_python = False |
198 | | - in_options = False |
199 | | - |
200 | | - if not needs_migration: |
201 | | - return |
202 | | - |
203 | | - # 2) Perform the line-based rewrite: |
204 | | - new_lines: list[str] = [] |
205 | | - inserted_paths = False |
206 | | - |
207 | | - for line in lines: |
208 | | - # When we hit the python_section line, insert new paths config directly under it |
209 | | - if line.startswith(python_section) and not inserted_paths: |
210 | | - new_lines.append(line) |
211 | | - new_lines.append(f" paths: {paths}\n") |
212 | | - inserted_paths = True |
213 | | - continue |
214 | | - |
215 | | - # After inserting, drop the old " paths:" line |
216 | | - if inserted_paths and line.startswith(bad_paths_config): |
217 | | - continue |
218 | | - |
219 | | - new_lines.append(line) |
220 | | - |
221 | | - file_path.write_text("".join(new_lines), encoding="utf-8") |
222 | | - |
223 | | - |
224 | 39 | def apply_patch(patch_content: str) -> None: |
225 | 40 | """Apply a patch using the patch utility.""" |
226 | 41 | subprocess.run(["patch", "-p1"], input=patch_content.encode(), check=True) |
|
0 commit comments