pygeodesy 24.10.10__py2.py3-none-any.whl → 24.11.11__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 (76) hide show
  1. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/METADATA +12 -12
  2. PyGeodesy-24.11.11.dist-info/RECORD +118 -0
  3. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/WHEEL +1 -1
  4. pygeodesy/__init__.py +14 -14
  5. pygeodesy/__main__.py +5 -5
  6. pygeodesy/albers.py +12 -17
  7. pygeodesy/azimuthal.py +51 -61
  8. pygeodesy/basics.py +60 -62
  9. pygeodesy/booleans.py +87 -79
  10. pygeodesy/cartesianBase.py +6 -6
  11. pygeodesy/constants.py +23 -19
  12. pygeodesy/css.py +7 -8
  13. pygeodesy/datums.py +3 -3
  14. pygeodesy/deprecated/__init__.py +1 -1
  15. pygeodesy/deprecated/classes.py +9 -9
  16. pygeodesy/deprecated/functions.py +6 -6
  17. pygeodesy/dms.py +250 -270
  18. pygeodesy/ecef.py +11 -14
  19. pygeodesy/ellipsoidalBase.py +106 -121
  20. pygeodesy/ellipsoidalBaseDI.py +114 -118
  21. pygeodesy/ellipsoidalExact.py +35 -37
  22. pygeodesy/ellipsoidalNvector.py +4 -4
  23. pygeodesy/ellipsoidalVincenty.py +2 -2
  24. pygeodesy/ellipsoids.py +10 -51
  25. pygeodesy/elliptic.py +14 -14
  26. pygeodesy/errors.py +28 -28
  27. pygeodesy/etm.py +92 -68
  28. pygeodesy/fmath.py +42 -40
  29. pygeodesy/formy.py +7 -6
  30. pygeodesy/fsums.py +72 -51
  31. pygeodesy/geodesici.py +43 -40
  32. pygeodesy/geodesicw.py +17 -16
  33. pygeodesy/geodesicx/__init__.py +2 -2
  34. pygeodesy/geodesicx/gxarea.py +3 -2
  35. pygeodesy/geodsolve.py +79 -39
  36. pygeodesy/geohash.py +2 -2
  37. pygeodesy/geoids.py +32 -31
  38. pygeodesy/heights.py +2 -2
  39. pygeodesy/internals.py +201 -147
  40. pygeodesy/interns.py +23 -20
  41. pygeodesy/karney.py +62 -13
  42. pygeodesy/ktm.py +11 -13
  43. pygeodesy/latlonBase.py +18 -20
  44. pygeodesy/lazily.py +210 -218
  45. pygeodesy/lcc.py +4 -4
  46. pygeodesy/ltp.py +10 -10
  47. pygeodesy/ltpTuples.py +74 -75
  48. pygeodesy/mgrs.py +20 -21
  49. pygeodesy/named.py +15 -10
  50. pygeodesy/nvectorBase.py +1 -1
  51. pygeodesy/osgr.py +9 -12
  52. pygeodesy/points.py +2 -2
  53. pygeodesy/props.py +35 -14
  54. pygeodesy/resections.py +9 -10
  55. pygeodesy/rhumb/__init__.py +1 -1
  56. pygeodesy/rhumb/bases.py +5 -5
  57. pygeodesy/rhumb/solve.py +9 -10
  58. pygeodesy/simplify.py +5 -5
  59. pygeodesy/solveBase.py +7 -25
  60. pygeodesy/sphericalBase.py +20 -23
  61. pygeodesy/sphericalNvector.py +103 -145
  62. pygeodesy/sphericalTrigonometry.py +68 -73
  63. pygeodesy/streprs.py +5 -5
  64. pygeodesy/trf.py +6 -4
  65. pygeodesy/triaxials.py +46 -9
  66. pygeodesy/units.py +5 -4
  67. pygeodesy/ups.py +6 -6
  68. pygeodesy/utily.py +2 -2
  69. pygeodesy/utm.py +7 -7
  70. pygeodesy/vector2d.py +13 -13
  71. pygeodesy/vector3d.py +19 -21
  72. pygeodesy/vector3dBase.py +21 -19
  73. pygeodesy/webmercator.py +4 -4
  74. pygeodesy/wgrs.py +4 -4
  75. PyGeodesy-24.10.10.dist-info/RECORD +0 -118
  76. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/top_level.txt +0 -0
pygeodesy/internals.py CHANGED
@@ -3,19 +3,20 @@
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_, \
10
- _QUOTE2_, _s_, _SPACE_, _sys, _UNDER_, _utf_8_
10
+ _QUOTE2_, _s_, _SPACE_, _sys, _UNDER_
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
19
+ _100_0 = 100.0 # in .constants
19
20
  _arm64_ = 'arm64'
20
21
  _iOS_ = 'iOS'
21
22
  _macOS_ = 'macOS'
@@ -23,8 +24,8 @@ _SIsecs = 'fs', 'ps', 'ns', 'us', 'ms', 'sec' # reversed
23
24
  _Windows_ = 'Windows'
24
25
 
25
26
 
26
- def _dunder_nameof(inst, *dflt):
27
- '''(INTERNAL) Get the double_underscore __name__ attr.
27
+ def _DUNDER_nameof(inst, *dflt):
28
+ '''(INTERNAL) Get the DUNDER C{.__name__} attr.
28
29
  '''
29
30
  try:
30
31
  return inst.__name__
@@ -33,21 +34,21 @@ def _dunder_nameof(inst, *dflt):
33
34
  return dflt[0] if dflt else inst.__class__.__name__
34
35
 
35
36
 
36
- def _dunder_nameof_(*names__): # in .errors._IsnotError
37
- '''(INTERNAL) Yield the _dunder_nameof or name.
37
+ def _DUNDER_nameof_(*names__): # in .errors._IsnotError
38
+ '''(INTERNAL) Yield the _DUNDER_nameof or name.
38
39
  '''
39
- return map(_dunder_nameof, names__, names__)
40
+ return map(_DUNDER_nameof, names__, names__)
40
41
 
41
42
 
42
43
  def _Property_RO(method):
43
- '''(INTERNAL) Can't I{recursively} import L{props.property_RO}.
44
+ '''(INTERNAL) Can't import L{props.Property_RO}, I{recursively}.
44
45
  '''
45
- name = _dunder_nameof(method)
46
+ name = _DUNDER_nameof(method)
46
47
 
47
- def _del(inst, attr): # PYCHOK no cover
48
- delattr(inst, attr) # force error
48
+ def _del(inst, *unused): # PYCHOK no cover
49
+ inst.__dict__.pop(name, None)
49
50
 
50
- def _get(inst, **unused): # PYCHOK 2 vs 3 args
51
+ def _get(inst, *unused): # PYCHOK 2 vs 3 args
51
52
  try: # to get the cached value immediately
52
53
  v = inst.__dict__[name]
53
54
  except (AttributeError, KeyError):
@@ -68,16 +69,23 @@ class _MODS_Base(object):
68
69
  self.__dict__.pop(attr, None)
69
70
 
70
71
  def __setattr__(self, attr, value): # PYCHOK no cover
71
- m = _MODS.errors
72
- t = _EQUALSPACED_(self._DOT_(attr), repr(value))
73
- raise m._AttributeError(_immutable_, txt=t)
72
+ e = _MODS.errors
73
+ n = _DOT_(self.name, attr)
74
+ t = _EQUALSPACED_(n, repr(value))
75
+ raise e._AttributeError(_immutable_, txt=t)
76
+
77
+ @_Property_RO
78
+ def basics(self):
79
+ '''Get module C{pygeodesy.basics}, I{once}.
80
+ '''
81
+ from pygeodesy import basics as b # DON'T _lazy_import2
82
+ return b
74
83
 
75
84
  @_Property_RO
76
85
  def bits_machine2(self):
77
86
  '''Get platform 2-list C{[bits, machine]}, I{once}.
78
87
  '''
79
88
  import platform as p
80
-
81
89
  m = p.machine() # ARM64, arm64, x86_64, iPhone13,2, etc.
82
90
  m = m.replace(_COMMA_, _UNDER_)
83
91
  if m.lower() == 'x86_64': # PYCHOK on Intel or Rosetta2 ...
@@ -92,67 +100,54 @@ class _MODS_Base(object):
92
100
 
93
101
  @_Property_RO
94
102
  def ctypes3(self):
95
- '''Get 3-tuple C{(ctypes.CDLL, ._dlopen, .util.findlibrary)}, I{once}.
103
+ '''Get C{ctypes.CDLL}, C{find_library} and C{dlopen}, I{once}.
96
104
  '''
97
- if _ismacOS():
98
- from ctypes import CDLL, DEFAULT_MODE, _dlopen
105
+ import ctypes as c
106
+ from ctypes.util import find_library as f
99
107
 
100
- def dlopen(name):
101
- return _dlopen(name, DEFAULT_MODE)
102
- else: # PYCHOK no cover
103
- from ctypes import CDLL
104
- dlopen = _passarg
108
+ def dlopen(name): # on macOS only
109
+ return c._dlopen(name, c.DEFAULT_MODE)
105
110
 
106
- from ctypes.util import find_library
107
- return CDLL, dlopen, find_library
111
+ return c.CDLL, f, (dlopen if _ismacOS() else None)
108
112
 
109
113
  @_Property_RO
110
- def ctypes5(self):
111
- '''Get 5-tuple C{(ctypes.byref, .c_char_p, .c_size_t, .c_uint, .sizeof)}, I{once}.
114
+ def errors(self):
115
+ '''Get module C{pygeodesy.errors}, I{once}.
112
116
  '''
113
- from ctypes import byref, c_char_p, c_size_t, c_uint, sizeof # get_errno
114
- return byref, c_char_p, c_size_t, c_uint, sizeof
115
-
116
- def _DOT_(self, name): # PYCHOK no cover
117
- return _DOT_(self.name, name)
117
+ from pygeodesy import errors as e # DON'T _lazy_import2
118
+ return e
118
119
 
119
120
  @_Property_RO
120
- def errors(self):
121
- '''Get module C{pygeodesy.errors}, I{once}.
121
+ def inspect(self): # in .basics
122
+ '''Get module C{inspect}, I{once}.
122
123
  '''
123
- from pygeodesy import errors # DON'T _lazy_import2
124
- return errors
124
+ import inspect as i
125
+ return i
125
126
 
126
127
  def ios_ver(self):
127
128
  '''Mimick C{platform.xxx_ver} for C{iOS}.
128
129
  '''
129
130
  try: # Pythonista only
130
131
  from platform import iOS_ver
131
- return iOS_ver()
132
+ t = iOS_ver()
132
133
  except (AttributeError, ImportError):
133
- return NN, (NN, NN, NN), NN
134
-
135
- @_Property_RO
136
- def libc(self):
137
- '''Load C{libc.dll|dylib}, I{once}.
138
- '''
139
- return _load_lib('libc')
134
+ t = NN, (NN, NN, NN), NN
135
+ return t
140
136
 
141
137
  @_Property_RO
142
138
  def name(self):
143
139
  '''Get this name (C{str}).
144
140
  '''
145
- return _dunder_nameof(self.__class__)
141
+ return _DUNDER_nameof(self.__class__)
146
142
 
147
143
  @_Property_RO
148
144
  def nix2(self): # PYCHOK no cover
149
- '''Get Linux 2-list C{[distro, version]}, I{once}.
145
+ '''Get Linux 2-tuple C{(distro, version)}, I{once}.
150
146
  '''
151
- import platform as p
152
-
153
- n, v = p.uname()[0], NN
147
+ from platform import uname
148
+ v, n = NN, uname()[0] # [0] == .system
154
149
  if n.lower() == 'linux':
155
- try: # use distro only for Linux, not macOS, etc.
150
+ try: # use distro only on Linux, not macOS, etc.
156
151
  import distro # <https://PyPI.org/project/distro>
157
152
  _a = _MODS.streprs.anstr
158
153
  v = _a(distro.version()) # first
@@ -169,12 +164,19 @@ class _MODS_Base(object):
169
164
  t = _version2(v, n=3) if v else (NN, NN, NN)
170
165
  return v, t, machine()
171
166
 
167
+ @_Property_RO
168
+ def os(self):
169
+ '''Get module C{os}, I{once}.
170
+ '''
171
+ import os as o
172
+ import os.path
173
+ return o
174
+
172
175
  @_Property_RO
173
176
  def osversion2(self):
174
177
  '''Get 2-list C{[OS, release]}, I{once}.
175
178
  '''
176
179
  import platform as p
177
-
178
180
  _Nix, _ = _MODS.nix2
179
181
  # - mac_ver() returns ('10.12.5', ..., 'x86_64') on
180
182
  # macOS and ('10.3.3', ..., 'iPad4,2') on iOS
@@ -193,62 +195,84 @@ class _MODS_Base(object):
193
195
  v = v()[0]
194
196
  if v and n:
195
197
  break
196
- else:
197
- n = v = NN # XXX AssertioError?
198
+ else:
199
+ n = v = NN # XXX AssertionError?
198
200
  return [n, v]
199
201
 
202
+ @_Property_RO
203
+ def _Popen_kwds2(self):
204
+ '''(INTERNAL) Get C{subprocess.Popen} and C{-kwds}.
205
+ '''
206
+ import subprocess as s
207
+ kwds = dict(creationflags=0, # executable=sys.executable, shell=True,
208
+ stdin=s.PIPE, stdout=s.PIPE, stderr=s.STDOUT)
209
+ if _MODS.sys_version_info2 > (3, 6):
210
+ kwds.update(text=True)
211
+ return s.Popen, kwds
212
+
200
213
  @_Property_RO
201
214
  def Pythonarchine(self):
202
215
  '''Get 3- or 4-list C{[PyPy, Python, bits, machine]}, I{once}.
203
216
  '''
204
217
  v = _sys.version
205
- l3 = [_Python_(v)] + self.bits_machine2
218
+ l3 = [_Python_(v)] + _MODS.bits_machine2
206
219
  pypy = _PyPy__(v)
207
220
  if pypy: # PYCHOK no cover
208
221
  l3.insert(0, pypy)
209
222
  return l3
210
223
 
211
224
  @_Property_RO
212
- def _Str_Bytes(self):
213
- '''Get all C{str} and C{bytes} types.
225
+ def streprs(self):
226
+ '''Get module C{pygeodesy.streprs}, I{once}.
214
227
  '''
215
- import pygeodesy.basics as m
216
- return m._Strs + m._Bytes # + (range, map)
228
+ from pygeodesy import streprs as s # DON'T _lazy_import2
229
+ return s
217
230
 
218
231
  @_Property_RO
219
- def streprs(self):
220
- '''Get module C{pygeodesy.streprs}, I{once}.
232
+ def sys_version_info2(self):
233
+ '''Get C{sys.version_inf0[:2], I{once}.
221
234
  '''
222
- from pygeodesy import streprs # DON'T _lazy_import2
223
- return streprs
235
+ return _sys.version_info[:2]
224
236
 
225
237
  @_Property_RO
226
238
  def version(self):
227
239
  '''Get pygeodesy version, I{once}.
228
240
  '''
229
- from pygeodesy import version
230
- return version
241
+ from pygeodesy import version as v
242
+ return v
231
243
 
232
244
  _MODS = _MODS_Base() # PYCHOK overwritten by .lazily
233
245
 
234
246
 
235
- def _caller3(up): # in .lazily, .named
247
+ def _caller3(up, base=True): # in .lazily, .named
236
248
  '''(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
249
+ for the caller B{C{up}} frames back in the Python call stack.
246
250
 
247
-
248
- def _dunder_ismain(name):
249
- '''(INTERNAL) Return C{name == '__main__'}.
251
+ @kwarg base: Use C{B{base}=False} for the fully-qualified file
252
+ name, otherwise the base (module) name (C{bool}).
250
253
  '''
251
- return name == '__main__'
254
+ f = None
255
+ _b = _MODS.os.path.basename if base else _passarg
256
+ try:
257
+ f = _sys._getframe(up + 1) # == inspect.stack()[up + 1][0]
258
+ t = _MODS.inspect.getframeinfo(f)
259
+ t = t.function, _b(t.filename), t.lineno
260
+ # or ...
261
+ # f = _sys._getframe(up + 1)
262
+ # c = f.f_code
263
+ # t = (c.co_name, # caller name
264
+ # _b(c.co_filename), # file name .py
265
+ # f.f_lineno) # line number
266
+ # or ...
267
+ # t = _MODS.inspect.stack()[up + 1] # (frame, filename, lineno, function, ...)
268
+ # t = t[3], _b(t[1]), t[2]
269
+ except (AttributeError, IndexError, ValueError):
270
+ # sys._getframe(1) ... 'importlib._bootstrap' line 1032,
271
+ # may throw a ValueError('call stack not deep enough')
272
+ t = NN, NN, 0
273
+ finally:
274
+ del f # break ref cycle
275
+ return t
252
276
 
253
277
 
254
278
  def _enquote(strs, quote=_QUOTE2_, white=NN): # in .basics, .solveBase
@@ -262,12 +286,21 @@ def _enquote(strs, quote=_QUOTE2_, white=NN): # in .basics, .solveBase
262
286
  return strs
263
287
 
264
288
 
265
- def _fper(p, q, per=100.0, prec=1):
289
+ def _fper(p, q, per=_100_0, prec=1):
266
290
  '''Format a percentage C{B{p} * B{per} / B{q}} (C{str}).
267
291
  '''
268
292
  return '%.*f%%' % (prec, (float(p) * per / float(q)))
269
293
 
270
294
 
295
+ _getenv = _MODS.os.getenv # PYCHOK in .lazily, ...
296
+
297
+
298
+ def _getPYGEODESY(which, dflt=NN):
299
+ '''(INTERNAL) Return an C{PYGEODESY_...} ENV value or C{dflt}.
300
+ '''
301
+ return _getenv(_PYGEODESY(which), dflt)
302
+
303
+
271
304
  def _headof(name):
272
305
  '''(INTERNAL) Get the head name of qualified C{name} or the C{name}.
273
306
  '''
@@ -281,46 +314,52 @@ def _headof(name):
281
314
  # return (a == b) if _isPyPy() else (a is b)
282
315
 
283
316
 
284
- def _isAppleM():
285
- '''(INTERNAL) Is this C{Apple Silicon}? (C{bool})
317
+ def _isAppleSi(): # PYCHOK no cover
318
+ '''(INTERNAL) Is this C{macOS on Apple Silicon}? (C{bool})
286
319
  '''
287
320
  return _ismacOS() and machine().startswith(_arm64_)
288
321
 
289
322
 
290
- def _isiOS(): # in test/bases.py
323
+ def _is_DUNDER_main(name):
324
+ '''(INTERNAL) Return C{bool(name == '__main__')}.
325
+ '''
326
+ return name == '__main__'
327
+
328
+
329
+ def _isiOS(): # in test/bases
291
330
  '''(INTERNAL) Is this C{iOS}? (C{bool})
292
331
  '''
293
332
  return _MODS.osversion2[0] is _iOS_
294
333
 
295
334
 
296
- def _ismacOS(): # in test/bases.py
335
+ def _ismacOS(): # in test/bases
297
336
  '''(INTERNAL) Is this C{macOS}? (C{bool})
298
337
  '''
299
338
  return _sys.platform[:6] == 'darwin' and \
300
- _MODS.osversion2[0] is _macOS_ # and os.name == 'posix'
339
+ _MODS.osversion2[0] is _macOS_ # and _MODS.os.name == 'posix'
301
340
 
302
341
 
303
- def _isNix(): # in test/bases.py
342
+ def _isNix(): # in test/bases
304
343
  '''(INTERNAL) Is this a C{Linux} distro? (C{str} or L{NN})
305
344
  '''
306
345
  return _MODS.nix2[0]
307
346
 
308
347
 
309
- def _isPyChecker():
348
+ def _isPyChecker(): # PYCHOK no cover
310
349
  '''(INTERNAL) Is C{PyChecker} running? (C{bool}).
311
350
  '''
312
351
  # .../pychecker/checker.py --limit 0 --stdlib pygeodesy/<mod>/<name>.py
313
352
  return _sys.argv[0].endswith('/pychecker/checker.py')
314
353
 
315
354
 
316
- def _isPyPy(): # in test/bases.py
355
+ def _isPyPy(): # in test/bases
317
356
  '''(INTERNAL) Is this C{PyPy}? (C{bool})
318
357
  '''
319
358
  # platform.python_implementation() == 'PyPy'
320
359
  return _MODS.Pythonarchine[0].startswith(_PyPy__)
321
360
 
322
361
 
323
- def _isWindows(): # in test/bases.py
362
+ def _isWindows(): # in test/bases
324
363
  '''(INTERNAL) Is this C{Windows}? (C{bool})
325
364
  '''
326
365
  return _sys.platform[:3] == 'win' and \
@@ -330,17 +369,19 @@ def _isWindows(): # in test/bases.py
330
369
  def _load_lib(name):
331
370
  '''(INTERNAL) Load a C{dylib}, B{C{name}} must startwith('lib').
332
371
  '''
333
- # macOS 11+ (aka 10.16) no longer provides direct loading of
334
- # system libraries. As a result, C{ctypes.util.find_library}
335
- # will not find any library, unless previously installed by a
336
- # low-level dlopen(name) call (with the library base C{name}).
337
- CDLL, dlopen, find_lib = _MODS.ctypes3
338
-
372
+ CDLL, find_lib, dlopen = _MODS.ctypes3
339
373
  ns = find_lib(name), name
340
- if dlopen is not _passarg: # _ismacOS()
374
+ if dlopen:
375
+ # macOS 11+ (aka 10.16) no longer provides direct loading of
376
+ # system libraries. As a result, C{ctypes.util.find_library}
377
+ # will not find any library, unless previously installed by a
378
+ # low-level dlopen(name) call (with the library base C{name}).
341
379
  ns += (_DOT_(name, 'dylib'),
342
- _DOT_(name, 'framework'), _os_path.join(
343
- _DOT_(name, 'framework'), name))
380
+ _DOT_(name, 'framework'), _MODS.os.path.join(
381
+ _DOT_(name, 'framework'), name))
382
+ else: # not macOS
383
+ dlopen = _passarg # no-op
384
+
344
385
  for n in ns:
345
386
  try:
346
387
  if n and dlopen(n): # pre-load handle
@@ -364,30 +405,12 @@ def machine():
364
405
  return _MODS.bits_machine2[1]
365
406
 
366
407
 
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
408
  def _name_version(pkg):
374
409
  '''(INTERNAL) Return C{pskg.__name__ + ' ' + .__version__}.
375
410
  '''
376
411
  return _SPACE_(pkg.__name__, pkg.__version__)
377
412
 
378
413
 
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
414
  def _osversion2(sep=NN): # in .lazily, test/bases.versions
392
415
  '''(INTERNAL) Get the O/S name and release as C{2-list} or C{str}.
393
416
  '''
@@ -413,6 +436,16 @@ def _plural(noun, n, nn=NN):
413
436
  return NN(noun, _s_) if n > 1 else (noun if n else nn)
414
437
 
415
438
 
439
+ def _popen2(cmd, stdin=None): # in .mgrs, .solveBase, .testMgrs
440
+ '''(INTERNAL) Invoke C{B{cmd} tuple} and return 2-tuple C{(std, status)}
441
+ with all C{stdout/-err} output, I{stripped} and C{int} exit status.
442
+ '''
443
+ _Popen, kwds = _MODS._Popen_kwds2
444
+ p = _Popen(cmd, **kwds) # PYCHOK kwArgs
445
+ r = p.communicate(stdin)[0] # stdout + NL + stderr
446
+ return _MODS.basics.ub2str(r).strip(), p.returncode
447
+
448
+
416
449
  def print_(*args, **nl_nt_prec_prefix__end_file_flush_sep__kwds): # PYCHOK no cover
417
450
  '''Python 3+ C{print}-like formatting and printing.
418
451
 
@@ -476,17 +509,27 @@ def _print7(nl=0, nt=0, prec=6, prefix=NN, sep=_SPACE_, file=_sys.stdout,
476
509
  return prefix, end, file, flush, prec, sep, kwds
477
510
 
478
511
 
479
- def _Pythonarchine(sep=NN): # in .lazily, test/bases.py versions
512
+ def _PYGEODESY(which, i=0):
513
+ '''(INTERNAL) Return an ENV C{str} C{PYGEODESY_...}.
514
+ '''
515
+ try:
516
+ w = which.__name__.lstrip(_UNDER_)[i:]
517
+ except AttributeError:
518
+ w = which
519
+ return _UNDER_(_pygeodesy_, w).upper()
520
+
521
+
522
+ def _Pythonarchine(sep=NN): # in .lazily, test/bases versions
480
523
  '''(INTERNAL) Get PyPy and Python versions, bits and machine as C{3- or 4-list} or C{str}.
481
524
  '''
482
525
  l3 = _MODS.Pythonarchine
483
526
  return sep.join(l3) if sep else l3 # 3- or 4-list
484
527
 
485
528
 
486
- def _secs2str(secs): # in .geoids, ../test/bases.py
529
+ def _secs2str(secs): # in .geoids, ../test/bases
487
530
  '''Convert a time in C{secs} to C{str}.
488
531
  '''
489
- if secs < _MODS.constants._100_0:
532
+ if secs < _100_0:
490
533
  unit = len(_SIsecs) - 1
491
534
  while 0 < secs < 1 and unit > 0:
492
535
  secs *= 1e3 # _1000_0
@@ -520,7 +563,9 @@ def _sizeof(obj, deep=True):
520
563
  except TypeError: # PyPy3.10
521
564
  return None
522
565
 
523
- _isiterablen = _MODS.basics.isiterablen
566
+ b = _MODS.basics
567
+ _isiterablen = b.isiterablen
568
+ _Str_Bytes = b._Strs + b._Bytes # + (range, map)
524
569
 
525
570
  def _zR(s, iterable):
526
571
  z, _s = 0, s.add
@@ -533,7 +578,7 @@ def _sizeof(obj, deep=True):
533
578
  z += _zR(s, o.keys())
534
579
  z += _zR(s, o.values())
535
580
  elif _isiterablen(o) and not \
536
- isinstance(o, _MODS._Str_Bytes):
581
+ isinstance(o, _Str_Bytes):
537
582
  z += _zR(s, o)
538
583
  elif deep:
539
584
  try: # size instance' attr values only
@@ -546,18 +591,18 @@ def _sizeof(obj, deep=True):
546
591
 
547
592
 
548
593
  def _sysctl_uint(name):
549
- '''(INTERNAL) Get an unsigned int sysctl item by name, use on macOS ONLY!
594
+ '''(INTERNAL) Get an C{unsigned int sysctl} item by name, I{ONLY on macOS!}
550
595
  '''
551
- libc = _MODS.libc
596
+ libc = _load_lib('libc') if _ismacOS() else None
552
597
  if libc: # <https://StackOverflow.com/questions/759892/python-ctypes-and-sysctl>
553
- byref, char_p, size_t, uint, sizeof = _MODS.ctypes5
554
- n = name if str is bytes else bytes(name, _utf_8_) # PYCHOK isPython2 = str is bytes
555
- u = uint(0)
556
- z = size_t(sizeof(u))
557
- r = libc.sysctlbyname(char_p(n), byref(u), byref(z), None, size_t(0))
558
- else: # could find or load 'libc'
598
+ import ctypes as c
599
+ n = c.c_char_p(_MODS.basics.str2ub(name)) # bytes(name, _utf_8_)
600
+ u = c.c_uint(0)
601
+ z = c.c_size_t(c.sizeof(u))
602
+ r = libc.sysctlbyname(n, c.byref(u), c.byref(z), None, c.c_size_t(0)) # PYCHOK attr
603
+ else: # not macOS or couldn't find or load 'libc'=
559
604
  r = -2
560
- return int(r if r else u.value) # -1 ENOENT error, -2 no libc
605
+ return int(r if r else u.value) # -1 ENOENT error, -2 no libc or not macOS
561
606
 
562
607
 
563
608
  def _tailof(name):
@@ -573,7 +618,7 @@ def _under(name): # PYCHOK in .datums, .auxilats, .ups, .utm, .utmupsBase, ...
573
618
  return name if name.startswith(_UNDER_) else NN(_UNDER_, name)
574
619
 
575
620
 
576
- def _usage(file_py, *args, **opts_help): # in .etm, .geodesici
621
+ def _usage(file_py, *args, **opts_help): # in .etm, .geodesici # PYCHOK no cover
577
622
  '''(INTERNAL) Build "usage: python -m ..." cmd line for module B{C{file_py}}.
578
623
  '''
579
624
  if opts_help:
@@ -597,19 +642,22 @@ def _usage(file_py, *args, **opts_help): # in .etm, .geodesici
597
642
 
598
643
  args = _help(**opts_help) or (tuple(_opts(**opts_help)) + args)
599
644
 
600
- u = _COLON_(_dunder_nameof(_usage)[1:], NN)
645
+ u = _COLON_(_DUNDER_nameof(_usage)[1:], NN)
601
646
  return _SPACE_(u, *_usage_argv(file_py, *args))
602
647
 
603
648
 
604
649
  def _usage_argv(argv0, *args):
605
650
  '''(INTERNAL) Return 3-tuple C{(python, '-m', module, *args)}.
606
651
  '''
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):
652
+ o = _MODS.os
653
+ m = o.path.dirname(argv0)
654
+ m = m.replace(o.getcwd(), _ELLIPSIS_) \
655
+ .replace(o.sep, _DOT_).strip()
656
+ b = o.path.basename(argv0)
657
+ b, x = o.path.splitext(b)
658
+ if x == '.py' and not _is_DUNDER_main(b):
611
659
  m = _DOT_(m or _pygeodesy_, b)
612
- p = NN(_python_, _sys.version_info[0])
660
+ p = NN(_python_, _MODS.sys_version_info2[0])
613
661
  return (p, '-m', _enquote(m)) + args
614
662
 
615
663
 
@@ -622,7 +670,7 @@ def _version2(version, n=2):
622
670
  return t[:n]
623
671
 
624
672
 
625
- def _version_info(package): # in .Base.karney, .basics
673
+ def _version_info(package): # in .basics, .karney._kWrapped.Math
626
674
  '''(INTERNAL) Get the C{package.__version_info__} as a 2- or
627
675
  3-tuple C{(major, minor, revision)} if C{int}s.
628
676
  '''
@@ -646,21 +694,27 @@ def _version_ints(vs):
646
694
 
647
695
 
648
696
  def _versions(sep=_SPACE_):
649
- '''(INTERNAL) Get pygeodesy, PyPy and Python versions, bits, machine and OS as C{7- or 8-list} or C{str}.
697
+ '''(INTERNAL) Get pygeodesy, PyPy and Python versions, bits, machine and OS as C{8- or 9-list} or C{str}.
650
698
  '''
651
699
  l7 = [_pygeodesy_, _MODS.version] + _Pythonarchine() + _osversion2()
652
700
  return sep.join(l7) if sep else l7 # 5- or 6-list
653
701
 
654
702
 
655
- __all__ = tuple(map(_dunder_nameof, (machine, print_, printf)))
656
- __version__ = '24.09.04'
703
+ __all__ = tuple(map(_DUNDER_nameof, (machine, print_, printf)))
704
+ __version__ = '24.11.06'
705
+
706
+ if _is_DUNDER_main(__name__): # PYCHOK no cover
707
+
708
+ def _main():
709
+ from pygeodesy import _isfrozen, isLazy
657
710
 
658
- if _dunder_ismain(__name__): # PYCHOK no cover
711
+ print_(*(_versions(sep=NN) + ['_isfrozen', _isfrozen,
712
+ 'isLazy', isLazy]))
659
713
 
660
- from pygeodesy import _isfrozen, isLazy
714
+ _main()
661
715
 
662
- print_(*(_versions(sep=NN) + ['_isfrozen', _isfrozen,
663
- 'isLazy', isLazy]))
716
+ # % python3 -m pygeodesy.internals
717
+ # pygeodesy 24.11.11 Python 3.13.0 64bit arm64 macOS 14.6.1 _isfrozen False isLazy 1
664
718
 
665
719
  # **) MIT License
666
720
  #