|
1 | 1 | #!/usr/bin/env python
|
2 |
| -""" |
3 |
| -Manage translation for Python documentation |
4 |
| -""" |
5 | 2 |
|
6 | 3 | # SPDX-License-Identifier: CC0-1.0
|
7 | 4 |
|
8 |
| - |
9 | 5 | import argparse
|
| 6 | +import contextlib |
10 | 7 | import logging
|
11 | 8 | import os
|
12 | 9 | import shutil
|
|
16 | 13 | from typing import Optional
|
17 | 14 |
|
18 | 15 | ROOTDIR = Path(__file__).resolve().parent.parent
|
19 |
| -COMMANDS = { |
20 |
| - "build", |
21 |
| -} |
22 |
| - |
23 |
| -# Logger configuration |
24 |
| -logging.basicConfig( |
25 |
| - level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" |
26 |
| -) |
| 16 | +COMMANDS = ["build"] |
| 17 | + |
| 18 | +logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") |
27 | 19 | logger = logging.getLogger(__name__)
|
28 | 20 |
|
29 | 21 |
|
30 | 22 | def configure_parser() -> argparse.ArgumentParser:
|
31 |
| - parser = argparse.ArgumentParser(description=__doc__) |
| 23 | + """Configure and return the argument parser.""" |
| 24 | + parser = argparse.ArgumentParser(description="Manage translation for Python documentation") |
32 | 25 | parser.add_argument("command", choices=COMMANDS, help="The command to execute")
|
33 |
| - parser.add_argument( |
34 |
| - "--language", "-l", help="Language for the translated documentation" |
35 |
| - ) |
36 |
| - parser.add_argument("--python-version", "-v", help="Python version to be used") |
37 |
| - parser.add_argument( |
38 |
| - "--logs-dir", |
39 |
| - "-L", |
40 |
| - default=ROOTDIR / "logs", |
41 |
| - help="Directory for logs (default: 'logs')", |
42 |
| - ) |
43 |
| - parser.add_argument( |
44 |
| - "--cpython-path", |
45 |
| - "-c", |
46 |
| - default=ROOTDIR / "cpython", |
47 |
| - type=Path, |
48 |
| - help="Path to the CPython repository (default: 'cpython')", |
49 |
| - ) |
| 26 | + parser.add_argument("-l", "--language", help="Language for the translated documentation") |
| 27 | + parser.add_argument("-v", "--python-version", help="Python version to be used") |
| 28 | + parser.add_argument("-L", "--logs-dir", default=ROOTDIR / "logs", type=Path, help="Directory for logs") |
| 29 | + parser.add_argument("-c", "--cpython-path", default=ROOTDIR / "cpython", type=Path, help="Path to the CPython repository") |
50 | 30 | return parser
|
51 | 31 |
|
52 | 32 |
|
53 | 33 | def get_value(env_var_name: str, arg_value: Optional[str]) -> str:
|
54 |
| - """ |
55 |
| - Return value passed via command-line interface arguments *arg_value*, |
56 |
| - and if not passed, use the environment variable *env_var_name* instead. |
57 |
| - """ |
58 |
| - |
| 34 | + """Return a CLI argument or environment variable value.""" |
59 | 35 | value = arg_value or os.getenv(env_var_name)
|
60 | 36 | if not value:
|
61 |
| - logger.error( |
62 |
| - f"The environment variable {env_var_name} is not defined, and no value was provided by the command line." |
63 |
| - ) |
| 37 | + logger.error(f"The environment variable {env_var_name} is not defined, and no value was provided.") |
64 | 38 | sys.exit(1)
|
65 | 39 | return value
|
66 | 40 |
|
67 | 41 |
|
68 | 42 | def get_minor_version(version: str) -> int:
|
69 |
| - """Return Python minor *version* assuming the schema as X.Y, e.g. 3.13""" |
70 |
| - return int(version.split(".")[1]) |
| 43 | + """Return the minor version number from a version string (e.g., '3.13').""" |
| 44 | + try: |
| 45 | + return int(version.split(".")[1]) |
| 46 | + except (IndexError, ValueError) as e: |
| 47 | + logger.error(f"Invalid version format '{version}': {e}") |
| 48 | + sys.exit(1) |
71 | 49 |
|
72 | 50 |
|
73 |
| -def build(language: str, version: str, logs_dir: Path, cpython_path: Path) -> None: |
| 51 | +def build_docs(language: str, version: str, logs_dir: Path, cpython_path: Path) -> None: |
| 52 | + """Build the documentation using Sphinx.""" |
74 | 53 | minor_version = get_minor_version(version)
|
75 | 54 | warning_log = logs_dir / "sphinxwarnings.txt"
|
76 | 55 |
|
77 |
| - # Sphinx options. |
78 |
| - # Append gettext_compact=False if python version is 3.11 or older, |
79 |
| - # because this confval was added to conf.py only in 3.12. |
80 |
| - opts = f"-E -D language={language} --keep-going -w {warning_log}" |
| 56 | + sphinx_opts = f"-E -D language={language} --keep-going -w {warning_log}" |
81 | 57 | if minor_version < 12:
|
82 |
| - opts += " -D gettext_compact=False" |
| 58 | + sphinx_opts += "-D gettext_compact=False" |
83 | 59 |
|
84 | 60 | try:
|
85 |
| - # Run the make command |
86 |
| - logger.info( |
87 |
| - f"Building documentation for language {language}, Python version {version}." |
88 |
| - ) |
89 |
| - subprocess.run( |
90 |
| - ["make", "-C", cpython_path / "Doc", "html", f"SPHINXOPTS={opts}"], |
91 |
| - check=True, |
92 |
| - ) |
| 61 | + logger.info(f"Building documentation for {language}, Python {version}.") |
| 62 | + subprocess.run([ |
| 63 | + "make", "-C", str(cpython_path / "Doc"), "html", f"SPHINXOPTS={sphinx_opts}" |
| 64 | + ], check=True) |
| 65 | + |
| 66 | + if warning_log.exists() and not warning_log.stat().st_size: |
| 67 | + warning_log.unlink() |
| 68 | + logger.info("Empty warning log file removed.") |
| 69 | + |
93 | 70 | except subprocess.CalledProcessError as e:
|
94 |
| - logger.error(f"Error executing the make command: {e}") |
95 |
| - raise |
| 71 | + logger.error(f"Make command failed: {e}") |
| 72 | + sys.exit(1) |
| 73 | + |
96 | 74 |
|
97 |
| - # Remove the warning log file if it is empty |
98 |
| - if warning_log.exists() and warning_log.stat().st_size == 0: |
99 |
| - warning_log.unlink() |
100 |
| - logger.info("The warning log file was empty and has been removed.") |
| 75 | +def validate_paths(cpython_path: Path) -> None: |
| 76 | + """Validate necessary paths for handling documentation.""" |
| 77 | + if not (cpython_path / "Doc" / "conf.py").exists(): |
| 78 | + logger.error(f"Missing conf.py in {cpython_path}. Invalid CPython directory.") |
| 79 | + sys.exit(1) |
101 | 80 |
|
102 | 81 |
|
103 | 82 | def main() -> None:
|
104 |
| - # Configure ArgumentParser |
105 | 83 | parser = configure_parser()
|
106 | 84 | args = parser.parse_args()
|
107 | 85 |
|
108 |
| - # Get values from environment variables or arguments |
109 | 86 | language = get_value("PYDOC_LANGUAGE", args.language)
|
110 | 87 | version = get_value("PYDOC_VERSION", args.python_version)
|
111 | 88 | logs_dir = Path(get_value("PYDOC_LOGS", str(args.logs_dir)))
|
112 | 89 | cpython_path = args.cpython_path
|
113 | 90 |
|
114 |
| - # Validate contents of the CPython local checkout |
115 |
| - conf_file = cpython_path / "Doc" / "conf.py" |
116 |
| - if not conf_file.exists(): |
117 |
| - logger.error( |
118 |
| - f"Configuration file '{conf_file}' not found. Invalid CPython checkout directory." |
119 |
| - ) |
120 |
| - sys.exit(1) |
| 91 | + validate_paths(cpython_path) |
121 | 92 |
|
122 |
| - # Check if the command is one of those that use Sphinx |
123 |
| - if args.command in [ |
124 |
| - "build", |
125 |
| - ]: |
126 |
| - # make is required |
| 93 | + if args.command == "build": |
127 | 94 | if not shutil.which("make"):
|
128 |
| - logger.error("Executable 'make' not found, make sure it is installed.") |
| 95 | + logger.error("'make' not found. Please install it.") |
129 | 96 | sys.exit(1)
|
130 | 97 |
|
131 |
| - # Create the logs directory if it doesn't exist |
132 | 98 | logs_dir.mkdir(exist_ok=True)
|
133 |
| - logger.info(f"Logs will be stored in the directory: {logs_dir}") |
| 99 | + logger.info(f"Logs will be stored in: {logs_dir}") |
134 | 100 |
|
135 |
| - if args.command == "build": |
136 |
| - # Build the documentation |
137 |
| - try: |
138 |
| - build(language, version, logs_dir, cpython_path) |
139 |
| - logger.info("Documentation built successfully.") |
140 |
| - except Exception as e: |
141 |
| - logger.error(f"Error building the documentation: {e}") |
142 |
| - raise |
| 101 | + build_docs(language, version, logs_dir, cpython_path) |
| 102 | + logger.info("Documentation build completed successfully.") |
143 | 103 |
|
144 | 104 |
|
145 | 105 | if __name__ == "__main__":
|
146 | 106 | main()
|
| 107 | + |
0 commit comments