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 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+ assert not 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,62 @@ 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+ class BuildDetailsRelativePathsTests (unittest .TestCase ):
182+ @property
183+ def build_details_absolute_paths (self ):
184+ data = generate_build_details .generate_data (schema_version = '1.0' )
185+ return json .loads (json .dumps (data ))
186+
187+ @property
188+ def build_details_relative_paths (self ):
189+ data = self .build_details_absolute_paths
190+ generate_build_details .make_paths_relative (data , config_path = None )
191+ return data
192+
193+ def test_round_trip (self ):
194+ data_abs_path = self .build_details_absolute_paths
195+ data_rel_path = self .build_details_relative_paths
196+
197+ self .assertEqual (data_abs_path ['base_prefix' ],
198+ data_rel_path ['base_prefix' ])
199+
200+ base_prefix = data_abs_path ['base_prefix' ]
201+
202+ top_level_keys = ('base_interpreter' ,)
203+ for key in top_level_keys :
204+ self .assertEqual (key in data_abs_path , key in data_rel_path )
205+ if key not in data_abs_path :
206+ continue
207+
208+ abs_rel_path = os .path .join (base_prefix , data_rel_path [key ])
209+ abs_rel_path = os .path .normpath (abs_rel_path )
210+ self .assertEqual (data_abs_path [key ], abs_rel_path )
211+
212+ second_level_keys = (
213+ ('libpython' , 'dynamic' ),
214+ ('libpython' , 'dynamic_stableabi' ),
215+ ('libpython' , 'static' ),
216+ ('c_api' , 'headers' ),
217+ ('c_api' , 'pkgconfig_path' ),
218+
219+ )
220+ for part , key in second_level_keys :
221+ self .assertEqual (part in data_abs_path , part in data_rel_path )
222+ if part not in data_abs_path :
223+ continue
224+ self .assertEqual (key in data_abs_path [part ],
225+ key in data_rel_path [part ])
226+ if key not in data_abs_path [part ]:
227+ continue
228+
229+ abs_rel_path = os .path .join (base_prefix , data_rel_path [part ][key ])
230+ abs_rel_path = os .path .normpath (abs_rel_path )
231+ self .assertEqual (data_abs_path [part ][key ], abs_rel_path )
232+
233+
150234if __name__ == '__main__' :
151235 unittest .main ()
0 commit comments