1+ import importlib
12import json
23import os
4+ import os .path
35import sys
46import sysconfig
57import string
68import unittest
9+ from pathlib import Path
710
811from test .support import is_android , is_apple_mobile , is_wasm32
912
13+ BASE_PATH = Path (
14+ __file__ , # Lib/test/test_build_details.py
15+ '..' , # Lib/test
16+ '..' , # Lib
17+ '..' , # <src/install dir>
18+ ).resolve ()
19+ MODULE_PATH = BASE_PATH / 'Tools' / 'build' / 'generate-build-details.py'
20+
21+ try :
22+ # Import "generate-build-details.py" as "generate_build_details"
23+ spec = importlib .util .spec_from_file_location (
24+ "generate_build_details" , MODULE_PATH
25+ )
26+ generate_build_details = importlib .util .module_from_spec (spec )
27+ sys .modules ["generate_build_details" ] = generate_build_details
28+ spec .loader .exec_module (generate_build_details )
29+ except (FileNotFoundError , ImportError ):
30+ generate_build_details = None
31+
1032
1133class FormatTestsBase :
1234 @property
@@ -31,16 +53,15 @@ def key(self, name):
3153 value = value [part ]
3254 return value
3355
34- def test_parse (self ):
35- self .data
36-
3756 def test_top_level_container (self ):
3857 self .assertIsInstance (self .data , dict )
3958 for key , value in self .data .items ():
4059 with self .subTest (key = key ):
41- if key in ('schema_version' , 'base_prefix' , 'base_interpreter' , 'platform' ):
60+ if key in ('schema_version' , 'base_prefix' , 'base_interpreter' ,
61+ 'platform' ):
4262 self .assertIsInstance (value , str )
43- elif key in ('language' , 'implementation' , 'abi' , 'suffixes' , 'libpython' , 'c_api' , 'arbitrary_data' ):
63+ elif key in ('language' , 'implementation' , 'abi' , 'suffixes' ,
64+ 'libpython' , 'c_api' , 'arbitrary_data' ):
4465 self .assertIsInstance (value , dict )
4566
4667 def test_base_prefix (self ):
@@ -71,15 +92,20 @@ def test_language_version_info(self):
7192 self .assertEqual (len (value ), sys .version_info .n_fields )
7293 for part_name , part_value in value .items ():
7394 with self .subTest (part = part_name ):
74- self .assertEqual (part_value , getattr (sys .version_info , part_name ))
95+ sys_version_value = getattr (sys .version_info , part_name )
96+ self .assertEqual (part_value , sys_version_value )
7597
7698 def test_implementation (self ):
99+ impl_ver = sys .implementation .version
77100 for key , value in self .key ('implementation' ).items ():
78101 with self .subTest (part = key ):
79102 if key == 'version' :
80- self .assertEqual (len (value ), len (sys . implementation . version ))
103+ self .assertEqual (len (value ), len (impl_ver ))
81104 for part_name , part_value in value .items ():
82- self .assertEqual (getattr (sys .implementation .version , part_name ), part_value )
105+ self .assertFalse (isinstance (sys .implementation .version , dict ))
106+ getattr (sys .implementation .version , part_name )
107+ sys_implementation_value = getattr (impl_ver , part_name )
108+ self .assertEqual (sys_implementation_value , part_value )
83109 else :
84110 self .assertEqual (getattr (sys .implementation , key ), value )
85111
@@ -99,15 +125,16 @@ class CPythonBuildDetailsTests(unittest.TestCase, FormatTestsBase):
99125 def location (self ):
100126 if sysconfig .is_python_build ():
101127 projectdir = sysconfig .get_config_var ('projectbase' )
102- with open (os .path .join (projectdir , 'pybuilddir.txt' )) as f :
128+ pybuilddir = os .path .join (projectdir , 'pybuilddir.txt' )
129+ with open (pybuilddir , encoding = 'utf-8' ) as f :
103130 dirname = os .path .join (projectdir , f .read ())
104131 else :
105132 dirname = sysconfig .get_path ('stdlib' )
106133 return os .path .join (dirname , 'build-details.json' )
107134
108135 @property
109136 def contents (self ):
110- with open (self .location , 'r' ) as f :
137+ with open (self .location , 'r' , encoding = 'utf-8' ) as f :
111138 return f .read ()
112139
113140 @needs_installed_python
@@ -147,5 +174,64 @@ def test_c_api(self):
147174 self .assertTrue (os .path .exists (os .path .join (value ['pkgconfig_path' ], f'python-{ version } .pc' )))
148175
149176
177+ @unittest .skipIf (
178+ generate_build_details is None ,
179+ "Failed to import generate-build-details"
180+ )
181+ @unittest .skipIf (os .name != 'posix' , 'Feature only implemented on POSIX right now' )
182+ @unittest .skipIf (is_wasm32 , 'Feature not available on WebAssembly builds' )
183+ class BuildDetailsRelativePathsTests (unittest .TestCase ):
184+ @property
185+ def build_details_absolute_paths (self ):
186+ data = generate_build_details .generate_data (schema_version = '1.0' )
187+ return json .loads (json .dumps (data ))
188+
189+ @property
190+ def build_details_relative_paths (self ):
191+ data = self .build_details_absolute_paths
192+ generate_build_details .make_paths_relative (data , config_path = None )
193+ return data
194+
195+ def test_round_trip (self ):
196+ data_abs_path = self .build_details_absolute_paths
197+ data_rel_path = self .build_details_relative_paths
198+
199+ self .assertEqual (data_abs_path ['base_prefix' ],
200+ data_rel_path ['base_prefix' ])
201+
202+ base_prefix = data_abs_path ['base_prefix' ]
203+
204+ top_level_keys = ('base_interpreter' ,)
205+ for key in top_level_keys :
206+ self .assertEqual (key in data_abs_path , key in data_rel_path )
207+ if key not in data_abs_path :
208+ continue
209+
210+ abs_rel_path = os .path .join (base_prefix , data_rel_path [key ])
211+ abs_rel_path = os .path .normpath (abs_rel_path )
212+ self .assertEqual (data_abs_path [key ], abs_rel_path )
213+
214+ second_level_keys = (
215+ ('libpython' , 'dynamic' ),
216+ ('libpython' , 'dynamic_stableabi' ),
217+ ('libpython' , 'static' ),
218+ ('c_api' , 'headers' ),
219+ ('c_api' , 'pkgconfig_path' ),
220+
221+ )
222+ for part , key in second_level_keys :
223+ self .assertEqual (part in data_abs_path , part in data_rel_path )
224+ if part not in data_abs_path :
225+ continue
226+ self .assertEqual (key in data_abs_path [part ],
227+ key in data_rel_path [part ])
228+ if key not in data_abs_path [part ]:
229+ continue
230+
231+ abs_rel_path = os .path .join (base_prefix , data_rel_path [part ][key ])
232+ abs_rel_path = os .path .normpath (abs_rel_path )
233+ self .assertEqual (data_abs_path [part ][key ], abs_rel_path )
234+
235+
150236if __name__ == '__main__' :
151237 unittest .main ()
0 commit comments