@@ -45,31 +45,99 @@ class BuildDetails(TypedDict):
4545_32_BIT_INTERPRETER = struct .calcsize ('P' ) == 4
4646
4747
48- def get_interpreter_tag (build_details : BuildDetails | None = None ) -> str :
49- if build_details is None :
50- name = sys .implementation .name
51- major , minor = sys .version_info [:2 ]
52- else :
53- name = build_details ['implementation' ]['name' ]
54- _v = build_details ['implementation' ]['version' ]
55- major = _v ['major' ]
56- minor = _v ['minor' ]
48+ def _get_macosx_platform () -> str :
49+ ver , _ , arch = platform .mac_ver ()
50+ major , minor = map (int , ver .split ('.' )[:2 ])
51+
52+ # Python built with older macOS SDK on macOS 11, reports an
53+ # nonexistent macOS 10.16 version instead of the real version.
54+ #
55+ # The packaging module introduced a workaround
56+ # https://github.com/pypa/packaging/commit/67c4a2820c549070bbfc4bfbf5e2a250075048da
57+ #
58+ # This results in packaging versions up to 21.3 generating
59+ # platform tags like "macosx_10_16_x86_64" and later versions
60+ # generating "macosx_11_0_x86_64". Using the latter would be more
61+ # correct but prevents the resulting wheel from being installed on
62+ # systems using packaging 21.3 or earlier (pip 22.3 or earlier).
63+ #
64+ # Fortunately packaging versions carrying the workaround still
65+ # accepts "macosx_10_16_x86_64" as a compatible platform tag. We
66+ # can therefore ignore the issue and generate the slightly
67+ # incorrect tag.
68+
69+ if _32_BIT_INTERPRETER :
70+ # 32-bit Python running on a 64-bit kernel.
71+ if arch == 'ppc64' :
72+ arch = 'ppc'
73+ if arch == 'x86_64' :
74+ arch = 'i386'
75+
76+ return f'macosx-{ major } .{ minor } -{ arch } '
77+
78+
79+ def _get_ios_platform () -> str :
80+ ver = platform .ios_ver ().release
81+ major , minor = map (int , ver .split ('.' )[:2 ])
82+
83+ # Although _multiarch is an internal implementation detail, it's a core part
84+ # of how CPython is implemented on iOS; this attribute is also relied upon
85+ # by `packaging` as part of tag determination.
86+ multiarch = sys .implementation ._multiarch .replace ('-' , '_' )
87+
88+ return f'ios-{ major } .{ minor } -{ multiarch } '
89+
90+
91+ def introspect_build_details () -> BuildDetails :
92+ platform = sysconfig .get_platform ()
93+ if platform .startswith ('macosx' ):
94+ platform = _get_macosx_platform ()
95+ elif platform .startswith ('ios' ):
96+ platform = _get_ios_platform ()
97+ elif _32_BIT_INTERPRETER :
98+ # 32-bit Python running on a 64-bit kernel.
99+ if platform == 'linux-x86_64' :
100+ platform = 'linux_i686'
101+ if platform == 'linux-aarch64' :
102+ platform = 'linux_armv7l'
103+
104+ return {
105+ 'abi' : {
106+ # PyPy reports a $SOABI that does not agree with $EXT_SUFFIX.
107+ # Using $EXT_SUFFIX will not break when PyPy will fix this.
108+ # See https://foss.heptapod.net/pypy/pypy/-/issues/3816 and
109+ # https://github.com/pypa/packaging/pull/607.
110+ 'extension_suffix' : str (sysconfig .get_config_var ('EXT_SUFFIX' )),
111+ },
112+ 'implementation' : {
113+ 'name' : sys .implementation .name ,
114+ 'version' : {
115+ 'major' : sys .version_info .major ,
116+ 'minor' : sys .version_info .minor ,
117+ },
118+ },
119+ 'platform' : platform ,
120+ }
121+
122+
123+ def get_interpreter_tag (build_details : BuildDetails ) -> str :
124+ name = build_details ['implementation' ]['name' ]
125+ _v = build_details ['implementation' ]['version' ]
126+ major = _v ['major' ]
127+ minor = _v ['minor' ]
57128 name = INTERPRETERS .get (name , name )
58129 return f'{ name } { major } { minor } '
59130
60131
61- def get_abi_tag (build_details : BuildDetails | None = None ) -> str :
132+ def get_abi_tag (build_details : BuildDetails ) -> str :
62133 # The best solution to obtain the Python ABI is to parse the
63134 # $SOABI or $EXT_SUFFIX sysconfig variables as defined in PEP-314.
64135
65136 # PyPy reports a $SOABI that does not agree with $EXT_SUFFIX.
66137 # Using $EXT_SUFFIX will not break when PyPy will fix this.
67138 # See https://foss.heptapod.net/pypy/pypy/-/issues/3816 and
68139 # https://github.com/pypa/packaging/pull/607.
69- if build_details is None :
70- ext_suffix = str (sysconfig .get_config_var ('EXT_SUFFIX' ))
71- else :
72- ext_suffix = build_details ['abi' ]['extension_suffix' ]
140+ ext_suffix = build_details ['abi' ]['extension_suffix' ]
73141 empty , abi , ext = ext_suffix .split ('.' )
74142
75143 # The packaging module initially based his understanding of the
@@ -91,8 +159,9 @@ def get_abi_tag(build_details: BuildDetails | None = None) -> str:
91159 return abi .replace ('.' , '_' ).replace ('-' , '_' )
92160
93161
94- def _get_macosx_platform_tag (build_details : BuildDetails | None = None ) -> str :
95- ver , _ , arch = platform .mac_ver ()
162+ def _get_macosx_platform_tag (platform : str ) -> str :
163+ name , version , arch = platform .split ('-' , 2 )
164+ assert name == 'macosx'
96165
97166 # Override the architecture with the one provided in the
98167 # _PYTHON_HOST_PLATFORM environment variable. This environment
@@ -112,24 +181,7 @@ def _get_macosx_platform_tag(build_details: BuildDetails | None = None) -> str:
112181 parts = os .environ .get ('MACOSX_DEPLOYMENT_TARGET' , '' ).split ('.' )[:2 ]
113182 version = tuple (map (int , parts + ['0' ] * (2 - len (parts ))))
114183 except ValueError :
115- version = tuple (map (int , ver .split ('.' )))[:2 ]
116-
117- # Python built with older macOS SDK on macOS 11, reports an
118- # nonexistent macOS 10.16 version instead of the real version.
119- #
120- # The packaging module introduced a workaround
121- # https://github.com/pypa/packaging/commit/67c4a2820c549070bbfc4bfbf5e2a250075048da
122- #
123- # This results in packaging versions up to 21.3 generating
124- # platform tags like "macosx_10_16_x86_64" and later versions
125- # generating "macosx_11_0_x86_64". Using the latter would be more
126- # correct but prevents the resulting wheel from being installed on
127- # systems using packaging 21.3 or earlier (pip 22.3 or earlier).
128- #
129- # Fortunately packaging versions carrying the workaround still
130- # accepts "macosx_10_16_x86_64" as a compatible platform tag. We
131- # can therefore ignore the issue and generate the slightly
132- # incorrect tag.
184+ version = tuple (map (int , version .split ('.' )[:2 ]))
133185
134186 # The minimum macOS ABI version on arm64 is 11.0. The macOS SDK
135187 # on arm64 silently bumps any compatibility version specified via
@@ -151,59 +203,36 @@ def _get_macosx_platform_tag(build_details: BuildDetails | None = None) -> str:
151203 # the patch level. Reset the patch level to zero.
152204 minor = 0
153205
154- # When using build-details.json, the platform recorded should be correct
155- # per the bitness of the interpreter.
156- if build_details is None and _32_BIT_INTERPRETER :
157- # 32-bit Python running on a 64-bit kernel.
158- if arch == 'ppc64' :
159- arch = 'ppc'
160- if arch == 'x86_64' :
161- arch = 'i386'
162-
163206 return f'macosx_{ major } _{ minor } _{ arch } '
164207
165208
166- def _get_ios_platform_tag () -> str :
209+ def _get_ios_platform_tag (platform : str ) -> str :
210+ name , version , multiarch = platform .split ('-' , 2 )
211+ assert name == 'ios'
212+
167213 # Override the iOS version if one is provided via the
168214 # IPHONEOS_DEPLOYMENT_TARGET environment variable.
169215 try :
170216 parts = os .environ .get ('IPHONEOS_DEPLOYMENT_TARGET' , '' ).split ('.' )[:2 ]
171- version = tuple (map (int , parts + ['0' ] * (2 - len (parts ))))
217+ version = '.' . join (map (int , parts + ['0' ] * (2 - len (parts ))))
172218 except ValueError :
173- version = tuple (map (int , platform .ios_ver ().release .split ('.' )))[:2 ] # type: ignore[attr-defined]
174-
175- # Although _multiarch is an internal implementation detail, it's a core part
176- # of how CPython is implemented on iOS; this attribute is also relied upon
177- # by `packaging` as part of tag determination.
178- multiarch = sys .implementation ._multiarch .replace ('-' , '_' )
219+ pass
179220
180- return f'ios_{ version [ 0 ] } _ { version [ 1 ] } _{ multiarch } '
221+ return f'ios_{ version . replace ( '.' , '_' ) } _{ multiarch . replace ( '-' , '_' ) } '
181222
182223
183224def get_platform_tag (build_details : BuildDetails | None = None ) -> str :
184- if build_details is None :
185- platform = sysconfig .get_platform ()
186- else :
187- platform = build_details ['platform' ]
188-
225+ platform = build_details ['platform' ]
189226 if platform .startswith ('macosx' ):
190- return _get_macosx_platform_tag (build_details )
227+ return _get_macosx_platform_tag (platform )
191228 if platform .startswith ('ios' ):
192- return _get_ios_platform_tag ()
193- # When using build-details.json, the platform recorded should be correct
194- # per the bitness of the interpreter.
195- if build_details is None and _32_BIT_INTERPRETER :
196- # 32-bit Python running on a 64-bit kernel.
197- if platform == 'linux-x86_64' :
198- return 'linux_i686'
199- if platform == 'linux-aarch64' :
200- return 'linux_armv7l'
229+ return _get_ios_platform_tag (platform )
201230 return platform .replace ('-' , '_' ).replace ('.' , '_' ).lower ()
202231
203232
204233class Tag :
205234 def __init__ (self , interpreter : str | None = None , abi : str | None = None , platform : str | None = None ,
206- build_details : BuildDetails | None = None ):
235+ * , build_details : BuildDetails ):
207236 self .interpreter = interpreter or get_interpreter_tag (build_details )
208237 self .abi = abi or get_abi_tag (build_details )
209238 self .platform = platform or get_platform_tag (build_details )
0 commit comments