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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. {PyGeodesy-24.5.8.dist-info → PyGeodesy-24.5.24.dist-info}/METADATA +2 -2
  2. PyGeodesy-24.5.24.dist-info/RECORD +116 -0
  3. pygeodesy/__init__.py +16 -12
  4. pygeodesy/__main__.py +9 -10
  5. pygeodesy/albers.py +42 -42
  6. pygeodesy/auxilats/__init__.py +1 -1
  7. pygeodesy/auxilats/__main__.py +7 -10
  8. pygeodesy/auxilats/auxAngle.py +32 -31
  9. pygeodesy/auxilats/auxLat.py +81 -51
  10. pygeodesy/azimuthal.py +123 -124
  11. pygeodesy/basics.py +165 -176
  12. pygeodesy/booleans.py +14 -15
  13. pygeodesy/cartesianBase.py +25 -23
  14. pygeodesy/clipy.py +3 -3
  15. pygeodesy/constants.py +8 -6
  16. pygeodesy/css.py +50 -42
  17. pygeodesy/datums.py +50 -48
  18. pygeodesy/dms.py +6 -6
  19. pygeodesy/ecef.py +27 -27
  20. pygeodesy/elevations.py +2 -2
  21. pygeodesy/ellipsoidalBase.py +28 -27
  22. pygeodesy/ellipsoidalBaseDI.py +8 -7
  23. pygeodesy/ellipsoidalNvector.py +11 -12
  24. pygeodesy/ellipsoids.py +41 -35
  25. pygeodesy/elliptic.py +12 -10
  26. pygeodesy/epsg.py +4 -3
  27. pygeodesy/errors.py +35 -13
  28. pygeodesy/etm.py +62 -53
  29. pygeodesy/fmath.py +48 -41
  30. pygeodesy/formy.py +93 -65
  31. pygeodesy/frechet.py +117 -102
  32. pygeodesy/fstats.py +52 -46
  33. pygeodesy/fsums.py +169 -145
  34. pygeodesy/gars.py +10 -9
  35. pygeodesy/geodesicw.py +32 -30
  36. pygeodesy/geodesicx/__init__.py +1 -1
  37. pygeodesy/geodesicx/__main__.py +4 -4
  38. pygeodesy/geodesicx/gx.py +40 -32
  39. pygeodesy/geodesicx/gxarea.py +15 -12
  40. pygeodesy/geodesicx/gxbases.py +3 -4
  41. pygeodesy/geodesicx/gxline.py +6 -8
  42. pygeodesy/geodsolve.py +28 -26
  43. pygeodesy/geohash.py +47 -44
  44. pygeodesy/geoids.py +37 -35
  45. pygeodesy/hausdorff.py +112 -99
  46. pygeodesy/heights.py +136 -129
  47. pygeodesy/internals.py +576 -0
  48. pygeodesy/interns.py +6 -207
  49. pygeodesy/iters.py +22 -19
  50. pygeodesy/karney.py +18 -15
  51. pygeodesy/ktm.py +31 -24
  52. pygeodesy/latlonBase.py +12 -11
  53. pygeodesy/lazily.py +140 -218
  54. pygeodesy/lcc.py +24 -25
  55. pygeodesy/ltp.py +83 -71
  56. pygeodesy/ltpTuples.py +7 -5
  57. pygeodesy/mgrs.py +5 -4
  58. pygeodesy/named.py +136 -49
  59. pygeodesy/namedTuples.py +33 -25
  60. pygeodesy/nvectorBase.py +10 -9
  61. pygeodesy/osgr.py +14 -12
  62. pygeodesy/points.py +13 -13
  63. pygeodesy/props.py +7 -7
  64. pygeodesy/rhumb/__init__.py +1 -1
  65. pygeodesy/rhumb/bases.py +3 -2
  66. pygeodesy/rhumb/solve.py +2 -2
  67. pygeodesy/solveBase.py +8 -7
  68. pygeodesy/sphericalTrigonometry.py +5 -5
  69. pygeodesy/streprs.py +8 -7
  70. pygeodesy/trf.py +8 -8
  71. pygeodesy/triaxials.py +67 -63
  72. pygeodesy/units.py +48 -50
  73. pygeodesy/unitsBase.py +24 -11
  74. pygeodesy/ups.py +7 -6
  75. pygeodesy/utily.py +4 -4
  76. pygeodesy/utm.py +53 -52
  77. pygeodesy/utmupsBase.py +11 -8
  78. pygeodesy/vector2d.py +6 -7
  79. pygeodesy/vector3d.py +16 -17
  80. pygeodesy/vector3dBase.py +5 -5
  81. PyGeodesy-24.5.8.dist-info/RECORD +0 -115
  82. {PyGeodesy-24.5.8.dist-info → PyGeodesy-24.5.24.dist-info}/WHEEL +0 -0
  83. {PyGeodesy-24.5.8.dist-info → PyGeodesy-24.5.24.dist-info}/top_level.txt +0 -0
pygeodesy/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_, _enquote, _EQUAL_, _in_, _invalid_, _N_A_, \
24
- _not_, _not_scalar_, _odd_, _SPACE_, _UNDER_, _version_, \
25
- _version_info
24
+ _ELLIPSIS4_, _EQUAL_, _in_, _invalid_, _N_A_, _not_, \
25
+ _not_scalar_, _odd_, _SPACE_, _UNDER_, _version_
26
26
  # from pygeodesy.latlonBase import LatLonBase # _MODS
27
- from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _FOR_DOCS, \
28
- _getenv, LazyImportError, _sys, _sys_version_info2
29
- # from pygeodesy.named import classname, modulename # _MODS
27
+ from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _FOR_DOCS, _getenv, \
28
+ LazyImportError, _sys_version_info2
29
+ # from pygeodesy.named import classname, modulename, _name__ # _MODS
30
30
  # from pygeodesy.nvectorBase import NvectorBase # _MODS
31
31
  # from pygeodesy.props import _update_all # _MODS
32
+ # from pygeodesy.streprs import Fmt # _MODS
32
33
 
33
34
  from copy import copy as _copy, deepcopy as _deepcopy
34
35
  from math import copysign as _copysign
35
36
  import inspect as _inspect
36
37
 
37
38
  __all__ = _ALL_LAZY.basics
38
- __version__ = '24.05.08'
39
+ __version__ = '24.05.21'
39
40
 
40
- _0_0 = 0.0 # in .constants
41
41
  _below_ = 'below'
42
42
  _list_tuple_types = (list, tuple)
43
- _list_tuple_set_types = (list, tuple, set)
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 = _Ints + (float,)
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
- '''Check whether an object is C{bool}ean.
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 B{C{obj}} is C{bool}ean,
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 B{C{obj}} is a C{Cartesian} instance of
238
- the required type, C{False} if a C{Cartesian} of an other
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
- def iscomplex(obj):
250
- '''Check whether an object is a C{complex} or complex C{str}.
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 B{C{obj}} is C{complex}, otherwise
255
- C{False}.
238
+ @return: C{True} if C{complex}, C{False} otherwise.
256
239
  '''
257
- try: # hasattr('conjugate'), hasattr('real') and hasattr('imag')
258
- return isinstance(obj, complex) or (isstr(obj)
259
- and isinstance(complex(obj), complex)) # numbers.Complex?
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
- '''Return C{True} if C{B{obj}} is a C{DEPRECATED} class, method
266
- or function, C{False} if not or C{None} if undetermined.
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
- return bool(obj.__doc__.lstrip().startswith(_DEPRECATED_))
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
- '''Check whether an object is a C{float} or float C{str}.
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 B{C{obj}} is a C{float}, otherwise
280
- C{False}.
266
+ @return: C{True} if C{float}, C{False} otherwise.
281
267
  '''
282
268
  try:
283
- return isinstance( obj, float) or (isstr(obj)
284
- and isinstance(float(obj), float))
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
- '''Return C{True} if B{C{obj}} is a Python identifier.
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, *classes):
302
- '''Is B{C{ob}} an instance of one of the C{classes}?
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 instance (any C{type}).
305
- @arg classes: One or more classes (C{class}).
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{obj}} is an instance
308
- of the B{C{classes}}, C{None} otherwise.
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, classes) else None
296
+ return type(obj) if isinstance(obj, Classes) else None
311
297
 
312
298
 
313
299
  def isint(obj, both=False):
314
- '''Check for C{int} type or an integer C{float} value.
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{true}, check C{float} and L{Fsum}
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 B{C{obj}} is C{int} or I{integer}
321
- C{float} or L{Fsum}, C{False} otherwise.
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) and not isbool(obj):
327
- return True
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 B{C{obj}} is a C{LatLon} instance of
355
- the required type, C{False} if a C{LatLon} of an other
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
- '''Check for list or tuple C{type} with a minumal length.
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 B{C{obj}} is C{list} or C{tuple} with
373
- C{len} at least B{C{minum}}, C{False} otherwise.
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 B{C{obj}} is an C{Nvector} instance of
387
- the required type, C{False} if an C{Nvector} of an other
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 B{C{x}} is odd,
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
- '''Check for scalar types.
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 B{C{obj}} is C{scalar}, C{False} otherwise.
419
+ @return: C{True} if C{int}, C{float} or L{Fsum} with
420
+ zero residual, C{False} otherwise.
415
421
  '''
416
- return isinstance(obj, _Scalars) and not isbool(obj)
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
- '''Check for sequence types.
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 B{C{obj}} is a sequence, C{False} otherwise.
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
- '''Check for string types.
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 B{C{obj}} is C{str}, C{False} otherwise.
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
- '''Check whether a class is a sub-class of some other class(es).
457
+ '''Is B{C{Sub}} a class and sub-class of some other class(es)?
444
458
 
445
- @arg Sub: The sub-class (C{class}).
446
- @arg Supers: One or more C(super) classes (C{class}).
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 B{C{Sub}} is a sub-class of any B{C{Supers}},
449
- C{False} if not (C{bool}) or C{None} if B{C{Sub}} is not
450
- a class or if no B{C{Supers}} are given or none of those
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 keyword argument C{B{asorted}=False}
467
- for I{alphabetical, case-sensitive} sorting and
468
- C{B{reverse}=True} for sorting in C{descending}
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
- return item[0].lower()
483
+ def _ins(item): # functools.cmp_to_key
484
+ k, v = item
485
+ return k.lower()
473
486
 
474
- def _key_rev(asorted=True, reverse=False):
475
- return (_ins if asorted else None), reverse
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, reverse=rev, key=key)
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
- '''Apply a single-argument function to each B{C{xs}} and
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
- '''Apply a function to arguments and return a C{tuple} of results.
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{list, tuple, ...}).
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 (_0_0 if neg0 is None else (x if not neg0 else
535
- (_0_0 if signBit(x) else _MODS.constants.NEG0)))
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):
@@ -550,12 +565,14 @@ def _neg0(x):
550
565
  return _MODS.constants.NEG0 if x < 0 else _0_0
551
566
 
552
567
 
553
- def _req_d_by(where, name=NN): # in .basics
568
+ def _req_d_by(where, **name):
554
569
  '''(INTERNAL) Get the fully qualified name.
555
570
  '''
556
- m = _MODS.named.modulename(where, prefixed=True)
557
- if name:
558
- m = _DOT_(m, name)
571
+ m = _MODS.named
572
+ n = m._name__(**name)
573
+ m = m.modulename(where, prefixed=True)
574
+ if n:
575
+ m = _DOT_(m, n)
559
576
  return _SPACE_(_required_, _by_, m)
560
577
 
561
578
 
@@ -587,48 +604,10 @@ def signOf(x):
587
604
  try:
588
605
  s = x.signOf() # Fsum instance?
589
606
  except AttributeError:
590
- s = _signOf(x, 0)
607
+ s = _signOf(x, 0)
591
608
  return s
592
609
 
593
610
 
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
611
  def splice(iterable, n=2, **fill):
633
612
  '''Split an iterable into C{n} slices.
634
613
 
@@ -669,9 +648,9 @@ def splice(iterable, n=2, **fill):
669
648
  if not isint(n):
670
649
  raise _TypeError(n=n)
671
650
 
672
- t = iterable
651
+ t = _xiterablen(iterable)
673
652
  if not isinstance(t, _list_tuple_types):
674
- t = tuple(t) # force tuple, also for PyPy3
653
+ t = tuple(t)
675
654
 
676
655
  if n > 1:
677
656
  if fill:
@@ -679,12 +658,12 @@ def splice(iterable, n=2, **fill):
679
658
  if fill is not MISSING:
680
659
  m = len(t) % n
681
660
  if m > 0: # same type fill
682
- t += type(t)((fill,) * (n - m))
661
+ t = t + type(t)((fill,) * (n - m))
683
662
  for i in range(n):
684
663
  # XXX t[i::n] chokes PyChecker
685
664
  yield t[slice(i, None, n)]
686
665
  else:
687
- yield t
666
+ yield t # 1 slice, all
688
667
 
689
668
 
690
669
  def _splituple(strs, *sep_splits): # in .mgrs, .osgr, .webmercator
@@ -778,21 +757,23 @@ def _xinstanceof(*Types, **names_values):
778
757
  raise _TypesError(n, v, *Types)
779
758
 
780
759
 
781
- def _xisscalar(**names_values):
782
- '''(INTERNAL) Check all C{name=value} pairs to be C{scalar}.
760
+ def _xiterable(obj):
761
+ '''(INTERNAL) Return C{obj} if iterable, otherwise raise C{TypeError}.
783
762
  '''
784
- for n, v in names_values.items():
785
- if not isscalar(v):
786
- raise _TypeError(n, v, txt=_not_scalar_)
763
+ return obj if isiterable(obj) else _xiterror(obj, _xiterable) # PYCHOK None
787
764
 
788
765
 
789
- def _xiterable(obj):
790
- '''(INTERNAL) Raise C{TypeError} if C{obj} is not iterable.
766
+ def _xiterablen(obj):
767
+ '''(INTERNAL) Return C{obj} if iterable with C{__len__}, otherwise raise C{TypeError}.
791
768
  '''
792
- # https://PyPI.org/project/isiterable/
793
- if not (hasattr(obj, '__iter__') or
794
- hasattr(obj, '__getitem__')):
795
- raise TypeError(_not_(_xiterable.__name__[2:]))
769
+ return obj if isiterablen(obj) else _xiterror(obj, _xiterablen) # PYCHOK None
770
+
771
+
772
+ def _xiterror(obj, _xwhich):
773
+ '''(INTERNAL) Helper for C{_xinterable} and C{_xiterablen}.
774
+ '''
775
+ t = _not_(_xwhich.__name__[2:]) # _dunder_nameof
776
+ raise _TypeError(repr(obj), txt=t)
796
777
 
797
778
 
798
779
  def _xnumpy(where, *required):
@@ -817,13 +798,21 @@ def _xor(x, *xs):
817
798
  def _xpackage(_xpkg):
818
799
  '''(INTERNAL) Check dependency to be excluded.
819
800
  '''
820
- n = _xpkg.__name__[2:] # remove _x
801
+ n = _xpkg.__name__[2:] # _dunder_nameof
821
802
  if n in _XPACKAGES:
822
803
  x = _SPACE_(n, _in_, _PYGEODESY_XPACKAGES_)
823
804
  e = _enquote(_getenv(_PYGEODESY_XPACKAGES_, NN))
824
805
  raise ImportError(_EQUAL_(x, e))
825
806
 
826
807
 
808
+ def _xscalar(**names_values):
809
+ '''(INTERNAL) Check all C{name=value} pairs to be C{scalar}.
810
+ '''
811
+ for n, v in names_values.items():
812
+ if not isscalar(v):
813
+ raise _TypeError(n, v, txt=_not_scalar_)
814
+
815
+
827
816
  def _xscipy(where, *required):
828
817
  '''(INTERNAL) Import C{scipy} and check required version.
829
818
  '''
@@ -860,7 +849,7 @@ def _xversion(package, where, *required, **name):
860
849
  if required:
861
850
  t = _version_info(package)
862
851
  if t[:len(required)] < required:
863
- t = _SPACE_(package.__name__,
852
+ t = _SPACE_(package.__name__, # _dunder_nameof
864
853
  _version_, _DOT_(*t),
865
854
  _below_, _DOT_(*required),
866
855
  _req_d_by(where, **name))