Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deepcopy on throws on certain Dataset #1816

Closed
erikogabrielsson opened this issue Jun 19, 2023 · 3 comments · Fixed by #1930
Closed

Deepcopy on throws on certain Dataset #1816

erikogabrielsson opened this issue Jun 19, 2023 · 3 comments · Fixed by #1930
Assignees
Milestone

Comments

@erikogabrielsson
Copy link
Contributor

Describe the bug
Doing a deepcopy() on a Dataset after an update() with another Dataset containing a Sequence throws AttributeError: 'DataElement' object has no attribute 'VR'.
I'm using 2.4.1 (not sure why version info says otherwise).

Expected behavior
Using 2.3.1 I get a copy of the Dataset including the elements from the update-with Dataset.
With the steps to reproduce:

(0048, 0105)  Optical Path Sequence  1 item(s) ---- 
   (0048, 0106) Optical Path Identifier             SH: '0'
   ---------

Steps To Reproduce

from copy import deepcopy
from pydicom import Dataset, Sequence
optical_path_dataset = Dataset()
optical_path_item = Dataset()
optical_path_item.OpticalPathIdentifier = "0"
optical_path_dataset.OpticalPathSequence = Sequence([optical_path_item])
# Does not throw
deepcopy(optical_path_dataset)

# Also does not throw
dataset = Dataset()
dataset.update(deepcopy(optical_path_dataset))
deepcopy(dataset)

# Throws
dataset = Dataset()
dataset.update(optical_path_dataset)
deepcopy(dataset)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[3], line 18
     16 dataset = Dataset()
     17 dataset.update(optical_path_dataset)
---> 18 deepcopy(dataset)

File [c:\Users\er-gac\.pyenv\pyenv-win\versions\3.11.2\Lib\copy.py:153](file:///C:/Users/er-gac/.pyenv/pyenv-win/versions/3.11.2/Lib/copy.py:153), in deepcopy(x, memo, _nil)
    151 copier = getattr(x, "__deepcopy__", None)
    152 if copier is not None:
--> 153     y = copier(memo)
    154 else:
    155     reductor = dispatch_table.get(cls)

File [c:\Users\er-gac\.pyenv\pyenv-win\versions\3.11.2\Lib\site-packages\pydicom\dataset.py:477](file:///C:/Users/er-gac/.pyenv/pyenv-win/versions/3.11.2/Lib/site-packages/pydicom/dataset.py:477), in Dataset.__deepcopy__(self, memo)
    475     memo[id(self)] = copied   # add the new class to the memo
    476 # Insert a deepcopy of all instance attributes
--> 477 copied.__dict__.update(copy.deepcopy(self.__dict__, memo))
    478 # Manually update the weakref to be correct
    479 for elem in copied:  # DICOM elements

File [c:\Users\er-gac\.pyenv\pyenv-win\versions\3.11.2\Lib\copy.py:146](file:///C:/Users/er-gac/.pyenv/pyenv-win/versions/3.11.2/Lib/copy.py:146), in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File [c:\Users\er-gac\.pyenv\pyenv-win\versions\3.11.2\Lib\copy.py:231](file:///C:/Users/er-gac/.pyenv/pyenv-win/versions/3.11.2/Lib/copy.py:231), in _deepcopy_dict(x, memo, deepcopy)
    229 memo[id(x)] = y
    230 for key, value in x.items():
--> 231     y[deepcopy(key, memo)] = deepcopy(value, memo)
    232 return y

File [c:\Users\er-gac\.pyenv\pyenv-win\versions\3.11.2\Lib\copy.py:146](file:///C:/Users/er-gac/.pyenv/pyenv-win/versions/3.11.2/Lib/copy.py:146), in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File [c:\Users\er-gac\.pyenv\pyenv-win\versions\3.11.2\Lib\copy.py:231](file:///C:/Users/er-gac/.pyenv/pyenv-win/versions/3.11.2/Lib/copy.py:231), in _deepcopy_dict(x, memo, deepcopy)
    229 memo[id(x)] = y
    230 for key, value in x.items():
--> 231     y[deepcopy(key, memo)] = deepcopy(value, memo)
    232 return y

File [c:\Users\er-gac\.pyenv\pyenv-win\versions\3.11.2\Lib\copy.py:172](file:///C:/Users/er-gac/.pyenv/pyenv-win/versions/3.11.2/Lib/copy.py:172), in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File [c:\Users\er-gac\.pyenv\pyenv-win\versions\3.11.2\Lib\copy.py:271](file:///C:/Users/er-gac/.pyenv/pyenv-win/versions/3.11.2/Lib/copy.py:271), in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    269 if state is not None:
    270     if deep:
--> 271         state = deepcopy(state, memo)
    272     if hasattr(y, '__setstate__'):
    273         y.__setstate__(state)

File [c:\Users\er-gac\.pyenv\pyenv-win\versions\3.11.2\Lib\copy.py:146](file:///C:/Users/er-gac/.pyenv/pyenv-win/versions/3.11.2/Lib/copy.py:146), in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File [c:\Users\er-gac\.pyenv\pyenv-win\versions\3.11.2\Lib\copy.py:231](file:///C:/Users/er-gac/.pyenv/pyenv-win/versions/3.11.2/Lib/copy.py:231), in _deepcopy_dict(x, memo, deepcopy)
    229 memo[id(x)] = y
    230 for key, value in x.items():
--> 231     y[deepcopy(key, memo)] = deepcopy(value, memo)
    232 return y

File [c:\Users\er-gac\.pyenv\pyenv-win\versions\3.11.2\Lib\copy.py:153](file:///C:/Users/er-gac/.pyenv/pyenv-win/versions/3.11.2/Lib/copy.py:153), in deepcopy(x, memo, _nil)
    151 copier = getattr(x, "__deepcopy__", None)
    152 if copier is not None:
--> 153     y = copier(memo)
    154 else:
    155     reductor = dispatch_table.get(cls)

File [c:\Users\er-gac\.pyenv\pyenv-win\versions\3.11.2\Lib\site-packages\pydicom\dataset.py:480](file:///C:/Users/er-gac/.pyenv/pyenv-win/versions/3.11.2/Lib/site-packages/pydicom/dataset.py:480), in Dataset.__deepcopy__(self, memo)
    478 # Manually update the weakref to be correct
    479 for elem in copied:  # DICOM elements
--> 480     if elem.VR == VR_.SQ:
    481         elem.value.parent_dataset = copied  # setter does weakref
    482 return copied

AttributeError: 'DataElement' object has no attribute 'VR'

Your environment

module version
platform Windows-10-10.0.19045-SP0
Python 3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)]
pydicom 2.4.0
gdcm module not found
jpeg_ls module not found
numpy 1.24.0
PIL 9.4.0
pylibjpeg module not found
openjpeg module not found
libjpeg module not found
@darcymason
Copy link
Member

Thanks for the issue and detailed explanation/report.

I'm using 2.4.1 (not sure why version info says otherwise).

I see that too now in a local venv ... I'll look into that as well.

@darcymason
Copy link
Member

I've confirmed the issue, will try to work on it when I get a chance.

@erikogabrielsson
Copy link
Contributor Author

Thanks for the fix @scaramallion!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants