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/internals.py ADDED
@@ -0,0 +1,571 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ u'''Mostly INTERNAL functions, except L{machine}, L{print_} and L{printf}.
4
+ '''
5
+ # from pygeodesy.basics import isiterablen # _MODS
6
+ # from pygeodesy.errors import _AttributeError, _error_init, _xError2 # _MODS
7
+ from pygeodesy.interns import NN, _COLON_, _DOT_, _ELLIPSIS_, _EQUALSPACED_, \
8
+ _immutable_, _NL_, _pygeodesy_, _PyPy__, _python_, \
9
+ _QUOTE1_, _QUOTE2_, _SPACE_, _UNDER_, _utf_8_
10
+ from pygeodesy.interns import _COMMA_, _sys, _Python_ # PYCHOK used!
11
+ # from pygeodesy.streprs import anstr, pairs, unstr # _MODS
12
+
13
+ import os as _os # in .lazily, ...
14
+ import os.path as _os_path
15
+ # import sys as _sys # from .interns
16
+
17
+ _0_0 = 0.0 # PYCHOK in .basics, .constants
18
+ _arm64_ = 'arm64'
19
+ _iOS_ = 'iOS'
20
+ _macOS_ = 'macOS'
21
+ _Windows_ = 'Windows'
22
+
23
+
24
+ def _dunder_nameof(inst, *dflt):
25
+ '''(INTERNAL) Get the double_underscore __name__ attr.
26
+ '''
27
+ try:
28
+ return inst.__name__
29
+ except AttributeError:
30
+ pass
31
+ return dflt[0] if dflt else inst.__class__.__name__
32
+
33
+
34
+ def _Property_RO(method):
35
+ '''(INTERNAL) Can't Irecursively import L{props.property_RO}.
36
+ '''
37
+ name = _dunder_nameof(method)
38
+
39
+ def _del(inst, attr): # PYCHOK no cover
40
+ delattr(inst, attr) # force error
41
+
42
+ def _get(inst, **unused): # PYCHOK 2 vs 3 args
43
+ try: # to get the cached value immediately
44
+ v = inst.__dict__[name]
45
+ except (AttributeError, KeyError):
46
+ # cache the value in the instance' __dict__
47
+ inst.__dict__[name] = v = method(inst)
48
+ return v
49
+
50
+ def _set(inst, val): # PYCHOK no cover
51
+ setattr(inst, name, val) # force error
52
+
53
+ return property(_get, _set, _del)
54
+
55
+
56
+ class _ALL_MODS_Base(object):
57
+ '''(INTERNAL) Base-class for C{lazily._ALL_MODS}.
58
+ '''
59
+ def __delattr__(self, attr): # PYCHOK no cover
60
+ self.__dict__.pop(attr, None)
61
+
62
+ def __setattr__(self, attr, value): # PYCHOK no cover
63
+ m = _MODS.errors
64
+ t = _EQUALSPACED_(self._DOT_(attr), repr(value))
65
+ raise m._AttributeError(_immutable_, txt=t)
66
+
67
+ @_Property_RO
68
+ def bits_machine2(self):
69
+ '''Get platform 2-list C{[bits, machine]}, I{once}.
70
+ '''
71
+ import platform as p
72
+
73
+ m = p.machine() # ARM64, arm64, x86_64, iPhone13,2, etc.
74
+ m = m.replace(_COMMA_, _UNDER_)
75
+ if m.lower() == 'x86_64': # PYCHOK on Intel or Rosetta2 ...
76
+ v = p.mac_ver()[0] # ... and only on macOS ...
77
+ if v and _version2(v) > (10, 15): # ... 11+ aka 10.16
78
+ # <https://Developer.Apple.com/forums/thread/659846>
79
+ # _sysctl_uint('hw.optional.arm64') and \
80
+ if _sysctl_uint('sysctl.proc_translated'):
81
+ m = _UNDER_(_arm64_, m) # Apple Si emulating Intel x86-64
82
+ return [p.architecture()[0], # bits
83
+ m] # arm64, arm64_x86_64, x86_64, etc.
84
+
85
+ @_Property_RO
86
+ def ctypes3(self):
87
+ '''Get 3-tuple C{(ctypes.CDLL, ._dlopen, .util.findlibrary)}, I{once}.
88
+ '''
89
+ if _ismacOS():
90
+ from ctypes import CDLL, DEFAULT_MODE, _dlopen
91
+
92
+ def dlopen(name):
93
+ return _dlopen(name, DEFAULT_MODE)
94
+ else: # PYCHOK no cover
95
+ from ctypes import CDLL
96
+ dlopen = _passarg
97
+
98
+ from ctypes.util import find_library
99
+ return CDLL, dlopen, find_library
100
+
101
+ @_Property_RO
102
+ def ctypes5(self):
103
+ '''Get 5-tuple C{(ctypes.byref, .c_char_p, .c_size_t, .c_uint, .sizeof)}, I{once}.
104
+ '''
105
+ from ctypes import byref, c_char_p, c_size_t, c_uint, sizeof # get_errno
106
+ return byref, c_char_p, c_size_t, c_uint, sizeof
107
+
108
+ def _DOT_(self, name): # PYCHOK no cover
109
+ return _DOT_(self.name, name)
110
+
111
+ @_Property_RO
112
+ def errors(self):
113
+ '''Get module C{pygeodesy.errors}, I{once}.
114
+ '''
115
+ from pygeodesy import errors # DON'T _lazy_import2
116
+ return errors
117
+
118
+ def ios_ver(self):
119
+ '''Mimick C{platform.xxx_ver} for C{iOS}.
120
+ '''
121
+ try: # Pythonista only
122
+ from platform import iOS_ver
123
+ return iOS_ver()
124
+ except (AttributeError, ImportError):
125
+ return NN, (NN, NN, NN), NN
126
+
127
+ @_Property_RO
128
+ def libc(self):
129
+ '''Load C{libc.dll|dylib}, I{once}.
130
+ '''
131
+ return _load_lib('libc')
132
+
133
+ @_Property_RO
134
+ def name(self):
135
+ '''Get this name (C{str}).
136
+ '''
137
+ return _dunder_nameof(self.__class__)
138
+
139
+ @_Property_RO
140
+ def nix2(self): # PYCHOK no cover
141
+ '''Get Linux 2-list C{[distro, version]}, I{once}.
142
+ '''
143
+ import platform as p
144
+
145
+ n, v = p.uname()[0], NN
146
+ if n.lower() == 'linux':
147
+ try: # use distro only for Linux, not macOS, etc.
148
+ import distro # <https://PyPI.org/project/distro>
149
+ _a = _MODS.streprs.anstr
150
+ v = _a(distro.version()) # first
151
+ n = _a(distro.id()) # .name()?
152
+ except (AttributeError, ImportError):
153
+ pass # v = str(_0_0)
154
+ n = n.capitalize()
155
+ return n, v
156
+
157
+ def nix_ver(self): # PYCHOK no cover
158
+ '''Mimick C{platform.xxx_ver} for C{*nix}.
159
+ '''
160
+ _, v = _MODS.nix2
161
+ t = _version2(v, n=3) if v else (NN, NN, NN)
162
+ return v, t, machine()
163
+
164
+ @_Property_RO
165
+ def osversion2(self):
166
+ '''Get 2-list C{[OS, release]}, I{once}.
167
+ '''
168
+ import platform as p
169
+
170
+ _Nix, _ = _MODS.nix2
171
+ # - mac_ver() returns ('10.12.5', ..., 'x86_64') on
172
+ # macOS and ('10.3.3', ..., 'iPad4,2') on iOS
173
+ # - win32_ver is ('XP', ..., 'SP3', ...) on Windows XP SP3
174
+ # - platform() returns 'Darwin-16.6.0-x86_64-i386-64bit'
175
+ # on macOS and 'Darwin-16.6.0-iPad4,2-64bit' on iOS
176
+ # - sys.platform is 'darwin' on macOS, 'ios' on iOS,
177
+ # 'win32' on Windows and 'cygwin' on Windows/Gygwin
178
+ # - distro.id() and .name() return 'Darwin' on macOS
179
+ for n, v in ((_iOS_, _MODS.ios_ver),
180
+ (_macOS_, p.mac_ver),
181
+ (_Windows_, p.win32_ver),
182
+ (_Nix, _MODS.nix_ver),
183
+ ('Java', p.java_ver),
184
+ ('uname', p.uname)):
185
+ v = v()[0]
186
+ if v and n:
187
+ break
188
+ else:
189
+ n = v = NN # XXX AssertioError?
190
+ return [n, v]
191
+
192
+ @_Property_RO
193
+ def Pythonarchine(self):
194
+ '''Get 3- or 4-list C{[PyPy, Python, bits, machine]}, I{once}.
195
+ '''
196
+ v = _sys.version
197
+ l3 = [_Python_(v)] + self.bits_machine2
198
+ pypy = _PyPy__(v)
199
+ if pypy: # PYCHOK no cover
200
+ l3.insert(0, pypy)
201
+ return l3
202
+
203
+ @_Property_RO
204
+ def streprs(self):
205
+ '''Get module C{pygeodesy.streprs}, I{once}.
206
+ '''
207
+ from pygeodesy import streprs # DON'T _lazy_import2
208
+ return streprs
209
+
210
+ _MODS = _ALL_MODS_Base() # PYCHOK overwritten by .lazily
211
+
212
+
213
+ def _caller3(up): # in .lazily, .named
214
+ '''(INTERNAL) Get 3-tuple C{(caller name, file name, line number)}
215
+ for the caller B{C{up}} stack frames in the Python call stack.
216
+ '''
217
+ # sys._getframe(1) ... 'importlib._bootstrap' line 1032,
218
+ # may throw a ValueError('call stack not deep enough')
219
+ f = _sys._getframe(up + 1)
220
+ return (f.f_code.co_name, # caller name
221
+ _os_path.basename(f.f_code.co_filename), # file name
222
+ f.f_lineno) # line number
223
+
224
+
225
+ def _dunder_main(name):
226
+ '''(INTERNAL) Return C{name == '__main__'}.
227
+ '''
228
+ return name == '__main__'
229
+
230
+
231
+ def _enquote(strs, quote=_QUOTE2_, white=NN): # in .basics, .solveBase
232
+ '''(INTERNAL) Enquote a string containing whitespace or replace
233
+ whitespace by C{white} if specified.
234
+ '''
235
+ if strs:
236
+ t = strs.split()
237
+ if len(t) > 1:
238
+ strs = white.join(t if white else (quote, strs, quote))
239
+ return strs
240
+
241
+
242
+ def _headof(name):
243
+ '''(INTERNAL) Get the head name of qualified C{name} or the C{name}.
244
+ '''
245
+ i = name.find(_DOT_)
246
+ return name if i < 0 else name[:i]
247
+
248
+
249
+ # def _is(a, b): # PYCHOK no cover
250
+ # '''(INTERNAL) C{a is b}? in C{PyPy}
251
+ # '''
252
+ # return (a == b) if _isPyPy() else (a is b)
253
+
254
+
255
+ def _isAppleM():
256
+ '''(INTERNAL) Is this C{Apple Silicon}? (C{bool})
257
+ '''
258
+ return _ismacOS() and machine().startswith(_arm64_)
259
+
260
+
261
+ def _isiOS(): # in test/bases.py
262
+ '''(INTERNAL) Is this C{iOS}? (C{bool})
263
+ '''
264
+ return _MODS.osversion2[0] is _iOS_
265
+
266
+
267
+ def _ismacOS(): # in test/bases.py
268
+ '''(INTERNAL) Is this C{macOS}? (C{bool})
269
+ '''
270
+ return _sys.platform[:6] == 'darwin' and \
271
+ _MODS.osversion2[0] is _macOS_ # and os.name == 'posix'
272
+
273
+
274
+ def _isNix(): # in test/bases.py
275
+ '''(INTERNAL) Is this a C{Linux} distro? (C{str} or L{NN})
276
+ '''
277
+ return _MODS.nix2[0]
278
+
279
+
280
+ def _isPyPy(): # in test/bases.py
281
+ '''(INTERNAL) Is this C{PyPy}? (C{bool})
282
+ '''
283
+ # platform.python_implementation() == 'PyPy'
284
+ return _MODS.Pythonarchine[0].startswith(_PyPy__)
285
+
286
+
287
+ def _isWindows(): # in test/bases.py
288
+ '''(INTERNAL) Is this C{Windows}? (C{bool})
289
+ '''
290
+ return _sys.platform[:3] == 'win' and \
291
+ _MODS.osversion2[0] is _Windows_
292
+
293
+
294
+ def _load_lib(name):
295
+ '''(INTERNAL) Load a C{dylib}, B{C{name}} must startwith('lib').
296
+ '''
297
+ # macOS 11+ (aka 10.16) no longer provides direct loading of
298
+ # system libraries. As a result, C{ctypes.util.find_library}
299
+ # will not find any library, unless previously installed by a
300
+ # low-level dlopen(name) call (with the library base C{name}).
301
+ CDLL, dlopen, find_lib = _MODS.ctypes3
302
+
303
+ ns = find_lib(name), name
304
+ if dlopen is not _passarg: # _ismacOS()
305
+ ns += (_DOT_(name, 'dylib'),
306
+ _DOT_(name, 'framework'), _os_path.join(
307
+ _DOT_(name, 'framework'), name))
308
+ for n in ns:
309
+ try:
310
+ if n and dlopen(n): # pre-load handle
311
+ lib = CDLL(n) # == ctypes.cdll.LoadLibrary(n)
312
+ if lib._name: # has a qualified name
313
+ return lib
314
+ except (AttributeError, OSError):
315
+ pass
316
+
317
+ return None # raise OSError
318
+
319
+
320
+ def machine():
321
+ '''Return standard C{platform.machine}, but distinguishing Intel I{native}
322
+ from Intel I{emulation} on Apple Silicon (on macOS only).
323
+
324
+ @return: Machine C{'arm64'} for Apple Silicon I{native}, C{'x86_64'}
325
+ for Intel I{native}, C{"arm64_x86_64"} for Intel I{emulation},
326
+ etc. (C{str} with C{comma}s replaced by C{underscore}s).
327
+ '''
328
+ return _MODS.bits_machine2[1]
329
+
330
+
331
+ def _name_version(pkg):
332
+ '''(INTERNAL) Return C{pskg.__name__ + ' ' + .__version__}.
333
+ '''
334
+ return _SPACE_(pkg.__name__, pkg.__version__)
335
+
336
+
337
+ def _osversion2(sep=NN): # in .lazily, test/bases.versions
338
+ '''(INTERNAL) Get the O/S name and release as C{2-list} or C{str}.
339
+ '''
340
+ l2 = _MODS.osversion2
341
+ return sep.join(l2) if sep else l2 # 2-list()
342
+
343
+
344
+ def _passarg(arg):
345
+ '''(INTERNAL) Helper, no-op.
346
+ '''
347
+ return arg
348
+
349
+
350
+ def _passargs(*args):
351
+ '''(INTERNAL) Helper, no-op.
352
+ '''
353
+ return args
354
+
355
+
356
+ def print_(*args, **nl_nt_prec_prefix__end_file_flush_sep_kwds): # PYCHOK no cover
357
+ '''Python 3+ C{print}-like formatting and printing.
358
+
359
+ @arg args: Values to be converted to C{str} and joined by B{C{sep}},
360
+ all positional.
361
+
362
+ @see: Function L{printf} for further details.
363
+ '''
364
+ return printf(NN, *args, **nl_nt_prec_prefix__end_file_flush_sep_kwds)
365
+
366
+
367
+ def printf(fmt, *args, **nl_nt_prec_prefix__end_file_flush_sep_kwds):
368
+ '''C{Printf-style} and Python 3+ C{print}-like formatting and printing.
369
+
370
+ @arg fmt: U{Printf-style<https://Docs.Python.org/3/library/stdtypes.html#
371
+ printf-style-string-formatting>} format specification (C{str}).
372
+ @arg args: Arguments to be formatted (any C{type}, all positional).
373
+ @kwarg nl_nt_prec_prefix__end_file_flush_sep_kwds: Optional keyword arguments
374
+ C{B{nl}=0} for the number of leading blank lines (C{int}), C{B{nt}=0}
375
+ the number of trailing blank lines (C{int}), C{B{prefix}=NN} to be
376
+ inserted before the formatted text (C{str}) and Python 3+ C{print}
377
+ keyword arguments C{B{end}}, C{B{sep}}, C{B{file}} and C{B{flush}}.
378
+ Any remaining C{B{kwds}} are C{printf-style} name-value pairs to be
379
+ formatted, I{iff no B{C{args}} are present} using C{B{prec}=6} for
380
+ the number of decimal digits (C{int}).
381
+
382
+ @return: Number of bytes written.
383
+ '''
384
+ b, e, f, fl, p, s, kwds = _print7(**nl_nt_prec_prefix__end_file_flush_sep_kwds)
385
+ try:
386
+ if args:
387
+ t = (fmt % args) if fmt else s.join(map(str, args))
388
+ elif kwds:
389
+ t = (fmt % kwds) if fmt else s.join(
390
+ _MODS.streprs.pairs(kwds, prec=p))
391
+ else:
392
+ t = fmt
393
+ except Exception as x:
394
+ _E, s = _MODS.errors._xError2(x)
395
+ unstr = _MODS.streprs.unstr
396
+ t = unstr(printf, fmt, *args, **nl_nt_prec_prefix__end_file_flush_sep_kwds)
397
+ raise _E(s, txt=t, cause=x)
398
+ try:
399
+ n = f.write(NN(b, t, e))
400
+ except UnicodeEncodeError: # XXX only Windows
401
+ t = t.replace('\u2032', _QUOTE1_).replace('\u2033', _QUOTE2_)
402
+ n = f.write(NN(b, t, e))
403
+ if fl: # PYCHOK no cover
404
+ f.flush()
405
+ return n
406
+
407
+
408
+ def _print7(nl=0, nt=0, prec=6, prefix=NN, sep=_SPACE_, file=_sys.stdout,
409
+ end=_NL_, flush=False, **kwds):
410
+ '''(INTERNAL) Unravel the C{printf} and remaining keyword arguments.
411
+ '''
412
+ if nl > 0:
413
+ prefix = NN(_NL_ * nl, prefix)
414
+ if nt > 0:
415
+ end = NN(end, _NL_ * nt)
416
+ return prefix, end, file, flush, prec, sep, kwds
417
+
418
+
419
+ def _Pythonarchine(sep=NN): # in .lazily, test/bases.py versions
420
+ '''(INTERNAL) Get PyPy and Python versions, bit and machine as C{3- or 4-list} or C{str}.
421
+ '''
422
+ l3 = _MODS.Pythonarchine
423
+ return sep.join(l3) if sep else l3 # 3- or 4-list
424
+
425
+
426
+ def _sizeof(obj):
427
+ '''(INTERNAL) Recursively size an C{obj}ect.
428
+
429
+ @return: The C{obj} size in bytes (C{int}),
430
+ ignoring class attributes and
431
+ counting duplicates only once or
432
+ C{None}.
433
+
434
+ @note: With C{PyPy}, the size is always C{None}.
435
+ '''
436
+ try:
437
+ _zB = _sys.getsizeof
438
+ _zD = _zB(None) # some default
439
+ except TypeError: # PyPy3.10
440
+ return None
441
+
442
+ _isiterablen = _MODS.basics.isiterablen
443
+
444
+ def _zR(s, iterable):
445
+ z, _s = 0, s.add
446
+ for o in iterable:
447
+ i = id(o)
448
+ if i not in s:
449
+ _s(i)
450
+ z += _zB(o, _zD)
451
+ if isinstance(o, dict):
452
+ z += _zR(s, o.keys())
453
+ z += _zR(s, o.values())
454
+ elif _isiterablen(o): # not map, ...
455
+ z += _zR(s, o)
456
+ else:
457
+ try: # size instance' attr values only
458
+ z += _zR(s, o.__dict__.values())
459
+ except AttributeError: # None, int, etc.
460
+ pass
461
+ return z
462
+
463
+ return _zR(set(), (obj,))
464
+
465
+
466
+ def _sysctl_uint(name):
467
+ '''(INTERNAL) Get an unsigned int sysctl item by name, use on macOS ONLY!
468
+ '''
469
+ libc = _MODS.libc
470
+ if libc: # <https://StackOverflow.com/questions/759892/python-ctypes-and-sysctl>
471
+ byref, char_p, size_t, uint, sizeof = _MODS.ctypes5
472
+ n = name if str is bytes else bytes(name, _utf_8_) # PYCHOK isPython2 = str is bytes
473
+ u = uint(0)
474
+ z = size_t(sizeof(u))
475
+ r = libc.sysctlbyname(char_p(n), byref(u), byref(z), None, size_t(0))
476
+ else: # could find or load 'libc'
477
+ r = -2
478
+ return int(r if r else u.value) # -1 ENOENT error, -2 no libc
479
+
480
+
481
+ def _tailof(name):
482
+ '''(INTERNAL) Get the base name of qualified C{name} or the C{name}.
483
+ '''
484
+ i = name.rfind(_DOT_) + 1
485
+ return name[i:] if i > 0 else name
486
+
487
+
488
+ def _under(name): # PYCHOK in .datums, .auxilats, .ups, .utm, .utmupsBase, ...
489
+ '''(INTERNAL) Prefix C{name} with an I{underscore}.
490
+ '''
491
+ return name if name.startswith(_UNDER_) else NN(_UNDER_, name)
492
+
493
+
494
+ def _usage(file_py, *args): # in .etm
495
+ '''(INTERNAL) Build "usage: python -m ..." cmd line for module B{C{file_py}}.
496
+ '''
497
+ m = _os_path.dirname(file_py).replace(_os.getcwd(), _ELLIPSIS_) \
498
+ .replace(_os.sep, _DOT_).strip()
499
+ b, x = _os_path.splitext(_os_path.basename(file_py))
500
+ if x == '.py' and not _dunder_main(b):
501
+ m = _DOT_(m or _pygeodesy_, b)
502
+ p = NN(_python_, _sys.version_info[0])
503
+ u = _COLON_(_dunder_nameof(_usage)[1:], NN)
504
+ return _SPACE_(u, p, '-m', _enquote(m), *args)
505
+
506
+
507
+ def _version2(version, n=2):
508
+ '''(INTERNAL) Split C{B{version} str} into a C{1-, 2- or 3-tuple} of C{int}s.
509
+ '''
510
+ t = _version_ints(version.split(_DOT_, 2))
511
+ if len(t) < n:
512
+ t += (0,) * n
513
+ return t[:n]
514
+
515
+
516
+ def _version_info(package): # in .Base.karney, .basics
517
+ '''(INTERNAL) Get the C{package.__version_info__} as a 2- or
518
+ 3-tuple C{(major, minor, revision)} if C{int}s.
519
+ '''
520
+ try:
521
+ return _version_ints(package.__version_info__)
522
+ except AttributeError:
523
+ return _version2(package.__version__.strip(), n=3)
524
+
525
+
526
+ def _version_ints(vs):
527
+ # helper for _version2 and _version_info above
528
+
529
+ def _ints(vs):
530
+ for v in vs:
531
+ try:
532
+ yield int(v.strip())
533
+ except (TypeError, ValueError):
534
+ pass
535
+
536
+ return tuple(_ints(vs))
537
+
538
+
539
+ __all__ = (machine.__name__,
540
+ print_.__name__, printf.__name__) # _dunder_nameof
541
+ __version__ = '24.05.15'
542
+
543
+ if _dunder_main(__name__): # PYCHOK no cover
544
+
545
+ from pygeodesy import _isfrozen, isLazy, version as vs
546
+
547
+ print_(_pygeodesy_, vs, *(_Pythonarchine() + _osversion2()
548
+ + ['isfrozen', _isfrozen,
549
+ 'isLazy', isLazy]))
550
+
551
+ # **) MIT License
552
+ #
553
+ # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
554
+ #
555
+ # Permission is hereby granted, free of charge, to any person obtaining a
556
+ # copy of this software and associated documentation files (the "Software"),
557
+ # to deal in the Software without restriction, including without limitation
558
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
559
+ # and/or sell copies of the Software, and to permit persons to whom the
560
+ # Software is furnished to do so, subject to the following conditions:
561
+ #
562
+ # The above copyright notice and this permission notice shall be included
563
+ # in all copies or substantial portions of the Software.
564
+ #
565
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
566
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
567
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
568
+ # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
569
+ # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
570
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
571
+ # OTHER DEALINGS IN THE SOFTWARE.