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.
Files changed (120) hide show
  1. {sofar-1.2.0 → sofar-1.2.2}/CONTRIBUTING.rst +2 -4
  2. {sofar-1.2.0 → sofar-1.2.2}/HISTORY.rst +9 -0
  3. {sofar-1.2.0 → sofar-1.2.2}/PKG-INFO +58 -12
  4. {sofar-1.2.0 → sofar-1.2.2}/README.md +1 -0
  5. {sofar-1.2.0 → sofar-1.2.2}/docs/conf.py +44 -12
  6. sofar-1.2.2/docs/resources/conventions.py +162 -0
  7. sofar-1.2.2/pyproject.toml +157 -0
  8. sofar-1.2.2/setup.cfg +4 -0
  9. {sofar-1.2.0 → sofar-1.2.2}/sofar/__init__.py +2 -1
  10. {sofar-1.2.0 → sofar-1.2.2}/sofar/io.py +15 -19
  11. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa.py +53 -29
  12. sofar-1.2.2/sofar/sofa_conventions/write_upgrade_rules.py +139 -0
  13. sofar-1.2.2/sofar/sofa_conventions/write_verification_data.py +313 -0
  14. sofar-1.2.2/sofar/sofa_conventions/write_verification_rules.py +356 -0
  15. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofastream.py +13 -8
  16. {sofar-1.2.0 → sofar-1.2.2}/sofar/update_conventions.py +19 -17
  17. {sofar-1.2.0 → sofar-1.2.2}/sofar/utils.py +4 -3
  18. {sofar-1.2.0 → sofar-1.2.2}/sofar.egg-info/PKG-INFO +58 -12
  19. {sofar-1.2.0 → sofar-1.2.2}/sofar.egg-info/SOURCES.txt +4 -4
  20. sofar-1.2.2/sofar.egg-info/requires.txt +31 -0
  21. sofar-1.2.2/sofar.egg-info/top_level.txt +5 -0
  22. {sofar-1.2.0 → sofar-1.2.2}/tests/test_deprecations.py +2 -2
  23. {sofar-1.2.0 → sofar-1.2.2}/tests/test_io.py +18 -17
  24. {sofar-1.2.0 → sofar-1.2.2}/tests/test_sofa.py +29 -30
  25. {sofar-1.2.0 → sofar-1.2.2}/tests/test_sofa_upgrade_conventions.py +1 -1
  26. {sofar-1.2.0 → sofar-1.2.2}/tests/test_sofa_verify.py +40 -39
  27. {sofar-1.2.0 → sofar-1.2.2}/tests/test_sofastream.py +12 -11
  28. {sofar-1.2.0 → sofar-1.2.2}/tests/test_utils.py +5 -6
  29. sofar-1.2.0/AUTHORS.rst +0 -15
  30. sofar-1.2.0/pyproject.toml +0 -13
  31. sofar-1.2.0/setup.cfg +0 -23
  32. sofar-1.2.0/setup.py +0 -76
  33. sofar-1.2.0/sofar.egg-info/not-zip-safe +0 -1
  34. sofar-1.2.0/sofar.egg-info/requires.txt +0 -5
  35. sofar-1.2.0/sofar.egg-info/top_level.txt +0 -2
  36. {sofar-1.2.0 → sofar-1.2.2}/LICENSE +0 -0
  37. {sofar-1.2.0 → sofar-1.2.2}/MANIFEST.in +0 -0
  38. {sofar-1.2.0 → sofar-1.2.2}/docs/Makefile +0 -0
  39. {sofar-1.2.0 → sofar-1.2.2}/docs/api_reference.rst +0 -0
  40. {sofar-1.2.0 → sofar-1.2.2}/docs/contributing.rst +0 -0
  41. {sofar-1.2.0 → sofar-1.2.2}/docs/history.rst +0 -0
  42. {sofar-1.2.0 → sofar-1.2.2}/docs/index.rst +0 -0
  43. {sofar-1.2.0 → sofar-1.2.2}/docs/make.bat +0 -0
  44. {sofar-1.2.0 → sofar-1.2.2}/docs/readme.rst +0 -0
  45. {sofar-1.2.0 → sofar-1.2.2}/docs/resources/working_with_sofa_HRIR_lateral.png +0 -0
  46. {sofar-1.2.0 → sofar-1.2.2}/docs/resources/working_with_sofa_source_horizontal.png +0 -0
  47. {sofar-1.2.0 → sofar-1.2.2}/docs/resources/working_with_sofa_source_lateral.png +0 -0
  48. {sofar-1.2.0 → sofar-1.2.2}/docs/sofar.rst +0 -0
  49. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/VERSION +0 -0
  50. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/AnnotatedEmitterAudio_0.2.csv +0 -0
  51. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/AnnotatedEmitterAudio_0.2.json +0 -0
  52. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/AnnotatedReceiverAudio_0.2.csv +0 -0
  53. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/AnnotatedReceiverAudio_0.2.json +0 -0
  54. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/FreeFieldDirectivityTF_1.1.csv +0 -0
  55. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/FreeFieldDirectivityTF_1.1.json +0 -0
  56. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/FreeFieldHRIR_1.0.csv +0 -0
  57. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/FreeFieldHRIR_1.0.json +0 -0
  58. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/FreeFieldHRTF_1.0.csv +0 -0
  59. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/FreeFieldHRTF_1.0.json +0 -0
  60. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralFIR-E_2.0.csv +0 -0
  61. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralFIR-E_2.0.json +0 -0
  62. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralFIR_1.0.csv +0 -0
  63. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralFIR_1.0.json +0 -0
  64. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralSOS_1.0.csv +0 -0
  65. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralSOS_1.0.json +0 -0
  66. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralTF-E_1.0.csv +0 -0
  67. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralTF-E_1.0.json +0 -0
  68. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralTF_1.0.csv +0 -0
  69. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralTF_1.0.json +0 -0
  70. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralTF_2.0.csv +0 -0
  71. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/GeneralTF_2.0.json +0 -0
  72. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldHRIR_1.0.csv +0 -0
  73. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldHRIR_1.0.json +0 -0
  74. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldHRSOS_1.0.csv +0 -0
  75. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldHRSOS_1.0.json +0 -0
  76. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldHRTF_1.0.csv +0 -0
  77. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldHRTF_1.0.json +0 -0
  78. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldSOS_1.0.csv +0 -0
  79. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleFreeFieldSOS_1.0.json +0 -0
  80. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleHeadphoneIR_1.0.csv +0 -0
  81. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SimpleHeadphoneIR_1.0.json +0 -0
  82. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SingleRoomMIMOSRIR_1.0.csv +0 -0
  83. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SingleRoomMIMOSRIR_1.0.json +0 -0
  84. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SingleRoomSRIR_1.0.csv +0 -0
  85. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/SingleRoomSRIR_1.0.json +0 -0
  86. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/AnnotatedEmitterAudio_0.1.csv +0 -0
  87. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/AnnotatedEmitterAudio_0.1.json +0 -0
  88. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/AnnotatedReceiverAudio_0.1.csv +0 -0
  89. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/AnnotatedReceiverAudio_0.1.json +0 -0
  90. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/FreeFieldDirectivityTF_1.0.csv +0 -0
  91. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/FreeFieldDirectivityTF_1.0.json +0 -0
  92. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/GeneralFIRE_1.0.csv +0 -0
  93. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/GeneralFIRE_1.0.json +0 -0
  94. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/MultiSpeakerBRIR_0.3.csv +0 -0
  95. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/MultiSpeakerBRIR_0.3.json +0 -0
  96. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldHRIR_0.4.csv +0 -0
  97. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldHRIR_0.4.json +0 -0
  98. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldTF_0.4.csv +0 -0
  99. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldTF_0.4.json +0 -0
  100. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldTF_1.0.csv +0 -0
  101. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleFreeFieldTF_1.0.json +0 -0
  102. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleHeadphoneIR_0.1.csv +0 -0
  103. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleHeadphoneIR_0.1.json +0 -0
  104. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleHeadphoneIR_0.2.csv +0 -0
  105. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SimpleHeadphoneIR_0.2.json +0 -0
  106. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleRoomDRIR_0.2.csv +0 -0
  107. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleRoomDRIR_0.2.json +0 -0
  108. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleRoomDRIR_0.3.csv +0 -0
  109. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleRoomDRIR_0.3.json +0 -0
  110. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleTrackedAudio_0.1.csv +0 -0
  111. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleTrackedAudio_0.1.json +0 -0
  112. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleTrackedAudio_0.2.csv +0 -0
  113. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/conventions/deprecated/SingleTrackedAudio_0.2.json +0 -0
  114. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/rules/deprecations.json +0 -0
  115. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/rules/rules.json +0 -0
  116. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/rules/unit_aliases.json +0 -0
  117. {sofar-1.2.0 → sofar-1.2.2}/sofar/sofa_conventions/rules/upgrade.json +0 -0
  118. {sofar-1.2.0 → sofar-1.2.2}/sofar.egg-info/dependency_links.txt +0 -0
  119. {sofar-1.2.0 → sofar-1.2.2}/tests/__init__.py +0 -0
  120. {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
- $ conda install pip
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
1
+ Metadata-Version: 2.4
2
2
  Name: sofar
3
- Version: 1.2.0
4
- Summary: Maybe the most complete python package for SOFA files so far
5
- Home-page: https://pyfar.org/
6
- Download-URL: https://pypi.org/project/sofar/
7
- Author: The pyfar developers
8
- Author-email: info@pyfar.org
9
- License: MIT license
10
- Project-URL: Bug Tracker, https://github.com/pyfar/sofar/issues
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: Source Code, https://github.com/pyfar/sofar
13
- Keywords: sofar
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
  [![PyPI version](https://badge.fury.io/py/sofar.svg)](https://badge.fury.io/py/sofar)
39
84
  [![Documentation Status](https://readthedocs.org/projects/sofar/badge/?version=latest)](https://sofar.readthedocs.io/en/latest/?badge=latest)
40
85
  [![CircleCI](https://circleci.com/gh/pyfar/sofar.svg?style=shield)](https://circleci.com/gh/pyfar/sofar)
86
+ [![Binder](https://mybinder.org/badge_logo.svg)](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
  [![PyPI version](https://badge.fury.io/py/sofar.svg)](https://badge.fury.io/py/sofar)
6
6
  [![Documentation Status](https://readthedocs.org/projects/sofar/badge/?version=latest)](https://sofar.readthedocs.io/en/latest/?badge=latest)
7
7
  [![CircleCI](https://circleci.com/gh/pyfar/sofar.svg?style=shield)](https://circleci.com/gh/pyfar/sofar)
8
+ [![Binder](https://mybinder.org/badge_logo.svg)](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 # noqa
16
- import resources.conventions # noqa: build conventions for documentation
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": 8,
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
- c = urllib3.PoolManager()
154
- for file in folders_in:
155
- url = link + file
156
- filename = file
157
- os.makedirs(os.path.dirname(filename), exist_ok=True)
158
- with c.request('GET', url, preload_content=False) as res, open(filename, 'wb') as out_file:
159
- shutil.copyfileobj(res, out_file)
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
- fout.write(line.replace(f'https://{project}.readthedocs.io', project))
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
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -1,7 +1,8 @@
1
+ """Main init that determines how the sofar package is structured."""
1
2
  # -*- coding: utf-8 -*-
2
3
  __author__ = """The pyfar developers"""
3
4
  __email__ = 'info@pyfar.org'
4
- __version__ = '1.2.0'
5
+ __version__ = '1.2.2'
5
6
 
6
7
  from .sofa import Sofa
7
8
 
@@ -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 = getattr(file, "SOFAConventions")
133
- version = getattr(file, "SOFAConventionsVersion")
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: # noqa (No error handling - just improved verbosity)
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 of ``9`` optimizes the file
239
- size but increases the time for writing files to disk.
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: This definition of attribute is blurry:
313
- # lax definition:
314
- # sofa._convention[key]["type"] == "attribute":
315
- # strict definition:
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 = tuple(list(sofa._dimensions[key]))
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)