cefast 0.1.0__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 (99) hide show
  1. cefast-0.1.0/.clang-format +26 -0
  2. cefast-0.1.0/.github/dependabot.yml +7 -0
  3. cefast-0.1.0/.github/workflows/tests.yml +109 -0
  4. cefast-0.1.0/.github/workflows/wheels.yml +119 -0
  5. cefast-0.1.0/.gitignore +12 -0
  6. cefast-0.1.0/COPYING +21 -0
  7. cefast-0.1.0/PKG-INFO +219 -0
  8. cefast-0.1.0/README.md +171 -0
  9. cefast-0.1.0/cefast/__init__.py +6 -0
  10. cefast-0.1.0/cefast/_version.py.in +1 -0
  11. cefast-0.1.0/cefast/meson.build +17 -0
  12. cefast-0.1.0/docs/accepted-deviations.md +45 -0
  13. cefast-0.1.0/docs/images/cefast_logo.png +0 -0
  14. cefast-0.1.0/docs/perf/2026-11-round1-profile.md +197 -0
  15. cefast-0.1.0/docs/perf/2026-11-round5-parallel.md +165 -0
  16. cefast-0.1.0/docs/perf/2026-11-round6-small-files.md +133 -0
  17. cefast-0.1.0/docs/perf/2026-11-round7.md +116 -0
  18. cefast-0.1.0/docs/superpowers/plans/2026-11-05-cefast-reader.md +240 -0
  19. cefast-0.1.0/docs/superpowers/plans/2026-11-05-cefast-speed-round2.md +68 -0
  20. cefast-0.1.0/docs/superpowers/plans/2026-11-05-cefast-speed-round3.md +110 -0
  21. cefast-0.1.0/docs/superpowers/plans/2026-11-05-cefast-speed.md +91 -0
  22. cefast-0.1.0/docs/superpowers/plans/2026-11-05-cpp-utils-python.md +122 -0
  23. cefast-0.1.0/docs/superpowers/plans/2026-11-05-plan-review-opencode.md +97 -0
  24. cefast-0.1.0/docs/superpowers/plans/2026-11-06-cefast-speed-round4.md +63 -0
  25. cefast-0.1.0/docs/superpowers/plans/2026-11-06-cefast-speed-round5.md +84 -0
  26. cefast-0.1.0/docs/superpowers/plans/2026-11-06-cefast-speed-round6.md +69 -0
  27. cefast-0.1.0/docs/superpowers/plans/2026-11-06-cefast-speed-round7.md +143 -0
  28. cefast-0.1.0/docs/superpowers/specs/2026-11-05-cef-facts.md +59 -0
  29. cefast-0.1.0/docs/superpowers/specs/2026-11-05-cefast-design.md +228 -0
  30. cefast-0.1.0/docs/superpowers/specs/2026-11-05-csa-cef-probe.md +93 -0
  31. cefast-0.1.0/include/cefast/cefast.hpp +48 -0
  32. cefast-0.1.0/include/cefast/data/parallel.hpp +214 -0
  33. cefast-0.1.0/include/cefast/data/records.hpp +871 -0
  34. cefast-0.1.0/include/cefast/data/structural.hpp +50 -0
  35. cefast-0.1.0/include/cefast/data/workers.hpp +178 -0
  36. cefast-0.1.0/include/cefast/errors.hpp +40 -0
  37. cefast-0.1.0/include/cefast/gzip.hpp +148 -0
  38. cefast-0.1.0/include/cefast/header/attributes.hpp +17 -0
  39. cefast-0.1.0/include/cefast/header/lexer.hpp +390 -0
  40. cefast-0.1.0/include/cefast/header/parser.hpp +669 -0
  41. cefast-0.1.0/include/cefast/input.hpp +165 -0
  42. cefast-0.1.0/include/cefast/model.hpp +71 -0
  43. cefast-0.1.0/include/cefast/time.hpp +263 -0
  44. cefast-0.1.0/include/cefast/values.hpp +291 -0
  45. cefast-0.1.0/meson.build +63 -0
  46. cefast-0.1.0/meson_options.txt +4 -0
  47. cefast-0.1.0/pycefast/_cefast.cpp +335 -0
  48. cefast-0.1.0/pycefast/meson.build +9 -0
  49. cefast-0.1.0/pyproject.toml +53 -0
  50. cefast-0.1.0/subprojects/catch2.wrap +11 -0
  51. cefast-0.1.0/subprojects/cpp_utils.wrap +3 -0
  52. cefast-0.1.0/subprojects/fast_float.wrap +14 -0
  53. cefast-0.1.0/subprojects/hedley.wrap +12 -0
  54. cefast-0.1.0/subprojects/pybind11.wrap +13 -0
  55. cefast-0.1.0/subprojects/zlib.wrap +14 -0
  56. cefast-0.1.0/tests/cpp/test_corpus.cpp +769 -0
  57. cefast-0.1.0/tests/cpp/test_header.cpp +562 -0
  58. cefast-0.1.0/tests/cpp/test_input.cpp +195 -0
  59. cefast-0.1.0/tests/cpp/test_lexer.cpp +209 -0
  60. cefast-0.1.0/tests/cpp/test_records.cpp +576 -0
  61. cefast-0.1.0/tests/cpp/test_time.cpp +93 -0
  62. cefast-0.1.0/tests/cpp/test_values.cpp +323 -0
  63. cefast-0.1.0/tests/meson.build +57 -0
  64. cefast-0.1.0/tests/python/test_cefast.py +255 -0
  65. cefast-0.1.0/tests/python/test_vs_ceflib.py +259 -0
  66. cefast-0.1.0/tests/resources/csa_manifest.json +332 -0
  67. cefast-0.1.0/tests/resources/fixtures/codif-header.cef +524 -0
  68. cefast-0.1.0/tests/resources/fixtures/hello.cef +5 -0
  69. cefast-0.1.0/tests/resources/fixtures/hello.cef.gz +0 -0
  70. cefast-0.1.0/tests/resources/fixtures/include/broken.cef +3 -0
  71. cefast-0.1.0/tests/resources/fixtures/include/broken.ceh +1 -0
  72. cefast-0.1.0/tests/resources/fixtures/include/common.ceh +4 -0
  73. cefast-0.1.0/tests/resources/fixtures/include/cycle-a.cef +3 -0
  74. cefast-0.1.0/tests/resources/fixtures/include/cycle-b.ceh +1 -0
  75. cefast-0.1.0/tests/resources/fixtures/include/main.cef +5 -0
  76. cefast-0.1.0/tests/resources/fixtures/include/nested.ceh +3 -0
  77. cefast-0.1.0/tests/resources/fixtures/trailing_zeros.cef.gz +0 -0
  78. cefast-0.1.0/tests/resources/fixtures/truncated.cef.gz +0 -0
  79. cefast-0.1.0/tests/resources/fixtures/two_members.cef.gz +0 -0
  80. cefast-0.1.0/tests/resources/fixtures/whi-header.cef +472 -0
  81. cefast-0.1.0/tests/resources/make_gz.py +24 -0
  82. cefast-0.1.0/tests/wheel/test_wheel.py +75 -0
  83. cefast-0.1.0/tools/bench/bench_load.cpp +93 -0
  84. cefast-0.1.0/tools/bench/meson.build +1 -0
  85. cefast-0.1.0/tools/ceflib/benchmark.py +103 -0
  86. cefast-0.1.0/tools/ceflib/build_ceflib.sh +42 -0
  87. cefast-0.1.0/tools/fetch_csa_corpus.py +273 -0
  88. cefast-0.1.0/tools/fuzz/cef.dict +56 -0
  89. cefast-0.1.0/tools/fuzz/compare.hpp +139 -0
  90. cefast-0.1.0/tools/fuzz/fuzz_float.cpp +139 -0
  91. cefast-0.1.0/tools/fuzz/fuzz_lexer.cpp +43 -0
  92. cefast-0.1.0/tools/fuzz/fuzz_lexer_diff.cpp +161 -0
  93. cefast-0.1.0/tools/fuzz/fuzz_load.cpp +73 -0
  94. cefast-0.1.0/tools/fuzz/fuzz_records_diff.cpp +172 -0
  95. cefast-0.1.0/tools/fuzz/fuzz_time.cpp +52 -0
  96. cefast-0.1.0/tools/fuzz/make_corpus.py +163 -0
  97. cefast-0.1.0/tools/fuzz/meson.build +19 -0
  98. cefast-0.1.0/tools/fuzz/reference_lexer.hpp +280 -0
  99. cefast-0.1.0/tools/fuzz/reference_records.hpp +846 -0
@@ -0,0 +1,26 @@
1
+ ---
2
+ # See http://clang.llvm.org/docs/ClangFormatStyleOptions.html for a definition
3
+ # of the options
4
+ Language: Cpp
5
+ BasedOnStyle: WebKit
6
+
7
+ # Line length
8
+ ColumnLimit: 100
9
+
10
+ # Indent with 4 spaces
11
+ IndentWidth: 4
12
+ AccessModifierOffset: -4 # -IndentWidth
13
+ ConstructorInitializerIndentWidth: 8 # 2 * IndentWidth
14
+
15
+ BreakBeforeBraces: Allman
16
+
17
+ AllowShortFunctionsOnASingleLine: Inline
18
+ AlwaysBreakTemplateDeclarations: true
19
+ AlwaysBreakBeforeMultilineStrings: true
20
+ BreakBeforeBinaryOperators: true
21
+ ConstructorInitializerAllOnOneLineOrOnePerLine: true
22
+ IndentCaseLabels: true
23
+ MaxEmptyLinesToKeep: 2
24
+ Standard: Cpp11
25
+ UseTab: Never
26
+
@@ -0,0 +1,7 @@
1
+ version: 2
2
+ updates:
3
+ # Actions are pinned to commit SHAs: this is what keeps them current.
4
+ - package-ecosystem: "github-actions"
5
+ directory: "/"
6
+ schedule:
7
+ interval: "weekly"
@@ -0,0 +1,109 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ tests:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
16
+ - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7
17
+ with:
18
+ python-version: "3.12"
19
+ - name: Install build tools
20
+ run: pip install meson ninja numpy meson-python
21
+ # The CSA sample corpus is not in the repository: it is downloaded from the archive and
22
+ # verified against tests/resources/csa_manifest.json, so the manifest is the cache key.
23
+ - name: Restore the CSA corpus
24
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
25
+ with:
26
+ path: tests/resources/csa
27
+ key: csa-corpus-${{ hashFiles('tests/resources/csa_manifest.json') }}
28
+ - name: Download the CSA corpus
29
+ run: python -I tools/fetch_csa_corpus.py
30
+ - name: Configure
31
+ run: meson setup build
32
+ - name: Test
33
+ run: meson test -C build --print-errorlogs
34
+ - name: Test log
35
+ if: failure()
36
+ run: cat build/meson-logs/testlog.txt
37
+
38
+ sanitizers:
39
+ runs-on: ubuntu-latest
40
+ env:
41
+ UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1
42
+ ASAN_OPTIONS: halt_on_error=1:print_summary=1
43
+ steps:
44
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
45
+ - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7
46
+ with:
47
+ python-version: "3.12"
48
+ - name: Install build tools
49
+ run: pip install meson ninja
50
+ - name: Restore the CSA corpus
51
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
52
+ with:
53
+ path: tests/resources/csa
54
+ key: csa-corpus-${{ hashFiles('tests/resources/csa_manifest.json') }}
55
+ - name: Download the CSA corpus
56
+ run: python -I tools/fetch_csa_corpus.py
57
+ - name: Configure
58
+ # No python module: the sanitised extension would need a matching interpreter.
59
+ run: >
60
+ meson setup build-asan -Db_sanitize=address,undefined -Db_lundef=false -Dpython=false
61
+ - name: Test
62
+ run: meson test -C build-asan --print-errorlogs
63
+ - name: Test log
64
+ if: failure()
65
+ run: cat build-asan/meson-logs/testlog.txt
66
+
67
+ fuzz:
68
+ runs-on: ubuntu-latest
69
+ env:
70
+ CC: clang
71
+ CXX: clang++
72
+ steps:
73
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
74
+ - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7
75
+ with:
76
+ python-version: "3.12"
77
+ - name: Install build tools
78
+ run: pip install meson ninja
79
+ - name: Install clang
80
+ run: sudo apt-get update && sudo apt-get install -y clang
81
+ - name: Restore the CSA corpus
82
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
83
+ with:
84
+ path: tests/resources/csa
85
+ key: csa-corpus-${{ hashFiles('tests/resources/csa_manifest.json') }}
86
+ - name: Download the CSA corpus
87
+ run: python -I tools/fetch_csa_corpus.py
88
+ - name: Configure
89
+ run: meson setup build-fuzz -Dpython=false -Dwith_tests=false -Dfuzzing=true -Dbuildtype=debugoptimized
90
+ - name: Compile
91
+ run: ninja -C build-fuzz
92
+ - name: Seeds
93
+ run: python3 tools/fuzz/make_corpus.py --output "$RUNNER_TEMP/corpus"
94
+ # A short run keeps the job cheap: it is a regression gate for the corpus, not a
95
+ # campaign. One process per target so a finding fails the job with its artifact.
96
+ - name: Fuzz
97
+ run: |
98
+ for target in load time float lexer lexer_diff records_diff; do
99
+ max_len=65536
100
+ test "$target" = load && max_len=262144
101
+ mkdir -p "$RUNNER_TEMP/artifacts/$target"
102
+ ./build-fuzz/tools/fuzz/fuzz_$target "$RUNNER_TEMP/corpus/$target" \
103
+ -dict=tools/fuzz/cef.dict -max_total_time=60 -max_len=$max_len \
104
+ -rss_limit_mb=2048 \
105
+ -artifact_prefix="$RUNNER_TEMP/artifacts/$target/"
106
+ done
107
+ - name: Fuzz artifacts
108
+ if: failure()
109
+ run: find "$RUNNER_TEMP/artifacts" -type f -exec sh -c 'echo "== $1"; xxd "$1" | head -40' _ {} \;
@@ -0,0 +1,119 @@
1
+ name: Build and test wheels on multiple platforms
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ push:
7
+ pull_request:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ build_sdist:
14
+ name: Build source distribution
15
+ runs-on: ubuntu-latest
16
+ permissions:
17
+ contents: read
18
+ actions: write
19
+ steps:
20
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
21
+ - name: Build sdist
22
+ run: pipx run build --sdist
23
+ - name: Upload artifact
24
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
25
+ with:
26
+ name: cibw-sdist
27
+ path: dist/*.tar.gz
28
+
29
+ build_wheels:
30
+ name: ${{ matrix.os }} ${{ matrix.CIBW_ARCHS }} wheels
31
+ runs-on: ${{ matrix.os }}
32
+ permissions:
33
+ contents: read
34
+ actions: write
35
+ strategy:
36
+ matrix:
37
+ include:
38
+ - os: ubuntu-latest
39
+ CIBW_ENVIRONMENT: ''
40
+ CIBW_ARCHS: "x86_64"
41
+ CIBW_PLATFORM: "auto"
42
+ - os: ubuntu-latest
43
+ CIBW_ENVIRONMENT: ''
44
+ CIBW_ARCHS: "wasm32"
45
+ CIBW_PLATFORM: "pyodide"
46
+ - os: ubuntu-24.04-arm
47
+ CIBW_ENVIRONMENT: ''
48
+ CIBW_ARCHS: "aarch64"
49
+ CIBW_PLATFORM: "auto"
50
+ - os: windows-latest
51
+ CIBW_ENVIRONMENT: ''
52
+ CIBW_ARCHS: "AMD64"
53
+ CIBW_PLATFORM: "auto"
54
+ - os: windows-11-arm
55
+ CIBW_ENVIRONMENT: ''
56
+ CIBW_ARCHS: "ARM64"
57
+ CIBW_PLATFORM: "auto"
58
+ - os: macos-15-intel
59
+ CIBW_ENVIRONMENT: >
60
+ MACOSX_DEPLOYMENT_TARGET='13.0'
61
+ CIBW_ARCHS: "x86_64"
62
+ CIBW_PLATFORM: "auto"
63
+ - os: macos-latest # Apple Silicon
64
+ CIBW_ENVIRONMENT: >
65
+ MACOSX_DEPLOYMENT_TARGET='13.0'
66
+ CIBW_ARCHS: "arm64"
67
+ CIBW_PLATFORM: "auto"
68
+ env:
69
+ CIBW_ENVIRONMENT: ${{ matrix.CIBW_ENVIRONMENT }}
70
+ # Windows on ARM has native CPython builds from 3.11 only
71
+ CIBW_SKIP: "*-win32 *i686 cp310-win_arm64"
72
+ CIBW_ARCHS: ${{ matrix.CIBW_ARCHS }}
73
+ CIBW_PLATFORM: ${{ matrix.CIBW_PLATFORM }}
74
+ CIBW_ENVIRONMENT_LINUX: PATH=/usr/local/bin:/usr/lib/ccache:$PATH CCACHE_DIR=/host${{ github.workspace }}/.ccache CCACHE_CONFIGPATH=/host/home/runner/.config/ccache/ccache.conf
75
+ # see https://github.com/matplotlib/matplotlib/pull/28687/files#diff-504e739c530d50b780e9a09ae8fd0c3ea8258ea7553be06afb06f03f95b1ee0aR103
76
+ CIBW_CONFIG_SETTINGS_WINDOWS: >-
77
+ setup-args="--vsenv"
78
+ setup-args="-Db_vscrt=mt"
79
+ setup-args="-Dcpp_link_args=['ucrt.lib','vcruntime.lib','/nodefaultlib:libucrt.lib','/nodefaultlib:libvcruntime.lib']"
80
+ steps:
81
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
82
+ - name: ccache
83
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2
84
+ with:
85
+ key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.CIBW_ARCHS }}
86
+ max-size: "5G"
87
+ # Each wheel runs tests/wheel/test_wheel.py in its own environment (see
88
+ # [tool.cibuildwheel] in pyproject.toml): import cefast, load a small inline CEF file from
89
+ # bytes, gzip bytes and a path. The CSA corpus is never needed.
90
+ - name: Build wheels
91
+ uses: pypa/cibuildwheel@f9b966cfadf4109556cadc5bb39ddb72d0ce664e # v4.3.5
92
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
93
+ with:
94
+ name: cibw-wheels-${{ matrix.os }}-${{ matrix.CIBW_ARCHS }}
95
+ path: ./wheelhouse/*.whl
96
+
97
+ upload_pypi:
98
+ needs: [build_sdist, build_wheels]
99
+ runs-on: ubuntu-latest
100
+ # upload to PyPI only on github releases
101
+ environment:
102
+ name: pypi
103
+ url: https://pypi.org/p/cefast
104
+ permissions:
105
+ # id-token is what trusted publishing uses; the two reads are all this job needs.
106
+ id-token: write
107
+ contents: read
108
+ actions: read
109
+ if: github.event_name == 'release' && github.event.action == 'published' && github.repository_owner == 'SciQLop'
110
+ steps:
111
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
112
+ with:
113
+ pattern: cibw-*
114
+ path: dist
115
+ merge-multiple: true
116
+ - name: Publish to PyPI
117
+ uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # release/v1
118
+ with:
119
+ skip-existing: true
@@ -0,0 +1,12 @@
1
+ build/
2
+ build*/
3
+ subprojects/*
4
+ !subprojects/*.wrap
5
+ !subprojects/packagefiles/
6
+ *.kdev4
7
+ *__pycache__*
8
+ *.py[cod]
9
+ .cache/
10
+ compile_commands.json
11
+ tests/resources/csa/
12
+ fuzz-*.log
cefast-0.1.0/COPYING ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Laboratory of Plasma Physics, Ecole Polytechnique, CNRS, Sorbonne Université, Université Paris-Saclay
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
cefast-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,219 @@
1
+ Metadata-Version: 2.1
2
+ Name: cefast
3
+ Version: 0.1.0
4
+ Summary: Fast reader for ESA's Cluster Exchange Format (CEF 2.0)
5
+ Author-Email: Alexis Jeandet <alexis.jeandet@member.fsf.org>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Laboratory of Plasma Physics, Ecole Polytechnique, CNRS, Sorbonne Université, Université Paris-Saclay
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
+ Classifier: Development Status :: 4 - Beta
29
+ Classifier: Intended Audience :: Science/Research
30
+ Classifier: License :: OSI Approved :: MIT License
31
+ Classifier: Natural Language :: English
32
+ Classifier: Operating System :: OS Independent
33
+ Classifier: Programming Language :: C++
34
+ Classifier: Programming Language :: Python :: 3
35
+ Classifier: Programming Language :: Python :: 3.10
36
+ Classifier: Programming Language :: Python :: 3.11
37
+ Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Programming Language :: Python :: 3.13
39
+ Classifier: Programming Language :: Python :: 3.14
40
+ Classifier: Programming Language :: Python :: 3.15
41
+ Classifier: Topic :: Scientific/Engineering :: Astronomy
42
+ Classifier: Topic :: Scientific/Engineering :: Physics
43
+ Project-URL: homepage, https://github.com/SciQLop/CEFast
44
+ Project-URL: repository, https://github.com/SciQLop/CEFast
45
+ Requires-Python: >=3.10
46
+ Requires-Dist: numpy
47
+ Description-Content-Type: text/markdown
48
+
49
+ [![tests](https://github.com/SciQLop/CEFast/actions/workflows/tests.yml/badge.svg)](https://github.com/SciQLop/CEFast/actions/workflows/tests.yml)
50
+ [![wheels](https://github.com/SciQLop/CEFast/actions/workflows/wheels.yml/badge.svg)](https://github.com/SciQLop/CEFast/actions/workflows/wheels.yml)
51
+ [![PyPI](https://img.shields.io/pypi/v/cefast)](https://pypi.org/project/cefast/)
52
+ [![Python versions](https://img.shields.io/pypi/pyversions/cefast)](https://pypi.org/project/cefast/)
53
+ [![license](https://img.shields.io/badge/license-MIT-blue)](COPYING)
54
+
55
+ <p align="center"><img src="docs/images/cefast_logo.png" alt="CEFast" width="600"></p>
56
+
57
+ # CEFast
58
+
59
+ A fast reader for CEF (Cluster Exchange Format), the text format of ESA's Cluster Science Archive.
60
+ C++20 core, Python bindings, no dependencies beyond numpy.
61
+
62
+ ```sh
63
+ pip install cefast
64
+ ```
65
+
66
+ ```python
67
+ import cefast
68
+ f = cefast.load("C1_CP_FGM_SPIN__20010201_000000_20010202_000000_V140305.cef.gz")
69
+ f["B_vec_xyz_gse__C1_CP_FGM_SPIN"].values # (records, 3) float32
70
+ f["time_tags__C1_CP_FGM_SPIN"].values.dtype # datetime64[ns]
71
+ ```
72
+
73
+ ## Why CEFast
74
+
75
+ CEFLIB is the reference CEF reader, and it is hard to live with: source tarball only, no wheels,
76
+ a global singleton, and no working byte variables. CEFast is
77
+ installable with pip, free of global state, and readable by someone else.
78
+
79
+ Correctness is checked, not claimed:
80
+
81
+ - every CEF 2.0 construct the archive uses, checked against the specification, with the deviations
82
+ we accept listed in [docs/accepted-deviations.md](docs/accepted-deviations.md);
83
+ - 41 real CSA files, every one CEFLIB can read compared value by value against CEFLIB 1.8.6,
84
+ plus hand-made files for malformed input;
85
+ - the full suite runs under ASan and UBSan in CI, together with an allocation budget test for the
86
+ header path;
87
+ - libFuzzer targets run in CI, each comparing a fast path with a slow reference: serial against
88
+ parallel loading, the float parser against `strtod`, the fixed-width time parser against the
89
+ general one, the header lexer and the record scanner against frozen copies of the simpler code
90
+ they replaced;
91
+ - a malformed file raises a `ParseError` naming the file, the line and the record: it never returns
92
+ shifted columns or garbage.
93
+
94
+ ## Install
95
+
96
+ ```sh
97
+ pip install cefast
98
+ ```
99
+
100
+ Wheels are built for Linux (x86_64, aarch64), macOS 13+ (x86_64, arm64) and Windows (x64,
101
+ ARM64), for CPython 3.10 and newer, including free-threaded builds. A Pyodide (wasm32) wheel is
102
+ built too. Elsewhere, `pip install` builds from the sdist with a C++20 compiler and meson.
103
+
104
+ ## Loading
105
+
106
+ ```python
107
+ cefast.load("file.cef") # path or os.PathLike
108
+ cefast.load("file.cef.gz") # gzip, detected from the content
109
+ cefast.load(data) # bytes, bytearray or memoryview
110
+ ```
111
+
112
+ `threads=0` (the default) picks a thread count from the machine, `threads=1` parses serially,
113
+ `threads=N` uses at most N. Data sections above ~48 KiB are split across threads; the result is
114
+ identical either way.
115
+
116
+ Loading releases the GIL. A path is memory-mapped, or read when the platform has no mmap, and bytes
117
+ are borrowed: the returned arrays are views on that memory, valid as long as the `CEF` object and
118
+ its variables live.
119
+
120
+ ## Variables
121
+
122
+ ```python
123
+ f.keys() # names, in file order
124
+ "B_vec_xyz_gse__C1_CP_FGM_SPIN" in f
125
+ v = f["B_vec_xyz_gse__C1_CP_FGM_SPIN"]
126
+ v.name, v.value_type # 'B_vec_xyz_gse__C1_CP_FGM_SPIN', 'FLOAT'
127
+ v.sizes # (3,), the CEF SIZES attribute
128
+ v.is_nrv # True when the values are in the header (DATA), not per record
129
+ v.attributes # dict of the other variable attributes
130
+ f.attributes # dict of the global attributes
131
+ ```
132
+
133
+ Attribute values are plain Python values: text and numbers come as one value or a list, times as
134
+ `datetime.datetime`, time ranges as a pair of them.
135
+
136
+ Values are numpy arrays. Record-varying variables get a record axis, header variables keep their
137
+ declared shape.
138
+
139
+ | CEF VALUE_TYPE | numpy dtype |
140
+ | --- | --- |
141
+ | FLOAT | float32 |
142
+ | DOUBLE | float64 |
143
+ | INT | int32 |
144
+ | BYTE | uint8 |
145
+ | CHAR | numpy unicode string, copied |
146
+ | ISO_TIME | datetime64[ns] |
147
+ | ISO_TIME_RANGE | datetime64[ns], one extra dimension of 2 |
148
+
149
+ Missing data stays raw for numeric variables (the `FILLVAL` number itself) and becomes `NaT` for
150
+ time variables.
151
+
152
+ ## INCLUDE
153
+
154
+ `INCLUDE = "file.ceh"` is resolved, in this order, with `include_resolver` first when given:
155
+
156
+ ```python
157
+ cefast.load("file.cef", include_paths=["/data/headers"])
158
+ cefast.load("file.cef", include_resolver=lambda name: headers.get(name)) # str or None
159
+ ```
160
+
161
+ then the directory of the file being read, then `include_paths`, then the `CEFPATH` environment
162
+ variable, then the current directory (which is what CEFLIB does).
163
+
164
+ ## Errors
165
+
166
+ Anything that would silently produce wrong numbers raises instead:
167
+
168
+ ```python
169
+ try:
170
+ cefast.load("broken.cef")
171
+ except cefast.ParseError as error:
172
+ print(error) # broken.cef:214: expected 31 values, got 30 (record 12)
173
+ ```
174
+
175
+ `ParseError` subclasses `ValueError` and names the file, the line and, inside the data section, the
176
+ record.
177
+
178
+ ## C++
179
+
180
+ Header-only C++20, same API shape:
181
+
182
+ ```cpp
183
+ #include <cefast/cefast.hpp>
184
+
185
+ auto file = cefast::load("file.cef");
186
+ for (const auto& var : file.variables)
187
+ std::cout << var.name << '\n';
188
+ ```
189
+
190
+ With meson: `dependency('cefast', fallback: ['cefast', 'cefast_dep'])`.
191
+
192
+ ## Performance
193
+
194
+ On the 41-file CSA sample corpus (10.4 MB), against CEFLIB 1.8.6, loading every file from Python
195
+ with the default threads: **11.5 ms against 35.1 ms** (3.05x overall, median 1.60x per file).
196
+ Every file is faster, from 1.20x to 7x. Numbers from a Ryzen 7 5800X; gzipped files are limited by
197
+ decompression. `tools/ceflib/benchmark.py` reproduces them.
198
+
199
+ Speed does not cost correctness: every float is correctly rounded (the value `strtod` gives), and a
200
+ malformed value is an error, where CEFLIB reads `12abc` as `12`.
201
+
202
+ ## Tests
203
+
204
+ ```sh
205
+ python -I tools/fetch_csa_corpus.py # downloads the CSA sample corpus and verifies its hashes
206
+ meson setup build && meson test -C build
207
+ ```
208
+
209
+ The corpus is not in the repository: it is fetched from the archive and checked against
210
+ `tests/resources/csa_manifest.json`. Tests that need it skip when it is missing.
211
+ `tools/ceflib/benchmark.py` builds CEFLIB to compare against it; the differential test skips when
212
+ CEFLIB is not importable.
213
+
214
+ Known differences from CEFLIB and from the strict CEF 2.0 document are listed in
215
+ [docs/accepted-deviations.md](docs/accepted-deviations.md).
216
+
217
+ ## License
218
+
219
+ MIT, see [COPYING](COPYING).
cefast-0.1.0/README.md ADDED
@@ -0,0 +1,171 @@
1
+ [![tests](https://github.com/SciQLop/CEFast/actions/workflows/tests.yml/badge.svg)](https://github.com/SciQLop/CEFast/actions/workflows/tests.yml)
2
+ [![wheels](https://github.com/SciQLop/CEFast/actions/workflows/wheels.yml/badge.svg)](https://github.com/SciQLop/CEFast/actions/workflows/wheels.yml)
3
+ [![PyPI](https://img.shields.io/pypi/v/cefast)](https://pypi.org/project/cefast/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/cefast)](https://pypi.org/project/cefast/)
5
+ [![license](https://img.shields.io/badge/license-MIT-blue)](COPYING)
6
+
7
+ <p align="center"><img src="docs/images/cefast_logo.png" alt="CEFast" width="600"></p>
8
+
9
+ # CEFast
10
+
11
+ A fast reader for CEF (Cluster Exchange Format), the text format of ESA's Cluster Science Archive.
12
+ C++20 core, Python bindings, no dependencies beyond numpy.
13
+
14
+ ```sh
15
+ pip install cefast
16
+ ```
17
+
18
+ ```python
19
+ import cefast
20
+ f = cefast.load("C1_CP_FGM_SPIN__20010201_000000_20010202_000000_V140305.cef.gz")
21
+ f["B_vec_xyz_gse__C1_CP_FGM_SPIN"].values # (records, 3) float32
22
+ f["time_tags__C1_CP_FGM_SPIN"].values.dtype # datetime64[ns]
23
+ ```
24
+
25
+ ## Why CEFast
26
+
27
+ CEFLIB is the reference CEF reader, and it is hard to live with: source tarball only, no wheels,
28
+ a global singleton, and no working byte variables. CEFast is
29
+ installable with pip, free of global state, and readable by someone else.
30
+
31
+ Correctness is checked, not claimed:
32
+
33
+ - every CEF 2.0 construct the archive uses, checked against the specification, with the deviations
34
+ we accept listed in [docs/accepted-deviations.md](docs/accepted-deviations.md);
35
+ - 41 real CSA files, every one CEFLIB can read compared value by value against CEFLIB 1.8.6,
36
+ plus hand-made files for malformed input;
37
+ - the full suite runs under ASan and UBSan in CI, together with an allocation budget test for the
38
+ header path;
39
+ - libFuzzer targets run in CI, each comparing a fast path with a slow reference: serial against
40
+ parallel loading, the float parser against `strtod`, the fixed-width time parser against the
41
+ general one, the header lexer and the record scanner against frozen copies of the simpler code
42
+ they replaced;
43
+ - a malformed file raises a `ParseError` naming the file, the line and the record: it never returns
44
+ shifted columns or garbage.
45
+
46
+ ## Install
47
+
48
+ ```sh
49
+ pip install cefast
50
+ ```
51
+
52
+ Wheels are built for Linux (x86_64, aarch64), macOS 13+ (x86_64, arm64) and Windows (x64,
53
+ ARM64), for CPython 3.10 and newer, including free-threaded builds. A Pyodide (wasm32) wheel is
54
+ built too. Elsewhere, `pip install` builds from the sdist with a C++20 compiler and meson.
55
+
56
+ ## Loading
57
+
58
+ ```python
59
+ cefast.load("file.cef") # path or os.PathLike
60
+ cefast.load("file.cef.gz") # gzip, detected from the content
61
+ cefast.load(data) # bytes, bytearray or memoryview
62
+ ```
63
+
64
+ `threads=0` (the default) picks a thread count from the machine, `threads=1` parses serially,
65
+ `threads=N` uses at most N. Data sections above ~48 KiB are split across threads; the result is
66
+ identical either way.
67
+
68
+ Loading releases the GIL. A path is memory-mapped, or read when the platform has no mmap, and bytes
69
+ are borrowed: the returned arrays are views on that memory, valid as long as the `CEF` object and
70
+ its variables live.
71
+
72
+ ## Variables
73
+
74
+ ```python
75
+ f.keys() # names, in file order
76
+ "B_vec_xyz_gse__C1_CP_FGM_SPIN" in f
77
+ v = f["B_vec_xyz_gse__C1_CP_FGM_SPIN"]
78
+ v.name, v.value_type # 'B_vec_xyz_gse__C1_CP_FGM_SPIN', 'FLOAT'
79
+ v.sizes # (3,), the CEF SIZES attribute
80
+ v.is_nrv # True when the values are in the header (DATA), not per record
81
+ v.attributes # dict of the other variable attributes
82
+ f.attributes # dict of the global attributes
83
+ ```
84
+
85
+ Attribute values are plain Python values: text and numbers come as one value or a list, times as
86
+ `datetime.datetime`, time ranges as a pair of them.
87
+
88
+ Values are numpy arrays. Record-varying variables get a record axis, header variables keep their
89
+ declared shape.
90
+
91
+ | CEF VALUE_TYPE | numpy dtype |
92
+ | --- | --- |
93
+ | FLOAT | float32 |
94
+ | DOUBLE | float64 |
95
+ | INT | int32 |
96
+ | BYTE | uint8 |
97
+ | CHAR | numpy unicode string, copied |
98
+ | ISO_TIME | datetime64[ns] |
99
+ | ISO_TIME_RANGE | datetime64[ns], one extra dimension of 2 |
100
+
101
+ Missing data stays raw for numeric variables (the `FILLVAL` number itself) and becomes `NaT` for
102
+ time variables.
103
+
104
+ ## INCLUDE
105
+
106
+ `INCLUDE = "file.ceh"` is resolved, in this order, with `include_resolver` first when given:
107
+
108
+ ```python
109
+ cefast.load("file.cef", include_paths=["/data/headers"])
110
+ cefast.load("file.cef", include_resolver=lambda name: headers.get(name)) # str or None
111
+ ```
112
+
113
+ then the directory of the file being read, then `include_paths`, then the `CEFPATH` environment
114
+ variable, then the current directory (which is what CEFLIB does).
115
+
116
+ ## Errors
117
+
118
+ Anything that would silently produce wrong numbers raises instead:
119
+
120
+ ```python
121
+ try:
122
+ cefast.load("broken.cef")
123
+ except cefast.ParseError as error:
124
+ print(error) # broken.cef:214: expected 31 values, got 30 (record 12)
125
+ ```
126
+
127
+ `ParseError` subclasses `ValueError` and names the file, the line and, inside the data section, the
128
+ record.
129
+
130
+ ## C++
131
+
132
+ Header-only C++20, same API shape:
133
+
134
+ ```cpp
135
+ #include <cefast/cefast.hpp>
136
+
137
+ auto file = cefast::load("file.cef");
138
+ for (const auto& var : file.variables)
139
+ std::cout << var.name << '\n';
140
+ ```
141
+
142
+ With meson: `dependency('cefast', fallback: ['cefast', 'cefast_dep'])`.
143
+
144
+ ## Performance
145
+
146
+ On the 41-file CSA sample corpus (10.4 MB), against CEFLIB 1.8.6, loading every file from Python
147
+ with the default threads: **11.5 ms against 35.1 ms** (3.05x overall, median 1.60x per file).
148
+ Every file is faster, from 1.20x to 7x. Numbers from a Ryzen 7 5800X; gzipped files are limited by
149
+ decompression. `tools/ceflib/benchmark.py` reproduces them.
150
+
151
+ Speed does not cost correctness: every float is correctly rounded (the value `strtod` gives), and a
152
+ malformed value is an error, where CEFLIB reads `12abc` as `12`.
153
+
154
+ ## Tests
155
+
156
+ ```sh
157
+ python -I tools/fetch_csa_corpus.py # downloads the CSA sample corpus and verifies its hashes
158
+ meson setup build && meson test -C build
159
+ ```
160
+
161
+ The corpus is not in the repository: it is fetched from the archive and checked against
162
+ `tests/resources/csa_manifest.json`. Tests that need it skip when it is missing.
163
+ `tools/ceflib/benchmark.py` builds CEFLIB to compare against it; the differential test skips when
164
+ CEFLIB is not importable.
165
+
166
+ Known differences from CEFLIB and from the strict CEF 2.0 document are listed in
167
+ [docs/accepted-deviations.md](docs/accepted-deviations.md).
168
+
169
+ ## License
170
+
171
+ MIT, see [COPYING](COPYING).