|
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 | importargparse |
| 6 | +importcontextlib |
10 | 7 | importlogging |
11 | 8 | importos |
12 | 9 | importshutil |
|
16 | 13 | fromtypingimportOptional |
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 | defconfigure_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 | returnparser |
51 | 31 |
|
52 | 32 |
|
53 | 33 | defget_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_valueoros.getenv(env_var_name) |
60 | 36 | ifnotvalue: |
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 | returnvalue |
66 | 40 |
|
67 | 41 |
|
68 | 42 | defget_minor_version(version:str)->int: |
69 | | -"""Return Python minor *version* assuming the schema as X.Y, e.g. 3.13""" |
70 | | -returnint(version.split(".")[1]) |
| 43 | +"""Return the minor version number from a version string (e.g., '3.13').""" |
| 44 | +try: |
| 45 | +returnint(version.split(".")[1]) |
| 46 | +except (IndexError,ValueError)ase: |
| 47 | +logger.error(f"Invalid version format '{version}':{e}") |
| 48 | +sys.exit(1) |
71 | 49 |
|
72 | 50 |
|
73 | | -defbuild(language:str,version:str,logs_dir:Path,cpython_path:Path)->None: |
| 51 | +defbuild_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 | ifminor_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 | +ifwarning_log.exists()andnotwarning_log.stat().st_size: |
| 67 | +warning_log.unlink() |
| 68 | +logger.info("Empty warning log file removed.") |
| 69 | + |
93 | 70 | exceptsubprocess.CalledProcessErrorase: |
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 | | -ifwarning_log.exists()andwarning_log.stat().st_size==0: |
99 | | -warning_log.unlink() |
100 | | -logger.info("The warning log file was empty and has been removed.") |
| 75 | +defvalidate_paths(cpython_path:Path)->None: |
| 76 | +"""Validate necessary paths for handling documentation.""" |
| 77 | +ifnot (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 | defmain()->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 | | -ifnotconf_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 | | -ifargs.commandin [ |
124 | | -"build", |
125 | | - ]: |
126 | | -# make is required |
| 93 | +ifargs.command=="build": |
127 | 94 | ifnotshutil.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 | | -ifargs.command=="build": |
136 | | -# Build the documentation |
137 | | -try: |
138 | | -build(language,version,logs_dir,cpython_path) |
139 | | -logger.info("Documentation built successfully.") |
140 | | -exceptExceptionase: |
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 | + |