Skip to content

Commit 6260442

Browse files
authored
Merge pull request #1378 from effigies/fix/legacy_nifti_extension_content
FIX: Restore access to private attr Nifti1Extension._content
2 parents 1712cb0 + e97f572 commit 6260442

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

nibabel/nifti1.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ class NiftiExtension(ty.Generic[T]):
326326

327327
code: int
328328
encoding: str | None = None
329-
_content: bytes
329+
_raw: bytes
330330
_object: T | None = None
331331

332332
def __init__(
@@ -351,10 +351,14 @@ def __init__(
351351
self.code = extension_codes.code[code] # type: ignore[assignment]
352352
except KeyError:
353353
self.code = code # type: ignore[assignment]
354-
self._content = content
354+
self._raw = content
355355
if object is not None:
356356
self._object = object
357357

358+
@property
359+
def _content(self):
360+
return self.get_object()
361+
358362
@classmethod
359363
def from_bytes(cls, content: bytes) -> Self:
360364
"""Create an extension from raw bytes.
@@ -394,15 +398,15 @@ def _sync(self) -> None:
394398
and updates the bytes representation accordingly.
395399
"""
396400
if self._object is not None:
397-
self._content = self._mangle(self._object)
401+
self._raw = self._mangle(self._object)
398402

399403
def __repr__(self) -> str:
400404
try:
401405
code = extension_codes.label[self.code]
402406
except KeyError:
403407
# deal with unknown codes
404408
code = self.code
405-
return f'{self.__class__.__name__}({code}, {self._content!r})'
409+
return f'{self.__class__.__name__}({code}, {self._raw!r})'
406410

407411
def __eq__(self, other: object) -> bool:
408412
return (
@@ -425,7 +429,7 @@ def get_code(self):
425429
def content(self) -> bytes:
426430
"""Return the extension content as raw bytes."""
427431
self._sync()
428-
return self._content
432+
return self._raw
429433

430434
@property
431435
def text(self) -> str:
@@ -452,7 +456,7 @@ def get_object(self) -> T:
452456
instead.
453457
"""
454458
if self._object is None:
455-
self._object = self._unmangle(self._content)
459+
self._object = self._unmangle(self._raw)
456460
return self._object
457461

458462
# Backwards compatibility
@@ -488,7 +492,7 @@ def write_to(self, fileobj: ty.BinaryIO, byteswap: bool = False) -> None:
488492
extinfo = extinfo.byteswap()
489493
fileobj.write(extinfo.tobytes())
490494
# followed by the actual extension content, synced above
491-
fileobj.write(self._content)
495+
fileobj.write(self._raw)
492496
# be nice and zero out remaining part of the extension till the
493497
# next 16 byte border
494498
pad = extstart + rawsize - fileobj.tell()

nibabel/tests/test_nifti1.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,33 @@ def test_extension_content_access():
12501250
assert json_ext.json() == {'a': 1}
12511251

12521252

1253+
def test_legacy_underscore_content():
1254+
"""Verify that subclasses that depended on access to ._content continue to work."""
1255+
import io
1256+
import json
1257+
1258+
class MyLegacyExtension(Nifti1Extension):
1259+
def _mangle(self, value):
1260+
return json.dumps(value).encode()
1261+
1262+
def _unmangle(self, value):
1263+
if isinstance(value, bytes):
1264+
value = value.decode()
1265+
return json.loads(value)
1266+
1267+
ext = MyLegacyExtension(0, '{}')
1268+
1269+
assert isinstance(ext._content, dict)
1270+
# Object identity is not broken by multiple accesses
1271+
assert ext._content is ext._content
1272+
1273+
ext._content['val'] = 1
1274+
1275+
fobj = io.BytesIO()
1276+
ext.write_to(fobj)
1277+
assert fobj.getvalue() == b'\x20\x00\x00\x00\x00\x00\x00\x00{"val": 1}' + bytes(14)
1278+
1279+
12531280
def test_extension_codes():
12541281
for k in extension_codes.keys():
12551282
Nifti1Extension(k, 'somevalue')

0 commit comments

Comments
 (0)