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.
Files changed (51) hide show
  1. {PyGeodesy-24.5.6.dist-info → PyGeodesy-24.5.15.dist-info}/METADATA +4 -4
  2. {PyGeodesy-24.5.6.dist-info → PyGeodesy-24.5.15.dist-info}/RECORD +51 -50
  3. pygeodesy/__init__.py +18 -14
  4. pygeodesy/__main__.py +9 -10
  5. pygeodesy/albers.py +2 -2
  6. pygeodesy/auxilats/__main__.py +7 -10
  7. pygeodesy/auxilats/auxLat.py +2 -1
  8. pygeodesy/basics.py +161 -165
  9. pygeodesy/booleans.py +4 -4
  10. pygeodesy/constants.py +8 -6
  11. pygeodesy/datums.py +9 -8
  12. pygeodesy/ecef.py +5 -4
  13. pygeodesy/elevations.py +2 -2
  14. pygeodesy/ellipsoidalBaseDI.py +7 -5
  15. pygeodesy/elliptic.py +10 -7
  16. pygeodesy/errors.py +6 -6
  17. pygeodesy/etm.py +3 -2
  18. pygeodesy/fmath.py +14 -13
  19. pygeodesy/fstats.py +281 -219
  20. pygeodesy/fsums.py +133 -104
  21. pygeodesy/geodesicw.py +14 -14
  22. pygeodesy/geodesicx/__main__.py +4 -4
  23. pygeodesy/geodesicx/gxarea.py +4 -4
  24. pygeodesy/geodsolve.py +3 -2
  25. pygeodesy/geoids.py +6 -6
  26. pygeodesy/heights.py +4 -4
  27. pygeodesy/internals.py +571 -0
  28. pygeodesy/interns.py +5 -202
  29. pygeodesy/iters.py +3 -2
  30. pygeodesy/karney.py +4 -4
  31. pygeodesy/ktm.py +7 -7
  32. pygeodesy/lazily.py +139 -217
  33. pygeodesy/mgrs.py +3 -2
  34. pygeodesy/named.py +13 -10
  35. pygeodesy/nvectorBase.py +4 -3
  36. pygeodesy/osgr.py +14 -12
  37. pygeodesy/points.py +5 -5
  38. pygeodesy/props.py +7 -7
  39. pygeodesy/rhumb/bases.py +3 -2
  40. pygeodesy/rhumb/solve.py +2 -2
  41. pygeodesy/solveBase.py +3 -2
  42. pygeodesy/streprs.py +5 -4
  43. pygeodesy/trf.py +4 -4
  44. pygeodesy/units.py +15 -17
  45. pygeodesy/ups.py +7 -6
  46. pygeodesy/utily.py +4 -4
  47. pygeodesy/utm.py +5 -4
  48. pygeodesy/utmupsBase.py +4 -3
  49. pygeodesy/vector3dBase.py +2 -1
  50. {PyGeodesy-24.5.6.dist-info → PyGeodesy-24.5.15.dist-info}/WHEEL +0 -0
  51. {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_, _enquote, _EQUAL_, _in_, _invalid_, _N_A_, \
24
- _not_scalar_, _SPACE_, _UNDER_, _version_, _version_info
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
- _getenv, LazyImportError, _sys, _sys_version_info2
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.04.28'
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 = _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):
@@ -587,48 +602,10 @@ def signOf(x):
587
602
  try:
588
603
  s = x.signOf() # Fsum instance?
589
604
  except AttributeError:
590
- s = _signOf(x, 0)
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) # force tuple, also for PyPy3
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 += type(t)((fill,) * (n - m))
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 _xisscalar(**names_values):
782
- '''(INTERNAL) Check all C{name=value} pairs to be C{scalar}.
758
+ def _xiterable(obj):
759
+ '''(INTERNAL) Return C{obj} if iterable, otherwise raise C{TypeError}.
783
760
  '''
784
- for n, v in names_values.items():
785
- if not isscalar(v):
786
- raise _TypeError(n, v, txt=_not_scalar_)
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:] # remove _x
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, _xisscalar
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.02.06'
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
- _xisscalar(other=other)
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 _0_0, _copysign, isbool, iscomplex, isint, _ALL_LAZY
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 .basics
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.04.23'
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 bool(both and
359
- (not obj) and isint(obj, both=True))) and not isbool(obj)
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):