pygeodesy 25.1.9__py2.py3-none-any.whl → 25.4.25__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 (96) hide show
  1. pygeodesy/__init__.py +35 -31
  2. pygeodesy/__main__.py +3 -3
  3. pygeodesy/albers.py +29 -36
  4. pygeodesy/auxilats/_CX_4.py +2 -2
  5. pygeodesy/auxilats/_CX_6.py +2 -2
  6. pygeodesy/auxilats/_CX_8.py +2 -2
  7. pygeodesy/auxilats/_CX_Rs.py +59 -40
  8. pygeodesy/auxilats/__init__.py +3 -3
  9. pygeodesy/auxilats/__main__.py +9 -7
  10. pygeodesy/auxilats/auxAngle.py +2 -2
  11. pygeodesy/auxilats/auxLat.py +13 -13
  12. pygeodesy/auxilats/auxily.py +13 -9
  13. pygeodesy/azimuthal.py +7 -6
  14. pygeodesy/basics.py +65 -22
  15. pygeodesy/booleans.py +12 -10
  16. pygeodesy/cartesianBase.py +21 -20
  17. pygeodesy/clipy.py +11 -10
  18. pygeodesy/constants.py +11 -10
  19. pygeodesy/css.py +14 -11
  20. pygeodesy/datums.py +8 -8
  21. pygeodesy/deprecated/bases.py +2 -2
  22. pygeodesy/deprecated/classes.py +2 -2
  23. pygeodesy/deprecated/consterns.py +4 -4
  24. pygeodesy/dms.py +8 -8
  25. pygeodesy/ecef.py +10 -7
  26. pygeodesy/elevations.py +9 -8
  27. pygeodesy/ellipsoidalBase.py +19 -8
  28. pygeodesy/ellipsoidalBaseDI.py +17 -15
  29. pygeodesy/ellipsoidalNvector.py +6 -3
  30. pygeodesy/ellipsoidalVincenty.py +4 -1
  31. pygeodesy/ellipsoids.py +167 -138
  32. pygeodesy/elliptic.py +9 -9
  33. pygeodesy/errors.py +44 -43
  34. pygeodesy/etm.py +9 -9
  35. pygeodesy/fmath.py +10 -9
  36. pygeodesy/formy.py +11 -12
  37. pygeodesy/frechet.py +216 -109
  38. pygeodesy/fstats.py +5 -4
  39. pygeodesy/fsums.py +107 -122
  40. pygeodesy/gars.py +7 -7
  41. pygeodesy/geodesici.py +15 -14
  42. pygeodesy/geodesicw.py +34 -32
  43. pygeodesy/geodesicx/__init__.py +1 -1
  44. pygeodesy/geodesicx/__main__.py +12 -10
  45. pygeodesy/geodesicx/gx.py +30 -33
  46. pygeodesy/geodesicx/gxarea.py +2 -2
  47. pygeodesy/geodesicx/gxline.py +5 -5
  48. pygeodesy/geodsolve.py +18 -17
  49. pygeodesy/geohash.py +7 -8
  50. pygeodesy/geoids.py +35 -34
  51. pygeodesy/hausdorff.py +17 -13
  52. pygeodesy/heights.py +2 -4
  53. pygeodesy/internals.py +31 -46
  54. pygeodesy/interns.py +12 -9
  55. pygeodesy/iters.py +8 -8
  56. pygeodesy/karney.py +73 -66
  57. pygeodesy/ktm.py +5 -5
  58. pygeodesy/latlonBase.py +14 -18
  59. pygeodesy/lazily.py +73 -74
  60. pygeodesy/lcc.py +11 -9
  61. pygeodesy/ltp.py +8 -7
  62. pygeodesy/ltpTuples.py +2 -2
  63. pygeodesy/mgrs.py +7 -6
  64. pygeodesy/named.py +47 -31
  65. pygeodesy/nvectorBase.py +7 -7
  66. pygeodesy/osgr.py +9 -8
  67. pygeodesy/points.py +12 -10
  68. pygeodesy/props.py +25 -25
  69. pygeodesy/resections.py +11 -10
  70. pygeodesy/rhumb/__init__.py +1 -1
  71. pygeodesy/rhumb/aux_.py +14 -14
  72. pygeodesy/rhumb/bases.py +22 -20
  73. pygeodesy/rhumb/ekx.py +6 -6
  74. pygeodesy/rhumb/solve.py +15 -15
  75. pygeodesy/solveBase.py +3 -3
  76. pygeodesy/sphericalBase.py +6 -6
  77. pygeodesy/sphericalNvector.py +6 -5
  78. pygeodesy/sphericalTrigonometry.py +8 -7
  79. pygeodesy/streprs.py +14 -14
  80. pygeodesy/trf.py +14 -12
  81. pygeodesy/triaxials.py +29 -26
  82. pygeodesy/units.py +5 -4
  83. pygeodesy/unitsBase.py +5 -4
  84. pygeodesy/ups.py +3 -3
  85. pygeodesy/utily.py +4 -4
  86. pygeodesy/utmups.py +4 -4
  87. pygeodesy/utmupsBase.py +88 -18
  88. pygeodesy/vector2d.py +18 -11
  89. pygeodesy/vector3d.py +7 -6
  90. pygeodesy/webmercator.py +6 -5
  91. pygeodesy/wgrs.py +6 -5
  92. {pygeodesy-25.1.9.dist-info → pygeodesy-25.4.25.dist-info}/METADATA +35 -31
  93. pygeodesy-25.4.25.dist-info/RECORD +118 -0
  94. pygeodesy-25.1.9.dist-info/RECORD +0 -118
  95. {pygeodesy-25.1.9.dist-info → pygeodesy-25.4.25.dist-info}/WHEEL +0 -0
  96. {pygeodesy-25.1.9.dist-info → pygeodesy-25.4.25.dist-info}/top_level.txt +0 -0
@@ -5,23 +5,22 @@ u'''Print L{auxilats} version, etc. using C{python -m pygeodesy.auxilats}.
5
5
  '''
6
6
 
7
7
  __all__ = ()
8
- __version__ = '24.09.04'
8
+ __version__ = '25.04.14'
9
9
 
10
10
 
11
11
  def _main(**ALorder): # PYCHOK no cover
12
12
 
13
13
  try:
14
- from pygeodesy import auxilats
14
+ from pygeodesy import ADict, auxilats
15
15
  from pygeodesy.internals import _fper, _name_version, \
16
16
  printf, _versions
17
- from pygeodesy.interns import _COMMASPACE_, _EQUAL_
17
+ from pygeodesy.interns import _COMMASPACE_
18
18
 
19
19
  A = auxilats.AuxLat(**ALorder)
20
20
  Cx = A._CXcoeffs # PropertyRO: Adict of _Rdicts
21
21
  b, n, u, z = Cx.bnuz4()
22
- p = dict(ALorder=A.ALorder,CXb=b, CXb_z=_fper(b, z),
23
- CXn=n, CXu=u, CXu_n=_fper(u, n))
24
- p = list(_EQUAL_(*t) for t in p.items())
22
+ p = ADict(ALorder=A.ALorder, CXb=b, CXb_z=_fper(b, z),
23
+ CXn=n, CXu=u, CXu_n=_fper(u, n))._toL()
25
24
  try:
26
25
  import geographiclib
27
26
  p.append(_name_version(geographiclib))
@@ -36,9 +35,12 @@ def _main(**ALorder): # PYCHOK no cover
36
35
  print(_usage(__file__))
37
36
 
38
37
 
39
- from sys import argv # .internals._isPyChecker
38
+ from sys import argv # .internals._isPyChOK
40
39
  _main(ALorder=int(argv[1])) if len(argv) == 2 and argv[1].isdigit() else _main()
41
40
 
41
+ # % python3.13 -m pygeodesy.auxilats
42
+ # pygeodesy.auxilats 25.04.14: ALorder=6, CXb=11099, CXb_z=64.1%, CXn=522, CXu=448, CXu_n=85.8%, geographiclib 2.0 (pygeodesy 25.4.24 Python 3.13.3 64bit arm64 macOS 15.4)
43
+
42
44
  # % python3.12 -m pygeodesy.auxilats 8
43
45
  # pygeodesy.auxilats 24.09.04: ALorder=8, CXb=20310, CXb_z=71.5%, CXn=888, CXu=780, CXu_n=87.8%, geographiclib 2.0 (pygeodesy 24.9.9 Python 3.12.5 64bit arm64 macOS 14.6.1)
44
46
 
@@ -32,7 +32,7 @@ from pygeodesy.utily import atan2, atan2d, sincos2, sincos2d
32
32
  from math import asinh, copysign, degrees, fabs, radians, sinh
33
33
 
34
34
  __all__ = ()
35
- __version__ = '24.11.24'
35
+ __version__ = '25.04.14'
36
36
 
37
37
  _0_INF_NAN_NINF = (0, _0_0) + _INF_NAN_NINF
38
38
  _MAX_2 = MAX * _0_5 # PYCHOK used!
@@ -207,7 +207,7 @@ class AuxAngle(_Named):
207
207
  def _copy_2(self, which):
208
208
  '''(INTERNAL) Copy for I{dyadic} operators.
209
209
  '''
210
- return _Named.copy(self, deep=False, name=which.__name__)
210
+ return _Named.copy(self, deep=False, name__=which)
211
211
 
212
212
  def _copy_r2(self, other, which):
213
213
  '''(INTERNAL) Copy for I{reverse-dyadic} operators.
@@ -9,8 +9,8 @@ Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2022-2024) and lice
9
9
  under the MIT/X11 License. For more information, see the U{GeographicLib
10
10
  <https://GeographicLib.SourceForge.io>} documentation.
11
11
 
12
- @see: U{Auxiliary latitudes<https:#GeographicLib.SourceForge.io/C++/doc/auxlat.html>}
13
- U{On auxiliary latitudes<https:#ArXiv.org/abs/2212.05818>}.
12
+ @see: U{Auxiliary latitudes<https://GeographicLib.SourceForge.io/C++/doc/auxlat.html>}
13
+ U{On auxiliary latitudes<https://ArXiv.org/abs/2212.05818>}.
14
14
  '''
15
15
  # make sure int/int division yields float quotient, see .basics
16
16
  from __future__ import division as _; del _ # PYCHOK semicolon
@@ -18,8 +18,8 @@ from __future__ import division as _; del _ # PYCHOK semicolon
18
18
  from pygeodesy.auxilats.auxAngle import AuxAngle, AuxBeta, AuxChi, _AuxClass, \
19
19
  AuxMu, AuxPhi, AuxTheta, AuxXi
20
20
  from pygeodesy.auxilats.auxily import Aux, _sc, _sn
21
- from pygeodesy.auxilats._CX_Rs import _Rdict, _Rtuple
22
- from pygeodesy.basics import _reverange, _xinstanceof, _passarg
21
+ from pygeodesy.auxilats._CX_Rs import _Rdict, _Rkey, _Rtuple
22
+ from pygeodesy.basics import _isin, _reverange, _xinstanceof, _passarg
23
23
  from pygeodesy.constants import INF, MAX_EXP, MIN_EXP, NAN, PI_2, PI_4, _EPSqrt, \
24
24
  _0_0, _0_0s, _0_1, _0_5, _1_0, _2_0, _3_0, _360_0, \
25
25
  _log2, _over, isfinite, isinf, isnan
@@ -48,7 +48,7 @@ except ImportError: # Python 3.11-
48
48
  return pow(_2_0, x)
49
49
 
50
50
  __all__ = ()
51
- __version__ = '24.09.03'
51
+ __version__ = '25.04.14'
52
52
 
53
53
  _TRIPS = 1024 # XXX 2 or 3?
54
54
 
@@ -90,7 +90,7 @@ class AuxLat(AuxAngle):
90
90
  else:
91
91
  name = NN
92
92
  try:
93
- if a_earth not in (_EWGS84, _WGS84):
93
+ if not _isin(a_earth, _EWGS84, _WGS84):
94
94
  n = _name__(name, name__=AuxLat)
95
95
  if b is f is None:
96
96
  E = _ellipsoidal_datum(a_earth, name=n).ellipsoid # XXX raiser=_earth_
@@ -829,16 +829,16 @@ def _Newton(tphi, Zeta, _toZeta, **name):
829
829
 
830
830
 
831
831
  _AR2Coeffs = _Rdict(18,
832
- _Rtuple(4, 4, '4/315, 4/105, 4/15, -1/3'),
833
- _Rtuple(6, 6, '4/1287, 4/693, 4/15, 4/105, 4/315, -1/3'),
834
- _Rtuple(8, 8, '4/3315, 4/2145, 4/1287, 4/693, 4/315, 4/105, 4/15, -1/3'))
832
+ _Rtuple(_Rkey(4), 4, '4/315, 4/105, 4/15, -1/3'),
833
+ _Rtuple(_Rkey(6), 6, '4/1287, 4/693, 4/15, 4/105, 4/315, -1/3'),
834
+ _Rtuple(_Rkey(8), 8, '4/3315, 4/2145, 4/1287, 4/693, 4/315, 4/105, 4/15, -1/3'))
835
835
 
836
836
  _RRCoeffs = _Rdict(9,
837
- _Rtuple(4, 2, '1/64, 1/4'),
838
- _Rtuple(6, 3, '1/256, 1/64, 1/4'),
839
- _Rtuple(8, 4, '25/16384, 1/256, 1/64, 1/4')) # PYCHOK used!
837
+ _Rtuple(_Rkey(4), 2, '1/64, 1/4'),
838
+ _Rtuple(_Rkey(6), 3, '1/256, 1/64, 1/4'),
839
+ _Rtuple(_Rkey(8), 4, '25/16384, 1/256, 1/64, 1/4')) # PYCHOK used!
840
840
 
841
- del _Rdict, _Rtuple
841
+ del _Rdict, _Rkey, _Rtuple
842
842
  # assert set(_AR2Coeffs.keys()) == set(_RRCoeffs.keys())
843
843
 
844
844
  # AuxLat._Lmax = max(_AR2Coeffs.keys()) # == max(ALorder)
@@ -15,10 +15,13 @@ under the MIT/X11 License. For more information, see the U{GeographicLib
15
15
  from __future__ import division as _; del _ # PYCHOK semicolon
16
16
 
17
17
  # from pygeodesy import auxilats # _MODS
18
+ from pygeodesy.auxilats._CX_Rs import _Rkey
19
+ from pygeodesy.basics import _isin, typename
18
20
  from pygeodesy.constants import INF, NAN, isinf, isnan, _0_0, _0_5, _1_0, \
19
21
  _copysign_1_0, _over, _1_over
20
22
  from pygeodesy.errors import AuxError
21
23
  from pygeodesy.fmath import hypot1 as _sc, hypot2_
24
+ # from pygeodesy.internals import typename # from .basics
22
25
  from pygeodesy.interns import NN, _DOT_, _UNDER_ # PYCHOK used!
23
26
  from pygeodesy.lazily import _ALL_DOCS, _ALL_MODS as _MODS # PYCHOK used!
24
27
  from pygeodesy.utily import atan1
@@ -26,19 +29,19 @@ from pygeodesy.utily import atan1
26
29
  from math import asinh, copysign
27
30
 
28
31
  __all__ = ()
29
- __version__ = '24.09.03'
32
+ __version__ = '25.04.14'
30
33
 
31
34
 
32
35
  class Aux(object):
33
36
  '''Enum-style Aux names.
34
37
  '''
35
38
  _coeffs = {}
36
- GEOGRAPHIC = PHI = GEODETIC = 0
37
- PARAMETRIC = BETA = REDUCED = 1
38
- GEOCENTRIC = THETA = 2 # all ...
39
- RECTIFYING = MU = 3 # use n^2
40
- CONFORMAL = CHI = 4 # use n
41
- AUTHALIC = XI = 5 # use n
39
+ GEOGRAPHIC = PHI = GEODETIC = _Rkey(0)
40
+ PARAMETRIC = BETA = REDUCED = _Rkey(1)
41
+ GEOCENTRIC = THETA = _Rkey(2) # all ...
42
+ RECTIFYING = MU = _Rkey(3) # use n^2
43
+ CONFORMAL = CHI = _Rkey(4) # use n
44
+ AUTHALIC = XI = _Rkey(5) # use n
42
45
  N = 6
43
46
  N2 = 36
44
47
 
@@ -57,7 +60,7 @@ class Aux(object):
57
60
  _coeffs = Aux._coeffs[aL]
58
61
  except KeyError:
59
62
  try: # from pygeodesy.auxilats._CX_x import _coeffs_x as _coeffs
60
- _CX_x = _DOT_(_MODS.auxilats.__name__, _UNDER_('_CX', aL))
63
+ _CX_x = _DOT_(typename(_MODS.auxilats), _UNDER_('_CX', aL))
61
64
  _coeffs = _MODS.getattr(_CX_x, _UNDER_('_coeffs', aL))
62
65
  except (AttributeError, ImportError, KeyError, TypeError) as x:
63
66
  raise AuxError(ALorder=aL, cause=x)
@@ -91,7 +94,7 @@ class Aux(object):
91
94
  return (auxout - auxin) if max(auxin, auxout) < Aux.MU else None
92
95
 
93
96
  def use_n2(self, aux):
94
- return aux not in (Aux.CHI, Aux.XI)
97
+ return not _isin(aux, Aux.CHI, Aux.XI)
95
98
 
96
99
  Aux = Aux() # PYCHOK singleton
97
100
 
@@ -228,6 +231,7 @@ def _sn(tx):
228
231
 
229
232
 
230
233
  __all__ += _ALL_DOCS(Aux.__class__)
234
+ del _Rkey
231
235
 
232
236
  # **) MIT License
233
237
  #
pygeodesy/azimuthal.py CHANGED
@@ -42,19 +42,20 @@ altitude in Earth radii<https://WikiPedia.org/wiki/Azimuthal_equidistant_project
42
42
  # make sure int/int division yields float quotient, see .basics
43
43
  from __future__ import division as _; del _ # PYCHOK semicolon
44
44
 
45
- # from pygeodesy.basics import _xinstanceof # from .ellipsoidalBase
45
+ # from pygeodesy.basics import _isin, _xinstanceof # from .ellipsoidalBase
46
46
  from pygeodesy.constants import EPS, EPS0, EPS1, NAN, isnon0, _umod_360, \
47
47
  _EPStol, _0_0, _0_1, _0_5, _1_0, _N_1_0, _2_0
48
48
  from pygeodesy.ellipsoidalBase import LatLonEllipsoidalBase as _LLEB, \
49
- _xinstanceof
49
+ _isin, _xinstanceof
50
50
  from pygeodesy.datums import _spherical_datum, _WGS84
51
51
  from pygeodesy.errors import _ValueError, _xdatum, _xkwds
52
52
  from pygeodesy.fmath import euclid, fdot_, hypot as _hypot, Fsum
53
53
  # from pygeodesy.fsums import Fsum # from .fmath
54
54
  # from pygeodesy.formy import antipode # _MODS
55
+ # from pygeodesy.internals import typename # from .karney
55
56
  from pygeodesy.interns import _azimuth_, _datum_, _lat_, _lon_, _scale_, \
56
57
  _SPACE_, _x_, _y_
57
- from pygeodesy.karney import _norm180
58
+ from pygeodesy.karney import _norm180, typename
58
59
  from pygeodesy.latlonBase import _MODS, LatLonBase as _LLB
59
60
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _FOR_DOCS # ALL_MODS
60
61
  from pygeodesy.named import _name__, _name2__, _NamedBase, _NamedTuple, _Pass
@@ -70,7 +71,7 @@ from pygeodesy.utily import asin1, atan1, atan2, atan2b, atan2d, \
70
71
  from math import acos, degrees, fabs, sin, sqrt
71
72
 
72
73
  __all__ = _ALL_LAZY.azimuthal
73
- __version__ = '24.11.24'
74
+ __version__ = '25.04.14'
74
75
 
75
76
  _EPS_K = _EPStol * _0_1 # Karney's eps_ or _EPSmin * _0_1?
76
77
  _over_horizon_ = 'over horizon'
@@ -112,7 +113,7 @@ class _AzimuthalBase(_NamedBase):
112
113
 
113
114
  @raise TypeError: Invalid B{C{datum}}.
114
115
  '''
115
- if datum not in (None, self._datum):
116
+ if not _isin(datum, None, self._datum):
116
117
  self._datum = _spherical_datum(datum, **name)
117
118
  if name:
118
119
  self.name = name
@@ -1088,7 +1089,7 @@ class Stereographic(_AzimuthalBase):
1088
1089
  def k0(self, factor):
1089
1090
  '''Set the central scale factor (C{scalar}).
1090
1091
  '''
1091
- n = Stereographic.k0.fget.__name__ # 'k0', name__=Stereographic.k0.fget
1092
+ n = typename(Stereographic.k0.fget) # 'k0', name__=Stereographic.k0.fget
1092
1093
  self._k0 = Scalar_(factor, name=n, low=EPS, high=2) # XXX high=1, 2, other?
1093
1094
  self._k02 = self._k0 * _2_0
1094
1095
 
pygeodesy/basics.py CHANGED
@@ -20,8 +20,8 @@ from pygeodesy.errors import _AttributeError, _ImportError, _NotImplementedError
20
20
  _TypeError, _TypesError, _ValueError, _xAssertionError, \
21
21
  _xkwds_get1
22
22
  # from pygeodesy.fsums import _isFsum_2Tuple # _MODS
23
- from pygeodesy.internals import _0_0, _enquote, _getenv, _passarg, _PYGEODESY, \
24
- _version_info
23
+ from pygeodesy.internals import _0_0, _enquote, _envPYGEODESY, _getenv, _passarg, \
24
+ _PYGEODESY_ENV, typename, _version_info
25
25
  from pygeodesy.interns import MISSING, NN, _1_, _by_, _COMMA_, _DOT_, _DEPRECATED_, \
26
26
  _ELLIPSIS4_, _EQUAL_, _in_, _invalid_, _N_A_, _not_, \
27
27
  _not_scalar_, _odd_, _SPACE_, _UNDER_, _version_
@@ -37,7 +37,7 @@ from math import copysign as _copysign
37
37
  # import inspect as _inspect # _MODS
38
38
 
39
39
  __all__ = _ALL_LAZY.basics
40
- __version__ = '24.12.31'
40
+ __version__ = '25.04.14'
41
41
 
42
42
  _below_ = 'below'
43
43
  _list_tuple_types = (list, tuple)
@@ -207,6 +207,22 @@ def _enumereverse(iterable):
207
207
  yield j, iterable[j]
208
208
 
209
209
 
210
+ try:
211
+ from math import gcd as _gcd
212
+ except ImportError: # 3.4-
213
+
214
+ def _gcd(a, b): # PYCHOK redef
215
+ # <https://WikiPedia.org/wiki/Greatest_common_divisor>
216
+ a, b = int(a), int(b)
217
+ if b > a:
218
+ a, b = b, a
219
+ # if b <= 0:
220
+ # return 1
221
+ while b:
222
+ a, b = b, (a % b)
223
+ return a
224
+
225
+
210
226
  def halfs2(str2):
211
227
  '''Split a string in 2 halfs.
212
228
 
@@ -222,6 +238,15 @@ def halfs2(str2):
222
238
  return str2[:h], str2[h:]
223
239
 
224
240
 
241
+ def _integer_ratio2(x): # PYCHOK no cover
242
+ '''(INTERNAL) Return C{B{x}.as_interger_ratio()}.
243
+ '''
244
+ try: # int.as_integer_ratio in 3.8+
245
+ return x.as_integer_ratio()
246
+ except (AttributeError, OverflowError, TypeError, ValueError):
247
+ return (x if isint(x) else float(x)), 1
248
+
249
+
225
250
  def int1s(x): # PYCHOK no cover
226
251
  '''Count the number of 1-bits in an C{int}, I{unsigned}.
227
252
 
@@ -287,17 +312,23 @@ def iscomplex(obj, both=False):
287
312
  return False
288
313
 
289
314
 
290
- def isDEPRECATED(obj):
291
- '''Is B{C{obj}}ect a C{DEPRECATED} class, method or function?
315
+ def isDEPRECATED(obj, outer=1):
316
+ '''Is B{C{obj}}ect or its outer C{type} a C{DEPRECATED}
317
+ class, constant, method or function?
292
318
 
293
319
  @return: C{True} if C{DEPRECATED}, {False} if not or
294
320
  C{None} if undetermined.
295
321
  '''
296
- try: # XXX inspect.getdoc(obj) or obj.__doc__
297
- doc = obj.__doc__.lstrip()
298
- return bool(doc and doc.startswith(_DEPRECATED_))
299
- except AttributeError:
300
- return None
322
+ r = None
323
+ for _ in range(max(0, outer) + 1):
324
+ try: # inspect.getdoc(obj)
325
+ if _DEPRECATED_ in obj.__doc__:
326
+ return True
327
+ r = False
328
+ except AttributeError:
329
+ pass
330
+ obj = type(obj)
331
+ return r
301
332
 
302
333
 
303
334
  def isfloat(obj, both=False):
@@ -327,6 +358,13 @@ except AttributeError: # Python 2-
327
358
  and not obj[:1].isdigit())
328
359
 
329
360
 
361
+ def _isin(obj, *objs):
362
+ '''(INTERNAL) Return C{bool(obj in objs)} with C{True} and C{False} matching.
363
+ '''
364
+ return any(o is obj for o in objs) or \
365
+ any(o == obj for o in objs if not isbool(o))
366
+
367
+
330
368
  def isinstanceof(obj, *Classes):
331
369
  '''Is B{C{obj}}ect an instance of one of the C{Classes}?
332
370
 
@@ -371,7 +409,7 @@ def isiterable(obj, strict=False):
371
409
  @return: C{True} if C{iterable}, C{False} otherwise.
372
410
  '''
373
411
  # <https://PyPI.org/project/isiterable/>
374
- return isiterabletype(obj) if strict else hasattr(obj, '__iter__') # map, range, set
412
+ return bool(isiterabletype(obj)) if strict else hasattr(obj, '__iter__') # map, range, set
375
413
 
376
414
 
377
415
  def isiterablen(obj, strict=False):
@@ -383,7 +421,7 @@ def isiterablen(obj, strict=False):
383
421
  @return: C{True} if C{iterable} with C{len}gth, C{False} otherwise.
384
422
  '''
385
423
  _has = isiterabletype if strict else hasattr
386
- return _has(obj, '__len__') and _has(obj, '__getitem__')
424
+ return bool(_has(obj, '__len__') and _has(obj, '__getitem__'))
387
425
 
388
426
 
389
427
  def isiterabletype(obj, method='__iter__'):
@@ -763,9 +801,13 @@ def _splituple(strs, *sep_splits): # in .mgrs, ...
763
801
  '''(INTERNAL) Split a C{comma}- or C{whitespace}-separated
764
802
  string into a C{tuple} of stripped C{str}ings.
765
803
  '''
766
- t = (strs.split(*sep_splits) if sep_splits else
767
- strs.replace(_COMMA_, _SPACE_).split()) if strs else ()
768
- return tuple(s.strip() for s in t if s)
804
+ if sep_splits:
805
+ t = (t.strip() for t in strs.split(*sep_splits))
806
+ else:
807
+ t = strs.strip()
808
+ if t:
809
+ t = t.replace(_COMMA_, _SPACE_).split()
810
+ return tuple(t) if t else ()
769
811
 
770
812
 
771
813
  def unsigned0(x):
@@ -876,8 +918,8 @@ def _xiterablen(obj):
876
918
  def _xiterror(obj, _xwhich):
877
919
  '''(INTERNAL) Helper for C{_xinterable} and C{_xiterablen}.
878
920
  '''
879
- t = _not_(_xwhich.__name__[2:]) # _DUNDER_nameof
880
- raise _TypeError(repr(obj), txt=t)
921
+ t = typename(_xwhich)[2:] # less '_x'
922
+ raise _TypeError(repr(obj), txt=_not_(t))
881
923
 
882
924
 
883
925
  def _xnumpy(where, *required):
@@ -899,13 +941,13 @@ def _xor(x, *xs):
899
941
  return x
900
942
 
901
943
 
902
- def _xpackages(_xpkgf):
944
+ def _xpackages(_xhich):
903
945
  '''(INTERNAL) Check dependency to be excluded.
904
946
  '''
905
947
  if _XPACKAGES: # PYCHOK no cover
906
- n = _xpkgf.__name__[2:] # _DUNDER_nameof, less '_x'
948
+ n = typename(_xhich)[2:] # less '_x'
907
949
  if n.lower() in _XPACKAGES:
908
- E = _PYGEODESY(_xpackages)
950
+ E = _PYGEODESY_ENV(_xpackages_)
909
951
  x = _SPACE_(n, _in_, E)
910
952
  e = _enquote(_getenv(E, NN))
911
953
  raise ImportError(_EQUAL_(x, e))
@@ -955,7 +997,7 @@ def _xversion(package, where, *required, **name):
955
997
  if required:
956
998
  t = _version_info(package)
957
999
  if t[:len(required)] < required:
958
- t = _SPACE_(package.__name__, # _DUNDER_nameof
1000
+ t = _SPACE_(typename(package),
959
1001
  _version_, _DOT_(*t),
960
1002
  _below_, _DOT_(*required),
961
1003
  _req_d_by(where, **name))
@@ -982,7 +1024,8 @@ else: # Python 3.10+
982
1024
  def _zip(*args):
983
1025
  return zip(*args, strict=True)
984
1026
 
985
- _XPACKAGES = _splituple(_getenv(_PYGEODESY(_xpackages), NN).lower()) # test/bases._X_OK
1027
+ _xpackages_ = typename(_xpackages).lstrip(_UNDER_)
1028
+ _XPACKAGES = _splituple(_envPYGEODESY(_xpackages_).lower()) # test/bases._X_OK
986
1029
 
987
1030
  # **) MIT License
988
1031
  #
pygeodesy/booleans.py CHANGED
@@ -17,12 +17,14 @@ C{reverse-difference}, C{sum} and C{union}.
17
17
  # make sure int/int division yields float quotient, see .basics
18
18
  from __future__ import division as _; del _ # PYCHOK semicolon
19
19
 
20
- from pygeodesy.basics import isodd, issubclassof, map2, _xscalar
20
+ from pygeodesy.basics import _isin, isodd, issubclassof, map2, \
21
+ _xscalar, typename
21
22
  from pygeodesy.constants import EPS, EPS2, INT0, _0_0, _0_5, _1_0
22
23
  from pygeodesy.errors import ClipError, _IsnotError, _TypeError, \
23
24
  _ValueError, _xattr, _xkwds_get, _xkwds_pop2
24
25
  from pygeodesy.fmath import favg, fdot_, hypot, hypot2
25
26
  # from pygeodesy.fsums import fsum1 # _MODS
27
+ # from pygeodesy.internals import typename # from .basics
26
28
  from pygeodesy.interns import NN, _BANG_, _clipid_, _COMMASPACE_, \
27
29
  _composite_, _DOT_, _duplicate_, _e_, \
28
30
  _ELLIPSIS_, _few_, _height_, _lat_, _LatLon_, \
@@ -43,7 +45,7 @@ from pygeodesy.utily import fabs, _unrollon, _Wrap
43
45
  # from math import fabs # from .utily
44
46
 
45
47
  __all__ = _ALL_LAZY.booleans
46
- __version__ = '24.11.07'
48
+ __version__ = '25.04.14'
47
49
 
48
50
  _0EPS = EPS # near-zero, positive
49
51
  _EPS0 = -EPS # near-zero, negative
@@ -352,11 +354,11 @@ class LatLonFHP(_LatLonBool):
352
354
  def _isduplicate(self):
353
355
  # Is this point a I{duplicate} intersection?
354
356
  p = self._dupof
355
- return bool(p and self._linked
356
- and p is not self
357
- and p == self
358
- # and p._alpha in (None, self._alpha)
359
- and self._alpha in (_0_0, p._alpha))
357
+ return bool(p and self._linked
358
+ and p is not self
359
+ and p == self
360
+ # and _isin(p._alpha, None, self._alpha)
361
+ and _isin(self._alpha, _0_0, p._alpha))
360
362
 
361
363
  # @property_RO
362
364
  # def _isduplicated(self):
@@ -940,7 +942,7 @@ class _CompositeBase(_Named):
940
942
  c = Fmt.SQUARE(c) if c > 1 else NN
941
943
  n = Fmt.SQUARE(len(self))
942
944
  t = Fmt.PAREN(self) # XXX not unstr
943
- return NN(self.__class__.__name__, c, n, t)
945
+ return NN(self.typename, c, n, t)
944
946
 
945
947
  def __str__(self):
946
948
  '''String C{str} of this composite.
@@ -1051,7 +1053,7 @@ class _CompositeBase(_Named):
1051
1053
  def _kwds(self, op, **more):
1052
1054
  # Get all keyword arguments as C{dict}.
1053
1055
  kwds = dict(raiser=self.raiser, eps=self.eps,
1054
- name=self.name or op.__name__)
1056
+ name=self.name or typename(op))
1055
1057
  kwds.update(more)
1056
1058
  return kwds
1057
1059
 
@@ -1105,7 +1107,7 @@ class _CompositeBase(_Named):
1105
1107
  def _sum(self, other, op):
1106
1108
  # Combine this and an C{other} composite
1107
1109
  LL = self._LL
1108
- sp = self.copy(name=self.name or op.__name__)
1110
+ sp = self.copy(name=self.name or typename(op))
1109
1111
  sp._clips, sid = (), INT0 # new clips
1110
1112
  for cp in (self, other):
1111
1113
  for c in cp._clips:
@@ -10,17 +10,18 @@ U{https://www.Movable-Type.co.UK/scripts/latlong-vectors.html} and
10
10
  U{https://www.Movable-Type.co.UK/scripts/geodesy/docs/latlon-ellipsoidal.js.html}.
11
11
  '''
12
12
 
13
- # from pygeodesy.basics import _xinstanceof # from .datums
13
+ from pygeodesy.basics import _isin, _xinstanceof, typename
14
14
  from pygeodesy.constants import EPS, EPS0, INT0, PI2, _isfinite, isnear0, \
15
15
  _0_0, _1_0, _N_1_0, _2_0, _4_0, _6_0
16
16
  from pygeodesy.datums import Datum, _earth_ellipsoid, _spherical_datum, \
17
- Transform, _WGS84, _xinstanceof
17
+ Transform, _WGS84
18
18
  # from pygeodesy.ecef import EcefKarney # _MODS
19
19
  from pygeodesy.errors import _IsnotError, _TypeError, _ValueError, _xattr, \
20
20
  _xdatum, _xkwds, _xkwds_get, _xkwds_pop2
21
21
  from pygeodesy.fmath import cbrt, hypot, hypot_, hypot2, fabs, sqrt # hypot
22
22
  # from pygeodesy.formy import _hartzell # _MODS
23
23
  from pygeodesy.fsums import fsumf_, Fmt
24
+ # from pygeodesy.internals import typename # from .basics
24
25
  from pygeodesy.interns import _COMMASPACE_, _datum_, _no_, _phi_
25
26
  from pygeodesy.interns import _ellipsoidal_, _spherical_ # PYCHOK used!
26
27
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
@@ -30,8 +31,7 @@ from pygeodesy.namedTuples import LatLon4Tuple, _NamedTupleTo , Vector3Tuple, \
30
31
  # from pygeodesy.nvectorBase import _N_vector # _MODS
31
32
  from pygeodesy.props import deprecated_method, Property, Property_RO, property_doc_, \
32
33
  property_RO, _update_all
33
- # from pygeodesy,resections import cassini, collins5, pierlot, pierlotx, \
34
- # tienstra7 # _MODS
34
+ # from pygeodesy import resections as _resections # _MODS.into
35
35
  # from pygeodesy.streprs import Fmt # from .fsums
36
36
  # from pygeodesy.triaxials import Triaxial_ # _MODS
37
37
  from pygeodesy.units import Degrees, Height, _heigHt, _isMeter, Meter, Radians
@@ -43,10 +43,11 @@ from pygeodesy.vector3d import Vector3d, _xyzhdlln4
43
43
  # from math import degrees, fabs, radians, sqrt # from .fmath, .utily
44
44
 
45
45
  __all__ = _ALL_LAZY.cartesianBase
46
- __version__ = '24.12.04'
46
+ __version__ = '25.04.21'
47
47
 
48
- _r_ = 'r'
49
- _theta_ = 'theta'
48
+ _r_ = 'r'
49
+ _resections = _MODS.into(resections=__name__)
50
+ _theta_ = 'theta'
50
51
 
51
52
 
52
53
  class CartesianBase(Vector3d, _NamedLocal):
@@ -112,8 +113,8 @@ class CartesianBase(Vector3d, _NamedLocal):
112
113
 
113
114
  @see: Function L{pygeodesy.cassini} for references and more details.
114
115
  '''
115
- return _MODS.resections.cassini(self, pointB, pointC, alpha, beta,
116
- useZ=useZ, datum=self.datum)
116
+ return _resections.cassini(self, pointB, pointC, alpha, beta,
117
+ useZ=useZ, datum=self.datum)
117
118
 
118
119
  @deprecated_method
119
120
  def collins(self, pointB, pointC, alpha, beta, useZ=False):
@@ -148,8 +149,8 @@ class CartesianBase(Vector3d, _NamedLocal):
148
149
 
149
150
  @see: Function L{pygeodesy.collins5} for references and more details.
150
151
  '''
151
- return _MODS.resections.collins5(self, pointB, pointC, alpha, beta,
152
- useZ=useZ, datum=self.datum)
152
+ return _resections.collins5(self, pointB, pointC, alpha, beta,
153
+ useZ=useZ, datum=self.datum)
153
154
 
154
155
  @deprecated_method
155
156
  def convertDatum(self, datum2, **datum):
@@ -304,7 +305,7 @@ class CartesianBase(Vector3d, _NamedLocal):
304
305
 
305
306
  @raise TypeError: Invalid or undefined B{C{earth}} or C{datum}.
306
307
  '''
307
- n = self.height3.__name__
308
+ n = typename(self.height3)
308
309
  d = self.datum if earth is None else _spherical_datum(earth, name=n)
309
310
  c, h = self, _heigHt(self, height)
310
311
  if h and d:
@@ -357,7 +358,7 @@ class CartesianBase(Vector3d, _NamedLocal):
357
358
 
358
359
  @see: Methods L{Ellipsoid.height4} and L{Triaxial_.height4} for more information.
359
360
  '''
360
- n = self.height4.__name__
361
+ n = typename(self.height4)
361
362
  d = self.datum if earth is None else earth
362
363
  if normal and d is self.datum:
363
364
  r = self._height4
@@ -504,8 +505,8 @@ class CartesianBase(Vector3d, _NamedLocal):
504
505
 
505
506
  @see: Function L{pygeodesy.pierlot} for references and more details.
506
507
  '''
507
- return _MODS.resections.pierlot(self, point2, point3, alpha12, alpha23,
508
- useZ=useZ, eps=eps, datum=self.datum)
508
+ return _resections.pierlot(self, point2, point3, alpha12, alpha23,
509
+ useZ=useZ, eps=eps, datum=self.datum)
509
510
 
510
511
  def pierlotx(self, point2, point3, alpha1, alpha2, alpha3, useZ=False):
511
512
  '''3-Point resection between this and two other points using U{Pierlot
@@ -531,8 +532,8 @@ class CartesianBase(Vector3d, _NamedLocal):
531
532
 
532
533
  @see: Function L{pygeodesy.pierlotx} for references and more details.
533
534
  '''
534
- return _MODS.resections.pierlotx(self, point2, point3, alpha1, alpha2, alpha3,
535
- useZ=useZ, datum=self.datum)
535
+ return _resections.pierlotx(self, point2, point3, alpha1, alpha2, alpha3,
536
+ useZ=useZ, datum=self.datum)
536
537
 
537
538
  def Roc2(self, earth=None):
538
539
  '''Compute this cartesian's I{normal} and I{pseudo, z-based} radius of curvature.
@@ -605,8 +606,8 @@ class CartesianBase(Vector3d, _NamedLocal):
605
606
 
606
607
  @see: Function L{pygeodesy.tienstra7} for references and more details.
607
608
  '''
608
- return _MODS.resections.tienstra7(self, pointB, pointC, alpha, beta, gamma,
609
- useZ=useZ, datum=self.datum)
609
+ return _resections.tienstra7(self, pointB, pointC, alpha, beta, gamma,
610
+ useZ=useZ, datum=self.datum)
610
611
 
611
612
  @deprecated_method
612
613
  def to2ab(self): # PYCHOK no cover
@@ -659,7 +660,7 @@ class CartesianBase(Vector3d, _NamedLocal):
659
660
  '''
660
661
  _xinstanceof(Datum, datum2=datum2)
661
662
 
662
- c = self if datum in (None, self.datum) else \
663
+ c = self if _isin(datum, None, self.datum) else \
663
664
  self.toDatum(datum)
664
665
 
665
666
  i, d = False, c.datum