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
@@ -101,15 +127,16 @@ def location(self):
101127 dirname = sysconfig .get_config_var ('BINDIR' )
102128 else :
103129 projectdir = sysconfig .get_config_var ('projectbase' )
104- with open (os .path .join (projectdir , 'pybuilddir.txt' )) as f :
130+ pybuilddir = os .path .join (projectdir , 'pybuilddir.txt' )
131+ with open (pybuilddir , encoding = 'utf-8' ) as f :
105132 dirname = os .path .join (projectdir , f .read ())
106133 else :
107134 dirname = sysconfig .get_path ('stdlib' )
108135 return os .path .join (dirname , 'build-details.json' )
109136
110137 @property
111138 def contents (self ):
112- with open (self .location , 'r' ) as f :
139+ with open (self .location , 'r' , encoding = 'utf-8' ) as f :
113140 return f .read ()
114141
115142 @needs_installed_python
@@ -149,5 +176,62 @@ def test_c_api(self):
149176 self .assertTrue (os .path .exists (os .path .join (value ['pkgconfig_path' ], f'python-{ version } .pc' )))
150177
151178
179+ @unittest .skipIf (
180+ generate_build_details is None ,
181+ "Failed to import generate-build-details"
182+ )
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+
152236if __name__ == '__main__' :
153237 unittest .main ()
0 commit comments