1# -*- coding: utf-8 -*- 2 3u'''Single-instance C{float}s and C{str}ings, C{intern}'ed across modules. 4''' 5from math import pi as PI, sqrt 6 7 8class _Dash(str): 9 '''(INTERNAL) Extended C{str} for prefix_DASH_. 10 ''' 11 def __call__(self, *args): 12 '''Join C{self} plus all B{C{args}} like C{str.join((self,) + B{args})}. 13 ''' 14 return _DASH_(self, *args) # re-callable 15 16 17class _Join(str): 18 '''(INTERNAL) Extended, callable C{str}. 19 ''' 20 def join_(self, *args): 21 '''Join all B{C{args}} like C{str.join(B{args})}. 22 ''' 23 return _Join(str.join(self, map(str, args))) # re-callable 24 25 __call__ = join_ 26 27 28class _Prefix(_Join): 29 '''(INTERNAL) Extended C{str} for prefix. 30 ''' 31 def __call__(self, *args): 32 '''Join C{self} plus all B{C{args}} like C{str.join((self,) + B{args})}. 33 ''' 34 return _SPACE_.join_(self, *args) # re-callable 35 36 37class _Python_(str): # overwritten below 38 '''(INTERNAL) Extended C{str} for C{Python} and version. 39 ''' 40 def __call__(self, sys): 41 '''Return C{"Python <version>"}. 42 ''' 43 return _SPACE_(self, sys.version.split()[0]) 44 45 46class _Slicer(str): 47 '''(INTERNAL) String slicer C{.fromX} or C{.tillY}. 48 ''' 49 def __getattr__(self, name): # .fromX, .tillY 50 if name.startswith(_till_): 51 i = self.find(name[len(_till_):]) 52 if 0 < i < len(self): 53 return _Slicer(self[:i + 1]) 54 elif name.startswith(_from_): 55 i = self.find(name[len(_from_):]) 56 if 0 < (i + 1) < len(self): 57 return _Slicer(self[i:]) 58 else: 59 return getattr(str, name) 60 return self 61 62 63class MISSING(object): 64 '''(INTERNAL) Singleton. 65 ''' 66 def toRepr(self, **unused): 67 return self.__class__.__name__ 68 69 __repr__ = toRepr 70 __str__ = toRepr 71 toStr = toRepr 72 73MISSING = MISSING() # PYCHOK singleton 74MISSING.__name__ = str(MISSING) 75 76NN = _Join('') # Nomen Nescio <https://Wiktionary.org/wiki/N.N.> 77 78# __DUNDER__-style names would get mangled in classes 79_0_ = '0' # PYCHOK expected 80_0to9_ = '0123456789' # PYCHOK expected 81_1_ = '1' # PYCHOK expected 82_2_ = '2' # PYCHOK expected 83_3_ = '3' # PYCHOK expected 84_4_ = '4' # PYCHOK expected 85_a_ = 'a' # PYCHOK expected 86_A_ = 'A' # PYCHOK expected 87_Airy1830_ = 'Airy1830' # PYCHOK expected 88_AiryModified_ = 'AiryModified' # PYCHOK expected 89_an_ = 'an' # PYCHOK expected 90_angle_ = 'angle' # PYCHOK expected 91_areaOf_ = 'areaOf' # PYCHOK expected 92_ambiguous_ = 'ambiguous' # PYCHOK expected 93# _AMPERSAND_ = _Join('&') # PYCHOK expected 94# _AND_ = _AMPERSAND_ # PYCHOK expected 95_and_ = 'and' # PYCHOK expected 96_at_ = 'at' # PYCHOK expected 97_AT_ = _Join('@') # PYCHOK expected 98_AtoZnoIO_ = _Slicer('ABCDEFGHJKLMNPQRSTUVWXYZ') # PYCHOK in C{gars}, C{mgrs} and C{wgrs} 99_attribute_ = 'attribute' # PYCHOK expected 100_azi2_ = 'azi2' # PYCHOK expected 101_azimuth_ = 'azimuth' # PYCHOK expected 102_B_ = 'B' # PYCHOK expected 103_band_ = 'band' # PYCHOK expected 104_BAR_ = _Join('|') # PYCHOK expected 105_bearing_ = 'bearing' # PYCHOK expected 106_Bessel1841_ = 'Bessel1841' # PYCHOK expected 107_by_ = 'by' # PYCHOK expected 108_C_ = 'C' # PYCHOK expected 109_Cartesian_ = 'Cartesian' # PYCHOK expected 110_center_ = 'center' # PYCHOK expected 111_Clarke1866_ = 'Clarke1866' # PYCHOK expected 112_Clarke1880IGN_ = 'Clarke1880IGN' # PYCHOK expected 113_coincident_ = 'coincident' # PYCHOK expected 114_colinear_ = 'colinear' # PYCHOK expected 115_COLON_ = _Join(':') # PYCHOK expected 116_COLONSPACE_ = _Join(': ') # PYCHOK expected 117_COMMA_ = _Join(',') # PYCHOK expected 118_COMMASPACE_ = _Join(', ') # PYCHOK expected 119_concentric_ = 'concentric' # PYCHOK expected 120_convergence_ = _Prefix('convergence') # PYCHOK expected 121_conversion_ = 'conversion' # PYCHOK expected 122_convex_ = 'convex' # PYCHOK expected 123_cubic_ = 'cubic' # PYCHOK expected 124_DASH_ = _Join('-') # PYCHOK == _MINUS_ 125_datum_ = 'datum' # PYCHOK expected 126_decode3_ = 'decode3' # PYCHOK expected 127_deg_ = 'deg' # PYCHOK expected 128_degrees_ = 'degrees' # PYCHOK expected 129_degrees2_ = 'degrees2' # PYCHOK SQUARED 130_DEQUALSPACED_ = _Join(' == ') # PYCHOK expected 131_distance_ = 'distance' # PYCHOK expected 132_distanceTo_ = 'distanceTo' # PYCHOK expected 133_distant_ = _Prefix('distant') # PYCHOK expected 134_doesn_t_exist_ = "doesn't exist" # PYCHOK expected 135_DOT_ = _Join('.') # PYCHOK expected 136_down_ = 'down' # PYCHOK expected 137_e_ = 'e' # PYCHOK expected 138_E_ = 'E' # PYCHOK expected 139_east_ = 'east' # PYCHOK expected 140_easting_ = 'easting' # PYCHOK expected 141_ecef_ = 'ecef' # PYCHOK expected 142_edge_ = 'edge' # PYCHOK expected 143_elevation_ = 'elevation' # PYCHOK expected 144_ELLIPSIS_ = _Join('...') # PYCHOK expected 145# _ELLIPSISPACED_ = _Join(' ... ') # PYCHOK <https://www.ThePunctuationGuide.com/ellipses.html> 146_ellipsoid_ = 'ellipsoid' # PYCHOK expected 147_ellipsoidal_ = 'ellipsoidal' # PYCHOK expected 148_enabled_ = 'enabled' # PYCHOK expected 149_encode_ = 'encode' # PYCHOK expected 150_end_ = 'end' # PYCHOK expected 151_epoch_ = 'epoch' # PYCHOK expected 152_EPS_ = 'EPS' # PYCHOK expected 153_EPS0_ = 'EPS0' # PYCHOK expected 154_EQUAL_ = _Join('=') # PYCHOK expected 155_EQUALSPACED_ = _Join(' = ') # PYCHOK expected 156_exceed_PI_radians_ = 'exceed PI radians' # PYCHOK expected 157_exceeds_ = _Prefix('exceeds') # PYCHOK expected 158_exists_ = 'exists' # PYCHOK expected 159_f_ = 'f' # PYCHOK expected 160_feet_ = 'feet' # PYCHOK expected 161_few_ = 'few' # PYCHOK expected 162_finite_ = 'finite' # PYCHOK expected 163_fraction_ = 'fraction' # PYCHOK expected 164_from_ = 'from' # PYCHOK expected 165_g_ = 'g' # PYCHOK expected 166_gamma_ = 'gamma' # PYCHOK expected 167_GRS80_ = 'GRS80' # PYCHOK expected 168_h_ = 'h' # PYCHOK expected 169_H_ = 'H' # PYCHOK expected 170_height_ = 'height' # PYCHOK expected 171_hemipole_ = 'hemipole' # PYCHOK expected 172_immutable_ = 'immutable' # PYCHOK expected 173_i_ = 'i' # PYCHOK expected 174_I_ = 'I' # PYCHOK expected 175_in_ = 'in' # PYCHOK expected 176_INF_ = 'INF' # PYCHOK expected 177_initial_ = 'initial' # PYCHOK expected 178_inside_ = 'inside' # PYCHOK expected 179_intersection_ = 'intersection' # PYCHOK expected 180_Intl1924_ = 'Intl1924' # PYCHOK expected 181_invalid_ = 'invalid' # PYCHOK expected 182_isclockwise_ = 'isclockwise' # PYCHOK expected 183_ispolar_ = 'ispolar' # PYCHOK expected 184_j_ = 'j' # PYCHOK expected 185_k0_ = 'k0' # PYCHOK expected 186_kind_ = 'kind' # PYCHOK expected 187_knots_ = 'knots' # PYCHOK expected 188_Krassovski1940_ = 'Krassovski1940' # PYCHOK expected 189_Krassowsky1940_ = 'Krassowsky1940' # PYCHOK expected 190#_LANGLE_ = '<' # PYCHOK expected 191_lam_ = 'lam' # PYCHOK expected 192_lat_ = 'lat' # PYCHOK expected 193_lat0_ = 'lat0' # PYCHOK expected 194_lat1_ = 'lat1' # PYCHOK expected 195_lat2_ = 'lat2' # PYCHOK expected 196_latlon_ = 'latlon' # PYCHOK expected 197_LatLon_ = 'LatLon' # PYCHOK expected 198#_LCURLY_ = '{' # PYCHOK LBRACE 199_len_ = 'len' # PYCHOK expected 200_linear_ = 'linear' # PYCHOK expected 201#_LPAREN_ = '(' # PYCHOK expected 202_lon_ = 'lon' # PYCHOK expected 203_lon0_ = 'lon0' # PYCHOK expected 204_lon2_ = 'lon2' # PYCHOK expected 205#_LSQUARE_ = '[' # PYCHOK LBRACK 206_ltp_ = 'ltp' # PYCHOK expected 207_m_ = 'm' # PYCHOK expected 208_M_ = 'M' # PYCHOK expected 209_mean_ = 'mean' # PYCHOK expected 210_meanOf_ = 'meanOf' # PYCHOK expected 211_meridional_ = 'meridional' # PYCHOK expected 212_meter_ = 'meter' # PYCHOK expected 213_meter2_ = 'meter2' # PYCHOK SQUARED 214_MGRS_ = 'MGRS' # PYCHOK expected 215_MINUS_ = _DASH_ # PYCHOK expected 216_module_ = 'module' # PYCHOK expected 217_n_ = 'n' # PYCHOK expected 218_N_ = 'N' # PYCHOK expected 219_n_a_ = 'n/a' # PYCHOK expected 220_N_A_ = 'N/A' # PYCHOK expected 221_NAD27_ = 'NAD27' # PYCHOK expected 222_NAD83_ = 'NAD83' # PYCHOK expected 223_name_ = 'name' # PYCHOK expected 224_NAN_ = 'NAN' # PYCHOK expected 225_near_ = _Dash('near') # PYCHOK expected 226_nearestOn2_ = 'nearestOn2' # PYCHOK expected 227_negative_ = 'negative' # PYCHOK expected 228_NL_ = _Join('\n') # PYCHOK expected 229_NL_hash_ = _Join(_NL_ + '# ') # PYCHOK expected 230_NL_var_ = _Join(_NL_ + '@var ') # PYCHOK expected 231_no_ = _Prefix('no') # PYCHOK expected 232_north_ = 'north' # PYCHOK expected 233_northing_ = 'northing' # PYCHOK expected 234_NorthPole_ = 'NorthPole' # PYCHOK expected 235_not_ = _Prefix('not') # PYCHOK expected 236_NTF_ = 'NTF' # PYCHOK expected 237_null_ = 'null' # PYCHOK expected 238_number_ = 'number' # PYCHOK expected 239_numpy_ = 'numpy' # PYCHOK expected 240_Nv00_ = 'Nv00' # PYCHOK expected 241_O_ = 'O' # PYCHOK expected 242_OKd_ = '._-' # PYCHOK expected 243_on_ = 'on' # PYCHOK expected 244_or_ = 'or' # PYCHOK expected 245_other_ = 'other' # PYCHOK expected 246_outside_ = 'outside' # PYCHOK expected 247_overlap_ = 'overlap' # PYCHOK expected 248_PERCENT_ = '%' # PYCHOK expected 249_PERCENTDOTSTAR_ = '%.*' # PYCHOK _DOT_(_PERCENT_, _STAR_) 250_perimeterOf_ = 'perimeterOf' # PYCHOK expected 251_phi_ = 'phi' # PYCHOK expected 252_PLUS_ = _Join('+') # PYCHOK expected 253_PLUSMINUS_ = _PLUS_ + _MINUS_ # PYCHOK expected 254_point_ = 'point' # PYCHOK expected 255_points_ = 'points' # PYCHOK expected 256_pole_ = 'pole' # PYCHOK expected 257_precision_ = 'precision' # PYCHOK expected 258_prime_vertical_ = 'prime_vertical' # PYCHOK expected 259_pygeodesy_abspath_ = 'pygeodesy_abspath' # PYCHOK expected 260_Python_ = _Python_('Python') # PYCHOK singleton 261# _QUOTE1_ = "'" # PYCHOK expected 262_QUOTE2_ = '"' # PYCHOK expected 263# _QUOTE3_ = "'''" # PYCHOK expected 264# _QUOTE6_ = '"""' # PYCHOK expected 265_radians_ = 'radians' # PYCHOK expected 266_radians2_ = 'radians2' # PYCHOK SQUARED 267_radius_ = 'radius' # PYCHOK expected 268_radius1_ = 'radius1' # PYCHOK expected 269_radius2_ = 'radius2' # PYCHOK expected 270# _range_ = _Range('range') # moved down 271#_RANGLE_ = '>' # PYCHOK expected 272#_RCURLY_ = '}' # PYCHOK RBRACE 273_reciprocal_ = 'reciprocal' # PYCHOK expected 274_reframe_ = 'reframe' # PYCHOK expected 275_resolution_ = 'resolution' # PYCHOK expected 276#_RPAREN_ = ')' # PYCHOK expected 277#_RSQUARE_ = ']' # PYCHOK RBRACK 278_s_ = 's' # PYCHOK expected 279_S_ = 'S' # PYCHOK expected 280_scalar_ = 'scalar' # PYCHOK expected 281_scale_ = 'scale' # PYCHOK expected 282_scipy_ = 'scipy' # PYCHOK expected 283_semi_circular_ = 'semi-circular' # PYCHOK expected 284_sep_ = 'sep' # PYCHOK expected 285_singular_ = 'singular' # PYCHOK expected 286_small_ = 'small' # PYCHOK expected 287_Sphere_ = 'Sphere' # PYCHOK expected 288_spherical_ = 'spherical' # PYCHOK expected 289_SouthPole_ = 'SouthPole' # PYCHOK expected 290_SPACE_ = _Join(' ') # PYCHOK expected 291_STAR_ = _Join('*') # PYCHOK expected 292_start_ = 'start' # PYCHOK expected 293_std_ = 'std' # PYCHOK expected 294_stdev_ = 'stdev' # PYCHOK expected 295_supported_ = 'supported' # PYCHOK expected 296_sx_ = 'sx' # PYCHOK expected 297_sy_ = 'sy' # PYCHOK expected 298_sz_ = 'sz' # PYCHOK expected 299_tbd_ = 'tbd' # PYCHOK expected 300_till_ = 'till' # PYCHOK expected 301_to_ = 'to' # PYCHOK expected 302_too_ = _Prefix('too') # PYCHOK expected 303_transform_ = 'transform' # PYCHOK expected 304_tx_ = 'tx' # PYCHOK expected 305_ty_ = 'ty' # PYCHOK expected 306_tz_ = 'tz' # PYCHOK expected 307_UNDER_ = _Join('_') # PYCHOK expected 308_units_ = 'units' # PYCHOK expected 309_up_ = 'up' # PYCHOK expected 310_UPS_ = 'UPS' # PYCHOK expected 311_utf_8_ = 'utf-8' # PYCHOK expected 312_UTM_ = 'UTM' # PYCHOK expected 313_V_ = 'V' # PYCHOK expected 314_valid_ = 'valid' # PYCHOK expected 315_version_ = 'version' # PYCHOK expected 316_vs_ = 'vs' # PYCHOK expected 317__vs__ = ' vs ' # PYCHOK vs-SPACED 318_W_ = 'W' # PYCHOK expected 319_WGS72_ = 'WGS72' # PYCHOK expected 320_WGS84_ = 'WGS84' # PYCHOK expected 321_width_ = 'width' # PYCHOK expected 322_x_ = 'x' # PYCHOK expected 323_X_ = 'X' # PYCHOK expected 324_xyz_ = 'xyz' # PYCHOK expected 325_y_ = 'y' # PYCHOK expected 326_z_ = 'z' # PYCHOK expected 327_zone_ = 'zone' # PYCHOK expected 328 329_EW_ = _E_ + _W_ # PYCHOK common cardinals 330_NE_ = _N_ + _E_ # PYCHOK expected 331_NS_ = _N_ + _S_ # PYCHOK expected 332_NSEW_ = _NS_ + _EW_ # PYCHOK expected 333_NW_ = _N_ + _W_ # PYCHOK expected 334_SE_ = _S_ + _E_ # PYCHOK expected 335_SW_ = _S_ + _W_ # PYCHOK negative ones 336 337_DDOT_ = _Join(_DOT_ * 2) # PYCHOK expected 338# _DEQUAL_ = _Join(_EQUAL_ * 2) # PYCHOK expected 339_DUNDER_ = _Join(_UNDER_ * 2) # PYCHOK expected 340 341 342class _Range(str): 343 '''(INTERNAL) Extended C{str} for C{range} strings. 344 ''' 345 def __call__(self, lo, hi, prec=0, lopen=False, ropen=False, 346 join=_COMMASPACE_): 347 '''Return the range as C{"(lo, hi)"}, C{"(lo, hi]"}, 348 C{"[lo, hi)"} or C{"[lo, hi]"}. 349 ''' 350 from pygeodesy.streprs import Fmt # PYCHOK re-imported 351 r = NN(Fmt.f(lo, prec=prec), join, 352 Fmt.f(hi, prec=prec)) 353 if lopen: 354 r = Fmt.PAREN(r) if ropen else Fmt.LOPEN(r) 355 else: 356 r = Fmt.ROPEN(r) if ropen else Fmt.SQUARE(r) 357 return r 358 359_range_ = _Range('range') # PYCHOK expected 360 361 362def _dunder_name(inst, *dflt): 363 '''(INTERNAL) Get the double_underscore __name__ attr. 364 ''' 365 try: 366 return inst.__name__ 367 except AttributeError: 368 pass 369 return dflt[0] if dflt else inst.__class__.__name__ 370 371 372def _float(f): # in .datums, .ellipsoids, .trf 373 '''(INTERNAL) cache initial C{float}s. 374 ''' 375 f = float(f) 376 return _floats.setdefault(f, f) # PYCHOK del _floats 377 378 379def _floatuple(*fs): 380 '''(INTERNAL) Cache a tuple of C{float}s. 381 ''' 382 return tuple(map(_float, fs)) 383 384 385_floats = {} # PYCHOK floats cache, in .__main__ 386# _float = float # PYCHOK expected 387# del _floats # XXX zap floats cache never 388 389_0_0 = _float( 0) # PYCHOK expected 390_0_001 = _float( 0.001) # PYCHOK expected 391_0_01 = _float( 0.01) # PYCHOK expected 392_0_1 = _float( 0.1) # PYCHOK expected 393_0_125 = _float( 0.125) # PYCHOK expected 394_0_25 = _float( 0.25) # PYCHOK expected 395_0_26 = _float( 0.26) # PYCHOK expected 396_0_5 = _float( 0.5) # PYCHOK expected 397_1_0 = _float( 1) # PYCHOK expected 398_1_0_T = _1_0, # PYCHOK 1-tuple 399_1_5 = _float( 1.5) # PYCHOK expected 400_2_0 = _float( 2) # PYCHOK expected 401_3_0 = _float( 3) # PYCHOK expected 402_4_0 = _float( 4) # PYCHOK expected 403_5_0 = _float( 5) # PYCHOK expected 404_6_0 = _float( 6) # PYCHOK expected 405_8_0 = _float( 8) # PYCHOK expected 406_9_0 = _float( 9) # PYCHOK expected 407_10_0 = _float( 10) # PYCHOK expected 408_16_0 = _float( 16) # PYCHOK expected 409_24_0 = _float( 24) # PYCHOK expected 410_32_0 = _float( 32) # PYCHOK expected 411_60_0 = _float( 60) # PYCHOK expected 412_90_0 = _float( 90) # PYCHOK expected 413_120_0 = _float( 120) # PYCHOK expected 414_180_0 = _float( 180) # PYCHOK expected 415_270_0 = _float( 270) # PYCHOK expected 416_360_0 = _float( 360) # PYCHOK expected 417_400_0 = _float( 400) # PYCHOK expected 418_720_0 = _float( 720) # PYCHOK expected 419_1000_0 = _float(1000) # PYCHOK expected 420_3600_0 = _float(3600) # PYCHOK expected 421 422try: 423 from sys import float_info as _float_info 424 425 DIG = _float_info.dig # PYCHOK system's float decimal digits 426 EPS = _float(_float_info.epsilon) # PYCHOK system's EPSilon 427 MANT_DIG = _float_info.mant_dig # PYCHOK system's float mantissa bits 428 MAX = _float(_float_info.max) # PYCHOK system's MAX float 1.7976931348623157e+308 429 MIN = _float(_float_info.min) # PYCHOK system's MIN float 2.2250738585072014e-308 430except (AttributeError, ImportError): # PYCHOK no cover 431 DIG = 15 # PYCHOK system's float decimal digits 432 EPS = _float(2.220446049250313e-16) # PYCHOK EPSilon 2**-52, M{EPS +/- 1 != 1} 433 MAN_DIG = 53 # PYCHOK float mantissa bits ≈ 53 (C{int}) 434 MAX = _float(pow(_2_0, 1023) * (_2_0 - EPS)) # PYCHOK ≈ 10**308 435 MIN = _float(pow(_2_0, -1022)) # PYCHOK ≈ 10**-308 436 437EPS2 = _float(EPS * _2_0) # PYCHOK ≈ 4.440892098501e-16 438EPS4 = _float(EPS * _4_0) # PYCHOK ≈ 8.881784197001e-16 439EPS_2 = _float(EPS / _2_0) # PYCHOK ≈ 1.110223024625e-16 440EPS1 = _float(_1_0 - EPS) # PYCHOK ≈ 0.9999999999999998 441EPS1_2 = _float(_1_0 - EPS_2) # PYCHOK ≈ 0.9999999999999999 442# _1EPS = _float(_1_0 + EPS) # PYCHOK ≈ 1.0000000000000002 443_1_EPS = _float(_1_0 / EPS) # PYCHOK = 4503599627370496.0 444# _2_EPS = _float(_2_0 / EPS) # PYCHOK = 9007199254740992.0 445_EPS4e8 = _float(EPS4 * 1e8) # PYCHOK ≈ 8.881784197001e-08 446_EPSmin = _float(sqrt(MIN)) # PYCHOK = 1.49166814624e-154 447_EPSqrt = _float(sqrt(EPS)) # PYCHOK = 1.49011611938e5-08 448_EPStol = _float(_EPSqrt * _0_1) # PYCHOK = 1.49011611938e5-09 == sqrt(EPS * _0_01) 449 450EPS0 = _float(EPS**2) # PYCHOK near-zero comparison 4.930381e-32, or EPS or EPS_2 451EPS02 = _float(EPS**4) # PYCHOK near-zero-squared comparison 2.430865e-63 452INF = _float( _INF_) # PYCHOK INFinity, see function L{isinf}, L{isfinite} 453NAN = _float( _NAN_) # PYCHOK Not-A-Number, see function L{isnan} 454NEG0 = float('-0.0') # PYCHOK NEGative 0.0, see function L{isneg0} 455 456PI2 = _float(PI * _2_0) # PYCHOK Two PI, M{PI * 2} aka I{Tau} 457PI3 = _float(PI * _3_0) # PYCHOK Three PI, M{PI * 3} 458PI3_2 = _float(PI * _1_5) # PYCHOK PI and a half, M{PI * 3 / 2} 459PI4 = _float(PI * _4_0) # PYCHOK Four PI, M{PI * 4} 460PI_2 = _float(PI / _2_0) # PYCHOK Half PI, M{PI / 2} 461PI_4 = _float(PI / _4_0) # PYCHOK Quarter PI, M{PI / 4} 462 463R_M = _float(6371008.771415) # PYCHOK mean, spherical earth radius (C{meter}) 464 465MANTIS = MANT_DIG # DEPRECATED, use C{MANT_DIG}. 466 467__all__ = ('DIG', _EPS_, 'EPS2', 'EPS4', 'EPS1', 'EPS1_2', 'EPS_2', _EPS0_, 'EPS02', 468 'INF', 'MANT_DIG', 469 'MANTIS', # DEPRECATED 470 'MAX', 'MIN', # not 'MISSING'! 471 'NAN', 'NEG0', 'NN', 472 'PI', 'PI2', 'PI3', 'PI3_2', 'PI4', 'PI_2', 'PI_4', 473 'machine') # imported by .lazily 474__version__ = '21.09.14' 475 476 477def _load_lib(name): # must startwith('lib') 478 # macOS 11 (aka 10.16) no longer provides direct loading 479 # of system libraries, instead it installs the library 480 # after a low-level dlopen(name) call with the library 481 # base name. As a result, ctypes.util.find_library 482 # can not find any library not previously dlopen'ed. 483 from ctypes import CDLL 484 from ctypes.util import find_library 485 from sys import platform 486 487 ns = find_library(name), name 488 if platform[:6] == 'darwin': # and os.name == 'posix' 489 from ctypes import _dlopen 490 from os.path import join 491 ns += (_DOT_(name, 'dylib'), 492 _DOT_(name, 'framework'), join( 493 _DOT_(name, 'framework'), name)) 494 else: # non-macOS 495 def _dlopen(unused): 496 return True 497 498 for n in ns: 499 try: 500 if n and _dlopen(n): # handle 501 lib = CDLL(n) # == ctypes.cdll.LoadLibrary(n) 502 if lib._name: # has a qualified name 503 return lib 504 except (AttributeError, OSError): 505 pass 506 507 return None # raise OSError 508 509 510def machine(): 511 '''Return the C{platform.machine} string, distinguishing Intel from 512 I{emulating} Intel on Apple Silicon (on macOS). 513 514 @return: Machine C{'arm64'} for Apple Silicon, C{"arm64_x86_64""} for 515 Intel I{emulated}, C{'x86_64'} for Intel, etc. (C{str} with 516 any C{comma}s replaced with C{underscore}s). 517 ''' 518 return _platform2()[1] 519 520 521def _platform2(sep=NN): 522 # get platform architecture and machine as C{2-list} or C{str} 523 import platform 524 m = platform.machine().replace(_COMMA_, _UNDER_) # arm64, x86_64, iPhone13_2, etc. 525 if m == 'x86_64': # only on Intel or Rosetta2 ... 526 v = platform.mac_ver() # ... and only macOS 527 if v and _version2(v[0]) > (10, 15): # macOS 11 Big Sur aka 10.16 528 # <https://Developer.Apple.com/forums/thread/659846> 529 if _sysctl_uint('sysctl.proc_translated') == 1: # and \ 530# _sysctl_uint('hw.optional.arm64') == 1: # PYCHOK indent 531 m = _UNDER_('arm64', m) # Apple Silicon emulating Intel x86-64 532 el = [platform.architecture()[0], # bits 533 m] # arm64, arm64_x86_64, x86_64, etc. 534 return sep.join(el) if sep else el # list 535 536 537def _pythonarchine(sep=NN): # in test/base.py versions 538 # get PyPy and Python versions and C{_platform2} as C{3-} or C{4-list} or C{str} 539 from sys import version # XXX shadows? 540 el = [_SPACE_(_Python_, version.split(None, 1)[0])] + _platform2() 541 if '[PyPy ' in version: # see test/base.py 542 el.insert(0, _SPACE_('PyPy', version.split('[PyPy ')[1].split()[0])) 543 return sep.join(el) if sep else el # list 544 545 546def _sysctl_uint(name): 547 # get an unsigned int sysctl item by name, use on macOS ONLY! 548 libc = _load_lib('libc') 549 if libc: # <https://StackOverflow.com/questions/759892/python-ctypes-and-sysctl> 550 from ctypes import byref, c_char_p, c_size_t, c_uint, sizeof # get_errno 551 n = name if str is bytes else bytes(name, _utf_8_) # PYCHOK isPython2 = str is bytes 552 u = c_uint(0) 553 z = c_size_t(sizeof(u)) 554 r = libc.sysctlbyname(c_char_p(n), byref(u), byref(z), None, c_size_t(0)) 555 else: # could find or load 'libc' 556 r = -2 557 return int(r if r else u.value) # -1 ENOENT error, -2 no libc 558 559 560def _version2(version, n=2): 561 # split C{B{version} str} into 1-, 2- or 3-tuple of C{int}s 562 t = (tuple(map(int, version.split(_DOT_)[:n])) if version else ()) + (0, 0, 0) 563 return t[:n] 564 565# **) MIT License 566# 567# Copyright (C) 2016-2021 -- mrJean1 at Gmail -- All Rights Reserved. 568# 569# Permission is hereby granted, free of charge, to any person obtaining a 570# copy of this software and associated documentation files (the "Software"), 571# to deal in the Software without restriction, including without limitation 572# the rights to use, copy, modify, merge, publish, distribute, sublicense, 573# and/or sell copies of the Software, and to permit persons to whom the 574# Software is furnished to do so, subject to the following conditions: 575# 576# The above copyright notice and this permission notice shall be included 577# in all copies or substantial portions of the Software. 578# 579# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 580# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 581# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 582# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 583# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 584# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 585# OTHER DEALINGS IN THE SOFTWARE. 586