codecov[bot]: # [Codecov](https://codecov.io/gh/pydicom/pydicom/pull/1151?src=pr&el=h1) Report
> Merging [#1151](https://codecov.io/gh/pydicom/pydicom/pull/1151?src=pr&el=desc) into [master](https://codecov.io/gh/pydicom/pydicom/commit/5c4e74e77f0a384c3dedb1678fbe02c60575d70e&el=desc) will **decrease** coverage by `0.10%`.
> The diff coverage is `87.65%`.

[![Impacted file tree graph](https://codecov.io/gh/pydicom/pydicom/pull/1151/graphs/tree.svg?width=650&height=150&src=pr&token=YciLV15Lwr)](https://codecov.io/gh/pydicom/pydicom/pull/1151?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #1151      +/-   ##
==========================================
- Coverage   94.95%   94.85%   -0.11%     
==========================================
  Files          91       93       +2     
  Lines       18924    19094     +170     
==========================================
+ Hits        17970    18111     +141     
- Misses        954      983      +29     
```


| [Impacted Files](https://codecov.io/gh/pydicom/pydicom/pull/1151?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pydicom/sr/codedict.py](https://codecov.io/gh/pydicom/pydicom/pull/1151/diff?src=pr&el=tree#diff-cHlkaWNvbS9zci9jb2RlZGljdC5weQ==) | `63.10% <50.00%> (+1.28%)` | :arrow_up: |
| [pydicom/data/retry.py](https://codecov.io/gh/pydicom/pydicom/pull/1151/diff?src=pr&el=tree#diff-cHlkaWNvbS9kYXRhL3JldHJ5LnB5) | `57.14% <57.14%> (ø)` | |
| [pydicom/filereader.py](https://codecov.io/gh/pydicom/pydicom/pull/1151/diff?src=pr&el=tree#diff-cHlkaWNvbS9maWxlcmVhZGVyLnB5) | `92.95% <66.66%> (ø)` | |
| [pydicom/data/download.py](https://codecov.io/gh/pydicom/pydicom/pull/1151/diff?src=pr&el=tree#diff-cHlkaWNvbS9kYXRhL2Rvd25sb2FkLnB5) | `76.63% <76.63%> (ø)` | |
| [pydicom/charset.py](https://codecov.io/gh/pydicom/pydicom/pull/1151/diff?src=pr&el=tree#diff-cHlkaWNvbS9jaGFyc2V0LnB5) | `94.07% <83.33%> (ø)` | |
| [pydicom/filewriter.py](https://codecov.io/gh/pydicom/pydicom/pull/1151/diff?src=pr&el=tree#diff-cHlkaWNvbS9maWxld3JpdGVyLnB5) | `97.08% <91.30%> (+0.28%)` | :arrow_up: |
| [pydicom/data/data\_manager.py](https://codecov.io/gh/pydicom/pydicom/pull/1151/diff?src=pr&el=tree#diff-cHlkaWNvbS9kYXRhL2RhdGFfbWFuYWdlci5weQ==) | `100.00% <100.00%> (ø)` | |
| [pydicom/dataset.py](https://codecov.io/gh/pydicom/pydicom/pull/1151/diff?src=pr&el=tree#diff-cHlkaWNvbS9kYXRhc2V0LnB5) | `98.73% <100.00%> (+<0.01%)` | :arrow_up: |
| [pydicom/tests/test\_charset.py](https://codecov.io/gh/pydicom/pydicom/pull/1151/diff?src=pr&el=tree#diff-cHlkaWNvbS90ZXN0cy90ZXN0X2NoYXJzZXQucHk=) | `100.00% <100.00%> (ø)` | |
| [pydicom/tests/test\_data\_manager.py](https://codecov.io/gh/pydicom/pydicom/pull/1151/diff?src=pr&el=tree#diff-cHlkaWNvbS90ZXN0cy90ZXN0X2RhdGFfbWFuYWdlci5weQ==) | `100.00% <100.00%> (ø)` | |
| ... and [13 more](https://codecov.io/gh/pydicom/pydicom/pull/1151/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pydicom/pydicom/pull/1151?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pydicom/pydicom/pull/1151?src=pr&el=footer). Last update [b9fb05c...48f46b6](https://codecov.io/gh/pydicom/pydicom/pull/1151?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

mrbean-bremen: I have been thinking about this, and my gut feeling is to leave it as it is, e.g. `Dataset.copy` just doing a shallow copy as in `dict`. I don't think we shall change the functionality of `copy.copy` and `copy.deepcopy`. For `Dataset.copy` one could argue, that the expected behavior is a deep copy (I remember a related discussion), or we could add an additional `Dataset.deepcopy`.

What do you think? 
darcymason: > What do you think?

Oops - typed my answer in the review conversation.
darcymason: > and my gut feeling is to leave it as it is, e.g. `Dataset.copy` just doing a shallow copy as in `dict`. I don't think we shall change the functionality of `copy.copy` and `copy.deepcopy`. For `Dataset.copy` one could argue though, that the expected behavior is a deep copy (I remember a related discussion), or we could add an additional `Dataset.deepcopy`

Sorry - I'm catching up after a complete hardware failure on my laptop - should have consolidated all my answers. ...  Just to address this part a little more specifically - I agree to leave ds.copy() as shallow as in `dict`.  I don't remember the details of the related conversation but I think adherence to Python standard way should be a top principle (as per iter discussion, it always causes confusion when we deviate).  I think `copy` (shallow) in Python is a 'gotcha' which causes unexpected behavior for many people (change some attribute and it changes in the copy too), but it is what it is and I think it is defensible to 'copy' that behavior in pydicom.
mrbean-bremen: > Sorry - I'm catching up after a complete hardware failure on my laptop

Argh - yes, I had that last year... had to install a new SSD. And of course didn't backup all data before...
darcymason: > > Sorry - I'm catching up after a complete hardware failure on my laptop
> 
> Argh - yes, I had that last year... had to install a new SSD. And of course didn't backup all data before...

Mine was a complete lack of anything happening on pushing the power button.  Eventually came back after some magic combination of resetting internal battery, then powering on while plugged in without the main battery, etc.... not sure if what I did actually solved it or whether it will randomly reappear.

diff --git a/doc/release_notes/v2.1.0.rst b/doc/release_notes/v2.1.0.rst
index f8d89bda0..b7cfca5bd 100644
--- a/doc/release_notes/v2.1.0.rst
+++ b/doc/release_notes/v2.1.0.rst
@@ -21,3 +21,4 @@ Enhancements
 
 Fixes
 .....
+* ``Dataset.copy`` now works as expected (see :issue:`1146`)
\ No newline at end of file
diff --git a/pydicom/dataset.py b/pydicom/dataset.py
index 8274c97cb..abe3de5a4 100644
--- a/pydicom/dataset.py
+++ b/pydicom/dataset.py
@@ -14,7 +14,7 @@ Dataset (dict subclass)
         * A Sequence (list subclass), where each item is a Dataset which
             contains its own DataElements, and so on in a recursive manner.
 """
-
+import copy
 from bisect import bisect_left
 import io
 import inspect  # for __dir__
@@ -502,6 +502,10 @@ class Dataset(dict):
 
         self.walk(decode_callback, recursive=False)
 
+    def copy(self):
+        """Return a shallow copy of the dataset."""
+        return copy.copy(self)
+
     def __delattr__(self, name):
         """Intercept requests to delete an attribute by `name`.
 

Dataset.copy returns an empty dict
**Describe the bug**
Call to Dataset.copy on an instance of a Dataset object returns an empty python dict.

**Expected behavior**
A shallow copy of the callee

**Steps To Reproduce**
```python
>>> from pydicom import Dataset
>>> ds = Dataset()
>>> ds.PatientName = "Jhon^Doe"
>>> ds
(0010, 0010) Patient's Name                      PN: 'Jhon^Doe'
>>> ds_copy = ds.copy()
>>> ds_copy
{}
>>> 
```


**Your environment**
```python
>>> import platform, sys, pydicom
>>> print(platform.platform(),
...       "\nPython", sys.version,
...       "\npydicom", pydicom.__version__)
Linux-5.4.0-40-generic-x86_64-with-debian-bullseye-sid 
Python 3.7.6 (default, May 20 2020, 16:52:50) 
[GCC 9.3.0] 
pydicom 1.4.2
```
diff --git a/pydicom/tests/test_dataset.py b/pydicom/tests/test_dataset.py
index fc186273e..38cffa086 100644
--- a/pydicom/tests/test_dataset.py
+++ b/pydicom/tests/test_dataset.py
@@ -1,16 +1,17 @@
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
 """Unit tests for the pydicom.dataset module."""
+import copy
 
 import pytest
 
 import pydicom
+from pydicom import dcmread
 from pydicom.data import get_testdata_file
 from pydicom.dataelem import DataElement, RawDataElement
 from pydicom.dataset import (
     Dataset, FileDataset, validate_file_meta, FileMetaDataset
 )
 from pydicom.encaps import encapsulate
-from pydicom import dcmread
 from pydicom.filebase import DicomBytesIO
 from pydicom.overlay_data_handlers import numpy_handler as NP_HANDLER
 from pydicom.pixel_data_handlers.util import get_image_pixel_ids
@@ -1834,3 +1835,29 @@ class TestFileMeta:
         assert shown.startswith("(0010, 0010) Patient's Name")
 
         pydicom.config.show_file_meta = orig_show
+
+    @pytest.mark.parametrize('copy_method',
+                             [Dataset.copy, copy.copy, copy.deepcopy])
+    def test_copy(self, copy_method):
+        ds = Dataset()
+        ds.PatientName = "John^Doe"
+        ds.BeamSequence = [Dataset(), Dataset(), Dataset()]
+        ds.BeamSequence[0].Manufacturer = "Linac, co."
+        ds.BeamSequence[1].Manufacturer = "Linac and Sons, co."
+        ds.is_implicit_VR = True
+        ds.is_little_endian = True
+        ds.read_encoding = "utf-8"
+        ds_copy = copy_method(ds)
+        assert isinstance(ds_copy, Dataset)
+        assert len(ds_copy) == 2
+        assert ds_copy.PatientName == "John^Doe"
+        assert ds_copy.BeamSequence[0].Manufacturer == "Linac, co."
+        assert ds_copy.BeamSequence[1].Manufacturer == "Linac and Sons, co."
+        if copy_method == copy.deepcopy:
+            assert id(ds_copy.BeamSequence[0]) != id(ds.BeamSequence[0])
+        else:
+            # shallow copy
+            assert id(ds_copy.BeamSequence[0]) == id(ds.BeamSequence[0])
+        assert ds_copy.is_implicit_VR
+        assert ds_copy.is_little_endian
+        assert ds_copy.read_encoding == "utf-8"

pip install -e .
parse_log_pytest
requirements.txt
numpy>=1.16.0 pillow
apt-get update apt-get install -y gcc
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
numpy==2.0.2
pillow==11.1.0
-e git+https://github.com/pydicom/pydicom.git@b9fb05c177b685bf683f7f57b2d57374eb7d882d#egg=pydicom

name: pydicom
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - numpy==2.0.2
      - pillow==11.1.0
prefix: /opt/conda/envs/pydicom

pydicom/tests/test_dataset.py::TestFileMeta::test_copy[copy0]
pydicom/tests/test_dataset.py::TestDataset::test_set_existing_data_element_by_name pydicom/tests/test_dataset.py::TestDataset::test_membership pydicom/tests/test_dataset.py::TestDataset::test_contains pydicom/tests/test_dataset.py::TestDataset::test_clear pydicom/tests/test_dataset.py::TestDataset::test_pop pydicom/tests/test_dataset.py::TestDataset::test_pop_using_tuple pydicom/tests/test_dataset.py::TestDataset::test_pop_using_keyword pydicom/tests/test_dataset.py::TestDataset::test_popitem pydicom/tests/test_dataset.py::TestDataset::test_setdefault pydicom/tests/test_dataset.py::TestDataset::test_setdefault_tuple pydicom/tests/test_dataset.py::TestDataset::test_setdefault_use_value pydicom/tests/test_dataset.py::TestDataset::test_setdefault_keyword pydicom/tests/test_dataset.py::TestDataset::test_get_exists1 pydicom/tests/test_dataset.py::TestDataset::test_get_exists2 pydicom/tests/test_dataset.py::TestDataset::test_get_exists3 pydicom/tests/test_dataset.py::TestDataset::test_get_exists4 pydicom/tests/test_dataset.py::TestDataset::test_get_default1 pydicom/tests/test_dataset.py::TestDataset::test_get_default2 pydicom/tests/test_dataset.py::TestDataset::test_get_default3 pydicom/tests/test_dataset.py::TestDataset::test_get_default4 pydicom/tests/test_dataset.py::TestDataset::test_get_raises pydicom/tests/test_dataset.py::TestDataset::test_named_member_updated pydicom/tests/test_dataset.py::TestDataset::test_update pydicom/tests/test_dataset.py::TestDataset::test_dir pydicom/tests/test_dataset.py::TestDataset::test_dir_filter pydicom/tests/test_dataset.py::TestDataset::test_delete_dicom_attr pydicom/tests/test_dataset.py::TestDataset::test_delete_dicom_command_group_length pydicom/tests/test_dataset.py::TestDataset::test_delete_other_attr pydicom/tests/test_dataset.py::TestDataset::test_delete_item_long pydicom/tests/test_dataset.py::TestDataset::test_delete_item_tuple pydicom/tests/test_dataset.py::TestDataset::test_delete_non_existing_item pydicom/tests/test_dataset.py::TestDatasetElements::test_sequence_assignment pydicom/tests/test_dataset.py::TestDatasetElements::test_ensure_file_meta pydicom/tests/test_dataset.py::TestDatasetElements::test_fix_meta_info pydicom/tests/test_dataset.py::TestFileDataset::test_pickle pydicom/tests/test_dataset.py::TestFileDataset::test_pickle_modified pydicom/tests/test_dataset.py::TestFileDataset::test_equality_file_meta pydicom/tests/test_dataset.py::TestDatasetOverlayArray::test_no_possible pydicom/tests/test_dataset.py::TestDatasetOverlayArray::test_possible_not_available pydicom/tests/test_dataset.py::TestDatasetOverlayArray::test_possible_available pydicom/tests/test_dataset.py::TestDatasetOverlayArray::test_handler_raises
pydicom/tests/test_dataset.py::TestDataset::test_attribute_error_in_property pydicom/tests/test_dataset.py::TestDataset::test_for_stray_raw_data_element pydicom/tests/test_dataset.py::TestDataset::test_attribute_error_in_property_correct_debug pydicom/tests/test_dataset.py::TestDataset::test_tag_exception_print pydicom/tests/test_dataset.py::TestDataset::test_tag_exception_walk pydicom/tests/test_dataset.py::TestDataset::test_set_new_data_element_by_name pydicom/tests/test_dataset.py::TestDataset::test_set_non_dicom pydicom/tests/test_dataset.py::TestDataset::test_get_from_raw pydicom/tests/test_dataset.py::TestDataset::test__setitem__ pydicom/tests/test_dataset.py::TestDataset::test_matching_tags pydicom/tests/test_dataset.py::TestDataset::test_dir_subclass pydicom/tests/test_dataset.py::TestDataset::test_delete_dicom_attr_we_dont_have pydicom/tests/test_dataset.py::TestDataset::test_equality_no_sequence pydicom/tests/test_dataset.py::TestDataset::test_equality_private pydicom/tests/test_dataset.py::TestDataset::test_equality_sequence pydicom/tests/test_dataset.py::TestDataset::test_equality_not_dataset pydicom/tests/test_dataset.py::TestDataset::test_equality_unknown pydicom/tests/test_dataset.py::TestDataset::test_equality_inheritance pydicom/tests/test_dataset.py::TestDataset::test_equality_elements pydicom/tests/test_dataset.py::TestDataset::test_inequality pydicom/tests/test_dataset.py::TestDataset::test_hash pydicom/tests/test_dataset.py::TestDataset::test_property pydicom/tests/test_dataset.py::TestDataset::test_add_repeater_elem_by_keyword pydicom/tests/test_dataset.py::TestDataset::test_setitem_slice_raises pydicom/tests/test_dataset.py::TestDataset::test_getitem_slice_raises pydicom/tests/test_dataset.py::TestDataset::test_empty_slice pydicom/tests/test_dataset.py::TestDataset::test_getitem_slice pydicom/tests/test_dataset.py::TestDataset::test_getitem_slice_ffff pydicom/tests/test_dataset.py::TestDataset::test_delitem_slice pydicom/tests/test_dataset.py::TestDataset::test_group_dataset pydicom/tests/test_dataset.py::TestDataset::test_get_item pydicom/tests/test_dataset.py::TestDataset::test_get_item_slice pydicom/tests/test_dataset.py::TestDataset::test_get_private_item pydicom/tests/test_dataset.py::TestDataset::test_private_block pydicom/tests/test_dataset.py::TestDataset::test_private_creator_from_raw_ds pydicom/tests/test_dataset.py::TestDataset::test_add_known_private_tag pydicom/tests/test_dataset.py::TestDataset::test_add_new_private_tag pydicom/tests/test_dataset.py::TestDataset::test_delete_private_tag pydicom/tests/test_dataset.py::TestDataset::test_private_creators pydicom/tests/test_dataset.py::TestDataset::test_non_contiguous_private_creators pydicom/tests/test_dataset.py::TestDataset::test_create_private_tag_after_removing_all pydicom/tests/test_dataset.py::TestDataset::test_create_private_tag_after_removing_private_creator pydicom/tests/test_dataset.py::TestDataset::test_create_private_tag_after_removing_slice pydicom/tests/test_dataset.py::TestDataset::test_is_original_encoding pydicom/tests/test_dataset.py::TestDataset::test_remove_private_tags pydicom/tests/test_dataset.py::TestDataset::test_data_element pydicom/tests/test_dataset.py::TestDataset::test_iterall pydicom/tests/test_dataset.py::TestDataset::test_save_as pydicom/tests/test_dataset.py::TestDataset::test_save_as_compressed_no_encaps pydicom/tests/test_dataset.py::TestDataset::test_save_as_compressed_encaps pydicom/tests/test_dataset.py::TestDataset::test_save_as_no_pixel_data pydicom/tests/test_dataset.py::TestDataset::test_save_as_no_file_meta pydicom/tests/test_dataset.py::TestDataset::test_save_as_private_transfer_syntax pydicom/tests/test_dataset.py::TestDataset::test_save_as_set_little_implicit_with_tsyntax pydicom/tests/test_dataset.py::TestDataset::test_save_as_undefined pydicom/tests/test_dataset.py::TestDataset::test_save_as_undefined_private pydicom/tests/test_dataset.py::TestDataset::test_save_as_undefined_no_tsyntax pydicom/tests/test_dataset.py::TestDataset::test_with pydicom/tests/test_dataset.py::TestDataset::test_exit_exception pydicom/tests/test_dataset.py::TestDataset::test_pixel_array_already_have pydicom/tests/test_dataset.py::TestDataset::test_pixel_array_id_changed pydicom/tests/test_dataset.py::TestDataset::test_pixel_array_unknown_syntax pydicom/tests/test_dataset.py::TestDataset::test_formatted_lines pydicom/tests/test_dataset.py::TestDataset::test_formatted_lines_known_uid pydicom/tests/test_dataset.py::TestDataset::test_set_convert_private_elem_from_raw pydicom/tests/test_dataset.py::TestDataset::test_top pydicom/tests/test_dataset.py::TestDataset::test_trait_names pydicom/tests/test_dataset.py::TestDataset::test_walk pydicom/tests/test_dataset.py::TestDataset::test_update_with_dataset pydicom/tests/test_dataset.py::TestDatasetElements::test_validate_and_correct_file_meta pydicom/tests/test_dataset.py::TestFileDataset::test_creation_with_container pydicom/tests/test_dataset.py::TestFileDataset::test_works_as_expected_within_numpy_array pydicom/tests/test_dataset.py::TestFileDataset::test_dataset_overrides_all_dict_attributes pydicom/tests/test_dataset.py::TestFileMeta::test_deprecation_warning pydicom/tests/test_dataset.py::TestFileMeta::test_assign_file_meta pydicom/tests/test_dataset.py::TestFileMeta::test_init_file_meta pydicom/tests/test_dataset.py::TestFileMeta::test_set_file_meta pydicom/tests/test_dataset.py::TestFileMeta::test_del_file_meta pydicom/tests/test_dataset.py::TestFileMeta::test_show_file_meta pydicom/tests/test_dataset.py::TestFileMeta::test_copy[copy1] pydicom/tests/test_dataset.py::TestFileMeta::test_copy[deepcopy]
pydicom/dataset.py doc/release_notes/v2.1.0.rst
pydicom/dataset.py doc/release_notes/v2.1.0.rst