Coverage for pygeodesy/lazily.py: 96%

1

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

3

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

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

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

7

8 C{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

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

11 I{and newer}.

12

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

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

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

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

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

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

19 and 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

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

31 _isfrozen # DON'T _lazy_import2

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

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

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

35# _MODS_Base, _MODS.sys_version_info2

36 from 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_

41 try:

42 from importlib import import_module

43 except 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>

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

59

60

61 class 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

68 class 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

75 class _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)

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

112 class _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

160 def _a(*names):

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

162 '''

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

164

165

166 def _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(), # module 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', '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', 'EcefKarney', 'EcefSudano', 'EcefUPC', 'EcefVeness', 'EcefYou',

220 'EcefError', 'EcefMatrix', 'Ecef9Tuple'),

221 ecefLocals=_a(), # module only

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

223 'elevation2', 'geoidHeight2'),

224 ellipses=_a('Ellipse',),

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', 'Circle4Tuple', '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_', 'sqrt0', 'sqrt3', 'sqrt_a', 'zcrt', 'zqrt'),

254 formy=_a('Radical2Tuple',

255 'angle2chord', 'antipode', 'antipode_', 'bearing', 'bearing_',

256 'chord2angle', 'compassAngle', 'cosineLaw', 'cosineLaw_',

257 'equirectangular', 'equirectangular4', 'euclidean', 'euclidean_',

258 'excessAbc_', 'excessCagnoli_', 'excessGirard_', 'excessLHuilier_',

259 'excessKarney', 'excessKarney_', 'excessQuad', 'excessQuad_',

260 'flatLocal', 'flatLocal_', 'flatPolar', 'flatPolar_',

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

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

263 'normal', 'normal_', 'opposing', 'opposing_', 'radical2',

264 'thomas', 'thomas_', 'vincentys', 'vincentys_'),

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

266 'FrechetDistanceTo', 'FrechetEquirectangular', 'FrechetEuclidean', 'FrechetExact',

267 'FrechetFlatLocal', 'FrechetFlatPolar', 'FrechetHaversine', 'FrechetHubeny', 'FrechetKarney',

268 'FrechetThomas', 'FrechetVincentys', 'Frechet6Tuple',

269 'frechet_'),

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

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

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

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

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

275 'Intersector', 'Intersector5Tuple', 'Middle5Tuple', 'XDict'),

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

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

278 'GeodesicAreaExact', 'GeodesicExact', 'GeodesicLineExact', 'PolygonArea'),

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

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

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

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

283 'PGMError', 'GeoidHeight5Tuple'),

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

285 'HausdorffDistanceTo', 'HausdorffEquirectangular', 'HausdorffEuclidean', 'HausdorffExact',

286 'HausdorffFlatLocal', 'HausdorffFlatPolar', 'HausdorffHaversine', 'HausdorffHubeny',

287 'HausdorffKarney', 'HausdorffThomas', 'HausdorffVincentys', 'Hausdorff6Tuple',

288 'hausdorff_', 'randomrangenerator'),

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

290 'HeightIDWequirectangular', 'HeightIDWeuclidean', 'HeightIDWexact', 'HeightIDWflatLocal',

291 'HeightIDWflatPolar', 'HeightIDWhaversine', 'HeightIDWhubeny', 'HeightIDWkarney', 'HeightIDWthomas',

292 'HeightIDWvincentys', 'HeightLinear', 'HeightLSQBiSpline', 'HeightSmoothBiSpline'),

293 internals=_internals.__all__,

294 interns=_interns.__all__,

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

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

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

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

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

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

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

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

303 'LocalCartesian', 'LocalError', 'Ltp', 'tyr3d'),

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

305 'ChLVEN2Tuple', 'ChLV9Tuple', 'ChLVYX2Tuple', 'ChLVyx2Tuple',

306 'Enu', 'Enu4Tuple', 'Footprint5Tuple', 'Local9Tuple', 'Los',

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

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

309 named=_a('ADict',

310 'callername', 'classname', 'classnaming', 'modulename',

311 'nameof', 'notImplemented', 'notOverloaded'),

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

313 'Destination2Tuple', 'Destination3Tuple',

314 'Distance2Tuple', 'Distance3Tuple', 'Distance4Tuple',

315 'EasNor2Tuple', 'EasNor3Tuple', 'Forward4Tuple', 'Intersection3Tuple',

316 'LatLon2Tuple', 'LatLon3Tuple', 'LatLon4Tuple',

317 'LatLonDatum3Tuple', 'LatLonDatum5Tuple',

318 'LatLonPrec3Tuple', 'LatLonPrec5Tuple',

319 'NearestOn2Tuple', 'NearestOn3Tuple', 'NearestOn6Tuple', 'NearestOn8Tuple',

320 'PhiLam2Tuple', 'PhiLam3Tuple', 'PhiLam4Tuple', 'Point3Tuple', 'Points2Tuple',

321 'Reverse4Tuple', 'Triangle7Tuple', 'Triangle8Tuple', 'Trilaterate5Tuple',

322 'UtmUps2Tuple', 'UtmUps5Tuple', 'UtmUps8Tuple', 'UtmUpsLatLon5Tuple',

323 'Vector2Tuple', 'Vector3Tuple', 'Vector4Tuple'),

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

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

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

327 'areaOf', 'boundsOf', 'centroidOf', 'fractional',

328 'isclockwise', 'isconvex', 'isconvex_', 'isenclosedBy', 'ispolar',

329 'luneOf', 'nearestOn5', 'perimeterOf', 'quadOf'),

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

331 'property_RO', 'property_ROnce', 'property_ROver',

332 'deprecated_class', 'deprecated_function', 'deprecated_method',

333 'deprecated_Property_RO', 'deprecated_property_RO', 'DeprecationWarnings'),

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

335 'TriAngle5Tuple', 'TriSide2Tuple', 'TriSide4Tuple',

336 'cassini', 'collins5', 'pierlot', 'pierlotx', 'tienstra7',

337 'snellius3', 'wildberger3',

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

339 rhumb=_a(), # module only

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

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

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

343 sphericalBase=_a(), # module only

344 sphericalNvector=_a(), # module only

345 sphericalTrigonometry=_a(), # module only

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

347 solveBase=_a(), # module only

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

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

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

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

352 triaxials=_a(), # module only

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

354 triaxials_conformal3=_a('BetOmgGam5Tuple',

355 'Conformal3', 'Conformal3B', 'Conformal3Sphere', 'Conformal5Tuple'),

356 triaxials_triaxial3=_a('BetOmgAlp5Tuple', 'Cartesian5Tuple', 'PhiLamZet5Tuple',

357 'Triaxial3', 'Triaxial3B', 'Triaxial3s'),

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

359 'Conformal', 'ConformalSphere', 'Conformal2Tuple',

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

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

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

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

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

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

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

367 'Radius_', 'Scalar', 'Scalar_', 'Zone'),

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

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

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

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

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

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

374 'gdf', 'grades', 'grades400', 'grades2degrees', 'grades2radians',

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

376 'ha2acre', 'ha2m2', 'hav', 'km2m',

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

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

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

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

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

382 'unroll180', 'unrollPI',

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

384 'yard2m'),

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

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

387 'utmupsValidate', 'utmupsValidateOK', 'utmupsZoneBand5'),

388 utmupsBase=_a(), # module only

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

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

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

392 'trilaterate3d2'),

393 vector3dBase=_a(), # module only

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

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

396

397 _ALL_DEPRECATED = _NamedEnum_RO(_name='_ALL_DEPRECATED',

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

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

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

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

402 'FrechetCosineAndoyerLambert', 'FrechetCosineForsytheAndoyerLambert',

403 'HausdorffCosineAndoyerLambert', 'HausdorffCosineForsytheAndoyerLambert',

404 'HeightIDW', 'HeightIDW2', 'HeightIDW3', 'HeightIDWcosineAndoyerLambert',

405 'HeightIDWcosineForsytheAndoyerLambert', 'Helmert7Tuple',

406 'JacobiConformal', 'JacobiConformalSpherical', 'Jacobi2Tuple',

407 'Lam_', 'LatLonExact4Tuple', 'NearestOn4Tuple', 'Ned3Tuple',

408 'Phi_', 'RefFrameError', 'Rhumb7Tuple', 'RhumbOrder2Tuple',

409 'Transform7Tuple', 'TriAngle4Tuple', 'UtmUps4Tuple', 'XDist'),

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

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

412 'Datums', 'Ellipsoids', 'Transforms',

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

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

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

416 'cosineAndoyerLambert', 'cosineAndoyerLambert_',

417 'cosineForsytheAndoyerLambert', 'cosineForsytheAndoyerLambert_',

418 'decodeEPSG2',

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

420 'excessAbc', 'excessGirard', 'excessLHuilier',

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

422 'hypot3', 'inStr', 'isenclosedby', 'istuplist',

423 'joined', 'joined_', 'nearestOn3', 'nearestOn4',

424 'parseUTM', 'perimeterof', 'polygon',

425 'scalar', 'simplify2', 'simplifyRDPm', 'simplifyVWm',

426 'tienstra', 'toUtm', 'triAngle4',

427 'unsign0', 'unStr', 'utmZoneBand2'),

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

429

430

431 class _ALL_MODS(_internals._MODS_Base):

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

433 '''

434 def __getattr__(self, name):

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

436

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

438

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

440

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

442 '''

443 try:

444 v = _lazy_dict[name] # package.__dict__

445 except KeyError:

446 v = _lazy_module(name) # package.__getattr__

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

448 try:

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

450 except AttributeError:

451 pass # XXX LazyAttributeError?

452 return v

453

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

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

456

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

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

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

460

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

462

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

464

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

466 '''

467 v = self.getmodule(name)

468 if attr_dflt:

469 v = getattr(v, *attr_dflt)

470 return v

471

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

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

474

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

476

477 @return: The C{pygeodesy} module.

478

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

480 '''

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

482 name = _DOT_(parent, name)

483 try:

484 return _sys.modules[name]

485 except KeyError:

486 return _getmodule(name, parent)

487

488 def imported(self, name):

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

490 '''

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

492

493 def into(self, **mod_DNAME):

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

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

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

497 '''

498 # assert len(mod_DNAME) == 1

499 # mod, dun = mod_DNAME.popitem()

500

501 class _Into(object):

502

503 def __getattr__(unused, name):

504 m = _getmodinto(mod_DNAME, _Into)

505 return getattr(m, name)

506

507 return _Into()

508

509# @_Property_RO

510# def _isBoolean(self):

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

512# '''

513# return self.booleans.isBoolean

514

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

516 '''Yield the modules imported so far.

517 '''

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

519 if _headof(n) == _pygeodesy_:

520 yield n, m

521

522 @_Property_RO

523 def _triaxials_triaxial5(self):

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

525 '''

526 return self.triaxials.triaxial5

527

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

529

530 __all__ = _ALL_LAZY.lazily

531 __version__ = '26.02.09'

532

533

534 def _ALL_OTHER(*objs):

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

536 '''

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

538 n = _tailof(typename(o))

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

540 return getattr(_interns, i, n)

541

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

543

544

545 if _FOR_DOCS: # PYCHOK no cover

546 _ALL_DOCS = _ALL_OTHER

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

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

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

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

551 # too much internal documentation.

552 else:

553 def _ALL_DOCS(*unused):

554 return ()

555

556

557 def _all_deprecates():

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

559 '''

560 D = _ALL_DEPRECATES

561 if not D:

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

563 return D

564

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

566

567

568 def _all_enums():

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

570 '''

571 # assert _init__all__

572 for mod_t in _ALL_LAZY.enums():

573 yield mod_t

574 if _FOR_DOCS:

575 for mod_t in _ALL_DEPRECATED.enums():

576 yield mod_t

577

578

579 def _all_imports():

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

581 '''

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

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

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

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

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

587 D = _ALL_IMPORTS

588 if not D:

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

590 return D

591

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

593

594

595 def _all_missing2(_all_):

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

597 '''

598 def _diff(one, two):

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

600

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

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

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

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

605

606

607 def _getattras(attr_as): # test/testDeprecated

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

609 '''

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

611 return as_ or a_.rstrip(_DOT_)

612

613

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

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

616 '''

617 try:

618 return getattr(m, name)

619 except AttributeError:

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

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

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

623

624

625 def _getmodinto(mod_DNAME, *Intos):

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

627 '''

628 _MODS = _ALL_MODS

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

630 _mod = _UNDER_(NN, mod)

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

632 i = _getmodattr(d, _mod, dun)

633 assert isinstance(i, Intos)

634 m = _MODS.getmodule(mod)

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

636 if isLazy and isLazy > 1:

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

638 _hash_imported(t, _MODS.into.__name__)

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

640 return m

641

642

643 def _getmodule(name, *parent):

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

645 '''

646 try:

647 return import_module(name, parent)

648 except ImportError:

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

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

651

652

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

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

655 '''

656 if isLazy and isLazy > 2:

657 try: # see C{internals._caller3}

658 _, f, s = _caller3(up)

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

660 except ValueError:

661 pass

662 printf(t) # XXX print

663

664

665# def _lazy_attributes(DUNDER_name):

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

667# on lazily imported modules and sub-modules.

668# '''

669# if _unlazy:

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

671#

672# def _getattr(attr, *dflt):

673# try: # a module name

674# return _ALL_MODS.getmodule(attr)

675# except (AttributeError, ImportError):

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

677#

678# return _getattr

679

680

681 _lazy_dict = {} # PYCHOK overwritten by _lazy_import2

682

683

684 def _lazy_import2(pack): # MCCABE 14

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

686

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

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

689

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

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

692 C{package.__getattr__}.

693

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

695 invalid or does not exist.

696

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

698 an import failed.

699

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

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

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

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

704 causing a C{ModuleNotFoundError}.

705

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

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

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

709 '''

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

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

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

713

714 package, parent = _lazy_init2(pack) # _pygeodesy_

715

716 _DPACKAGE_ = '__package__'

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

718

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

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

721 imports = _all_imports()

722 deprecates = _all_deprecates()

723

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

725 # only called once for each undefined pygeodesy attribute

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

727 if mod:

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

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

730 # note in the _lazy_import2.__doc__ above).

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

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

733 else: # from mod import name

734 attr = name

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

736 t = getattr(v, _DPACKAGE_, None)

737 if t not in sub_packages: # invalid module package

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

739 if attr: # get mod.attr

740 v = _getmodattr(v, attr, mod)

741

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

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

744 else: # PYCHOK no cover

745 t = _no_(_module_, _or_, _attribute_)

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

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

748

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

750 if isLazy > 1:

751 t = _DOT_(_lazily_imported_, name)

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

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

754 _hash_imported(t, _by_)

755

756 return v # __getattr__

757

758 global _lazy_dict, _lazy_module

759 _lazy_dict = package.__dict__

760 _lazy_module = __getattr__

761

762 return package, __getattr__ # _lazy_import2

763

764

765# def _lazy_import_all(Dname):

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

767# of all items, see .deprecated.__init__

768# '''

769# if _unlazy:

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

771#

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

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

774#

775# def _import_all(attr, *dflt):

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

777# _getattr(attr, *dflt)

778#

779# return _import_all

780

781

782 def _lazy_import_as(DUNDER_name):

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

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

785 lazily exported by C{__name__}.

786 '''

787 if _unlazy:

788 return None

789

790 def _import_as(mod):

791 try:

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

793 except ImportError:

794 return _lazy_module(mod)

795

796 return _import_as

797

798

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

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

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

802# '''

803# if _unlazy:

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

805#

806# def _import_star(_into_):

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

808# '''

809# d = dict()

810# nm = _tailof(DUNDER_name)

811# _g = _ALL_MODS.getattr # pygeodesy.__getattr__

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

813# if _headof(m) == nm:

814# try:

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

816# except (AttributeError, ImportError):

817# pass

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

819# return d.keys() # imported names

820#

821# return _import_star

822

823

824 def _lazy_init2(pack):

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

826

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

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

829

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

831 for easy reference within itself and its name aka the

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

833

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

835 an import failed or the package name is

836 invalid or does not exist.

837

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

839 '''

840 global isLazy, _unLazy0

841

842 E = _internals._PYGEODESY_ENV('LAZY_IMPORT')

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

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

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

846

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

848

849 if isLazy < 1: # invalid, not enabled

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

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

852 isLazy += 1

853

854 try: # to initialize in Python 3+

855 package = import_module(pack)

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

857 if parent != pack: # assert

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

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

860

861 except (AttributeError, ImportError) as x:

862 isLazy = False # failed

863 z = typename(_lazy_init2)

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

865

866 return package, parent

867

868

869 def _lazy_module(name): # overwritten by _lazy_import2

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

871 '''

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

873 m = _ALL_MODS.getmodule(name)

874 except (AttributeError, ImportError) as x:

875 raise LazyImportError(name, cause=x)

876 _lazy_dict[name] = m # cache

877 return m

878

879

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

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

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

883# '''

884# sm = dict()

885# if force and __name__ != _DMAIN_:

886# nm = _tailof(__name__)

887# _a = _ALL_MODS.getattr

888# _m = _ALL_MODS.getmodule

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

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

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

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

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

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

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

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

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

898# pass

899# d.update(sm)

900#

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

902

903

904 if __name__ == _DMAIN_:

905

906 def _main():

907 from timeit import timeit

908

909 def t1():

910 from pygeodesy.trf import RefFrame

911 return RefFrame

912

913 def t2():

914 return _ALL_MODS.trf.RefFrame

915

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

917

918 t1 = timeit(t1, number=1000000)

919 t2 = timeit(t2, number=1000000)

920 A = typename(_ALL_MODS)

921 v = _versions()

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

923

924 _main()

925

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

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

928

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

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

931

932# % python2 -m pygeodesy.lazily

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

934

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

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

937

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

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

940

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

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

943

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

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

946

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

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

949

950# % python2 -m pygeodesy.lazily

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

952

953# **) MIT License

954#

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

956#

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

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

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

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

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

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

963#

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

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

966#

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

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

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

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

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

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

973# OTHER DEALINGS IN THE SOFTWARE.