mirror of
				https://github.com/astral-sh/ruff.git
				synced 2025-10-31 03:55:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			116 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			116 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """Script to generate `crates/ruff_python_stdlib/src/builtin_modules.rs`.
 | |
| 
 | |
| This script requires the following executables to be callable via a subprocess:
 | |
| - `python3.7`
 | |
| - `python3.8`
 | |
| - `python3.9`
 | |
| - `python3.10`
 | |
| - `python3.11`
 | |
| - `python3.12`
 | |
| - `python3.13`
 | |
| """
 | |
| 
 | |
| from __future__ import annotations
 | |
| 
 | |
| import builtins
 | |
| import subprocess
 | |
| import textwrap
 | |
| from functools import partial
 | |
| from pathlib import Path
 | |
| 
 | |
| MODULE_CRATE = "ruff_python_stdlib"
 | |
| MODULE_PATH = Path("crates") / MODULE_CRATE / "src" / "sys" / "builtin_modules.rs"
 | |
| 
 | |
| type Version = tuple[int, int]
 | |
| 
 | |
| PYTHON_VERSIONS: list[Version] = [
 | |
|     (3, 7),
 | |
|     (3, 8),
 | |
|     (3, 9),
 | |
|     (3, 10),
 | |
|     (3, 11),
 | |
|     (3, 12),
 | |
|     (3, 13),
 | |
| ]
 | |
| 
 | |
| 
 | |
| def builtin_modules_on_version(major_version: int, minor_version: int) -> set[str]:
 | |
|     executable = f"python{major_version}.{minor_version}"
 | |
|     try:
 | |
|         proc = subprocess.run(
 | |
|             [executable, "-c", "import sys; print(sys.builtin_module_names)"],
 | |
|             check=True,
 | |
|             text=True,
 | |
|             capture_output=True,
 | |
|         )
 | |
|     except subprocess.CalledProcessError as e:
 | |
|         print(e.stdout)
 | |
|         print(e.stderr)
 | |
|         raise
 | |
|     return set(eval(proc.stdout))
 | |
| 
 | |
| 
 | |
| def generate_module(
 | |
|     script_destination: Path, crate_name: str, python_versions: list[Version]
 | |
| ) -> None:
 | |
|     with script_destination.open("w") as f:
 | |
|         print = partial(builtins.print, file=f)
 | |
| 
 | |
|         print(
 | |
|             textwrap.dedent(
 | |
|                 """\
 | |
|                 //! This file is generated by `scripts/generate_builtin_modules.py`
 | |
| 
 | |
|                 /// Return `true` if `module` is a [builtin module] on the given
 | |
|                 /// Python 3 version.
 | |
|                 ///
 | |
|                 /// "Builtin modules" are modules that are compiled directly into the
 | |
|                 /// Python interpreter. These can never be shadowed by first-party
 | |
|                 /// modules; the normal rules of module resolution do not apply to these
 | |
|                 /// modules.
 | |
|                 ///
 | |
|                 /// [builtin module]: https://docs.python.org/3/library/sys.html#sys.builtin_module_names
 | |
|                 #[expect(clippy::unnested_or_patterns)]
 | |
|                 pub fn is_builtin_module(minor_version: u8, module: &str) -> bool {
 | |
|                     matches!((minor_version, module),
 | |
|                 """,
 | |
|             )
 | |
|         )
 | |
| 
 | |
|         modules_by_version = {
 | |
|             minor_version: builtin_modules_on_version(major_version, minor_version)
 | |
|             for major_version, minor_version in python_versions
 | |
|         }
 | |
| 
 | |
|         # First, add a case for the modules that are in all versions.
 | |
|         ubiquitous_modules = set.intersection(*modules_by_version.values())
 | |
| 
 | |
|         print("(_, ")
 | |
|         for i, module in enumerate(sorted(ubiquitous_modules)):
 | |
|             if i > 0:
 | |
|                 print(" | ", end="")
 | |
|             print(f'"{module}"')
 | |
|         print(")")
 | |
| 
 | |
|         # Next, add any version-specific modules.
 | |
|         for _major_version, minor_version in python_versions:
 | |
|             version_modules = set.difference(
 | |
|                 modules_by_version[minor_version],
 | |
|                 ubiquitous_modules,
 | |
|             )
 | |
| 
 | |
|             print(" | ")
 | |
|             print(f"({minor_version}, ")
 | |
|             for i, module in enumerate(sorted(version_modules)):
 | |
|                 if i > 0:
 | |
|                     print(" | ", end="")
 | |
|                 print(f'"{module}"')
 | |
|             print(")")
 | |
| 
 | |
|         print(")}")
 | |
| 
 | |
|     subprocess.run(["cargo", "fmt", "--package", crate_name], check=True)
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     generate_module(MODULE_PATH, MODULE_CRATE, PYTHON_VERSIONS)
 | 
