23
23
"""
24
24
25
25
from argparse import ArgumentParser
26
- from contextlib import suppress
26
+ from contextlib import suppress , contextmanager
27
27
from dataclasses import dataclass
28
28
import filecmp
29
- from itertools import chain , product
30
29
import json
31
30
import logging
32
31
import logging .handlers
37
36
import shutil
38
37
import subprocess
39
38
import sys
40
- import time
41
39
from bisect import bisect_left as bisect
42
40
from collections import OrderedDict
43
- from contextlib import contextmanager
44
41
from pathlib import Path
45
42
from string import Template
46
43
from textwrap import indent
49
46
import zc .lockfile
50
47
import jinja2
51
48
import requests
52
- from tomlkit import parse
49
+ import tomlkit
53
50
54
51
55
- HERE = Path (__file__ ).resolve ().parent
56
-
57
52
try :
58
53
from os import EX_OK , EX_SOFTWARE as EX_FAILURE
59
54
except ImportError :
66
61
else :
67
62
sentry_sdk .init ()
68
63
69
- if not hasattr (shlex , "join" ):
70
- # Add shlex.join if missing (pre 3.8)
71
- shlex .join = lambda split_command : " " .join (
72
- shlex .quote (arg ) for arg in split_command
73
- )
64
+ HERE = Path (__file__ ).resolve ().parent
74
65
75
66
76
67
@total_ordering
@@ -98,7 +89,8 @@ def __init__(
98
89
status = self .SYNONYMS .get (status , status )
99
90
if status not in self .STATUSES :
100
91
raise ValueError (
101
- f"Version status expected to be one of: { ', ' .join (self .STATUSES | set (self .SYNONYMS .keys ()))} , got { status !r} ."
92
+ "Version status expected to be one of: "
93
+ f"{ ', ' .join (self .STATUSES | set (self .SYNONYMS .keys ()))} , got { status !r} ."
102
94
)
103
95
self .name = name
104
96
self .branch_or_tag = branch_or_tag
@@ -167,7 +159,7 @@ def filter(versions, branch=None):
167
159
@staticmethod
168
160
def current_stable (versions ):
169
161
"""Find the current stable cPython version."""
170
- return max ([ v for v in versions if v .status == "stable" ] , key = Version .as_tuple )
162
+ return max (( v for v in versions if v .status == "stable" ) , key = Version .as_tuple )
171
163
172
164
@staticmethod
173
165
def current_dev (versions ):
@@ -201,6 +193,7 @@ def setup_indexsidebar(self, versions, dest_path):
201
193
202
194
@classmethod
203
195
def from_json (cls , name , values ):
196
+ """Loads a version from devguide's json representation."""
204
197
return cls (name , status = values ["status" ], branch_or_tag = values ["branch" ])
205
198
206
199
def __eq__ (self , other ):
@@ -221,6 +214,7 @@ class Language:
221
214
222
215
@staticmethod
223
216
def filter (languages , language_tags = None ):
217
+ """Filter a sequence of languages according to --languages."""
224
218
if language_tags :
225
219
languages_dict = {language .tag : language for language in languages }
226
220
return [languages_dict [tag ] for tag in language_tags ]
@@ -447,7 +441,7 @@ def build_robots_txt(
447
441
robots_file .chmod (0o775 )
448
442
run (["chgrp" , group , robots_file ])
449
443
if not skip_cache_invalidation :
450
- requests .request ("PURGE" , "https://docs.python.org/robots.txt" )
444
+ requests .request ("PURGE" , "https://docs.python.org/robots.txt" , timeout = 30 )
451
445
452
446
453
447
def build_sitemap (
@@ -703,13 +697,19 @@ def build(self):
703
697
if self .language .tag == "ja" :
704
698
# Since luatex doesn't support \ufffd, replace \ufffd with '?'.
705
699
# https://gist.github.com/zr-tex8r/e0931df922f38fbb67634f05dfdaf66b
706
- # Luatex already fixed this issue, so we can remove this once Texlive is updated.
700
+ # Luatex already fixed this issue, so we can remove this once Texlive
701
+ # is updated.
707
702
# (https://github.com/TeX-Live/luatex/commit/eaa95ce0a141eaf7a02)
708
- subprocess .check_output ("sed -i s/\N{REPLACEMENT CHARACTER} /?/g "
709
- f"{ locale_dirs } /ja/LC_MESSAGES/**/*.po" ,
710
- shell = True )
711
- subprocess .check_output ("sed -i s/\N{REPLACEMENT CHARACTER} /?/g "
712
- f"{ self .checkout } /Doc/**/*.rst" , shell = True )
703
+ subprocess .check_output (
704
+ "sed -i s/\N{REPLACEMENT CHARACTER} /?/g "
705
+ f"{ locale_dirs } /ja/LC_MESSAGES/**/*.po" ,
706
+ shell = True ,
707
+ )
708
+ subprocess .check_output (
709
+ "sed -i s/\N{REPLACEMENT CHARACTER} /?/g "
710
+ f"{ self .checkout } /Doc/**/*.rst" ,
711
+ shell = True ,
712
+ )
713
713
714
714
if self .version .status == "EOL" :
715
715
sphinxopts .append ("-D html_context.outdated=1" )
@@ -983,7 +983,7 @@ def proofread_canonicals(www_root: Path, skip_cache_invalidation: bool) -> None:
983
983
if not skip_cache_invalidation :
984
984
url = str (file ).replace ("/srv/" , "https://" )
985
985
logging .info ("Purging %s from CDN" , url )
986
- requests .request ("PURGE" , url )
986
+ requests .request ("PURGE" , url , timeout = 30 )
987
987
988
988
989
989
def purge_path (www_root : Path , path : Path ):
@@ -995,7 +995,9 @@ def purge_path(www_root: Path, path: Path):
995
995
996
996
def parse_versions_from_devguide ():
997
997
releases = requests .get (
998
- "https://raw.githubusercontent.com/python/devguide/main/include/release-cycle.json"
998
+ "https://raw.githubusercontent.com/"
999
+ "python/devguide/main/include/release-cycle.json" ,
1000
+ timeout = 30 ,
999
1001
).json ()
1000
1002
return [Version .from_json (name , release ) for name , release in releases .items ()]
1001
1003
@@ -1057,14 +1059,13 @@ def main():
1057
1059
lock = zc .lockfile .LockFile (HERE / "build_docs.lock" )
1058
1060
except zc .lockfile .LockError :
1059
1061
logging .info ("Another builder is running... dying..." )
1060
- return False
1062
+ return EX_FAILURE
1061
1063
1062
1064
try :
1063
- build_docs (args )
1065
+ return EX_OK if build_docs (args ) else EX_FAILURE
1064
1066
finally :
1065
1067
lock .close ()
1066
1068
1067
1069
1068
1070
if __name__ == "__main__" :
1069
- all_built_successfully = main ()
1070
- sys .exit (EX_OK if all_built_successfully else EX_FAILURE )
1071
+ sys .exit (main ())
0 commit comments