Repository navigation
Keep the characters after the length number in char_dim_name - #11757
Conversation
validate_char_dim_name matched the last digit run anywhere in the name and rebuilt the name as prefix + strlen, dropping everything after the digits. A char dimension like "n3_chars" was therefore re-encoded as "n3", so a decode/encode roundtrip silently renamed it. Only treat a trailing number as the string length. Co-authored-by: Claude <[email protected]>
|
Thanks for the fix! The suffix was definitely getting lost, but I think the new regex goes a bit too far. A number that isn't at the end of the name is no longer treated as the length at all, so the clash protection from #10395 doesn't apply to those names anymore. 1. Name with a number in the middle, matching length (fixed by this PR) import numpy as np
import xarray as xr
ds = xr.Dataset({"a": ("x", np.array([b"ab", b"cdef"]))})
ds.a.encoding["char_dim_name"] = "n4_chars"
ds.to_netcdf("ex1.nc")
xr.open_dataset("ex1.nc", decode_cf=False).sizes
# main: {'x': 2, 'n4': 4}
# PR: {'x': 2, 'n4_chars': 4}2. Two variables share the name, one is shorter (regression) ds = xr.Dataset(
{
"a": ("x", np.array([b"ab", b"cdef"])),
"b": ("x", np.array([b"ab", b"cde"])),
}
)
ds.a.encoding["char_dim_name"] = "n4_chars"
ds.b.encoding["char_dim_name"] = "n4_chars"
ds.to_netcdf("ex2.nc")
# main: works (with a warning), dims 'n4': 4 and 'n3': 3
# PR: ValueError: shape mismatch: objects cannot be broadcast to a single shape.
# Mismatch is between arg 0 with shape (2, 3) and arg 1 with shape (2, 4).3. Round trip, then shorten one variable ds = xr.Dataset(
{
"a": ("x", np.array([b"ab", b"cdef"])),
"b": ("x", np.array([b"ab", b"cdef"])),
}
)
ds.a.encoding["char_dim_name"] = "n4_chars"
ds.b.encoding["char_dim_name"] = "n4_chars"
ds.to_netcdf("ex3.nc")
ds2 = xr.open_dataset("ex3.nc").load()
ds2["b"] = ds2.b.str[:3].astype("S")
ds2.b.encoding = {"char_dim_name": "n4_chars", "original_shape": (2, 4)}
ds2.to_netcdf("ex3b.nc")
xr.open_dataset("ex3b.nc", decode_cf=False).sizes
# main: {'x': 2, 'n4': 4, 'n3': 3}
# PR: {'x': 2, 'n4_chars': 4, 'n4_chars3': 3}So the question is what the dimension name should be when the length changes and the number isn't at the end. Any thoughts on what the expected behavior would be here? |
Restore the previous rule that the last number in char_dim_name is the string length, so the clash protection from pydata#10395 keeps working, and keep the characters after that number. A mismatched "n4_chars" now becomes "n3_chars" instead of "n3" (main) or "n4_chars3" (previous commit).
|
Thanks for the examples, you're right that the trailing-only regex dropped the clash protection. I think the number should still be read as the length, wherever it is, and only the characters after it should be kept. So the last number gets replaced by the real length and the suffix stays. I pushed that in cacfc61:
Only the last number is swapped, so |
Co-Authored-By: Claude Opus 5.5 <[email protected]>

Description
In xarray, a dimension name such as
n3_charswas rebuilt asn3: the last number in the name was taken as the string length and everything after it was dropped. The last number is still read as the length (so the clash protection from #10395 still applies), but the characters after it are now kept. A matching name stays as is, and a mismatched one only has its number replaced (n4_charswith length 3 becomesn3_chars).Checklist
whats-new.rstAI Disclosure
Tools: Claude Code. Prompt: find a reproducible bug in xarray's utilities/coding modules and propose a minimal fix with a regression test.