Coverage for pygeodesy / lazily.py: 96%

216 statements  

« prev     ^ index     » next       coverage.py v7.14.0, created at 2026-10-21 16:43 -0400

1 

2# -*- coding: utf-8 -*- 

3 

4u'''Lazily import C{pygeodesy} modules and attributes, based on 

5U{lazy_import<https://modutil.ReadTheDocs.io/en/latest/#lazy_import>} 

6from I{Brett Cannon}'s U{modutil<https://PyPI.org/project/modutil>}. 

7 

8C{Lazy import} is I{supported only for }U{Python 3.7+ 

9<https://Snarky.Ca/lazy-importing-in-python-3-7>} and is I{enabled by 

10default} in U{PyGeodesy 18.11.10<https://PyPI.org/project/PyGeodesy>} 

11I{and newer}. 

12 

13To I{enable} C{lazy import}, set C{env} variable C{PYGEODESY_LAZY_IMPORT} 

14to C{1}, C{2}, C{3} or higher prior to C{import pygeodesy}. To I{disable} 

15C{lazy import}, set C{env} variable C{PYGEODESY_LAZY_IMPORT} to C{0} or 

16an empty string. Use C{2} or higher to print a message for each lazily 

17imported module and attribute, similar to C{env} variable C{PYTHONVERBOSE} 

18showing imports. Using C{3} or higher also shows the importing file name 

19and line number. 

20 

21@note: C{Lazy import} applies only to top-level modules of C{pygeodesy}. 

22 The C{lazy import} of a top-level module invariably loads all 

23 sub-modules imported by that top-level module. 

24 

25@note: C{Lazy import} raises a L{LazyAttributeError} or L{LazyImportError} 

26 depending on the cause of the error and such errors can occur late, 

27 after all initial imports. 

28''' 

29 

30from pygeodesy import internals as _internals, interns as _interns, \ 

31 _isfrozen # DON'T _lazy_import2 

32# from pygeodesy.errors import _error_init, _ImmutableError, _xkwds_get, _xkwds_item2 # _ALL_MODS 

33from pygeodesy.internals import _caller3, _envPYGEODESY, _headof, printf, _Property_RO, \ 

34 _tailof, typename, _versions # _getenv, _PYGEODESY_ENV, \ 

35# _MODS_Base, _MODS.sys_version_info2 

36from pygeodesy.interns import _attribute_, _by_, _COLONSPACE_, _COMMASPACE_, _DALL_, \ 

37 _DMAIN_, _doesn_t_exist_, _DOT_, _EQUALSPACED_, _from_, \ 

38 _HASH_, _line_, _module_, NN, _no_, _not_, _pygeodesy_, \ 

39 _pygeodesy_abspath_, _SPACE_, _SUB_PACKAGES, _or_, \ 

40 _UNDER_, _version_, _sys, _intern # function, _1_ 

41try: 

42 from importlib import import_module # in .rdnap._v_grid 

43except ImportError as x: # Python 2.6- 

44 raise ImportError(_COLONSPACE_(x, _versions())) 

45# import sys as _sys # from .interns 

46 

47_a0 = () # PYCHOK empty tuple 

48_asSPACED_ = ' as ' 

49_FOR_DOCS = _envPYGEODESY('FOR_DOCS') # for epydoc ... 

50_imported_ = 'imported' 

51_init__all__ = _FOR_DOCS or _envPYGEODESY('_init__all__', _DALL_) == _DALL_ # PYCHOK exported 

52_lazily_ = 'lazily' 

53_PYTHON_X_DEV = getattr(_sys.flags, 'dev_mode', False) # PYCHOK Python 3.2+ 

54_unlazy = _unLazy0 = _isfrozen or _internals._MODS.sys_version_info2 < (3, 7) # PYCHOK mod.__getattr__ 3.7+ 

55_WARNINGS_X_DEV = _envPYGEODESY('WARNINGS') and (_PYTHON_X_DEV or bool(_sys.warnoptions)) # PYCHOK .props 

56 

57# @module_property[_RO?] <https://GitHub.com/jtushman/proxy_tools/> <https://discuss.Python.org/t/47379> 

58isLazy = None # see @var isLazy in .__init__ 

59 

60 

61class LazyAttributeError(AttributeError): 

62 '''Raised if a C{lazily imported} attribute is missing or invalid. 

63 ''' 

64 def __init__(self, *args, **kwds): 

65 _ALL_MODS.errors._error_init(AttributeError, self, args, **kwds) 

66 

67 

68class LazyImportError(ImportError): 

69 '''Raised if C{lazy import} is not supported, disabled or failed. 

70 ''' 

71 def __init__(self, *args, **kwds): 

72 _ALL_MODS.errors._error_init(ImportError, self, args, **kwds) 

73 

74 

75class _Dict(dict): 

76 '''(INTERNAL) Imports C{dict}. 

77 ''' 

78 _name = NN 

79 

80 def __getattr__(self, attr): 

81 try: 

82 return self[attr] 

83 except KeyError: 

84 return dict.__getattr__(self, attr) # PYLINT E1101 

85 

86# def __setattr__(self, attr, value): 

87# if attr in self: 

88# self[attr] = value 

89# else: 

90# dict.__setattr__(self, attr, value) 

91 

92 def add(self, name, mod_, *subs): 

93 '''Add a C{[name] = mod_} item. 

94 

95 @raise AssertionError: The B{C{name}} already exists 

96 with a different B{C{mod_}}. 

97 ''' 

98 try: 

99 sub = self[name] # duplicate OK 

100 if sub != mod_ and sub not in subs: 

101 t = _DOT_(self._name, name) 

102 t = _COLONSPACE_(t, repr(sub)) 

103 t = _COMMASPACE_(t, _not_(repr(mod_))) 

104 raise AssertionError(t) 

105 except KeyError: 

106 self[name] = mod_ 

107 

108 def _NAME(self, which): 

109 self._name = _intern(typename(which).upper()) 

110 

111 

112class _NamedEnum_RO(dict): 

113 '''(INTERNAL) C{Read_Only} enum-like C{dict} sub-class. 

114 ''' 

115# _name = NN # also first kwd, __init__(_name=...) 

116 

117 def _DOT_(self, attr): # PYCHOK no cover 

118 return _DOT_(self._name, attr) # PYCHOK _name 

119 

120 def __getattr__(self, attr): 

121 try: 

122 return self[attr] 

123 except KeyError: 

124 t = self._DOT_(attr) 

125 raise LazyAttributeError(t, txt=_doesn_t_exist_) 

126 

127 def __setattr__(self, attr, value): # PYCHOK no cover 

128 e = _ALL_MODS.errors 

129 raise e._ImmutableError(self, attr, value, 

130 Error=LazyAttributeError) 

131 

132 def enums(self): 

133 # Yield all C{(mod_, tuple)} pairs 

134 for m, t in dict.items(self): 

135 n = m.replace(_UNDER_, _DOT_) 

136 if n != m: 

137 if m.startswith(_UNDER_): 

138 continue # skip _name= ... 

139 u = m.rstrip(_UNDER_) 

140 if u != m: 

141 u = len(u) 

142 n = n[:u] + m[u:] 

143 yield n, t 

144 

145 def fill_D(self, _D, which): 

146 # Fill C{_Dict _D}. 

147 _D._NAME(which) 

148 _a = _D.add 

149 for m, t in self.enums(): 

150 _a(m, _DOT_(m, NN, NN)) # import module 

151 for a in t: 

152 a, _, as_ = a.partition(_asSPACED_) 

153 if as_: # import attr as attr_ 

154 _a(as_, _DOT_(m, a, NN), *_SUB_PACKAGES) 

155 else: 

156 _a(a, m) 

157 return _D 

158 

159 

160def _a(*names): 

161 '''(INTERNAL) Intern all C{names}. 

162 ''' 

163 return tuple(map(_intern, names)) if names else _a0 

164 

165 

166def _ALL_ATTRS(*attrs): 

167 '''(INTERNAL) Unravel all exported module attributes. 

168 ''' 

169 t = () 

170 for attr in attrs: 

171 t += tuple(map(_getattras, attr)) 

172 return t 

173 

174 

175_ALL_INIT = _a(_pygeodesy_abspath_, _version_) 

176 

177# __all__ value for most modules, accessible as _ALL_LAZY.<module> 

178_ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY', 

179 albers=_a('AlbersEqualArea', 'AlbersEqualArea2', 'AlbersEqualArea4', 

180 'AlbersEqualAreaCylindrical', 'AlbersEqualAreaNorth', 'AlbersEqualAreaSouth', 

181 'AlbersError', 'Albers7Tuple'), 

182 angles=_a('Ang', 'Deg', 'Lambertian', 'Rad', 'isAng'), 

183 auxilats=_a(), # package only 

184 azimuthal=_a('AzimuthalError', 'Azimuthal7Tuple', 

185 'Equidistant', 'EquidistantExact', 'EquidistantGeodSolve', 'EquidistantKarney', 

186 'Gnomonic', 'GnomonicExact', 'GnomonicGeodSolve', 'GnomonicKarney', 

187 'LambertEqualArea', 'Orthographic', 'Stereographic', 

188 'equidistant', 'gnomonic'), 

189 basics=_a('clips', 'copysign0', 'copytype', 'halfs2', 

190 'int1s', 'isbool', 'isCartesian', 'isclass', 'iscomplex', 'isDEPRECATED', 'isfloat', 

191 'isidentifier', 'isinstanceof', 'isint', 'isiterable', 'isiterablen', 'isiterabletype', 

192 'iskeyword', 'isLatLon', 'islistuple', 'isNvector', 'isodd', 

193 'isscalar', 'issequence', 'isstr', 'issubclassof', 'itemsorted', 

194 'len2', 'map1', 'map2', 'max2', 'min2', 'neg', 'neg_', 

195 'signBit', 'signOf', 'splice', 'str2ub', 'ub2str', 'unsigned0'), 

196 booleans=_a('BooleanFHP', 'BooleanGH', 'LatLonFHP', 'LatLonGH', 

197 'isBoolean'), 

198 cartesianBase=_a('RadiusThetaPhi3Tuple', 'rtp2xyz', 'rtp2xyz_', 'xyz2rtp', 'xyz2rtp_'), 

199 clipy=_a('ClipCS4Tuple', 'ClipFHP4Tuple', 'ClipGH4Tuple', 'ClipLB6Tuple', 'ClipSH3Tuple', 

200 'clipCS4', 'clipFHP4', 'clipGH4', 'clipLB6', 'clipSH', 'clipSH3'), 

201 css=_a('CassiniSoldner', 'Css', 'CSSError', 'toCss', 

202 'EasNorAziRk4Tuple', 'EasNorAziRkEqu6Tuple', 'LatLonAziRk4Tuple'), 

203 constants=_a('DIG', 'EPS', 'EPS0', 'EPS02', 'EPS1', 'EPS2', 'EPS4', 'EPS8', 'EPS_2', 

204 'INF', 'INT0', 'MANT_DIG', 'MAX', 'MAX_EXP', 'MIN', 'MIN_EXP', 'NAN', 'NEG0', 'NINF', 

205 'OVERFLOW', 'PI', 'PI2', 'PI_2', 'PI3', 'PI_3', 'PI3_2', 'PI4', 'PI_4', 'PI_6', 

206 'R_FM', 'R_GM', 'R_KM', 'R_M', 'R_MA', 'R_MB', 'R_NM', 'R_QM', 'R_SM', 'R_VM', 

207 'float_', 'float0_', 'floats_', 'isclose', 'isfinite', 'isinf', 'isint0', 

208 'isnan', 'isnear0', 'isnear1', 'isnear90', 'isneg', 'isneg0', 'isninf', 'isnon0', 

209 'remainder'), 

210 datums=_a('Datum', 'Datums', 'Similarity', 'Transform', 'Transforms'), 

211# deprecated=_a(), # module only 

212 dms=_a('F_D', 'F_DM', 'F_DMS', 'F_DEG', 'F_MIN', 'F_SEC', 'F_D60', 'F__E', 'F__F', 'F__G', 'F_RAD', 

213 'F_D_', 'F_DM_', 'F_DMS_', 'F_DEG_', 'F_MIN_', 'F_SEC_', 'F_D60_', 'F__E_', 'F__F_', 'F__G_', 'F_RAD_', 

214 'F_D__', 'F_DM__', 'F_DMS__', 'F_DEG__', 'F_MIN__', 'F_SEC__', 'F_D60__', 'F__E__', 'F__F__', 'F__G__', 'F_RAD__', 

215 'S_DEG', 'S_MIN', 'S_SEC', 'S_DMS', 'S_RAD', 'S_SEP', 

216 'bearingDMS', 'clipDegrees', 'clipRadians', 'compassDMS', 'compassPoint', 

217 'degDMS', 'latDMS', 'latlonDMS', 'latlonDMS_', 'lonDMS', 'normDMS', 

218 'parseDDDMMSS', 'parseDMS', 'parseDMS2', 'parse3llh', 'parseRad', 'precision', 'toDMS'), 

219 ecef=_a('EcefFarrell21', 'EcefFarrell22', 'EcefFukushima', 'EcefKarney', 'EcefOlson', 'EcefOsen', 

220 'EcefSudano', 'EcefUPC', 'EcefVeness', 'EcefYou', 'EcefError', 'EcefMatrix', 'Ecef9Tuple'), 

221 ecefLocals=_a(), # module only 

222 elevations=_a('Elevation2Tuple', 'GeoidHeight2Tuple', 

223 'elevation2', 'geoidHeight2'), 

224 ellipses=_a('Ellipse', 'EllipseError'), 

225 ellipsoidalBase=_a(), # module only 

226 ellipsoidalBaseDI=_a(), # module only 

227 ellipsoidalExact=_a(), # module only 

228 ellipsoidalGeodSolve=_a(), # module only 

229 ellipsoidalKarney=_a(), # module only 

230 ellipsoidalNvector=_a(), # module only 

231 ellipsoidalVincenty=_a('VincentyError',), # nothing else 

232 ellipsoids=_a('a_f2Tuple', 'Curvature2Tuple', 

233 'Ellipsoid', 'Ellipsoid2', 'Ellipsoids', 

234 'a_b2e', 'a_b2e2', 'a_b2e22', 'a_b2e32', 'a_b2f', 'a_b2f_', 'a_b2f2', 'a_b2n', 

235 'a_f2b', 'a_f_2b', 'b_f2a', 'b_f_2a', 

236 'e2f', 'e22f', 

237 'f2e2', 'f2e22', 'f2e32', 'f_2f', 'f2f_', 'f2f2', 'f2n', 'n2e2', 'n2f', 'n2f_'), 

238 elliptic=_a('Elliptic', 'EllipticError', 'Elliptic3Tuple'), 

239 epsg=_a('Epsg', 'EPSGError'), 

240 errors=_a('AuxError', 'ClipError', 'CrossError', 'GeodesicError', 'IntersectionError', 

241 'NumPyError', 'LenError', 'LimitError', 'MGRSError', 

242 'ParseError', 'PointsError', 'RangeError', 'RhumbError', 

243 'SciPyError', 'SciPyWarning', 'TRFError', 'TriangleError', 'UnitError', 'VectorError', 

244 'crosserrors', 'exception_chaining', 'isError', 'limiterrors', 'rangerrors'), 

245 etm=_a('Etm', 'ETMError', 'ExactTransverseMercator', 

246 'parseETM5', 'toEtm8'), 

247 fmath=_a('Fdot', 'Fdot_', 'Fhorner', 'Fhypot', 'Fpolynomial', 'Fpowers', 'Fcbrt', 'Froot', 'Fsqrt', 

248 'bqrt', 'cbrt', 'cbrt2', 'euclid', 'euclid_', 

249 'facos1', 'fasin1', 'fatan', 'fatan1', 'fatan2', 'favg', 

250 'fdot', 'fdot_', 'fdot3', 'fma', 'fmean', 'fmean_', 'fhorner', 'fidw', 'f2mul_', 

251 'fpolynomial', 'fpowers', 'fprod', 'frandoms', 'frange', 'freduce', 'fremainder', 

252 'hypot', 'hypot_', 'hypot1', 'hypot2', 'hypot2_', 

253 'norm2', 'norm_', 'polar2', 'polar2d', 

254 'sqrt0', 'sqrt3', 'sqrt_a', 'zcrt', 'zqrt'), 

255 formy=_a('Radical2Tuple', 

256 'angle2chord', 'antipode', 'antipode_', 'bearing', 'bearing_', 

257 'chord2angle', 'compassAngle', 'cosineLaw', 'cosineLaw_', 

258 'equirectangular', 'equirectangular4', 'euclidean', 'euclidean_', 

259 'excessAbc_', 'excessCagnoli_', 'excessGirard_', 'excessLHuilier_', 

260 'excessKarney', 'excessKarney_', 'excessQuad', 'excessQuad_', 

261 'flatLocal', 'flatLocal_', 'flatPolar', 'flatPolar_', 

262 'hartzell', 'haversine', 'haversine_', 'heightOf', 'heightOrthometric', 'horizon', 'hubeny', 'hubeny_', 

263 'intersection2', 'intersections2', 'isantipode', 'isantipode_', 'isnormal', 'isnormal_', 

264 'normal', 'normal_', 'opposing', 'opposing_', 'radical2', 

265 'thomas', 'thomas_', 'vincentys', 'vincentys_'), 

266 frechet=_a('Frechet', 'FrechetDegrees', 'FrechetError', 'FrechetRadians', 'FrechetCosineLaw', 

267 'FrechetDistanceTo', 'FrechetEquirectangular', 'FrechetEuclidean', 'FrechetExact', 

268 'FrechetFlatLocal', 'FrechetFlatPolar', 'FrechetHaversine', 'FrechetHubeny', 'FrechetKarney', 

269 'FrechetThomas', 'FrechetVincentys', 'Frechet6Tuple', 

270 'frechet_'), 

271 fstats=_a('Fcook', 'Flinear', 'Fwelford'), 

272 fsums=_a('Fsum', 'DivMod2Tuple', 'Fsum2Tuple', 'ResidualError', 

273 'f2product', 'fsum', 'fsum_', 'fsumf_', 'fsum1', 'fsum1_', 'fsum1f_', 'nonfiniterrors'), 

274 gars=_a('Garef', 'GARSError'), 

275 geodesici=_a('Intersectool', 'Intersectool5Tuple', 'Intersect7Tuple', 

276 'Intersector', 'Intersector5Tuple', 'Middle5Tuple', 'XDict'), 

277 geodesicw=_a('Geodesic', 'GeodesicLine', 'Geodesic_WGS84'), 

278 geodesicx=_a('gx', 'gxarea', 'gxbases', 'gxline', # modules 

279 'GeodesicAreaExact', 'GeodesicExact', 'GeodesicLineExact', 'PolygonArea'), 

280 geodsolve=_a('GeodesicSolve', 'GeodesicLineSolve', 'GeodSolve12Tuple'), 

281 geod3solve=_a('Geodesic3Solve', 'GeodesicLine3Solve', 'Geod3Solve8Tuple', 'Geodesic3Error'), 

282 geohash=_a('Geohash', 'Geohashed', 'GeohashError', 'Neighbors8Dict', 'Resolutions2Tuple', 'Sizes3Tuple'), 

283 geoids=_a('GeoidEGM96', 'GeoidG2012B', 'GeoidKarney', 'GeoidPGM', 'GeoidQuasi', 

284 'GeoidError', 'GeoidHeight5Tuple', 'PGMError', 'egmGeoidHeights'), 

285 hausdorff=_a('Hausdorff', 'HausdorffDegrees', 'HausdorffError', 'HausdorffRadians', 'HausdorffCosineLaw', 

286 'HausdorffDistanceTo', 'HausdorffEquirectangular', 'HausdorffEuclidean', 'HausdorffExact', 

287 'HausdorffFlatLocal', 'HausdorffFlatPolar', 'HausdorffHaversine', 'HausdorffHubeny', 

288 'HausdorffKarney', 'HausdorffThomas', 'HausdorffVincentys', 'Hausdorff6Tuple', 

289 'hausdorff_', 'randomrangenerator'), 

290 heights=_a('HeightCubic', 'HeightError', 'HeightIDWcosineLaw', 'HeightIDWdistanceTo', 

291 'HeightIDWequirectangular', 'HeightIDWeuclidean', 'HeightIDWexact', 'HeightIDWflatLocal', 

292 'HeightIDWflatPolar', 'HeightIDWhaversine', 'HeightIDWhubeny', 'HeightIDWkarney', 'HeightIDWthomas', 

293 'HeightIDWvincentys', 'HeightLinear', 'HeightLSQBiSpline', 'HeightSmoothBiSpline'), 

294 hom=_a('HotineError', 'HotineOblique1', 'HotineOblique2', 'HotineOblique3', 

295 'HotineObliqueA', 'HotineObliqueB', 'Hotine8Tuple', 'HotineAB14Tuple'), 

296 internals=_internals.__all__, 

297 interns=_interns.__all__, 

298 iters=_a('LatLon2PsxyIter', 'PointsIter', 'points2', 

299 'isNumpy2', 'isPoints2', 'isTuple2', 'iterNumpy2', 'iterNumpy2over'), 

300 karney=_a('Area3Tuple', 'Caps', 'Direct9Tuple', 'GDict', 'Inverse10Tuple'), 

301 ktm=_a('KTMError', 'KTransverseMercator'), 

302 latlonBase=_a('latlon2n_xyz', 'philam2n_xyz'), 

303 lazily=_a('LazyAttributeError', 'LazyImportError', 'isLazy'), 

304 lcc=_a('Conic', 'Conics', 'Lcc', 'LCCError', 'toLcc'), 

305 lom=_a('LabordeError', 'LabordeOblique', 'Laborde8Tuple'), 

306 ltp=_a('Attitude', 'AttitudeError', 'Frustum', 

307 'LocalCartesian', 'LocalError', 'Ltp', 'LqRD', 'tyr3d'), 

308 ltpTuples=_a('Aer', 'Aer4Tuple', 'Attitude4Tuple', 

309 'Enu', 'Enu4Tuple', 'Footprint5Tuple', 'Local9Tuple', 'Los', 

310 'Ned', 'Ned4Tuple', 'Uvw', 'Uvw3Tuple', 'XyzLocal', 'Xyz4Tuple'), 

311 mgrs=_a('Mgrs', 'parseMGRS', 'toMgrs', 'Mgrs4Tuple', 'Mgrs6Tuple'), 

312 named=_a('ADict', 

313 'callername', 'classname', 'classnaming', 'modulename', 

314 'nameof', 'notImplemented', 'notOverloaded'), 

315 namedTuples=_a('Bearing2Tuple', 'Bounds2Tuple', 'Bounds4Tuple', 

316 'Circle4Tuple', 'Destination2Tuple', 'Destination3Tuple', 

317 'Distance2Tuple', 'Distance3Tuple', 'Distance4Tuple', 

318 'EasNor2Tuple', 'EasNor3Tuple', 'Ellipse5Tuple', 

319 'Forward4Tuple', 'Intersection3Tuple', 

320 'LatLon2Tuple', 'LatLon3Tuple', 'LatLon4Tuple', 

321 'LatLonDatum3Tuple', 'LatLonDatum5Tuple', 'LatLonHeight3Tuple', 'LatLonNgeoid3Tuple', 

322 'LatLonPrec3Tuple', 'LatLonPrec5Tuple', 

323 'NearestOn2Tuple', 'NearestOn3Tuple', 'NearestOn6Tuple', 'NearestOn8Tuple', 

324 'PhiLam2Tuple', 'PhiLam3Tuple', 'PhiLam4Tuple', 'PhiLamHeight3Tuple', 'PhiLamNgeoid3Tuple', 

325 'Point3Tuple', 'Points2Tuple', 

326 'RD4Tuple', 'Reverse4Tuple', 'Triangle7Tuple', 'Triangle8Tuple', 'Trilaterate5Tuple', 

327 'UtmUps2Tuple', 'UtmUps5Tuple', 'UtmUps8Tuple', 'UtmUpsLatLon5Tuple', 

328 'Vector2Tuple', 'Vector3Tuple', 'Vector4Tuple'), 

329 nvectorBase=_a('NorthPole', 'SouthPole', 'n_xyz2latlon', 'n_xyz2philam'), 

330 osgr=_a('Osgr', 'OSGRError', 'parseOSGR', 'toOsgr'), 

331 points=_a('LatLon_', 'LatLon2psxy', 'Numpy2LatLon', 'Shape2Tuple', 'Tuple2LatLon', 

332 'areaOf', 'boundsOf', 'centroidOf', 'fractional', 

333 'isclockwise', 'isconvex', 'isconvex_', 'isenclosedBy', 'ispolar', 

334 'luneOf', 'nearestOn5', 'perimeterOf', 'quadOf'), 

335 props=_a('Property', 'Property_RO', 'property_doc_', 

336 'property_RO', 'property_ROnce', 'property_ROver', 

337 'deprecated_class', 'deprecated_function', 'deprecated_method', 

338 'deprecated_Property_RO', 'deprecated_property_RO', 'DeprecationWarnings'), 

339 resections=_a('Collins5Tuple', 'ResectionError', 'Survey3Tuple', 'Tienstra7Tuple', 

340 'TriAngle5Tuple', 'TriSide2Tuple', 'TriSide4Tuple', 

341 'cassini', 'collins5', 'pierlot', 'pierlotx', 'tienstra7', 

342 'snellius3', 'wildberger3', 

343 'triAngle', 'triAngle5', 'triArea', 'triSide', 'triSide2', 'triSide4'), 

344 rhumb=_a(), # package only 

345 rhumb_aux_=_a('RhumbAux', 'RhumbLineAux'), 

346 rhumb_ekx=_a('Rhumb', 'RhumbLine'), 

347 rhumb_solve=_a('RhumbSolve', 'RhumbLineSolve', 'RhumbSolve7Tuple', 'Rhumb8Tuple'), # in .karney 

348 sphericalBase=_a(), # module only 

349 sphericalNvector=_a(), # module only 

350 sphericalTrigonometry=_a(), # module only 

351 simplify=_a('simplify1', 'simplifyRDP', 'simplifyRW', 'simplifyVW'), 

352 solveBase=_a(), # module only 

353 streprs=_a('anstr', 'attrs', 'enstr2', 'fstr', 'fstrzs', 'hstr', 'instr', 

354 'lrstrip', 'pairs', 'reprs', 'strs', 'unstr'), 

355 trf=_a('RefFrame', 'RefFrames', 'TransformXform', 'TRFXform', 'TRFXform7Tuple', 

356 'date2epoch', 'epoch2date', 'trfTransform0', 'trfTransforms', 'trfXform'), 

357 triaxials=_a(), # package only 

358 triaxials_bases=_a('LLK', 'TriaxialError'), 

359 triaxials_conformal3=_a('BetOmgGam5Tuple', 

360 'Conformal3', 'Conformal3B', 'Conformal3Sphere', 'Conformal5Tuple'), 

361 triaxials_triaxial3=_a('BetOmgAlp5Tuple', 'Cartesian5Tuple', 'LatLonAzi5Tuple', 'PhiLamZet5Tuple', 

362 'Triaxial3', 'Triaxial3B', 'Triaxial3s'), 

363 triaxials_triaxial5=_a('BetaOmega2Tuple', 'BetaOmega3Tuple', 

364 'Conformal', 'ConformalSphere', 'Conformal2Tuple', 

365 'Triaxial', 'Triaxial_', 'Triaxials', 'hartzell4', 'height4'), 

366 units=_a('Azimuth', 'Band', 'Bearing', 'Bearing_', 'Bool', 

367 'Degrees', 'Degrees_', 'Degrees2', 'Distance', 'Distance_', 'Easting', 'Epoch', 

368 'Feet', 'FIx', 'Float_', 'Height', 'Height_', 'HeightX', 'Int_', 

369 'Lam', 'Lamd', 'Lat', 'Lat_', 'Lon', 'Lon_', 

370 'Meter', 'Meter_', 'Meter2', 'Meter3', 'Northing', 'Number_', 

371 'Phi', 'Phid', 'Precision_', 'Radians', 'Radians_', 'Radians2', 

372 'Radius_', 'Scalar', 'Scalar_', 'Zone'), 

373 unitsBase=_a('Float', 'Int', 'Radius', 'Str'), 

374 ups=_a('Ups', 'UPSError', 'parseUPS5', 'toUps8', 'upsZoneBand5'), 

375 utily=_a('acos1', 'acre2ha', 'acre2m2', 'agdf', 'asin1', 

376 'atan1', 'atan1d', 'atan2', 'atan2b', 'atan2d', 'atan2p', 

377 'chain2m', 'circle4', 'cot', 'cot_', 'cotd', 'cotd_', 

378 'degrees', 'degrees90', 'degrees180', 'degrees360', 'degrees2grades', 'degrees2m', 

379 'fathom2m', 'ft2m', 'furlong2m', # 'degrees2grades as degrees2gons', 

380 'gdf', 'grades', 'grades400', 'grades2degrees', 'grades2radians', 

381# 'grades as gons', 'grades400 as gons400', 'grades2degrees as gons2degrees', 'grades2radians as gons2radians', 

382 'ha2acre', 'ha2m2', 'hav', 'km2m', 

383 'm2acre', 'm2chain', 'm2degrees', 'm2fathom', 'm2ft', 'm2furlong', 

384 'm2ha', 'm2km', 'm2NM', 'm2radians', 'm2SM', 'm2toise', 'm2yard', 

385 'NM2m', 'radians', 'radiansPI', 'radiansPI2', 'radiansPI_2', 'radians2m', 

386 'sincos2', 'SinCos2', 'sincos2_', 'sincos2d', 'sincos2d_', 'sincostan3', 'sincostan3d', 'SM2m', 

387 'tan', 'tan_', 'tand', 'tand_', 'tan_2', 'tanPI_2_2', 'toise2m', 'truncate', 

388 'unroll180', 'unrollPI', 

389 'wrap90', 'wrap180', 'wrap360', 'wrapPI_2', 'wrapPI', 'wrapPI2', 'wrap_normal', 

390 'yard2m'), 

391 utm=_a('Utm', 'UTMError', 'parseUTM5', 'toUtm8', 'utmZoneBand5'), 

392 utmups=_a('UtmUps', 'UTMUPSError', 'parseUTMUPS5', 'toUtmUps8', 

393 'utmupsValidate', 'utmupsValidateOK', 'utmupsZoneBand5'), 

394 utmupsBase=_a(), # module only 

395 vector2d=_a('Circin6Tuple', 'Circum3Tuple', 'Circum4Tuple', 'Meeus2Tuple', 'Radii11Tuple', 'Soddy4Tuple', 'Triaxum5Tuple', 

396 'circin6', 'circum3', 'circum4', 'circum4_', 'meeus2', 'radii11', 'soddy4', 'triaxum5', 'trilaterate2d2'), 

397 vector3d=_a('Vector3d', 'intersection3d3', 'iscolinearWith', 'nearestOn', 'nearestOn6', 'parse3d', 

398 'trilaterate3d2'), 

399 vector3dBase=_a(), # module only 

400 webmercator=_a('Wm', 'WebMercatorError', 'parseWM', 'toWm', 'EasNorRadius3Tuple'), 

401 wgrs=_a('Georef', 'WGRSError'),) 

402 

403_ALL_DEPRECATED = _NamedEnum_RO(_name='_ALL_DEPRECATED', 

404 deprecated=_a('bases', 'datum', 'nvector', # DEPRECATED modules and ... 

405 'rhumbaux', 'rhumbBase', 'rhumbsolve', 'rhumbx'), # ... names 

406 deprecated_bases=_a('LatLonHeightBase', 'points2'), 

407 deprecated_classes=_a('ChLV', 'ChLVa', 'ChLVe', 'ChLVEN2Tuple', 'ChLV9Tuple', 'ChLVYX2Tuple', 'ChLVyx2Tuple', 

408 'ClipCS3Tuple', 'EasNorExact4Tuple', 'EcefCartesian', 'Fn_rt', 

409 'FrechetCosineAndoyerLambert', 'FrechetCosineForsytheAndoyerLambert', 

410 'HausdorffCosineAndoyerLambert', 'HausdorffCosineForsytheAndoyerLambert', 

411 'HeightIDW', 'HeightIDW2', 'HeightIDW3', 'HeightIDWcosineAndoyerLambert', 

412 'HeightIDWcosineForsytheAndoyerLambert', 'Helmert7Tuple', 

413 'JacobiConformal', 'JacobiConformalSpherical', 'Jacobi2Tuple', 

414 'Lam_', 'LatLonExact4Tuple', 'NearestOn4Tuple', 'Ned3Tuple', 

415 'Phi_', 'RefFrameError', 'Rhumb7Tuple', 'RhumbOrder2Tuple', 

416 'Transform7Tuple', 'TriAngle4Tuple', 'UtmUps4Tuple', 'XDist'), 

417 deprecated_consterns=_a('Elliperim', 'EPS1_2', 'MANTIS', 'OK'), 

418 deprecated_datum=_a('Curvature2Tuple', 'Datum', 'Ellipsoid', 'Transform', # assert 

419 'Datums', 'Ellipsoids', 'Transforms', 

420 'R_FM', 'R_KM', 'R_M', 'R_MA', 'R_MB', 'R_NM', 'R_SM', 'R_VM'), 

421 deprecated_functions=_a('anStr', 'areaof', 'atand', 'bounds', # most of the DEPRECATED functions, except ellipsoidal ... 

422 'clipCS3', 'clipDMS', 'clipStr', 'collins', 'copysign', # ... and spherical flavors 

423 'cosineAndoyerLambert', 'cosineAndoyerLambert_', 

424 'cosineForsytheAndoyerLambert', 'cosineForsytheAndoyerLambert_', 

425 'decodeEPSG2', 

426 'elliperim', 'elliperim_', 'encodeEPSG', 'enStr2', 'equirectangular_', 'equirectangular3', 

427 'excessAbc', 'excessGirard', 'excessLHuilier', 

428 'false2f', 'falsed2f', 'float0', 'fStr', 'fStrzs', 'Fsum2product', 

429 'hypot3', 'inStr', 'isenclosedby', 'istuplist', 

430 'joined', 'joined_', 'nearestOn3', 'nearestOn4', 

431 'parseUTM', 'perimeterof', 'polygon', 

432 'scalar', 'simplify2', 'simplifyRDPm', 'simplifyVWm', 

433 'tienstra', 'toUtm', 'triAngle4', 

434 'unsign0', 'unStr', 'utmZoneBand2'), 

435 deprecated_nvector=_a('LatLonNvectorBase', 'Nvector', 'sumOf', 'NorthPole', 'SouthPole'),) 

436 

437 

438class _ALL_MODS(_internals._MODS_Base): 

439 '''(INTERNAL) Memoized import of any L{pygeodesy} module. 

440 ''' 

441 def __getattr__(self, name): 

442 '''Get a C{pygeodesy} module or attribute by B{C{name}}. 

443 

444 @arg name: Un/qualified module or qualified attribute name (C{str}). 

445 

446 @raise ImportError: Importing module B{C{name}} failed. 

447 

448 @raise AttributeError: No attribute named B{C{name}}. 

449 ''' 

450 try: 

451 v = _lazy_dict[name] # package.__dict__ 

452 except KeyError: 

453 v = _lazy_module(name) # package.__getattr__ 

454 if _tailof(typename(v)) != name: 

455 try: 

456 v = getattr(v, _tailof(name)) 

457 except AttributeError: 

458 pass # XXX LazyAttributeError? 

459 return v 

460 

461 def getattr(self, name, *attr_dflt): # , parent=_pygeodesy_ 

462 '''Get an attribute of/or a C{pygeodesy} module. 

463 

464 @arg name: Un/qualified module name (C{str}). 

465 @arg attr_dflt: Optional attribute name (C{str}) and 

466 optional default value (any C{type}). 

467 

468 @return: The C{pygeodesy} module's attribute value. 

469 

470 @raise ImportError: Importing module B{C{name}} failed. 

471 

472 @raise AttributeError: No attribute named B{C{attr}}. 

473 ''' 

474 v = self.getmodule(name) 

475 if attr_dflt: 

476 v = getattr(v, *attr_dflt) 

477 return v 

478 

479 def getmodule(self, name, parent=_pygeodesy_): 

480 '''Get a C{pygeodesy} module or the C{__main__}. 

481 

482 @arg name: Un/qualified module name (C{str}). 

483 

484 @return: The C{pygeodesy} module. 

485 

486 @raise ImportError: Importing module B{C{name}} failed. 

487 ''' 

488 if _headof(name) != parent and name != _DMAIN_: 

489 name = _DOT_(parent, name) 

490 try: 

491 return _sys.modules[name] 

492 except KeyError: 

493 return _getmodule(name, parent) 

494 

495 def imported(self, name): 

496 '''Return module or package C{name} if already imported. 

497 ''' 

498 return _sys.modules.get(name, None) 

499 

500 def into(self, **mod_DNAME): 

501 '''Deferred import of module C{mod} into module C{_DNAME_} 

502 and overwrite C{_DNAME_._mod} to module C{mod}, I{once} 

503 at the first access of an attribute of module C{mod}. 

504 ''' 

505 # assert len(mod_DNAME) == 1 

506 # mod, dun = mod_DNAME.popitem() 

507 

508 class _Into(object): 

509 

510 def __getattr__(unused, name): # PYLINT E0213 

511 m = _getmodinto(mod_DNAME, _Into) 

512 return getattr(m, name) 

513 

514 return _Into() 

515 

516# @_Property_RO 

517# def _isBoolean(self): 

518# '''(INTERNAL) Get function C(.booleans.isBoolean}, I{once}. 

519# ''' 

520# return self.booleans.isBoolean 

521 

522 def items(self): # no module named 'items' 

523 '''Yield the modules imported so far. 

524 ''' 

525 for n, m in _sys.modules.items(): 

526 if _headof(n) == _pygeodesy_: 

527 yield n, m 

528 

529 @_Property_RO 

530 def _triaxials_triaxial5(self): 

531 '''(INTERNAL) Get module C{triaxial.triaxials}. 

532 ''' 

533 return self.triaxials.triaxial5 

534 

535_internals._MODS = _ALL_MODS = _ALL_MODS() # PYCHOK singleton 

536 

537 

538def _ALL_OTHER(*objs): 

539 '''(INTERNAL) Get class and function B{C{objs}} for __all__. 

540 ''' 

541 def _interned(o): # intern'd base name 

542 n = _tailof(typename(o)) 

543 i = NN(_UNDER_, n, _UNDER_) # intern'd 

544 return getattr(_interns, i, n) 

545 

546 return tuple(map(_interned, objs)) # map2 

547 

548 

549def _ALL_STAR(pack, *mods, **abspath): # PYCHOK no cover 

550 '''(INTERNAL) Mimick "for m in mods: from m import *" inside pack.__init__ 

551 returning a tuple of __all__ names collected, sorted and extended with 

552 "pack_abspath" for use in packs pyaxqg, pybelbg, pychlv and pyrdnap. 

553 ''' 

554 p = import_module(pack) # sys.modules[pack] 

555 d = p.__dict__ 

556 t = [] 

557 for m in mods: 

558 for n in m.__all__: 

559 x = getattr(m, n) 

560 if d.get(n, x) is x: 

561 d[n] = x 

562 t.append(n) 

563 else: 

564 t = '%r vs %r' % (d[n], x) 

565 raise LazyAttributeError(duplicate=n, txt=t) 

566 if abspath.get('abspath', True): 

567 t.append(_UNDER_(pack, 'abspath')) 

568 return tuple(sorted(t)) 

569 

570 

571if _FOR_DOCS: # PYCHOK no cover 

572 _ALL_DOCS = _ALL_OTHER 

573 # (INTERNAL) Only export B{C{objs.__name__}} when making the 

574 # docs to force C{epydoc} to include certain classes, methods, 

575 # functions and other names in the documentation. Using the 

576 # C{epydoc --private ...} command line option tends to include 

577 # too much internal documentation. 

578else: 

579 def _ALL_DOCS(*unused): 

580 return () 

581 

582 

583def _all_deprecates(): 

584 '''(INTERNAL) Build C{dict} of all deprecated imports and attributes. 

585 ''' 

586 D = _ALL_DEPRECATES 

587 if not D: 

588 _ALL_DEPRECATED.fill_D(D, _all_deprecates) # see _all_imports() 

589 return D 

590 

591_ALL_DEPRECATES = _Dict() # PYCHOK _ALL_DEPRECATED.imports() 

592 

593 

594def _all_enums(): 

595 '''(INTERNAL) Yield all C{(mod_, tuple)} pairs for C{__init__._all}. 

596 ''' 

597 # assert _init__all__ 

598 for mod_t in _ALL_LAZY.enums(): 

599 yield mod_t 

600 if _FOR_DOCS: 

601 for mod_t in _ALL_DEPRECATED.enums(): 

602 yield mod_t 

603 

604 

605def _all_imports(): 

606 '''(INTERNAL) Build C{dict} of all lazy imports. 

607 ''' 

608 # imports naming conventions stored below - [<key>] = <from>: 

609 # import <module> - [<module>] = <module> 

610 # from <module> import <attr> - [<attr>] = <module> 

611 # from pygeodesy import <attr> - [<attr>] = <attr> 

612 # from <module> import <attr> as <name> - [<name>] = <module>.<attr>. 

613 D = _ALL_IMPORTS 

614 if not D: 

615 _ALL_LAZY.fill_D(D, _all_imports) # see _all_deprecates() 

616 return D 

617 

618_ALL_IMPORTS = _Dict() # PYCHOK _ALL_LAZY.imports() 

619 

620 

621def _all_missing2(_all_): 

622 '''(INTERNAL) Get diffs between pygeodesy.__all__ and lazily._all_imports. 

623 ''' 

624 def _diff(one, two): 

625 return tuple(sorted(a for a in one if a not in two)) 

626 

627 _alzy = _Dict((a, a) for a in _ALL_INIT) 

628 _alzy.update(_all_imports()) # without _all_backups! 

629 return ((_DOT_(_lazily_, _all_imports.__name__), _diff(_all_, _alzy)), 

630 (_DOT_(_pygeodesy_, _DALL_), _diff(_alzy.keys(), _all_))) 

631 

632 

633def _getattras(attr_as): # test/testDeprecated 

634 '''(INTERNAL) Get the C{"as name"} or C{"name"} of a lazy entry. 

635 ''' 

636 a_, _, as_ = attr_as.partition(_asSPACED_) 

637 return as_ or a_.rstrip(_DOT_) 

638 

639 

640def _getmodattr(m, name, mod=_pygeodesy_): 

641 '''(INTERNAL) Get attr C{m.name}. 

642 ''' 

643 try: 

644 return getattr(m, name) 

645 except AttributeError: 

646 name = _DOT_(typename(m, mod), name) 

647 # <https://GitHub.com/mrJean1/PyGeodesy/issues/76> 

648 raise LazyAttributeError(_no_(_attribute_), txt=name) 

649 

650 

651def _getmodinto(mod_DNAME, *Intos): 

652 '''(INTERNAL) Core of C{_ALL_MODS.into}. 

653 ''' 

654 _MODS = _ALL_MODS 

655 mod, dun = _MODS.errors._xkwds_item2(mod_DNAME) 

656 _mod = _UNDER_(NN, mod) 

657 d = _MODS.getmodule(dun) # '__main__' OK 

658 i = _getmodattr(d, _mod, dun) 

659 assert isinstance(i, Intos) 

660 m = _MODS.getmodule(mod) 

661 setattr(d, _mod, m) # overwrite C{d._mod} 

662 if isLazy and isLazy > 1: 

663 t = _SPACE_(_HASH_, _imported_, m.__name__) # typename(m) 

664 _hash_imported(t, _MODS.into.__name__) 

665 assert getattr(d, _mod, None) is m 

666 return m 

667 

668 

669def _getmodule(name, *parent): 

670 '''(INTERNAL) Wrapper for C{import_module}. 

671 ''' 

672 try: 

673 return import_module(name, parent) 

674 except ImportError: 

675 # <https://GitHub.com/mrJean1/PyGeodesy/issues/76> 

676 raise LazyImportError(_no_(_module_), txt=name) 

677 

678 

679def _hash_imported(t, by_into, up=3): 

680 '''(INTERNAL) Helper for C{_lazy_import2} and C{_ALL_MODS.into}. 

681 ''' 

682 if isLazy and isLazy > 2: 

683 try: # see C{internals._caller3} 

684 _, f, s = _caller3(up) 

685 t = _SPACE_(t, by_into, f, _line_, s) 

686 except ValueError: 

687 pass 

688 printf(t) # XXX print 

689 

690 

691# def _lazy_attributes(DUNDER_name): 

692# '''(INTERNAL) Return a function to C{B{__name__}.__getattr__(attr)} 

693# on lazily imported modules and sub-modules. 

694# ''' 

695# if _unlazy: 

696# raise AssertionError(_COMMASPACE_(DUNDER_name, _not_(_DEPRECATED_))) 

697# 

698# def _getattr(attr, *dflt): 

699# try: # a module name 

700# return _ALL_MODS.getmodule(attr) 

701# except (AttributeError, ImportError): 

702# return _ALL_MODS.getattr(DUNDER_name, attr, *dflt) 

703# 

704# return _getattr 

705 

706 

707_lazy_dict = {} # PYCHOK overwritten by _lazy_import2 

708 

709 

710def _lazy_import2(pack): # MCCABE 14 

711 '''Check for and set up C{lazy import}. 

712 

713 @arg pack: The name of the package (C{str}) performing the imports, 

714 to help resolving relative imports, usually C{__package__}. 

715 

716 @return: 2-Tuple C{(package, getattr)} of the importing package for 

717 easy reference within itself and the callable to be set to 

718 C{package.__getattr__}. 

719 

720 @raise LazyAttributeError: The package, module or attribute name is 

721 invalid or does not exist. 

722 

723 @raise LazyImportError: Lazy import not supported or not enabled or 

724 an import failed. 

725 

726 @note: This is I{Brett Cannon}'s function U{modutil.lazy_import 

727 <https://GitHub.com/brettcannon/modutil/blob/master/modutil.py>} 

728 modified to handle the C{__all__} and C{__dir__} attributes and 

729 call C{importlib.import_module(<module>.<name>, ...)} without 

730 causing a C{ModuleNotFoundError}. 

731 

732 @see: The original U{modutil<https://PyPI.org/project/modutil>}, 

733 U{PEP 562<https://www.Python.org/dev/peps/pep-0562>} and the 

734 U{new way<https://Snarky.CA/lazy-importing-in-python-3-7/>}. 

735 ''' 

736 if pack != _pygeodesy_ or _unlazy: # Python 3.7+ # PYCHOK no cover 

737 t = _DOT_(pack, typename(_lazy_import2)) 

738 raise LazyImportError(_no_(t), txt=_versions()) 

739 

740 package, parent = _lazy_init2(pack) # _pygeodesy_ 

741 

742 _DPACKAGE_ = '__package__' 

743 _lazily_imported_ = _SPACE_(_HASH_, _lazily_, _imported_, parent) 

744 

745 sub_packages = set((parent, NN) + tuple( 

746 _DOT_(parent, s) for s in _SUB_PACKAGES)) 

747 imports = _all_imports() 

748 deprecates = _all_deprecates() 

749 

750 def __getattr__(name): # __getattr__ only for Python 3.7+ 

751 # only called once for each undefined pygeodesy attribute 

752 mod = imports.get(name, NN) or deprecates.get(name, NN) 

753 if mod: 

754 # importlib.import_module() implicitly sets sub-modules 

755 # on this module as appropriate for direct imports (see 

756 # note in the _lazy_import2.__doc__ above). 

757 if mod.endswith(_DOT_): # import mod[.attr] as name 

758 mod, _, attr = mod[:-1].rpartition(_DOT_) 

759 else: # from mod import name 

760 attr = name 

761 v = _getmodule(_DOT_(pack, mod), parent) 

762 t = getattr(v, _DPACKAGE_, None) 

763 if t not in sub_packages: # invalid module package 

764 raise LazyImportError(_DOT_(mod, _DPACKAGE_), t) 

765 if attr: # get mod.attr 

766 v = _getmodattr(v, attr, mod) 

767 

768 elif name in (_DALL_,): # XXX _Ddir_, _Dmembers_? 

769 v = _ALL_INIT + tuple(imports.keys()) 

770 else: # PYCHOK no cover 

771 t = _no_(_module_, _or_, _attribute_) 

772 # <https://GitHub.com/mrJean1/PyGeodesy/issues/76> 

773 raise LazyAttributeError(t, txt=_DOT_(parent, name)) 

774 

775 setattr(package, name, v) # package.__dict__[name] = val 

776 if isLazy > 1: 

777 t = _DOT_(_lazily_imported_, name) 

778 if mod and _tailof(mod) != name: 

779 t = _SPACE_(t, _from_, _DOT_(NN, mod)) 

780 _hash_imported(t, _by_) 

781 

782 return v # __getattr__ 

783 

784 global _lazy_dict, _lazy_module # PYLINT W0603 

785 _lazy_dict = package.__dict__ 

786 _lazy_module = __getattr__ 

787 

788 return package, __getattr__ # _lazy_import2 

789 

790 

791# def _lazy_import_all(Dname): 

792# '''(INTERNAL) Return a function mimicking C{from B{__name__} import *}, 

793# of all items, see .deprecated.__init__ 

794# ''' 

795# if _unlazy: 

796# raise AssertionError(_COMMASPACE_(Dname, _not_(_DEPRECATED_))) 

797# 

798# _getattr = _lazy_attributes(Dname) # __name__.__getattr__ 

799# _import_start = _lazy_import_star(Dname, ALL_=_ALL_IMPORTS) 

800# 

801# def _import_all(attr, *dflt): 

802# return _import_star(Dname) if attr == _DALL_ else \ 

803# _getattr(attr, *dflt) 

804# 

805# return _import_all 

806 

807 

808def _lazy_import_as(DUNDER_name): 

809 '''(INTERNAL) Return a function to C{import B{__name__}.mod as mod} 

810 I{of modules only}, see .deprecated, .rhumb or get an attribute 

811 lazily exported by C{__name__}. 

812 ''' 

813 if _unlazy: 

814 return None 

815 

816 def _import_as(mod): 

817 try: 

818 return _ALL_MODS.getmodule(_DOT_(DUNDER_name, mod)) 

819 except ImportError: 

820 return _lazy_module(mod) 

821 

822 return _import_as 

823 

824 

825# def _lazy_import_star(DUNDER_name, ALL_=_ALL_DEPRECATES): 

826# '''(INTERNAL) Return a function to mimick C{from B{__name__} import *}, 

827# of all DEPRECATED items, see .deprecated, .testDeprecated 

828# ''' 

829# if _unlazy: 

830# raise AssertionError(_COMMASPACE_(DUNDER_name, _not_(_DEPRECATED_))) 

831# 

832# def _import_star(_into_): 

833# '''Do C{from B{__name__} import *} inside module C{B{__into__}}. 

834# ''' 

835# d = dict() 

836# nm = _tailof(DUNDER_name) 

837# _g = _ALL_MODS.getattr # pygeodesy.__getattr__ 

838# for a, m in ALL_.items(): 

839# if _headof(m) == nm: 

840# try: 

841# d[a] = _g(m, a) 

842# except (AttributeError, ImportError): 

843# pass 

844# _sys.modules[_into_].__dict__.update(d) 

845# return d.keys() # imported names 

846# 

847# return _import_star 

848 

849 

850def _lazy_init2(pack): 

851 '''(INTERNAL) Initialize lazy import and set globals C{isLazy} and C{_unLazy0}. 

852 

853 @arg pack: The name of the package (C{str}) performing the imports, 

854 to resolve relative imports, usually C{__package__}. 

855 

856 @return: 2-Tuple C{(package, parent)} with the importing C{package} 

857 for easy reference within itself and its name aka the 

858 C(package)'s C{parent}, same as B{C{pack}}. 

859 

860 @raise LazyImportError: Lazy import not supported or not enabled, 

861 an import failed or the package name is 

862 invalid or does not exist. 

863 

864 @note: Global C{isLazy} is set accordingly. 

865 ''' 

866 global isLazy, _unLazy0 # PYLINT W0603 

867 

868 E = _internals._PYGEODESY_ENV('LAZY_IMPORT') 

869 z = _internals._getenv(E, _interns._1_) # 1 default on 3.7+ 

870 z = z.strip() # like PYTHONVERBOSE et.al. 

871 isLazy = int(z) if z.isdigit() else (1 if z else 0) 

872 

873 _unLazy0 = _unlazy or not isLazy # pre-3.7 or w/o lazy import 

874 

875 if isLazy < 1: # invalid, not enabled 

876 raise LazyImportError(E, repr(z), txt_not_='enabled') 

877 if _sys.flags.verbose: # PYCHOK no cover 

878 isLazy += 1 

879 

880 try: # to initialize in Python 3+ 

881 package = import_module(pack) 

882 parent = package.__spec__.parent # __spec__ only in Python 3.7+ 

883 if parent != pack: # assert 

884 t = _COMMASPACE_(parent, _not_(pack)) # PYCHOK no cover 

885 raise AttributeError(_EQUALSPACED_('parent', t)) 

886 

887 except (AttributeError, ImportError) as x: 

888 isLazy = False # failed 

889 z = typename(_lazy_init2) 

890 raise LazyImportError(z, pack, cause=x) 

891 

892 return package, parent 

893 

894 

895def _lazy_module(name): # overwritten by _lazy_import2 

896 '''(INTERNAL) Get or import a C{pygeodesy} module. 

897 ''' 

898 try: # most likely ... module has been imported 

899 m = _ALL_MODS.getmodule(name) 

900 except (AttributeError, ImportError) as x: 

901 raise LazyImportError(name, cause=x) 

902 _lazy_dict[name] = m # cache 

903 return m 

904 

905 

906# def _lazy_subs(__name__, force=_FOR_DOCS, over=False): 

907# '''(INTERNAL) Return the names of a __name__ package's sub-packages 

908# and update the package's C{__dict__} accordingly. 

909# ''' 

910# sm = dict() 

911# if force and __name__ != _DMAIN_: 

912# nm = _tailof(__name__) 

913# _a = _ALL_MODS.getattr 

914# _m = _ALL_MODS.getmodule 

915# d = _a(__name__, _DDICT_, {}) 

916# for n in _a(__name__, _DALL_, ()): 

917# try: # n is a class name, get its mod name 

918# m = _a(__name__, n).__module__ 

919# n, s = m.split(_DOT_)[-2:] 

920# if n == nm and s not in sm: 

921# m = _m(m) # == import m as s 

922# sm[s] = m if over else d.get(s, m) 

923# except (AttributeError, ImportError, ValueError) as x: 

924# pass 

925# d.update(sm) 

926# 

927# return _ALL_OTHER(*sm.values()) 

928 

929 

930__all__ = _ALL_LAZY.lazily 

931__version__ = '26.10.18' 

932 

933if __name__ == _DMAIN_: 

934 

935 def _main(): 

936 from timeit import timeit 

937 

938 def t1(): 

939 from pygeodesy.trf import RefFrame 

940 return RefFrame 

941 

942 def t2(): 

943 return _ALL_MODS.trf.RefFrame 

944 

945 assert t1() is t2() # prime each 

946 

947 t1 = timeit(t1, number=1000000) 

948 t2 = timeit(t2, number=1000000) 

949 A = typename(_ALL_MODS) 

950 v = _versions() 

951 printf('%.6f import vs %.6f %s: %.2fX, %s', t1, t2, A, (t1 / t2), v) 

952 

953 _main() 

954 

955# % python3.15 -W ignore -m pygeodesy.lazily 

956# 0.078365 import vs 0.052132 _ALL_MODS: 1.50X, pygeodesy 26.8.18 Python 3.15.0rc1 64bit arm64 macOS 26.5.2 

957 

958# n% python3.14 -W ignore -m pygeodesy.lazily 

959# 0.064455 import vs 0.046083 _ALL_MODS: 1.40X, pygeodesy 26.8.18 Python 3.14.7 64bit arm64 macOS 26.5.2 

960 

961# % python2 -W ignore -m pygeodesy.lazily 

962# 0.685969 import vs 0.321554 _ALL_MODS: 2.13X, pygeodesy 26.8.18 Python 2.7.18 64bit arm64_x86_64 macOS 26.5.2 

963 

964# % python3.14 -W ignore -m pygeodesy.lazily 

965# 0.061219 import vs 0.047896 _ALL_MODS: 1.28X, pygeodesy 25.12.6 Python 3.14.0 64bit arm64 macOS 26.1 

966 

967# % python3.13 -W ignore -m pygeodesy.lazily 

968# 0.054235 import vs 0.052469 _ALL_MODS: 1.03X, pygeodesy 25.4.24 Python 3.13.3 64bit arm64 macOS 15.4 

969 

970# % python2 -m pygeodesy.lazily 

971# 0.653715 import vs 0.321318 _ALL_MODS: 2.03X, pygeodesy 25.4.24 Python 2.7.18 64bit arm64_x86_64 macOS 10.16 

972 

973# % python3.13 -W ignore -m pygeodesy.lazily 

974# 0.106602 import vs 0.078136 _ALL_MODS: 1.36X, pygeodesy 24.10.24 Python 3.13.0 64bit arm64 macOS 14.6.1 

975 

976# % python3.12 -W ignore -m pygeodesy.lazily 

977# 0.138844 import vs 0.080458 _ALL_MODS: 1.73X, pygeodesy 24.10.24 Python 3.12.7 64bit arm64 macOS 14.6.1 

978 

979# % python3.11 -W ignore -m pygeodesy.lazily 

980# 0.387520 import vs 0.254229 _ALL_MODS: 1.52X, pygeodesy 24.10.24 Python 3.11.5 64bit arm64 macOS 14.6.1 

981 

982# % python3.10 -W ignore -m pygeodesy.lazily 

983# 0.371269 import vs 0.272897 _ALL_MODS: 1.36X, pygeodesy 24.10.24 Python 3.10.8 64bit arm64 macOS 14.6.1 

984 

985# % python3.8 -W ignore -m pygeodesy.lazily 

986# 0.555572 import vs 0.370304 _ALL_MODS: 1.50X, pygeodesy 24.10.24 Python 3.8.10 64bit arm64_x86_64 macOS 10.16 

987 

988# % python2 -m pygeodesy.lazily 

989# 1.160292 import vs 0.490279 _ALL_MODS: 2.37X, pygeodesy 24.10.24 Python 2.7.18 64bit arm64_x86_64 macOS 10.16 

990 

991# **) MIT License 

992# 

993# Copyright (C) 2018-2026 -- mrJean1 at Gmail -- All Rights Reserved. 

994# 

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

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

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

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

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

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

1001# 

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

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

1004# 

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

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

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

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

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

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

1011# OTHER DEALINGS IN THE SOFTWARE.