1# -*- coding: utf-8 -*-

2

3 u'''Single C{str}ing constants, C{intern}'ed across C{pygeodesy}

4 modules and function L{pygeodesy.machine}.

5'''

6_COMMASPACE_ = ', ' # overriden below

7_pl2List = None # cached _platform2 lists

8_Py3List = None # cached _pythonarchine lists

9

10

11 class _Dash(str):

12 '''(INTERNAL) Extended C{str} for prefix_DASH_.

13 '''

14 def __call__(self, *args):

15 '''Join C{self} plus all B{C{args}} like C{'-'.join((self,) + B{args})}.

16 '''

17 return _DASH_(self, *args) # re-callable

18

19

20 class _Int(int):

21 '''(INTERNAL) Unique C{int}.

22 '''

23 pass

24

25

26 class Str_(str):

27 '''Extended, I{callable} C{str} class, not nameable.

28

29 @see: Nameable and callable class L{pygeodesy.Str}.

30 '''

31 def join_(self, *args):

32 '''Join all positional B{C{args}} like C{self.join(B{args})}.

33

34 @return: All B{C{args}} joined by this instance (L{Str_}).

35

36 @note: An other L{Str_} instance is returned to make the

37 result re-callable.

38 '''

39 return Str_(str.join(self, map(str, args))) # re-callable

40

41 __call__ = join_

42

43

44 class _Prefix(Str_):

45 '''(INTERNAL) Extended C{str} for prefix.

46 '''

47 def __call__(self, *args):

48 '''Join C{self} plus all B{C{args}} like C{" ".join((self,) + B{args})}.

49 '''

50 return _SPACE_.join_(self, *args) # re-callable

51

52

53 class _Python_(str): # overwritten by singleton below

54 '''(INTERNAL) Extended C{str} for C{"Python"} and version.

55 '''

56 def __call__(self, version=None):

57 '''Return C{"Python <version>"}.

58 '''

59 if not version:

60 from sys import version

61 return _SPACE_(self, version.split(None, 1)[0])

62

63

64 class _Range(str):

65 '''(INTERNAL) Extended C{str} for C{range} strings.

66 '''

67 def __call__(self, lo, hi, lopen=False, ropen=False,

68 prec=0, sep=_COMMASPACE_):

69 '''Return the range as C{"(lo, hi)"}, C{"(lo, hi]"},

70 C{"[lo, hi)"} or C{"[lo, hi]"}.

71 '''

72 from pygeodesy.streprs import Fmt

73 r = NN(Fmt.f(lo, prec=prec), sep,

74 Fmt.f(hi, prec=prec))

75 if lopen:

76 r = Fmt.PAREN(r) if ropen else Fmt.LOPEN(r)

77 else:

78 r = Fmt.ROPEN(r) if ropen else Fmt.SQUARE(r)

79 return r

80

81

82 class _Slicer(str):

83 '''(INTERNAL) String slicer C{.fromX} or C{.tillY}.

84 '''

85 def __getattr__(self, name): # .fromX, .tillY

86 if name.startswith(_till_):

87 i = self.find(name[len(_till_):])

88 if 0 < i < len(self):

89 return _Slicer(self[:i + 1])

90 elif name.startswith(_from_):

91 i = self.find(name[len(_from_):])

92 if 0 < (i + 1) < len(self):

93 return _Slicer(self[i:])

94 else:

95 return getattr(str, name)

96 return self

97

98

99 class MISSING(object):

100 '''(INTERNAL) Singleton C{str}.

101 '''

102 def toRepr(self, **unused):

103 return self.__class__.__name__

104

105 __repr__ = toRepr

106 __str__ = toRepr

107 toStr = toRepr

108

109 MISSING = MISSING() # PYCHOK singleton

110 MISSING.__name__ = str(MISSING)

111

112 NN = Str_('') # Nomen Nescio <https://Wiktionary.org/wiki/N.N.>

113

114# __DUNDER__-style names would get mangled in classes

115_0_ = '0' # PYCHOK 'zero'

116_0to9_ = '0123456789' # PYCHOK OK

117_1_ = '1' # PYCHOK OK

118_2_ = '2' # PYCHOK OK

119_3_ = '3' # PYCHOK OK

120_4_ = '4' # PYCHOK OK

121_a_ = 'a' # PYCHOK OK

122_A_ = 'A' # PYCHOK OK

123_a12_ = 'a12' # PYCHOK OK

124_area_ = 'area' # PYCHOK OK

125_Airy1830_ = 'Airy1830' # PYCHOK OK

126_AiryModified_ = 'AiryModified' # PYCHOK OK

127_ambiguous_ = 'ambiguous' # PYCHOK OK

128_AMPERSAND_ = Str_('&') # PYCHOK OK

129_an_ = 'an' # PYCHOK OK

130_and_ = 'and' # PYCHOK OK

131# _AND_ = _AMPERSAND_ # PYCHOK OK

132_angle_ = 'angle' # PYCHOK OK

133_antipodal_ = 'antipodal' # PYCHOK OK

134_areaOf_ = 'areaOf' # PYCHOK OK

135_arg_ = 'arg' # PYCHOK OK

136_at_ = 'at' # PYCHOK OK

137_AT_ = Str_('@') # PYCHOK OK

138_AtoZnoIO_ = _Slicer('ABCDEFGHJKLMNPQRSTUVWXYZ') # PYCHOK in C{gars}, C{mgrs} and C{wgrs}

139_attribute_ = 'attribute' # PYCHOK OK

140_azi1_ = 'azi1' # PYCHOK OK

141_azi12_ = 'azi12' # PYCHOK OK

142_azi2_ = 'azi2' # PYCHOK OK

143_azimuth_ = 'azimuth' # PYCHOK OK

144_b_ = 'b' # PYCHOK OK

145_B_ = 'B' # PYCHOK OK

146_BACKSLASH_ = Str_('\\') # PYCHOK OK

147_band_ = 'band' # PYCHOK OK

148_BANG_ = Str_('!') # PYCHOK OK

149_BAR_ = Str_('|') # PYCHOK OK

150_bearing_ = 'bearing' # PYCHOK OK

151_Bessel1841_ = 'Bessel1841' # PYCHOK OK

152_beta_ = 'beta' # PYCHOK OK

153_by_ = 'by' # PYCHOK OK

154_c_ = 'c' # PYCHOK OK

155_C_ = 'C' # PYCHOK OK

156_cartesian_ = 'cartesian' # PYCHOK OK

157_center_ = 'center' # PYCHOK OK

158# _CIRCUMFLEX_ = '^' # PYCHOK OK

159_Clarke1866_ = 'Clarke1866' # PYCHOK OK

160_Clarke1880IGN_ = 'Clarke1880IGN' # PYCHOK OK

161_clip_ = 'clip' # PYCHOK OK

162_clipid_ = 'clipid' # PYCHOK OK

163_coincident_ = 'coincident' # PYCHOK OK

164_colinear_ = 'colinear' # PYCHOK OK

165_COLON_ = Str_(':') # PYCHOK OK

166_COLONSPACE_ = Str_(': ') # PYCHOK OK

167_COMMA_ = Str_(',') # PYCHOK OK

168_COMMASPACE_ = Str_(_COMMASPACE_) # PYCHOK OK

169_composite_ = 'composite' # PYCHOK OK

170_concentric_ = 'concentric' # PYCHOK OK

171_convergence_ = _Prefix('convergence') # PYCHOK OK

172_conversion_ = 'conversion' # PYCHOK OK

173_convex_ = 'convex' # PYCHOK OK

174_cubic_ = 'cubic' # PYCHOK OK

175_d_ = 'd' # PYCHOK OK

176_D_ = 'D' # PYCHOK OK

177_DASH_ = Str_('-') # PYCHOK == _MINUS_

178_datum_ = 'datum' # PYCHOK OK

179_decode3_ = 'decode3' # PYCHOK OK

180_deg_ = 'deg' # PYCHOK OK

181_degrees_ = 'degrees' # PYCHOK OK

182_degrees2_ = 'degrees2' # PYCHOK SQUARED

183_delta_ = 'delta' # PYCHOK OK

184_DEPRECATED_ = 'DEPRECATED' # PYCHOK OK

185_DEQUALSPACED_ = Str_(' == ') # PYCHOK OK

186_distance_ = 'distance' # PYCHOK OK

187_distant_ = _Prefix('distant') # PYCHOK OK

188_doesn_t_exist_ = "doesn't exist" # PYCHOK OK

189_DOT_ = Str_('.') # PYCHOK OK

190_down_ = 'down' # PYCHOK OK

191_e_ = 'e' # PYCHOK OK

192_E_ = 'E' # PYCHOK OK

193_earth_ = 'earth' # PYCHOK OK

194_east_ = 'east' # PYCHOK OK

195_easting_ = 'easting' # PYCHOK OK

196_ecef_ = 'ecef' # PYCHOK OK

197_edge_ = 'edge' # PYCHOK OK

198_elevation_ = 'elevation' # PYCHOK OK

199_ELLIPSIS_ = Str_('...') # PYCHOK OK

200_ELLIPSIS4_ = Str_('....') # PYCHOK OK

201# _ELLIPSISPACED_ = Str_(' ... ') # PYCHOK <https://www.ThePunctuationGuide.com/ellipses.html>

202_ellipsoid_ = 'ellipsoid' # PYCHOK OK

203_ellipsoidal_ = 'ellipsoidal' # PYCHOK OK

204_enabled_ = 'enabled' # PYCHOK OK

205_encode_ = 'encode' # PYCHOK OK

206_end_ = 'end' # PYCHOK OK

207_epoch_ = 'epoch' # PYCHOK OK

208_eps_ = 'eps' # PYCHOK OK

209_EQUAL_ = Str_('=') # PYCHOK OK

210_EQUALSPACED_ = Str_(' = ') # PYCHOK OK

211_Error_ = 'Error' # PYCHOK OK

212_exceed_PI_radians_ = 'exceed PI radians' # PYCHOK OK

213_exceeds_ = _Prefix('exceeds') # PYCHOK OK

214# _EXCLAMATION_ = _BANG_ # PYCHOK OK

215_exists_ = 'exists' # PYCHOK OK

216_f_ = 'f' # PYCHOK OK

217_F_ = 'F' # PYCHOK OK

218_feet_ = 'feet' # PYCHOK OK

219_few_ = 'few' # PYCHOK OK

220_fi_ = 'fi' # PYCHOK OK

221_finite_ = 'finite' # PYCHOK OK

222_from_ = 'from' # PYCHOK OK

223_g_ = 'g' # PYCHOK OK

224_gamma_ = 'gamma' # PYCHOK OK

225_GRS80_ = 'GRS80' # PYCHOK OK

226_h_ = 'h' # PYCHOK OK

227_H_ = 'H' # PYCHOK OK

228_height_ = 'height' # PYCHOK OK

229_hemipole_ = 'hemipole' # PYCHOK OK

230_i_ = 'i' # PYCHOK OK

231_iadd_ = '+=' # PYCHOK OK

232_immutable_ = 'immutable' # PYCHOK OK

233_in_ = 'in' # PYCHOK OK

234_incompatible_ = 'incompatible' # PYCHOK OK

235_INF_ = 'INF' # PYCHOK OK

236_infinite_ = 'infinite' # PYCHOK _not_finite_

237_initial_ = 'initial' # PYCHOK OK

238_inside_ = 'inside' # PYCHOK OK

239_insufficient_ = 'insufficient' # PYCHOK OK

240_intersection_ = 'intersection' # PYCHOK OK

241_Intl1924_ = 'Intl1924' # PYCHOK OK

242_invalid_ = 'invalid' # PYCHOK OK

243_isclockwise_ = 'isclockwise' # PYCHOK OK

244_ispolar_ = 'ispolar' # PYCHOK OK

245_j_ = 'j' # PYCHOK OK

246_k0_ = 'k0' # PYCHOK OK

247_kind_ = 'kind' # PYCHOK OK

248_knots_ = 'knots' # PYCHOK OK

249_Krassovski1940_ = 'Krassovski1940' # PYCHOK OK

250_Krassowsky1940_ = 'Krassowsky1940' # PYCHOK OK

251_LANGLE_ = '<' # PYCHOK OK

252_lam_ = 'lam' # PYCHOK OK

253_lat_ = 'lat' # PYCHOK OK

254_lat0_ = 'lat0' # PYCHOK OK

255_lat1_ = 'lat1' # PYCHOK OK

256_lat2_ = 'lat2' # PYCHOK OK

257_latlon_ = 'latlon' # PYCHOK OK

258_LatLon_ = 'LatLon' # PYCHOK OK

259_LCURLY_ = '{' # PYCHOK LBRACE

260_len_ = 'len' # PYCHOK OK

261_limit_ = 'limit' # PYCHOK OK

262_line_ = 'line' # PYCHOK OK

263_linear_ = 'linear' # PYCHOK OK

264_LPAREN_ = '(' # PYCHOK OK

265_lon_ = 'lon' # PYCHOK OK

266_lon0_ = 'lon0' # PYCHOK OK

267_lon1_ = 'lon1' # PYCHOK OK

268_lon2_ = 'lon2' # PYCHOK OK

269_low_ = 'low' # PYCHOK OK

270_LSQUARE_ = '[' # PYCHOK LBRACK

271_ltp_ = 'ltp' # PYCHOK OK

272_m_ = 'm' # PYCHOK OK

273_M_ = 'M' # PYCHOK OK

274_m12_ = 'm12' # PYCHOK OK

275_M12_ = 'M12' # PYCHOK OK

276_M21_ = 'M21' # PYCHOK OK

277_MANT_DIG_ = 'MANT_DIG' # PYCHOK OK

278_MAX_ = 'MAX' # PYCHOK OK

279_mean_ = 'mean' # PYCHOK OK

280_meanOf_ = 'meanOf' # PYCHOK OK

281_meridional_ = 'meridional' # PYCHOK OK

282_meter_ = 'meter' # PYCHOK OK

283_meter2_ = 'meter2' # PYCHOK SQUARED

284_MGRS_ = 'MGRS' # PYCHOK OK

285_MIN_ = 'MIN' # PYCHOK OK

286_MINUS_ = _DASH_ # PYCHOK OK

287_module_ = 'module' # PYCHOK OK

288_n_ = 'n' # PYCHOK OK

289_N_ = 'N' # PYCHOK OK

290_n_a_ = 'n/a' # PYCHOK OK

291_N_A_ = 'N/A' # PYCHOK OK

292_NAD27_ = 'NAD27' # PYCHOK OK

293_NAD83_ = 'NAD83' # PYCHOK OK

294_name_ = 'name' # PYCHOK OK

295_NAN_ = 'NAN' # PYCHOK OK

296_near_ = _Dash('near') # PYCHOK OK

297_nearestOn2_ = 'nearestOn2' # PYCHOK OK

298_negative_ = 'negative' # PYCHOK OK

299_NL_ = Str_('\n') # PYCHOK OK

300_NLATvar_ = Str_(_NL_ + '@var ') # PYCHOK OK

301_NLHASH_ = Str_(_NL_ + '# ') # PYCHOK OK

302# _NLNL_ = _DNL_ # PYCHOK OK

303_NN_ = 'NN' # PYCHOK OK

304_no_ = _Prefix('no') # PYCHOK OK

305_north_ = 'north' # PYCHOK OK

306_northing_ = 'northing' # PYCHOK OK

307_NorthPole_ = 'NorthPole' # PYCHOK OK

308_not_ = _Prefix('not') # PYCHOK OK

309_NOTEQUAL_ = _BANG_ + _EQUAL_ # PYCHOK OK

310_not_finite_ = 'not finite' # PYCHOK _not_(_finite_), _infinite_

311_not_scalar_ = 'not scalar' # PYCHOK _not_(_scalar_)

312_NTF_ = 'NTF' # PYCHOK OK

313_null_ = 'null' # PYCHOK OK

314_number_ = 'number' # PYCHOK OK

315_numpy_ = 'numpy' # PYCHOK OK

316_Nv00_ = 'Nv00' # PYCHOK OK

317_of_ = 'of' # PYCHOK OK

318_on_ = 'on' # PYCHOK OK

319_opposite_ = 'opposite' # PYCHOK OK

320_or_ = 'or' # PYCHOK OK

321_other_ = 'other' # PYCHOK OK

322_outside_ = 'outside' # PYCHOK OK

323_overlap_ = 'overlap' # PYCHOK OK

324_PERCENT_ = '%' # PYCHOK OK

325_PERCENTDOTSTAR_ = '%.*' # PYCHOK _DOT_(_PERCENT_, _STAR_)

326_phi_ = 'phi' # PYCHOK OK

327_PLUS_ = Str_('+') # PYCHOK OK

328_PLUSMINUS_ = _PLUS_ + _MINUS_ # PYCHOK OK

329_point_ = 'point' # PYCHOK OK

330_points_ = 'points' # PYCHOK OK

331_pole_ = 'pole' # PYCHOK OK

332_precision_ = 'precision' # PYCHOK OK

333_prime_vertical_ = 'prime_vertical' # PYCHOK OK

334_pygeodesy_abspath_ = 'pygeodesy_abspath' # PYCHOK OK

335_PyPy__ = 'PyPy ' # PYCHOK + _SPACE_

336_Python_ = _Python_('Python') # PYCHOK singleton

337_python_ = 'python' # PYCHOK OK

338_QUOTE1_ = "'" # PYCHOK OK

339_QUOTE2_ = '"' # PYCHOK OK

340# _QUOTE3_ = "'''" # PYCHOK OK

341# _QUOTE6_ = '"""' # PYCHOK OK

342_R_ = 'R' # PYCHOK OK

343_radians_ = 'radians' # PYCHOK OK

344_radians2_ = 'radians2' # PYCHOK SQUARED

345_radius_ = 'radius' # PYCHOK OK

346_radius1_ = 'radius1' # PYCHOK OK

347_radius2_ = 'radius2' # PYCHOK OK

348_range_ = _Range('range') # PYCHOK OK

349_RANGLE_ = '>' # PYCHOK OK

350_RCURLY_ = '}' # PYCHOK RBRACE

351_reciprocal_ = 'reciprocal' # PYCHOK OK

352_reframe_ = 'reframe' # PYCHOK OK

353_resolution_ = 'resolution' # PYCHOK OK

354_rIn_ = 'rIn' # PYCHOK OK

355_RPAREN_ = ')' # PYCHOK OK

356_RSQUARE_ = ']' # PYCHOK RBRACK

357_s_ = 's' # PYCHOK OK

358_S_ = 'S' # PYCHOK OK

359_s12_ = 's12' # PYCHOK OK

360_S12_ = 'S12' # PYCHOK OK

361_scalar_ = 'scalar' # PYCHOK OK

362_scale_ = 'scale' # PYCHOK OK

363_scale0_ = 'scale0' # PYCHOK OK

364_scipy_ = 'scipy' # PYCHOK OK

365_semi_circular_ = 'semi-circular' # PYCHOK OK

366_sep_ = 'sep' # PYCHOK OK

367_singular_ = 'singular' # PYCHOK OK

368_SLASH_ = Str_('/') # PYCHOK OK

369_small_ = 'small' # PYCHOK OK

370_Sphere_ = 'Sphere' # PYCHOK OK

371_spherical_ = 'spherical' # PYCHOK OK

372_SouthPole_ = 'SouthPole' # PYCHOK OK

373_SPACE_ = Str_(' ') # PYCHOK OK

374_specified_ = 'specified' # PYCHOK OK

375_STAR_ = Str_('*') # PYCHOK OK

376_start_ = 'start' # PYCHOK OK

377_std_ = 'std' # PYCHOK OK

378_stdev_ = 'stdev' # PYCHOK OK

379_supported_ = 'supported' # PYCHOK OK

380_sx_ = 'sx' # PYCHOK OK

381_sy_ = 'sy' # PYCHOK OK

382_sz_ = 'sz' # PYCHOK OK

383_tbd_ = 'tbd' # PYCHOK OK

384_TILDE_ = '~' # PYCHOK OK

385_till_ = 'till' # PYCHOK OK

386_to_ = 'to' # PYCHOK OK

387_tolerance_ = _Prefix('tolerance') # PYCHOK OK

388_too_ = _Prefix('too') # PYCHOK OK

389_transform_ = 'transform' # PYCHOK OK

390_tx_ = 'tx' # PYCHOK OK

391_ty_ = 'ty' # PYCHOK OK

392_tz_ = 'tz' # PYCHOK OK

393_UNDER_ = Str_('_') # PYCHOK OK

394

395 def _UNDER(name): # PYCHOK in .datums, .rhumbx, .ups, .utm, .utmupsBase

396 '''(INTERNAL) Prefix C{name} with I{underscore}.

397 '''

398 return name if name.startswith(_UNDER_) else NN(_UNDER_, name)

399

400_units_ = 'units' # PYCHOK OK

401_up_ = 'up' # PYCHOK OK

402_UPS_ = 'UPS' # PYCHOK OK

403_utf_8_ = 'utf-8' # PYCHOK OK

404_UTM_ = 'UTM' # PYCHOK OK

405_V_ = 'V' # PYCHOK OK

406_valid_ = 'valid' # PYCHOK OK

407_value_ = 'value' # PYCHOK OK

408_version_ = 'version' # PYCHOK OK

409_vs_ = 'vs' # PYCHOK OK

410_W_ = 'W' # PYCHOK OK

411_WGS72_ = 'WGS72' # PYCHOK OK

412_WGS84_ = 'WGS84' # PYCHOK OK

413_width_ = 'width' # PYCHOK OK

414_with_ = 'with' # PYCHOK OK

415_x_ = 'x' # PYCHOK OK

416_X_ = 'X' # PYCHOK OK

417_xyz_ = 'xyz' # PYCHOK OK

418_y_ = 'y' # PYCHOK OK

419_Y_ = 'Y' # PYCHOK OK

420_z_ = 'z' # PYCHOK OK

421_Z_ = 'Z' # PYCHOK OK

422_zone_ = 'zone' # PYCHOK OK

423

424_EW_ = _E_ + _W_ # PYCHOK common cardinals

425_NE_ = _N_ + _E_ # PYCHOK positive ones

426_NS_ = _N_ + _S_ # PYCHOK OK

427_NSEW_ = _NS_ + _EW_ # PYCHOK OK

428_NW_ = _N_ + _W_ # PYCHOK OK

429_SE_ = _S_ + _E_ # PYCHOK OK

430_SW_ = _S_ + _W_ # PYCHOK negative ones

431# _NESW_ = _NE_ + _SW_ # PYCHOK clockwise

432

433_DDOT_ = Str_(_DOT_ * 2) # PYCHOK OK

434# _DEQUAL_ = Str_(_EQUAL_ * 2) # PYCHOK OK

435_DNL_ = Str_(_NL_ * 2) # PYCHOK OK

436# _DSLASH_ = Str_(_SLASH_ * 2) # PYCHOK OK

437# _DSTAR_ = Str_(_STAR_ * 2) # PYCHOK OK

438_DUNDER_ = Str_(_UNDER_ * 2) # PYCHOK OK

439

440_LR_PAIRS = {_LANGLE_: _RANGLE_,

441 _LCURLY_: _RCURLY_,

442 _LPAREN_: _RPAREN_,

443 _LSQUARE_: _RSQUARE_} # PYCHOK OK

444

445

446 def _dunder_nameof(inst, *dflt):

447 '''(INTERNAL) Get the double_underscore __name__ attr.

448 '''

449 try:

450 return inst.__name__

451 except AttributeError:

452 pass

453 return dflt[0] if dflt else inst.__class__.__name__

454

455

456 def _enquote(strs, quote=_QUOTE2_): # in .basics

457 '''(INTERNAL) Enquote a string containing whitespace.

458 '''

459 if len(strs.split()) > 1:

460 strs = NN(quote, strs, quote)

461 return strs

462

463

464 def _load_lib(name):

465 '''(INTERNAL) Load a C{dylib}, B{C{name}} must startwith('lib').

466 '''

467 # macOS 11+ (aka 10.16) no longer provides direct loading of

468 # system libraries, instead it installs the library after a

469 # low-level dlopen(name) call where name is the library base

470 # name. As a result, ctypes.util.find_library can not find

471 # any library not previously dlopen'ed.

472 from ctypes import CDLL

473 from ctypes.util import find_library

474 from sys import platform

475

476 ns = find_library(name), name

477 if platform[:6] == 'darwin': # and os.name == 'posix'

478 from ctypes import _dlopen

479 from os.path import join

480 ns += (_DOT_(name, 'dylib'),

481 _DOT_(name, 'framework'), join(

482 _DOT_(name, 'framework'), name))

483 else: # non-macOS

484 def _dlopen(unused):

485 return True

486

487 for n in ns:

488 try:

489 if n and _dlopen(n): # handle

490 lib = CDLL(n) # == ctypes.cdll.LoadLibrary(n)

491 if lib._name: # has a qualified name

492 return lib

493 except (AttributeError, OSError):

494 pass

495

496 return None # raise OSError

497

498

499 def machine():

500 '''Return standard C{platform.machine}, but distinguishing Intel I{native}

501 from Intel I{emulation} on Apple Silicon (on macOS only).

502

503 @return: Machine C{'arm64'} for Apple Silicon I{native}, C{'x86_64'}

504 for Intel I{native}, C{"arm64_x86_64"} for Intel I{emulation},

505 etc. (C{str} with C{comma}s replaced by C{underscore}s).

506 '''

507 return _platform2()[1]

508

509

510 def _platform2(sep=NN):

511 '''(INTERNAL) Get platform architecture and machine as C{2-list} or C{str}.

512 '''

513 global _pl2List

514 if _pl2List is None:

515 import platform

516 m = platform.machine() # ARM64, arm64, x86_64, iPhone13,2, etc.

517 m = m.replace(_COMMA_, _UNDER_)

518 if m.lower() == 'x86_64': # on Intel or Rosetta2 ...

519 v = platform.mac_ver() # ... and only on macOS ...

520 if v and _version2(v[0]) > (10, 15): # ... 11+ aka 10.16

521 # <https://Developer.Apple.com/forums/thread/659846>

522 if _sysctl_uint('sysctl.proc_translated') == 1: # and \

523# _sysctl_uint('hw.optional.arm64') == 1: # PYCHOK indent

524 m = _UNDER_('arm64', m) # Apple Si emulating Intel x86-64

525 _pl2List = [platform.architecture()[0], # bits

526 m] # arm64, arm64_x86_64, x86_64, etc.

527 return sep.join(_pl2List) if sep else _pl2List # 2-list()

528

529

530 def _pythonarchine(sep=NN): # in test/base.py versions

531 '''(INTERNAL) Get PyPy and Python versions and C{_platform2} as C{3-} or C{4-list} or C{str}.

532 '''

533 global _Py3List

534 if _Py3List is None:

535 from sys import version # XXX shadows?

536 _Py3List = [_Python_(version)] + _platform2()

537 if _PyPy__ in version: # see test/base.py

538 v = version.split(_PyPy__)[1].split(None, 1)[0]

539 _Py3List.insert(0, NN(_PyPy__, v))

540 return sep.join(_Py3List) if sep else _Py3List # 3- or 4-list

541

542

543 def _splituple(strs, *sep_splits): # in .basics, .mgrs

544 '''(INTERNAL) Split a C{comma}- or C{whitespace}-separated

545 string into a C{tuple} of stripped strings.

546 '''

547 t = (strs.split(*sep_splits) if sep_splits else

548 strs.replace(_COMMA_, _SPACE_).split()) if strs else ()

549 return tuple(s.strip() for s in t if s)

550

551

552 def _sysctl_uint(name):

553 '''(INTERNAL) Get an unsigned int sysctl item by name, use on macOS ONLY!

554 '''

555 libc = _load_lib('libc')

556 if libc: # <https://StackOverflow.com/questions/759892/python-ctypes-and-sysctl>

557 from ctypes import byref, c_char_p, c_size_t, c_uint, sizeof # get_errno

558 n = name if str is bytes else bytes(name, _utf_8_) # PYCHOK isPython2 = str is bytes

559 u = c_uint(0)

560 z = c_size_t(sizeof(u))

561 r = libc.sysctlbyname(c_char_p(n), byref(u), byref(z), None, c_size_t(0))

562 else: # could find or load 'libc'

563 r = -2

564 return int(r if r else u.value) # -1 ENOENT error, -2 no libc

565

566

567 def _usage(file_py, *args): # in .etm

568 '''(INTERNAL) Build "usage: python -m ..." cmd line for module B{C{file_py}}.

569 '''

570 import os, sys # PYCHOK imports

571 p = NN(_python_, sys.version_info[0])

572 m = os.path.dirname(file_py).replace(os.getcwd(), _ELLIPSIS_) \

573 .replace(os.sep, _DOT_).strip()

574 b, x = os.path.splitext(os.path.basename(file_py))

575 if x == '.py' and b != '__main__':

576 m = _DOT_(m, b)

577 return NN('usage', _SPACE_(_COLON_, p, '-m', _enquote(m), *args))

578

579

580 def _version2(version, n=2):

581 '''(INTERNAL) Split C{B{version} str} into 1-, 2- or 3-tuple of C{int}s.

582 '''

583 def _int(*vs):

584 for v in vs:

585 try:

586 yield int(v)

587 except (TypeError, ValueError):

588 pass

589

590 t = tuple(_int(*_splituple(version, _DOT_, 2))) + (0,) * n

591 return t[:n]

592

593

594__all__ = (_NN_, # not MISSING!

595 Str_.__name__, # classes

596 machine.__name__) # in .lazily

597__version__ = '23.06.12'

598

599 if __name__ == '__main__':

600

601 from pygeodesy.errors import itemsorted

602 from pygeodesy.lazily import printf

603

604 t = b = 0

605 for n, v in itemsorted(locals(), asorted=False, reverse=True):

606 if n.endswith(_UNDER_) and n.startswith(_UNDER_) and \

607 not n.startswith(_DUNDER_):

608 t += 1

609 b += len(v)

610 m = n[1:-1]

611 if m != v and m.replace(_UNDER_, _SPACE_) != v:

612 printf('%4d: %s = %r', t, n, v)

613 n = len(locals())

614 printf('%4d (%d) names, %s chars total, %.2f chars avg', t, n, b, float(b) / t, nl=1)

615

616# **) MIT License

617#

618# Copyright (C) 2016-2023 -- mrJean1 at Gmail -- All Rights Reserved.

619#

620# Permission is hereby granted, free of charge, to any person obtaining a

621# copy of this software and associated documentation files (the "Software"),

622# to deal in the Software without restriction, including without limitation

623# the rights to use, copy, modify, merge, publish, distribute, sublicense,

624# and/or sell copies of the Software, and to permit persons to whom the

625# Software is furnished to do so, subject to the following conditions:

626#

627# The above copyright notice and this permission notice shall be included

628# in all copies or substantial portions of the Software.

629#

630# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS

631# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

632# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL

633# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR

634# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,

635# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR

636# OTHER DEALINGS IN THE SOFTWARE.