Skip to content

Commit

Permalink
Fix deepcopy of Dataset and Sequence (#1814)
Browse files Browse the repository at this point in the history
* Use __class__ for subtypes

* Add tests
  • Loading branch information
CPBridge committed Jun 18, 2023
1 parent 4b0efe0 commit 6d29252
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 2 deletions.
3 changes: 2 additions & 1 deletion src/pydicom/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,8 @@ def parent(self, value: "Dataset") -> None:
self._parent = weakref.ref(value)

def __deepcopy__(self, memo: Optional[Dict[int, Any]]) -> "Dataset":
copied = Dataset()
cls = self.__class__
copied = cls.__new__(cls)
if memo:
memo[id(self)] = copied # add the new class to the memo
# Insert a deepcopy of all instance attributes
Expand Down
3 changes: 2 additions & 1 deletion src/pydicom/sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ def extend(self, val: Iterable[Dataset]) -> None: # type: ignore[override]
ds.parent_seq = self # type: ignore

def __deepcopy__(self, memo: Optional[Dict[int, Any]]) -> "Sequence":
copied = Sequence()
cls = self.__class__
copied = cls.__new__(cls)
if memo is not None:
memo[id(self)] = copied
copied.__dict__.update(deepcopy(self.__dict__, memo))
Expand Down
10 changes: 10 additions & 0 deletions tests/test_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -1972,6 +1972,16 @@ def test_deepcopy_without_filename(self):
ds2 = copy.deepcopy(ds)
assert ds2.filename == ""

def test_deepcopy_dataset_subclass(self):
"""Regression test for #1813."""
class MyDatasetSubclass(pydicom.Dataset):
pass

my_dataset_subclass = MyDatasetSubclass()

ds2 = copy.deepcopy(my_dataset_subclass)
assert ds2.__class__ is MyDatasetSubclass


class TestDatasetOverlayArray:
"""Tests for Dataset.overlay_array()."""
Expand Down
11 changes: 11 additions & 0 deletions tests/test_sequence.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Copyright 2008-2020 pydicom authors. See LICENSE file for details.
"""Unit tests for the pydicom.sequence module."""

import copy
import weakref

import pytest
Expand Down Expand Up @@ -174,3 +175,13 @@ def test_iadd(self):

for ds in seq:
assert isinstance(ds.parent_seq, weakref.ReferenceType)

def test_deepcopy_sequence_subclass(self):
"""Regression test for #1813."""
class MySequenceSubclass(Sequence):
pass

my_sequence_subclass = MySequenceSubclass()

seq2 = copy.deepcopy(my_sequence_subclass)
assert seq2.__class__ is MySequenceSubclass

0 comments on commit 6d29252

Please sign in to comment.