Coverage for pygeodesy/lazily.py: 97%

199 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2025-04-09 11:05 -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, _xkwds_item2 # _ALL_MODS 

33from pygeodesy.internals import _caller3, _DUNDER_nameof, _getPYGEODESY, _headof, \ 

34 _is_DUNDER_main, printf, _tailof, _versions 

35from pygeodesy.interns import NN, _1_, _attribute_, _by_, _COLONSPACE_, _COMMASPACE_, \ 

36 _doesn_t_exist_, _DOT_, _DUNDER_all_, _EQUALSPACED_, \ 

37 _from_, _HASH_, _immutable_, _line_, _module_, _no_, \ 

38 _not_, _or_, _pygeodesy_abspath_, _pygeodesy_, _sys, \ 

39 _SUB_PACKAGES, _UNDER_, _version_, _intern # function 

40try: 

41 from importlib import import_module 

42except ImportError as x: # Python 2.6- 

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

44# import sys as _sys # from .interns 

45 

46_a0 = () # PYCHOK empty tuple 

47_asSPACED_ = ' as ' 

48_FOR_DOCS = _getPYGEODESY('FOR_DOCS') # for epydoc ... 

49_init__all__ = _FOR_DOCS or _getPYGEODESY('_init__all__', _DUNDER_all_) == _DUNDER_all_ # PYCHOK exported 

50_lazily_ = 'lazily' 

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

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

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

54 

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

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

57 

58 

59class LazyAttributeError(AttributeError): 

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

61 ''' 

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

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

64 

65 

66class LazyImportError(ImportError): 

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

68 ''' 

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

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

71 

72 

73class _Dict(dict): 

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

75 ''' 

76 _name = NN 

77 

78 def __getattr__(self, attr): 

79 try: 

80 return self[attr] 

81 except KeyError: 

82 return dict.__getattr__(self, attr) 

83 

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

85# if attr in self: 

86# self[attr] = value 

87# else: 

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

89 

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

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

92 

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

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

95 ''' 

96 if name in self: # PYCHOK no cover 

97 sub = self[name] # duplicate OK 

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

99 t = _DOT_(self._name, name) 

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

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

102 raise AssertionError(t) 

103 else: 

104 self[name] = mod_ 

105 

106 def _NAME(self, which): 

107 self._name = _intern(_DUNDER_nameof(which).upper()) 

108 

109 

110class _NamedEnum_RO(dict): 

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

112 ''' 

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

114 

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

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

117 

118 def __getattr__(self, attr): 

119 try: 

120 return self[attr] 

121 except KeyError: 

122 t = self._DOT_(attr) 

123 raise LazyAttributeError(t, txt=_doesn_t_exist_) 

124 

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

126 t = _EQUALSPACED_(self._DOT_(attr), repr(value)) 

127 raise LazyAttributeError(_immutable_, txt=t) 

128 

129 def enums(self): 

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

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

132 n = m.replace(_UNDER_, _DOT_) 

133 if n != m: 

134 if m.startswith(_UNDER_): 

135 continue # skip _name= ... 

136 u = m.rstrip(_UNDER_) 

137 if u != m: 

138 u = len(u) 

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

140 yield n, t 

141 

142 def fill_D(self, _D, which): 

143 # Fill C{_Dict _D}. 

144 _D._NAME(which) 

145 _a = _D.add 

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

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

148 for a in t: 

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

150 if as_: # import attr as attr_ 

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

152 else: 

153 _a(a, m) 

154 return _D 

155 

156 

157def _a(*names): 

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

159 ''' 

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

161 

162 

163def _ALL_ATTRS(*attrs): 

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

165 ''' 

166 t = () 

167 for attr in attrs: 

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

169 return t 

170 

171 

172_ALL_INIT = _a(_pygeodesy_abspath_, _version_) 

173 

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

175_ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY', 

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

177 'AlbersEqualAreaCylindrical', 'AlbersEqualAreaNorth', 'AlbersEqualAreaSouth', 

178 'AlbersError', 'Albers7Tuple'), 

179 auxilats=_a(), # module only 

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

181 'Equidistant', 'EquidistantExact', 'EquidistantGeodSolve', 'EquidistantKarney', 

182 'Gnomonic', 'GnomonicExact', 'GnomonicGeodSolve', 'GnomonicKarney', 

183 'LambertEqualArea', 'Orthographic', 'Stereographic', 

184 'equidistant', 'gnomonic'), 

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

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

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

188 'iskeyword', 'isLatLon', 'islistuple', 'isNvector', 'isodd', 

189 'isscalar', 'issequence', 'isstr', 'issubclassof', 'itemsorted', 

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

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

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

193 'isBoolean'), 

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

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

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

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

198 'EasNorAziRk4Tuple', 'EasNorAziRkEqu6Tuple', 'LatLonAziRk4Tuple'), 

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

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

201 'PI', 'PI2', 'PI_2', 'PI3', 'PI_3', 'PI3_2', 'PI4', 'PI_4', 

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

203 'float_', 'float0_', 'isclose', 'isfinite', 'isinf', 'isint0', 

204 'isnan', 'isnear0', 'isnear1', 'isnear90', 'isneg0', 'isninf', 'isnon0', 

205 'remainder'), 

206 datums=_a('Datum', 'Datums', 'Transform', 'Transforms'), 

207# deprecated=_a(), # module only 

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

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

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

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

212 'bearingDMS', 'clipDegrees', 'clipRadians', 'compassDMS', 'compassPoint', 

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

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

215 ecef=_a('EcefError', 'EcefFarrell21', 'EcefFarrell22', 'EcefKarney', 'EcefMatrix', 

216 'EcefSudano', 'Ecef9Tuple', 'EcefVeness', 'EcefYou'), 

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

218 'elevation2', 'geoidHeight2'), 

219 ellipsoidalBase=_a(), # module only 

220 ellipsoidalBaseDI=_a(), # module only 

221 ellipsoidalExact=_a(), # module only 

222 ellipsoidalGeodSolve=_a(), # module only 

223 ellipsoidalKarney=_a(), # module only 

224 ellipsoidalNvector=_a(), # module only 

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

226 ellipsoids=_a('a_f2Tuple', 'Circle4Tuple', 'Curvature2Tuple', 

227 'Ellipsoid', 'Ellipsoid2', 'Ellipsoids', 

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

229 'a_f2b', 'a_f_2b', 'b_f2a', 'b_f_2a', 

230 'e2f', 'e22f', 

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

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

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

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

235 'NumPyError', 'LenError', 'LimitError', 'MGRSError', 

236 'ParseError', 'PointsError', 'RangeError', 'RhumbError', 

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

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

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

240 'parseETM5', 'toEtm8'), 

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

242 'bqrt', 'cbrt', 'cbrt2', 'euclid', 'euclid_', 

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

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

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

246 'hypot', 'hypot_', 'hypot1', 'hypot2', 'hypot2_', 

247 'norm2', 'norm_', 'sqrt0', 'sqrt3', 'sqrt_a', 'zcrt', 'zqrt'), 

248 formy=_a('Radical2Tuple', 

249 'angle2chord', 'antipode', 'antipode_', 'bearing', 'bearing_', 

250 'chord2angle', 'compassAngle', 'cosineLaw', 'cosineLaw_', 

251 'equirectangular', 'equirectangular4', 'euclidean', 'euclidean_', 

252 'excessAbc_', 'excessCagnoli_', 'excessGirard_', 'excessLHuilier_', 

253 'excessKarney', 'excessKarney_', 'excessQuad', 'excessQuad_', 

254 'flatLocal', 'flatLocal_', 'flatPolar', 'flatPolar_', 

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

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

257 'normal', 'normal_', 'opposing', 'opposing_', 'radical2', 

258 'thomas', 'thomas_', 'vincentys', 'vincentys_'), 

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

260 'FrechetDistanceTo', 'FrechetEquirectangular', 'FrechetEuclidean', 'FrechetExact', 

261 'FrechetFlatLocal', 'FrechetFlatPolar', 'FrechetHaversine', 'FrechetHubeny', 'FrechetKarney', 

262 'FrechetThomas', 'FrechetVincentys', 'Frechet6Tuple', 

263 'frechet_'), 

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

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

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

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

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

269 'Intersector', 'Intersector5Tuple', 'Middle5Tuple', 'XDict'), 

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

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

272 'GeodesicAreaExact', 'GeodesicExact', 'GeodesicLineExact', 'PolygonArea'), 

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

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

275 geoids=_a('GeoidError', 'GeoidEGM96', 'GeoidG2012B', 'GeoidKarney', 'GeoidPGM', 'egmGeoidHeights', 

276 'PGMError', 'GeoidHeight5Tuple'), 

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

278 'HausdorffDistanceTo', 'HausdorffEquirectangular', 'HausdorffEuclidean', 'HausdorffExact', 

279 'HausdorffFlatLocal', 'HausdorffFlatPolar', 'HausdorffHaversine', 'HausdorffHubeny', 

280 'HausdorffKarney', 'HausdorffThomas', 'HausdorffVincentys', 'Hausdorff6Tuple', 

281 'hausdorff_', 'randomrangenerator'), 

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

283 'HeightIDWequirectangular', 'HeightIDWeuclidean', 'HeightIDWexact', 'HeightIDWflatLocal', 

284 'HeightIDWflatPolar', 'HeightIDWhaversine', 'HeightIDWhubeny', 'HeightIDWkarney', 'HeightIDWthomas', 

285 'HeightIDWvincentys', 'HeightLinear', 'HeightLSQBiSpline', 'HeightSmoothBiSpline'), 

286 internals=_internals.__all__, 

287 interns=_interns.__all__, 

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

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

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

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

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

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

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

295 ltp=_a('Attitude', 'AttitudeError', 'ChLV', 'ChLVa', 'ChLVe', 'Frustum', 

296 'LocalCartesian', 'LocalError', 'Ltp', 'tyr3d'), 

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

298 'ChLVEN2Tuple', 'ChLV9Tuple', 'ChLVYX2Tuple', 'ChLVyx2Tuple', 

299 'Enu', 'Enu4Tuple', 'Footprint5Tuple', 'Local9Tuple', 'Los', 

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

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

302 named=_a('ADict', 

303 'callername', 'classname', 'classnaming', 'modulename', 

304 'nameof', 'notImplemented', 'notOverloaded'), 

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

306 'Destination2Tuple', 'Destination3Tuple', 

307 'Distance2Tuple', 'Distance3Tuple', 'Distance4Tuple', 

308 'EasNor2Tuple', 'EasNor3Tuple', 'Forward4Tuple', 'Intersection3Tuple', 

309 'LatLon2Tuple', 'LatLon3Tuple', 'LatLon4Tuple', 

310 'LatLonDatum3Tuple', 'LatLonDatum5Tuple', 

311 'LatLonPrec3Tuple', 'LatLonPrec5Tuple', 

312 'NearestOn2Tuple', 'NearestOn3Tuple', 'NearestOn6Tuple', 'NearestOn8Tuple', 

313 'PhiLam2Tuple', 'PhiLam3Tuple', 'PhiLam4Tuple', 'Point3Tuple', 'Points2Tuple', 

314 'Reverse4Tuple', 'Triangle7Tuple', 'Triangle8Tuple', 'Trilaterate5Tuple', 

315 'UtmUps2Tuple', 'UtmUps5Tuple', 'UtmUps8Tuple', 'UtmUpsLatLon5Tuple', 

316 'Vector2Tuple', 'Vector3Tuple', 'Vector4Tuple'), 

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

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

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

320 'areaOf', 'boundsOf', 'centroidOf', 'fractional', 

321 'isclockwise', 'isconvex', 'isconvex_', 'isenclosedBy', 'ispolar', 

322 'luneOf', 'nearestOn5', 'perimeterOf', 'quadOf'), 

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

324 'property_RO', 'property_ROnce', 'property_ROver', 

325 'deprecated_class', 'deprecated_function', 'deprecated_method', 

326 'deprecated_Property_RO', 'deprecated_property_RO', 'DeprecationWarnings'), 

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

328 'TriAngle5Tuple', 'TriSide2Tuple', 'TriSide4Tuple', 

329 'cassini', 'collins5', 'pierlot', 'pierlotx', 'tienstra7', 

330 'snellius3', 'wildberger3', 

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

332 rhumb=_a(), # module only 

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

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

335 rhumb_solve=_a('RhumbSolve', 'RhumbLineSolve', 'RhumbSolve7Tuple'), 

336 sphericalBase=_a(), # module only 

337 sphericalNvector=_a(), # module only 

338 sphericalTrigonometry=_a(), # module only 

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

340 solveBase=_a(), # module only 

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

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

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

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

345 triaxials=_a('BetaOmega2Tuple', 'BetaOmega3Tuple', 'Jacobi2Tuple', 

346 'JacobiConformal', 'JacobiConformalSpherical', 

347 'Triaxial', 'Triaxial_', 'TriaxialError', 'Triaxials', 'hartzell4'), 

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

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

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

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

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

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

354 'Radius_', 'Scalar', 'Scalar_', 'Zone'), 

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

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

357 utily=_a('acos1', 'acre2ha', 'acre2m2', 'asin1', 'atan1', 'atan1d', 'atan2', 'atan2b', 'atan2d', 

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

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

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

361 'grades', 'grades400', 'grades2degrees', 'grades2radians', 

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

363 'ha2acre', 'ha2m2', 'hav', 'km2m', 

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

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

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

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

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

369 'unroll180', 'unrollPI', 

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

371 'yard2m'), 

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

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

374 'utmupsValidate', 'utmupsValidateOK', 'utmupsZoneBand5'), 

375 utmupsBase=_a(), # module only 

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

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

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

379 'trilaterate3d2'), 

380 vector3dBase=_a(), # module only 

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

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

383 

384_ALL_DEPRECATED = _NamedEnum_RO(_name='_ALL_DEPRECATED', 

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

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

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

388 deprecated_classes=_a('ClipCS3Tuple', 'EasNorExact4Tuple', 'EcefCartesian', 'Fn_rt', 

389 'FrechetCosineAndoyerLambert', 'FrechetCosineForsytheAndoyerLambert', 

390 'HausdorffCosineAndoyerLambert', 'HausdorffCosineForsytheAndoyerLambert', 

391 'HeightIDW', 'HeightIDW2', 'HeightIDW3', 'HeightIDWcosineAndoyerLambert', 

392 'HeightIDWcosineForsytheAndoyerLambert', 'Helmert7Tuple', 

393 'Lam_', 'LatLonExact4Tuple', 'NearestOn4Tuple', 'Ned3Tuple', 

394 'Phi_', 'RefFrameError', 'Rhumb7Tuple', 'RhumbOrder2Tuple', 

395 'Transform7Tuple', 'TriAngle4Tuple', 'UtmUps4Tuple', 'XDist'), 

396 deprecated_consterns=_a('EPS1_2', 'MANTIS', 'OK'), 

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

398 'Datums', 'Ellipsoids', 'Transforms', 

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

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

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

402 'cosineAndoyerLambert', 'cosineAndoyerLambert_', 

403 'cosineForsytheAndoyerLambert', 'cosineForsytheAndoyerLambert_', 

404 'decodeEPSG2', 'encodeEPSG', 'enStr2', 'equirectangular_', 'equirectangular3', 

405 'excessAbc', 'excessGirard', 'excessLHuilier', 

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

407 'hypot3', 'inStr', 'isenclosedby', 'istuplist', 

408 'joined', 'joined_', 'nearestOn3', 'nearestOn4', 

409 'parseUTM', 'perimeterof', 'polygon', 

410 'scalar', 'simplify2', 'simplifyRDPm', 'simplifyVWm', 

411 'tienstra', 'toUtm', 'triAngle4', 

412 'unsign0', 'unStr', 'utmZoneBand2'), 

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

414 

415 

416class _ALL_MODS(_internals._MODS_Base): 

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

418 ''' 

419 def __getattr__(self, name): 

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

421 

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

423 

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

425 

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

427 ''' 

428 try: 

429 v = _lazy_dict[name] # package.__dict__ 

430 except KeyError: 

431 v = _lazy_module(name) # package.__getattr__ 

432 if _tailof(_DUNDER_nameof(v)) != name: 

433 try: 

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

435 except AttributeError: 

436 pass # XXX LazyAttributeError? 

437 return v 

438 

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

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

441 

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

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

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

445 

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

447 

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

449 

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

451 ''' 

452 v = self.getmodule(name) 

453 if attr_dflt: 

454 v = getattr(v, *attr_dflt) 

455 return v 

456 

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

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

459 

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

461 

462 @return: The C{pygeodesy} module. 

463 

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

465 ''' 

466 if _headof(name) != parent and not _is_DUNDER_main(name): 

467 name = _DOT_(parent, name) 

468 try: 

469 return _sys.modules[name] 

470 except KeyError: 

471 return _getmodule(name, parent) 

472 

473 def imported(self, name): 

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

475 ''' 

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

477 

478 def into(self, **mod_DUNDER_name): 

479 '''Lazily import module C{mod} into module C{DUNDER_name} 

480 and set C{DUNDER_name._mod} to module C{mod}, I{once}. 

481 ''' 

482 class _Into(object): 

483 

484 def __getattr__(unused, name): 

485 mod, dun = self.errors._xkwds_item2(mod_DUNDER_name) 

486 _mod = _UNDER_(NN, mod) 

487 d = self.getmodule(dun) # '__main__' OK 

488 i = _getmodattr(d, _mod, dun) 

489 assert isinstance(i, _Into) 

490 m = self.getmodule(mod) 

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

492 return getattr(m, name) 

493 

494 return _Into() 

495 

496# @_Property_RO 

497# def _isBoolean(self): 

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

499# ''' 

500# return self.booleans.isBoolean 

501 

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

503 '''Yield the modules imported so far. 

504 ''' 

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

506 if _headof(n) == _pygeodesy_: 

507 yield n, m 

508 

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

510 

511__all__ = _ALL_LAZY.lazily 

512__version__ = '25.01.25' 

513 

514 

515def _ALL_OTHER(*objs): 

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

517 ''' 

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

519 n = _tailof(_DUNDER_nameof(o)) 

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

521 return getattr(_interns, i, n) 

522 

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

524 

525 

526if _FOR_DOCS: # PYCHOK no cover 

527 _ALL_DOCS = _ALL_OTHER 

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

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

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

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

532 # too much internal documentation. 

533else: 

534 def _ALL_DOCS(*unused): 

535 return () 

536 

537 

538def _all_deprecates(): 

539 '''(INTERNAL) Build C{dict} of all deprecated imports. 

540 ''' 

541 _D = _ALL_DEPRECATES 

542 if not _D: 

543 _ALL_DEPRECATED.fill_D(_D, _all_deprecates) # see _all_imports() 

544 return _D 

545 

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

547 

548 

549def _all_enums(): 

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

551 ''' 

552 # assert _init__all__ 

553 for mod_t in _ALL_LAZY.enums(): 

554 yield mod_t 

555 if _FOR_DOCS: 

556 for mod_t in _ALL_DEPRECATED.enums(): 

557 yield mod_t 

558 

559 

560def _all_imports(): 

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

562 ''' 

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

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

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

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

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

568 _D = _ALL_IMPORTS 

569 if not _D: 

570 _ALL_LAZY.fill_D(_D, _all_imports) # see _all_deprecates() 

571 return _D 

572 

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

574 

575 

576def _all_missing2(_all_): 

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

578 ''' 

579 def _diff(one, two): 

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

581 

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

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

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

585 (_DOT_(_pygeodesy_, _DUNDER_all_), _diff(_alzy.keys(), _all_))) 

586 

587 

588def _getattras(attr_as): # test/testDeprecated 

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

590 ''' 

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

592 return as_ or a_.rstrip(_DOT_) 

593 

594 

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

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

597 ''' 

598 try: 

599 return getattr(m, name) 

600 except AttributeError: 

601 name = _DOT_(mod, name) 

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

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

604 

605 

606def _getmodule(name, *parent): 

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

608 ''' 

609 try: 

610 return import_module(name, parent) 

611 except ImportError: 

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

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

614 

615 

616# def _lazy_attributes(DUNDER_name): 

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

618# on lazily imported modules and sub-modules. 

619# ''' 

620# if _unlazy: 

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

622# 

623# def _getattr(attr, *dflt): 

624# try: # a module name 

625# return _ALL_MODS.getmodule(attr) 

626# except (AttributeError, ImportError): 

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

628# 

629# return _getattr 

630 

631 

632_lazy_dict = {} # PYCHOK overwritten by _lazy_import2 

633 

634 

635def _lazy_import2(pack): # MCCABE 14 

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

637 

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

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

640 

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

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

643 C{package.__getattr__}. 

644 

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

646 invalid or does not exist. 

647 

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

649 an import failed. 

650 

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

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

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

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

655 causing a C{ModuleNotFoundError}. 

656 

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

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

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

660 ''' 

661 _DOT_ = _interns._DOT_ 

662 _SPACE_ = _interns._SPACE_ 

663 

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

665 t = _DOT_(pack, _DUNDER_nameof(_lazy_import2)) 

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

667 

668 package, parent = _lazy_init2(pack) # _pygeodesy_ 

669 

670 _DUNDER_package_ = '__package__' 

671 _lazily_imported_ = _SPACE_(_HASH_, _lazily_, 'imported', parent) 

672 

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

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

675 imports = _all_imports() 

676 deprecates = _all_deprecates() 

677 

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

679 # only called once for each undefined pygeodesy attribute 

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

681 if mod: 

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

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

684 # note in the _lazy_import2.__doc__ above). 

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

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

687 else: # from mod import name 

688 attr = name 

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

690 t = getattr(v, _DUNDER_package_, None) 

691 if t not in sub_packages: # invalid module package 

692 raise LazyImportError(_DOT_(mod, _DUNDER_package_), t) 

693 if attr: # get mod.attr 

694 v = _getmodattr(v, attr, mod) 

695 

696 elif name in (_DUNDER_all_,): # XXX _DUNDER_dir_, _DUNDER_members_? 

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

698 else: # PYCHOK no cover 

699 t = _no_(_module_, _or_, _attribute_) 

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

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

702 

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

704 if isLazy > 1: 

705 t = _DOT_(_lazily_imported_, name) 

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

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

708 if isLazy > 2: 

709 try: # see C{_caller3} 

710 _, f, s = _caller3(2) 

711 t = _SPACE_(t, _by_, f, _line_, s) 

712 except ValueError: 

713 pass 

714 printf(t) # XXX print 

715 

716 return v # __getattr__ 

717 

718 global _lazy_dict, _lazy_module 

719 _lazy_dict = package.__dict__ 

720 _lazy_module = __getattr__ 

721 

722 return package, __getattr__ # _lazy_import2 

723 

724 

725# def _lazy_import_all(DUNDER_name): 

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

727# of all items, see .deprecated.__init__ 

728# ''' 

729# if _unlazy: 

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

731# 

732# _getattr = _lazy_attributes(DUNDER_name) # __name__.__getattr__ 

733# _import_start = _lazy_import_star(DUNDER_name, ALL_=_ALL_IMPORTS) 

734# 

735# def _import_all(attr, *dflt): 

736# return _import_star(DUNDER_name) if attr == _DUNDER_all_ else \ 

737# _getattr(attr, *dflt) 

738# 

739# return _import_all 

740 

741 

742def _lazy_import_as(DUNDER_name): 

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

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

745 lazily exported by C{__name__}. 

746 ''' 

747 if _unlazy: 

748 return None 

749 

750 def _import_as(mod): 

751 try: 

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

753 except ImportError: 

754 return _lazy_module(mod) 

755 

756 return _import_as 

757 

758 

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

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

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

762# ''' 

763# if _unlazy: 

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

765# 

766# def _import_star(_into_): 

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

768# ''' 

769# d = dict() 

770# nm = _tailof(DUNDER_name) 

771# _g = _ALL_MODS.getattr # pygeodesy.__getattr__ 

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

773# if _headof(m) == nm: 

774# try: 

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

776# except (AttributeError, ImportError): 

777# pass 

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

779# return d.keys() # imported names 

780# 

781# return _import_star 

782 

783 

784def _lazy_init2(pack): 

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

786 

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

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

789 

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

791 for easy reference within itself and its name aka the 

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

793 

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

795 an import failed or the package name is 

796 invalid or does not exist. 

797 

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

799 ''' 

800 global isLazy, _unLazy0 

801 

802 z = _getPYGEODESY('LAZY_IMPORT', _1_) # 1 default on 3.7+ 

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

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

805 

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

807 

808 if isLazy < 1: # invalid, not enabled 

809 e = _internals._PYGEODESY('LAZY_IMPORT') 

810 raise LazyImportError(e, repr(z), txt_not_='enabled') 

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

812 isLazy += 1 

813 

814 try: # to initialize in Python 3+ 

815 package = import_module(pack) 

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

817 if parent != pack: # assert 

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

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

820 

821 except (AttributeError, ImportError) as x: 

822 isLazy = False # failed 

823 z = _DUNDER_nameof(_lazy_init2) 

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

825 

826 return package, parent 

827 

828 

829def _lazy_module(name): # overwritten by _lazy_import2 

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

831 ''' 

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

833 m = _ALL_MODS.getmodule(name) 

834 except (AttributeError, ImportError) as x: 

835 raise LazyImportError(name, cause=x) 

836 _lazy_dict[name] = m # cache 

837 return m 

838 

839 

840# def _lazy_subs(DUNDER_name, force=_FOR_DOCS, over=False): 

841# '''(INTERNAL) Return the names of a package's sub-packages and 

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

843# ''' 

844# sm = dict() 

845# if force and not _is_DUNDER_main(DUNDER_name): 

846# nm = _tailof(DUNDER_name) 

847# _a = _ALL_MODS.getattr 

848# _m = _ALL_MODS.getmodule 

849# d = _a(DUNDER_name, _DUNDER_dict_, {}) 

850# for n in _a(DUNDER_name, _DUNDER_all_, ()): 

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

852# m = _a(DUNDER_name, n).__module__ 

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

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

855# # like import m as s 

856# m = _m(m) 

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

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

859# pass 

860# d.update(sm) 

861# 

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

863 

864# del _a, _a0 

865 

866if _is_DUNDER_main(__name__): # PYCHOK no cover 

867 

868 def _main(): 

869 from timeit import timeit 

870 

871 def t1(): 

872 from pygeodesy.trf import RefFrame 

873 return RefFrame 

874 

875 def t2(): 

876 return _ALL_MODS.trf.RefFrame 

877 

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

879 

880 t1 = timeit(t1, number=1000000) 

881 t2 = timeit(t2, number=1000000) 

882 A = _DUNDER_nameof(_ALL_MODS.__class__) 

883 v = _versions() 

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

885 

886 _main() 

887 

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

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

890 

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

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

893 

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

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

896 

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

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

899 

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

901# 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 

902 

903# % python2 -m pygeodesy.lazily 

904# 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 

905 

906# **) MIT License 

907# 

908# Copyright (C) 2018-2025 -- mrJean1 at Gmail -- All Rights Reserved. 

909# 

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

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

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

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

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

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

916# 

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

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

919# 

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

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

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

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

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

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

926# OTHER DEALINGS IN THE SOFTWARE.