pygeodesy 24.5.8__py2.py3-none-any.whl → 24.5.24__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. {PyGeodesy-24.5.8.dist-info → PyGeodesy-24.5.24.dist-info}/METADATA +2 -2
  2. PyGeodesy-24.5.24.dist-info/RECORD +116 -0
  3. pygeodesy/__init__.py +16 -12
  4. pygeodesy/__main__.py +9 -10
  5. pygeodesy/albers.py +42 -42
  6. pygeodesy/auxilats/__init__.py +1 -1
  7. pygeodesy/auxilats/__main__.py +7 -10
  8. pygeodesy/auxilats/auxAngle.py +32 -31
  9. pygeodesy/auxilats/auxLat.py +81 -51
  10. pygeodesy/azimuthal.py +123 -124
  11. pygeodesy/basics.py +165 -176
  12. pygeodesy/booleans.py +14 -15
  13. pygeodesy/cartesianBase.py +25 -23
  14. pygeodesy/clipy.py +3 -3
  15. pygeodesy/constants.py +8 -6
  16. pygeodesy/css.py +50 -42
  17. pygeodesy/datums.py +50 -48
  18. pygeodesy/dms.py +6 -6
  19. pygeodesy/ecef.py +27 -27
  20. pygeodesy/elevations.py +2 -2
  21. pygeodesy/ellipsoidalBase.py +28 -27
  22. pygeodesy/ellipsoidalBaseDI.py +8 -7
  23. pygeodesy/ellipsoidalNvector.py +11 -12
  24. pygeodesy/ellipsoids.py +41 -35
  25. pygeodesy/elliptic.py +12 -10
  26. pygeodesy/epsg.py +4 -3
  27. pygeodesy/errors.py +35 -13
  28. pygeodesy/etm.py +62 -53
  29. pygeodesy/fmath.py +48 -41
  30. pygeodesy/formy.py +93 -65
  31. pygeodesy/frechet.py +117 -102
  32. pygeodesy/fstats.py +52 -46
  33. pygeodesy/fsums.py +169 -145
  34. pygeodesy/gars.py +10 -9
  35. pygeodesy/geodesicw.py +32 -30
  36. pygeodesy/geodesicx/__init__.py +1 -1
  37. pygeodesy/geodesicx/__main__.py +4 -4
  38. pygeodesy/geodesicx/gx.py +40 -32
  39. pygeodesy/geodesicx/gxarea.py +15 -12
  40. pygeodesy/geodesicx/gxbases.py +3 -4
  41. pygeodesy/geodesicx/gxline.py +6 -8
  42. pygeodesy/geodsolve.py +28 -26
  43. pygeodesy/geohash.py +47 -44
  44. pygeodesy/geoids.py +37 -35
  45. pygeodesy/hausdorff.py +112 -99
  46. pygeodesy/heights.py +136 -129
  47. pygeodesy/internals.py +576 -0
  48. pygeodesy/interns.py +6 -207
  49. pygeodesy/iters.py +22 -19
  50. pygeodesy/karney.py +18 -15
  51. pygeodesy/ktm.py +31 -24
  52. pygeodesy/latlonBase.py +12 -11
  53. pygeodesy/lazily.py +140 -218
  54. pygeodesy/lcc.py +24 -25
  55. pygeodesy/ltp.py +83 -71
  56. pygeodesy/ltpTuples.py +7 -5
  57. pygeodesy/mgrs.py +5 -4
  58. pygeodesy/named.py +136 -49
  59. pygeodesy/namedTuples.py +33 -25
  60. pygeodesy/nvectorBase.py +10 -9
  61. pygeodesy/osgr.py +14 -12
  62. pygeodesy/points.py +13 -13
  63. pygeodesy/props.py +7 -7
  64. pygeodesy/rhumb/__init__.py +1 -1
  65. pygeodesy/rhumb/bases.py +3 -2
  66. pygeodesy/rhumb/solve.py +2 -2
  67. pygeodesy/solveBase.py +8 -7
  68. pygeodesy/sphericalTrigonometry.py +5 -5
  69. pygeodesy/streprs.py +8 -7
  70. pygeodesy/trf.py +8 -8
  71. pygeodesy/triaxials.py +67 -63
  72. pygeodesy/units.py +48 -50
  73. pygeodesy/unitsBase.py +24 -11
  74. pygeodesy/ups.py +7 -6
  75. pygeodesy/utily.py +4 -4
  76. pygeodesy/utm.py +53 -52
  77. pygeodesy/utmupsBase.py +11 -8
  78. pygeodesy/vector2d.py +6 -7
  79. pygeodesy/vector3d.py +16 -17
  80. pygeodesy/vector3dBase.py +5 -5
  81. PyGeodesy-24.5.8.dist-info/RECORD +0 -115
  82. {PyGeodesy-24.5.8.dist-info → PyGeodesy-24.5.24.dist-info}/WHEEL +0 -0
  83. {PyGeodesy-24.5.8.dist-info → PyGeodesy-24.5.24.dist-info}/top_level.txt +0 -0
pygeodesy/latlonBase.py CHANGED
@@ -53,7 +53,7 @@ from contextlib import contextmanager
53
53
  from math import asin, cos, degrees, fabs, radians
54
54
 
55
55
  __all__ = _ALL_LAZY.latlonBase
56
- __version__ = '24.04.07'
56
+ __version__ = '24.05.18'
57
57
 
58
58
 
59
59
  class LatLonBase(_NamedBase):
@@ -66,7 +66,7 @@ class LatLonBase(_NamedBase):
66
66
  _lat = 0 # latitude (C{degrees})
67
67
  _lon = 0 # longitude (C{degrees})
68
68
 
69
- def __init__(self, latlonh, lon=None, height=0, wrap=False, name=NN, datum=None):
69
+ def __init__(self, latlonh, lon=None, height=0, wrap=False, datum=None, **name):
70
70
  '''New C{LatLon}.
71
71
 
72
72
  @arg latlonh: Latitude (C{degrees} or DMS C{str} with N or S suffix) or
@@ -77,9 +77,9 @@ class LatLonBase(_NamedBase):
77
77
  (C{meter}, conventionally).
78
78
  @kwarg wrap: If C{True}, wrap or I{normalize} B{C{lat}} and B{C{lon}}
79
79
  (C{bool}).
80
- @kwarg name: Optional name (C{str}).
81
80
  @kwarg datum: Optional datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2},
82
81
  L{a_f2Tuple} or I{scalar} radius) or C{None}.
82
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
83
83
 
84
84
  @return: New instance (C{LatLon}).
85
85
 
@@ -1418,13 +1418,14 @@ class LatLonBase(_NamedBase):
1418
1418
  for p in (p, c):
1419
1419
  e = _xattr(p, Ecef=None)
1420
1420
  if e not in (None, E): # PYCHOK no cover
1421
- n = Fmt.INDEX(_xkwds_item2(name_point)[0], i)
1422
- raise _ValueError(n, e, txt=_incompatible(E.__name__))
1421
+ n, _ = _xkwds_item2(name_point)
1422
+ n = Fmt.INDEX(n, i)
1423
+ raise _ValueError(n, e, txt=_incompatible(E.__name__)) # txt__
1423
1424
  return c
1424
1425
 
1425
- def toDatum(self, datum2, height=None, name=NN):
1426
+ def toDatum(self, datum2, height=None, **name):
1426
1427
  '''I{Must be overloaded}.'''
1427
- self._notOverloaded(datum2, height=height, name=name)
1428
+ self._notOverloaded(datum2, height=height, **name)
1428
1429
 
1429
1430
  def toEcef(self, height=None, M=False):
1430
1431
  '''Convert this point to I{geocentric} coordinates, also known as
@@ -1476,16 +1477,16 @@ class LatLonBase(_NamedBase):
1476
1477
  return self._Ltp if Ecef in (None, self.Ecef) else self._ltp.Ltp(
1477
1478
  self, ecef=Ecef(self.datum), name=self.name)
1478
1479
 
1479
- def toNormal(self, deep=False, name=NN):
1480
+ def toNormal(self, deep=False, **name):
1480
1481
  '''Get this point I{normalized} to C{abs(lat) <= 90}
1481
1482
  and C{abs(lon) <= 180}.
1482
1483
 
1483
1484
  @kwarg deep: If C{True} make a deep, otherwise a
1484
1485
  shallow copy (C{bool}).
1485
- @kwarg name: Optional name of the copy (C{str}).
1486
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
1486
1487
 
1487
- @return: A copy of this point, I{normalized} and
1488
- optionally renamed (C{LatLon}).
1488
+ @return: A copy of this point, I{normalized} (C{LatLon}),
1489
+ optionally renamed.
1489
1490
 
1490
1491
  @see: Property L{isnormal}, method L{normal} and function
1491
1492
  L{pygeodesy.normal}.
pygeodesy/lazily.py CHANGED
@@ -27,38 +27,41 @@ and line number.
27
27
  after all initial imports.
28
28
  '''
29
29
 
30
- # from pygeodesy.errors import _xError2 # _ALL_MODS
31
- from pygeodesy.interns import MISSING, NN, __all__ as _interns__all__, _areaOf_, \
32
- _attribute_, _by_, _COLONSPACE_, _COMMASPACE_, \
33
- _doesn_t_exist_, _DOT_, _enabled_, _EQUALSPACED_, \
34
- _from_, _HASH_, _immutable_, _isclockwise_, _ispolar_, \
35
- _NL_, _no_, _NorthPole_, _not_, _or_, _pygeodesy_, \
36
- _line_, _module_, _pygeodesy_abspath_, _Python_, _QUOTE1_, \
37
- _QUOTE2_, _SouthPole_, _SPACE_, _sub_packages, _UNDER_, \
38
- _version_, _dunder_nameof, _headof, _tailof # _DEPRECATED_
39
- from pygeodesy.interns import _intern # PYCHOK used!
40
- # from pygeodesy.streprs import Fmt, pairs, unstr # _ALL_MODS
41
- from pygeodesy import _isfrozen # handle as w/o lazy import
42
-
43
- from os import getenv as _getenv # in .errors, .geodsolve, .props, .units
44
- from os.path import basename as _basename
45
- import sys as _sys # in .basics._sizeof
30
+ from pygeodesy import internals as _internals, interns as _interns, \
31
+ _isfrozen # DON'T _lazy_import2
32
+ # from pygeodesy.errors import _error_init # _ALL_MODS
33
+ from pygeodesy.internals import _caller3, _dunder_nameof, _dunder_ismain, \
34
+ _headof, _osversion2, printf, _Pythonarchine, \
35
+ _tailof
36
+ from pygeodesy.interns import NN, _areaOf_, _attribute_, _by_, _COLONSPACE_, \
37
+ _COMMASPACE_, _doesn_t_exist_, _DOT_, _enabled_, \
38
+ _EQUALSPACED_, _from_, _HASH_, _immutable_, \
39
+ _isclockwise_, _ispolar_, _line_, _module_, \
40
+ _no_, _NorthPole_, _not_, _or_, _pygeodesy_, \
41
+ _pygeodesy_abspath_, _SouthPole_, \
42
+ _SPACE_, _sub_packages, _sys, _UNDER_, _version_, \
43
+ _intern # function
44
+ # from pygeodesy.streprs import unstr # _ALL_MODS
45
+
46
+ from os import getenv as _getenv
46
47
  try:
47
48
  from importlib import import_module
48
- except ImportError: # Python 2.6-
49
+ except ImportError as x: # Python 2.6-
50
+ _str_x = str(x)
51
+
49
52
  def import_module(name, *package):
50
53
  t = _ALL_MODS.streprs.unstr(import_module, name, *package)
51
- raise LazyImportError(t, txt=_doesn_t_exist_)
54
+ raise LazyImportError(t, txt=_str_x)
52
55
 
53
- _a_l_l_ = '__all__' # .__main__
54
56
  __as__ = ' as '
57
+ _dunder_all_ = '__all__' # in .__main__
58
+ _dunder_package_ = '__package__'
55
59
  _FOR_DOCS = _getenv('PYGEODESY_FOR_DOCS', NN) # for epydoc ...
56
60
  _from_DOT__ = _SPACE_(NN, _from_, _DOT_)
57
61
  _i0 = () # PYCHOK empty tuple
58
- _init__all__ = _FOR_DOCS or _getenv('PYGEODESY_INIT__ALL__', _a_l_l_) == _a_l_l_ # PYCHOK expoted
62
+ _init__all__ = _FOR_DOCS or _getenv('PYGEODESY_INIT__ALL__', _dunder_all_) == _dunder_all_ # PYCHOK exported
59
63
  _lazily_ = 'lazily'
60
64
  _lazily_imported__ = _SPACE_(_HASH_, _lazily_, 'imported', NN)
61
- _p_a_c_k_a_g_e_ = '__package__'
62
65
  _PYGEODESY_GEOCONVERT_ = 'PYGEODESY_GEOCONVERT' # PYCHOK .mgrs, test.bases
63
66
  _PYGEODESY_GEODSOLVE_ = 'PYGEODESY_GEODSOLVE' # PYCHOK .geodsolve, test.bases
64
67
  _PYGEODESY_LAZY_IMPORT_ = 'PYGEODESY_LAZY_IMPORT'
@@ -121,7 +124,7 @@ class _Dict(dict):
121
124
  self[name] = mod_
122
125
 
123
126
  def _NAME(self, which):
124
- self._name = _intern(which.__name__.upper())
127
+ self._name = _intern(_dunder_nameof(which).upper())
125
128
 
126
129
 
127
130
  class _NamedEnum_RO(dict):
@@ -140,8 +143,8 @@ class _NamedEnum_RO(dict):
140
143
  raise LazyAttributeError(t, txt=_doesn_t_exist_)
141
144
 
142
145
  def __setattr__(self, attr, value): # PYCHOK no cover
143
- t = _EQUALSPACED_(self._DOT_(attr), value)
144
- raise LazyAttributeError(t, txt=_immutable_)
146
+ t = _EQUALSPACED_(self._DOT_(attr), repr(value))
147
+ raise LazyAttributeError(_immutable_, txt=t)
145
148
 
146
149
  def enums(self):
147
150
  # Yield all C{(mod_, tuple)} pairs
@@ -149,14 +152,12 @@ class _NamedEnum_RO(dict):
149
152
  n = m.replace(_UNDER_, _DOT_)
150
153
  if n != m:
151
154
  if m.startswith(_UNDER_):
152
- t = None # skip _name= ...
153
- else:
154
- u = m.rstrip(_UNDER_)
155
- if u != m:
156
- u = len(u)
157
- n = n[:u] + m[u:]
158
- if isinstance(t, tuple):
159
- yield n, t
155
+ continue # skip _name= ...
156
+ u = m.rstrip(_UNDER_)
157
+ if u != m:
158
+ u = len(u)
159
+ n = n[:u] + m[u:]
160
+ yield n, t
160
161
 
161
162
  def fill_D(self, _D, which):
162
163
  # Fill C{_Dict _D}.
@@ -203,8 +204,9 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
203
204
  'equidistant', 'gnomonic'),
204
205
  basics=_i('clips', 'copysign0', 'copytype', 'halfs2',
205
206
  'int1s', 'isbool', 'isCartesian', 'isclass', 'iscomplex', 'isDEPRECATED', 'isfloat',
206
- 'isidentifier', 'isinstanceof', 'isint', 'iskeyword', 'isLatLon', 'islistuple',
207
- 'isNvector', 'isodd', 'isscalar', 'issequence', 'isstr', 'issubclassof', 'itemsorted',
207
+ 'isidentifier', 'isinstanceof', 'isint', 'isiterable', 'isiterablen', 'iskeyword',
208
+ 'isLatLon', 'islistuple', 'isNvector', 'isodd', 'isscalar', 'issequence', 'isstr',
209
+ 'issubclassof', 'itemsorted',
208
210
  'len2', 'map1', 'map2', 'neg', 'neg_',
209
211
  'signBit', 'signOf', 'splice', 'str2ub', 'ub2str', 'unsigned0'),
210
212
  booleans=_i('BooleanFHP', 'BooleanGH', 'LatLonFHP', 'LatLonGH',
@@ -307,13 +309,14 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
307
309
  'HeightIDWeuclidean', 'HeightIDWexact', 'HeightIDWflatLocal', 'HeightIDWflatPolar',
308
310
  'HeightIDWhaversine', 'HeightIDWhubeny', 'HeightIDWkarney', 'HeightIDWthomas',
309
311
  'HeightIDWvincentys', 'HeightLinear', 'HeightLSQBiSpline', 'HeightSmoothBiSpline'),
310
- interns=_interns__all__,
312
+ internals=_internals.__all__,
313
+ interns=_interns.__all__,
311
314
  iters=_i('LatLon2PsxyIter', 'PointsIter', 'points2',
312
315
  'isNumpy2', 'isPoints2', 'isTuple2', 'iterNumpy2', 'iterNumpy2over'),
313
316
  karney=_i('Area3Tuple', 'Caps', 'Direct9Tuple', 'GDict', 'Inverse10Tuple', 'Rhumb8Tuple'),
314
317
  ktm=_i('KTMError', 'KTransverseMercator'),
315
318
  latlonBase=_i(), # module only
316
- lazily=_i('LazyAttributeError', 'LazyImportError', 'isLazy', 'print_', 'printf'),
319
+ lazily=_i('LazyAttributeError', 'LazyImportError', 'isLazy'),
317
320
  lcc=_i('Conic', 'Conics', 'Lcc', 'LCCError', 'toLcc'),
318
321
  ltp=_i('Attitude', 'AttitudeError', 'ChLV', 'ChLVa', 'ChLVe', 'Frustum',
319
322
  'LocalCartesian', 'LocalError', 'Ltp', 'tyr3d'),
@@ -429,12 +432,9 @@ _ALL_DEPRECATED = _NamedEnum_RO(_name='_ALL_DEPRECATED',
429
432
  deprecated_nvector=_i('LatLonNvectorBase', 'Nvector', 'sumOf', 'NorthPole', 'SouthPole'),)
430
433
 
431
434
 
432
- class _ALL_MODS(object):
433
- '''(INTERNAL) Memoize import of any L{pygeodesy} module.
435
+ class _ALL_MODS(_internals._ALL_MODS_Base):
436
+ '''(INTERNAL) Memoized import of any L{pygeodesy} module.
434
437
  '''
435
- def _DOT_(self, name): # PYCHOK no cover
436
- return _DOT_(self.__class__.__name__, name)
437
-
438
438
  def __getattr__(self, name):
439
439
  '''Get a C{pygeodesy} module or attribute by B{C{name}}.
440
440
 
@@ -444,18 +444,16 @@ class _ALL_MODS(object):
444
444
 
445
445
  @raise AttributeError: No attribute named B{C{name}}.
446
446
  '''
447
- try: # most likely ... module is already imported
448
- return _sys.modules[_DOT_(_pygeodesy_, name)]
447
+ try:
448
+ v = _lazy_dict[name] # package.__dict__
449
449
  except KeyError:
450
- pass
451
-
452
- m = self.getmodule(name)
453
- return m if _tailof(m.__name__) == name else \
454
- getattr(m, _tailof(name))
455
-
456
- def __setattr__(self, attr, value): # PYCHOK no cover
457
- t = _EQUALSPACED_(self._DOT_(attr), repr(value))
458
- raise AttributeError(_COLONSPACE_(t, _immutable_))
450
+ v = _lazy_module(name) # package.__getattr__
451
+ if _tailof(_dunder_nameof(v)) != name:
452
+ try:
453
+ v = getattr(v, _tailof(name))
454
+ except AttributeError:
455
+ pass # XXX LazyAttributeError?
456
+ return v
459
457
 
460
458
  def getattr(self, name, *attr_dflt): # , parent=_pygeodesy_
461
459
  '''Get an attribute of/or a C{pygeodesy} module.
@@ -478,7 +476,7 @@ class _ALL_MODS(object):
478
476
  def getmodule(self, name, parent=_pygeodesy_):
479
477
  '''Get a C{pygeodesy} module.
480
478
 
481
- @arg name: Qualified module name (C{str}).
479
+ @arg name: Un/qualified module name (C{str}).
482
480
 
483
481
  @return: The C{pygeodesy} module.
484
482
 
@@ -494,24 +492,20 @@ class _ALL_MODS(object):
494
492
  def items(self): # no module named 'items'
495
493
  '''Yield the modules imported so far.
496
494
  '''
495
+ _hd = _headof
497
496
  for n, m in _sys.modules.items():
498
- yield n, m
497
+ if _hd(n) == _pygeodesy_:
498
+ yield n, m
499
499
 
500
- @property # property_RO
501
- def name(self):
502
- return self.__class__.__name__
503
-
504
- _ALL_MODS = _ALL_MODS() # PYCHOK singleton
500
+ _internals._MODS = _ALL_MODS = _ALL_MODS() # PYCHOK singleton
505
501
 
506
502
  __all__ = _ALL_LAZY.lazily
507
- __version__ = '24.04.22'
503
+ __version__ = '24.05.15'
508
504
 
509
505
 
510
506
  def _ALL_OTHER(*objs):
511
507
  '''(INTERNAL) Get class and function B{C{objs}} for __all__.
512
508
  '''
513
- _interns = _ALL_MODS.interns # from pygeodesy import interns
514
-
515
509
  def _interned(o): # intern'd base name
516
510
  n = _tailof(_dunder_nameof(o))
517
511
  i = NN(_UNDER_, n, _UNDER_) # intern'd
@@ -567,8 +561,8 @@ def _all_missing2(_all_):
567
561
 
568
562
  _alzy = _Dict((a, a) for a in _ALL_INIT)
569
563
  _alzy.update(_all_imports()) # without _all_backups!
570
- return ((_DOT_(_lazily_, _all_imports.__name__), _diff(_all_, _alzy)),
571
- (_DOT_(_pygeodesy_, _a_l_l_), _diff(_alzy.keys(), _all_)))
564
+ return ((_DOT_(_lazily_, _all_imports.__name__), _diff(_all_, _alzy)),
565
+ (_DOT_(_pygeodesy_, _dunder_all_), _diff(_alzy.keys(), _all_)))
572
566
 
573
567
 
574
568
  def _attrof(attr_as): # .testDeprecated
@@ -576,38 +570,25 @@ def _attrof(attr_as): # .testDeprecated
576
570
  return as_ or a_.rstrip(_DOT_)
577
571
 
578
572
 
579
- def _caller3(up): # in .named
580
- '''(INTERNAL) Get 3-tuple C{(caller name, file name, line number)}
581
- for the caller B{C{up}} stack frames in the Python call stack.
582
- '''
583
- # sys._getframe(1) ... 'importlib._bootstrap' line 1032,
584
- # may throw a ValueError('call stack not deep enough')
585
- f = _sys._getframe(up + 1)
586
- return (f.f_code.co_name, # caller name
587
- _basename(f.f_code.co_filename), # file name
588
- f.f_lineno) # line number
589
-
590
-
591
- def _lazy_attr(unused): # PYCHOK overwritten in _lazy_import
592
- pass
593
-
594
-
595
- # def _lazy_attributes(_name_):
596
- # '''(INTERNAL) Return a function to C{B{_name_}.__getattr__(attr)}
573
+ # def _lazy_attributes(_dunder_name_):
574
+ # '''(INTERNAL) Return a function to C{B{__name__}.__getattr__(attr)}
597
575
  # on lazily imported modules and sub-modules.
598
576
  # '''
599
577
  # if _unlazy:
600
- # raise AssertionError(_COMMASPACE_(_name_, _not_(_DEPRECATED_)))
578
+ # raise AssertionError(_COMMASPACE_(_dunder_name_, _not_(_DEPRECATED_)))
601
579
  #
602
580
  # def _getattr(attr, *dflt):
603
581
  # try: # a module name
604
582
  # return _ALL_MODS.getmodule(attr)
605
583
  # except (AttributeError, ImportError):
606
- # return _ALL_MODS.getattr(_name_, attr, *dflt)
584
+ # return _ALL_MODS.getattr(_dunder_name_, attr, *dflt)
607
585
  #
608
586
  # return _getattr
609
587
 
610
588
 
589
+ _lazy_dict = {} # PYCHOK overwritten by _lazy_import2
590
+
591
+
611
592
  def _lazy_import2(pack): # MCCABE 14
612
593
  '''Check for and set up C{lazy import}.
613
594
 
@@ -634,14 +615,15 @@ def _lazy_import2(pack): # MCCABE 14
634
615
  U{PEP 562<https://www.Python.org/dev/peps/pep-0562>} and the
635
616
  U{new way<https://Snarky.Ca/lazy-importing-in-python-3-7/>}.
636
617
  '''
637
- if pack != _pygeodesy_ or _unlazy: # new in 3.7
638
- t = _no_(_DOT_(pack, _lazy_import2.__name__)) # PYCHOK no cover
639
- raise LazyImportError(t, txt=_Python_(_sys.version))
618
+ if pack != _pygeodesy_ or _unlazy: # Python 3.7+
619
+ t = _no_(_DOT_(pack, _dunder_nameof(_lazy_import2))) # PYCHOK no cover
620
+ raise LazyImportError(t, txt=_Pythonarchine(sep=_SPACE_))
640
621
 
641
622
  package, parent = _lazy_init2(pack) # _pygeodesy_
642
623
 
643
- subpacks = set((parent, '__main__', NN) + tuple(
644
- _DOT_(parent, s) for s in _sub_packages))
624
+ subpacks = set((parent, NN) + tuple(
625
+ _DOT_(parent, s) for s in _sub_packages))
626
+ MISSING = object() # DON'T interns.MISSING!
645
627
  imports = _all_imports()
646
628
  deprecates = _all_deprecates()
647
629
 
@@ -658,28 +640,28 @@ def _lazy_import2(pack): # MCCABE 14
658
640
  attr = name
659
641
  try:
660
642
  t = _DOT_(pack, mod)
661
- imported = import_module(t, parent)
643
+ v = import_module(t, parent)
662
644
  except ImportError:
663
645
  # <https://GitHub.com/mrJean1/PyGeodesy/issues/76>
664
646
  raise LazyImportError(_no_(_module_), txt=t)
665
- t = getattr(imported, _p_a_c_k_a_g_e_, None)
647
+ t = getattr(v, _dunder_package_, None)
666
648
  if t not in subpacks: # invalid module package
667
- raise LazyImportError(_DOT_(mod, _p_a_c_k_a_g_e_), t)
649
+ raise LazyImportError(_DOT_(mod, _dunder_package_), t)
668
650
  if attr: # get the attribute
669
- imported = getattr(imported, attr, MISSING)
670
- if imported is MISSING: # PYCHOK no cover
651
+ v = getattr(v, attr, MISSING)
652
+ if v is MISSING: # PYCHOK no cover
671
653
  t = _DOT_(mod, attr)
672
654
  # <https://GitHub.com/mrJean1/PyGeodesy/issues/76>
673
655
  raise LazyAttributeError(_no_(_attribute_), txt=t)
674
656
 
675
- elif name in (_a_l_l_,): # XXX '_d_i_r_', '_m_e_m_b_e_r_s_'?
676
- imported = _ALL_INIT + tuple(imports.keys())
657
+ elif name in (_dunder_all_,): # XXX _dunder_dir_, _dunder_members_?
658
+ v = _ALL_INIT + tuple(imports.keys())
677
659
  else: # PYCHOK no cover
678
660
  t = _no_(_module_, _or_, _attribute_)
679
661
  # <https://GitHub.com/mrJean1/PyGeodesy/issues/76>
680
662
  raise LazyAttributeError(t, txt=_DOT_(parent, name))
681
663
 
682
- setattr(package, name, imported)
664
+ setattr(package, name, v) # package.__dict__[name] = val
683
665
  if isLazy > 1:
684
666
  t = NN(_lazily_imported__, _DOT_(parent, name))
685
667
  if mod and _tailof(mod) != name:
@@ -692,32 +674,33 @@ def _lazy_import2(pack): # MCCABE 14
692
674
  pass
693
675
  printf(t) # XXX print
694
676
 
695
- return imported # __getattr__
677
+ return v # __getattr__
696
678
 
697
- global _lazy_attr
698
- _lazy_attr = __getattr__
679
+ global _lazy_dict, _lazy_module
680
+ _lazy_dict = package.__dict__
681
+ _lazy_module = __getattr__
699
682
 
700
683
  return package, __getattr__ # _lazy_import2
701
684
 
702
685
 
703
- # def _lazy_import_all(_name_):
686
+ # def _lazy_import_all(_dunder_name_):
704
687
  # '''(INTERNAL) Return a function mimicking C{from B{__name__} import *},
705
688
  # of all items, see .deprecated.__init__
706
689
  # '''
707
690
  # if _unlazy:
708
- # raise AssertionError(_COMMASPACE_(_name_, _not_(_DEPRECATED_)))
691
+ # raise AssertionError(_COMMASPACE_(_dunder_name_, _not_(_DEPRECATED_)))
709
692
  #
710
- # _getattr = _lazy_attributes(_name_) # _name_.__getattr__
711
- # _import_start = _lazy_import_star(_name_, ALL_=_ALL_IMPORTS)
693
+ # _getattr = _lazy_attributes(_dunder_name_) # __name__.__getattr__
694
+ # _import_start = _lazy_import_star(_dunder_name_, ALL_=_ALL_IMPORTS)
712
695
  #
713
696
  # def _import_all(attr, *dflt):
714
- # return _import_star(_name_) if attr == _a_l_l_ else \
697
+ # return _import_star(_dunder_name_) if attr == _dunder_all_ else \
715
698
  # _getattr(attr, *dflt)
716
699
  #
717
700
  # return _import_all
718
701
 
719
702
 
720
- def _lazy_import_as(_name_):
703
+ def _lazy_import_as(_dunder_name_):
721
704
  '''(INTERNAL) Return a function to C{import B{__name__}.mod as mod}
722
705
  I{of modules only}, see .deprecated, .rhumb or get an attribute
723
706
  lazily exported by C{__name__}.
@@ -727,25 +710,25 @@ def _lazy_import_as(_name_):
727
710
 
728
711
  def _import_as(mod):
729
712
  try:
730
- return _ALL_MODS.getmodule(_DOT_(_name_, mod))
713
+ return _ALL_MODS.getmodule(_DOT_(_dunder_name_, mod))
731
714
  except ImportError:
732
- return _lazy_attr(mod)
715
+ return _lazy_module(mod)
733
716
 
734
717
  return _import_as
735
718
 
736
719
 
737
- # def _lazy_import_star(_name_, ALL_=_ALL_DEPRECATES):
720
+ # def _lazy_import_star(_dunder_name_, ALL_=_ALL_DEPRECATES):
738
721
  # '''(INTERNAL) Return a function to mimick C{from B{__name__} import *},
739
722
  # of all DEPRECATED items, see .deprecated, .testDeprecated
740
723
  # '''
741
724
  # if _unlazy:
742
- # raise AssertionError(_COMMASPACE_(_name_, _not_(_DEPRECATED_)))
725
+ # raise AssertionError(_COMMASPACE_(_dunder_name_, _not_(_DEPRECATED_)))
743
726
  #
744
727
  # def _import_star(_into_):
745
728
  # '''Do C{from B{__name__} import *} inside module C{B{__into__}}.
746
729
  # '''
747
730
  # d = dict()
748
- # nm = _tailof(_name_)
731
+ # nm = _tailof(_dunder_name_)
749
732
  # _g = _ALL_MODS.getattr # pygeodesy.__getattr__
750
733
  # _h = _headof
751
734
  # for a, m in ALL_.items():
@@ -760,31 +743,6 @@ def _lazy_import_as(_name_):
760
743
  # return _import_star
761
744
 
762
745
 
763
- # def _lazy_subs(_name_, force=_FOR_DOCS, over=False):
764
- # '''(INTERNAL) Return the names of a package's sub-packages and
765
- # update the package's C{__dict__} accordingly.
766
- # '''
767
- # sm = dict()
768
- # if force and _name_ != '__main__':
769
- # nm = _tailof(_name_)
770
- # _a = _ALL_MODS.getattr
771
- # _m = _ALL_MODS.getmodule
772
- # d = _a(_name_, '__dict__', {})
773
- # for n in _a(_name_, _a_l_l_, ()):
774
- # try: # n is a class name, get its mod name
775
- # m = _a(_name_, n).__module__
776
- # n, s = m.split(_DOT_)[-2:]
777
- # if n == nm and s not in sm:
778
- # # like import m as s
779
- # m = _m(m)
780
- # sm[s] = m if over else d.get(s, m)
781
- # except (AttributeError, ImportError, ValueError) as x:
782
- # pass
783
- # d.update(sm)
784
- #
785
- # return _ALL_OTHER(*sm.values())
786
-
787
-
788
746
  def _lazy_init2(pack):
789
747
  '''(INTERNAL) Initialize lazy import and set globals C{isLazy} and C{_unLazy0}.
790
748
 
@@ -813,7 +771,7 @@ def _lazy_init2(pack):
813
771
  _unLazy0 = _unlazy or not isLazy # pre-3.7 or w/o lazy import
814
772
 
815
773
  if isLazy < 1: # not enabled
816
- raise LazyImportError(_PYGEODESY_LAZY_IMPORT_, repr(z), txt=_not_(_enabled_))
774
+ raise LazyImportError(_PYGEODESY_LAZY_IMPORT_, repr(z), txt_not_=_enabled_)
817
775
  if _getenv('PYTHONVERBOSE', None): # PYCHOK no cover
818
776
  isLazy += 1
819
777
 
@@ -831,82 +789,45 @@ def _lazy_init2(pack):
831
789
  return package, parent
832
790
 
833
791
 
834
- def _pairs(*args, **kwds): # in .ktm
835
- # from pygeodesy.streprs import pairs
836
- return _ALL_MODS.streprs.pairs(*args, **kwds)
837
-
838
-
839
- def print_(*args, **nl_nt_prefix_end_file_flush_sep): # PYCHOK no cover
840
- '''Python 3+ C{print}-like formatting and printing.
841
-
842
- @arg args: Arguments to be converted to C{str} and joined by B{C{sep}}
843
- (any C{type}, all positional).
844
- @kwarg nl_nt_prefix_end_file_flush_sep: Keyword arguments C{B{nl}=0}
845
- for the number of leading blank lines (C{int}), C{B{nt}=0}
846
- the number of trailing blank lines (C{int}), C{B{prefix}=NN}
847
- to be inserted before the formatted text (C{str}) and Python
848
- 3+ C{print} keyword arguments C{B{end}}, C{B{sep}}, C{B{file}}
849
- and C{B{flush}}.
850
-
851
- @return: Number of bytes written.
792
+ def _lazy_module(name): # overwritten by _lazy_import2
793
+ '''(INTERNAL) Get or import a C{pygeodesy} module.
852
794
  '''
853
- return printf(NN, *args, **nl_nt_prefix_end_file_flush_sep)
854
-
855
-
856
- def printf(fmt, *args, **nl_nt_prefix_end_file_flush_sep_kwds):
857
- '''C{Printf-style} and Python 3+ C{print}-like formatting and printing.
795
+ try: # most likely ... module has been imported
796
+ m = _ALL_MODS.getmodule(name)
797
+ except (AttributeError, ImportError) as x:
798
+ raise LazyImportError(name, cause=x)
799
+ _lazy_dict[name] = m # cache
800
+ return m
858
801
 
859
- @arg fmt: U{Printf-style<https://Docs.Python.org/3/library/stdtypes.html#
860
- printf-style-string-formatting>} format specification (C{str}).
861
- @arg args: Arguments to be formatted (any C{type}, all positional).
862
- @kwarg nl_nt_prefix_end_file_flush_sep_kwds: Keyword arguments C{B{nl}=0}
863
- for the number of leading blank lines (C{int}), C{B{nt}=0} the
864
- number of trailing blank lines (C{int}), C{B{prefix}=NN} to
865
- be inserted before the formatted text (C{str}) and Python 3+
866
- C{print} keyword arguments C{B{end}}, C{B{sep}}, C{B{file}} and
867
- C{B{flush}}. Any remaining C{B{kwds}} are U{printf-style
868
- <https://Docs.Python.org/3/library/stdtypes.html#printf-style-string-formatting>}
869
- keyword arguments to be formatted, I{iff no B{C{args}} are present}.
870
802
 
871
- @return: Number of bytes written.
872
- '''
873
- b, e, s, f, fl, p, kwds = _xprint7(**nl_nt_prefix_end_file_flush_sep_kwds)
874
- try:
875
- if args:
876
- t = (fmt % args) if fmt else s.join(map(str, args))
877
- elif kwds: # PYCHOK no cover
878
- t = (fmt % kwds) if fmt else s.join(_pairs(kwds, prec=p))
879
- else: # PYCHOK no cover
880
- t = fmt
881
- except Exception as x:
882
- _E, s = _ALL_MODS.errors._xError2(x)
883
- unstr = _ALL_MODS.streprs.unstr
884
- t = unstr(printf, fmt, *args, **nl_nt_prefix_end_file_flush_sep_kwds)
885
- raise _E(s, txt=t, cause=x)
886
- try:
887
- n = f.write(NN(b, t, e))
888
- except UnicodeEncodeError: # XXX only Windows
889
- t = t.replace('\u2032', _QUOTE1_).replace('\u2033', _QUOTE2_)
890
- n = f.write(NN(b, t, e))
891
- if fl: # PYCHOK no cover
892
- f.flush()
893
- return n
894
-
895
-
896
- def _xprint7(nl=0, nt=0, prec=6, prefix=NN, sep=_SPACE_, file=_sys.stdout,
897
- end=_NL_, flush=False, **kwds):
898
- '''(INTERNAL) Unravel the C{printf} and remaining keyword arguments.
899
- '''
900
- if nl > 0:
901
- prefix = NN(_NL_ * nl, prefix)
902
- if nt > 0:
903
- end = NN(end, _NL_ * nt)
904
- return prefix, end, sep, file, flush, prec, kwds
803
+ # def _lazy_subs(_dunder_name_, force=_FOR_DOCS, over=False):
804
+ # '''(INTERNAL) Return the names of a package's sub-packages and
805
+ # update the package's C{__dict__} accordingly.
806
+ # '''
807
+ # sm = dict()
808
+ # if force and not _dunder_ismain(_dunder_name_):
809
+ # nm = _tailof(_dunder_name_)
810
+ # _a = _ALL_MODS.getattr
811
+ # _m = _ALL_MODS.getmodule
812
+ # d = _a(_dunder_name_, _dunder_dict_, {})
813
+ # for n in _a(_dunder_name_, _dunder_all_, ()):
814
+ # try: # n is a class name, get its mod name
815
+ # m = _a(_dunder_name_, n).__module__
816
+ # n, s = m.split(_DOT_)[-2:]
817
+ # if n == nm and s not in sm:
818
+ # # like import m as s
819
+ # m = _m(m)
820
+ # sm[s] = m if over else d.get(s, m)
821
+ # except (AttributeError, ImportError, ValueError) as x:
822
+ # pass
823
+ # d.update(sm)
824
+ #
825
+ # return _ALL_OTHER(*sm.values())
905
826
 
906
827
 
907
- # del _i, _i0, _intern
828
+ # del _i, _i0
908
829
 
909
- if __name__ == '__main__':
830
+ if _dunder_ismain(__name__): # PYCHOK no cover
910
831
 
911
832
  from timeit import timeit
912
833
 
@@ -921,21 +842,22 @@ if __name__ == '__main__':
921
842
 
922
843
  t1 = timeit(t1, number=1000000)
923
844
  t2 = timeit(t2, number=1000000)
924
- v = _Python_(_sys.version)
925
- printf('%.8f import vs %.8f _ALL_MODS: %.3fX, %s', t1, t2, t2 / t1, v)
926
- del t1, t2, v
845
+ v = _SPACE_.join(_Pythonarchine() + _osversion2())
846
+ printf('%.6f import vs %.6f _ALL_MODS: %.2fX, %s', t1, t2, t1 / t2, v)
847
+
848
+ # del t1, t2, timeit, v
927
849
 
928
- # python3.12 -m pygeodesy.lazily
929
- # 0.13352763 import vs 0.70804508 _ALL_MODS: 5.303X, Python 3.12.0
850
+ # python3.12 -W ignore -m pygeodesy.lazily
851
+ # 0.145177 import vs 0.075402 _ALL_MODS: 1.93X, Python 3.12.3 64bit arm64 macOS 14.4.1
930
852
 
931
- # % python3.11 -W ignore -m pygeodesy.lazily
932
- # 0.37998008 import vs 0.79537812 _ALL_MODS: 2.093X, Python 3.11.5
853
+ # python3.11 -W ignore -m pygeodesy.lazily
854
+ # 0.381723 import vs 0.251589 _ALL_MODS: 1.52X, Python 3.11.5 64bit arm64 macOS 14.4.1
933
855
 
934
- # % python3.10 -W ignore -m pygeodesy.lazily
935
- # 0.39046367 import vs 0.90492925 _ALL_MODS: 2.318X, Python 3.10.8
856
+ # python3.10 -W ignore -m pygeodesy.lazily
857
+ # 0.378293 import vs 0.266507 _ALL_MODS: 1.42X, Python 3.10.8 64bit arm64 macOS 14.4.1
936
858
 
937
- # % python2 -m pygeodesy.lazily
938
- # 1.17563510 import vs 2.02626395 _ALL_MODS: 1.724X, Python 2.7.18
859
+ # python2 -m pygeodesy.lazily
860
+ # 1.213805 import vs 0.474075 _ALL_MODS: 2.56X, Python 2.7.18 64bit arm64_x86_64 macOS 10.16
939
861
 
940
862
  # **) MIT License
941
863
  #