sofar 1.2.0__tar.gz → 1.2.2__tar.gz
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.
- {sofar-1.2.0 → sofar-1.2.2}/CONTRIBUTING.rst +2 -4
- {sofar-1.2.0 → sofar-1.2.2}/HISTORY.rst +9 -0
- {sofar-1.2.0 → sofar-1.2.2}/PKG-INFO +58 -12
- {sofar-1.2.0 → sofar-1.2.2}/README.md +1 -0
- {sofar-1.2.0 → sofar-1.2.2}/docs/conf.py +44 -12
- sofar-1.2.2/docs/resources/conventions.py +162 -0
- sofar-1.2.2/pyproject.toml +157 -0
- sofar-1.2.2/setup.cfg +4 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/__init__.py +2 -1
- {sofar-1.2.0 → sofar-1.2.2}/sofar/io.py +15 -19
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa.py +53 -29
- sofar-1.2.2/sofar/sofa_conventions/write_upgrade_rules.py +139 -0
- sofar-1.2.2/sofar/sofa_conventions/write_verification_data.py +313 -0
- sofar-1.2.2/sofar/sofa_conventions/write_verification_rules.py +356 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofastream.py +13 -8
- {sofar-1.2.0 → sofar-1.2.2}/sofar/update_conventions.py +19 -17
- {sofar-1.2.0 → sofar-1.2.2}/sofar/utils.py +4 -3
- {sofar-1.2.0 → sofar-1.2.2}/sofar.egg-info/PKG-INFO +58 -12
- {sofar-1.2.0 → sofar-1.2.2}/sofar.egg-info/SOURCES.txt +4 -4
- sofar-1.2.2/sofar.egg-info/requires.txt +31 -0
- sofar-1.2.2/sofar.egg-info/top_level.txt +5 -0
- {sofar-1.2.0 → sofar-1.2.2}/tests/test_deprecations.py +2 -2
- {sofar-1.2.0 → sofar-1.2.2}/tests/test_io.py +18 -17
- {sofar-1.2.0 → sofar-1.2.2}/tests/test_sofa.py +29 -30
- {sofar-1.2.0 → sofar-1.2.2}/tests/test_sofa_upgrade_conventions.py +1 -1
- {sofar-1.2.0 → sofar-1.2.2}/tests/test_sofa_verify.py +40 -39
- {sofar-1.2.0 → sofar-1.2.2}/tests/test_sofastream.py +12 -11
- {sofar-1.2.0 → sofar-1.2.2}/tests/test_utils.py +5 -6
- sofar-1.2.0/AUTHORS.rst +0 -15
- sofar-1.2.0/pyproject.toml +0 -13
- sofar-1.2.0/setup.cfg +0 -23
- sofar-1.2.0/setup.py +0 -76
- sofar-1.2.0/sofar.egg-info/not-zip-safe +0 -1
- sofar-1.2.0/sofar.egg-info/requires.txt +0 -5
- sofar-1.2.0/sofar.egg-info/top_level.txt +0 -2
- {sofar-1.2.0 → sofar-1.2.2}/LICENSE +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/MANIFEST.in +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/docs/Makefile +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/docs/api_reference.rst +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/docs/contributing.rst +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/docs/history.rst +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/docs/index.rst +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/docs/make.bat +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/docs/readme.rst +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/docs/resources/working_with_sofa_HRIR_lateral.png +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/docs/resources/working_with_sofa_source_horizontal.png +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/docs/resources/working_with_sofa_source_lateral.png +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/docs/sofar.rst +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/VERSION +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/AnnotatedEmitterAudio_0.2.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/AnnotatedEmitterAudio_0.2.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/AnnotatedReceiverAudio_0.2.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/AnnotatedReceiverAudio_0.2.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/FreeFieldDirectivityTF_1.1.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/FreeFieldDirectivityTF_1.1.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/FreeFieldHRIR_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/FreeFieldHRIR_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/FreeFieldHRTF_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/FreeFieldHRTF_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralFIR-E_2.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralFIR-E_2.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralFIR_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralFIR_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralSOS_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralSOS_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralTF-E_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralTF-E_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralTF_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralTF_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralTF_2.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralTF_2.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldHRIR_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldHRIR_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldHRSOS_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldHRSOS_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldHRTF_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldHRTF_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldSOS_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldSOS_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleHeadphoneIR_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleHeadphoneIR_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SingleRoomMIMOSRIR_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SingleRoomMIMOSRIR_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SingleRoomSRIR_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SingleRoomSRIR_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/AnnotatedEmitterAudio_0.1.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/AnnotatedEmitterAudio_0.1.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/AnnotatedReceiverAudio_0.1.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/AnnotatedReceiverAudio_0.1.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/FreeFieldDirectivityTF_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/FreeFieldDirectivityTF_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/GeneralFIRE_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/GeneralFIRE_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/MultiSpeakerBRIR_0.3.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/MultiSpeakerBRIR_0.3.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldHRIR_0.4.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldHRIR_0.4.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldTF_0.4.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldTF_0.4.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldTF_1.0.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldTF_1.0.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleHeadphoneIR_0.1.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleHeadphoneIR_0.1.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleHeadphoneIR_0.2.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleHeadphoneIR_0.2.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleRoomDRIR_0.2.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleRoomDRIR_0.2.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleRoomDRIR_0.3.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleRoomDRIR_0.3.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleTrackedAudio_0.1.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleTrackedAudio_0.1.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleTrackedAudio_0.2.csv +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleTrackedAudio_0.2.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/rules/deprecations.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/rules/rules.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/rules/unit_aliases.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/rules/upgrade.json +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/sofar.egg-info/dependency_links.txt +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/tests/__init__.py +0 -0
- {sofar-1.2.0 → sofar-1.2.2}/tests/conftest.py +0 -0
@@ -45,14 +45,12 @@ Ready to contribute? Here's how to set up `sofar` for local development using th
|
|
45
45
|
3. Note that some graphical Git interfaces can not do the recursive clone. If the folder sofar/sofa_conventions is empty try::
|
46
46
|
|
47
47
|
$ git submodule update --init
|
48
|
-
|
48
|
+
|
49
49
|
4. Install your local copy into a virtualenv. Assuming you have Anaconda or Miniconda installed, this is how you set up your fork for local development::
|
50
50
|
|
51
51
|
$ conda create --name sofar python
|
52
52
|
$ conda activate sofar
|
53
|
-
$
|
54
|
-
$ pip install -e .
|
55
|
-
$ pip install -r requirements_dev.txt
|
53
|
+
$ pip install -e ".[dev]"
|
56
54
|
|
57
55
|
5. Create a branch for local development. Indicate the intention of your branch in its respective name (i.e. `feature/branch-name` or `bugfix/branch-name`)::
|
58
56
|
|
@@ -2,6 +2,15 @@
|
|
2
2
|
History
|
3
3
|
=======
|
4
4
|
|
5
|
+
1.2.2 (2025-05-09)
|
6
|
+
------------------
|
7
|
+
* Docs: Improve layout of header (#125)
|
8
|
+
* Deployment: Add missing dependency for `packaging` package and support for Python 3.13 (PR #125, #127)
|
9
|
+
|
10
|
+
1.2.1 (2024-12-12)
|
11
|
+
------------------
|
12
|
+
* Deployment: Move from setup.py to pyproject.toml (PR #114, #115)
|
13
|
+
|
5
14
|
1.2.0 (2024-08-29)
|
6
15
|
------------------
|
7
16
|
* Feature: Introduce `SofaStream` class for reading parts of large Sofa files without reading the entire file (PR #90, 97)
|
@@ -1,16 +1,38 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: sofar
|
3
|
-
Version: 1.2.
|
4
|
-
Summary: Maybe the most complete python package for SOFA files so far
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
Version: 1.2.2
|
4
|
+
Summary: Maybe the most complete python package for SOFA files so far.
|
5
|
+
Author-email: The pyfar developers <info@pyfar.org>
|
6
|
+
License: MIT License
|
7
|
+
|
8
|
+
Copyright (c) 2021, The pyfar developers
|
9
|
+
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
12
|
+
in the Software without restriction, including without limitation the rights
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
15
|
+
furnished to do so, subject to the following conditions:
|
16
|
+
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
18
|
+
copies or substantial portions of the Software.
|
19
|
+
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
26
|
+
SOFTWARE.
|
27
|
+
|
28
|
+
|
29
|
+
Project-URL: Tracker, https://github.com/pyfar/sofar/issues
|
11
30
|
Project-URL: Documentation, https://sofar.readthedocs.io/
|
12
|
-
Project-URL:
|
13
|
-
|
31
|
+
Project-URL: Download, https://pypi.org/project/sofar/
|
32
|
+
Project-URL: Homepage, https://pyfar.org/
|
33
|
+
Project-URL: Source, https://github.com/pyfar/sofar
|
34
|
+
Project-URL: Changelog, https://github.com/pyfar/sofar/blob/main/HISTORY.rst
|
35
|
+
Keywords: acoustics,pyfar
|
14
36
|
Classifier: Development Status :: 4 - Beta
|
15
37
|
Classifier: Intended Audience :: Science/Research
|
16
38
|
Classifier: License :: OSI Approved :: MIT License
|
@@ -21,15 +43,38 @@ Classifier: Programming Language :: Python :: 3.9
|
|
21
43
|
Classifier: Programming Language :: Python :: 3.10
|
22
44
|
Classifier: Programming Language :: Python :: 3.11
|
23
45
|
Classifier: Programming Language :: Python :: 3.12
|
46
|
+
Classifier: Programming Language :: Python :: 3.13
|
24
47
|
Requires-Python: >=3.8
|
25
48
|
Description-Content-Type: text/markdown
|
26
49
|
License-File: LICENSE
|
27
|
-
License-File: AUTHORS.rst
|
28
50
|
Requires-Dist: netCDF4
|
29
51
|
Requires-Dist: numpy>=1.14.0
|
30
52
|
Requires-Dist: beautifulsoup4
|
31
53
|
Requires-Dist: requests
|
32
54
|
Requires-Dist: packaging
|
55
|
+
Provides-Extra: deploy
|
56
|
+
Requires-Dist: twine; extra == "deploy"
|
57
|
+
Requires-Dist: wheel; extra == "deploy"
|
58
|
+
Requires-Dist: build; extra == "deploy"
|
59
|
+
Requires-Dist: setuptools; extra == "deploy"
|
60
|
+
Requires-Dist: bump-my-version; extra == "deploy"
|
61
|
+
Provides-Extra: tests
|
62
|
+
Requires-Dist: pytest; extra == "tests"
|
63
|
+
Requires-Dist: pytest-cov; extra == "tests"
|
64
|
+
Requires-Dist: watchdog; extra == "tests"
|
65
|
+
Requires-Dist: ruff==0.8.2; extra == "tests"
|
66
|
+
Requires-Dist: coverage; extra == "tests"
|
67
|
+
Provides-Extra: docs
|
68
|
+
Requires-Dist: sphinx; extra == "docs"
|
69
|
+
Requires-Dist: autodocsumm>=0.2.14; extra == "docs"
|
70
|
+
Requires-Dist: pydata-sphinx-theme; extra == "docs"
|
71
|
+
Requires-Dist: sphinx_mdinclude; extra == "docs"
|
72
|
+
Requires-Dist: sphinx-design; extra == "docs"
|
73
|
+
Requires-Dist: sphinx-favicon; extra == "docs"
|
74
|
+
Requires-Dist: sphinx-reredirects; extra == "docs"
|
75
|
+
Provides-Extra: dev
|
76
|
+
Requires-Dist: sofar[deploy,docs,tests]; extra == "dev"
|
77
|
+
Dynamic: license-file
|
33
78
|
|
34
79
|
<h1 align="center">
|
35
80
|
<img src="https://github.com/pyfar/gallery/raw/main/docs/resources/logos/pyfar_logos_fixed_size_sofar.png" width="300">
|
@@ -38,6 +83,7 @@ Requires-Dist: packaging
|
|
38
83
|
[](https://badge.fury.io/py/sofar)
|
39
84
|
[](https://sofar.readthedocs.io/en/latest/?badge=latest)
|
40
85
|
[](https://circleci.com/gh/pyfar/sofar)
|
86
|
+
[](https://mybinder.org/v2/gh/pyfar/gallery/main?labpath=docs/gallery/interactive/sofar_introduction.ipynb)
|
41
87
|
|
42
88
|
Sofar is maybe the most complete Python package for the SOFA file format so
|
43
89
|
far. SOFA files store spatially distributed acoustic data such as impulse
|
@@ -5,6 +5,7 @@
|
|
5
5
|
[](https://badge.fury.io/py/sofar)
|
6
6
|
[](https://sofar.readthedocs.io/en/latest/?badge=latest)
|
7
7
|
[](https://circleci.com/gh/pyfar/sofar)
|
8
|
+
[](https://mybinder.org/v2/gh/pyfar/gallery/main?labpath=docs/gallery/interactive/sofar_introduction.ipynb)
|
8
9
|
|
9
10
|
Sofar is maybe the most complete Python package for the SOFA file format so
|
10
11
|
far. SOFA files store spatially distributed acoustic data such as impulse
|
@@ -10,10 +10,11 @@ import os
|
|
10
10
|
import sys
|
11
11
|
import urllib3
|
12
12
|
import shutil
|
13
|
+
import numpy as np
|
13
14
|
sys.path.insert(0, os.path.abspath('..'))
|
14
15
|
|
15
|
-
import sofar
|
16
|
-
import resources.conventions
|
16
|
+
import sofar
|
17
|
+
import resources.conventions
|
17
18
|
|
18
19
|
# -- General configuration ---------------------------------------------------
|
19
20
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
@@ -117,7 +118,8 @@ html_theme_options = {
|
|
117
118
|
"navbar_start": ["navbar-logo"],
|
118
119
|
"navbar_end": ["navbar-icon-links", "theme-switcher"],
|
119
120
|
"navbar_align": "content",
|
120
|
-
"header_links_before_dropdown":
|
121
|
+
"header_links_before_dropdown": None, # will be automatically set later based on headers.rst
|
122
|
+
"header_dropdown_text": "Packages", # Change dropdown name from "More" to "Packages"
|
121
123
|
"icon_links": [
|
122
124
|
{
|
123
125
|
"name": "GitHub",
|
@@ -130,6 +132,8 @@ html_theme_options = {
|
|
130
132
|
"show_toc_level": 3, # Show all subsections of notebooks
|
131
133
|
"secondary_sidebar_items": ["page-toc"], # Omit 'show source' link that that shows notebook in json format
|
132
134
|
"navigation_with_keys": True,
|
135
|
+
# Configure navigation depth for section navigation
|
136
|
+
"navigation_depth": 1,
|
133
137
|
}
|
134
138
|
|
135
139
|
html_context = {
|
@@ -150,16 +154,44 @@ folders_in = [
|
|
150
154
|
'_static/header.rst',
|
151
155
|
'resources/logos/pyfar_logos_fixed_size_sofar.png',
|
152
156
|
]
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
157
|
+
|
158
|
+
def download_files_from_gallery(link, folders_in):
|
159
|
+
c = urllib3.PoolManager()
|
160
|
+
for file in folders_in:
|
161
|
+
url = link + file
|
162
|
+
filename = file
|
163
|
+
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
164
|
+
with c.request('GET', url, preload_content=False) as res:
|
165
|
+
if res.status == 200:
|
166
|
+
with open(filename, 'wb') as out_file:
|
167
|
+
shutil.copyfileobj(res, out_file)
|
168
|
+
|
169
|
+
download_files_from_gallery(link, folders_in)
|
170
|
+
# if logo does not exist, use pyfar logo
|
171
|
+
if not os.path.exists(html_logo):
|
172
|
+
download_files_from_gallery(
|
173
|
+
link, ['resources/logos/pyfar_logos_fixed_size_pyfar.png'])
|
174
|
+
shutil.copyfile(
|
175
|
+
'resources/logos/pyfar_logos_fixed_size_pyfar.png', html_logo)
|
160
176
|
|
161
177
|
# replace sofar hard link to internal link
|
162
178
|
with open("_static/header.rst", "rt") as fin:
|
163
179
|
with open("header.rst", "wt") as fout:
|
164
|
-
for line in fin
|
165
|
-
|
180
|
+
lines = [line.replace(f'https://{project}.readthedocs.io', project) for line in fin]
|
181
|
+
contains_project = any(project in line for line in lines)
|
182
|
+
|
183
|
+
fout.writelines(lines)
|
184
|
+
|
185
|
+
# add project to the list of projects if not in header
|
186
|
+
if not contains_project:
|
187
|
+
fout.write(f' {project} <{project}>\n')
|
188
|
+
|
189
|
+
# count the number of gallery headings
|
190
|
+
count_gallery_headings = np.sum(
|
191
|
+
['https://pyfar-gallery.readthedocs.io' in line for line in lines])
|
192
|
+
|
193
|
+
|
194
|
+
# set dropdown header after gallery headings
|
195
|
+
html_theme_options['header_links_before_dropdown'] = count_gallery_headings+1
|
196
|
+
|
197
|
+
|
@@ -0,0 +1,162 @@
|
|
1
|
+
import os
|
2
|
+
import sys
|
3
|
+
import json
|
4
|
+
sys.path.insert(0, os.path.abspath(os.path.join('..', '..')))
|
5
|
+
|
6
|
+
import sofar as sf
|
7
|
+
|
8
|
+
base_dir = os.path.dirname(__file__)
|
9
|
+
|
10
|
+
# get conventions (paths, names, version) and upgrade rules -------------------
|
11
|
+
paths = sf.utils._get_conventions('path')
|
12
|
+
names_versions = sf.utils._get_conventions('name_version')
|
13
|
+
|
14
|
+
# using Sofa()._verification_rules() does not work on readthedocs
|
15
|
+
upgrade_rules = os.path.join(
|
16
|
+
os.path.dirname(paths[0]), '..', 'rules', 'upgrade.json')
|
17
|
+
with open(upgrade_rules) as file:
|
18
|
+
upgrade_rules = json.load(file)
|
19
|
+
|
20
|
+
deprecation_rules = os.path.join(
|
21
|
+
os.path.dirname(paths[0]), '..', 'rules', 'deprecations.json')
|
22
|
+
with open(deprecation_rules) as file:
|
23
|
+
deprecation_rules = json.load(file)
|
24
|
+
|
25
|
+
# write general information ---------------------------------------------------
|
26
|
+
docs = (
|
27
|
+
'.. _conventions_introduction:\n\n'
|
28
|
+
'SOFA Conventions\n'
|
29
|
+
'================\n\n'
|
30
|
+
'SOFA conventions specify what data and metadata must be stored in a SOFA '
|
31
|
+
'file. Different conventions can be used to store different types of data,'
|
32
|
+
'e.g., head-related impulse responses or musical instrument directivities.'
|
33
|
+
'It is advised to always use the conventions that is most specific for the'
|
34
|
+
'data.\n\n'
|
35
|
+
'In the following, SOFA conventions are described in tables with the '
|
36
|
+
'information\n\n'
|
37
|
+
'* **Name:** The Name of the data. The prefix *GLOBAL* denotes global '
|
38
|
+
'attribute, i.e., attributes that pertain the entire data set. Underscores'
|
39
|
+
' denote attributes that are data specific. E.g., *SourcePosition_Units* '
|
40
|
+
'denotes the *Units* of the data *SourcePosition*.\n'
|
41
|
+
'* **Type:** The Type of the data.\n\n'
|
42
|
+
' * **Attribute:** A verbose description given by a string\n'
|
43
|
+
' * **Double:** A numeric array of data\n'
|
44
|
+
' * **String:** A string array of data\n\n'
|
45
|
+
'* **Default:** The default value\n'
|
46
|
+
'* **Dimensions:** The dimensions of the data. Lower case letters denote '
|
47
|
+
'the data that sets the dimension.\n\n'
|
48
|
+
' * **E:** Number of emitters\n'
|
49
|
+
' * **R:** Number of receivers\n'
|
50
|
+
' * **M:** Number of measurements\n'
|
51
|
+
' * **N:** Number of samples or frequency bins of the data\n'
|
52
|
+
' * **C:** Number of coordinates (always 3)\n'
|
53
|
+
' * **I:** Unity dimensions (always 1)\n'
|
54
|
+
' * **S:** Lengths of the longest string contained in the data '
|
55
|
+
'(detected automatically)\n\n'
|
56
|
+
'* **Flags:**\n\n'
|
57
|
+
' * **r:** read only data. Data can be written if flag is missing.\n'
|
58
|
+
' * **m:** mandatory data. Data is optional if flag is missing\n\n')
|
59
|
+
|
60
|
+
# write table of content ------------------------------------------------------
|
61
|
+
docs += '.. _conventions:\n\nConventions\n-----------\n\n'
|
62
|
+
for path, name_version in zip(paths, names_versions):
|
63
|
+
name, version = name_version
|
64
|
+
|
65
|
+
label = f'{name} v{version}'
|
66
|
+
if 'deprecated' in path:
|
67
|
+
label += ' (deprecated)'
|
68
|
+
reference = f'{name}_{version}'
|
69
|
+
|
70
|
+
docs += f'* :ref:`{label} <{reference}>`\n'
|
71
|
+
|
72
|
+
# write conventions -----------------------------------------------------------
|
73
|
+
docs += '\nCurrent\n-------\n\n'
|
74
|
+
|
75
|
+
# loop conventions
|
76
|
+
deprecated = False
|
77
|
+
for path, name_version in zip(paths, names_versions):
|
78
|
+
name, version = name_version
|
79
|
+
|
80
|
+
# read convention from json file
|
81
|
+
with open(path, 'r') as file:
|
82
|
+
convention = json.load(file)
|
83
|
+
|
84
|
+
# write section title
|
85
|
+
if 'deprecated' in path and not deprecated:
|
86
|
+
docs += 'Deprecated\n----------\n\n'
|
87
|
+
deprecated = True
|
88
|
+
|
89
|
+
# write convention name, version
|
90
|
+
docs += f'.. _{name}_{version}:\n\n'
|
91
|
+
docs += f'**{name} v{version}**\n\n'
|
92
|
+
|
93
|
+
# name new convention if current convention is deprecated
|
94
|
+
if deprecated:
|
95
|
+
# upgrade rules give best feedback
|
96
|
+
if name in upgrade_rules:
|
97
|
+
for upgrade in upgrade_rules[name]['from_to']:
|
98
|
+
if version in upgrade[0]:
|
99
|
+
upgrade_to = upgrade[1]
|
100
|
+
references = [f':ref:`{u} <{u}>`' for u in upgrade_to]
|
101
|
+
':ref:`{label} <{reference}>`'
|
102
|
+
docs += ('This convention is deprecated. '
|
103
|
+
f'Use {", ".join(references)} instead.\n\n')
|
104
|
+
# deprecations are used if no upgrade rules are available
|
105
|
+
elif name in deprecation_rules['GLOBAL:SOFAConventions']:
|
106
|
+
docs += ("This convention is deprecated. Use "
|
107
|
+
f"{deprecation_rules['GLOBAL:SOFAConventions'][name]} "
|
108
|
+
"instead.\n\n")
|
109
|
+
|
110
|
+
# name purpose of the convention
|
111
|
+
docs += f'{convention["GLOBAL:SOFAConventions"]["comment"]}\n\n'
|
112
|
+
|
113
|
+
# write header
|
114
|
+
docs += (
|
115
|
+
'.. list-table::\n'
|
116
|
+
' :widths: 20 50 25 30 100\n'
|
117
|
+
' :header-rows: 1\n\n'
|
118
|
+
' * - Name (Type)\n'
|
119
|
+
' - Default\n'
|
120
|
+
' - Dim.\n'
|
121
|
+
' - Flags\n'
|
122
|
+
' - Comment\n')
|
123
|
+
|
124
|
+
# loop entries
|
125
|
+
for key, value in convention.items():
|
126
|
+
|
127
|
+
if value["dimensions"] is None:
|
128
|
+
dimensions = ""
|
129
|
+
else:
|
130
|
+
dimensions = value["dimensions"]
|
131
|
+
|
132
|
+
if value["flags"] is None:
|
133
|
+
flags = ""
|
134
|
+
elif len(value["flags"]) > 1:
|
135
|
+
flags = f'{value["flags"][0]}, {value["flags"][1]}'
|
136
|
+
else:
|
137
|
+
flags = value["flags"]
|
138
|
+
|
139
|
+
if key == "GLOBAL:SOFAConventions":
|
140
|
+
value["comment"] = ""
|
141
|
+
|
142
|
+
if value["type"] == 'attribute':
|
143
|
+
type_str = 'attr.'
|
144
|
+
elif value["type"] == 'double':
|
145
|
+
type_str = 'doub.'
|
146
|
+
else:
|
147
|
+
type_str = 'str.'
|
148
|
+
|
149
|
+
docs += (
|
150
|
+
f' * - {key.replace(":", "_").replace(".", "_")} '
|
151
|
+
f'(*{value["type"]}*)\n'
|
152
|
+
f' - {value["default"]}\n'
|
153
|
+
f' - {dimensions}\n'
|
154
|
+
f' - {flags}\n'
|
155
|
+
f' - {value["comment"]}\n')
|
156
|
+
|
157
|
+
docs += '\n:ref:`back to top <conventions>`\n\n'
|
158
|
+
|
159
|
+
# write docs to rst file ------------------------------------------------------
|
160
|
+
docs_file = os.path.join(base_dir, 'conventions.rst')
|
161
|
+
with open(docs_file, 'w') as file:
|
162
|
+
file.writelines(docs)
|
@@ -0,0 +1,157 @@
|
|
1
|
+
[project]
|
2
|
+
name = "sofar"
|
3
|
+
version = "1.2.2"
|
4
|
+
description = "Maybe the most complete python package for SOFA files so far."
|
5
|
+
readme = "README.md"
|
6
|
+
license = {file = "LICENSE"}
|
7
|
+
requires-python = ">=3.8"
|
8
|
+
authors = [
|
9
|
+
{ name = "The pyfar developers", email = "info@pyfar.org" },
|
10
|
+
]
|
11
|
+
keywords = [
|
12
|
+
"acoustics",
|
13
|
+
"pyfar",
|
14
|
+
]
|
15
|
+
classifiers = [
|
16
|
+
"Development Status :: 4 - Beta",
|
17
|
+
"Intended Audience :: Science/Research",
|
18
|
+
"License :: OSI Approved :: MIT License",
|
19
|
+
"Natural Language :: English",
|
20
|
+
"Programming Language :: Python :: 3",
|
21
|
+
"Programming Language :: Python :: 3.8",
|
22
|
+
"Programming Language :: Python :: 3.9",
|
23
|
+
"Programming Language :: Python :: 3.10",
|
24
|
+
"Programming Language :: Python :: 3.11",
|
25
|
+
"Programming Language :: Python :: 3.12",
|
26
|
+
"Programming Language :: Python :: 3.13",
|
27
|
+
]
|
28
|
+
dependencies = [
|
29
|
+
'netCDF4',
|
30
|
+
'numpy>=1.14.0',
|
31
|
+
'beautifulsoup4',
|
32
|
+
'requests',
|
33
|
+
'packaging',
|
34
|
+
]
|
35
|
+
|
36
|
+
[project.optional-dependencies]
|
37
|
+
deploy = [
|
38
|
+
"twine",
|
39
|
+
"wheel",
|
40
|
+
"build",
|
41
|
+
"setuptools",
|
42
|
+
"bump-my-version",
|
43
|
+
]
|
44
|
+
tests = [
|
45
|
+
"pytest",
|
46
|
+
"pytest-cov",
|
47
|
+
"watchdog",
|
48
|
+
"ruff==0.8.2",
|
49
|
+
"coverage",
|
50
|
+
]
|
51
|
+
docs = [
|
52
|
+
"sphinx",
|
53
|
+
"autodocsumm>=0.2.14",
|
54
|
+
"pydata-sphinx-theme",
|
55
|
+
"sphinx_mdinclude",
|
56
|
+
"sphinx-design",
|
57
|
+
"sphinx-favicon",
|
58
|
+
"sphinx-reredirects",
|
59
|
+
]
|
60
|
+
dev = ["sofar[deploy,tests,docs]"]
|
61
|
+
|
62
|
+
[project.urls]
|
63
|
+
Tracker = "https://github.com/pyfar/sofar/issues"
|
64
|
+
Documentation = "https://sofar.readthedocs.io/"
|
65
|
+
Download = "https://pypi.org/project/sofar/"
|
66
|
+
Homepage = "https://pyfar.org/"
|
67
|
+
Source = "https://github.com/pyfar/sofar"
|
68
|
+
Changelog = "https://github.com/pyfar/sofar/blob/main/HISTORY.rst"
|
69
|
+
|
70
|
+
[build-system]
|
71
|
+
requires = ["setuptools>=61.0", "wheel"]
|
72
|
+
build-backend = "setuptools.build_meta"
|
73
|
+
|
74
|
+
[tool.setuptools.packages]
|
75
|
+
find = {} # Scan the project directory with the default parameters
|
76
|
+
|
77
|
+
|
78
|
+
[tool.ruff]
|
79
|
+
exclude = [
|
80
|
+
".git",
|
81
|
+
"docs",
|
82
|
+
]
|
83
|
+
line-length = 79
|
84
|
+
lint.ignore = [
|
85
|
+
"D200", # One-line docstring should fit on one line with quotes
|
86
|
+
"D202", # No blank lines allowed after function docstring
|
87
|
+
"D205", # 1 blank line required between summary line and description
|
88
|
+
"D401", # First line should be in imperative mood
|
89
|
+
"D404", # First word of the docstring should not be "This"
|
90
|
+
"B006", # Do not use mutable data structures for argument defaults
|
91
|
+
"B008", # Do not perform calls in argument defaults
|
92
|
+
"PT018", # Assertion should be broken down into multiple parts
|
93
|
+
"PT019", # Fixture `_` without value is injected as parameter
|
94
|
+
]
|
95
|
+
lint.select = [
|
96
|
+
"B", # bugbear extension
|
97
|
+
"ARG", # Remove unused function/method arguments
|
98
|
+
"C4", # Check for common security issues
|
99
|
+
"E", # PEP8 errors
|
100
|
+
"F", # Pyflakes
|
101
|
+
"W", # PEP8 warnings
|
102
|
+
"D", # Docstring guidelines
|
103
|
+
"NPY", # Check all numpy related deprecations
|
104
|
+
"D417", # Missing argument descriptions in the docstring
|
105
|
+
"PT", # Pytest style
|
106
|
+
"A", # Avoid builtin function and type shadowing
|
107
|
+
"ERA", # No commented out code
|
108
|
+
"NPY", # Check all numpy related deprecations
|
109
|
+
"COM", # trailing comma rules
|
110
|
+
"I002", # missing required import
|
111
|
+
"TID252", # Use absolute over relative imports
|
112
|
+
"FIX", # Code should not contain FIXME, TODO, etc
|
113
|
+
]
|
114
|
+
|
115
|
+
# Ignore missing docstrings in tests
|
116
|
+
[tool.ruff.lint.per-file-ignores]
|
117
|
+
"tests/*" = [
|
118
|
+
"D100",
|
119
|
+
"D101",
|
120
|
+
"D103",
|
121
|
+
"D104",
|
122
|
+
]
|
123
|
+
|
124
|
+
[tool.ruff.lint.pydocstyle]
|
125
|
+
convention = "numpy"
|
126
|
+
|
127
|
+
|
128
|
+
[tool.bumpversion]
|
129
|
+
current_version = "1.2.2"
|
130
|
+
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
131
|
+
serialize = ["{major}.{minor}.{patch}"]
|
132
|
+
search = "{current_version}"
|
133
|
+
replace = "{new_version}"
|
134
|
+
regex = true
|
135
|
+
ignore_missing_version = false
|
136
|
+
ignore_missing_files = false
|
137
|
+
tag = true
|
138
|
+
sign_tags = false
|
139
|
+
tag_name = "v{new_version}"
|
140
|
+
tag_message = "Bump version: {current_version} → {new_version}"
|
141
|
+
allow_dirty = false
|
142
|
+
commit = true
|
143
|
+
message = "Bump version: {current_version} → {new_version}"
|
144
|
+
commit_args = ""
|
145
|
+
setup_hooks = []
|
146
|
+
pre_commit_hooks = []
|
147
|
+
post_commit_hooks = []
|
148
|
+
|
149
|
+
[[tool.bumpversion.files]]
|
150
|
+
filename = "pyproject.toml"
|
151
|
+
search = '\nversion = "{current_version}"'
|
152
|
+
replace = '\nversion = "{new_version}"'
|
153
|
+
|
154
|
+
[[tool.bumpversion.files]]
|
155
|
+
filename = "sofar/__init__.py"
|
156
|
+
search = "__version__ = '{current_version}'"
|
157
|
+
replace = "__version__ = '{new_version}'"
|
sofar-1.2.2/setup.cfg
ADDED
@@ -1,3 +1,4 @@
|
|
1
|
+
"""Module for reading and writing Sofa files with sofar."""
|
1
2
|
import contextlib
|
2
3
|
import os
|
3
4
|
import numpy as np
|
@@ -41,7 +42,6 @@ def read_sofa(filename, verify='auto', verbose=True):
|
|
41
42
|
|
42
43
|
Notes
|
43
44
|
-----
|
44
|
-
|
45
45
|
1. Missing dimensions are appended when writing the SOFA object to disk.
|
46
46
|
E.g., if ``sofa.Data_IR`` is of shape (1, 2) it is written as an array
|
47
47
|
of shape (1, 2, 1) because the SOFA standard AES69 defines it as a
|
@@ -92,7 +92,6 @@ def read_sofa_as_netcdf(filename):
|
|
92
92
|
|
93
93
|
Notes
|
94
94
|
-----
|
95
|
-
|
96
95
|
1. Missing dimensions are appended when writing the SOFA object to disk.
|
97
96
|
E.g., if ``sofa.Data_IR`` is of shape (1, 2) it is written as an array
|
98
97
|
of shape (1, 2, 1) because the SOFA standard AES69 defines it as a
|
@@ -129,8 +128,8 @@ def _read_netcdf(filename, verify, verbose, mode):
|
|
129
128
|
|
130
129
|
if mode == "sofa":
|
131
130
|
# get convention name and version
|
132
|
-
convention =
|
133
|
-
version =
|
131
|
+
convention = file.SOFAConventions
|
132
|
+
version = file.SOFAConventionsVersion
|
134
133
|
|
135
134
|
# check if convention and version exist
|
136
135
|
_verify_convention_and_version(version, convention)
|
@@ -213,11 +212,11 @@ def _read_netcdf(filename, verify, verbose, mode):
|
|
213
212
|
if verify:
|
214
213
|
try:
|
215
214
|
sofa.verify(mode="read")
|
216
|
-
except:
|
215
|
+
except: # noqa: E722
|
217
216
|
raise ValueError((
|
218
217
|
"The SOFA object could not be verified, maybe due to erroneous"
|
219
218
|
" data. Call sofa=sofar.read_sofa(filename, verify=False) and "
|
220
|
-
"then sofa.verify() to get more information"))
|
219
|
+
"then sofa.verify() to get more information")) from None
|
221
220
|
|
222
221
|
return sofa
|
223
222
|
|
@@ -235,12 +234,11 @@ def write_sofa(filename: str, sofa: sf.Sofa, compression=4):
|
|
235
234
|
The SOFA object that is written to disk
|
236
235
|
compression : int
|
237
236
|
The level of compression with ``0`` being no compression and ``9``
|
238
|
-
being the best compression. The default
|
239
|
-
size
|
237
|
+
being the best compression. The default ``4`` is a tradeoff between
|
238
|
+
file size and the time required for reading and writing the file.
|
240
239
|
|
241
240
|
Notes
|
242
241
|
-----
|
243
|
-
|
244
242
|
1. Missing dimensions are appended when writing the SOFA object to disk.
|
245
243
|
E.g., if ``sofa.Data_IR`` is of shape (1, 2) it is written as an array
|
246
244
|
of shape (1, 2, 1) because the SOFA standard AES69 defines it as a
|
@@ -281,7 +279,7 @@ def _write_sofa(filename: str, sofa: sf.Sofa, compression=4, verify=True):
|
|
281
279
|
"Writing SOFA object with outdated Convention "
|
282
280
|
f"version {current}. It is recommend to upgrade "
|
283
281
|
" data with Sofa.upgrade_convention() before "
|
284
|
-
"writing to disk if possible."))
|
282
|
+
"writing to disk if possible."), stacklevel=2)
|
285
283
|
|
286
284
|
# setting the netCDF compression parameter
|
287
285
|
use_zlib = compression != 0
|
@@ -309,12 +307,10 @@ def _write_sofa(filename: str, sofa: sf.Sofa, compression=4, verify=True):
|
|
309
307
|
for key in all_keys:
|
310
308
|
|
311
309
|
# skip attributes
|
312
|
-
# Note:
|
313
|
-
#
|
314
|
-
#
|
315
|
-
#
|
316
|
-
# ("_" in key and not key.startswith("Data_")) or \
|
317
|
-
# key.count("_") > 1
|
310
|
+
# Note: The used definition of attributes is lax. The strict
|
311
|
+
# definition would parse `key` and assume an attribute if
|
312
|
+
# 1. "_" is in key and key does not start with "DATA_", or
|
313
|
+
# 2. key contains more than one "_"
|
318
314
|
#
|
319
315
|
# The strict definition is implicitly included in the SOFA standard
|
320
316
|
# since underscores only occur for variables starting with Data_
|
@@ -327,7 +323,7 @@ def _write_sofa(filename: str, sofa: sf.Sofa, compression=4, verify=True):
|
|
327
323
|
sofa._dimensions[key], sofa._api["S"])
|
328
324
|
|
329
325
|
# create variable and write data
|
330
|
-
shape =
|
326
|
+
shape = list(sofa._dimensions[key])
|
331
327
|
tmp_var = file.createVariable(
|
332
328
|
key.replace("Data_", "Data."), dtype, shape,
|
333
329
|
zlib=use_zlib, complevel=compression)
|
@@ -391,7 +387,7 @@ def _format_value_for_netcdf(value, key, dtype, dimensions, S):
|
|
391
387
|
|
392
388
|
def _format_value_from_netcdf(value, key):
|
393
389
|
"""
|
394
|
-
Format value from NETCDF4 file for saving in a SOFA object
|
390
|
+
Format value from NETCDF4 file for saving in a SOFA object.
|
395
391
|
|
396
392
|
Parameters
|
397
393
|
----------
|
@@ -408,7 +404,7 @@ def _format_value_from_netcdf(value, key):
|
|
408
404
|
|
409
405
|
if "float" in str(value.dtype) or "int" in str(value.dtype):
|
410
406
|
if np.ma.is_masked(value):
|
411
|
-
warnings.warn(f"Entry {key} contains missing data")
|
407
|
+
warnings.warn(f"Entry {key} contains missing data", stacklevel=3)
|
412
408
|
else:
|
413
409
|
# Convert to numpy array or scalar
|
414
410
|
value = np.asarray(value)
|