pygeodesy 24.9.9__py2.py3-none-any.whl → 24.9.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyGeodesy
3
- Version: 24.9.9
3
+ Version: 24.9.24
4
4
  Summary: Pure Python geodesy tools
5
5
  Home-page: https://GitHub.com/mrJean1/PyGeodesy
6
6
  Author: Jean M. Brouwers
@@ -115,7 +115,7 @@ line: ``epydoc --html --no-private --no-source --name=PyGeodesy --url=... -v pyg
115
115
  Tests
116
116
  =====
117
117
 
118
- The tests ran with Python 3.13.0rc1, 3.12.5 (with geographiclib_ 2.0, numpy_ 2.1.0, scipy_ 1.14.1,
118
+ The tests ran with Python 3.13.0rc2, 3.12.6 (with geographiclib_ 2.0, numpy_ 2.1.0, scipy_ 1.14.1,
119
119
  GeodSolve_ 2.3, IntersectTool_ 2.3 and RhumbSolve_ 2.3), 3.11.5 (with geographiclib_ 2.0, numpy_
120
120
  1.24.2 and scipy_ 1.10.1), Python 3.10.8 (with geographiclib_ 2.0, numpy_ 1.23.3, scipy_ 1.9.1,
121
121
  GeoConvert_ 2.3, GeodSolve_ 2.3), Python 3.9.6 and Python 2.7.18 (with geographiclib_ 1.50, numpy_
@@ -126,13 +126,13 @@ All tests ran with and without ``lazy import`` for Python 3 and with command lin
126
126
  and env variable ``PYGEODESY_WARNINGS=on`` for all Python versions. The results of those tests are
127
127
  included in the distribution files.
128
128
 
129
- Python 3.13.0rc1, 3.12.5, 3.11.5 and 3.10.8 run on Apple M1 Silicon (``arm64``), *natively*. Python 2.7.18
129
+ Python 3.13.0rc2, 3.12.6, 3.11.5 and 3.10.8 run on Apple M1 Silicon (``arm64``), *natively*. Python 2.7.18
130
130
  runs on Intel (``x86_64``) or Intel *emulation* (\"``arm64_x86_64``\", see function `pygeodesy.machine`_).
131
131
 
132
- Test coverage has been measured with coverage_ 7.6.0 using Python 3.12.5, 3.11.5 and 3.10.8. The complete
132
+ Test coverage has been measured with coverage_ 7.6.0 using Python 3.12.6, 3.11.5 and 3.10.8. The complete
133
133
  coverage report in HTML and a PDF summary are included in the distribution files.
134
134
 
135
- The tests also ran with Python 3.12.5 (and geographiclib_ 2.0) on `Debian 12`_ in 64-bit only and with
135
+ The tests also ran with Python 3.12.6 (and geographiclib_ 2.0) on `Debian 12`_ in 64-bit only and with
136
136
  Python 3.12.3 (and geographiclib_ 2.0) on `Windows 2019Server`_ in 64-bit only and with Python 2.7.18
137
137
  (and with geographiclib_ 1.52) on `Windows 10`_ in 64- and 32-bit.
138
138
 
@@ -160,7 +160,7 @@ and McCabe_ using Python 2.7.18 and with Flake8_ using Python 3.11.5, both in 64
160
160
 
161
161
  For a summary of all *Karney*-based functionality in ``pygeodesy``, see module karney_.
162
162
 
163
- *Last updated: Sep 09, 2024.*
163
+ *Last updated: Sep 24, 2024.*
164
164
 
165
165
  License
166
166
  =======
@@ -1,13 +1,13 @@
1
1
  pygeodesy/LICENSE,sha256=YfgAiyxOwY6P9Kkb1_5XN81nueTLrpb3Ffkv3EuPgFU,1144
2
- pygeodesy/__init__.py,sha256=ohpvlHHdgFq_uc-u1gq7deCyTlzB_nq-Lc8tZGWN-Go,42225
2
+ pygeodesy/__init__.py,sha256=gu-FjebeihoF1kw47l9X8UjHwQsI4lWn6n4_BPVu6hE,42475
3
3
  pygeodesy/__main__.py,sha256=OupAiDFT_RXFw1Lh6C8bVG9NaonV_Wy6jibN_hA4aJg,5442
4
4
  pygeodesy/albers.py,sha256=JXqeWAteV2N601e5R-D7bCsa8qAYv3oWm7M3R4uszXM,31078
5
5
  pygeodesy/azimuthal.py,sha256=erI5DTM0-Nr5YC2LnBTVNbUKlrnnXJUwKe0SCQ7-Soc,50223
6
- pygeodesy/basics.py,sha256=5fuWL_azUd6DxSGUwB4RJERH_ZrBB0vVqDc9wvxpIHo,30116
7
- pygeodesy/booleans.py,sha256=mWNdmk5cYfcH3v0sEpU3Aw5sFLp_dq5mXJodzenOEm0,73506
6
+ pygeodesy/basics.py,sha256=pY0SAIRoD_4okhVwNGAAhxEa9FIZI07XbyPu_sn6sNM,30121
7
+ pygeodesy/booleans.py,sha256=H1QbPYpelIGUzfOdwWd2hWXxi6vvbrQiEV_rK5cg1LA,73491
8
8
  pygeodesy/cartesianBase.py,sha256=jzPJR4_3Yp5jmK7A5inGOXskDebs7YMdjQzINHjzkP8,46935
9
- pygeodesy/clipy.py,sha256=3ysIEWQ89HjvLnSlZm0nZAt9EN5AQxIs1sLLM8yF9zM,27675
10
- pygeodesy/constants.py,sha256=vW6CWRa62hHJqmKhlPxI4Eu-cbLhoUYWYTd9ctfFo-8,19240
9
+ pygeodesy/clipy.py,sha256=hzI6IutTRkbssjPPgAjXv9OcgCIIZchjnMWaHin4YAU,27728
10
+ pygeodesy/constants.py,sha256=l5MDpwvrl_BhavQHSPdbqT6kt7YP1O78b6rIl43sVAo,19616
11
11
  pygeodesy/css.py,sha256=rPr5EcGm_blVt72h-851ytpVxdPhx1MEqqGs3Ppx3eI,25651
12
12
  pygeodesy/datums.py,sha256=-m9-cvUVOaJ92eeFgc3O54lel3WqnVYcS7o6WCXkNyw,34043
13
13
  pygeodesy/dms.py,sha256=QxiRtyc8QSiW-egm6Mrcrgmi_deWz3YnYwIm82JS4TU,44443
@@ -23,13 +23,13 @@ pygeodesy/ellipsoidalVincenty.py,sha256=hSQ7s6QGDJSsrZvP7KwM1Q4wJz0YjyFjODF6XPGZ
23
23
  pygeodesy/ellipsoids.py,sha256=i7piclEb17hYt5wqL7Q0p5qLuRVvz3yonUSUcvmiozc,108005
24
24
  pygeodesy/elliptic.py,sha256=M30EjB1Il_5Y8E94rN5hz4zPhYBQNoCo5Lj0TvCkiRE,45010
25
25
  pygeodesy/epsg.py,sha256=Vq_M1g7Z0x5Noqsmt6OCQkPdYJj4jpWObtixL5pAjDA,8220
26
- pygeodesy/errors.py,sha256=-UnQ1GhkiTR6uBd0z0vd_pFEmjWXlOESRDwMdxY_JD0,30605
26
+ pygeodesy/errors.py,sha256=6aofErGAi6l1xwXqd4PU7YSoPQiutc-gFiFiTamGoU4,31597
27
27
  pygeodesy/etm.py,sha256=G6dtN1LQAoft5mcUoxVgxHPnl9s8NBsXl-IlS8WP7jo,45328
28
- pygeodesy/fmath.py,sha256=7Bokavxcu4oFGMKHCn4JxbETDisbBkWJqJx-KiCtHPM,34374
28
+ pygeodesy/fmath.py,sha256=JEjiBJKjNt0Lm3EAIn_IiRoxtuTZbXNz2nscjJPEzUA,35376
29
29
  pygeodesy/formy.py,sha256=PrAlrSASKIXeFvawueyo7kRC-UJJSEQR3APhirHqhtE,75032
30
30
  pygeodesy/frechet.py,sha256=F6TYbOEYSOFcll6nvp4GhqafUWXh1umAKb1QaMYQtuM,34372
31
- pygeodesy/fstats.py,sha256=4eIhzSCMnn-2nVP3Q-5cCWCI-rvH0CE-zkk9hp3Pvn8,28642
32
- pygeodesy/fsums.py,sha256=Zk65c445gAz7Ld_iXL1zZ3ZtkA_gM2edDOf9nJSEnXE,87433
31
+ pygeodesy/fstats.py,sha256=nV5Kj5DrKO6zjU18rxlbTRwM-m7Rct9GLhOuH3_3hl8,28541
32
+ pygeodesy/fsums.py,sha256=cVNCB90BhvBfTCpZyvvPFVa9aEllzKd-CPJLPPeTFx4,99816
33
33
  pygeodesy/gars.py,sha256=KRlyZUv1euEl7ZkDYSZG913GAfFMRG2m2hp37ObYY_Y,11829
34
34
  pygeodesy/geodesici.py,sha256=I9e7saiO5lRodOXJk5DSQxladVcGfT0FR6KJSJVCw7Y,75015
35
35
  pygeodesy/geodesicw.py,sha256=oEs96Epw839BH3rVpxVdpXuQRBudbOftUsSBUid8fcc,28710
@@ -41,10 +41,10 @@ pygeodesy/heights.py,sha256=Gv3b1xC7I0tBvTO-DdmWVW8A3ZV3RKxY3jveUUZso38,42909
41
41
  pygeodesy/internals.py,sha256=TSJueckcn6dQddZUhLR0Vf9XN-Whm85IYmSvhVZbB_s,22550
42
42
  pygeodesy/interns.py,sha256=XvNyWODsUd8_vBLX9XLmcU9Bq97L0nahhF-gvLivzKA,23278
43
43
  pygeodesy/iters.py,sha256=xPH0ytomvJeKHu717Fjzi3QbRrEikO6n7vqkY_IDz1k,20311
44
- pygeodesy/karney.py,sha256=2G5Y9FvZlb8cTrDHtHF71n3gxCvGLxlWUgVwXGmAnjA,39033
44
+ pygeodesy/karney.py,sha256=ZkZhbsieGnr2cAIXjzmK-9OJdh72Hjp6Hya1wIoVP3c,38913
45
45
  pygeodesy/ktm.py,sha256=eUWYKhoPou1AiWiNz-xI8eDr-q-RvKDY6newAmYP26Q,27239
46
46
  pygeodesy/latlonBase.py,sha256=kCK6IcVg4oeGPYkIU0rgKbZLCRo36wC9NtY5OKBlpeQ,79106
47
- pygeodesy/lazily.py,sha256=jIfuqXPh-Gvg4H2XeGgbKoOGuc49SR_sMVMoBEVq4LQ,47370
47
+ pygeodesy/lazily.py,sha256=NpWnTIAOkIxMorgUMvyR7d3D65-55DqaU98eBnwxcrQ,47411
48
48
  pygeodesy/lcc.py,sha256=oDooTzFHnqsMtSKmmmfEbypHpdlPltfo7Mt0pAO4-_A,25669
49
49
  pygeodesy/ltp.py,sha256=ZMdfJHLKeDHSoymmjWfoAZTtrdoADf0O6WccRf53L2w,50745
50
50
  pygeodesy/ltpTuples.py,sha256=oNTxtjxmHveMDQvPdQCHl-JzSJJGb1jFRrF8SEG_Ojw,58480
@@ -53,14 +53,14 @@ pygeodesy/named.py,sha256=-uqZk54BC4rFtuVh4LwfWty704DVPLEIwI1EzpNImIg,52350
53
53
  pygeodesy/namedTuples.py,sha256=e0rV1Zb2tbx8fztXcSkUFsRTmZtye8B5i_Hi4vBUndU,28758
54
54
  pygeodesy/nvectorBase.py,sha256=rClYu26Bof9DsM1F60i0eccktNo8xYA_vkThwoY7N4o,28644
55
55
  pygeodesy/osgr.py,sha256=3Qon_oWuVrIb1vYnd3ae3L5MDkjp_tngyVdiYHuL4to,30821
56
- pygeodesy/points.py,sha256=e8ri5Pu5snpN4P6pPbGxmW_yx4-ApD9mOBuR0REoflA,64409
56
+ pygeodesy/points.py,sha256=vtPQdL2kLOenIrpOdGjOYrUWsav3I1JXQEJugMv46eY,64383
57
57
  pygeodesy/props.py,sha256=3BIkcaEDwyhSMJle6ufBaji0R0FrD64G3nuR4tPsnrU,23819
58
- pygeodesy/resections.py,sha256=fFthuI9EoO4WdY25Y_rCDN56gz2mPFsUypR3oGlh8Ks,43556
58
+ pygeodesy/resections.py,sha256=IrPHAHbF9JdBgAVd9LMgXoPgPFRkY8j1G7p0P8y8pdc,43543
59
59
  pygeodesy/simplify.py,sha256=vkOtO478sOjZHZBuSFvCaRh72qSDQuzXLQpMK1LKyYI,25232
60
60
  pygeodesy/solveBase.py,sha256=oI_-FFjSPI1_yQ598hF6HFKUa4tLsAfbnWtKoQ-TJgE,19206
61
61
  pygeodesy/sphericalBase.py,sha256=bDVuArfePzqcothiTTkyisUGrMDTallXKROjihotcn8,32239
62
- pygeodesy/sphericalNvector.py,sha256=MiWcCy5CdvXsCa3963GeUMEnSYGhBiXzkoAEX_tGX4Q,56952
63
- pygeodesy/sphericalTrigonometry.py,sha256=F84lPOSLj4Z2-f8xMjpqvTISuBpsjFwdF8fkuaEi5Hs,64077
62
+ pygeodesy/sphericalNvector.py,sha256=Ip0jPv-MXBoHf3f-uXitGqiMz2xynDtE15OSJEl268Q,56913
63
+ pygeodesy/sphericalTrigonometry.py,sha256=cfXuJaJJ6jrJZxQ5anFHhz3ZbgkAB7aiMfuyMtJXqsE,64064
64
64
  pygeodesy/streprs.py,sha256=1szfCzFlVgsyJ0H_QFGtzyMfOJpyIZNfj34qvWNACM4,23041
65
65
  pygeodesy/trf.py,sha256=CRFHmu0lFNtc41fddXavEkHmgnTFWEqR4RTFodcFKsw,119022
66
66
  pygeodesy/triaxials.py,sha256=a9vdXmSqUXOneL0WpLriEFwNMW9EB6MpVbKYXuw_wi8,62562
@@ -87,12 +87,12 @@ pygeodesy/auxilats/auxDLat.py,sha256=3sq7Wc-ykpVbldNh10IZ3tIlJ7DcQFDlmZ4nOhJEgo0
87
87
  pygeodesy/auxilats/auxDST.py,sha256=BSHR0M3hQBR1KjF_BUJHrNzGXr2PblYXUQsMD5L1Kcc,10468
88
88
  pygeodesy/auxilats/auxLat.py,sha256=7uxe7mtkY-9uSI3z2wmUNBqzCKyFujIpJU1v-8yDgds,31934
89
89
  pygeodesy/auxilats/auxily.py,sha256=X1y4_qC40Th7CgmZILqoQCLAUQoyORcR5W-bN4X0W4I,7882
90
- pygeodesy/deprecated/__init__.py,sha256=cBYqbh5Njkd5SnaJDaMUP6PL66HfLWii_JoLjnKfnP4,2815
90
+ pygeodesy/deprecated/__init__.py,sha256=jSwmipBzyIOYIQhiZxZwsIQlqMXPfNaPfVpppBu7zkw,2815
91
91
  pygeodesy/deprecated/bases.py,sha256=nxUtxscAg5cb7HEzTSmPJFafLc9Ad2SL5ovwkYaU5z8,1655
92
92
  pygeodesy/deprecated/classes.py,sha256=gktUr5qYXCm8ztH6lfzFgaHKqMiw1tHc1Vw6i6DEvNA,12377
93
93
  pygeodesy/deprecated/consterns.py,sha256=W-rQiw443_zCFEUzjCGykGND-i5P_ghEIyJUSGg7-Nc,1908
94
94
  pygeodesy/deprecated/datum.py,sha256=s8Hke053RucP5ACvg3gdX8weQfGM0x59pQyHpY11eOs,1875
95
- pygeodesy/deprecated/functions.py,sha256=EZMZe9WGkcbwmLDoWO2xKJyFlUkWAAMxmlbtCLa28lM,13866
95
+ pygeodesy/deprecated/functions.py,sha256=-spa_5k7yRWGd7s4UBObzf9QpAM0o-tgP4S0wX876JY,14122
96
96
  pygeodesy/deprecated/nvector.py,sha256=_dZf84RdmPr7e7i8Yi683R-8Mqn0ipTqIsDhNl29hGo,2117
97
97
  pygeodesy/deprecated/rhumbBase.py,sha256=d7YKW--dnRpobB2CSvhFsntWF0B5-HYJqID2pv5lD5k,1375
98
98
  pygeodesy/deprecated/rhumbaux.py,sha256=n29xazYMbVG4MJkLjAGu8B88bbcFF5xnvuj9xSxjfIk,1428
@@ -112,7 +112,7 @@ pygeodesy/rhumb/aux_.py,sha256=XN0zlNwhU525NdcHko-G_Igvc7-mzXbT7ypcVIt5ADw,16048
112
112
  pygeodesy/rhumb/bases.py,sha256=awpP60K6EOzS753oXM-h9S6paS6FwoCnco8Zt8n81jY,54162
113
113
  pygeodesy/rhumb/ekx.py,sha256=JsmdCatWKqsffF8jCh4HDu5IKt_kHq1qUdmP1LMuofY,24044
114
114
  pygeodesy/rhumb/solve.py,sha256=d4RujlW8B7BFAHlrwfj2Bup-uXZZTpgKWgI2JJBqUGc,24059
115
- PyGeodesy-24.9.9.dist-info/METADATA,sha256=NZ7vpJ3lZq-5fmen4MR9YO3yRCcEuJN8zhpO8QtbKe0,19876
116
- PyGeodesy-24.9.9.dist-info/WHEEL,sha256=fS9sRbCBHs7VFcwJLnLXN1MZRR0_TVTxvXKzOnaSFs8,110
117
- PyGeodesy-24.9.9.dist-info/top_level.txt,sha256=cEQPatCXzKZqrivpULC5V5fuy9_V_bAwaP_gUGid7pQ,10
118
- PyGeodesy-24.9.9.dist-info/RECORD,,
115
+ PyGeodesy-24.9.24.dist-info/METADATA,sha256=tIX957Sljzlxz05L-pGuqjt4ZCcfJnLuQ9E0mTwWruw,19877
116
+ PyGeodesy-24.9.24.dist-info/WHEEL,sha256=fS9sRbCBHs7VFcwJLnLXN1MZRR0_TVTxvXKzOnaSFs8,110
117
+ PyGeodesy-24.9.24.dist-info/top_level.txt,sha256=cEQPatCXzKZqrivpULC5V5fuy9_V_bAwaP_gUGid7pQ,10
118
+ PyGeodesy-24.9.24.dist-info/RECORD,,
pygeodesy/__init__.py CHANGED
@@ -122,7 +122,7 @@ C{epydoc --html --no-private --no-source --name=PyGeodesy --url=... -v pygeodesy
122
122
  Tests
123
123
  =====
124
124
 
125
- The tests ran with Python 3.13.0rc1, Python 3.12.5 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0,
125
+ The tests ran with Python 3.13.0rc2, Python 3.12.6 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0,
126
126
  U{numpy<https://PyPI.org/project/numpy>} 2.1.0, U{scipy<https://PyPI.org/project/scipy>} 1.14.1,
127
127
  U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.3,
128
128
  U{IntersectTool<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.3 and
@@ -144,13 +144,13 @@ All tests ran with and without C{lazy import} for Python 3 and with command line
144
144
  env variable C{PYGEODESY_WARNINGS=on} for all Python versions. The results of those tests are included in
145
145
  the distribution files.
146
146
 
147
- Test coverage has been measured with U{coverage<https://PyPI.org/project/coverage>} 7.6.0 using Python 3.12.5,
147
+ Test coverage has been measured with U{coverage<https://PyPI.org/project/coverage>} 7.6.0 using Python 3.12.6,
148
148
  3.11.5 and 3.10.8. The complete coverage report in HTML and a PDF summary are included in the distribution files.
149
149
 
150
- Python 3.13.0rc1, 3.12.5, 3.11.5 and 3.10.8 run on Apple M1 Silicon (C{arm64}), I{natively}. Python 2.7.18 runs on
150
+ Python 3.13.0rc2, 3.12.6, 3.11.5 and 3.10.8 run on Apple M1 Silicon (C{arm64}), I{natively}. Python 2.7.18 runs on
151
151
  Intel (C{x86_64}) or Intel I{emulation} ("C{arm64_x86_64}", see function L{machine<pygeodesy.machine>}).
152
152
 
153
- The tests also ran with Python 3.12.5 (and U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0) on U{Debian
153
+ The tests also ran with Python 3.12.6 (and U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0) on U{Debian
154
154
  12<https://Cirrus-CI.com/github/mrJean1/PyGeodesy/master>} in 64-bit only, with Python 3.12.3 (and
155
155
  U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0) on U{Windows
156
156
  2019Server<https://CI.AppVeyor.com/project/mrJean1/pygeodesy>} in 64-bit only and with Python 2.7.18 (and
@@ -199,6 +199,8 @@ The following environment variables are observed by C{PyGeodesy}:
199
199
 
200
200
  - C{PYGEODESY_EXCEPTION_CHAINING} - see module L{errors<pygeodesy.errors>}.
201
201
  - C{PYGEODESY_FMT_FORM} - see module L{dms<pygeodesy.dms>}.
202
+ - C{PYGEODESY_FSUM_F2PRODUCT} - see module L{fsums<pygeodesy.fsums>} and method L{f2product<pygeodesy.Fsum.f2product>}.
203
+ - C{PYGEODESY_FSUM_NONFINITES} - see module L{fsums<pygeodesy.fsums>} and function L{nonfiniterrors<pygeodesy.nonfiniterrors>}.
202
204
  - C{PYGEODESY_FSUM_RESIDUAL} - see module L{fsums<pygeodesy.fsums>} and class L{Fsum<pygeodesy.Fsum>}.
203
205
  - C{PYGEODESY_GEOCONVERT} - see module L{mgrs<pygeodesy.mgrs>}.
204
206
  - C{PYGEODESY_GEODSOLVE} - see module L{geodsolve<pygeodesy.geodsolve>}.
@@ -595,7 +597,7 @@ else:
595
597
 
596
598
  from pygeodesy.internals import _version2, _DOT_ # PYCHOK import
597
599
  # from pygeodesy.interns import _DOT_ # from .internals
598
- __version__ = '24.09.09'
600
+ __version__ = '24.09.24'
599
601
  # see setup.py for similar logic
600
602
  version = _DOT_(*_version2(__version__, n=3))
601
603
 
pygeodesy/basics.py CHANGED
@@ -19,6 +19,7 @@ del division
19
19
  from pygeodesy.errors import _AttributeError, _ImportError, _NotImplementedError, \
20
20
  _TypeError, _TypesError, _ValueError, _xAssertionError, \
21
21
  _xkwds_get1
22
+ # from pygeodesy.fsums import _isFsumTuple # _MODS
22
23
  from pygeodesy.internals import _0_0, _enquote, _passarg, _version_info
23
24
  from pygeodesy.interns import MISSING, NN, _1_, _by_, _COMMA_, _DOT_, _DEPRECATED_, \
24
25
  _ELLIPSIS4_, _EQUAL_, _in_, _invalid_, _N_A_, _not_, \
@@ -37,7 +38,7 @@ from math import copysign as _copysign
37
38
  import inspect as _inspect
38
39
 
39
40
  __all__ = _ALL_LAZY.basics
40
- __version__ = '24.09.02'
41
+ __version__ = '24.09.12'
41
42
 
42
43
  _below_ = 'below'
43
44
  _list_tuple_types = (list, tuple)
@@ -460,18 +461,16 @@ def isscalar(obj, both=False):
460
461
  '''Is B{C{obj}}ect an C{int} or integer C{float} value?
461
462
 
462
463
  @arg obj: The object (any C{type}).
463
- @kwarg both: If C{True}, check L{Fsum<Fsum.residual>}.
464
+ @kwarg both: If C{True}, check L{Fsum} and L{Fsum2Tuple}
465
+ residuals.
464
466
 
465
- @return: C{True} if C{int}, C{float} or L{Fsum} with
466
- zero residual, C{False} otherwise.
467
+ @return: C{True} if C{int}, C{float} or C{Fsum/-2Tuple}
468
+ with zero residual, C{False} otherwise.
467
469
  '''
468
470
  if isinstance(obj, _Scalars):
469
- return not isbool(obj)
470
- elif both: # and isinstance(obj, Fsum)
471
- try:
472
- return bool(obj.residual == 0)
473
- except (AttributeError, TypeError):
474
- pass # XXX float(int(obj)) == obj?
471
+ return not isbool(obj) # exclude bool
472
+ elif both and _MODS.fsums._isFsumTuple(obj):
473
+ return bool(obj.residual == 0)
475
474
  return False
476
475
 
477
476
 
pygeodesy/booleans.py CHANGED
@@ -43,7 +43,7 @@ from pygeodesy.utily import fabs, _unrollon, _Wrap
43
43
  # from math import fabs # from .utily
44
44
 
45
45
  __all__ = _ALL_LAZY.booleans
46
- __version__ = '24.08.30'
46
+ __version__ = '24.09.23'
47
47
 
48
48
  _0_EPS = EPS # near-zero, positive
49
49
  _EPS_0 = -EPS # near-zero, negative
@@ -1117,7 +1117,7 @@ class _CompositeBase(_Named):
1117
1117
 
1118
1118
  def _sum1(self, _a_p, *args, **kwds): # in .karney, .points
1119
1119
  # Sum the area or perimeter of all clips
1120
- return _MODS.fsums.fsum1((_a_p(c, *args, **kwds) for c in self._clips), floats=True)
1120
+ return _MODS.fsums.fsum1((_a_p(c, *args, **kwds) for c in self._clips))
1121
1121
 
1122
1122
  def _sum2(self, LL, _a_p, *args, **kwds): # in .sphericalNvector, -Trigonometry
1123
1123
  # Sum the area or perimeter of all clips
@@ -1127,7 +1127,7 @@ class _CompositeBase(_Named):
1127
1127
  for v in clip:
1128
1128
  yield _LL(v.lat, v.lon) # datum=Sphere
1129
1129
 
1130
- return _MODS.fsums.fsum1((_a_p(_lls(c), *args, **kwds) for c in self._clips), floats=True)
1130
+ return _MODS.fsums.fsum1((_a_p(_lls(c), *args, **kwds) for c in self._clips))
1131
1131
 
1132
1132
  def toLatLon(self, LatLon=None, closed=False, **LatLon_kwds):
1133
1133
  '''Yield all (non-duplicate) points and intersections
@@ -1187,7 +1187,7 @@ class _CompositeFHP(_CompositeBase):
1187
1187
  n, b = v, v._label
1188
1188
  if b in L.RIGHT_LEFT_ON: # next chain
1189
1189
  while True:
1190
- n._label = None # n.__dict__.pop('_label')
1190
+ n._label = None # _xkwds_pop(n.__dict__, _label=None)
1191
1191
  n = n._next
1192
1192
  if n is v or n._label is not L.ON_ON: # n._label and ...
1193
1193
  break
pygeodesy/clipy.py CHANGED
@@ -15,22 +15,22 @@ from __future__ import division as _; del _ # PYCHOK semicolon
15
15
  # from pygeodesy.basics import len2 # from .fmath
16
16
  from pygeodesy.constants import EPS, _0_0, _1_0
17
17
  from pygeodesy.errors import _AssertionError, ClipError, PointsError
18
- from pygeodesy.fmath import fabs, len2
19
- from pygeodesy.fsums import fsumf_, Property_RO
18
+ from pygeodesy.fmath import fabs, len2, Fsum
19
+ # from pygeodesy.fsums import Fsum # from .fmath
20
20
  from pygeodesy.interns import NN, _clipid_, _convex_, _DOT_, _end_, _few_, \
21
21
  _fi_, _height_, _i_, _invalid_, _j_, _lat_, \
22
22
  _lon_, _near_, _not_, _points_, _start_, _too_
23
23
  from pygeodesy.iters import _imdex2, points2
24
24
  from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
25
- from pygeodesy.named import _Named, _NamedTuple, _Pass
25
+ from pygeodesy.named import _Named, _NamedTuple, _Pass, Property_RO
26
26
  from pygeodesy.points import areaOf, boundsOf, isconvex_, LatLon_
27
- # from pygeodesy.props import Property_RO # from .fsums
27
+ # from pygeodesy.props import Property_RO # from .named
28
28
  from pygeodesy.units import Bool, FIx, HeightX, Lat, Lon, Number_
29
29
 
30
30
  # from math import fabs # from .fmath
31
31
 
32
32
  __all__ = _ALL_LAZY.clipy
33
- __version__ = '23.05.18'
33
+ __version__ = '23.09.20'
34
34
 
35
35
  _fj_ = 'fj'
36
36
  _original_ = 'original'
@@ -576,10 +576,10 @@ class _SH(_Named):
576
576
  x, dx = p1.lon, self._dx
577
577
  fy = float(p2.lat - y)
578
578
  fx = float(p2.lon - x)
579
- d = fy * dx - fx * dy
579
+ d = fy * dx - fx * dy # fdot((fx, fy), dx, -dy)
580
580
  if fabs(d) < EPS: # PYCHOK no cover
581
581
  raise _AssertionError(self._DOT_(self.intersect.__name__))
582
- d = fsumf_(self._xy, -y * dx, x * dy) / d
582
+ d = Fsum(self._xy, -y * dx, x * dy).fover(d)
583
583
  y += d * fy
584
584
  x += d * fx
585
585
  return _SHlli(y, x, p1.classof, edge)
pygeodesy/constants.py CHANGED
@@ -13,9 +13,9 @@ from pygeodesy.basics import _copysign, isbool, iscomplex, isint, _0_0
13
13
  from pygeodesy.errors import _xError, _xError2, _xkwds_get1, _xkwds_item2
14
14
  # from pygeodesy.internals import _0_0 # from .basics
15
15
  from pygeodesy.interns import _INF_, _NAN_, _UNDER_
16
- # from pygeodesy.lazily import _ALL_LAZY # from .unitsBase
16
+ from pygeodesy.lazily import _ALL_MODS as _MODS, _ALL_LAZY
17
17
  # from pygeodesy.streprs import Fmt # from .unitsBase
18
- from pygeodesy.unitsBase import Float, Int, Radius, _ALL_LAZY, Fmt
18
+ from pygeodesy.unitsBase import Float, Int, Radius, Fmt
19
19
 
20
20
  from math import fabs, isinf, isnan, pi as _pi, sqrt
21
21
  try:
@@ -24,7 +24,7 @@ except ImportError: # Python 2-
24
24
  _inf, _nan = float(_INF_), float(_NAN_)
25
25
 
26
26
  __all__ = _ALL_LAZY.constants
27
- __version__ = '24.08.26'
27
+ __version__ = '24.09.24'
28
28
 
29
29
 
30
30
  def _copysign_0_0(y):
@@ -320,20 +320,30 @@ def isclose(a, b, rel_tol=1e-12, abs_tol=EPS0):
320
320
  return _isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol)
321
321
 
322
322
 
323
+ try:
324
+ from cmath import isfinite as _iscfinite
325
+ except ImportError: # Python 3.1-
326
+
327
+ def _iscfinite(x): # PYCHOK not self?
328
+ '''Mimick Python 3.2+ C{cmath.isfinite}.
329
+ '''
330
+ return _isfinite(x.real) and _isfinite(x.imag)
331
+
323
332
  try:
324
333
  from math import isfinite as _isfinite # in .ellipsoids, ...
325
334
  except ImportError: # Python 3.1-
326
335
 
327
- def _isfinite(x):
336
+ def _isfinite(x): # PYCHOK not self?
328
337
  '''Mimick Python 3.2+ C{math.isfinite}.
329
338
  '''
330
339
  return not (isinf(x) or isnan(x))
331
340
 
332
341
 
333
342
  def isfinite(obj):
334
- '''Check a finite C{scalar} or C{complex} value.
343
+ '''Check a finite C{scalar}, C{complex}, ... value.
335
344
 
336
- @arg obj: Value (C{scalar} or C{complex}).
345
+ @arg obj: Value (C{scalar}, C{complex}, an L{Fsum} or
346
+ L{Fsum2Tuple}).
337
347
 
338
348
  @return: C{False} if B{C{obj}} is C{INF}, C{NINF}
339
349
  or C{NAN}, C{True} otherwise.
@@ -344,7 +354,9 @@ def isfinite(obj):
344
354
  return (obj not in _INF_NAN_NINF) and _isfinite(obj)
345
355
  except Exception as x:
346
356
  if iscomplex(obj): # _isfinite(complex) thows TypeError
347
- return isfinite(obj.real) and isfinite(obj.imag)
357
+ return _iscfinite(obj)
358
+ if _MODS.fsums._isFsumTuple(obj): # OverflowError
359
+ return obj.is_finite()
348
360
  raise _xError(x, Fmt.PAREN(isfinite.__name__, obj))
349
361
 
350
362
 
@@ -27,7 +27,7 @@ __all__ = (_ALL_DEPRECATED.deprecated_bases +
27
27
  _ALL_DEPRECATED.deprecated_classes +
28
28
  _ALL_DEPRECATED.deprecated_consterns +
29
29
  _ALL_DEPRECATED.deprecated_functions)
30
- __version__ = '24.07.02'
30
+ __version__ = '24.09.19'
31
31
 
32
32
  if _unLazy0:
33
33
  from pygeodesy.deprecated import bases, datum, nvector, rhumbBase, \
@@ -14,7 +14,7 @@ from pygeodesy.props import deprecated_function
14
14
  from pygeodesy.units import Number_, Scalar_
15
15
 
16
16
  __all__ = _ALL_DEPRECATED.deprecated_functions
17
- __version__ = '24.06.11'
17
+ __version__ = '24.09.19'
18
18
 
19
19
  _WGS84 = _UTM = object()
20
20
 
@@ -193,6 +193,14 @@ def fStrzs(floatstr): # PYCHOK no cover
193
193
  return _MODS.streprs.fstrzs(floatstr)
194
194
 
195
195
 
196
+ @deprecated_function
197
+ def Fsum2product(*xs, **kwds):
198
+ '''DEPRECATED on 2024.09.19, use L{Fsum}C{(*B{xs}, B{f2product}=True, ...)}.'''
199
+ F = _MODS.fsums.Fsum(**kwds)
200
+ _ = F.f2product(True)
201
+ return F._facc_args(xs, up=False) if xs else F
202
+
203
+
196
204
  @deprecated_function
197
205
  def hypot3(x, y, z): # PYCHOK no cover
198
206
  '''DEPRECATED, use function L{pygeodesy.hypot_}.'''
pygeodesy/errors.py CHANGED
@@ -27,7 +27,7 @@ from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _getenv, _PYTHON_X_D
27
27
  from copy import copy as _copy
28
28
 
29
29
  __all__ = _ALL_LAZY.errors # _ALL_DOCS('_InvalidError', '_IsnotError') _under
30
- __version__ = '24.07.07'
30
+ __version__ = '24.09.19'
31
31
 
32
32
  _argument_ = 'argument'
33
33
  _box_ = 'box'
@@ -759,14 +759,16 @@ try:
759
759
  _ = {}.__or__ # {} | {} # Python 3.9+
760
760
 
761
761
  def _xkwds(kwds, **dflts):
762
- '''(INTERNAL) Update C{dflts} with specified C{kwds}.
762
+ '''(INTERNAL) Update C{dflts} with specified C{kwds},
763
+ i.e. C{copy(kwds).update(dflts)}.
763
764
  '''
764
- return (dflts | kwds) if kwds else dflts
765
+ return ((dflts | kwds) if kwds else dflts) if dflts else kwds
765
766
 
766
767
  except AttributeError:
767
768
 
768
769
  def _xkwds(kwds, **dflts): # PYCHOK expected
769
- '''(INTERNAL) Update C{dflts} with specified C{kwds}.
770
+ '''(INTERNAL) Update C{dflts} with specified C{kwds},
771
+ i.e. C{copy(kwds).update(dflts)}.
770
772
  '''
771
773
  d = dflts
772
774
  if kwds:
@@ -787,6 +789,20 @@ except AttributeError:
787
789
  # setattr(inst, NN(_UNDER_, n), v)
788
790
 
789
791
 
792
+ def _xkwds_from(orig, *args, **kwds):
793
+ '''(INTERNAL) Return the items from C{orig} with the keys
794
+ from C{kwds} and a value not in C{args} and C{kwds}.
795
+ '''
796
+ def _items(orig, args, items):
797
+ for n, m in items:
798
+ if n in orig: # n in (orig.keys() & kwds.keys())
799
+ t = orig[n]
800
+ if t is not m and t not in args:
801
+ yield n, t
802
+
803
+ return _items(orig, args, kwds.items())
804
+
805
+
790
806
  def _xkwds_get(kwds, **name_default):
791
807
  '''(INTERNAL) Get a C{kwds} value by C{name} or the
792
808
  C{default} if not present.
@@ -809,7 +825,8 @@ def _xkwds_get_(kwds, **names_defaults):
809
825
 
810
826
  def _xkwds_get1(kwds, **name_default):
811
827
  '''(INTERNAL) Get one C{kwds} value by C{name} or the
812
- C{default} if not present.
828
+ C{default} if not present. Raise an C{_UnexpectedError}
829
+ with any remaining keyword arguments.
813
830
  '''
814
831
  v, kwds = _xkwds_pop2(kwds, **name_default)
815
832
  if kwds:
@@ -842,6 +859,16 @@ def _xkwds_not(*args, **kwds):
842
859
  return dict((n, v) for n, v in kwds.items() if v not in args)
843
860
 
844
861
 
862
+ def _xkwds_pop(kwds, **name_default):
863
+ '''(INTERNAL) Pop an item by C{name} from C{kwds} and
864
+ return its value, otherwise return the C{default}.
865
+ '''
866
+ if isinstance(kwds, dict) and len(name_default) == 1:
867
+ for n, v in name_default.items():
868
+ return kwds.pop(n, v)
869
+ raise _xAssertionError(_xkwds_pop, kwds, **name_default)
870
+
871
+
845
872
  def _xkwds_pop2(kwds, **name_default):
846
873
  '''(INTERNAL) Pop a C{kwds} item by C{name} and return the value and
847
874
  reduced C{kwds} copy, otherwise the C{default} and original C{kwds}.
pygeodesy/fmath.py CHANGED
@@ -10,11 +10,11 @@ from pygeodesy.basics import _copysign, copysign0, isbool, isint, isscalar, \
10
10
  len2, map1, _xiterable
11
11
  from pygeodesy.constants import EPS0, EPS02, EPS1, NAN, PI, PI_2, PI_4, \
12
12
  _0_0, _0_125, _1_6th, _0_25, _1_3rd, _0_5, _1_0, \
13
- _N_1_0, _1_5, _copysign_0_0, _isfinite, remainder
13
+ _N_1_0, _1_5, _copysign_0_0, isfinite, remainder
14
14
  from pygeodesy.errors import _IsnotError, LenError, _TypeError, _ValueError, \
15
15
  _xError, _xkwds_get1, _xkwds_pop2
16
- from pygeodesy.fsums import _2float, Fsum, fsum, fsum1_, _isFsumTuple, _1primed, \
17
- Fmt, unstr
16
+ from pygeodesy.fsums import _2float, Fsum, fsum, fsum1_, _isFsumTuple, \
17
+ _1primed, _Psum_, Fmt, unstr
18
18
  from pygeodesy.interns import MISSING, _negative_, _not_scalar_
19
19
  from pygeodesy.lazily import _ALL_LAZY, _sys_version_info2
20
20
  # from pygeodesy.streprs import Fmt, unstr # from .fsums
@@ -24,7 +24,7 @@ from math import fabs, sqrt # pow
24
24
  import operator as _operator # in .datums, .trf, .utm
25
25
 
26
26
  __all__ = _ALL_LAZY.fmath
27
- __version__ = '24.09.09'
27
+ __version__ = '24.09.19'
28
28
 
29
29
  # sqrt(2) - 1 <https://WikiPedia.org/wiki/Square_root_of_2>
30
30
  _0_4142 = 0.41421356237309504880 # ... ~ 3730904090310553 / 9007199254740992
@@ -431,8 +431,9 @@ def fdot(a, *b):
431
431
 
432
432
  @raise LenError: Unequal C{len(B{a})} and C{len(B{b})}.
433
433
 
434
- @see: Class L{Fdot} and U{Algorithm 5.10 B{DotK}
435
- <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}.
434
+ @see: Class L{Fdot}, U{Algorithm 5.10 B{DotK}
435
+ <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>} and function
436
+ C{math.sumprod} in Python 3.12 and later.
436
437
  '''
437
438
  return fsum(_map_mul(a, b, fdot))
438
439
 
@@ -544,16 +545,20 @@ def fidw(xs, ds, beta=2):
544
545
  return x
545
546
 
546
547
 
547
- def fma(x, y, z):
548
- '''Fused-multiply-add, as C{math.fma(x, y, z)} from Python 3.13+.
548
+ def fma(x, y, z, **raiser):
549
+ '''Fused-multiply-add, using C{math.fma(x, y, z)} from Python 3.13+
550
+ or an equivalent implementation.
549
551
 
550
- @arg x: A C{scalar}, an L{Fsum} or L{Fsum2Tuple} instance.
551
- @arg y: A C{scalar}, an L{Fsum} or L{Fsum2Tuple} instance.
552
- @arg z: A C{scalar}, an L{Fsum} or L{Fsum2Tuple} instance.
552
+ @arg x: Multiplicand (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
553
+ @arg y: Multiplier (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
554
+ @arg z: Addend (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
555
+ @kwarg raiser: Keyword argument C{B{raiser}=False}, if C{True},
556
+ throw an exception, otherwise pass any non-finite
557
+ result (C{bool}).
553
558
 
554
- @return: C{(x * y) + z} (C{float} or an L{Fsum}).
559
+ @return: C{(x * y) + z} (L{Fsum} or C{float}).
555
560
  '''
556
- return Fsum(x).fma(y, z).as_iscalar
561
+ return _Psum_(x).fma(y, z, raiser=raiser).as_iscalar
557
562
 
558
563
 
559
564
  def fmean(xs):
@@ -581,6 +586,22 @@ def fmean_(*xs):
581
586
  return fmean(xs)
582
587
 
583
588
 
589
+ def f2mul_(x, *ys, **raiser):
590
+ '''Cascaded, accurate multiplication C{B{x} * B{y} * B{y} ...} for all B{C{ys}}.
591
+
592
+ @arg x: Multiplicand (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
593
+ @arg ys: Multipliers (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all
594
+ positional.
595
+ @kwarg raiser: Keyword argument C{B{raiser}=False}, if C{True}, throw an
596
+ exception, otherwise pass any non-finite result (C{bool}).
597
+
598
+ @return: The cascaded I{TwoProduct} (L{Fsum}, C{float} or C{int}).
599
+
600
+ @see: U{Equations 2.3<https://www.TUHH.De/ti3/paper/rump/OzOgRuOi06.pdf>}
601
+ '''
602
+ return _Psum_(x).f2mul_(*ys, **raiser).as_iscalar
603
+
604
+
584
605
  def fpolynomial(x, *cs, **over):
585
606
  '''Evaluate the polynomial M{sum(cs[i] * x**i for i=0..len(cs))
586
607
  [/ over]}.
@@ -615,7 +636,7 @@ def fpowers(x, n, alts=0):
615
636
  elif n < 1:
616
637
  raise _ValueError(n=n)
617
638
 
618
- p = x if isint(x) or _isFsumTuple(x) else _2float(x=x)
639
+ p = x if isscalar(x) or _isFsumTuple(x) else _2float(x=x)
619
640
  ps = tuple(_powers(p, n))
620
641
 
621
642
  if alts > 0: # x**2, x**4, ...
@@ -752,7 +773,7 @@ def fremainder(x, y):
752
773
  # On Windows 32-bit with python 2.7, math.fmod(-0.0, 360)
753
774
  # == +0.0. This fixes this bug. See also Math::AngNormalize
754
775
  # in the C++ library, Math.sincosd has a similar fix.
755
- if _isfinite(x):
776
+ if isfinite(x):
756
777
  try:
757
778
  r = remainder(x, y) if x else x
758
779
  except Exception as e:
pygeodesy/fstats.py CHANGED
@@ -10,9 +10,10 @@ from __future__ import division as _; del _ # PYCHOK semicolon
10
10
  from pygeodesy.basics import isscalar, isodd, _xinstanceof, \
11
11
  _xiterable, _xsubclassof, _zip
12
12
  from pygeodesy.constants import _0_0, _1_0, _2_0, _3_0, _4_0, _6_0
13
- from pygeodesy.errors import _AssertionError, _ValueError, _xError
13
+ from pygeodesy.errors import _ValueError, _xError, _xkwds_item2
14
14
  from pygeodesy.fmath import Fsqrt, Fmt
15
- from pygeodesy.fsums import _2finite, Fsum, _iadd_op_, _isFsumTuple
15
+ from pygeodesy.fsums import _2finite, Fsum, _iadd_op_, \
16
+ _isFsumTuple, _xsError
16
17
  from pygeodesy.interns import _odd_, _SPACE_
17
18
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY
18
19
  from pygeodesy.named import _name__, _Named, _NotImplemented, \
@@ -21,24 +22,19 @@ from pygeodesy.named import _name__, _Named, _NotImplemented, \
21
22
  # from pygeodesy.streprs import Fmt # from .fmath
22
23
 
23
24
  __all__ = _ALL_LAZY.fstats
24
- __version__ = '24.05.21'
25
+ __version__ = '24.09.23'
25
26
 
26
27
 
27
28
  def _2Floats(**xs):
28
- '''(INTERNAL) Yield each value as C{float} or L{Fsum}.
29
+ '''(INTERNAL) Yield all C{xs} as C{float} or L{Fsum}.
29
30
  '''
31
+ name, xs = _xkwds_item2(xs)
30
32
  try:
31
- name, xs = xs.popitem()
32
- except Exception as X:
33
- raise _AssertionError(xs=xs, cause=X)
34
-
35
- try:
36
- i = None
33
+ i, x = None, xs
37
34
  for i, x in enumerate(_xiterable(xs)): # don't unravel Fsums
38
35
  yield x._Fsum if _isFsumTuple(x) else _2finite(x)
39
36
  except Exception as X:
40
- raise _xError(X, name, xs) if i is None else \
41
- _xError(X, Fmt.INDEX(name, i), x)
37
+ raise _xsError(X, xs, i, x, name)
42
38
 
43
39
 
44
40
  def _sampled(n, sample):