Coverage for pyTooling/Platform/__init__.py: 79%

281 statements  

« prev     ^ index     » next       coverage.py v7.10.3, created at 2025-08-12 20:40 +0000

1# ==================================================================================================================== # 

2# _____ _ _ ____ _ _ __ # 

3# _ __ _ |_ _|__ ___ | (_)_ __ __ _ | _ \| | __ _| |_ / _| ___ _ __ _ __ ___ # 

4# | '_ \| | | || |/ _ \ / _ \| | | '_ \ / _` | | |_) | |/ _` | __| |_ / _ \| '__| '_ ` _ \ # 

5# | |_) | |_| || | (_) | (_) | | | | | | (_| |_| __/| | (_| | |_| _| (_) | | | | | | | | # 

6# | .__/ \__, ||_|\___/ \___/|_|_|_| |_|\__, (_)_| |_|\__,_|\__|_| \___/|_| |_| |_| |_| # 

7# |_| |___/ |___/ # 

8# ==================================================================================================================== # 

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

13# ==================================================================================================================== # 

14# Copyright 2017-2025 Patrick Lehmann - Bötzingen, Germany # 

15# # 

16# Licensed under the Apache License, Version 2.0 (the "License"); # 

17# you may not use this file except in compliance with the License. # 

18# You may obtain a copy of the License at # 

19# # 

20# http://www.apache.org/licenses/LICENSE-2.0 # 

21# # 

22# Unless required by applicable law or agreed to in writing, software # 

23# distributed under the License is distributed on an "AS IS" BASIS, # 

24# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

25# See the License for the specific language governing permissions and # 

26# limitations under the License. # 

27# # 

28# SPDX-License-Identifier: Apache-2.0 # 

29# ==================================================================================================================== # 

30# 

31""" 

32Common platform information gathered from various sources. 

33 

34.. hint:: See :ref:`high-level help <COMMON/Platform>` for explanations and usage examples. 

35""" 

36from enum import Flag, auto, Enum 

37 

38try: 

39 from pyTooling.Decorators import export, readonly 

40 from pyTooling.Exceptions import ToolingException 

41 from pyTooling.MetaClasses import ExtendedType 

42 from pyTooling.Versioning import PythonVersion 

43except (ImportError, ModuleNotFoundError): # pragma: no cover 

44 print("[pyTooling.Platform] Could not import from 'pyTooling.*'!") 

45 

46 try: 

47 from Decorators import export, readonly 

48 from Exceptions import ToolingException 

49 from MetaClasses import ExtendedType 

50 from Versioning import PythonVersion 

51 except (ImportError, ModuleNotFoundError) as ex: # pragma: no cover 

52 print("[pyTooling.Platform] Could not import directly!") 

53 raise ex 

54 

55 

56__all__ = ["CurrentPlatform"] 

57 

58 

59@export 

60class PlatformException(ToolingException): 

61 """Base-exception of all exceptions raised by :mod:`pyTooling.Platform`.""" 

62 

63 

64@export 

65class UnknownPlatformException(PlatformException): 

66 """ 

67 The exception is raised by pyTooling.Platform when the platform can't be determined. 

68 

69 For debugging purposes, a list of system properties from various APIs is added as notes to this exception to ease 

70 debugging unknown or new platforms. 

71 """ 

72 

73 def __init__(self, *args) -> None: 

74 """ 

75 Initialize a new :class:`UnknownPlatformException` instance and add notes with further debugging information. 

76 

77 :param args: Forward positional parameters. 

78 """ 

79 super().__init__(*args) 

80 

81 import sys 

82 import os 

83 import platform 

84 import sysconfig 

85 

86 self.add_note(f"os.name: {os.name}") 

87 self.add_note(f"platform.system: {platform.system()}") 

88 self.add_note(f"platform.machine: {platform.machine()}") 

89 self.add_note(f"platform.architecture: {platform.architecture()}") 

90 self.add_note(f"sys.platform: {sys.platform}") 

91 self.add_note(f"sysconfig.get_platform: {sysconfig.get_platform()}") 

92 

93 

94@export 

95class UnknownOperatingSystemException(PlatformException): 

96 """The exception is raised by pyTooling.Platform when the operating system is unknown.""" 

97 

98 

99@export 

100class PythonImplementation(Enum): 

101 """An enumeration describing the Python implementation (CPython, PyPy, ...).""" 

102 Unknown = 0 #: Unknown Python implementation 

103 

104 CPython = 1 #: CPython (reference implementation) 

105 PyPy = 2 #: PyPy 

106 

107 

108@export 

109class Platforms(Flag): 

110 """A flag describing on which platform Python is running on and/or in which environment it's running in.""" 

111 Unknown = 0 

112 

113 OS_FreeBSD = auto() #: Operating System: BSD (Unix). 

114 OS_Linux = auto() #: Operating System: Linux. 

115 OS_MacOS = auto() #: Operating System: macOS. 

116 OS_Windows = auto() #: Operating System: Windows. 

117 

118 OperatingSystem = OS_FreeBSD | OS_Linux | OS_MacOS | OS_Windows #: Mask: Any operating system. 

119 

120 SEP_WindowsPath = auto() #: Seperator: Path element seperator (e.g. for directories). 

121 SEP_WindowsValue = auto() #: Seperator: Value seperator in variables (e.g. for paths in PATH). 

122 

123 ENV_Native = auto() #: Environment: :term:`native`. 

124 ENV_WSL = auto() #: Environment: :term:`Windows System for Linux <WSL>`. 

125 ENV_MSYS2 = auto() #: Environment: :term:`MSYS2`. 

126 ENV_Cygwin = auto() #: Environment: :term:`Cygwin`. 

127 

128 Environment = ENV_Native | ENV_WSL | ENV_MSYS2 | ENV_Cygwin #: Mask: Any environment. 

129 

130 ARCH_x86_32 = auto() #: Architecture: x86-32 (IA32). 

131 ARCH_x86_64 = auto() #: Architecture: x86-64 (AMD64). 

132 ARCH_AArch64 = auto() #: Architecture: AArch64 (arm64). 

133 

134 Arch_x86 = ARCH_x86_32 | ARCH_x86_64 #: Mask: Any x86 architecture. 

135 Arch_Arm = ARCH_AArch64 #: Mask: Any Arm architecture. 

136 Architecture = Arch_x86 | Arch_Arm #: Mask: Any architecture. 

137 

138 FreeBSD = OS_FreeBSD | ENV_Native | ARCH_x86_64 #: Group: native FreeBSD on x86-64. 

139 Linux = OS_Linux | ENV_Native | ARCH_x86_64 #: Group: native Linux on x86-64. 

140 MacOS = OS_MacOS | ENV_Native #: Group: native macOS. 

141 Windows = OS_Windows | ENV_Native | ARCH_x86_64 | SEP_WindowsPath | SEP_WindowsValue #: Group: native Windows on x86-64. 

142 

143 MacOS_Intel = MacOS | ARCH_x86_64 #: Group: native macOS on x86-64. 

144 MacOS_ARM = MacOS | ARCH_AArch64 #: Group: native macOS on aarch64. 

145 

146 MSYS = auto() #: MSYS2 Runtime: MSYS. 

147 MinGW32 = auto() #: MSYS2 Runtime: :term:`MinGW32 <MinGW>`. 

148 MinGW64 = auto() #: MSYS2 Runtime: :term:`MinGW64 <MinGW>`. 

149 UCRT64 = auto() #: MSYS2 Runtime: :term:`UCRT64 <UCRT>`. 

150 Clang32 = auto() #: MSYS2 Runtime: Clang32. 

151 Clang64 = auto() #: MSYS2 Runtime: Clang64. 

152 

153 MSYS2_Runtime = MSYS | MinGW32 | MinGW64 | UCRT64 | Clang32 | Clang64 #: Mask: Any MSYS2 runtime environment. 

154 

155 Windows_MSYS2_MSYS = OS_Windows | ENV_MSYS2 | ARCH_x86_64 | MSYS #: Group: MSYS runtime running on Windows x86-64 

156 Windows_MSYS2_MinGW32 = OS_Windows | ENV_MSYS2 | ARCH_x86_64 | MinGW32 #: Group: MinGW32 runtime running on Windows x86-64 

157 Windows_MSYS2_MinGW64 = OS_Windows | ENV_MSYS2 | ARCH_x86_64 | MinGW64 #: Group: MinGW64 runtime running on Windows x86-64 

158 Windows_MSYS2_UCRT64 = OS_Windows | ENV_MSYS2 | ARCH_x86_64 | UCRT64 #: Group: UCRT64 runtime running on Windows x86-64 

159 Windows_MSYS2_Clang32 = OS_Windows | ENV_MSYS2 | ARCH_x86_64 | Clang32 #: Group: Clang32 runtime running on Windows x86-64 

160 Windows_MSYS2_Clang64 = OS_Windows | ENV_MSYS2 | ARCH_x86_64 | Clang64 #: Group: Clang64 runtime running on Windows x86-64 

161 

162 Windows_Cygwin32 = OS_Windows | ENV_Cygwin | ARCH_x86_32 #: Group: 32-bit Cygwin runtime on Windows x86-64 

163 Windows_Cygwin64 = OS_Windows | ENV_Cygwin | ARCH_x86_64 #: Group: 64-bit Cygwin runtime on Windows x86-64 

164 

165 

166@export 

167class Platform(metaclass=ExtendedType, singleton=True, slots=True): 

168 """An instance of this class contains all gathered information available from various sources. 

169 

170 .. seealso:: 

171 

172 StackOverflow question: `Python: What OS am I running on? <https://stackoverflow.com/a/54837707/3719459>`__ 

173 """ 

174 

175 _platform: Platforms 

176 _pythonImplementation: PythonImplementation 

177 _pythonVersion: PythonVersion 

178 

179 def __init__(self) -> None: 

180 """ 

181 Initializes a platform by accessing multiple APIs of Python to gather all necessary information. 

182 """ 

183 import sys 

184 import os 

185 import platform 

186 import sysconfig 

187 

188 # Discover the Python implementation 

189 pythonImplementation = platform.python_implementation() 

190 if pythonImplementation == "CPython": 

191 self._pythonImplementation = PythonImplementation.CPython 

192 elif pythonImplementation == "PyPy": 

193 self._pythonImplementation = PythonImplementation.PyPy 

194 else: # pragma: no cover 

195 self._pythonImplementation = PythonImplementation.Unknown 

196 

197 # Discover the Python version 

198 self._pythonVersion = PythonVersion.FromSysVersionInfo() 

199 

200 # Discover the platform 

201 self._platform = Platforms.Unknown 

202 

203 machine = platform.machine() 

204 sys_platform = sys.platform 

205 sysconfig_platform = sysconfig.get_platform() 

206 

207 if os.name == "nt": 

208 self._platform |= Platforms.OS_Windows 

209 

210 if sysconfig_platform == "win32": 210 ↛ 211line 210 didn't jump to line 211 because the condition on line 210 was never true

211 self._platform |= Platforms.ENV_Native | Platforms.ARCH_x86_32 | Platforms.SEP_WindowsPath | Platforms.SEP_WindowsValue 

212 elif sysconfig_platform == "win-amd64": 

213 self._platform |= Platforms.ENV_Native | Platforms.ARCH_x86_64 | Platforms.SEP_WindowsPath | Platforms.SEP_WindowsValue 

214 elif sysconfig_platform.startswith("mingw"): 

215 if machine == "AMD64": 

216 self._platform |= Platforms.ARCH_x86_64 

217 else: # pragma: no cover 

218 raise UnknownPlatformException(f"Unknown architecture '{machine}' for Windows.") 

219 

220 if sysconfig_platform == "mingw_i686_msvcrt_gnu": 220 ↛ 221line 220 didn't jump to line 221 because the condition on line 220 was never true

221 self._platform |= Platforms.ENV_MSYS2 | Platforms.MinGW32 

222 elif sysconfig_platform == "mingw_x86_64_msvcrt_gnu": 

223 self._platform |= Platforms.ENV_MSYS2 | Platforms.MinGW64 

224 elif sysconfig_platform == "mingw_x86_64_ucrt_gnu": 

225 self._platform |= Platforms.ENV_MSYS2 | Platforms.UCRT64 

226 elif sysconfig_platform == "mingw_x86_64_ucrt_llvm": 

227 self._platform |= Platforms.ENV_MSYS2 | Platforms.Clang64 

228 elif sysconfig_platform == "mingw_i686": # pragma: no cover 

229 self._platform |= Platforms.ENV_MSYS2 | Platforms.MinGW32 

230 elif sysconfig_platform == "mingw_x86_64": # pragma: no cover 

231 self._platform |= Platforms.ENV_MSYS2 | Platforms.MinGW64 

232 elif sysconfig_platform == "mingw_x86_64_ucrt": # pragma: no cover 

233 self._platform |= Platforms.ENV_MSYS2 | Platforms.UCRT64 

234 elif sysconfig_platform == "mingw_x86_64_clang": # pragma: no cover 

235 self._platform |= Platforms.ENV_MSYS2 | Platforms.Clang64 

236 else: # pragma: no cover 

237 raise UnknownPlatformException(f"Unknown MSYS2 architecture '{sysconfig_platform}'.") 

238 else: # pragma: no cover 

239 raise UnknownPlatformException(f"Unknown platform '{sysconfig_platform}' running on Windows.") 

240 

241 elif os.name == "posix": 

242 if sys_platform == "linux": 

243 self._platform |= Platforms.OS_Linux | Platforms.ENV_Native 

244 

245 if sysconfig_platform == "linux-x86_64": # native Linux x86_64; Windows 64 + WSL 245 ↛ 247line 245 didn't jump to line 247 because the condition on line 245 was always true

246 self._platform |= Platforms.ARCH_x86_64 

247 elif sysconfig_platform == "linux-aarch64": # native Linux Aarch64 

248 self._platform |= Platforms.ARCH_AArch64 

249 else: # pragma: no cover 

250 raise UnknownPlatformException(f"Unknown architecture '{sysconfig_platform}' for a native Linux.") 

251 

252 elif sys_platform == "darwin": 252 ↛ 262line 252 didn't jump to line 262 because the condition on line 252 was always true

253 self._platform |= Platforms.OS_MacOS | Platforms.ENV_Native 

254 

255 if machine == "x86_64": 

256 self._platform |= Platforms.ARCH_x86_64 

257 elif machine == "arm64": 

258 self._platform |= Platforms.ARCH_AArch64 

259 else: # pragma: no cover 

260 raise UnknownPlatformException(f"Unknown architecture '{machine}' for a native macOS.") 

261 

262 elif sys_platform == "msys": 

263 self._platform |= Platforms.OS_Windows | Platforms.ENV_MSYS2 | Platforms.MSYS 

264 

265 if machine == "i686": 

266 self._platform |= Platforms.ARCH_x86_32 

267 elif machine == "x86_64": 

268 self._platform |= Platforms.ARCH_x86_64 

269 else: # pragma: no cover 

270 raise UnknownPlatformException(f"Unknown architecture '{machine}' for MSYS2-MSYS on Windows.") 

271 

272 elif sys_platform == "cygwin": 

273 self._platform |= Platforms.OS_Windows 

274 

275 if machine == "i686": 

276 self._platform |= Platforms.ARCH_x86_32 

277 elif machine == "x86_64": 

278 self._platform |= Platforms.ARCH_x86_64 

279 else: # pragma: no cover 

280 raise UnknownPlatformException(f"Unknown architecture '{machine}' for Cygwin on Windows.") 

281 

282 elif sys_platform.startswith("freebsd"): 

283 if machine == "amd64": 

284 self._platform = Platforms.FreeBSD 

285 else: # pragma: no cover 

286 raise UnknownPlatformException(f"Unknown architecture '{machine}' for FreeBSD.") 

287 else: # pragma: no cover 

288 raise UnknownPlatformException(f"Unknown POSIX platform '{sys_platform}'.") 

289 else: # pragma: no cover 

290 raise UnknownPlatformException(f"Unknown operating system '{os.name}'.") 

291 

292 @readonly 

293 def PythonImplementation(self) -> PythonImplementation: 

294 """ 

295 Read-only property to return the :class:`PythonImplementation` of the current interpreter. 

296 

297 :returns: Python implementation of the current interpreter. 

298 """ 

299 return self._pythonImplementation 

300 

301 @readonly 

302 def IsCPython(self) -> bool: 

303 """Returns true, if the Python implementation is a :term:`CPython`. 

304 

305 :returns: ``True``, if the Python implementation is CPython. 

306 """ 

307 return self._pythonImplementation is PythonImplementation.CPython 

308 

309 @readonly 

310 def IsPyPy(self) -> bool: 

311 """Returns true, if the Python implementation is a :term:`PyPy`. 

312 

313 :returns: ``True``, if the Python implementation is PyPY. 

314 """ 

315 return self._pythonImplementation is PythonImplementation.PyPy 

316 

317 @readonly 

318 def PythonVersion(self) -> PythonVersion: 

319 """ 

320 Read-only property to return the :class:`pyTooling.Versioning.PythonVersion` of the current interpreter. 

321 

322 :returns: Python version of the current interpreter. 

323 """ 

324 return self._pythonVersion 

325 

326 @readonly 

327 def HostOperatingSystem(self) -> Platforms: 

328 return self._platform & Platforms.OperatingSystem 

329 

330 @readonly 

331 def IsNativePlatform(self) -> bool: 

332 """Returns true, if the platform is a :term:`native` platform. 

333 

334 :returns: ``True``, if the platform is a native platform. 

335 """ 

336 return Platforms.ENV_Native in self._platform 

337 

338 @readonly 

339 def IsNativeFreeBSD(self) -> bool: 

340 """Returns true, if the platform is a :term:`native` FreeBSD x86-64 platform. 

341 

342 :returns: ``True``, if the platform is a native FreeBSD x86-64 platform. 

343 """ 

344 return Platforms.FreeBSD in self._platform 

345 

346 @readonly 

347 def IsNativeMacOS(self) -> bool: 

348 """Returns true, if the platform is a :term:`native` macOS x86-64 platform. 

349 

350 :returns: ``True``, if the platform is a native macOS x86-64 platform. 

351 """ 

352 return Platforms.MacOS in self._platform 

353 

354 @readonly 

355 def IsNativeLinux(self) -> bool: 

356 """Returns true, if the platform is a :term:`native` Linux x86-64 platform. 

357 

358 :returns: ``True``, if the platform is a native Linux x86-64 platform. 

359 """ 

360 return Platforms.Linux in self._platform 

361 

362 @readonly 

363 def IsNativeWindows(self) -> bool: 

364 """Returns true, if the platform is a :term:`native` Windows x86-64 platform. 

365 

366 :returns: ``True``, if the platform is a native Windows x86-64 platform. 

367 """ 

368 return Platforms.Windows in self._platform 

369 

370 @readonly 

371 def IsMSYS2Environment(self) -> bool: 

372 """Returns true, if the platform is a :term:`MSYS2` environment on Windows. 

373 

374 :returns: ``True``, if the platform is a MSYS2 environment on Windows. 

375 """ 

376 return Platforms.ENV_MSYS2 in self._platform 

377 

378 @readonly 

379 def IsMSYSOnWindows(self) -> bool: 

380 """Returns true, if the platform is a MSYS runtime on Windows. 

381 

382 :returns: ``True``, if the platform is a MSYS runtime on Windows. 

383 """ 

384 return Platforms.Windows_MSYS2_MSYS in self._platform 

385 

386 @readonly 

387 def IsMinGW32OnWindows(self) -> bool: 

388 """Returns true, if the platform is a :term:`MinGW32 <MinGW>` runtime on Windows. 

389 

390 :returns: ``True``, if the platform is a MINGW32 runtime on Windows. 

391 """ 

392 return Platforms.Windows_MSYS2_MinGW32 in self._platform 

393 

394 @readonly 

395 def IsMinGW64OnWindows(self) -> bool: 

396 """Returns true, if the platform is a :term:`MinGW64 <MinGW>` runtime on Windows. 

397 

398 :returns: ``True``, if the platform is a MINGW64 runtime on Windows. 

399 """ 

400 return Platforms.Windows_MSYS2_MinGW64 in self._platform 

401 

402 @readonly 

403 def IsUCRT64OnWindows(self) -> bool: 

404 """Returns true, if the platform is a :term:`UCRT64 <UCRT>` runtime on Windows. 

405 

406 :returns: ``True``, if the platform is a UCRT64 runtime on Windows. 

407 """ 

408 return Platforms.Windows_MSYS2_UCRT64 in self._platform 

409 

410 @readonly 

411 def IsClang32OnWindows(self) -> bool: 

412 """Returns true, if the platform is a Clang32 runtime on Windows. 

413 

414 :returns: ``True``, if the platform is a Clang32 runtime on Windows. 

415 """ 

416 return Platforms.Windows_MSYS2_Clang32 in self._platform 

417 

418 @readonly 

419 def IsClang64OnWindows(self) -> bool: 

420 """Returns true, if the platform is a Clang64 runtime on Windows. 

421 

422 :returns: ``True``, if the platform is a Clang64 runtime on Windows. 

423 """ 

424 return Platforms.Windows_MSYS2_Clang64 in self._platform 

425 

426 @readonly 

427 def IsCygwin32OnWindows(self) -> bool: 

428 """Returns true, if the platform is a 32-bit Cygwin runtime on Windows. 

429 

430 :returns: ``True``, if the platform is a 32-bit Cygwin runtime on Windows. 

431 """ 

432 return Platforms.Windows_Cygwin32 in self._platform 

433 

434 @readonly 

435 def IsCygwin64OnWindows(self) -> bool: 

436 """Returns true, if the platform is a 64-bit Cygwin runtime on Windows. 

437 

438 :returns: ``True``, if the platform is a 64-bit Cygwin runtime on Windows. 

439 """ 

440 return Platforms.Windows_Cygwin64 in self._platform 

441 

442 @readonly 

443 def IsPOSIX(self) -> bool: 

444 """ 

445 Returns true, if the platform is POSIX or POSIX-like. 

446 

447 :returns: ``True``, if POSIX or POSIX-like. 

448 """ 

449 return Platforms.SEP_WindowsPath not in self._platform 

450 

451 @readonly 

452 def PathSeperator(self) -> str: 

453 """ 

454 Returns the path element separation character (e.g. for directories). 

455 

456 * POSIX-like: ``/`` 

457 * Windows: ``\\`` 

458 

459 :returns: Path separation character. 

460 """ 

461 if Platforms.SEP_WindowsPath in self._platform: 

462 return "\\" 

463 else: 

464 return "/" 

465 

466 @readonly 

467 def ValueSeperator(self) -> str: 

468 """ 

469 Returns the value separation character (e.g. for paths in PATH). 

470 

471 * POSIX-like: ``:`` 

472 * Windows: ``;`` 

473 

474 :returns: Value separation character. 

475 """ 

476 if Platforms.SEP_WindowsValue in self._platform: 

477 return ";" 

478 else: 

479 return ":" 

480 

481 @readonly 

482 def ExecutableExtension(self) -> str: 

483 """ 

484 Returns the file extension for an executable. 

485 

486 * FreeBSD: ``""`` (empty string) 

487 * Linux: ``""`` (empty string) 

488 * macOS: ``""`` (empty string) 

489 * Windows: ``"exe"`` 

490 

491 :returns: File extension of an executable. 

492 :raises UnknownOperatingSystemException: If the operating system is unknown. 

493 """ 

494 

495 if Platforms.OS_FreeBSD in self._platform: 495 ↛ 496line 495 didn't jump to line 496 because the condition on line 495 was never true

496 return "" 

497 elif Platforms.OS_Linux in self._platform: 

498 return "" 

499 elif Platforms.OS_MacOS in self._platform: 

500 return "" 

501 elif Platforms.OS_Windows in self._platform: 

502 return "exe" 

503 else: # pragma: no cover 

504 raise UnknownOperatingSystemException("Unknown operating system.") 

505 

506 @readonly 

507 def StaticLibraryExtension(self) -> str: 

508 """ 

509 Returns the file extension for a static library. 

510 

511 * FreeBSD: ``"a"`` 

512 * Linux: ``"a"`` 

513 * macOS: ``"lib"`` 

514 * Windows: ``"lib"`` 

515 

516 :returns: File extension of a static library. 

517 :raises UnknownOperatingSystemException: If the operating system is unknown. 

518 """ 

519 if Platforms.OS_FreeBSD in self._platform: 519 ↛ 520line 519 didn't jump to line 520 because the condition on line 519 was never true

520 return "a" 

521 elif Platforms.OS_Linux in self._platform: 

522 return "a" 

523 elif Platforms.OS_MacOS in self._platform: 

524 return "a" 

525 elif Platforms.OS_Windows in self._platform: 

526 return "lib" 

527 else: # pragma: no cover 

528 raise UnknownOperatingSystemException("Unknown operating system.") 

529 

530 @readonly 

531 def DynamicLibraryExtension(self) -> str: 

532 """ 

533 Returns the file extension for a dynamic/shared library. 

534 

535 * FreeBSD: ``"so"`` 

536 * Linux: ``"so"`` 

537 * macOS: ``"dylib"`` 

538 * Windows: ``"dll"`` 

539 

540 :returns: File extension of a dynamic library. 

541 :raises UnknownOperatingSystemException: If the operating system is unknown. 

542 """ 

543 if Platforms.OS_FreeBSD in self._platform: 543 ↛ 544line 543 didn't jump to line 544 because the condition on line 543 was never true

544 return "so" 

545 elif Platforms.OS_Linux in self._platform: 

546 return "so" 

547 elif Platforms.OS_MacOS in self._platform: 

548 return "dylib" 

549 elif Platforms.OS_Windows in self._platform: 

550 return "dll" 

551 else: # pragma: no cover 

552 raise UnknownOperatingSystemException("Unknown operating system.") 

553 

554 def __repr__(self) -> str: 

555 """ 

556 Returns the platform's string representation. 

557 

558 :returns: The string representation of the current platform. 

559 """ 

560 return str(self._platform) 

561 

562 def __str__(self) -> str: 

563 """ 

564 Returns the platform's string equivalent. 

565 

566 :returns: The string equivalent of the platform. 

567 """ 

568 runtime = "" 

569 

570 if Platforms.OS_FreeBSD in self._platform: 570 ↛ 571line 570 didn't jump to line 571 because the condition on line 570 was never true

571 platform = "FreeBSD" 

572 elif Platforms.OS_MacOS in self._platform: 

573 platform = "macOS" 

574 elif Platforms.OS_Linux in self._platform: 

575 platform = "Linux" 

576 elif Platforms.OS_Windows in self._platform: 576 ↛ 579line 576 didn't jump to line 579 because the condition on line 576 was always true

577 platform = "Windows" 

578 else: 

579 platform = "plat:dec-err" 

580 

581 if Platforms.ENV_Native in self._platform: 

582 environment = "" 

583 elif Platforms.ENV_WSL in self._platform: 583 ↛ 584line 583 didn't jump to line 584 because the condition on line 583 was never true

584 environment = "+WSL" 

585 elif Platforms.ENV_MSYS2 in self._platform: 585 ↛ 603line 585 didn't jump to line 603 because the condition on line 585 was always true

586 environment = "+MSYS2" 

587 

588 if Platforms.MSYS in self._platform: 588 ↛ 589line 588 didn't jump to line 589 because the condition on line 588 was never true

589 runtime = " - MSYS" 

590 elif Platforms.MinGW32 in self._platform: 590 ↛ 591line 590 didn't jump to line 591 because the condition on line 590 was never true

591 runtime = " - MinGW32" 

592 elif Platforms.MinGW64 in self._platform: 

593 runtime = " - MinGW64" 

594 elif Platforms.UCRT64 in self._platform: 

595 runtime = " - UCRT64" 

596 elif Platforms.Clang32 in self._platform: 596 ↛ 597line 596 didn't jump to line 597 because the condition on line 596 was never true

597 runtime = " - Clang32" 

598 elif Platforms.Clang64 in self._platform: 598 ↛ 601line 598 didn't jump to line 601 because the condition on line 598 was always true

599 runtime = " - Clang64" 

600 else: 

601 runtime = "rt:dec-err" 

602 

603 elif Platforms.ENV_Cygwin in self._platform: 

604 environment = "+Cygwin" 

605 else: 

606 environment = "env:dec-err" 

607 

608 if Platforms.ARCH_x86_32 in self._platform: 608 ↛ 609line 608 didn't jump to line 609 because the condition on line 608 was never true

609 architecture = "x86-32" 

610 elif Platforms.ARCH_x86_64 in self._platform: 

611 architecture = "x86-64" 

612 elif Platforms.ARCH_AArch64 in self._platform: 612 ↛ 615line 612 didn't jump to line 615 because the condition on line 612 was always true

613 architecture = "aarch64" 

614 else: 

615 architecture = "arch:dec-err" 

616 

617 return f"{platform}{environment} ({architecture}){runtime}" 

618 

619 

620CurrentPlatform = Platform() #: Gathered information for the current platform.