2
2
from __future__ import annotations
3
3
4
4
import re
5
+ import struct
5
6
import sys
6
7
from dataclasses import dataclass
7
8
from enum import Enum
@@ -22,6 +23,15 @@ class PlatformError(Exception):
22
23
r"(?P<os>manylinux|macos|musllinux)_(?P<major>\d+?)_(?P<minor>\d+?)_(?P<arch>[a-z0-9_]+)$"
23
24
)
24
25
26
+ _os_mapping = {
27
+ "freebsd" : os .FreeBsd ,
28
+ "netbsd" : os .NetBsd ,
29
+ "openbsd" : os .OpenBsd ,
30
+ "dragonfly" : os .Dragonfly ,
31
+ "illumos" : os .Illumos ,
32
+ "haiku" : os .Haiku ,
33
+ }
34
+
25
35
26
36
@dataclass (frozen = True )
27
37
class Platform :
@@ -73,6 +83,9 @@ def parse(cls, platform: str) -> Self:
73
83
return cls (os .Musllinux (int (major ), int (minor )), Arch .parse (arch ))
74
84
else :
75
85
os_ , arch = platform .split ("_" , 1 )
86
+ if os_ in _os_mapping :
87
+ release , _ , arch = arch .partition ("_" )
88
+ return cls (_os_mapping [os_ ](release ), Arch .parse (arch ))
76
89
try :
77
90
return cls (os .Generic (os_ ), Arch .parse (arch ))
78
91
except ValueError as e :
@@ -89,38 +102,61 @@ def __str__(self) -> str:
89
102
def current (cls ) -> Self :
90
103
"""Return the current platform."""
91
104
import platform
105
+ import sysconfig
92
106
93
- system = platform .system ()
94
- arch = Arch .parse (platform .machine ().lower ())
95
- if (
96
- platform .machine ().lower () == "amd64"
97
- and platform .architecture ()[0 ] == "32bit"
98
- ):
99
- arch = Arch .parse ("x86" )
100
- if system == "Linux" :
101
- libc_ver = platform .libc_ver ()[1 ]
102
- if libc_ver :
103
- parts = libc_ver .split ("." )
104
- return cls (os .Manylinux (int (parts [0 ]), int (parts [1 ])), arch )
105
- else : # musl
106
- from packaging ._musllinux import _get_musl_version
107
-
108
- musl_version = _get_musl_version (sys .executable )
109
- if musl_version is None :
110
- raise PlatformError (
111
- "Failed to detect musl version or glibc version"
112
- )
113
- return cls (os .Musllinux (musl_version .major , musl_version .minor ), arch )
114
- elif system == "Windows" :
115
- return cls (os .Windows (), arch )
116
- elif system == "Darwin" :
117
- mac_ver = platform .mac_ver ()[0 ].split ("." )
118
- major , minor = int (mac_ver [0 ]), int (mac_ver [1 ])
119
- if major >= 11 :
120
- minor = 0
121
- return cls (os .Macos (major , minor ), arch )
107
+ platform_ = sysconfig .get_platform ()
108
+ platform_info = platform_ .split ("-" , 1 )
109
+ if len (platform_info ) == 1 :
110
+ if platform_info [0 ] == "win32" :
111
+ return cls (os .Windows (), Arch .X86 )
112
+ else :
113
+ raise PlatformError (f"Unsupported platform { platform_ } " )
114
+ else :
115
+ [operating_system , version_arch ] = platform_info
116
+ if "-" in version_arch :
117
+ # Ex: macosx-11.2-arm64
118
+ version , architecture = version_arch .rsplit ("-" , 1 )
122
119
else :
123
- raise PlatformError ("Unsupported platform" )
120
+ # Ex: linux-x86_64
121
+ version = None
122
+ architecture = version_arch
123
+
124
+ if operating_system == "linux" :
125
+ from packaging ._manylinux import _get_glibc_version
126
+ from packaging ._musllinux import _get_musl_version
127
+
128
+ musl_version = _get_musl_version (sys .executable )
129
+ glibc_version = _get_glibc_version ()
130
+ if musl_version :
131
+ os_ = os .Musllinux (musl_version [0 ], musl_version [1 ])
132
+ elif glibc_version != (- 1 , - 1 ):
133
+ os_ = os .Manylinux (glibc_version [0 ], glibc_version [1 ])
134
+ else :
135
+ raise PlatformError ("Unsupported platform: libc not found" )
136
+ elif operating_system == "win" :
137
+ os_ = os .Windows ()
138
+ elif operating_system == "macosx" :
139
+ # Apparently, Mac OS is reporting i386 sometimes in sysconfig.get_platform even
140
+ # though that's not a thing anymore.
141
+ # https://github.com/astral-sh/uv/issues/2450
142
+ version , _ , architecture = platform .mac_ver ()
143
+
144
+ # https://github.com/pypa/packaging/blob/cc938f984bbbe43c5734b9656c9837ab3a28191f/src/packaging/tags.py#L356-L363
145
+ is_32bit = struct .calcsize ("P" ) == 4
146
+ if is_32bit :
147
+ if architecture .startswith ("ppc" ):
148
+ architecture = "ppc"
149
+ else :
150
+ architecture = "i386"
151
+
152
+ version = version .split ("." )
153
+ os_ = os .Macos (int (version [0 ]), int (version [1 ]))
154
+ elif operating_system in _os_mapping :
155
+ os_ = _os_mapping [operating_system ](version )
156
+ else :
157
+ os_ = os .Generic (operating_system )
158
+
159
+ return cls (os_ , Arch .parse (architecture ))
124
160
125
161
@classmethod
126
162
def choices (cls ) -> list [str ]:
0 commit comments