Repository navigation
7.0: slim binding APIs, compatibility policy, and installable wheels on every platform - #142
Merged
Merged
Conversation
Wheels took the build runner's own platform tag, so 6.0.0 shipped as macosx_26_0_arm64 and manylinux_2_39_x86_64 although the library needs only macOS 12.0 and GLIBC 2.34: pip refused it on macOS 14/15, Debian 12, Ubuntu 22.04, RHEL 9 and Amazon Linux 2023. The build hook now reads the floor from the library (LC_BUILD_VERSION minos, newest GLIBC_2.N symbol), and CI checks each wheel installs on the runner that built it. Adds ubuntu-24.04-arm to the native, CLI and wheel builds, and fixes the arch detection that labelled Linux aarch64 (uname -m) as x64.
… wheels CodeQL picked its matrix from the languages a pull request touched, so a PR without C# changes never created "Analyze (csharp)" and the required check stayed pending. Both languages now always get a job, and an unchanged one skips its steps, as Build & Test already does. macos-15-intel joins the native, CLI and wheel builds. musl builds run in Alpine containers on x64 and arm64: build_native.py picks the linux-musl RID off glibc, and the wheel takes the musllinux tag when the library links musl.
…t the last release A versioning guide says what a minor version may change: new members on the interfaces only the library implements (with default implementations), new enum values, new options. The interfaces users implement gain nothing they would have to implement. Those library-implemented interfaces and the two growing enums now say so in their docs, and CONTRIBUTING lists the rules. ExcelReader.NET and ExcelReader.Arrow enable package validation against 7.0.0-rc.2, and CI packs both on every pull request, so a removed or changed member fails the build. The development version derives from the baseline, since validation requires an assembly version at least the baseline's; release builds still override it from the tag.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #142 +/- ##
=======================================
Coverage 91.06% 91.06%
=======================================
Files 251 251
Lines 17472 17472
Branches 3153 3153
=======================================
Hits 15911 15911
Misses 1070 1070
Partials 491 491 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
open_workbook() now takes a path, bytes, bytearray, memoryview, io.BytesIO, a Source, or any object with readinto()/read(), and picks the native open from the input's type. open_bytes(), open_source() and open_stream() are removed; the last two only existed in the 7.0 release candidates. BREAKING CHANGE: open_bytes(data, ...) becomes open_workbook(data, ...).
…unction each write_workbook(), write_arrow(), write_pandas() and write_polars() take the destination first: a path, or any binary object with write(), such as io.BytesIO or an open file. The four *_to_bytes() twins are removed. A destination with no path needs format=, and the frame writers take format and options as keywords instead of forwarding **kwargs. BREAKING CHANGE: write_*_to_bytes(x, format=f) becomes write_*(buffer, x, format=f) on an io.BytesIO.
…h one function each open_writer() takes a path or any binary object with write(); the latter receives the finished workbook in one write() call when the writer closes, even with a sheet left open. open_writer_to_memory() and SheetWriter.bytes() are removed. encrypt_package() takes the package as a path, bytes or io.BytesIO and the destination as a path or an object with write(). Path to path still uses the native file export; any other pair goes through memory. encrypt_package_bytes() is removed. BREAKING CHANGE: open_writer_to_memory(f) becomes open_writer(buffer, f), and encrypt_package_bytes(p, pw) becomes encrypt_package(p, buffer, pw).
…e function Removed: - Workbook.sheet_count, sheet_names, sheet_name_at (use workbook.sheets) - Sheet.read_all, read_all_columnar, ColumnarSheet, decode_cell - Sheet.to_record_batch (to_arrow now returns the RecordBatch) - Sheet.to_record_batch_reader (use pyarrow.RecordBatchReader.from_stream(sheet.to_arrow_stream(...))) - Sheet.iter_pandas, iter_polars - write_arrow, write_pandas, write_polars (write_workbook takes Arrow data) - SheetWriter.write_str/i64/f64/bool/date/time/timestamp/null, start_row, end_row (write_row infers types; (None, ColumnType.X) is a typed blank) - OpenOptions.csv_max_cell_bytes, csv_intern_strings (max_cell_bytes and intern_strings now reach the CSV reader too) - ArrowStream from __all__ to_pandas gains parallelism, matching to_polars. BREAKING CHANGE: the names above are gone from the Python package; each has a 7.0 replacement listed above. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One way to do each thing, with options passed as `const Opts& = {}`:
- Workbook::open is one overload set (path, byte span, unique_ptr<Source>,
unique_ptr<InputStream>); open_memory, open_source and open_stream are gone.
The format moves into OpenOptions::format.
- Workbook::sheet_count, sheet_name_at and sheet_names are removed; use
sheets(), sheet(i) and Sheet::name().
- Sheet::read_all_decoded is renamed read_all; RowCursor::read_all_decoded is
removed. typed_reader and arrow_stream reject batch_size <= 0.
- write_columns and write_sheet take a path or a std::vector<uint8_t>& and read
the format from WriteOptions::format (AUTO = path extension).
write_columns_to_memory, write_sheet_to_memory and the format overloads are
removed; format_from_path is internal.
- WriterHandle::open takes a path or a vector; open_memory and bytes() are
removed and finish() reports the result of completing the workbook.
- aggregate_csv(path | span, seed, OpenOptions, header_row, dop) replaces the
four aggregate_csv_file/aggregate_csv_memory functions and
CsvParallelOptions; the seed is a value copied per partition.
- The C ABI is hidden: raw-handle constructors, from_raw and handle() are
private or removed, to_c() is internal, XlType and FieldBinding move to
detail, TableView::to_vector is removed.
- ArrowSchemaGuard and ArrowArrayGuard merge into ArrowTable; every stream
batch carries its schema.
- OpenOptions::password_ and password() become a plain `password` field, and
csv_max_cell_bytes/csv_intern_strings are dropped: max_cell_bytes and
intern_strings now apply to CSV too.
- RowView's unused payload decoding is removed.
BREAKING CHANGE: the C++ header API changes as listed above; see the 7.0
migration guide for the mapping.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Flatten the crate to one path per item at the root, hide the FFI, and
fold duplicated entry points into option builders and enum arguments.
- Raw bindings (Xl* structs, xl_* functions, XL_* constants) move to a
private ffi module; derive support moves to #[doc(hidden)] __private.
- Modules workbook, writer, writer_handle, rows, source, aggregate and
arrow become private; their items are re-exported at the root.
- Format, ColumnType and ErrorKind replace the XL_FORMAT_*, XL_T_* and
status integers; Error becomes a struct with kind() and message().
- Opening: Workbook::open(path) plus OpenOptions::{open, open_bytes,
open_source, open_reader}; format is an OpenOptions setting.
Removed Workbook::{open_with, open_memory, open_source, open_reader,
sheet_count, sheet_name_at, sheet_names}.
- Reading: Sheet::read_all replaces read_all_decoded/DecodedRows and
read_all_blob; Sheet::parse replaces parse_sheet/parse_sheet_parallel;
Sheet::parse_arrow/parse_arrow_stream replace the arrow module's free
functions; infer_schema takes a parse_text flag.
- Writing: write_columns/write_sheet take a path and &WriteOptions;
write_columns_to/write_sheet_to take an io::Write and replace the
*_to_memory functions; format moves into WriteOptions (Auto infers
from the extension). WriterHandle::{create, new, finish} replace
open/open_with/open_memory/bytes; write_null is removed.
- aggregate_csv(input, &OpenOptions, header_row, parallelism, seed)
replaces aggregate_csv_file/aggregate_csv_memory/CsvParallelOptions.
- OpenOptions/WriteOptions are builder-only; csv_max_cell_bytes and
csv_intern_strings fold into max_cell_bytes/intern_strings.
BREAKING CHANGE: every module path, the raw FFI surface, integer format
and type codes, Error's enum shape and code(), and the removed functions
listed above are gone; see the 7.0 migration guide.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…as_date knows the date system Sheet.parse_typed is now parse and iter_parse_typed is parse_batches, the names the C++ and Rust bindings use. header_row, parallelism and batch_size are keyword-only on every read method. Cell carries its workbook's date1904, so as_date() takes no argument. BREAKING CHANGE: parse_typed -> parse, iter_parse_typed -> parse_batches, read keywords are keyword-only, Cell.as_date(date1904) -> Cell.as_date(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bumps Meziantou.Analyzer from 3.0.294 to 3.0.303 Bumps Microsoft.CodeAnalysis.NetAnalyzers from 10.0.401 to 10.0.402 --- updated-dependencies: - dependency-name: Meziantou.Analyzer dependency-version: 3.0.303 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: analyzers - dependency-name: Microsoft.CodeAnalysis.NetAnalyzers dependency-version: 10.0.402 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: analyzers ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps xunit.runner.visualstudio from 4.0.0 to 4.0.1 Bumps xunit.v3.mtp-v2 from 4.0.1 to 4.0.2 --- updated-dependencies: - dependency-name: xunit.runner.visualstudio dependency-version: 4.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: test - dependency-name: xunit.v3.mtp-v2 dependency-version: 4.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: test ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps OfficeIMO.Excel from 3.4.4 to 3.4.5 --- updated-dependencies: - dependency-name: OfficeIMO.Excel dependency-version: 3.4.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: benchmarks ... Signed-off-by: dependabot[bot] <support@github.com>
… ReadOptions
Sheet::typed_chunks is now parse_batches, parse_arrow is to_arrow and
parse_arrow_stream is to_arrow_stream (TypedChunks/ArrowChunks become
TypedBatches/ArrowBatches). The four take one ReadOptions builder
(header_row, parallelism, batch_size) instead of loose arguments.
Date, Time and Timestamp are built through their public field only.
BREAKING CHANGE: parse(h, n) -> parse(&ReadOptions), typed_chunks ->
parse_batches, parse_arrow -> to_arrow, parse_arrow_stream ->
to_arrow_stream, Date::new(d) -> Date { days_since_epoch: d }.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e ReadOptions
parse_sheet is now parse, typed_reader is parse_batches, parse_arrow is
to_arrow and arrow_stream is to_arrow_stream. The four take one
ReadOptions aggregate (header_row, parallelism, batch_size) instead of
loose arguments.
BREAKING CHANGE: parse_sheet<T>(s, h, n) -> parse<T>(s, {.header_row = h,
.parallelism = n}); typed_reader -> parse_batches; parse_arrow -> to_arrow;
arrow_stream -> to_arrow_stream.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ts/ExcelReader.Benchmarks/develop/benchmarks-62a6cf4621
…ts/ExcelReader.Tests/develop/test-3d9439c6bb
…elop/analyzers-fd646a9af5
…nly arguments for better compatibility
rows() creates one Cell per cell, and a frozen dataclass's __init__ goes through object.__setattr__ for every field. A plain slots dataclass is ~2x cheaper to construct (493 ns vs 1023 ns) and makes rows() ~10% faster on the 65K-row fixture (1.70-1.79 s vs 1.91-2.04 s, min of 3, interleaved). Cell stays keyword-only, so fields can still be added. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this change?
Everything on
developsince 7.0.0-rc.2. It does three things:docs/guide/migrating-to-v7.mdhas a v6 → v7 table per binding.The C ABI is unchanged and
XL_ABI_VERSIONstays 6.Wheels and native builds
macosx_26_0andmanylinux_2_39, so pip refused 6.0.0 and the 7.0 release candidates on macOS 14/15, Debian 12, Ubuntu 22.04, RHEL 9 and Amazon Linux 2023. The library itself needs macOS 12.0 and GLIBC 2.34.ubuntu-24.04-arm), macOS x86_64 (macos-15-intel), and musllinux x64/aarch64 built in Alpine containers (python/scripts/build_musl_wheel.sh).check_wheel_tag.pyfails CI when a wheel does not install on the runner that built it.aarch64. The old check would have published the Linux ARM assets and CLI as x64.manylinux_2_34_{x86_64,aarch64},musllinux_1_2_{x86_64,aarch64},macosx_12_0_{arm64,x86_64},win_amd64.CI
Analyze (csharp)andAnalyze (python). Before, a PR without C# changes never created the requiredAnalyze (csharp)check, so it stayed pending forever.ExcelReader.NETandExcelReader.Arrowenable package validation against 7.0.0-rc.2, andBuild & Test (ubuntu-latest)packs both. A removed or changed public member fails the build: a deliberate break was caught with CP0002.Compatibility policy
New guide page
docs/guide/versioning.mdsays what a minor version may change:Interfaces that users implement never gain a member they would have to implement.
XML docs on those interfaces and on
CellTypeandExcelColumnTypelink to the policy. CONTRIBUTING lists the rules.Python API
open_workbook(source)is the only opener. It takes a path, bytes/bytearray/memoryview/io.BytesIO, aSource, or a readable stream.open_bytes,open_sourceandopen_streamare removed.write_workbook(destination, data, types=None)takes a path or a binary object withwrite(), and aTypedTableor any Arrow-compatible table, including pandas and polars DataFrames. Removed:write_arrow,write_pandas,write_polarsand every*_to_bytes.open_writer(destination)andencrypt_package(package, destination, password)follow the same pattern.open_writer_to_memory,SheetWriter.bytes()andencrypt_package_bytesare removed.rows(),parse_typed()/iter_parse_typed(),to_arrow()(now aRecordBatch)/to_arrow_stream(), orto_pandas()/to_polars().read_all,read_all_columnar,ColumnarSheet,decode_cell,to_record_batch,to_record_batch_reader,iter_pandas,iter_polars,sheet_count,sheet_names,sheet_name_at.SheetWriterwrites whole rows only, withwrite_row. A typed blank is written as(None, ColumnType.X).C++ API
Workbook::openis one overload set: path, byte span,SourceorInputStream.write_columns,write_sheetandWriterHandle::opentake a path or astd::vector<std::uint8_t>&.WriterHandle::finish()reports errors.const Opts& = {}, with the format inside them.aggregate_csv;CsvParallelOptionsis removed.from_raw,handle()andto_c()are no longer public. The dead payload path inRowViewis removed.v7.0.0and documentsWriterHandle.Rust API
Xl*/xl_*/XL_*items.Format,ColumnType,ErrorKind.Workbook::open(path)plusOpenOptions::{open, open_bytes, open_source, open_reader}.OpenOptionsandWriteOptionsare builder-only.impl Writepairs (write_columns/write_columns_to,write_sheet/write_sheet_to).WriterHandle::new(writer)ends withfinish().Sheet::{parse, parse_arrow, parse_arrow_stream, read_all}and oneaggregate_csv.Behavior change in all three bindings
max_cell_bytesandintern_stringsnow apply to CSV too. Before, a CSV read used onlycsv_max_cell_bytes/csv_intern_strings, so the general limit never reached it. Thecsv_*pair is removed from the bindings.Checklist
dotnet build ExcelReader.slnx --configuration Releasebuilds clean (warnings are errors)dotnet test tests/ExcelReader.Tests/ExcelReader.Tests.csproj --configuration ReleasepassesPublicAPI.Unshipped.txtupdated (.NET public API unchanged; XML docs only)Test plan
developis green on every job: .NET on three OSes, ISA fallbacks, AOT, CodeQL, docs, the native build on five runners, Python smoke on five runners, musl on x64 and arm64, Rust and C++ on three OSes.find_packageconsumer.-D warningsand 133 tests plus 19 doctests.Known gaps
release.ymljobs added here (musl, macOS Intel CLI and wheel) first run on the next tag.PackageValidationBaselineVersionto7.0.0.