pygeodesy 24.10.10__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 (54) hide show
  1. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.10.24.dist-info}/METADATA +10 -10
  2. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.10.24.dist-info}/RECORD +54 -54
  3. pygeodesy/__init__.py +13 -13
  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 +5 -5
  19. pygeodesy/etm.py +18 -2
  20. pygeodesy/fmath.py +4 -4
  21. pygeodesy/formy.py +4 -4
  22. pygeodesy/fsums.py +22 -12
  23. pygeodesy/geodesici.py +43 -40
  24. pygeodesy/geodesicw.py +3 -3
  25. pygeodesy/geodesicx/gxarea.py +3 -2
  26. pygeodesy/geodsolve.py +73 -24
  27. pygeodesy/geohash.py +2 -2
  28. pygeodesy/geoids.py +28 -27
  29. pygeodesy/internals.py +155 -85
  30. pygeodesy/interns.py +23 -20
  31. pygeodesy/karney.py +61 -12
  32. pygeodesy/latlonBase.py +13 -15
  33. pygeodesy/lazily.py +206 -214
  34. pygeodesy/mgrs.py +13 -13
  35. pygeodesy/named.py +11 -10
  36. pygeodesy/nvectorBase.py +1 -1
  37. pygeodesy/points.py +2 -2
  38. pygeodesy/props.py +34 -13
  39. pygeodesy/rhumb/bases.py +5 -5
  40. pygeodesy/rhumb/solve.py +7 -8
  41. pygeodesy/solveBase.py +7 -25
  42. pygeodesy/sphericalBase.py +20 -23
  43. pygeodesy/sphericalNvector.py +24 -23
  44. pygeodesy/sphericalTrigonometry.py +9 -8
  45. pygeodesy/streprs.py +5 -5
  46. pygeodesy/trf.py +6 -4
  47. pygeodesy/triaxials.py +46 -9
  48. pygeodesy/units.py +4 -3
  49. pygeodesy/ups.py +6 -6
  50. pygeodesy/utily.py +2 -2
  51. pygeodesy/utm.py +2 -2
  52. pygeodesy/vector3dBase.py +4 -5
  53. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.10.24.dist-info}/WHEEL +0 -0
  54. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.10.24.dist-info}/top_level.txt +0 -0
pygeodesy/internals.py CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  u'''Mostly INTERNAL functions, except L{machine}, L{print_} and L{printf}.
5
5
  '''
6
- # from pygeodesy.basics import isiterablen # _MODS
6
+ # from pygeodesy.basics import isiterablen, ubstr # _MODS
7
7
  # from pygeodesy.errors import _AttributeError, _error_init, _UnexpectedError, _xError2 # _MODS
8
8
  from pygeodesy.interns import NN, _BAR_, _COLON_, _DASH_, _DOT_, _ELLIPSIS_, _EQUALSPACED_, \
9
9
  _immutable_, _NL_, _pygeodesy_, _PyPy__, _python_, _QUOTE1_, \
@@ -11,8 +11,8 @@ from pygeodesy.interns import NN, _BAR_, _COLON_, _DASH_, _DOT_, _ELLIPSIS_, _EQ
11
11
  from pygeodesy.interns import _COMMA_, _Python_ # PYCHOK used!
12
12
  # from pygeodesy.streprs import anstr, pairs, unstr # _MODS
13
13
 
14
- import os as _os # in .lazily, ...
15
- import os.path as _os_path
14
+ # import os # _MODS
15
+ # import os.path # _MODS
16
16
  # import sys as _sys # from .interns
17
17
 
18
18
  _0_0 = 0.0 # PYCHOK in .basics, .constants
@@ -23,8 +23,8 @@ _SIsecs = 'fs', 'ps', 'ns', 'us', 'ms', 'sec' # reversed
23
23
  _Windows_ = 'Windows'
24
24
 
25
25
 
26
- def _dunder_nameof(inst, *dflt):
27
- '''(INTERNAL) Get the double_underscore __name__ attr.
26
+ def _DUNDER_nameof(inst, *dflt):
27
+ '''(INTERNAL) Get the DUNDER C{.__name__} attr.
28
28
  '''
29
29
  try:
30
30
  return inst.__name__
@@ -33,16 +33,16 @@ def _dunder_nameof(inst, *dflt):
33
33
  return dflt[0] if dflt else inst.__class__.__name__
34
34
 
35
35
 
36
- def _dunder_nameof_(*names__): # in .errors._IsnotError
37
- '''(INTERNAL) Yield the _dunder_nameof or name.
36
+ def _DUNDER_nameof_(*names__): # in .errors._IsnotError
37
+ '''(INTERNAL) Yield the _DUNDER_nameof or name.
38
38
  '''
39
- return map(_dunder_nameof, names__, names__)
39
+ return map(_DUNDER_nameof, names__, names__)
40
40
 
41
41
 
42
42
  def _Property_RO(method):
43
43
  '''(INTERNAL) Can't I{recursively} import L{props.property_RO}.
44
44
  '''
45
- name = _dunder_nameof(method)
45
+ name = _DUNDER_nameof(method)
46
46
 
47
47
  def _del(inst, attr): # PYCHOK no cover
48
48
  delattr(inst, attr) # force error
@@ -68,9 +68,16 @@ class _MODS_Base(object):
68
68
  self.__dict__.pop(attr, None)
69
69
 
70
70
  def __setattr__(self, attr, value): # PYCHOK no cover
71
- m = _MODS.errors
71
+ e = _MODS.errors
72
72
  t = _EQUALSPACED_(self._DOT_(attr), repr(value))
73
- 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
74
81
 
75
82
  @_Property_RO
76
83
  def bits_machine2(self):
@@ -99,6 +106,7 @@ class _MODS_Base(object):
99
106
 
100
107
  def dlopen(name):
101
108
  return _dlopen(name, DEFAULT_MODE)
109
+
102
110
  else: # PYCHOK no cover
103
111
  from ctypes import CDLL
104
112
  dlopen = _passarg
@@ -120,8 +128,15 @@ class _MODS_Base(object):
120
128
  def errors(self):
121
129
  '''Get module C{pygeodesy.errors}, I{once}.
122
130
  '''
123
- from pygeodesy import errors # DON'T _lazy_import2
124
- 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
125
140
 
126
141
  def ios_ver(self):
127
142
  '''Mimick C{platform.xxx_ver} for C{iOS}.
@@ -142,7 +157,7 @@ class _MODS_Base(object):
142
157
  def name(self):
143
158
  '''Get this name (C{str}).
144
159
  '''
145
- return _dunder_nameof(self.__class__)
160
+ return _DUNDER_nameof(self.__class__)
146
161
 
147
162
  @_Property_RO
148
163
  def nix2(self): # PYCHOK no cover
@@ -169,6 +184,14 @@ class _MODS_Base(object):
169
184
  t = _version2(v, n=3) if v else (NN, NN, NN)
170
185
  return v, t, machine()
171
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
+
172
195
  @_Property_RO
173
196
  def osversion2(self):
174
197
  '''Get 2-list C{[OS, release]}, I{once}.
@@ -193,10 +216,21 @@ class _MODS_Base(object):
193
216
  v = v()[0]
194
217
  if v and n:
195
218
  break
196
- else:
197
- n = v = NN # XXX AssertioError?
219
+ else:
220
+ n = v = NN # XXX AssertioError?
198
221
  return [n, v]
199
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
+
200
234
  @_Property_RO
201
235
  def Pythonarchine(self):
202
236
  '''Get 3- or 4-list C{[PyPy, Python, bits, machine]}, I{once}.
@@ -209,46 +243,57 @@ class _MODS_Base(object):
209
243
  return l3
210
244
 
211
245
  @_Property_RO
212
- def _Str_Bytes(self):
213
- '''Get all C{str} and C{bytes} types.
246
+ def streprs(self):
247
+ '''Get module C{pygeodesy.streprs}, I{once}.
214
248
  '''
215
- import pygeodesy.basics as m
216
- return m._Strs + m._Bytes # + (range, map)
249
+ from pygeodesy import streprs as s # DON'T _lazy_import2
250
+ return s
217
251
 
218
252
  @_Property_RO
219
- def streprs(self):
220
- '''Get module C{pygeodesy.streprs}, I{once}.
253
+ def sys_version_info2(self):
254
+ '''Get C{sys.version_inf0[:2], I{once}.
221
255
  '''
222
- from pygeodesy import streprs # DON'T _lazy_import2
223
- return streprs
256
+ return _sys.version_info[:2]
224
257
 
225
258
  @_Property_RO
226
259
  def version(self):
227
260
  '''Get pygeodesy version, I{once}.
228
261
  '''
229
- from pygeodesy import version
230
- return version
262
+ from pygeodesy import version as v
263
+ return v
231
264
 
232
265
  _MODS = _MODS_Base() # PYCHOK overwritten by .lazily
233
266
 
234
267
 
235
- def _caller3(up): # in .lazily, .named
268
+ def _caller3(up, base=True): # in .lazily, .named
236
269
  '''(INTERNAL) Get 3-tuple C{(caller name, file name, line number)}
237
- for the caller B{C{up}} stack frames in the Python call stack.
238
- '''
239
- # sys._getframe(1) ... 'importlib._bootstrap' line 1032,
240
- # may throw a ValueError('call stack not deep enough')
241
- f = _sys._getframe(up + 1)
242
- c = f.f_code
243
- return (c.co_name, # caller name
244
- _os_path.basename(c.co_filename), # file name .py
245
- f.f_lineno) # line number
246
-
270
+ for the caller B{C{up}} frames back in the Python call stack.
247
271
 
248
- def _dunder_ismain(name):
249
- '''(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}).
250
274
  '''
251
- 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
252
297
 
253
298
 
254
299
  def _enquote(strs, quote=_QUOTE2_, white=NN): # in .basics, .solveBase
@@ -268,6 +313,15 @@ def _fper(p, q, per=100.0, prec=1):
268
313
  return '%.*f%%' % (prec, (float(p) * per / float(q)))
269
314
 
270
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
+
271
325
  def _headof(name):
272
326
  '''(INTERNAL) Get the head name of qualified C{name} or the C{name}.
273
327
  '''
@@ -281,26 +335,32 @@ def _headof(name):
281
335
  # return (a == b) if _isPyPy() else (a is b)
282
336
 
283
337
 
284
- def _isAppleM():
285
- '''(INTERNAL) Is this C{Apple Silicon}? (C{bool})
338
+ def _isAppleSi():
339
+ '''(INTERNAL) Is this C{macOS on Apple Silicon}? (C{bool})
286
340
  '''
287
341
  return _ismacOS() and machine().startswith(_arm64_)
288
342
 
289
343
 
290
- 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
291
351
  '''(INTERNAL) Is this C{iOS}? (C{bool})
292
352
  '''
293
353
  return _MODS.osversion2[0] is _iOS_
294
354
 
295
355
 
296
- def _ismacOS(): # in test/bases.py
356
+ def _ismacOS(): # in test/bases
297
357
  '''(INTERNAL) Is this C{macOS}? (C{bool})
298
358
  '''
299
359
  return _sys.platform[:6] == 'darwin' and \
300
- _MODS.osversion2[0] is _macOS_ # and os.name == 'posix'
360
+ _MODS.osversion2[0] is _macOS_ # and _MODS.os.name == 'posix'
301
361
 
302
362
 
303
- def _isNix(): # in test/bases.py
363
+ def _isNix(): # in test/bases
304
364
  '''(INTERNAL) Is this a C{Linux} distro? (C{str} or L{NN})
305
365
  '''
306
366
  return _MODS.nix2[0]
@@ -313,14 +373,14 @@ def _isPyChecker():
313
373
  return _sys.argv[0].endswith('/pychecker/checker.py')
314
374
 
315
375
 
316
- def _isPyPy(): # in test/bases.py
376
+ def _isPyPy(): # in test/bases
317
377
  '''(INTERNAL) Is this C{PyPy}? (C{bool})
318
378
  '''
319
379
  # platform.python_implementation() == 'PyPy'
320
380
  return _MODS.Pythonarchine[0].startswith(_PyPy__)
321
381
 
322
382
 
323
- def _isWindows(): # in test/bases.py
383
+ def _isWindows(): # in test/bases
324
384
  '''(INTERNAL) Is this C{Windows}? (C{bool})
325
385
  '''
326
386
  return _sys.platform[:3] == 'win' and \
@@ -339,8 +399,8 @@ def _load_lib(name):
339
399
  ns = find_lib(name), name
340
400
  if dlopen is not _passarg: # _ismacOS()
341
401
  ns += (_DOT_(name, 'dylib'),
342
- _DOT_(name, 'framework'), _os_path.join(
343
- _DOT_(name, 'framework'), name))
402
+ _DOT_(name, 'framework'), _MODS.os.path.join(
403
+ _DOT_(name, 'framework'), name))
344
404
  for n in ns:
345
405
  try:
346
406
  if n and dlopen(n): # pre-load handle
@@ -364,30 +424,12 @@ def machine():
364
424
  return _MODS.bits_machine2[1]
365
425
 
366
426
 
367
- def _Math_K_2():
368
- '''(INTERNAL) Return the I{Karney} Math setting.
369
- '''
370
- return _MODS.karney._wrapped.Math_K_2
371
-
372
-
373
427
  def _name_version(pkg):
374
428
  '''(INTERNAL) Return C{pskg.__name__ + ' ' + .__version__}.
375
429
  '''
376
430
  return _SPACE_(pkg.__name__, pkg.__version__)
377
431
 
378
432
 
379
- def _name_binary(path):
380
- '''(INTERNAL) Return C{(basename + ' ' + version)} of an executable.
381
- '''
382
- if path:
383
- try:
384
- _, r = _MODS.solveBase._popen2((path, '--version'))
385
- return _SPACE_(_os_path.basename(path), r.split()[-1])
386
- except (IndexError, IOError, OSError):
387
- pass
388
- return NN
389
-
390
-
391
433
  def _osversion2(sep=NN): # in .lazily, test/bases.versions
392
434
  '''(INTERNAL) Get the O/S name and release as C{2-list} or C{str}.
393
435
  '''
@@ -413,6 +455,16 @@ def _plural(noun, n, nn=NN):
413
455
  return NN(noun, _s_) if n > 1 else (noun if n else nn)
414
456
 
415
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
+
416
468
  def print_(*args, **nl_nt_prec_prefix__end_file_flush_sep__kwds): # PYCHOK no cover
417
469
  '''Python 3+ C{print}-like formatting and printing.
418
470
 
@@ -476,17 +528,27 @@ def _print7(nl=0, nt=0, prec=6, prefix=NN, sep=_SPACE_, file=_sys.stdout,
476
528
  return prefix, end, file, flush, prec, sep, kwds
477
529
 
478
530
 
479
- 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
480
542
  '''(INTERNAL) Get PyPy and Python versions, bits and machine as C{3- or 4-list} or C{str}.
481
543
  '''
482
544
  l3 = _MODS.Pythonarchine
483
545
  return sep.join(l3) if sep else l3 # 3- or 4-list
484
546
 
485
547
 
486
- def _secs2str(secs): # in .geoids, ../test/bases.py
548
+ def _secs2str(secs): # in .geoids, ../test/bases
487
549
  '''Convert a time in C{secs} to C{str}.
488
550
  '''
489
- if secs < _MODS.constants._100_0:
551
+ if secs < 100.0: # _100_0
490
552
  unit = len(_SIsecs) - 1
491
553
  while 0 < secs < 1 and unit > 0:
492
554
  secs *= 1e3 # _1000_0
@@ -520,7 +582,9 @@ def _sizeof(obj, deep=True):
520
582
  except TypeError: # PyPy3.10
521
583
  return None
522
584
 
523
- _isiterablen = _MODS.basics.isiterablen
585
+ b = _MODS.basics
586
+ _isiterablen = b.isiterablen
587
+ _Str_Bytes = b._Strs + b._Bytes # + (range, map)
524
588
 
525
589
  def _zR(s, iterable):
526
590
  z, _s = 0, s.add
@@ -533,7 +597,7 @@ def _sizeof(obj, deep=True):
533
597
  z += _zR(s, o.keys())
534
598
  z += _zR(s, o.values())
535
599
  elif _isiterablen(o) and not \
536
- isinstance(o, _MODS._Str_Bytes):
600
+ isinstance(o, _Str_Bytes):
537
601
  z += _zR(s, o)
538
602
  elif deep:
539
603
  try: # size instance' attr values only
@@ -555,7 +619,7 @@ def _sysctl_uint(name):
555
619
  u = uint(0)
556
620
  z = size_t(sizeof(u))
557
621
  r = libc.sysctlbyname(char_p(n), byref(u), byref(z), None, size_t(0))
558
- else: # could find or load 'libc'
622
+ else: # couldn't find or load 'libc'
559
623
  r = -2
560
624
  return int(r if r else u.value) # -1 ENOENT error, -2 no libc
561
625
 
@@ -597,17 +661,20 @@ def _usage(file_py, *args, **opts_help): # in .etm, .geodesici
597
661
 
598
662
  args = _help(**opts_help) or (tuple(_opts(**opts_help)) + args)
599
663
 
600
- u = _COLON_(_dunder_nameof(_usage)[1:], NN)
664
+ u = _COLON_(_DUNDER_nameof(_usage)[1:], NN)
601
665
  return _SPACE_(u, *_usage_argv(file_py, *args))
602
666
 
603
667
 
604
668
  def _usage_argv(argv0, *args):
605
669
  '''(INTERNAL) Return 3-tuple C{(python, '-m', module, *args)}.
606
670
  '''
607
- m = _os_path.dirname(argv0).replace(_os.getcwd(), _ELLIPSIS_) \
608
- .replace(_os.sep, _DOT_).strip()
609
- b, x = _os_path.splitext(_os_path.basename(argv0))
610
- 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):
611
678
  m = _DOT_(m or _pygeodesy_, b)
612
679
  p = NN(_python_, _sys.version_info[0])
613
680
  return (p, '-m', _enquote(m)) + args
@@ -652,15 +719,18 @@ def _versions(sep=_SPACE_):
652
719
  return sep.join(l7) if sep else l7 # 5- or 6-list
653
720
 
654
721
 
655
- __all__ = tuple(map(_dunder_nameof, (machine, print_, printf)))
656
- __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
657
726
 
658
- if _dunder_ismain(__name__): # PYCHOK no cover
727
+ def _main():
728
+ from pygeodesy import _isfrozen, isLazy
659
729
 
660
- from pygeodesy import _isfrozen, isLazy
730
+ print_(*(_versions(sep=NN) + ['_isfrozen', _isfrozen,
731
+ 'isLazy', isLazy]))
661
732
 
662
- print_(*(_versions(sep=NN) + ['_isfrozen', _isfrozen,
663
- 'isLazy', isLazy]))
733
+ _main()
664
734
 
665
735
  # **) MIT License
666
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