pygeodesy 24.5.6__py2.py3-none-any.whl → 24.5.15__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {PyGeodesy-24.5.6.dist-info → PyGeodesy-24.5.15.dist-info}/METADATA +4 -4
- {PyGeodesy-24.5.6.dist-info → PyGeodesy-24.5.15.dist-info}/RECORD +51 -50
- pygeodesy/__init__.py +18 -14
- pygeodesy/__main__.py +9 -10
- pygeodesy/albers.py +2 -2
- pygeodesy/auxilats/__main__.py +7 -10
- pygeodesy/auxilats/auxLat.py +2 -1
- pygeodesy/basics.py +161 -165
- pygeodesy/booleans.py +4 -4
- pygeodesy/constants.py +8 -6
- pygeodesy/datums.py +9 -8
- pygeodesy/ecef.py +5 -4
- pygeodesy/elevations.py +2 -2
- pygeodesy/ellipsoidalBaseDI.py +7 -5
- pygeodesy/elliptic.py +10 -7
- pygeodesy/errors.py +6 -6
- pygeodesy/etm.py +3 -2
- pygeodesy/fmath.py +14 -13
- pygeodesy/fstats.py +281 -219
- pygeodesy/fsums.py +133 -104
- pygeodesy/geodesicw.py +14 -14
- pygeodesy/geodesicx/__main__.py +4 -4
- pygeodesy/geodesicx/gxarea.py +4 -4
- pygeodesy/geodsolve.py +3 -2
- pygeodesy/geoids.py +6 -6
- pygeodesy/heights.py +4 -4
- pygeodesy/internals.py +571 -0
- pygeodesy/interns.py +5 -202
- pygeodesy/iters.py +3 -2
- pygeodesy/karney.py +4 -4
- pygeodesy/ktm.py +7 -7
- pygeodesy/lazily.py +139 -217
- pygeodesy/mgrs.py +3 -2
- pygeodesy/named.py +13 -10
- pygeodesy/nvectorBase.py +4 -3
- pygeodesy/osgr.py +14 -12
- pygeodesy/points.py +5 -5
- pygeodesy/props.py +7 -7
- pygeodesy/rhumb/bases.py +3 -2
- pygeodesy/rhumb/solve.py +2 -2
- pygeodesy/solveBase.py +3 -2
- pygeodesy/streprs.py +5 -4
- pygeodesy/trf.py +4 -4
- pygeodesy/units.py +15 -17
- pygeodesy/ups.py +7 -6
- pygeodesy/utily.py +4 -4
- pygeodesy/utm.py +5 -4
- pygeodesy/utmupsBase.py +4 -3
- pygeodesy/vector3dBase.py +2 -1
- {PyGeodesy-24.5.6.dist-info → PyGeodesy-24.5.15.dist-info}/WHEEL +0 -0
- {PyGeodesy-24.5.6.dist-info → PyGeodesy-24.5.15.dist-info}/top_level.txt +0 -0
pygeodesy/basics.py
CHANGED
|
@@ -19,28 +19,27 @@ del division
|
|
|
19
19
|
from pygeodesy.errors import _AttributeError, _ImportError, _NotImplementedError, \
|
|
20
20
|
_TypeError, _TypesError, _ValueError, _xAssertionError, \
|
|
21
21
|
_xkwds_get
|
|
22
|
+
from pygeodesy.internals import _0_0, _enquote, _passarg, _version_info
|
|
22
23
|
from pygeodesy.interns import MISSING, NN, _1_, _by_, _COMMA_, _DOT_, _DEPRECATED_, \
|
|
23
|
-
_ELLIPSIS4_,
|
|
24
|
-
_not_scalar_, _SPACE_, _UNDER_, _version_
|
|
24
|
+
_ELLIPSIS4_, _EQUAL_, _in_, _invalid_, _N_A_, _not_, \
|
|
25
|
+
_not_scalar_, _odd_, _SPACE_, _UNDER_, _version_
|
|
25
26
|
# from pygeodesy.latlonBase import LatLonBase # _MODS
|
|
26
|
-
from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _FOR_DOCS, \
|
|
27
|
-
|
|
27
|
+
from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _FOR_DOCS, _getenv, \
|
|
28
|
+
LazyImportError, _sys_version_info2
|
|
28
29
|
# from pygeodesy.named import classname, modulename # _MODS
|
|
29
30
|
# from pygeodesy.nvectorBase import NvectorBase # _MODS
|
|
30
31
|
# from pygeodesy.props import _update_all # _MODS
|
|
32
|
+
# from pygeodesy.streprs import Fmt # _MODS
|
|
31
33
|
|
|
32
34
|
from copy import copy as _copy, deepcopy as _deepcopy
|
|
33
35
|
from math import copysign as _copysign
|
|
34
36
|
import inspect as _inspect
|
|
35
37
|
|
|
36
38
|
__all__ = _ALL_LAZY.basics
|
|
37
|
-
__version__ = '24.
|
|
39
|
+
__version__ = '24.05.15'
|
|
38
40
|
|
|
39
|
-
_0_0 = 0.0 # in .constants
|
|
40
41
|
_below_ = 'below'
|
|
41
42
|
_list_tuple_types = (list, tuple)
|
|
42
|
-
_list_tuple_set_types = (list, tuple, set)
|
|
43
|
-
_odd_ = 'odd'
|
|
44
43
|
_PYGEODESY_XPACKAGES_ = 'PYGEODESY_XPACKAGES'
|
|
45
44
|
_required_ = 'required'
|
|
46
45
|
|
|
@@ -51,7 +50,7 @@ except ImportError:
|
|
|
51
50
|
_Ints = int, long # int objects (C{tuple})
|
|
52
51
|
except NameError: # Python 3+
|
|
53
52
|
_Ints = int, # int objects (C{tuple})
|
|
54
|
-
_Scalars =
|
|
53
|
+
_Scalars = (float,) + _Ints
|
|
55
54
|
|
|
56
55
|
try:
|
|
57
56
|
try: # use C{from collections.abc import ...} in Python 3.9+
|
|
@@ -67,19 +66,6 @@ except ImportError:
|
|
|
67
66
|
_Sequence = tuple # immutable for .points._Basequence
|
|
68
67
|
_Seqs = list, _Sequence # range for function len2 below
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
def _passarg(arg): # in .auxilats.auxLat
|
|
72
|
-
'''(INTERNAL) Helper, no-op.
|
|
73
|
-
'''
|
|
74
|
-
return arg
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def _passargs(*args): # in .utily
|
|
78
|
-
'''(INTERNAL) Helper, no-op.
|
|
79
|
-
'''
|
|
80
|
-
return args
|
|
81
|
-
|
|
82
|
-
|
|
83
69
|
try:
|
|
84
70
|
_Bytes = unicode, bytearray # PYCHOK expected
|
|
85
71
|
_Strs = basestring, str # XXX , bytes
|
|
@@ -202,41 +188,28 @@ def int1s(x):
|
|
|
202
188
|
|
|
203
189
|
|
|
204
190
|
def isbool(obj):
|
|
205
|
-
'''
|
|
191
|
+
'''Is B{C{obj}}ect a C{bool}ean?
|
|
206
192
|
|
|
207
193
|
@arg obj: The object (any C{type}).
|
|
208
194
|
|
|
209
|
-
@return: C{True} if
|
|
210
|
-
C{False} otherwise.
|
|
195
|
+
@return: C{True} if C{bool}ean, C{False} otherwise.
|
|
211
196
|
'''
|
|
212
197
|
return isinstance(obj, bool) # and (obj is False
|
|
213
198
|
# or obj is True)
|
|
214
199
|
|
|
215
200
|
assert not (isbool(1) or isbool(0) or isbool(None)) # PYCHOK 2
|
|
216
201
|
|
|
217
|
-
if _FOR_DOCS: # XXX avoid epydoc Python 2.7 error
|
|
218
|
-
|
|
219
|
-
def isclass(obj):
|
|
220
|
-
'''Return C{True} if B{C{obj}} is a C{class} or C{type}.
|
|
221
|
-
|
|
222
|
-
@see: Python's C{inspect.isclass}.
|
|
223
|
-
'''
|
|
224
|
-
return _inspect.isclass(obj)
|
|
225
|
-
else:
|
|
226
|
-
isclass = _inspect.isclass
|
|
227
|
-
|
|
228
202
|
|
|
229
203
|
def isCartesian(obj, ellipsoidal=None):
|
|
230
|
-
'''Is B{C{obj}} some C{Cartesian}?
|
|
204
|
+
'''Is B{C{obj}}ect some C{Cartesian}?
|
|
231
205
|
|
|
232
206
|
@arg obj: The object (any C{type}).
|
|
233
207
|
@kwarg ellipsoidal: If C{None}, return the type of any C{Cartesian},
|
|
234
208
|
if C{True}, only an ellipsoidal C{Cartesian type}
|
|
235
209
|
or if C{False}, only a spherical C{Cartesian type}.
|
|
236
210
|
|
|
237
|
-
@return: C{type(B{obj}} if
|
|
238
|
-
|
|
239
|
-
type or C{None} otherwise.
|
|
211
|
+
@return: C{type(B{obj}} if a C{Cartesian} of the required type, C{False}
|
|
212
|
+
if a C{Cartesian} of an other type or {None} otherwise.
|
|
240
213
|
'''
|
|
241
214
|
if ellipsoidal is not None:
|
|
242
215
|
try:
|
|
@@ -246,42 +219,55 @@ def isCartesian(obj, ellipsoidal=None):
|
|
|
246
219
|
return isinstanceof(obj, _MODS.cartesianBase.CartesianBase)
|
|
247
220
|
|
|
248
221
|
|
|
249
|
-
|
|
250
|
-
|
|
222
|
+
if _FOR_DOCS: # XXX avoid epydoc Python 2.7 error
|
|
223
|
+
|
|
224
|
+
def isclass(obj):
|
|
225
|
+
'''Is B{C{obj}}ect a C{Class} or C{type}?
|
|
226
|
+
'''
|
|
227
|
+
return _inspect.isclass(obj)
|
|
228
|
+
else:
|
|
229
|
+
isclass = _inspect.isclass
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def iscomplex(obj, both=False):
|
|
233
|
+
'''Is B{C{obj}}ect a C{complex} or complex literal C{str}?
|
|
251
234
|
|
|
252
235
|
@arg obj: The object (any C{type}).
|
|
236
|
+
@kwarg both: If C{True}, check complex C{str} (C{bool}).
|
|
253
237
|
|
|
254
|
-
@return: C{True} if
|
|
255
|
-
C{False}.
|
|
238
|
+
@return: C{True} if C{complex}, C{False} otherwise.
|
|
256
239
|
'''
|
|
257
|
-
try: # hasattr('conjugate'
|
|
258
|
-
return isinstance(obj,
|
|
259
|
-
|
|
240
|
+
try: # hasattr('conjugate', 'real' and 'imag')
|
|
241
|
+
return isinstance(obj, complex) or bool(both and isstr(obj) and
|
|
242
|
+
isinstance(complex(obj), complex)) # numbers.Complex?
|
|
260
243
|
except (TypeError, ValueError):
|
|
261
244
|
return False
|
|
262
245
|
|
|
263
246
|
|
|
264
247
|
def isDEPRECATED(obj):
|
|
265
|
-
'''
|
|
266
|
-
|
|
248
|
+
'''Is B{C{obj}}ect a C{DEPRECATED} class, method or function?
|
|
249
|
+
|
|
250
|
+
@return: C{True} if C{DEPRECATED}, {False} if not or
|
|
251
|
+
C{None} if undetermined.
|
|
267
252
|
'''
|
|
268
|
-
try: # XXX inspect.getdoc(obj)
|
|
269
|
-
|
|
253
|
+
try: # XXX inspect.getdoc(obj) or obj.__doc__
|
|
254
|
+
doc = obj.__doc__.lstrip()
|
|
255
|
+
return bool(doc and doc.startswith(_DEPRECATED_))
|
|
270
256
|
except AttributeError:
|
|
271
257
|
return None
|
|
272
258
|
|
|
273
259
|
|
|
274
|
-
def isfloat(obj):
|
|
275
|
-
'''
|
|
260
|
+
def isfloat(obj, both=False):
|
|
261
|
+
'''Is B{C{obj}}ect a C{float} or float literal C{str}?
|
|
276
262
|
|
|
277
263
|
@arg obj: The object (any C{type}).
|
|
264
|
+
@kwarg both: If C{True}, check float C{str} (C{bool}).
|
|
278
265
|
|
|
279
|
-
@return: C{True} if
|
|
280
|
-
C{False}.
|
|
266
|
+
@return: C{True} if C{float}, C{False} otherwise.
|
|
281
267
|
'''
|
|
282
268
|
try:
|
|
283
|
-
return isinstance(
|
|
284
|
-
|
|
269
|
+
return isinstance(obj, float) or bool(both and
|
|
270
|
+
isstr(obj) and isinstance(float(obj), float))
|
|
285
271
|
except (TypeError, ValueError):
|
|
286
272
|
return False
|
|
287
273
|
|
|
@@ -291,40 +277,40 @@ try:
|
|
|
291
277
|
except AttributeError: # Python 2-
|
|
292
278
|
|
|
293
279
|
def isidentifier(obj):
|
|
294
|
-
'''
|
|
280
|
+
'''Is B{C{obj}}ect a Python identifier?
|
|
295
281
|
'''
|
|
296
282
|
return bool(obj and isstr(obj)
|
|
297
283
|
and obj.replace(_UNDER_, NN).isalnum()
|
|
298
284
|
and not obj[:1].isdigit())
|
|
299
285
|
|
|
300
286
|
|
|
301
|
-
def isinstanceof(obj, *
|
|
302
|
-
'''Is B{C{
|
|
287
|
+
def isinstanceof(obj, *Classes):
|
|
288
|
+
'''Is B{C{obj}}ect an instance of one of the C{Classes}?
|
|
303
289
|
|
|
304
|
-
@arg obj: The
|
|
305
|
-
@arg
|
|
290
|
+
@arg obj: The object (any C{type}).
|
|
291
|
+
@arg Classes: One or more classes (C{Class}).
|
|
306
292
|
|
|
307
|
-
@return: C{type(B{obj}} if B{C{
|
|
308
|
-
|
|
293
|
+
@return: C{type(B{obj}} if one of the B{C{Classes}},
|
|
294
|
+
C{None} otherwise.
|
|
309
295
|
'''
|
|
310
|
-
return type(obj) if isinstance(obj,
|
|
296
|
+
return type(obj) if isinstance(obj, Classes) else None
|
|
311
297
|
|
|
312
298
|
|
|
313
299
|
def isint(obj, both=False):
|
|
314
|
-
'''
|
|
300
|
+
'''Is B{C{obj}}ect an C{int} or integer C{float} value?
|
|
315
301
|
|
|
316
302
|
@arg obj: The object (any C{type}).
|
|
317
|
-
@kwarg both: If C{
|
|
303
|
+
@kwarg both: If C{True}, check C{float} and L{Fsum}
|
|
318
304
|
type and value (C{bool}).
|
|
319
305
|
|
|
320
|
-
@return: C{True} if
|
|
321
|
-
|
|
306
|
+
@return: C{True} if C{int} or I{integer} C{float}
|
|
307
|
+
or L{Fsum}, C{False} otherwise.
|
|
322
308
|
|
|
323
309
|
@note: Both C{isint(True)} and C{isint(False)} return
|
|
324
310
|
C{False} (and no longer C{True}).
|
|
325
311
|
'''
|
|
326
|
-
if isinstance(obj, _Ints)
|
|
327
|
-
return
|
|
312
|
+
if isinstance(obj, _Ints):
|
|
313
|
+
return not isbool(obj)
|
|
328
314
|
elif both: # and isinstance(obj, (float, Fsum))
|
|
329
315
|
try: # NOT , _Scalars) to include Fsum!
|
|
330
316
|
return obj.is_integer()
|
|
@@ -333,6 +319,27 @@ def isint(obj, both=False):
|
|
|
333
319
|
return False
|
|
334
320
|
|
|
335
321
|
|
|
322
|
+
def isiterable(obj):
|
|
323
|
+
'''Is B{C{obj}}ect C{iterable}?
|
|
324
|
+
|
|
325
|
+
@arg obj: The object (any C{type}).
|
|
326
|
+
|
|
327
|
+
@return: C{True} if C{iterable}, C{False} otherwise.
|
|
328
|
+
'''
|
|
329
|
+
# <https://PyPI.org/project/isiterable/>
|
|
330
|
+
return hasattr(obj, '__iter__') # map, range, set
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def isiterablen(obj):
|
|
334
|
+
'''Is B{C{obj}}ect C{iterable} and has C{len}gth?
|
|
335
|
+
|
|
336
|
+
@arg obj: The object (any C{type}).
|
|
337
|
+
|
|
338
|
+
@return: C{True} if C{iterable} with C{len}gth, C{False} otherwise.
|
|
339
|
+
'''
|
|
340
|
+
return hasattr(obj, '__len__') and hasattr(obj, '__getitem__')
|
|
341
|
+
|
|
342
|
+
|
|
336
343
|
try:
|
|
337
344
|
from keyword import iskeyword # Python 2.7+
|
|
338
345
|
except ImportError:
|
|
@@ -344,16 +351,15 @@ except ImportError:
|
|
|
344
351
|
|
|
345
352
|
|
|
346
353
|
def isLatLon(obj, ellipsoidal=None):
|
|
347
|
-
'''Is B{C{obj}} some C{LatLon}?
|
|
354
|
+
'''Is B{C{obj}}ect some C{LatLon}?
|
|
348
355
|
|
|
349
356
|
@arg obj: The object (any C{type}).
|
|
350
357
|
@kwarg ellipsoidal: If C{None}, return the type of any C{LatLon},
|
|
351
358
|
if C{True}, only an ellipsoidal C{LatLon type}
|
|
352
359
|
or if C{False}, only a spherical C{LatLon type}.
|
|
353
360
|
|
|
354
|
-
@return: C{type(B{obj}} if
|
|
355
|
-
|
|
356
|
-
type or {None} otherwise.
|
|
361
|
+
@return: C{type(B{obj}} if a C{LatLon} of the required type, C{False}
|
|
362
|
+
if a C{LatLon} of an other type or {None} otherwise.
|
|
357
363
|
'''
|
|
358
364
|
if ellipsoidal is not None:
|
|
359
365
|
try:
|
|
@@ -364,28 +370,27 @@ def isLatLon(obj, ellipsoidal=None):
|
|
|
364
370
|
|
|
365
371
|
|
|
366
372
|
def islistuple(obj, minum=0):
|
|
367
|
-
'''
|
|
373
|
+
'''Is B{C{obj}}ect a C{list} or C{tuple} with non-zero length?
|
|
368
374
|
|
|
369
375
|
@arg obj: The object (any C{type}).
|
|
370
376
|
@kwarg minum: Minimal C{len} required C({int}).
|
|
371
377
|
|
|
372
|
-
@return: C{True} if
|
|
373
|
-
|
|
378
|
+
@return: C{True} if a C{list} or C{tuple} with C{len} at
|
|
379
|
+
least B{C{minum}}, C{False} otherwise.
|
|
374
380
|
'''
|
|
375
381
|
return isinstance(obj, _list_tuple_types) and len(obj) >= minum
|
|
376
382
|
|
|
377
383
|
|
|
378
384
|
def isNvector(obj, ellipsoidal=None):
|
|
379
|
-
'''Is B{C{obj}} some C{Nvector}?
|
|
385
|
+
'''Is B{C{obj}}ect some C{Nvector}?
|
|
380
386
|
|
|
381
387
|
@arg obj: The object (any C{type}).
|
|
382
388
|
@kwarg ellipsoidal: If C{None}, return the type of any C{Nvector},
|
|
383
389
|
if C{True}, only an ellipsoidal C{Nvector type}
|
|
384
390
|
or if C{False}, only a spherical C{Nvector type}.
|
|
385
391
|
|
|
386
|
-
@return: C{type(B{obj}} if
|
|
387
|
-
|
|
388
|
-
type or {None} otherwise.
|
|
392
|
+
@return: C{type(B{obj}} if an C{Nvector} of the required type, C{False}
|
|
393
|
+
if an C{Nvector} of an other type or {None} otherwise.
|
|
389
394
|
'''
|
|
390
395
|
if ellipsoidal is not None:
|
|
391
396
|
try:
|
|
@@ -400,55 +405,63 @@ def isodd(x):
|
|
|
400
405
|
|
|
401
406
|
@arg x: Value (C{scalar}).
|
|
402
407
|
|
|
403
|
-
@return: C{True} if
|
|
404
|
-
C{False} otherwise.
|
|
408
|
+
@return: C{True} if odd, C{False} otherwise.
|
|
405
409
|
'''
|
|
406
410
|
return bool(int(x) & 1) # == bool(int(x) % 2)
|
|
407
411
|
|
|
408
412
|
|
|
409
|
-
def isscalar(obj):
|
|
410
|
-
'''
|
|
413
|
+
def isscalar(obj, both=False):
|
|
414
|
+
'''Is B{C{obj}}ect an C{int} or integer C{float} value?
|
|
411
415
|
|
|
412
416
|
@arg obj: The object (any C{type}).
|
|
417
|
+
@kwarg both: If C{True}, check L{Fsum<Fsum.residual>}.
|
|
413
418
|
|
|
414
|
-
@return: C{True} if
|
|
419
|
+
@return: C{True} if C{int}, C{float} or L{Fsum} with
|
|
420
|
+
zero residual, C{False} otherwise.
|
|
415
421
|
'''
|
|
416
|
-
|
|
422
|
+
if isinstance(obj, _Scalars):
|
|
423
|
+
return not isbool(obj)
|
|
424
|
+
elif both: # and isinstance(obj, Fsum)
|
|
425
|
+
try:
|
|
426
|
+
return bool(obj.residual == 0)
|
|
427
|
+
except (AttributeError, TypeError):
|
|
428
|
+
pass # XXX float(int(obj)) == obj?
|
|
429
|
+
return False
|
|
417
430
|
|
|
418
431
|
|
|
419
432
|
def issequence(obj, *excls):
|
|
420
|
-
'''
|
|
433
|
+
'''Is B{C{obj}}ect some sequence type?
|
|
421
434
|
|
|
422
435
|
@arg obj: The object (any C{type}).
|
|
423
436
|
@arg excls: Classes to exclude (C{type}), all positional.
|
|
424
437
|
|
|
425
438
|
@note: Excluding C{tuple} implies excluding C{namedtuple}.
|
|
426
439
|
|
|
427
|
-
@return: C{True} if
|
|
440
|
+
@return: C{True} if a sequence, C{False} otherwise.
|
|
428
441
|
'''
|
|
429
442
|
return isinstance(obj, _Seqs) and not (excls and isinstance(obj, excls))
|
|
430
443
|
|
|
431
444
|
|
|
432
445
|
def isstr(obj):
|
|
433
|
-
'''
|
|
446
|
+
'''Is B{C{obj}}ect some string type?
|
|
434
447
|
|
|
435
448
|
@arg obj: The object (any C{type}).
|
|
436
449
|
|
|
437
|
-
@return: C{True} if
|
|
450
|
+
@return: C{True} if a C{str}, C{bytes}, ...,
|
|
451
|
+
C{False} otherwise.
|
|
438
452
|
'''
|
|
439
453
|
return isinstance(obj, _Strs)
|
|
440
454
|
|
|
441
455
|
|
|
442
456
|
def issubclassof(Sub, *Supers):
|
|
443
|
-
'''
|
|
457
|
+
'''Is B{C{Sub}} a class and sub-class of some other class(es)?
|
|
444
458
|
|
|
445
|
-
@arg Sub: The sub-class (C{
|
|
446
|
-
@arg Supers: One or more C(super) classes (C{
|
|
459
|
+
@arg Sub: The sub-class (C{Class}).
|
|
460
|
+
@arg Supers: One or more C(super) classes (C{Class}).
|
|
447
461
|
|
|
448
|
-
@return: C{True} if
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
are a class.
|
|
462
|
+
@return: C{True} if a sub-class of any B{C{Supers}}, C{False}
|
|
463
|
+
if not (C{bool}) or C{None} if not a class or if no
|
|
464
|
+
B{C{Supers}} are given or none of those are a class.
|
|
452
465
|
'''
|
|
453
466
|
if isclass(Sub):
|
|
454
467
|
t = tuple(S for S in Supers if isclass(S))
|
|
@@ -463,20 +476,19 @@ def itemsorted(adict, *items_args, **asorted_reverse):
|
|
|
463
476
|
|
|
464
477
|
@arg items_args: Optional positional argument(s) for method
|
|
465
478
|
C{B{adict}.items(B*{items_args})}.
|
|
466
|
-
@kwarg asorted_reverse: Use
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
order.
|
|
479
|
+
@kwarg asorted_reverse: Use C{B{asorted}=False} for I{alphabetical,
|
|
480
|
+
case-sensitive} sorting and C{B{reverse}=True} for
|
|
481
|
+
sorting in C{descending} order.
|
|
470
482
|
'''
|
|
471
|
-
def _ins(item):
|
|
472
|
-
|
|
483
|
+
def _ins(item): # functools.cmp_to_key
|
|
484
|
+
k, v = item
|
|
485
|
+
return k.lower()
|
|
473
486
|
|
|
474
|
-
def
|
|
475
|
-
return (_ins if asorted else None)
|
|
487
|
+
def _reverse_key(asorted=True, reverse=False):
|
|
488
|
+
return dict(reverse=reverse, key=_ins if asorted else None)
|
|
476
489
|
|
|
477
|
-
key, rev = _key_rev(**asorted_reverse)
|
|
478
490
|
items = adict.items(*items_args) if items_args else adict.items()
|
|
479
|
-
return sorted(items,
|
|
491
|
+
return sorted(items, **_reverse_key(**asorted_reverse))
|
|
480
492
|
|
|
481
493
|
|
|
482
494
|
def len2(items):
|
|
@@ -494,8 +506,8 @@ def len2(items):
|
|
|
494
506
|
|
|
495
507
|
|
|
496
508
|
def map1(fun1, *xs): # XXX map_
|
|
497
|
-
'''
|
|
498
|
-
return a C{tuple} of results.
|
|
509
|
+
'''Call a single-argument function to each B{C{xs}}
|
|
510
|
+
and return a C{tuple} of results.
|
|
499
511
|
|
|
500
512
|
@arg fun1: 1-Arg function (C{callable}).
|
|
501
513
|
@arg xs: Arguments (C{any positional}).
|
|
@@ -506,7 +518,7 @@ def map1(fun1, *xs): # XXX map_
|
|
|
506
518
|
|
|
507
519
|
|
|
508
520
|
def map2(fun, *xs):
|
|
509
|
-
'''
|
|
521
|
+
'''Like Python's B{C{map}} but returning a C{tuple} of results.
|
|
510
522
|
|
|
511
523
|
Unlike Python 2's built-in L{map}, Python 3+ L{map} returns a
|
|
512
524
|
L{map} object, an iterator-like object which generates the
|
|
@@ -514,7 +526,7 @@ def map2(fun, *xs):
|
|
|
514
526
|
maintains the Python 2 behavior.
|
|
515
527
|
|
|
516
528
|
@arg fun: Function (C{callable}).
|
|
517
|
-
@arg xs: Arguments (C{
|
|
529
|
+
@arg xs: Arguments (C{all positional}).
|
|
518
530
|
|
|
519
531
|
@return: Function results (C{tuple}).
|
|
520
532
|
'''
|
|
@@ -531,8 +543,11 @@ def neg(x, neg0=None):
|
|
|
531
543
|
|
|
532
544
|
@return: C{-B{x} if B{x} else 0.0, NEG0 or B{x}}.
|
|
533
545
|
'''
|
|
534
|
-
return (-x) if x else (
|
|
535
|
-
|
|
546
|
+
return (-x) if x else (
|
|
547
|
+
_0_0 if neg0 is None else (
|
|
548
|
+
x if not neg0 else (
|
|
549
|
+
_0_0 if signBit(x) else _MODS.constants.
|
|
550
|
+
NEG0))) # PYCHOK indent
|
|
536
551
|
|
|
537
552
|
|
|
538
553
|
def neg_(*xs):
|
|
@@ -587,48 +602,10 @@ def signOf(x):
|
|
|
587
602
|
try:
|
|
588
603
|
s = x.signOf() # Fsum instance?
|
|
589
604
|
except AttributeError:
|
|
590
|
-
s =
|
|
605
|
+
s = _signOf(x, 0)
|
|
591
606
|
return s
|
|
592
607
|
|
|
593
608
|
|
|
594
|
-
def _sizeof(inst):
|
|
595
|
-
'''(INTERNAL) Recursively size an C{inst}ance.
|
|
596
|
-
|
|
597
|
-
@return: Instance' size in bytes (C{int}),
|
|
598
|
-
ignoring class attributes and
|
|
599
|
-
counting duplicates only once or
|
|
600
|
-
C{None}.
|
|
601
|
-
|
|
602
|
-
@note: With C{PyPy}, the size is always C{None}.
|
|
603
|
-
'''
|
|
604
|
-
try:
|
|
605
|
-
_zB = _sys.getsizeof
|
|
606
|
-
_zD = _zB(None) # get some default
|
|
607
|
-
except TypeError: # PyPy3.10
|
|
608
|
-
return None
|
|
609
|
-
|
|
610
|
-
def _zR(s, iterable):
|
|
611
|
-
z, _s = 0, s.add
|
|
612
|
-
for o in iterable:
|
|
613
|
-
i = id(o)
|
|
614
|
-
if i not in s:
|
|
615
|
-
_s(i)
|
|
616
|
-
z += _zB(o, _zD)
|
|
617
|
-
if isinstance(o, dict):
|
|
618
|
-
z += _zR(s, o.keys())
|
|
619
|
-
z += _zR(s, o.values())
|
|
620
|
-
elif isinstance(o, _list_tuple_set_types):
|
|
621
|
-
z += _zR(s, o)
|
|
622
|
-
else:
|
|
623
|
-
try: # size instance' attr values only
|
|
624
|
-
z += _zR(s, o.__dict__.values())
|
|
625
|
-
except AttributeError: # None, int, etc.
|
|
626
|
-
pass
|
|
627
|
-
return z
|
|
628
|
-
|
|
629
|
-
return _zR(set(), (inst,))
|
|
630
|
-
|
|
631
|
-
|
|
632
609
|
def splice(iterable, n=2, **fill):
|
|
633
610
|
'''Split an iterable into C{n} slices.
|
|
634
611
|
|
|
@@ -669,9 +646,9 @@ def splice(iterable, n=2, **fill):
|
|
|
669
646
|
if not isint(n):
|
|
670
647
|
raise _TypeError(n=n)
|
|
671
648
|
|
|
672
|
-
t = iterable
|
|
649
|
+
t = _xiterablen(iterable)
|
|
673
650
|
if not isinstance(t, _list_tuple_types):
|
|
674
|
-
t = tuple(t)
|
|
651
|
+
t = tuple(t)
|
|
675
652
|
|
|
676
653
|
if n > 1:
|
|
677
654
|
if fill:
|
|
@@ -679,12 +656,12 @@ def splice(iterable, n=2, **fill):
|
|
|
679
656
|
if fill is not MISSING:
|
|
680
657
|
m = len(t) % n
|
|
681
658
|
if m > 0: # same type fill
|
|
682
|
-
t
|
|
659
|
+
t = t + type(t)((fill,) * (n - m))
|
|
683
660
|
for i in range(n):
|
|
684
661
|
# XXX t[i::n] chokes PyChecker
|
|
685
662
|
yield t[slice(i, None, n)]
|
|
686
663
|
else:
|
|
687
|
-
yield t
|
|
664
|
+
yield t # 1 slice, all
|
|
688
665
|
|
|
689
666
|
|
|
690
667
|
def _splituple(strs, *sep_splits): # in .mgrs, .osgr, .webmercator
|
|
@@ -778,12 +755,23 @@ def _xinstanceof(*Types, **names_values):
|
|
|
778
755
|
raise _TypesError(n, v, *Types)
|
|
779
756
|
|
|
780
757
|
|
|
781
|
-
def
|
|
782
|
-
'''(INTERNAL)
|
|
758
|
+
def _xiterable(obj):
|
|
759
|
+
'''(INTERNAL) Return C{obj} if iterable, otherwise raise C{TypeError}.
|
|
783
760
|
'''
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
761
|
+
return obj if isiterable(obj) else _xiterror(obj, _xiterable) # PYCHOK None
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
def _xiterablen(obj):
|
|
765
|
+
'''(INTERNAL) Return C{obj} if iterable with C{__len__}, otherwise raise C{TypeError}.
|
|
766
|
+
'''
|
|
767
|
+
return obj if isiterablen(obj) else _xiterror(obj, _xiterablen) # PYCHOK None
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
def _xiterror(obj, _xwhich):
|
|
771
|
+
'''(INTERNAL) Helper for C{_xinterable} and C{_xiterablen}.
|
|
772
|
+
'''
|
|
773
|
+
t = _not_(_xwhich.__name__[2:]) # _dunder_nameof
|
|
774
|
+
raise _TypeError(repr(obj), txt=t)
|
|
787
775
|
|
|
788
776
|
|
|
789
777
|
def _xnumpy(where, *required):
|
|
@@ -808,13 +796,21 @@ def _xor(x, *xs):
|
|
|
808
796
|
def _xpackage(_xpkg):
|
|
809
797
|
'''(INTERNAL) Check dependency to be excluded.
|
|
810
798
|
'''
|
|
811
|
-
n = _xpkg.__name__[2:] #
|
|
799
|
+
n = _xpkg.__name__[2:] # _dunder_nameof
|
|
812
800
|
if n in _XPACKAGES:
|
|
813
801
|
x = _SPACE_(n, _in_, _PYGEODESY_XPACKAGES_)
|
|
814
802
|
e = _enquote(_getenv(_PYGEODESY_XPACKAGES_, NN))
|
|
815
803
|
raise ImportError(_EQUAL_(x, e))
|
|
816
804
|
|
|
817
805
|
|
|
806
|
+
def _xscalar(**names_values):
|
|
807
|
+
'''(INTERNAL) Check all C{name=value} pairs to be C{scalar}.
|
|
808
|
+
'''
|
|
809
|
+
for n, v in names_values.items():
|
|
810
|
+
if not isscalar(v):
|
|
811
|
+
raise _TypeError(n, v, txt=_not_scalar_)
|
|
812
|
+
|
|
813
|
+
|
|
818
814
|
def _xscipy(where, *required):
|
|
819
815
|
'''(INTERNAL) Import C{scipy} and check required version.
|
|
820
816
|
'''
|
|
@@ -851,7 +847,7 @@ def _xversion(package, where, *required, **name):
|
|
|
851
847
|
if required:
|
|
852
848
|
t = _version_info(package)
|
|
853
849
|
if t[:len(required)] < required:
|
|
854
|
-
t = _SPACE_(package.__name__,
|
|
850
|
+
t = _SPACE_(package.__name__, # _dunder_nameof
|
|
855
851
|
_version_, _DOT_(*t),
|
|
856
852
|
_below_, _DOT_(*required),
|
|
857
853
|
_req_d_by(where, **name))
|
pygeodesy/booleans.py
CHANGED
|
@@ -17,7 +17,7 @@ C{reverse-difference}, C{sum} and C{union}.
|
|
|
17
17
|
# make sure int/int division yields float quotient, see .basics
|
|
18
18
|
from __future__ import division as _; del _ # PYCHOK semicolon
|
|
19
19
|
|
|
20
|
-
from pygeodesy.basics import isodd, issubclassof, map2,
|
|
20
|
+
from pygeodesy.basics import isodd, issubclassof, map2, _xscalar
|
|
21
21
|
from pygeodesy.constants import EPS, EPS2, INT0, _0_0, _0_5, _1_0
|
|
22
22
|
from pygeodesy.errors import ClipError, _IsnotError, _TypeError, \
|
|
23
23
|
_ValueError, _xattr, _xkwds_get
|
|
@@ -25,7 +25,7 @@ from pygeodesy.fmath import favg, hypot, hypot2
|
|
|
25
25
|
# from pygeodesy.fsums import fsum1 # _MODS
|
|
26
26
|
from pygeodesy.interns import NN, _BANG_, _clip_, _clipid_, _COMMASPACE_, \
|
|
27
27
|
_composite_, _DOT_, _e_, _ELLIPSIS_, _few_, \
|
|
28
|
-
_height_, _lat_,_LatLon_, _lon_, _not_, \
|
|
28
|
+
_height_, _lat_, _LatLon_, _lon_, _not_, \
|
|
29
29
|
_points_, _SPACE_, _too_, _X_, _x_, \
|
|
30
30
|
_B_, _d_, _R_ # PYCHOK used!
|
|
31
31
|
from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
|
|
@@ -42,7 +42,7 @@ from pygeodesy.utily import fabs, _unrollon, _Wrap
|
|
|
42
42
|
# from math import fabs # from .utily
|
|
43
43
|
|
|
44
44
|
__all__ = _ALL_LAZY.booleans
|
|
45
|
-
__version__ = '24.
|
|
45
|
+
__version__ = '24.05.15'
|
|
46
46
|
|
|
47
47
|
_0_EPS = EPS # near-zero, positive
|
|
48
48
|
_EPS_0 = -EPS # near-zero, negative
|
|
@@ -330,7 +330,7 @@ class LatLonFHP(_LatLonBool):
|
|
|
330
330
|
return self.x * other.x + self.y * other.y
|
|
331
331
|
|
|
332
332
|
def __rmul__(self, other): # scalar product
|
|
333
|
-
|
|
333
|
+
_xscalar(other=other)
|
|
334
334
|
return self.__class__(self.y * other, self.x * other)
|
|
335
335
|
|
|
336
336
|
def _e_x_str(self, t): # PYCHOK no cover
|
pygeodesy/constants.py
CHANGED
|
@@ -9,12 +9,13 @@ L{pygeodesy.isnon0} and L{pygeodesy.remainder}.
|
|
|
9
9
|
# make sure int/int division yields float quotient, see .basics
|
|
10
10
|
from __future__ import division as _; del _ # PYCHOK semicolon
|
|
11
11
|
|
|
12
|
-
from pygeodesy.basics import
|
|
12
|
+
from pygeodesy.basics import _copysign, isbool, iscomplex, isint, _0_0
|
|
13
13
|
from pygeodesy.errors import _xError, _xError2, _xkwds_get, _xkwds_item2
|
|
14
|
+
# from pygeodesy.internals import _0_0 # from .basics
|
|
14
15
|
from pygeodesy.interns import _INF_, _NAN_, _UNDER_
|
|
15
|
-
# from pygeodesy.lazily import _ALL_LAZY # from .
|
|
16
|
+
# from pygeodesy.lazily import _ALL_LAZY # from .unitsBase
|
|
16
17
|
# from pygeodesy.streprs import Fmt # from .unitsBase
|
|
17
|
-
from pygeodesy.unitsBase import Float, Int, Radius, Fmt
|
|
18
|
+
from pygeodesy.unitsBase import Float, Int, Radius, _ALL_LAZY, Fmt
|
|
18
19
|
|
|
19
20
|
from math import fabs, isinf, isnan, pi as _PI, sqrt
|
|
20
21
|
try:
|
|
@@ -23,7 +24,7 @@ except ImportError: # Python 2-
|
|
|
23
24
|
_inf, _nan = float(_INF_), float(_NAN_)
|
|
24
25
|
|
|
25
26
|
__all__ = _ALL_LAZY.constants
|
|
26
|
-
__version__ = '24.
|
|
27
|
+
__version__ = '24.05.14'
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
def _copysign_0_0(y):
|
|
@@ -355,8 +356,9 @@ def isint0(obj, both=False):
|
|
|
355
356
|
@return: C{True} if B{C{obj}} is L{INT0}, C{int(0)} or
|
|
356
357
|
C{float(0)}, C{False} otherwise.
|
|
357
358
|
'''
|
|
358
|
-
return (obj is INT0 or obj is int(0) or
|
|
359
|
-
|
|
359
|
+
return (obj is INT0 or obj is int(0) or
|
|
360
|
+
bool(both and (not obj) and isint(obj, both=True))) and \
|
|
361
|
+
not isbool(obj)
|
|
360
362
|
|
|
361
363
|
|
|
362
364
|
def isnear0(x, eps0=EPS0):
|