Contributing¶
Thanks for your interest in pygdb. This is a small, focused project
with a hard boundary on how it's developed, described below — please
read it before opening an issue or pull request.
Bug reports¶
Bug reports are very welcome, especially when a real .gdb or .grd
file trips up the reader. The most useful report includes:
- A minimal, reproducible example file (or the smallest real file you can share that reproduces the problem). Synthetic/hand-crafted files are fine too, as long as they reflect a real, naturally occurring database rather than an adversarial one (see below).
- The exact traceback, warning, or incorrect output you got.
- What you expected instead, ideally cross-checked against an
independent source (a paired ASCII/CSV export, a
.geoh5sibling, vendor documentation, etc.) rather than just "this doesn't look right."
If you can't share the file itself (proprietary/confidential survey data), a hex dump of the relevant region (header, symbol table, or the specific blob that fails) is a good substitute — see the format specification for what each region should look like.
If the reader printed an unseen-feature notice
(GDBUnseenFeatureWarning), please report it with the
unseen format feature
issue form, pasting the output of pygdb.unseen_feature_report(path) (or
python -m pygdb.report path). It holds only the file's structure, not
its data or name, and is usually all we need, so the file itself isn't
required.
What we will not do: reverse engineering the original software¶
This project was produced by clean-room methods only: reading
Geosoft's own published, open-source code and documentation,
independent third-party format readers, and byte-level analysis of
real, publicly downloaded .gdb/.grd files. No Geosoft software of
any kind — the geosoft/gxapi/gxpy compiled package, Oasis montaj,
Geosoft Desktop, or the free Geosoft Viewer — has ever been installed,
imported, run, decompiled, or disassembled in producing this project,
and it never will be as part of this project's development. See
Provenance for the full account of how this was
done.
In keeping with that:
- We will not accept contributions, patches, or findings derived from running, decompiling, disassembling, or otherwise reverse engineering Geosoft's proprietary software or SDK. If a pull request or issue relies on such a source, even indirectly, we won't merge or act on it.
- We will not accept sample files that look like they were purpose-built to defeat, extract, or probe Geosoft's own software (e.g. files clearly constructed to trigger and observe a specific internal code path, rather than files that are, or resemble, a real survey/processing database). If you're unsure whether a file you want to submit fits this project's clean-room constraints, please ask in the issue rather than assume.
- Real-world files with unusual, buggy, or leftover/garbage content (as long as they arose from ordinary use, not deliberate probing) are exactly the kind of thing this project wants — several of the format details already documented were found exactly that way.
Development¶
- The reader lives in
pygdb/at the repository root (gdb_reader.py,grd_reader.py,lzrw1.py,registry.py,gdb.py).numpyis its one required third-party dependency, used specifically so VA/array channels (docs/spec.md section 5) come back as correctly- shaped(n_rows, array_width)arrays instead of one flat buffer.xarrayis optional (pip install -e ".[xarray]"or.[dev]", which already includes it) -- onlyGDB.to_xarray()needs it, imported lazily inside that one method so importingpygdbitself never requires it.geoh5py(.[geoh5]) andpandas(.[pandas]) are optional the same way -- onlyGDB.to_geoh5()/GDB.to_dataframe()need them, respectively; both are also in.[dev]". rust/holds an optional Rust extension (pygdb._native) that accelerates the reader's real CPU-bound hot paths (LZRW1 decompression, fixed-width string decoding). This is one package, not two -- the rootpyproject.tomlis built withmaturin, which bundles the compiled extension into the samepython-gdbwheel as the pure-Python source whenever one's built for your platform, with no separate install step or extra. The pure-Python code inpygdb/is always the reference implementation and stays fully correct and usable on its own;pygdb/lzrw1.pyandpygdb/gdb_reader.pydispatch to_nativewhen it's built and fall back to plain Python otherwise, so both backends need to keep agreeing.rust/src/lib.rs's module doc records what was tried and deliberately left out after being benchmarked as not worth it -- worth reading before proposing another parallelism or I/O change there, so you're not re-deriving something already tested. See.github/workflows/wheels.yml's comments for the released wheel matrix and how to build locally.docs/spec.mdis the living reference for the on-disk format; it's updated as more real example files are tested against the reader. If your bug report changes what's known about the format, expect the fix to come with a spec update.docs/provenance/holds the historical research log, write-up, and one-off investigation scripts that produced the original implementation. It's kept as-is for provenance and isn't expected to be re-run against the current package layout.
Running the tests¶
The suite is split into synthetic-fixture unit tests (no sample data
needed, always run) and skip-safe integration tests in
tests/test_integration_samples.py that exercise the reader against
real files in a local, gitignored samples/ directory when one is
present, and skip cleanly when it isn't. If you're adding coverage for
a new format quirk, prefer extending tests/helpers.py's synthetic
fixture builders over requiring a real sample file, so the test stays
runnable by anyone.