Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bd49b56

Browse files
committed
Add --po-dir to be used by build_docs(), add generate_templates() target
1 parent ed63a34 commit bd49b56

File tree

1 file changed

+103
-30
lines changed

1 file changed

+103
-30
lines changed

scripts/manage_translations.py

Lines changed: 103 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@
66
import contextlib
77
import logging
88
import os
9+
import re
910
import shutil
1011
import subprocess
1112
import sys
1213
from pathlib import Path
1314
from typing import Optional
1415

16+
from sphinx_intl.transifex import create_txconfig, update_txconfig_resources
17+
1518
ROOTDIR = Path(__file__).resolve().parent.parent
16-
COMMANDS = ["build"]
19+
COMMANDS = ["build", 'generate_templates']
1720

1821
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
1922
logger = logging.getLogger(__name__)
@@ -25,81 +28,151 @@ def configure_parser() -> argparse.ArgumentParser:
2528
parser.add_argument("command", choices=COMMANDS, help="The command to execute")
2629
parser.add_argument("-l", "--language", help="Language for the translated documentation")
2730
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")
31+
parser.add_argument("-L", "--logs-dir", default=ROOTDIR / "logs", type=Path, help="Directory for logs (default: 'logs' in root directory")
32+
parser.add_argument("-c", "--cpython-path", default=ROOTDIR / "cpython", type=Path, help="Path to the CPython repository (default: 'cpython' in root directory")
33+
parser.add_argument("-p", "--po-dir", type=Path, help="Path to the language team repository containing PO files (default: CPYTHON_PATH/Doc/locales/LANGUAGE/LC_MESSAGES")
34+
parser.add_argument('-t', '--tx-project', help="Name of the Transifex project under python-doc Transifex organization")
3035
return parser
3136

3237

33-
def get_value(env_var_name: str, arg_value: Optional[str]) -> str:
38+
def get_value(arg_value: Optional[str], arg_name: str, env_var_name: str) -> str:
3439
"""Return a CLI argument or environment variable value."""
3540
value = arg_value or os.getenv(env_var_name)
3641
if not value:
37-
logger.error(f"The environment variable {env_var_name} is not defined, and no value was provided.")
42+
logger.error(f"'{arg_name}' not provided and the environment variable {env_var_name} is not set.")
3843
sys.exit(1)
3944
return value
4045

4146

42-
def get_minor_version(version: str) -> int:
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}")
47+
def validate_cpython_path(cpython_path: Path) -> None:
48+
if not (cpython_path / "Doc" / "conf.py").exists():
49+
logger.error(f"Missing conf.py in {cpython_path}. Invalid CPython directory.")
4850
sys.exit(1)
4951

5052

51-
def build_docs(language: str, version: str, logs_dir: Path, cpython_path: Path) -> None:
52-
"""Build the documentation using Sphinx."""
53-
minor_version = get_minor_version(version)
54-
warning_log = logs_dir / "sphinxwarnings.txt"
53+
def validate_po_dir(po_dir: Path) -> None:
54+
if not po_dir.exists() or not list(po_dir.glob("*.po")):
55+
logger.error(f"Invalid locale directory '{po_dir}'. No PO files found.")
56+
sys.exit(1)
57+
5558

56-
sphinx_opts = f"-E -D language={language} --keep-going -w {warning_log}"
57-
if minor_version < 12:
58-
sphinx_opts += "-D gettext_compact=False"
59+
def validate_tx_config(tx_config: str) -> None:
60+
if not re.match(r"python-(newest|\d+)", tx_config):
61+
logger.error(f"Invalid Transifex project name: {tx_config}")
62+
sys.exit(1)
63+
64+
65+
# contextlib implemented chdir since Python 3.11
66+
@contextlib.contextmanager
67+
def chdir(path: Path):
68+
"""Temporarily change the working directory."""
69+
original_dir = Path.cwd()
70+
logger.info(path)
71+
os.chdir(path)
72+
try:
73+
yield
74+
finally:
75+
os.chdir(original_dir)
76+
77+
78+
def build_docs(language: str, version: str, po_dir: Path, logs_dir: Path, cpython_path: Path) -> None:
79+
"""Build the documentation using Sphinx."""
80+
warning_log = logs_dir / "sphinx_warnings_build_docs.txt"
81+
sphinx_opts = ["-E", "-Dgettext_compact=0", f"-Dlanguage={language}", "--keep-going", "-w", f"{warning_log}"]
82+
locale_dirs = cpython_path / "Doc/locales"
83+
target_locale_dir = cpython_path / "Doc/locales" / language / "LC_MESSAGES"
84+
85+
# TODO Fix symlinking when po_dir is not equal to target_locale_dir
86+
#if not po_dir.relative_to(locale_dirs) and
87+
# not target_locale_dir.readlink() == po_dir:
88+
# if target_locale_dir.is_symlink():
89+
# target_locale_dir.unlink() # remove only if it is a symlink
90+
# if not target_locale_dir.exists() and not target_locale_dir.is_symlink():
91+
# (locale_dirs / language).mkdir(parents=True, exist_ok=True)
92+
# os.symlink(po_dir, target_locale_dir)
5993

6094
try:
6195
logger.info(f"Building documentation for {language}, Python {version}.")
6296
subprocess.run([
63-
"make", "-C", str(cpython_path / "Doc"), "html", f"SPHINXOPTS={sphinx_opts}"
97+
"make", "-C", str(cpython_path / "Doc"), "html", f"SPHINXOPTS={' '.join(sphinx_opts)}"
6498
], check=True)
6599

66100
if warning_log.exists() and not warning_log.stat().st_size:
67101
warning_log.unlink()
68-
logger.info("Empty warning log file removed.")
102+
logger.info("Removed empty warning log file.")
69103

70104
except subprocess.CalledProcessError as e:
71105
logger.error(f"Make command failed: {e}")
72106
sys.exit(1)
73107

74108

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.")
109+
def generate_templates(logs_dir: Path, cpython_path: Path, tx_project: str) -> None:
110+
"""Generate translation template files (a.k.a. POT files) with Sphinx"""
111+
warning_log = logs_dir / "sphinx_warnings_generate_templates.txt"
112+
all_sphinx_opts = [
113+
"-E", "-b", "gettext", "-Dgettext_compact=0", "--keep-going",
114+
"-w", f"{warning_log}", "-d", "build/.doctrees-gettext", ".", "build/gettext"
115+
]
116+
117+
try:
118+
logger.info("Generating template files for Python docs.")
119+
subprocess.run([
120+
"make", "-C", str(cpython_path / "Doc"), "build", f"ALLSPHINXOPTS={' '.join(all_sphinx_opts)}"
121+
], check=True)
122+
123+
if warning_log.exists() and not warning_log.stat().st_size:
124+
warning_log.unlink()
125+
logger.info("Removed empty warning log file.")
126+
127+
except subprocess.CalledProcessError as e:
128+
logger.error(f"Make command failed: {e}")
79129
sys.exit(1)
80130

131+
with chdir(cpython_path / "Doc/locales"):
132+
logger.info("Updating Transifex's resources configuration file")
133+
Path(".tx/config").unlink(missing_ok=True)
134+
create_txconfig()
135+
update_txconfig_resources(
136+
transifex_organization_name='python-doc',
137+
transifex_project_name=tx_project,
138+
locale_dir=Path("."),
139+
pot_dir=Path("../build/gettext")
140+
)
141+
81142

82143
def main() -> None:
83144
parser = configure_parser()
84145
args = parser.parse_args()
85146

86-
language = get_value("PYDOC_LANGUAGE", args.language)
87-
version = get_value("PYDOC_VERSION", args.python_version)
88-
logs_dir = Path(get_value("PYDOC_LOGS", str(args.logs_dir)))
147+
# Set and require variable depending on the command issued by the user
89148
cpython_path = args.cpython_path
149+
logs_dir = Path(get_value(str(args.logs_dir), "--logs-dir", "PYDOC_LOGS"))
90150

91-
validate_paths(cpython_path)
151+
if args.command == "generate_templates":
152+
tx_project = get_value(args.tx_project, "--tx-project", "PYDOC_TX_PROJECT")
92153

93154
if args.command == "build":
155+
language = get_value(args.language, "--language", "PYDOC_LANGUAGE")
156+
version = get_value(args.python_version, "--python-version", "PYDOC_VERSION")
157+
po_dir = args.po_dir.absolute() or cpython_path / f"Doc/locales/{language}/LC_MESSAGES"
158+
159+
if args.command in ["build", "generate_templates"]:
94160
if not shutil.which("make"):
95161
logger.error("'make' not found. Please install it.")
96162
sys.exit(1)
97163

98164
logs_dir.mkdir(exist_ok=True)
99165
logger.info(f"Logs will be stored in: {logs_dir}")
100166

101-
build_docs(language, version, logs_dir, cpython_path)
102-
logger.info("Documentation build completed successfully.")
167+
if args.command == "build":
168+
validate_cpython_path(cpython_path)
169+
validate_po_dir(po_dir)
170+
build_docs(language, version, po_dir, logs_dir, cpython_path)
171+
logger.info("Documentation build completed successfully.")
172+
elif args.command == "generate_templates":
173+
validate_cpython_path(cpython_path)
174+
validate_tx_config(tx_project)
175+
generate_templates(logs_dir, cpython_path, tx_project)
103176

104177

105178
if __name__ == "__main__":

0 commit comments

Comments
 (0)