@@ -434,7 +434,8 @@ def build_robots_txt(
434
434
www_root : Path ,
435
435
group ,
436
436
skip_cache_invalidation ,
437
- ):
437
+ session : requests .Session ,
438
+ ) -> None :
438
439
"""Disallow crawl of EOL versions in robots.txt."""
439
440
if not www_root .exists ():
440
441
logging .info ("Skipping robots.txt generation (www root does not even exists)." )
@@ -449,7 +450,7 @@ def build_robots_txt(
449
450
robots_file .chmod (0o775 )
450
451
run (["chgrp" , group , robots_file ])
451
452
if not skip_cache_invalidation :
452
- purge ("robots.txt" )
453
+ purge (session , "robots.txt" )
453
454
454
455
455
456
def build_sitemap (
@@ -642,7 +643,7 @@ def full_build(self):
642
643
"""
643
644
return not self .quick and not self .language .html_only
644
645
645
- def run (self ) -> bool :
646
+ def run (self , session : requests . Session ) -> bool :
646
647
"""Build and publish a Python doc, for a language, and a version."""
647
648
start_time = perf_counter ()
648
649
logging .info ("Running." )
@@ -653,7 +654,7 @@ def run(self) -> bool:
653
654
if self .should_rebuild ():
654
655
self .build_venv ()
655
656
self .build ()
656
- self .copy_build_to_webroot ()
657
+ self .copy_build_to_webroot (session )
657
658
self .save_state (build_duration = perf_counter () - start_time )
658
659
except Exception as err :
659
660
logging .exception ("Badly handled exception, human, please help." )
@@ -797,7 +798,7 @@ def build_venv(self):
797
798
run ([venv_path / "bin" / "python" , "-m" , "pip" , "freeze" , "--all" ])
798
799
self .venv = venv_path
799
800
800
- def copy_build_to_webroot (self ) :
801
+ def copy_build_to_webroot (self , session : requests . Session ) -> None :
801
802
"""Copy a given build to the appropriate webroot with appropriate rights."""
802
803
logging .info ("Publishing start." )
803
804
self .www_root .mkdir (parents = True , exist_ok = True )
@@ -909,9 +910,9 @@ def copy_build_to_webroot(self):
909
910
prefixes = run (["find" , "-L" , targets_dir , "-samefile" , target ]).stdout
910
911
prefixes = prefixes .replace (targets_dir + "/" , "" )
911
912
prefixes = [prefix + "/" for prefix in prefixes .split ("\n " ) if prefix ]
912
- purge (* prefixes )
913
+ purge (session , * prefixes )
913
914
for prefix in prefixes :
914
- purge (* [prefix + p for p in changed ])
915
+ purge (session , * [prefix + p for p in changed ])
915
916
logging .info ("Publishing done" )
916
917
917
918
def should_rebuild (self ):
@@ -977,7 +978,15 @@ def save_state(self, build_duration: float):
977
978
state_file .write_text (tomlkit .dumps (states ), encoding = "UTF-8" )
978
979
979
980
980
- def symlink (www_root : Path , language : Language , directory : str , name : str , group : str , skip_cache_invalidation : bool ):
981
+ def symlink (
982
+ www_root : Path ,
983
+ language : Language ,
984
+ directory : str ,
985
+ name : str ,
986
+ group : str ,
987
+ skip_cache_invalidation : bool ,
988
+ session : requests .Session ,
989
+ ) -> None :
981
990
"""Used by major_symlinks and dev_symlink to maintain symlinks."""
982
991
if language .tag == "en" : # english is rooted on /, no /en/
983
992
path = www_root
@@ -994,12 +1003,17 @@ def symlink(www_root: Path, language: Language, directory: str, name: str, group
994
1003
link .symlink_to (directory )
995
1004
run (["chown" , "-h" , ":" + group , str (link )])
996
1005
if not skip_cache_invalidation :
997
- purge_path (www_root , link )
1006
+ purge_path (session , www_root , link )
998
1007
999
1008
1000
1009
def major_symlinks (
1001
- www_root : Path , group , versions : Iterable [Version ], languages : Iterable [Language ], skip_cache_invalidation : bool
1002
- ):
1010
+ www_root : Path ,
1011
+ group : str ,
1012
+ versions : Iterable [Version ],
1013
+ languages : Iterable [Language ],
1014
+ skip_cache_invalidation : bool ,
1015
+ session : requests .Session ,
1016
+ ) -> None :
1003
1017
"""Maintains the /2/ and /3/ symlinks for each languages.
1004
1018
1005
1019
Like:
@@ -1009,11 +1023,26 @@ def major_symlinks(
1009
1023
"""
1010
1024
current_stable = Version .current_stable (versions ).name
1011
1025
for language in languages :
1012
- symlink (www_root , language , current_stable , "3" , group , skip_cache_invalidation )
1013
- symlink (www_root , language , "2.7" , "2" , group , skip_cache_invalidation )
1026
+ symlink (
1027
+ www_root ,
1028
+ language ,
1029
+ current_stable ,
1030
+ "3" ,
1031
+ group ,
1032
+ skip_cache_invalidation ,
1033
+ session ,
1034
+ )
1035
+ symlink (www_root , language , "2.7" , "2" , group , skip_cache_invalidation , session )
1014
1036
1015
1037
1016
- def dev_symlink (www_root : Path , group , versions , languages , skip_cache_invalidation : bool ):
1038
+ def dev_symlink (
1039
+ www_root : Path ,
1040
+ group ,
1041
+ versions ,
1042
+ languages ,
1043
+ skip_cache_invalidation : bool ,
1044
+ session : requests .Session ,
1045
+ ) -> None :
1017
1046
"""Maintains the /dev/ symlinks for each languages.
1018
1047
1019
1048
Like:
@@ -1023,10 +1052,18 @@ def dev_symlink(www_root: Path, group, versions, languages, skip_cache_invalidat
1023
1052
"""
1024
1053
current_dev = Version .current_dev (versions ).name
1025
1054
for language in languages :
1026
- symlink (www_root , language , current_dev , "dev" , group , skip_cache_invalidation )
1055
+ symlink (
1056
+ www_root ,
1057
+ language ,
1058
+ current_dev ,
1059
+ "dev" ,
1060
+ group ,
1061
+ skip_cache_invalidation ,
1062
+ session ,
1063
+ )
1027
1064
1028
1065
1029
- def purge (* paths ) :
1066
+ def purge (session : requests . Session , * paths : Path | str ) -> None :
1030
1067
"""Remove one or many paths from docs.python.org's CDN.
1031
1068
1032
1069
To be used when a file change, so the CDN fetch the new one.
@@ -1035,20 +1072,22 @@ def purge(*paths):
1035
1072
for path in paths :
1036
1073
url = urljoin (base , str (path ))
1037
1074
logging .debug ("Purging %s from CDN" , url )
1038
- requests .request ("PURGE" , url , timeout = 30 )
1075
+ session .request ("PURGE" , url , timeout = 30 )
1039
1076
1040
1077
1041
- def purge_path (www_root : Path , path : Path ):
1078
+ def purge_path (session : requests . Session , www_root : Path , path : Path ) -> None :
1042
1079
"""Recursively remove a path from docs.python.org's CDN.
1043
1080
1044
1081
To be used when a directory change, so the CDN fetch the new one.
1045
1082
"""
1046
- purge (* [file .relative_to (www_root ) for file in path .glob ("**/*" )])
1047
- purge (path .relative_to (www_root ))
1048
- purge (str (path .relative_to (www_root )) + "/" )
1083
+ purge (session , * [file .relative_to (www_root ) for file in path .glob ("**/*" )])
1084
+ purge (session , path .relative_to (www_root ))
1085
+ purge (session , str (path .relative_to (www_root )) + "/" )
1049
1086
1050
1087
1051
- def proofread_canonicals (www_root : Path , skip_cache_invalidation : bool ) -> None :
1088
+ def proofread_canonicals (
1089
+ www_root : Path , skip_cache_invalidation : bool , session : requests .Session
1090
+ ) -> None :
1052
1091
"""In www_root we check that all canonical links point to existing contents.
1053
1092
1054
1093
It can happen that a canonical is "broken":
@@ -1070,11 +1109,11 @@ def proofread_canonicals(www_root: Path, skip_cache_invalidation: bool) -> None:
1070
1109
html = html .replace (canonical .group (0 ), "" )
1071
1110
file .write_text (html , encoding = "UTF-8" , errors = "surrogateescape" )
1072
1111
if not skip_cache_invalidation :
1073
- purge (str (file ).replace ("/srv/docs.python.org/" , "" ))
1112
+ purge (session , str (file ).replace ("/srv/docs.python.org/" , "" ))
1074
1113
1075
1114
1076
- def parse_versions_from_devguide () :
1077
- releases = requests .get (
1115
+ def parse_versions_from_devguide (session : requests . Session ) -> list [ Version ] :
1116
+ releases = session .get (
1078
1117
"https://raw.githubusercontent.com/"
1079
1118
"python/devguide/main/include/release-cycle.json" ,
1080
1119
timeout = 30 ,
@@ -1101,8 +1140,9 @@ def parse_languages_from_config():
1101
1140
1102
1141
1103
1142
def build_docs (args ) -> bool :
1104
- """Build all docs (each languages and each versions)."""
1105
- versions = parse_versions_from_devguide ()
1143
+ """Build all docs (each language and each version)."""
1144
+ session = requests .Session ()
1145
+ versions = parse_versions_from_devguide (session )
1106
1146
languages = parse_languages_from_config ()
1107
1147
todo = [
1108
1148
(version , language )
@@ -1130,19 +1170,38 @@ def build_docs(args) -> bool:
1130
1170
builder = DocBuilder (
1131
1171
version , versions , language , languages , cpython_repo , ** vars (args )
1132
1172
)
1133
- all_built_successfully &= builder .run ()
1173
+ all_built_successfully &= builder .run (session )
1134
1174
logging .root .handlers [0 ].setFormatter (
1135
1175
logging .Formatter ("%(asctime)s %(levelname)s: %(message)s" )
1136
1176
)
1137
1177
1138
1178
build_sitemap (versions , languages , args .www_root , args .group )
1139
1179
build_404 (args .www_root , args .group )
1140
1180
build_robots_txt (
1141
- versions , languages , args .www_root , args .group , args .skip_cache_invalidation
1181
+ versions ,
1182
+ languages ,
1183
+ args .www_root ,
1184
+ args .group ,
1185
+ args .skip_cache_invalidation ,
1186
+ session ,
1187
+ )
1188
+ major_symlinks (
1189
+ args .www_root ,
1190
+ args .group ,
1191
+ versions ,
1192
+ languages ,
1193
+ args .skip_cache_invalidation ,
1194
+ session ,
1195
+ )
1196
+ dev_symlink (
1197
+ args .www_root ,
1198
+ args .group ,
1199
+ versions ,
1200
+ languages ,
1201
+ args .skip_cache_invalidation ,
1202
+ session ,
1142
1203
)
1143
- major_symlinks (args .www_root , args .group , versions , languages , args .skip_cache_invalidation )
1144
- dev_symlink (args .www_root , args .group , versions , languages , args .skip_cache_invalidation )
1145
- proofread_canonicals (args .www_root , args .skip_cache_invalidation )
1204
+ proofread_canonicals (args .www_root , args .skip_cache_invalidation , session )
1146
1205
1147
1206
return all_built_successfully
1148
1207
0 commit comments