pygeodesy 24.9.29__py2.py3-none-any.whl → 24.10.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 (56) hide show
  1. {PyGeodesy-24.9.29.dist-info → PyGeodesy-24.10.24.dist-info}/METADATA +15 -15
  2. {PyGeodesy-24.9.29.dist-info → PyGeodesy-24.10.24.dist-info}/RECORD +56 -56
  3. pygeodesy/__init__.py +20 -19
  4. pygeodesy/__main__.py +5 -5
  5. pygeodesy/albers.py +12 -17
  6. pygeodesy/basics.py +38 -41
  7. pygeodesy/booleans.py +54 -46
  8. pygeodesy/cartesianBase.py +2 -2
  9. pygeodesy/constants.py +20 -16
  10. pygeodesy/datums.py +3 -3
  11. pygeodesy/dms.py +250 -270
  12. pygeodesy/ellipsoidalBase.py +2 -2
  13. pygeodesy/ellipsoidalBaseDI.py +10 -10
  14. pygeodesy/ellipsoidalNvector.py +4 -4
  15. pygeodesy/ellipsoidalVincenty.py +2 -2
  16. pygeodesy/ellipsoids.py +7 -48
  17. pygeodesy/elliptic.py +14 -14
  18. pygeodesy/errors.py +15 -10
  19. pygeodesy/etm.py +18 -2
  20. pygeodesy/fmath.py +188 -176
  21. pygeodesy/formy.py +4 -4
  22. pygeodesy/fstats.py +54 -56
  23. pygeodesy/fsums.py +304 -266
  24. pygeodesy/geodesici.py +43 -40
  25. pygeodesy/geodesicw.py +3 -3
  26. pygeodesy/geodesicx/gxarea.py +3 -2
  27. pygeodesy/geodsolve.py +73 -24
  28. pygeodesy/geohash.py +2 -2
  29. pygeodesy/geoids.py +28 -27
  30. pygeodesy/internals.py +156 -85
  31. pygeodesy/interns.py +23 -20
  32. pygeodesy/karney.py +61 -12
  33. pygeodesy/latlonBase.py +13 -15
  34. pygeodesy/lazily.py +206 -214
  35. pygeodesy/mgrs.py +13 -13
  36. pygeodesy/named.py +11 -10
  37. pygeodesy/nvectorBase.py +1 -1
  38. pygeodesy/points.py +2 -2
  39. pygeodesy/props.py +34 -13
  40. pygeodesy/rhumb/bases.py +5 -5
  41. pygeodesy/rhumb/solve.py +7 -8
  42. pygeodesy/solveBase.py +7 -25
  43. pygeodesy/sphericalBase.py +20 -23
  44. pygeodesy/sphericalNvector.py +24 -23
  45. pygeodesy/sphericalTrigonometry.py +9 -8
  46. pygeodesy/streprs.py +11 -8
  47. pygeodesy/trf.py +6 -4
  48. pygeodesy/triaxials.py +46 -9
  49. pygeodesy/units.py +4 -3
  50. pygeodesy/ups.py +6 -6
  51. pygeodesy/utily.py +2 -2
  52. pygeodesy/utm.py +2 -2
  53. pygeodesy/vector3d.py +5 -5
  54. pygeodesy/vector3dBase.py +4 -5
  55. {PyGeodesy-24.9.29.dist-info → PyGeodesy-24.10.24.dist-info}/WHEEL +0 -0
  56. {PyGeodesy-24.9.29.dist-info → PyGeodesy-24.10.24.dist-info}/top_level.txt +0 -0
pygeodesy/internals.py CHANGED
@@ -1,8 +1,9 @@
1
+
1
2
  # -*- coding: utf-8 -*-
2
3
 
3
4
  u'''Mostly INTERNAL functions, except L{machine}, L{print_} and L{printf}.
4
5
  '''
5
- # from pygeodesy.basics import isiterablen # _MODS
6
+ # from pygeodesy.basics import isiterablen, ubstr # _MODS
6
7
  # from pygeodesy.errors import _AttributeError, _error_init, _UnexpectedError, _xError2 # _MODS
7
8
  from pygeodesy.interns import NN, _BAR_, _COLON_, _DASH_, _DOT_, _ELLIPSIS_, _EQUALSPACED_, \
8
9
  _immutable_, _NL_, _pygeodesy_, _PyPy__, _python_, _QUOTE1_, \
@@ -10,8 +11,8 @@ from pygeodesy.interns import NN, _BAR_, _COLON_, _DASH_, _DOT_, _ELLIPSIS_, _EQ
10
11
  from pygeodesy.interns import _COMMA_, _Python_ # PYCHOK used!
11
12
  # from pygeodesy.streprs import anstr, pairs, unstr # _MODS
12
13
 
13
- import os as _os # in .lazily, ...
14
- import os.path as _os_path
14
+ # import os # _MODS
15
+ # import os.path # _MODS
15
16
  # import sys as _sys # from .interns
16
17
 
17
18
  _0_0 = 0.0 # PYCHOK in .basics, .constants
@@ -22,8 +23,8 @@ _SIsecs = 'fs', 'ps', 'ns', 'us', 'ms', 'sec' # reversed
22
23
  _Windows_ = 'Windows'
23
24
 
24
25
 
25
- def _dunder_nameof(inst, *dflt):
26
- '''(INTERNAL) Get the double_underscore __name__ attr.
26
+ def _DUNDER_nameof(inst, *dflt):
27
+ '''(INTERNAL) Get the DUNDER C{.__name__} attr.
27
28
  '''
28
29
  try:
29
30
  return inst.__name__
@@ -32,16 +33,16 @@ def _dunder_nameof(inst, *dflt):
32
33
  return dflt[0] if dflt else inst.__class__.__name__
33
34
 
34
35
 
35
- def _dunder_nameof_(*names__): # in .errors._IsnotError
36
- '''(INTERNAL) Yield the _dunder_nameof or name.
36
+ def _DUNDER_nameof_(*names__): # in .errors._IsnotError
37
+ '''(INTERNAL) Yield the _DUNDER_nameof or name.
37
38
  '''
38
- return map(_dunder_nameof, names__, names__)
39
+ return map(_DUNDER_nameof, names__, names__)
39
40
 
40
41
 
41
42
  def _Property_RO(method):
42
43
  '''(INTERNAL) Can't I{recursively} import L{props.property_RO}.
43
44
  '''
44
- name = _dunder_nameof(method)
45
+ name = _DUNDER_nameof(method)
45
46
 
46
47
  def _del(inst, attr): # PYCHOK no cover
47
48
  delattr(inst, attr) # force error
@@ -67,9 +68,16 @@ class _MODS_Base(object):
67
68
  self.__dict__.pop(attr, None)
68
69
 
69
70
  def __setattr__(self, attr, value): # PYCHOK no cover
70
- m = _MODS.errors
71
+ e = _MODS.errors
71
72
  t = _EQUALSPACED_(self._DOT_(attr), repr(value))
72
- raise m._AttributeError(_immutable_, txt=t)
73
+ raise e._AttributeError(_immutable_, txt=t)
74
+
75
+ @_Property_RO
76
+ def basics(self):
77
+ '''Get module C{pygeodesy.basics}, I{once}.
78
+ '''
79
+ from pygeodesy import basics as b # DON'T _lazy_import2
80
+ return b
73
81
 
74
82
  @_Property_RO
75
83
  def bits_machine2(self):
@@ -98,6 +106,7 @@ class _MODS_Base(object):
98
106
 
99
107
  def dlopen(name):
100
108
  return _dlopen(name, DEFAULT_MODE)
109
+
101
110
  else: # PYCHOK no cover
102
111
  from ctypes import CDLL
103
112
  dlopen = _passarg
@@ -119,8 +128,15 @@ class _MODS_Base(object):
119
128
  def errors(self):
120
129
  '''Get module C{pygeodesy.errors}, I{once}.
121
130
  '''
122
- from pygeodesy import errors # DON'T _lazy_import2
123
- return errors
131
+ from pygeodesy import errors as e # DON'T _lazy_import2
132
+ return e
133
+
134
+ @_Property_RO
135
+ def inspect(self): # in .basics
136
+ '''Get module C{inspect}, I{once}.
137
+ '''
138
+ import inspect as i
139
+ return i
124
140
 
125
141
  def ios_ver(self):
126
142
  '''Mimick C{platform.xxx_ver} for C{iOS}.
@@ -141,7 +157,7 @@ class _MODS_Base(object):
141
157
  def name(self):
142
158
  '''Get this name (C{str}).
143
159
  '''
144
- return _dunder_nameof(self.__class__)
160
+ return _DUNDER_nameof(self.__class__)
145
161
 
146
162
  @_Property_RO
147
163
  def nix2(self): # PYCHOK no cover
@@ -168,6 +184,14 @@ class _MODS_Base(object):
168
184
  t = _version2(v, n=3) if v else (NN, NN, NN)
169
185
  return v, t, machine()
170
186
 
187
+ @_Property_RO
188
+ def os(self):
189
+ '''Get module C{os}, I{once}.
190
+ '''
191
+ import os as o
192
+ import os.path
193
+ return o
194
+
171
195
  @_Property_RO
172
196
  def osversion2(self):
173
197
  '''Get 2-list C{[OS, release]}, I{once}.
@@ -192,10 +216,21 @@ class _MODS_Base(object):
192
216
  v = v()[0]
193
217
  if v and n:
194
218
  break
195
- else:
196
- n = v = NN # XXX AssertioError?
219
+ else:
220
+ n = v = NN # XXX AssertioError?
197
221
  return [n, v]
198
222
 
223
+ @_Property_RO
224
+ def _Popen_kwds2(self):
225
+ '''(INTERNAL) Get C{subprocess.Popen} and C{-kwds}.
226
+ '''
227
+ import subprocess as _sub
228
+ kwds = dict(creationflags=0, # executable=sys.executable, shell=True,
229
+ stdin=_sub.PIPE, stdout=_sub.PIPE, stderr=_sub.STDOUT)
230
+ if _sys.version_info[:2] > (3, 6):
231
+ kwds.update(text=True)
232
+ return _sub.Popen, kwds
233
+
199
234
  @_Property_RO
200
235
  def Pythonarchine(self):
201
236
  '''Get 3- or 4-list C{[PyPy, Python, bits, machine]}, I{once}.
@@ -208,46 +243,57 @@ class _MODS_Base(object):
208
243
  return l3
209
244
 
210
245
  @_Property_RO
211
- def _Str_Bytes(self):
212
- '''Get all C{str} and C{bytes} types.
246
+ def streprs(self):
247
+ '''Get module C{pygeodesy.streprs}, I{once}.
213
248
  '''
214
- import pygeodesy.basics as m
215
- return m._Strs + m._Bytes # + (range, map)
249
+ from pygeodesy import streprs as s # DON'T _lazy_import2
250
+ return s
216
251
 
217
252
  @_Property_RO
218
- def streprs(self):
219
- '''Get module C{pygeodesy.streprs}, I{once}.
253
+ def sys_version_info2(self):
254
+ '''Get C{sys.version_inf0[:2], I{once}.
220
255
  '''
221
- from pygeodesy import streprs # DON'T _lazy_import2
222
- return streprs
256
+ return _sys.version_info[:2]
223
257
 
224
258
  @_Property_RO
225
259
  def version(self):
226
260
  '''Get pygeodesy version, I{once}.
227
261
  '''
228
- from pygeodesy import version
229
- return version
262
+ from pygeodesy import version as v
263
+ return v
230
264
 
231
265
  _MODS = _MODS_Base() # PYCHOK overwritten by .lazily
232
266
 
233
267
 
234
- def _caller3(up): # in .lazily, .named
268
+ def _caller3(up, base=True): # in .lazily, .named
235
269
  '''(INTERNAL) Get 3-tuple C{(caller name, file name, line number)}
236
- for the caller B{C{up}} stack frames in the Python call stack.
237
- '''
238
- # sys._getframe(1) ... 'importlib._bootstrap' line 1032,
239
- # may throw a ValueError('call stack not deep enough')
240
- f = _sys._getframe(up + 1)
241
- c = f.f_code
242
- return (c.co_name, # caller name
243
- _os_path.basename(c.co_filename), # file name .py
244
- f.f_lineno) # line number
245
-
270
+ for the caller B{C{up}} frames back in the Python call stack.
246
271
 
247
- def _dunder_ismain(name):
248
- '''(INTERNAL) Return C{name == '__main__'}.
272
+ @kwarg base: Use C{B{base}=False} for the fully-qualified file
273
+ name, otherwise the base (module) name (C{bool}).
249
274
  '''
250
- return name == '__main__'
275
+ f = None
276
+ _f = _MODS.os.path.basename if base else _passarg
277
+ try:
278
+ f = _sys._getframe(up + 1) # == inspect.stack()[up + 1][0]
279
+ t = _MODS.inspect.getframeinfo(f)
280
+ t = t.function, _f(t.filename), t.lineno
281
+ # or ...
282
+ # f = _sys._getframe(up + 1)
283
+ # c = f.f_code
284
+ # t = (c.co_name, # caller name
285
+ # _f(c.co_filename), # file name .py
286
+ # f.f_lineno) # line number
287
+ # or ...
288
+ # t = _MODS.inspect.stack()[up + 1] # (frame, filename, lineno, function, ...)
289
+ # t = t[3], _f(t[1]), t[2]
290
+ except (AttributeError, IndexError, ValueError):
291
+ # sys._getframe(1) ... 'importlib._bootstrap' line 1032,
292
+ # may throw a ValueError('call stack not deep enough')
293
+ t = NN, NN, 0
294
+ finally:
295
+ del f # break ref cycle
296
+ return t
251
297
 
252
298
 
253
299
  def _enquote(strs, quote=_QUOTE2_, white=NN): # in .basics, .solveBase
@@ -267,6 +313,15 @@ def _fper(p, q, per=100.0, prec=1):
267
313
  return '%.*f%%' % (prec, (float(p) * per / float(q)))
268
314
 
269
315
 
316
+ _getenv = _MODS.os.getenv # PYCHOK in .lazily, ...
317
+
318
+
319
+ def _getPYGEODESY(which, dflt=NN):
320
+ '''(INTERNAL) Return an C{PYGEODESY_...} ENV value or C{dflt}.
321
+ '''
322
+ return _getenv(_PYGEODESY(which), dflt)
323
+
324
+
270
325
  def _headof(name):
271
326
  '''(INTERNAL) Get the head name of qualified C{name} or the C{name}.
272
327
  '''
@@ -280,26 +335,32 @@ def _headof(name):
280
335
  # return (a == b) if _isPyPy() else (a is b)
281
336
 
282
337
 
283
- def _isAppleM():
284
- '''(INTERNAL) Is this C{Apple Silicon}? (C{bool})
338
+ def _isAppleSi():
339
+ '''(INTERNAL) Is this C{macOS on Apple Silicon}? (C{bool})
285
340
  '''
286
341
  return _ismacOS() and machine().startswith(_arm64_)
287
342
 
288
343
 
289
- def _isiOS(): # in test/bases.py
344
+ def _is_DUNDER_main(name):
345
+ '''(INTERNAL) Return C{bool(name == '__main__')}.
346
+ '''
347
+ return name == '__main__'
348
+
349
+
350
+ def _isiOS(): # in test/bases
290
351
  '''(INTERNAL) Is this C{iOS}? (C{bool})
291
352
  '''
292
353
  return _MODS.osversion2[0] is _iOS_
293
354
 
294
355
 
295
- def _ismacOS(): # in test/bases.py
356
+ def _ismacOS(): # in test/bases
296
357
  '''(INTERNAL) Is this C{macOS}? (C{bool})
297
358
  '''
298
359
  return _sys.platform[:6] == 'darwin' and \
299
- _MODS.osversion2[0] is _macOS_ # and os.name == 'posix'
360
+ _MODS.osversion2[0] is _macOS_ # and _MODS.os.name == 'posix'
300
361
 
301
362
 
302
- def _isNix(): # in test/bases.py
363
+ def _isNix(): # in test/bases
303
364
  '''(INTERNAL) Is this a C{Linux} distro? (C{str} or L{NN})
304
365
  '''
305
366
  return _MODS.nix2[0]
@@ -312,14 +373,14 @@ def _isPyChecker():
312
373
  return _sys.argv[0].endswith('/pychecker/checker.py')
313
374
 
314
375
 
315
- def _isPyPy(): # in test/bases.py
376
+ def _isPyPy(): # in test/bases
316
377
  '''(INTERNAL) Is this C{PyPy}? (C{bool})
317
378
  '''
318
379
  # platform.python_implementation() == 'PyPy'
319
380
  return _MODS.Pythonarchine[0].startswith(_PyPy__)
320
381
 
321
382
 
322
- def _isWindows(): # in test/bases.py
383
+ def _isWindows(): # in test/bases
323
384
  '''(INTERNAL) Is this C{Windows}? (C{bool})
324
385
  '''
325
386
  return _sys.platform[:3] == 'win' and \
@@ -338,8 +399,8 @@ def _load_lib(name):
338
399
  ns = find_lib(name), name
339
400
  if dlopen is not _passarg: # _ismacOS()
340
401
  ns += (_DOT_(name, 'dylib'),
341
- _DOT_(name, 'framework'), _os_path.join(
342
- _DOT_(name, 'framework'), name))
402
+ _DOT_(name, 'framework'), _MODS.os.path.join(
403
+ _DOT_(name, 'framework'), name))
343
404
  for n in ns:
344
405
  try:
345
406
  if n and dlopen(n): # pre-load handle
@@ -363,30 +424,12 @@ def machine():
363
424
  return _MODS.bits_machine2[1]
364
425
 
365
426
 
366
- def _Math_K_2():
367
- '''(INTERNAL) Return the I{Karney} Math setting.
368
- '''
369
- return _MODS.karney._wrapped.Math_K_2
370
-
371
-
372
427
  def _name_version(pkg):
373
428
  '''(INTERNAL) Return C{pskg.__name__ + ' ' + .__version__}.
374
429
  '''
375
430
  return _SPACE_(pkg.__name__, pkg.__version__)
376
431
 
377
432
 
378
- def _name_binary(path):
379
- '''(INTERNAL) Return C{(basename + ' ' + version)} of an executable.
380
- '''
381
- if path:
382
- try:
383
- _, r = _MODS.solveBase._popen2((path, '--version'))
384
- return _SPACE_(_os_path.basename(path), r.split()[-1])
385
- except (IndexError, IOError, OSError):
386
- pass
387
- return NN
388
-
389
-
390
433
  def _osversion2(sep=NN): # in .lazily, test/bases.versions
391
434
  '''(INTERNAL) Get the O/S name and release as C{2-list} or C{str}.
392
435
  '''
@@ -412,6 +455,16 @@ def _plural(noun, n, nn=NN):
412
455
  return NN(noun, _s_) if n > 1 else (noun if n else nn)
413
456
 
414
457
 
458
+ def _popen2(cmd, stdin=None): # in .mgrs, .solveBase, .testMgrs
459
+ '''(INTERNAL) Invoke C{B{cmd} tuple} and return 2-tuple C{(std, status)}
460
+ with all C{stdout/-err} output, I{stripped} and C{int} exit status.
461
+ '''
462
+ _Popen, kwds = _MODS._Popen_kwds2
463
+ p = _Popen(cmd, **kwds) # PYCHOK kwArgs
464
+ r = p.communicate(stdin)[0] # stdout + NL + stderr
465
+ return _MODS.basics.ub2str(r).strip(), p.returncode
466
+
467
+
415
468
  def print_(*args, **nl_nt_prec_prefix__end_file_flush_sep__kwds): # PYCHOK no cover
416
469
  '''Python 3+ C{print}-like formatting and printing.
417
470
 
@@ -475,17 +528,27 @@ def _print7(nl=0, nt=0, prec=6, prefix=NN, sep=_SPACE_, file=_sys.stdout,
475
528
  return prefix, end, file, flush, prec, sep, kwds
476
529
 
477
530
 
478
- def _Pythonarchine(sep=NN): # in .lazily, test/bases.py versions
531
+ def _PYGEODESY(which, i=0):
532
+ '''(INTERNAL) Return an ENV C{str} C{PYGEODESY_...}.
533
+ '''
534
+ try:
535
+ w = which.__name__.lstrip(_UNDER_)[i:]
536
+ except AttributeError:
537
+ w = which
538
+ return _UNDER_(_pygeodesy_, w).upper()
539
+
540
+
541
+ def _Pythonarchine(sep=NN): # in .lazily, test/bases versions
479
542
  '''(INTERNAL) Get PyPy and Python versions, bits and machine as C{3- or 4-list} or C{str}.
480
543
  '''
481
544
  l3 = _MODS.Pythonarchine
482
545
  return sep.join(l3) if sep else l3 # 3- or 4-list
483
546
 
484
547
 
485
- def _secs2str(secs): # in .geoids, ../test/bases.py
548
+ def _secs2str(secs): # in .geoids, ../test/bases
486
549
  '''Convert a time in C{secs} to C{str}.
487
550
  '''
488
- if secs < _MODS.constants._100_0:
551
+ if secs < 100.0: # _100_0
489
552
  unit = len(_SIsecs) - 1
490
553
  while 0 < secs < 1 and unit > 0:
491
554
  secs *= 1e3 # _1000_0
@@ -519,7 +582,9 @@ def _sizeof(obj, deep=True):
519
582
  except TypeError: # PyPy3.10
520
583
  return None
521
584
 
522
- _isiterablen = _MODS.basics.isiterablen
585
+ b = _MODS.basics
586
+ _isiterablen = b.isiterablen
587
+ _Str_Bytes = b._Strs + b._Bytes # + (range, map)
523
588
 
524
589
  def _zR(s, iterable):
525
590
  z, _s = 0, s.add
@@ -532,7 +597,7 @@ def _sizeof(obj, deep=True):
532
597
  z += _zR(s, o.keys())
533
598
  z += _zR(s, o.values())
534
599
  elif _isiterablen(o) and not \
535
- isinstance(o, _MODS._Str_Bytes):
600
+ isinstance(o, _Str_Bytes):
536
601
  z += _zR(s, o)
537
602
  elif deep:
538
603
  try: # size instance' attr values only
@@ -554,7 +619,7 @@ def _sysctl_uint(name):
554
619
  u = uint(0)
555
620
  z = size_t(sizeof(u))
556
621
  r = libc.sysctlbyname(char_p(n), byref(u), byref(z), None, size_t(0))
557
- else: # could find or load 'libc'
622
+ else: # couldn't find or load 'libc'
558
623
  r = -2
559
624
  return int(r if r else u.value) # -1 ENOENT error, -2 no libc
560
625
 
@@ -596,17 +661,20 @@ def _usage(file_py, *args, **opts_help): # in .etm, .geodesici
596
661
 
597
662
  args = _help(**opts_help) or (tuple(_opts(**opts_help)) + args)
598
663
 
599
- u = _COLON_(_dunder_nameof(_usage)[1:], NN)
664
+ u = _COLON_(_DUNDER_nameof(_usage)[1:], NN)
600
665
  return _SPACE_(u, *_usage_argv(file_py, *args))
601
666
 
602
667
 
603
668
  def _usage_argv(argv0, *args):
604
669
  '''(INTERNAL) Return 3-tuple C{(python, '-m', module, *args)}.
605
670
  '''
606
- m = _os_path.dirname(argv0).replace(_os.getcwd(), _ELLIPSIS_) \
607
- .replace(_os.sep, _DOT_).strip()
608
- b, x = _os_path.splitext(_os_path.basename(argv0))
609
- if x == '.py' and not _dunder_ismain(b):
671
+ o = _MODS.os
672
+ m = o.path.dirname(argv0)
673
+ m = m.replace(o.getcwd(), _ELLIPSIS_) \
674
+ .replace(o.sep, _DOT_).strip()
675
+ b = o.path.basename(argv0)
676
+ b, x = o.path.splitext(b)
677
+ if x == '.py' and not _is_DUNDER_main(b):
610
678
  m = _DOT_(m or _pygeodesy_, b)
611
679
  p = NN(_python_, _sys.version_info[0])
612
680
  return (p, '-m', _enquote(m)) + args
@@ -651,15 +719,18 @@ def _versions(sep=_SPACE_):
651
719
  return sep.join(l7) if sep else l7 # 5- or 6-list
652
720
 
653
721
 
654
- __all__ = tuple(map(_dunder_nameof, (machine, print_, printf)))
655
- __version__ = '24.09.04'
722
+ __all__ = tuple(map(_DUNDER_nameof, (machine, print_, printf)))
723
+ __version__ = '24.10.20'
724
+
725
+ if _is_DUNDER_main(__name__): # PYCHOK no cover
656
726
 
657
- if _dunder_ismain(__name__): # PYCHOK no cover
727
+ def _main():
728
+ from pygeodesy import _isfrozen, isLazy
658
729
 
659
- from pygeodesy import _isfrozen, isLazy
730
+ print_(*(_versions(sep=NN) + ['_isfrozen', _isfrozen,
731
+ 'isLazy', isLazy]))
660
732
 
661
- print_(*(_versions(sep=NN) + ['_isfrozen', _isfrozen,
662
- 'isLazy', isLazy]))
733
+ _main()
663
734
 
664
735
  # **) MIT License
665
736
  #
pygeodesy/interns.py CHANGED
@@ -3,7 +3,7 @@
3
3
  u'''Single C{str}ing constants, C{intern}'ed across C{pygeodesy}
4
4
  modules and function L{pygeodesy.machine}.
5
5
  '''
6
- import sys as _sys
6
+ import sys as _sys # in .internals, .lazily
7
7
  try:
8
8
  _intern = intern # PYCHOK in .lazily, .trf
9
9
  except NameError: # Python 3+
@@ -11,7 +11,7 @@ except NameError: # Python 3+
11
11
 
12
12
  _COMMASPACE_ = ', ' # overriden below
13
13
  _SUB_PACKAGES = 'auxilats', 'deprecated', 'geodesicx', 'rhumb' # PYCHOK in ...
14
- # ... .lazily, make._dist, MANIFEST, setup.setup, test.bases, .testModules
14
+ # ... .lazily, make._dist, MANIFEST, setup.setup, test/bases, test/testModules
15
15
 
16
16
 
17
17
  class _Dash(str):
@@ -199,7 +199,8 @@ _distance_ = 'distance' # PYCHOK OK
199
199
  _distant_ = _Prefix('distant') # PYCHOK OK
200
200
  _doesn_t_exist_ = "doesn't exist" # PYCHOK OK
201
201
  _DOT_ = Str_('.') # PYCHOK OK
202
- _dunder_name_ = '__name__' # PYCHOK _DUNDER_(NN, _name_, NN)
202
+ _DUNDER_all_ = '__all__' # PYCHOK OK
203
+ _DUNDER_name_ = '__name__' # PYCHOK _DUNDER_(NN, _name_, NN)
203
204
  _duplicate_ = 'duplicate' # PYCHOK OK
204
205
  _e_ = 'e' # PYCHOK OK
205
206
  _E_ = 'E' # PYCHOK OK
@@ -309,7 +310,6 @@ _negative_ = 'negative' # PYCHOK OK
309
310
  _NL_ = Str_('\n') # PYCHOK OK
310
311
  _NLATvar_ = Str_(_NL_ + '@var ') # PYCHOK OK
311
312
  _NLHASH_ = Str_(_NL_ + '# ') # PYCHOK OK
312
- # _NLNL_ = _DNL_ # PYCHOK OK
313
313
  _NN_ = 'NN' # PYCHOK OK
314
314
  _no_ = _Prefix('no') # PYCHOK OK
315
315
  _northing_ = 'northing' # PYCHOK OK
@@ -341,7 +341,7 @@ _points_ = 'points' # PYCHOK OK
341
341
  _pole_ = 'pole' # PYCHOK OK
342
342
  _precision_ = 'precision' # PYCHOK OK
343
343
  _prime_vertical_ = 'prime_vertical' # PYCHOK OK
344
- _pygeodesy_ = 'pygeodesy' # PYCHOK OK
344
+ _pygeodesy_ = 'pygeodesy' # PYCHOK OK # in test/bases
345
345
  _pygeodesy_abspath_ = 'pygeodesy_abspath' # PYCHOK OK
346
346
  _PyPy__ = _PyPy__('PyPy ') # PYCHOK + _SPACE_
347
347
  _Python_ = _Python_('Python') # PYCHOK singleton
@@ -429,7 +429,7 @@ _SW_ = _S_ + _W_ # PYCHOK negative ones
429
429
 
430
430
  _DDOT_ = Str_(_DOT_ * 2) # PYCHOK OK
431
431
  # _DEQUAL_ = Str_(_EQUAL_ * 2) # PYCHOK OK
432
- _DNL_ = Str_(_NL_ * 2) # PYCHOK OK
432
+ # _DNL_ = Str_(_NL_ * 2) # PYCHOK OK
433
433
  # _DSLASH_ = Str_(_SLASH_ * 2) # PYCHOK OK
434
434
  # _DSTAR_ = Str_(_STAR_ * 2) # PYCHOK OK
435
435
  _DUNDER_ = Str_(_UNDER_ * 2) # PYCHOK OK
@@ -441,23 +441,26 @@ _LR_PAIRS = {_LANGLE_: _RANGLE_,
441
441
 
442
442
  __all__ = (_NN_, # NOT MISSING!
443
443
  Str_.__name__) # classes
444
- __version__ = '24.08.30'
444
+ __version__ = '24.10.19'
445
445
 
446
446
  if __name__ == '__main__':
447
447
 
448
- from pygeodesy import itemsorted, printf
449
-
450
- t = b = 0
451
- for n, v in itemsorted(locals(), asorted=False, reverse=True):
452
- if n.endswith(_UNDER_) and n.startswith(_UNDER_) and \
453
- not n.startswith(_DUNDER_):
454
- t += 1
455
- b += len(v)
456
- m = n[1:-1]
457
- if m != v and m.replace(_UNDER_, _SPACE_) != v:
458
- printf('%4d: %s = %r', t, n, v)
459
- n = len(locals())
460
- printf('%4d (%d) names, %s chars total, %.2f chars avg', t, n, b, float(b) / t, nl=1)
448
+ def _main():
449
+ from pygeodesy import itemsorted, printf
450
+
451
+ t = b = 0
452
+ for n, v in itemsorted(locals(), asorted=False, reverse=True):
453
+ if n.endswith(_UNDER_) and n.startswith(_UNDER_) and \
454
+ not n.startswith(_DUNDER_):
455
+ t += 1
456
+ b += len(v)
457
+ m = n[1:-1]
458
+ if m != v and m.replace(_UNDER_, _SPACE_) != v:
459
+ printf('%4d: %s = %r', t, n, v)
460
+ n = len(locals())
461
+ printf('%4d (%d) names, %s chars total, %.2f chars avg', t, n, b, float(b) / t, nl=1)
462
+
463
+ _main()
461
464
 
462
465
  # **) MIT License
463
466
  #
pygeodesy/karney.py CHANGED
@@ -143,18 +143,18 @@ in C{pygeodesy} are based on I{Karney}'s post U{Area of a spherical polygon
143
143
  # make sure int/int division yields float quotient, see .basics
144
144
  from __future__ import division as _; del _ # PYCHOK semicolon
145
145
 
146
- from pygeodesy.basics import _copysign, isint, neg, unsigned0, _xgeographiclib, \
147
- _zip, _version_info
146
+ from pygeodesy.basics import _copysign, isint, neg, unsigned0, \
147
+ _xgeographiclib, _zip
148
148
  from pygeodesy.constants import NAN, _isfinite as _math_isfinite, _0_0, \
149
149
  _1_16th, _1_0, _2_0, _180_0, _N_180_0, _360_0
150
150
  from pygeodesy.errors import GeodesicError, _ValueError, _xkwds
151
151
  from pygeodesy.fmath import cbrt, fremainder, norm2 # Fhorner, Fsum
152
- # from pygeodesy.internals import _version_info # from .basics
153
- from pygeodesy.interns import NN, _2_, _a12_, _area_, _azi1_, _azi2_, _azi12_, \
152
+ from pygeodesy.internals import _getenv, _popen2, _PYGEODESY, _version_info
153
+ from pygeodesy.interns import NN, _a12_, _area_, _azi1_, _azi2_, _azi12_, \
154
154
  _composite_, _lat1_, _lat2_, _lon1_, _lon2_, \
155
155
  _m12_, _M12_, _M21_, _number_, _s12_, _S12_, \
156
- _UNDER_, _X_, _BAR_ # PYCHOK used!
157
- from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, _getenv
156
+ _SPACE_, _UNDER_, _X_, _1_, _2_, _BAR_ # PYCHOK used!
157
+ from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
158
158
  from pygeodesy.named import ADict, _NamedBase, _NamedTuple, notImplemented, _Pass
159
159
  from pygeodesy.props import deprecated_method, Property_RO, property_RO, \
160
160
  property_ROnce
@@ -165,11 +165,12 @@ from pygeodesy.utily import atan2d, sincos2d, tand, _unrollon, fabs
165
165
  # from math import fabs # from .utily
166
166
 
167
167
  __all__ = _ALL_LAZY.karney
168
- __version__ = '24.09.13'
168
+ __version__ = '24.10.14'
169
169
 
170
- _K_2_0 = _getenv('PYGEODESY_GEOGRAPHICLIB', _2_)
171
- _K_2_4 = _K_2_0 == '2.4'
172
- _K_2_0 = _K_2_0 == _2_ or _K_2_4
170
+ _2_4_ = '2.4'
171
+ _K_2_0 = _getenv(_PYGEODESY(_xgeographiclib, 1), _2_)
172
+ _K_2_4 = _K_2_0 == _2_4_
173
+ _K_2_0 = _K_2_4 or (_K_2_0 == _2_)
173
174
  _perimeter_ = 'perimeter'
174
175
 
175
176
 
@@ -576,8 +577,8 @@ class _kWrapped(object): # in .geodesicw
576
577
 
577
578
  @property_RO
578
579
  def Math_K_2(self):
579
- return ('_K_2_4' if _K_2_4 else
580
- ('_K_2_0' if _K_2_0 else '_K_1_0')) if self.Math else NN
580
+ return (_2_4_ if _K_2_4 else
581
+ (_2_ if _K_2_0 else _1_)) if self.Math else NN
581
582
 
582
583
  _wrapped = _kWrapped() # PYCHOK singleton, .datum, .test/base.py
583
584
 
@@ -639,6 +640,54 @@ class Rhumb8Tuple(_GTuple):
639
640
  return _MODS.deprecated.classes.Rhumb7Tuple(self[:-1])
640
641
 
641
642
 
643
+ class _Xables(object):
644
+ '''(INTERNAL) Get I{Karney}'s executable paths from/and env vars.
645
+ '''
646
+ bin_ = '/opt/local/bin/' # '/opt/local/Cellar/geographiclib/2.3/bin/' # HomeBrew on macOS
647
+ ENV = NN
648
+
649
+ def GeoConvert(self, *dir_):
650
+ return self._path(self.GeoConvert, *dir_)
651
+
652
+ def GeodSolve(self, *dir_):
653
+ return self._path(self.GeodSolve, *dir_)
654
+
655
+ def IntersectTool(self, *dir_):
656
+ return self._path(self.IntersectTool, *dir_)
657
+
658
+ def RhumbSolve(self, *dir_):
659
+ return self._path(self.RhumbSolve, *dir_)
660
+
661
+ def name_version(self, path, base=True):
662
+ # return C{(path + ' ' + version)} of an executable
663
+ if path:
664
+ try:
665
+ r, s = _popen2((path, '--version'))
666
+ if base:
667
+ path = _MODS.os.path.basename(path)
668
+ r = _SPACE_(path, r.split()[-1])
669
+ else:
670
+ r = _MODS.streprs.Fmt.PARENSPACED(r, s)
671
+ return r
672
+ except (IndexError, IOError, OSError):
673
+ pass
674
+ return NN
675
+
676
+ def _path(self, which, *dir_):
677
+ self.ENV = E = _PYGEODESY(which)
678
+ return _getenv(E, NN) or \
679
+ (NN(dir_[0], which.__name__) if dir_ else E)
680
+
681
+ def X_not(self, path):
682
+ return 'env %s=%r not executable' % (self.ENV, path)
683
+
684
+ def X_OK(self, path): # is C{path} an executable?
685
+ os = _MODS.os # import os
686
+ return os.access(path, os.X_OK) if path else False
687
+
688
+ _Xables = _Xables() # PYCHOK singleton
689
+
690
+
642
691
  def _around(x): # in .utily.sincos2d
643
692
  '''I{Coarsen} a scalar by rounding small values to underflow to C{0.0}.
644
693