prompt: Dataset.to_json_dict can still generate exceptions when suppress_invalid_tags=True
  **Describe the bug**
  I'm using `Dataset.to_json_dict(suppress_invalid_tags=True)` and can live with losing invalid tags.  Unfortunately, I can still trigger an exception with something like  `2.0` in an `IS` field.
  
  **Expected behavior**
  to_json_dict shouldn't throw an error about an invalid tag when `suppress_invalid_tags` is enabled.
  
  My thought was simply to move the `data_element = self[key]` into the try/catch block that's right after it.
  
  **Steps To Reproduce**
  
  Traceback:
  ```
    File "dicom.py", line 143, in create_dict
      json_ds = ds.to_json_dict(suppress_invalid_tags=True)
    File "/usr/lib/python3/dist-packages/pydicom/dataset.py", line 2495, in to_json_dict
      data_element = self[key]
    File "/usr/lib/python3/dist-packages/pydicom/dataset.py", line 939, in __getitem__
      self[tag] = DataElement_from_raw(elem, character_set, self)
    File "/usr/lib/python3/dist-packages/pydicom/dataelem.py", line 859, in DataElement_from_raw
      value = convert_value(vr, raw, encoding)
    File "/usr/lib/python3/dist-packages/pydicom/values.py", line 771, in convert_value
      return converter(byte_string, is_little_endian, num_format)
    File "/usr/lib/python3/dist-packages/pydicom/values.py", line 348, in convert_IS_string
      return MultiString(num_string, valtype=pydicom.valuerep.IS)
    File "/usr/lib/python3/dist-packages/pydicom/valuerep.py", line 1213, in MultiString
      return valtype(splitup[0])
    File "/usr/lib/python3/dist-packages/pydicom/valuerep.py", line 1131, in __new__
      raise TypeError("Could not convert value to integer without loss")
  TypeError: Could not convert value to integer without loss
  ```
  
  **Your environment**
  python 3.7, pydicom 2.3
  
  
  
instance: {"FAIL_TO_PASS": "[\"pydicom/tests/test_json.py::TestDataSetToJson::test_suppress_invalid_tags_with_failed_dataelement\"]", "PASS_TO_PASS": "[\"pydicom/tests/test_json.py::TestPersonName::test_json_pn_from_file\", \"pydicom/tests/test_json.py::TestPersonName::test_pn_components_to_json\", \"pydicom/tests/test_json.py::TestPersonName::test_pn_components_from_json\", \"pydicom/tests/test_json.py::TestPersonName::test_empty_value\", \"pydicom/tests/test_json.py::TestPersonName::test_multi_value_to_json\", \"pydicom/tests/test_json.py::TestPersonName::test_dataelem_from_json\", \"pydicom/tests/test_json.py::TestAT::test_to_json\", \"pydicom/tests/test_json.py::TestAT::test_from_json\", \"pydicom/tests/test_json.py::TestAT::test_invalid_value_in_json\", \"pydicom/tests/test_json.py::TestAT::test_invalid_tag_in_json\", \"pydicom/tests/test_json.py::TestDataSetToJson::test_json_from_dicom_file\", \"pydicom/tests/test_json.py::TestDataSetToJson::test_roundtrip\", \"pydicom/tests/test_json.py::TestDataSetToJson::test_dataset_dumphandler\", \"pydicom/tests/test_json.py::TestDataSetToJson::test_dataelement_dumphandler\", \"pydicom/tests/test_json.py::TestDataSetToJson::test_sort_order\", \"pydicom/tests/test_json.py::TestDataSetToJson::test_suppress_invalid_tags\", \"pydicom/tests/test_json.py::TestSequence::test_nested_sequences\", \"pydicom/tests/test_json.py::TestBinary::test_inline_binary\", \"pydicom/tests/test_json.py::TestBinary::test_invalid_inline_binary\", \"pydicom/tests/test_json.py::TestBinary::test_valid_bulkdata_uri\", \"pydicom/tests/test_json.py::TestBinary::test_invalid_bulkdata_uri\", \"pydicom/tests/test_json.py::TestBinary::test_bulk_data_reader_is_called\", \"pydicom/tests/test_json.py::TestBinary::test_bulk_data_reader_is_called_2\", \"pydicom/tests/test_json.py::TestBinary::test_bulk_data_reader_is_called_within_SQ\", \"pydicom/tests/test_json.py::TestNumeric::test_numeric_values\", \"pydicom/tests/test_json.py::TestNumeric::test_numeric_types\"]", "base_commit": "f8cf45b6c121e5a4bf4a43f71aba3bc64af3db9c", "created_at": "2022-09-20T18:52:53Z", "environment_setup_commit": "a8be738418dee0a2b93c241fbd5e0bc82f4b8680", "hints_text": "", "instance_id": "pydicom__pydicom-1694", "patch": "diff --git a/pydicom/dataset.py b/pydicom/dataset.py\n--- a/pydicom/dataset.py\n+++ b/pydicom/dataset.py\n@@ -2492,8 +2492,8 @@ def to_json_dict(\n         json_dataset = {}\n         for key in self.keys():\n             json_key = '{:08X}'.format(key)\n-            data_element = self[key]\n             try:\n+                data_element = self[key]\n                 json_dataset[json_key] = data_element.to_json_dict(\n                     bulk_data_element_handler=bulk_data_element_handler,\n                     bulk_data_threshold=bulk_data_threshold\n", "problem_statement": "Dataset.to_json_dict can still generate exceptions when suppress_invalid_tags=True\n**Describe the bug**\r\nI'm using `Dataset.to_json_dict(suppress_invalid_tags=True)` and can live with losing invalid tags.  Unfortunately, I can still trigger an exception with something like  `2.0` in an `IS` field.\r\n\r\n**Expected behavior**\r\nto_json_dict shouldn't throw an error about an invalid tag when `suppress_invalid_tags` is enabled.\r\n\r\nMy thought was simply to move the `data_element = self[key]` into the try/catch block that's right after it.\r\n\r\n**Steps To Reproduce**\r\n\r\nTraceback:\r\n```\r\n  File \"dicom.py\", line 143, in create_dict\r\n    json_ds = ds.to_json_dict(suppress_invalid_tags=True)\r\n  File \"/usr/lib/python3/dist-packages/pydicom/dataset.py\", line 2495, in to_json_dict\r\n    data_element = self[key]\r\n  File \"/usr/lib/python3/dist-packages/pydicom/dataset.py\", line 939, in __getitem__\r\n    self[tag] = DataElement_from_raw(elem, character_set, self)\r\n  File \"/usr/lib/python3/dist-packages/pydicom/dataelem.py\", line 859, in DataElement_from_raw\r\n    value = convert_value(vr, raw, encoding)\r\n  File \"/usr/lib/python3/dist-packages/pydicom/values.py\", line 771, in convert_value\r\n    return converter(byte_string, is_little_endian, num_format)\r\n  File \"/usr/lib/python3/dist-packages/pydicom/values.py\", line 348, in convert_IS_string\r\n    return MultiString(num_string, valtype=pydicom.valuerep.IS)\r\n  File \"/usr/lib/python3/dist-packages/pydicom/valuerep.py\", line 1213, in MultiString\r\n    return valtype(splitup[0])\r\n  File \"/usr/lib/python3/dist-packages/pydicom/valuerep.py\", line 1131, in __new__\r\n    raise TypeError(\"Could not convert value to integer without loss\")\r\nTypeError: Could not convert value to integer without loss\r\n```\r\n\r\n**Your environment**\r\npython 3.7, pydicom 2.3\r\n\r\n\n", "repo": "pydicom/pydicom", "test_patch": "diff --git a/pydicom/tests/test_json.py b/pydicom/tests/test_json.py\n--- a/pydicom/tests/test_json.py\n+++ b/pydicom/tests/test_json.py\n@@ -7,7 +7,7 @@\n \n from pydicom import dcmread\n from pydicom.data import get_testdata_file\n-from pydicom.dataelem import DataElement\n+from pydicom.dataelem import DataElement, RawDataElement\n from pydicom.dataset import Dataset\n from pydicom.tag import Tag, BaseTag\n from pydicom.valuerep import PersonName\n@@ -284,7 +284,23 @@ def test_suppress_invalid_tags(self, _):\n \n         ds_json = ds.to_json_dict(suppress_invalid_tags=True)\n \n-        assert ds_json.get(\"00100010\") is None\n+        assert \"00100010\" not in ds_json\n+\n+    def test_suppress_invalid_tags_with_failed_dataelement(self):\n+        \"\"\"Test tags that raise exceptions don't if suppress_invalid_tags True.\n+        \"\"\"\n+        ds = Dataset()\n+        # we have to add a RawDataElement as creating a DataElement would\n+        # already raise an exception\n+        ds[0x00082128] = RawDataElement(\n+            Tag(0x00082128), 'IS', 4, b'5.25', 0, True, True)\n+\n+        with pytest.raises(TypeError):\n+            ds.to_json_dict()\n+\n+        ds_json = ds.to_json_dict(suppress_invalid_tags=True)\n+\n+        assert \"00082128\" not in ds_json\n \n \n class TestSequence:\n", "version": "2.3"}
parsed_commit_content: {"file_diffs":[{"old_file_content":"# Copyright 2008-2021 pydicom authors. See LICENSE file for details.\n\"\"\"Define the Dataset and FileDataset classes.\n\nThe Dataset class represents the DICOM Dataset while the FileDataset class\nadds extra functionality to Dataset when data is read from or written to file.\n\nOverview of DICOM object model\n------------------------------\nDataset (dict subclass)\n  Contains DataElement instances, each of which has a tag, VR, VM and value.\n    The DataElement value can be:\n        * A single value, such as a number, string, etc. (i.e. VM = 1)\n        * A list of numbers, strings, etc. (i.e. VM > 1)\n        * A Sequence (list subclass), where each item is a Dataset which\n            contains its own DataElements, and so on in a recursive manner.\n\"\"\"\nimport copy\nfrom bisect import bisect_left\nimport io\nfrom importlib.util import find_spec as have_package\nimport inspect  # for __dir__\nfrom itertools import takewhile\nimport json\nimport os\nimport os.path\nimport re\nfrom types import TracebackType\nfrom typing import (\n    Optional, Tuple, Union, List, Any, cast, Dict, ValuesView,\n    Iterator, BinaryIO, AnyStr, Callable, TypeVar, Type, overload,\n    MutableSequence, MutableMapping, AbstractSet\n)\nimport warnings\nimport weakref\n\nfrom pydicom.filebase import DicomFileLike\n\ntry:\n    import numpy\nexcept ImportError:\n    pass\n\nimport pydicom  # for dcmwrite\nfrom pydicom import jsonrep, config\nfrom pydicom._version import __version_info__\nfrom pydicom.charset import default_encoding, convert_encodings\nfrom pydicom.config import logger\nfrom pydicom.datadict import (\n    dictionary_VR, tag_for_keyword, keyword_for_tag, repeater_has_keyword\n)\nfrom pydicom.dataelem import DataElement, DataElement_from_raw, RawDataElement\nfrom pydicom.encaps import encapsulate, encapsulate_extended\nfrom pydicom.fileutil import path_from_pathlike, PathType\nfrom pydicom.pixel_data_handlers.util import (\n    convert_color_space, reshape_pixel_array, get_image_pixel_ids\n)\nfrom pydicom.tag import Tag, BaseTag, tag_in_exception, TagType\nfrom pydicom.uid import (\n    ExplicitVRLittleEndian, ImplicitVRLittleEndian, ExplicitVRBigEndian,\n    RLELossless, PYDICOM_IMPLEMENTATION_UID, UID\n)\nfrom pydicom.valuerep import VR as VR_, AMBIGUOUS_VR\nfrom pydicom.waveforms import numpy_handler as wave_handler\n\n\nclass PrivateBlock:\n    \"\"\"Helper class for a private block in the :class:`Dataset`.\n\n    .. versionadded:: 1.3\n\n    See the DICOM Standard, Part 5,\n    :dcm:`Section 7.8.1<part05/sect_7.8.html#sect_7.8.1>` - Private Data\n    Element Tags\n\n    Attributes\n    ----------\n    group : int\n        The private group where the private block is located as a 32-bit\n        :class:`int`.\n    private_creator : str\n        The private creator string related to the block.\n    dataset : Dataset\n        The parent dataset.\n    block_start : int\n        The start element of the private block as a 32-bit :class:`int`. Note\n        that the 2 low order hex digits of the element are always 0.\n    \"\"\"\n\n    def __init__(\n        self,\n        key: Tuple[int, str],\n        dataset: \"Dataset\",\n        private_creator_element: int\n    ) -> None:\n        \"\"\"Initializes an object corresponding to a private tag block.\n\n        Parameters\n        ----------\n        key : tuple\n            The private (tag group, creator) as ``(int, str)``. The group\n            must be an odd number.\n        dataset : Dataset\n            The parent :class:`Dataset`.\n        private_creator_element : int\n            The element of the private creator tag as a 32-bit :class:`int`.\n        \"\"\"\n        self.group = key[0]\n        self.private_creator = key[1]\n        self.dataset = dataset\n        self.block_start = private_creator_element << 8\n\n    def get_tag(self, element_offset: int) -> BaseTag:\n        \"\"\"Return the private tag ID for the given `element_offset`.\n\n        Parameters\n        ----------\n        element_offset : int\n            The lower 16 bits (e.g. 2 hex numbers) of the element tag.\n\n        Returns\n        -------\n            The tag ID defined by the private block location and the\n            given element offset.\n\n        Raises\n        ------\n        ValueError\n            If `element_offset` is too large.\n        \"\"\"\n        if element_offset > 0xff:\n            raise ValueError('Element offset must be less than 256')\n        return Tag(self.group, self.block_start + element_offset)\n\n    def __contains__(self, element_offset: int) -> bool:\n        \"\"\"Return ``True`` if the tag with given `element_offset` is in\n        the parent :class:`Dataset`.\n        \"\"\"\n        return self.get_tag(element_offset) in self.dataset\n\n    def __getitem__(self, element_offset: int) -> DataElement:\n        \"\"\"Return the data element in the parent dataset for the given element\n        offset.\n\n        Parameters\n        ----------\n        element_offset : int\n            The lower 16 bits (e.g. 2 hex numbers) of the element tag.\n\n        Returns\n        -------\n            The data element of the tag in the parent dataset defined by the\n            private block location and the given element offset.\n\n        Raises\n        ------\n        ValueError\n            If `element_offset` is too large.\n        KeyError\n            If no data element exists at that offset.\n        \"\"\"\n        return self.dataset.__getitem__(self.get_tag(element_offset))\n\n    def __delitem__(self, element_offset: int) -> None:\n        \"\"\"Delete the tag with the given `element_offset` from the dataset.\n\n        Parameters\n        ----------\n        element_offset : int\n            The lower 16 bits (e.g. 2 hex numbers) of the element tag\n            to be deleted.\n\n        Raises\n        ------\n        ValueError\n            If `element_offset` is too large.\n        KeyError\n            If no data element exists at that offset.\n        \"\"\"\n        del self.dataset[self.get_tag(element_offset)]\n\n    def add_new(self, element_offset: int, VR: str, value: object) -> None:\n        \"\"\"Add a private element to the parent :class:`Dataset`.\n\n        Adds the private tag with the given `VR` and `value` to the parent\n        :class:`Dataset` at the tag ID defined by the private block and the\n        given `element_offset`.\n\n        Parameters\n        ----------\n        element_offset : int\n            The lower 16 bits (e.g. 2 hex numbers) of the element tag\n            to be added.\n        VR : str\n            The 2 character DICOM value representation.\n        value\n            The value of the data element. See :meth:`Dataset.add_new()`\n            for a description.\n        \"\"\"\n        tag = self.get_tag(element_offset)\n        self.dataset.add_new(tag, VR, value)\n        self.dataset[tag].private_creator = self.private_creator\n\n\ndef _dict_equal(\n    a: \"Dataset\", b: Any, exclude: Optional[List[str]] = None\n) -> bool:\n    \"\"\"Common method for Dataset.__eq__ and FileDataset.__eq__\n\n    Uses .keys() as needed because Dataset iter return items not keys\n    `exclude` is used in FileDataset__eq__ ds.__dict__ compare, which\n    would also compare the wrapped _dict member (entire dataset) again.\n    \"\"\"\n    return (len(a) == len(b) and\n            all(key in b for key in a.keys()) and\n            all(a[key] == b[key] for key in a.keys()\n                if exclude is None or key not in exclude)\n            )\n\n\n_DatasetValue = Union[DataElement, RawDataElement]\n_DatasetType = Union[\"Dataset\", MutableMapping[BaseTag, _DatasetValue]]\n\n\nclass Dataset:\n    \"\"\"A DICOM dataset as a mutable mapping of DICOM Data Elements.\n\n    Examples\n    --------\n    Add an element to the :class:`Dataset` (for elements in the DICOM\n    dictionary):\n\n    >>> ds = Dataset()\n    >>> ds.PatientName = \"CITIZEN^Joan\"\n    >>> ds.add_new(0x00100020, 'LO', '12345')\n    >>> ds[0x0010, 0x0030] = DataElement(0x00100030, 'DA', '20010101')\n\n    Add a sequence element to the :class:`Dataset`\n\n    >>> ds.BeamSequence = [Dataset(), Dataset(), Dataset()]\n    >>> ds.BeamSequence[0].Manufacturer = \"Linac, co.\"\n    >>> ds.BeamSequence[1].Manufacturer = \"Linac and Sons, co.\"\n    >>> ds.BeamSequence[2].Manufacturer = \"Linac and Daughters, co.\"\n\n    Add private elements to the :class:`Dataset`\n\n    >>> block = ds.private_block(0x0041, 'My Creator', create=True)\n    >>> block.add_new(0x01, 'LO', '12345')\n\n    Updating and retrieving element values:\n\n    >>> ds.PatientName = \"CITIZEN^Joan\"\n    >>> ds.PatientName\n    'CITIZEN^Joan'\n    >>> ds.PatientName = \"CITIZEN^John\"\n    >>> ds.PatientName\n    'CITIZEN^John'\n\n    Retrieving an element's value from a Sequence:\n\n    >>> ds.BeamSequence[0].Manufacturer\n    'Linac, co.'\n    >>> ds.BeamSequence[1].Manufacturer\n    'Linac and Sons, co.'\n\n    Accessing the :class:`~pydicom.dataelem.DataElement` items:\n\n    >>> elem = ds['PatientName']\n    >>> elem\n    (0010, 0010) Patient's Name                      PN: 'CITIZEN^John'\n    >>> elem = ds[0x00100010]\n    >>> elem\n    (0010, 0010) Patient's Name                      PN: 'CITIZEN^John'\n    >>> elem = ds.data_element('PatientName')\n    >>> elem\n    (0010, 0010) Patient's Name                      PN: 'CITIZEN^John'\n\n    Accessing a private :class:`~pydicom.dataelem.DataElement`\n    item:\n\n    >>> block = ds.private_block(0x0041, 'My Creator')\n    >>> elem = block[0x01]\n    >>> elem\n    (0041, 1001) Private tag data                    LO: '12345'\n    >>> elem.value\n    '12345'\n\n    Alternatively:\n\n    >>> ds.get_private_item(0x0041, 0x01, 'My Creator').value\n    '12345'\n\n    Deleting an element from the :class:`Dataset`\n\n    >>> del ds.PatientID\n    >>> del ds.BeamSequence[1].Manufacturer\n    >>> del ds.BeamSequence[2]\n\n    Deleting a private element from the :class:`Dataset`\n\n    >>> block = ds.private_block(0x0041, 'My Creator')\n    >>> if 0x01 in block:\n    ...     del block[0x01]\n\n    Determining if an element is present in the :class:`Dataset`\n\n    >>> 'PatientName' in ds\n    True\n    >>> 'PatientID' in ds\n    False\n    >>> (0x0010, 0x0030) in ds\n    True\n    >>> 'Manufacturer' in ds.BeamSequence[0]\n    True\n\n    Iterating through the top level of a :class:`Dataset` only (excluding\n    Sequences):\n\n    >>> for elem in ds:\n    ...    print(elem)\n    (0010, 0010) Patient's Name                      PN: 'CITIZEN^John'\n\n    Iterating through the entire :class:`Dataset` (including Sequences):\n\n    >>> for elem in ds.iterall():\n    ...     print(elem)\n    (0010, 0010) Patient's Name                      PN: 'CITIZEN^John'\n\n    Recursively iterate through a :class:`Dataset` (including Sequences):\n\n    >>> def recurse(ds):\n    ...     for elem in ds:\n    ...         if elem.VR == 'SQ':\n    ...             [recurse(item) for item in elem.value]\n    ...         else:\n    ...             # Do something useful with each DataElement\n\n    Converting the :class:`Dataset` to and from JSON:\n\n    >>> ds = Dataset()\n    >>> ds.PatientName = \"Some^Name\"\n    >>> jsonmodel = ds.to_json()\n    >>> ds2 = Dataset()\n    >>> ds2.from_json(jsonmodel)\n    (0010, 0010) Patient's Name                      PN: 'Some^Name'\n\n    Attributes\n    ----------\n    default_element_format : str\n        The default formatting for string display.\n    default_sequence_element_format : str\n        The default formatting for string display of sequences.\n    indent_chars : str\n        For string display, the characters used to indent nested Sequences.\n        Default is ``\"   \"``.\n    is_little_endian : bool\n        Shall be set before writing with ``write_like_original=False``.\n        The :class:`Dataset` (excluding the pixel data) will be written using\n        the given endianness.\n    is_implicit_VR : bool\n        Shall be set before writing with ``write_like_original=False``.\n        The :class:`Dataset` will be written using the transfer syntax with\n        the given VR handling, e.g *Little Endian Implicit VR* if ``True``,\n        and *Little Endian Explicit VR* or *Big Endian Explicit VR* (depending\n        on ``Dataset.is_little_endian``) if ``False``.\n    \"\"\"\n    indent_chars = \"   \"\n\n    def __init__(self, *args: _DatasetType, **kwargs: Any) -> None:\n        \"\"\"Create a new :class:`Dataset` instance.\"\"\"\n        self._parent_encoding: List[str] = kwargs.get(\n            'parent_encoding', default_encoding\n        )\n\n        self._dict: MutableMapping[BaseTag, _DatasetValue]\n        if not args:\n            self._dict = {}\n        elif isinstance(args[0], Dataset):\n            self._dict = args[0]._dict\n        else:\n            self._dict = args[0]\n\n        self.is_decompressed = False\n\n        # the following read_XXX attributes are used internally to store\n        # the properties of the dataset after read from a file\n        # set depending on the endianness of the read dataset\n        self.read_little_endian: Optional[bool] = None\n        # set depending on the VR handling of the read dataset\n        self.read_implicit_vr: Optional[bool] = None\n        # The dataset's original character set encoding\n        self.read_encoding: Union[None, str, MutableSequence[str]] = None\n\n        self.is_little_endian: Optional[bool] = None\n        self.is_implicit_VR: Optional[bool] = None\n\n        # True if the dataset is a sequence item with undefined length\n        self.is_undefined_length_sequence_item = False\n\n        # the parent data set, if this dataset is a sequence item\n        self.parent: \"Optional[weakref.ReferenceType[Dataset]]\" = None\n\n        # known private creator blocks\n        self._private_blocks: Dict[Tuple[int, str], PrivateBlock] = {}\n\n        self._pixel_array: Optional[\"numpy.ndarray\"] = None\n        self._pixel_id: Dict[str, int] = {}\n\n        self.file_meta: FileMetaDataset\n\n    def __enter__(self) -> \"Dataset\":\n        \"\"\"Method invoked on entry to a with statement.\"\"\"\n        return self\n\n    def __exit__(\n        self,\n        exc_type: Optional[Type[BaseException]],\n        exc_val: Optional[BaseException],\n        exc_tb: Optional[TracebackType]\n    ) -> Optional[bool]:\n        \"\"\"Method invoked on exit from a with statement.\"\"\"\n        # Returning anything other than True will re-raise any exceptions\n        return None\n\n    def add(self, data_element: DataElement) -> None:\n        \"\"\"Add an element to the :class:`Dataset`.\n\n        Equivalent to ``ds[data_element.tag] = data_element``\n\n        Parameters\n        ----------\n        data_element : dataelem.DataElement\n            The :class:`~pydicom.dataelem.DataElement` to add.\n        \"\"\"\n        self[data_element.tag] = data_element\n\n    def add_new(self, tag: TagType, VR: str, value: Any) -> None:\n        \"\"\"Create a new element and add it to the :class:`Dataset`.\n\n        Parameters\n        ----------\n        tag\n            The DICOM (group, element) tag in any form accepted by\n            :func:`~pydicom.tag.Tag` such as ``[0x0010, 0x0010]``,\n            ``(0x10, 0x10)``, ``0x00100010``, etc.\n        VR : str\n            The 2 character DICOM value representation (see DICOM Standard,\n            Part 5, :dcm:`Section 6.2<part05/sect_6.2.html>`).\n        value\n            The value of the data element. One of the following:\n\n            * a single string or number\n            * a :class:`list` or :class:`tuple` with all strings or all numbers\n            * a multi-value string with backslash separator\n            * for a sequence element, an empty :class:`list` or ``list`` of\n              :class:`Dataset`\n        \"\"\"\n        self.add(DataElement(tag, VR, value))\n\n    def __array__(self) -> \"numpy.ndarray\":\n        \"\"\"Support accessing the dataset from a numpy array.\"\"\"\n        return numpy.asarray(self._dict)\n\n    def data_element(self, name: str) -> Optional[DataElement]:\n        \"\"\"Return the element corresponding to the element keyword `name`.\n\n        Parameters\n        ----------\n        name : str\n            A DICOM element keyword.\n\n        Returns\n        -------\n        dataelem.DataElement or None\n            For the given DICOM element `keyword`, return the corresponding\n            :class:`~pydicom.dataelem.DataElement` if present, ``None``\n            otherwise.\n        \"\"\"\n        tag = tag_for_keyword(name)\n        # Test against None as (0000,0000) is a possible tag\n        if tag is not None:\n            return self[tag]\n        return None\n\n    def __contains__(self, name: TagType) -> bool:\n        \"\"\"Simulate dict.__contains__() to handle DICOM keywords.\n\n        Examples\n        --------\n\n        >>> ds = Dataset()\n        >>> ds.SliceLocation = '2'\n        >>> 'SliceLocation' in ds\n        True\n\n        Parameters\n        ----------\n        name : str or int or 2-tuple\n            The element keyword or tag to search for.\n\n        Returns\n        -------\n        bool\n            ``True`` if the corresponding element is in the :class:`Dataset`,\n            ``False`` otherwise.\n        \"\"\"\n        try:\n            return Tag(name) in self._dict\n        except Exception as exc:\n            msg = (\n                f\"Invalid value '{name}' used with the 'in' operator: must be \"\n                \"an element tag as a 2-tuple or int, or an element keyword\"\n            )\n            if isinstance(exc, OverflowError):\n                msg = (\n                    \"Invalid element tag value used with the 'in' operator: \"\n                    \"tags have a maximum value of (0xFFFF, 0xFFFF)\"\n                )\n\n            if config.INVALID_KEY_BEHAVIOR == \"WARN\":\n                warnings.warn(msg)\n            elif config.INVALID_KEY_BEHAVIOR == \"RAISE\":\n                raise ValueError(msg) from exc\n\n        return False\n\n    def decode(self) -> None:\n        \"\"\"Apply character set decoding to the elements in the\n        :class:`Dataset`.\n\n        See DICOM Standard, Part 5,\n        :dcm:`Section 6.1.1<part05/chapter_6.html#sect_6.1.1>`.\n        \"\"\"\n        # Find specific character set. 'ISO_IR 6' is default\n        # May be multi-valued, but let pydicom.charset handle all logic on that\n        dicom_character_set = self._character_set\n\n        # Shortcut to the decode function in pydicom.charset\n        decode_data_element = pydicom.charset.decode_element\n\n        # Callback for walk(), to decode the chr strings if necessary\n        # This simply calls the pydicom.charset.decode_element function\n        def decode_callback(ds: \"Dataset\", data_element: DataElement) -> None:\n            \"\"\"Callback to decode `data_element`.\"\"\"\n            if data_element.VR == VR_.SQ:\n                for dset in data_element.value:\n                    dset._parent_encoding = dicom_character_set\n                    dset.decode()\n            else:\n                decode_data_element(data_element, dicom_character_set)\n\n        self.walk(decode_callback, recursive=False)\n\n    def copy(self) -> \"Dataset\":\n        \"\"\"Return a shallow copy of the dataset.\"\"\"\n        return copy.copy(self)\n\n    def __delattr__(self, name: str) -> None:\n        \"\"\"Intercept requests to delete an attribute by `name`.\n\n        Examples\n        --------\n\n        >>> ds = Dataset()\n        >>> ds.PatientName = 'foo'\n        >>> ds.some_attribute = True\n\n        If `name` is a DICOM keyword - delete the corresponding\n        :class:`~pydicom.dataelem.DataElement`\n\n        >>> del ds.PatientName\n        >>> 'PatientName' in ds\n        False\n\n        If `name` is another attribute - delete it\n\n        >>> del ds.some_attribute\n        >>> hasattr(ds, 'some_attribute')\n        False\n\n        Parameters\n        ----------\n        name : str\n            The keyword for the DICOM element or the class attribute to delete.\n        \"\"\"\n        # First check if a valid DICOM keyword and if we have that data element\n        tag = cast(BaseTag, tag_for_keyword(name))\n        if tag is not None and tag in self._dict:\n            del self._dict[tag]\n        # If not a DICOM name in this dataset, check for regular instance name\n        #   can't do delete directly, that will call __delattr__ again\n        elif name in self.__dict__:\n            del self.__dict__[name]\n        # Not found, raise an error in same style as python does\n        else:\n            raise AttributeError(name)\n\n    def __delitem__(self, key: Union[slice, BaseTag, TagType]) -> None:\n        \"\"\"Intercept requests to delete an attribute by key.\n\n        Examples\n        --------\n        Indexing using :class:`~pydicom.dataelem.DataElement` tag\n\n        >>> ds = Dataset()\n        >>> ds.CommandGroupLength = 100\n        >>> ds.PatientName = 'CITIZEN^Jan'\n        >>> del ds[0x00000000]\n        >>> ds\n        (0010, 0010) Patient's Name                      PN: 'CITIZEN^Jan'\n\n        Slicing using :class:`~pydicom.dataelem.DataElement` tag\n\n        >>> ds = Dataset()\n        >>> ds.CommandGroupLength = 100\n        >>> ds.SOPInstanceUID = '1.2.3'\n        >>> ds.PatientName = 'CITIZEN^Jan'\n        >>> del ds[:0x00100000]\n        >>> ds\n        (0010, 0010) Patient's Name                      PN: 'CITIZEN^Jan'\n\n        Parameters\n        ----------\n        key\n            The key for the attribute to be deleted. If a ``slice`` is used\n            then the tags matching the slice conditions will be deleted.\n        \"\"\"\n        # If passed a slice, delete the corresponding DataElements\n        if isinstance(key, slice):\n            for tag in self._slice_dataset(key.start, key.stop, key.step):\n                del self._dict[tag]\n                # invalidate private blocks in case a private creator is\n                # deleted - will be re-created on next access\n                if self._private_blocks and BaseTag(tag).is_private_creator:\n                    self._private_blocks = {}\n        elif isinstance(key, BaseTag):\n            del self._dict[key]\n            if self._private_blocks and key.is_private_creator:\n                self._private_blocks = {}\n        else:\n            # If not a standard tag, than convert to Tag and try again\n            tag = Tag(key)\n            del self._dict[tag]\n            if self._private_blocks and tag.is_private_creator:\n                self._private_blocks = {}\n\n    def __dir__(self) -> List[str]:\n        \"\"\"Return a list of methods, properties, attributes and element\n        keywords available in the :class:`Dataset`.\n\n        List of attributes is used, for example, in auto-completion in editors\n        or command-line environments.\n        \"\"\"\n        names = set(super().__dir__())\n        keywords = set(self.dir())\n\n        return sorted(names | keywords)\n\n    def dir(self, *filters: str) -> List[str]:\n        \"\"\"Return an alphabetical list of element keywords in the\n        :class:`Dataset`.\n\n        Intended mainly for use in interactive Python sessions. Only lists the\n        element keywords in the current level of the :class:`Dataset` (i.e.\n        the contents of any sequence elements are ignored).\n\n        Parameters\n        ----------\n        filters : str\n            Zero or more string arguments to the function. Used for\n            case-insensitive match to any part of the DICOM keyword.\n\n        Returns\n        -------\n        list of str\n            The matching element keywords in the dataset. If no\n            filters are used then all element keywords are returned.\n        \"\"\"\n        allnames = [keyword_for_tag(tag) for tag in self._dict.keys()]\n        # remove blanks - tags without valid names (e.g. private tags)\n        allnames = [x for x in allnames if x]\n        # Store found names in a dict, so duplicate names appear only once\n        matches = {}\n        for filter_ in filters:\n            filter_ = filter_.lower()\n            match = [x for x in allnames if x.lower().find(filter_) != -1]\n            matches.update({x: 1 for x in match})\n\n        if filters:\n            return sorted(matches.keys())\n\n        return sorted(allnames)\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare `self` and `other` for equality.\n\n        Returns\n        -------\n        bool\n            The result if `self` and `other` are the same class\n        NotImplemented\n            If `other` is not the same class as `self` then returning\n            :class:`NotImplemented` delegates the result to\n            ``superclass.__eq__(subclass)``.\n        \"\"\"\n        # When comparing against self this will be faster\n        if other is self:\n            return True\n\n        if isinstance(other, self.__class__):\n            return _dict_equal(self, other)\n\n        return NotImplemented\n\n    @overload\n    def get(self, key: str, default: Optional[Any] = None) -> Any:\n        pass  # pragma: no cover\n\n    @overload\n    def get(\n        self,\n        key: Union[int, Tuple[int, int], BaseTag],\n        default: Optional[Any] = None\n    ) -> DataElement:\n        pass  # pragma: no cover\n\n    def get(\n        self,\n        key: Union[str, Union[int, Tuple[int, int], BaseTag]],\n        default: Optional[Any] = None\n    ) -> Union[Any, DataElement]:\n        \"\"\"Simulate ``dict.get()`` to handle element tags and keywords.\n\n        Parameters\n        ----------\n        key : str or int or Tuple[int, int] or BaseTag\n            The element keyword or tag or the class attribute name to get.\n        default : obj or None, optional\n            If the element or class attribute is not present, return\n            `default` (default ``None``).\n\n        Returns\n        -------\n        value\n            If `key` is the keyword for an element in the :class:`Dataset`\n            then return the element's value.\n        dataelem.DataElement\n            If `key` is a tag for a element in the :class:`Dataset` then\n            return the :class:`~pydicom.dataelem.DataElement`\n            instance.\n        value\n            If `key` is a class attribute then return its value.\n        \"\"\"\n        if isinstance(key, str):\n            try:\n                return getattr(self, key)\n            except AttributeError:\n                return default\n\n        # is not a string, try to make it into a tag and then hand it\n        # off to the underlying dict\n        try:\n            key = Tag(key)\n        except Exception as exc:\n            raise TypeError(\"Dataset.get key must be a string or tag\") from exc\n\n        try:\n            return self.__getitem__(key)\n        except KeyError:\n            return default\n\n    def items(self) -> AbstractSet[Tuple[BaseTag, _DatasetValue]]:\n        \"\"\"Return the :class:`Dataset` items to simulate :meth:`dict.items`.\n\n        Returns\n        -------\n        dict_items\n            The top-level (:class:`~pydicom.tag.BaseTag`,\n            :class:`~pydicom.dataelem.DataElement`) items for the\n            :class:`Dataset`.\n        \"\"\"\n        return self._dict.items()\n\n    def keys(self) -> AbstractSet[BaseTag]:\n        \"\"\"Return the :class:`Dataset` keys to simulate :meth:`dict.keys`.\n\n        Returns\n        -------\n        dict_keys\n            The :class:`~pydicom.tag.BaseTag` of all the elements in\n            the :class:`Dataset`.\n        \"\"\"\n        return self._dict.keys()\n\n    def values(self) -> ValuesView[_DatasetValue]:\n        \"\"\"Return the :class:`Dataset` values to simulate :meth:`dict.values`.\n\n        Returns\n        -------\n        dict_keys\n            The :class:`DataElements<pydicom.dataelem.DataElement>` that make\n            up the values of the :class:`Dataset`.\n        \"\"\"\n        return self._dict.values()\n\n    def __getattr__(self, name: str) -> Any:\n        \"\"\"Intercept requests for :class:`Dataset` attribute names.\n\n        If `name` matches a DICOM keyword, return the value for the\n        element with the corresponding tag.\n\n        Parameters\n        ----------\n        name : str\n            An element keyword or a class attribute name.\n\n        Returns\n        -------\n        value\n              If `name` matches a DICOM keyword, returns the corresponding\n              element's value. Otherwise returns the class attribute's\n              value (if present).\n        \"\"\"\n        tag = tag_for_keyword(name)\n        if tag is not None:  # `name` isn't a DICOM element keyword\n            tag = Tag(tag)\n            if tag in self._dict:  # DICOM DataElement not in the Dataset\n                return self[tag].value\n\n        # no tag or tag not contained in the dataset\n        if name == '_dict':\n            # special handling for contained dict, needed for pickle\n            return {}\n        # Try the base class attribute getter (fix for issue 332)\n        return object.__getattribute__(self, name)\n\n    @property\n    def _character_set(self) -> List[str]:\n        \"\"\"The character set used to encode text values.\"\"\"\n        char_set = self.get(BaseTag(0x00080005), None)\n        if not char_set:\n            return self._parent_encoding\n\n        return convert_encodings(char_set.value)\n\n    @overload\n    def __getitem__(self, key: slice) -> \"Dataset\":\n        pass  # pragma: no cover\n\n    @overload\n    def __getitem__(self, key: TagType) -> DataElement:\n        pass  # pragma: no cover\n\n    def __getitem__(\n        self, key: Union[slice, TagType]\n    ) -> Union[\"Dataset\", DataElement]:\n        \"\"\"Operator for ``Dataset[key]`` request.\n\n        Any deferred data elements will be read in and an attempt will be made\n        to correct any elements with ambiguous VRs.\n\n        Examples\n        --------\n        Indexing using :class:`~pydicom.dataelem.DataElement` tag\n\n        >>> ds = Dataset()\n        >>> ds.SOPInstanceUID = '1.2.3'\n        >>> ds.PatientName = 'CITIZEN^Jan'\n        >>> ds.PatientID = '12345'\n        >>> ds[0x00100010].value\n        'CITIZEN^Jan'\n\n        Slicing using element tags; all group ``0x0010`` elements in\n        the  dataset\n\n        >>> ds[0x00100000:0x00110000]\n        (0010, 0010) Patient's Name                      PN: 'CITIZEN^Jan'\n        (0010, 0020) Patient ID                          LO: '12345'\n\n        All group ``0x0002`` elements in the dataset\n\n        >>> ds[(0x0002, 0x0000):(0x0003, 0x0000)]\n        <BLANKLINE>\n\n        Parameters\n        ----------\n        key\n            The DICOM (group, element) tag in any form accepted by\n            :func:`~pydicom.tag.Tag` such as ``[0x0010, 0x0010]``,\n            ``(0x10, 0x10)``, ``0x00100010``, etc. May also be a :class:`slice`\n            made up of DICOM tags.\n\n        Returns\n        -------\n        dataelem.DataElement or Dataset\n            If a single DICOM element tag is used then returns the\n            corresponding :class:`~pydicom.dataelem.DataElement`.\n            If a :class:`slice` is used then returns a :class:`Dataset` object\n            containing the corresponding\n            :class:`DataElements<pydicom.dataelem.DataElement>`.\n        \"\"\"\n        # If passed a slice, return a Dataset containing the corresponding\n        #   DataElements\n        if isinstance(key, slice):\n            return self._dataset_slice(key)\n\n        if isinstance(key, BaseTag):\n            tag = key\n        else:\n            try:\n                tag = Tag(key)\n            except Exception as exc:\n                raise KeyError(f\"'{key}'\") from exc\n\n        elem = self._dict[tag]\n        if isinstance(elem, DataElement):\n            if elem.VR == VR_.SQ and elem.value:\n                # let a sequence know its parent dataset, as sequence items\n                # may need parent dataset tags to resolve ambiguous tags\n                elem.value.parent = self\n            return elem\n\n        if isinstance(elem, RawDataElement):\n            # If a deferred read, then go get the value now\n            if elem.value is None and elem.length != 0:\n                from pydicom.filereader import read_deferred_data_element\n\n                elem = read_deferred_data_element(\n                    self.fileobj_type,\n                    self.filename,\n                    self.timestamp,\n                    elem\n                )\n\n            if tag != BaseTag(0x00080005):\n                character_set = self.read_encoding or self._character_set\n            else:\n                character_set = default_encoding\n            # Not converted from raw form read from file yet; do so now\n            self[tag] = DataElement_from_raw(elem, character_set, self)\n\n            # If the Element has an ambiguous VR, try to correct it\n            if self[tag].VR in AMBIGUOUS_VR:\n                from pydicom.filewriter import correct_ambiguous_vr_element\n                self[tag] = correct_ambiguous_vr_element(\n                    self[tag], self, elem[6]\n                )\n\n        return cast(DataElement, self._dict.get(tag))\n\n    def private_block(\n        self, group: int, private_creator: str, create: bool = False\n    ) -> PrivateBlock:\n        \"\"\"Return the block for the given tag `group` and `private_creator`.\n\n        .. versionadded:: 1.3\n\n        If `create` is ``True`` and the `private_creator` does not exist,\n        the private creator tag is added.\n\n        Notes\n        -----\n        We ignore the unrealistic case that no free block is available.\n\n        Parameters\n        ----------\n        group : int\n            The group of the private tag to be found as a 32-bit :class:`int`.\n            Must be an odd number (e.g. a private group).\n        private_creator : str\n            The private creator string associated with the tag.\n        create : bool, optional\n            If ``True`` and `private_creator` does not exist, a new private\n            creator tag is added at the next free block. If ``False``\n            (the default) and `private_creator` does not exist,\n            :class:`KeyError` is raised instead.\n\n        Returns\n        -------\n        PrivateBlock\n            The existing or newly created private block.\n\n        Raises\n        ------\n        ValueError\n            If `group` doesn't belong to a private tag or `private_creator`\n            is empty.\n        KeyError\n            If the private creator tag is not found in the given group and\n            the `create` parameter is ``False``.\n        \"\"\"\n        def new_block(element: int) -> PrivateBlock:\n            block = PrivateBlock(key, self, element)\n            self._private_blocks[key] = block\n            return block\n\n        key = (group, private_creator)\n        if key in self._private_blocks:\n            return self._private_blocks[key]\n\n        if not private_creator:\n            raise ValueError('Private creator must have a value')\n\n        if group % 2 == 0:\n            raise ValueError(\n                'Tag must be private if private creator is given')\n\n        # find block with matching private creator\n        block = self[(group, 0x10):(group, 0x100)]  # type: ignore[misc]\n        data_el = next(\n            (\n                elem for elem in block if elem.value == private_creator\n            ),\n            None\n        )\n        if data_el is not None:\n            return new_block(data_el.tag.element)\n\n        if not create:\n            # not found and shall not be created - raise\n            raise KeyError(\n                \"Private creator '{}' not found\".format(private_creator))\n\n        # private creator not existing - find first unused private block\n        # and add the private creator\n        first_free_el = next(\n            el for el in range(0x10, 0x100)\n            if Tag(group, el) not in self._dict\n        )\n        self.add_new(Tag(group, first_free_el), 'LO', private_creator)\n        return new_block(first_free_el)\n\n    def private_creators(self, group: int) -> List[str]:\n        \"\"\"Return a list of private creator names in the given group.\n\n        .. versionadded:: 1.3\n\n        Examples\n        --------\n        This can be used to check if a given private creator exists in\n        the group of the dataset:\n\n        >>> ds = Dataset()\n        >>> if 'My Creator' in ds.private_creators(0x0041):\n        ...     block = ds.private_block(0x0041, 'My Creator')\n\n        Parameters\n        ----------\n        group : int\n            The private group as a 32-bit :class:`int`. Must be an odd number.\n\n        Returns\n        -------\n        list of str\n            All private creator names for private blocks in the group.\n\n        Raises\n        ------\n        ValueError\n            If `group` is not a private group.\n        \"\"\"\n        if group % 2 == 0:\n            raise ValueError('Group must be an odd number')\n\n        block = self[(group, 0x10):(group, 0x100)]  # type: ignore[misc]\n        return [x.value for x in block]\n\n    def get_private_item(\n        self, group: int, element_offset: int, private_creator: str\n    ) -> DataElement:\n        \"\"\"Return the data element for the given private tag `group`.\n\n        .. versionadded:: 1.3\n\n        This is analogous to ``Dataset.__getitem__()``, but only for private\n        tags. This allows to find the private tag for the correct private\n        creator without the need to add the tag to the private dictionary\n        first.\n\n        Parameters\n        ----------\n        group : int\n            The private tag group where the item is located as a 32-bit int.\n        element_offset : int\n            The lower 16 bits (e.g. 2 hex numbers) of the element tag.\n        private_creator : str\n            The private creator for the tag. Must match the private creator\n            for the tag to be returned.\n\n        Returns\n        -------\n        dataelem.DataElement\n            The corresponding element.\n\n        Raises\n        ------\n        ValueError\n            If `group` is not part of a private tag or `private_creator` is\n            empty.\n        KeyError\n            If the private creator tag is not found in the given group.\n            If the private tag is not found.\n        \"\"\"\n        block = self.private_block(group, private_creator)\n        return self.__getitem__(block.get_tag(element_offset))\n\n    @overload\n    def get_item(self, key: slice) -> \"Dataset\":\n        pass  # pragma: no cover\n\n    @overload\n    def get_item(self, key: TagType) -> DataElement:\n        pass  # pragma: no cover\n\n    def get_item(\n        self, key: Union[slice, TagType]\n    ) -> Union[\"Dataset\", DataElement, RawDataElement, None]:\n        \"\"\"Return the raw data element if possible.\n\n        It will be raw if the user has never accessed the value, or set their\n        own value. Note if the data element is a deferred-read element,\n        then it is read and converted before being returned.\n\n        Parameters\n        ----------\n        key\n            The DICOM (group, element) tag in any form accepted by\n            :func:`~pydicom.tag.Tag` such as ``[0x0010, 0x0010]``,\n            ``(0x10, 0x10)``, ``0x00100010``, etc. May also be a :class:`slice`\n            made up of DICOM tags.\n\n        Returns\n        -------\n        dataelem.DataElement\n            The corresponding element.\n        \"\"\"\n        if isinstance(key, slice):\n            return self._dataset_slice(key)\n\n        elem = self._dict.get(Tag(key))\n        # If a deferred read, return using __getitem__ to read and convert it\n        if isinstance(elem, RawDataElement) and elem.value is None:\n            return self[key]\n\n        return elem\n\n    def _dataset_slice(self, slce: slice) -> \"Dataset\":\n        \"\"\"Return a slice that has the same properties as the original dataset.\n\n        That includes properties related to endianness and VR handling,\n        and the specific character set. No element conversion is done, e.g.\n        elements of type ``RawDataElement`` are kept.\n        \"\"\"\n        tags = self._slice_dataset(slce.start, slce.stop, slce.step)\n        ds = Dataset({tag: self.get_item(tag) for tag in tags})\n        ds.is_little_endian = self.is_little_endian\n        ds.is_implicit_VR = self.is_implicit_VR\n        ds.set_original_encoding(\n            self.read_implicit_vr, self.read_little_endian, self.read_encoding\n        )\n        return ds\n\n    @property\n    def is_original_encoding(self) -> bool:\n        \"\"\"Return ``True`` if the encoding to be used for writing is set and\n        is the same as that used to originally encode the  :class:`Dataset`.\n\n        .. versionadded:: 1.1\n\n        This includes properties related to endianness, VR handling and the\n        (0008,0005) *Specific Character Set*.\n        \"\"\"\n        return (\n            self.is_implicit_VR is not None\n            and self.is_little_endian is not None\n            and self.read_implicit_vr == self.is_implicit_VR\n            and self.read_little_endian == self.is_little_endian\n            and self.read_encoding == self._character_set\n        )\n\n    def set_original_encoding(\n        self,\n        is_implicit_vr: Optional[bool],\n        is_little_endian: Optional[bool],\n        character_encoding: Union[None, str, MutableSequence[str]]\n    ) -> None:\n        \"\"\"Set the values for the original transfer syntax and encoding.\n\n        .. versionadded:: 1.2\n\n        Can be used for a :class:`Dataset` with raw data elements to enable\n        optimized writing (e.g. without decoding the data elements).\n        \"\"\"\n        self.read_implicit_vr = is_implicit_vr\n        self.read_little_endian = is_little_endian\n        self.read_encoding = character_encoding\n\n    def group_dataset(self, group: int) -> \"Dataset\":\n        \"\"\"Return a :class:`Dataset` containing only elements of a certain\n        group.\n\n        Parameters\n        ----------\n        group : int\n            The group part of a DICOM (group, element) tag.\n\n        Returns\n        -------\n        Dataset\n            A :class:`Dataset` containing elements of the group specified.\n        \"\"\"\n        return self[(group, 0x0000):(group + 1, 0x0000)]  # type: ignore[misc]\n\n    def __iter__(self) -> Iterator[DataElement]:\n        \"\"\"Iterate through the top-level of the Dataset, yielding DataElements.\n\n        Examples\n        --------\n\n        >>> ds = Dataset()\n        >>> for elem in ds:\n        ...     print(elem)\n\n        The :class:`DataElements<pydicom.dataelem.DataElement>` are returned in\n        increasing tag value order. Sequence items are returned as a single\n        :class:`~pydicom.dataelem.DataElement`, so it is up\n        to the calling code to recurse into the Sequence items if desired.\n\n        Yields\n        ------\n        dataelem.DataElement\n            The :class:`Dataset`'s\n            :class:`DataElements<pydicom.dataelem.DataElement>`, sorted by\n            increasing tag order.\n        \"\"\"\n        # Note this is different than the underlying dict class,\n        #        which returns the key of the key:value mapping.\n        #   Here the value is returned (but data_element.tag has the key)\n        taglist = sorted(self._dict.keys())\n        for tag in taglist:\n            yield self[tag]\n\n    def elements(self) -> Iterator[DataElement]:\n        \"\"\"Yield the top-level elements of the :class:`Dataset`.\n\n        .. versionadded:: 1.1\n\n        Examples\n        --------\n\n        >>> ds = Dataset()\n        >>> for elem in ds.elements():\n        ...     print(elem)\n\n        The elements are returned in the same way as in\n        ``Dataset.__getitem__()``.\n\n        Yields\n        ------\n        dataelem.DataElement or dataelem.RawDataElement\n            The unconverted elements sorted by increasing tag order.\n        \"\"\"\n        taglist = sorted(self._dict.keys())\n        for tag in taglist:\n            yield self.get_item(tag)\n\n    def __len__(self) -> int:\n        \"\"\"Return the number of elements in the top level of the dataset.\"\"\"\n        return len(self._dict)\n\n    def __ne__(self, other: Any) -> bool:\n        \"\"\"Compare `self` and `other` for inequality.\"\"\"\n        return not self == other\n\n    def clear(self) -> None:\n        \"\"\"Delete all the elements from the :class:`Dataset`.\"\"\"\n        self._dict.clear()\n\n    def pop(self, key: Union[BaseTag, TagType], *args: Any) -> _DatasetValue:\n        \"\"\"Emulate :meth:`dict.pop` with support for tags and keywords.\n\n        Removes the element for `key` if it exists and returns it,\n        otherwise returns a default value if given or raises :class:`KeyError`.\n\n        Parameters\n        ----------\n        key : int or str or 2-tuple\n\n            * If :class:`tuple` - the group and element number of the DICOM tag\n            * If :class:`int` - the combined group/element number\n            * If :class:`str` - the DICOM keyword of the tag\n\n        *args : zero or one argument\n            Defines the behavior if no tag exists for `key`: if given,\n            it defines the return value, if not given, :class:`KeyError` is\n            raised\n\n        Returns\n        -------\n        RawDataElement or DataElement\n            The element for `key` if it exists, or the default value if given.\n\n        Raises\n        ------\n        KeyError\n            If the `key` is not a valid tag or keyword.\n            If the tag does not exist and no default is given.\n        \"\"\"\n        try:\n            key = Tag(key)\n        except Exception:\n            pass\n\n        return self._dict.pop(cast(BaseTag, key), *args)\n\n    def popitem(self) -> Tuple[BaseTag, _DatasetValue]:\n        \"\"\"Emulate :meth:`dict.popitem`.\n\n        Returns\n        -------\n        tuple of (BaseTag, DataElement)\n        \"\"\"\n        return self._dict.popitem()\n\n    def setdefault(\n        self, key: TagType, default: Optional[Any] = None\n    ) -> DataElement:\n        \"\"\"Emulate :meth:`dict.setdefault` with support for tags and keywords.\n\n        Examples\n        --------\n\n        >>> ds = Dataset()\n        >>> elem = ds.setdefault((0x0010, 0x0010), \"Test\")\n        >>> elem\n        (0010, 0010) Patient's Name                      PN: 'Test'\n        >>> elem.value\n        'Test'\n        >>> elem = ds.setdefault('PatientSex',\n        ...     DataElement(0x00100040, 'CS', 'F'))\n        >>> elem.value\n        'F'\n\n        Parameters\n        ----------\n        key : int, str or 2-tuple of int\n\n            * If :class:`tuple` - the group and element number of the DICOM tag\n            * If :class:`int` - the combined group/element number\n            * If :class:`str` - the DICOM keyword of the tag\n        default : pydicom.dataelem.DataElement or object, optional\n            The :class:`~pydicom.dataelem.DataElement` to use with `key`, or\n            the value of the :class:`~pydicom.dataelem.DataElement` to use with\n            `key` (default ``None``).\n\n        Returns\n        -------\n        pydicom.dataelem.DataElement or object\n            The :class:`~pydicom.dataelem.DataElement` for `key`.\n\n        Raises\n        ------\n        ValueError\n            If `key` is not convertible to a valid tag or a known element\n            keyword.\n        KeyError\n            If :attr:`~pydicom.config.settings.reading_validation_mode` is\n             ``RAISE`` and `key` is an unknown non-private tag.\n        \"\"\"\n        tag = Tag(key)\n        if tag in self:\n            return self[tag]\n\n        vr: Union[str, VR_]\n        if not isinstance(default, DataElement):\n            if tag.is_private:\n                vr = VR_.UN\n            else:\n                try:\n                    vr = dictionary_VR(tag)\n                except KeyError:\n                    if (config.settings.writing_validation_mode ==\n                            config.RAISE):\n                        raise KeyError(f\"Unknown DICOM tag {tag}\")\n\n                    vr = VR_.UN\n                    warnings.warn(\n                        f\"Unknown DICOM tag {tag} - setting VR to 'UN'\"\n                    )\n\n            default = DataElement(tag, vr, default)\n\n        self[key] = default\n\n        return default\n\n    def convert_pixel_data(self, handler_name: str = '') -> None:\n        \"\"\"Convert pixel data to a :class:`numpy.ndarray` internally.\n\n        Parameters\n        ----------\n        handler_name : str, optional\n            The name of the pixel handler that shall be used to\n            decode the data. Supported names are: ``'gdcm'``,\n            ``'pillow'``, ``'jpeg_ls'``, ``'rle'``, ``'numpy'`` and\n            ``'pylibjpeg'``. If not used (the default), a matching handler is\n            used from the handlers configured in\n            :attr:`~pydicom.config.pixel_data_handlers`.\n\n        Returns\n        -------\n        None\n            Converted pixel data is stored internally in the dataset.\n\n        Raises\n        ------\n        ValueError\n            If `handler_name` is not a valid handler name.\n        NotImplementedError\n            If the given handler or any handler, if none given, is unable to\n            decompress pixel data with the current transfer syntax\n        RuntimeError\n            If the given handler, or the handler that has been selected if\n            none given, is not available.\n\n        Notes\n        -----\n        If the pixel data is in a compressed image format, the data is\n        decompressed and any related data elements are changed accordingly.\n        \"\"\"\n        # Check if already have converted to a NumPy array\n        # Also check if pixel data has changed. If so, get new NumPy array\n        already_have = True\n        if not hasattr(self, \"_pixel_array\"):\n            already_have = False\n        elif self._pixel_id != get_image_pixel_ids(self):\n            already_have = False\n\n        if already_have:\n            return\n\n        if handler_name:\n            self._convert_pixel_data_using_handler(handler_name)\n        else:\n            self._convert_pixel_data_without_handler()\n\n    def _convert_pixel_data_using_handler(self, name: str) -> None:\n        \"\"\"Convert the pixel data using handler with the given name.\n        See :meth:`~Dataset.convert_pixel_data` for more information.\n        \"\"\"\n        # handle some variations in name\n        handler_name = name.lower()\n        if not handler_name.endswith('_handler'):\n            handler_name += '_handler'\n        if handler_name == 'numpy_handler':\n            handler_name = 'np_handler'\n        if handler_name == 'jpeg_ls_handler':\n            # the name in config differs from the actual handler name\n            # we allow both\n            handler_name = 'jpegls_handler'\n        if not hasattr(pydicom.config, handler_name):\n            raise ValueError(f\"'{name}' is not a known handler name\")\n\n        handler = getattr(pydicom.config, handler_name)\n\n        tsyntax = self.file_meta.TransferSyntaxUID\n        if not handler.supports_transfer_syntax(tsyntax):\n            raise NotImplementedError(\n                \"Unable to decode pixel data with a transfer syntax UID\"\n                f\" of '{tsyntax}' ({tsyntax.name}) using the pixel data \"\n                f\"handler '{name}'. Please see the pydicom documentation for \"\n                \"information on supported transfer syntaxes.\"\n            )\n        if not handler.is_available():\n            raise RuntimeError(\n                f\"The pixel data handler '{name}' is not available on your \"\n                \"system. Please refer to the pydicom documentation for \"\n                \"information on installing needed packages.\"\n            )\n        # if the conversion fails, the exception is propagated up\n        self._do_pixel_data_conversion(handler)\n\n    def _convert_pixel_data_without_handler(self) -> None:\n        \"\"\"Convert the pixel data using the first matching handler.\n        See :meth:`~Dataset.convert_pixel_data` for more information.\n        \"\"\"\n        # Find all possible handlers that support the transfer syntax\n        ts = self.file_meta.TransferSyntaxUID\n        possible_handlers = [\n            hh for hh in pydicom.config.pixel_data_handlers\n            if hh is not None\n            and hh.supports_transfer_syntax(ts)\n        ]\n\n        # No handlers support the transfer syntax\n        if not possible_handlers:\n            raise NotImplementedError(\n                \"Unable to decode pixel data with a transfer syntax UID of \"\n                f\"'{ts}' ({ts.name}) as there are no pixel data \"\n                \"handlers available that support it. Please see the pydicom \"\n                \"documentation for information on supported transfer syntaxes \"\n            )\n\n        # Handlers that both support the transfer syntax and have their\n        #   dependencies met\n        available_handlers = [\n            hh for hh in possible_handlers\n            if hh.is_available()\n        ]\n\n        # There are handlers that support the transfer syntax but none of them\n        #   can be used as missing dependencies\n        if not available_handlers:\n            # For each of the possible handlers we want to find which\n            #   dependencies are missing\n            msg = (\n                \"The following handlers are available to decode the pixel \"\n                \"data however they are missing required dependencies: \"\n            )\n            pkg_msg = []\n            for hh in possible_handlers:\n                hh_deps = hh.DEPENDENCIES\n                # Missing packages\n                missing = [dd for dd in hh_deps if have_package(dd) is None]\n                # Package names\n                names = [hh_deps[name][1] for name in missing]\n                pkg_msg.append(\n                    f\"{hh.HANDLER_NAME} \"\n                    f\"(req. {', '.join(names)})\"\n                )\n\n            raise RuntimeError(msg + ', '.join(pkg_msg))\n\n        last_exception = None\n        for handler in available_handlers:\n            try:\n                self._do_pixel_data_conversion(handler)\n                return\n            except Exception as exc:\n                logger.debug(\n                    \"Exception raised by pixel data handler\", exc_info=exc\n                )\n                last_exception = exc\n\n        # The only way to get to this point is if we failed to get the pixel\n        #   array because all suitable handlers raised exceptions\n        self._pixel_array = None\n        self._pixel_id = {}\n\n        logger.info(\n            \"Unable to decode the pixel data using the following handlers: {}.\"\n            \"Please see the list of supported Transfer Syntaxes in the \"\n            \"pydicom documentation for alternative packages that might \"\n            \"be able to decode the data\"\n            .format(\", \".join([str(hh) for hh in available_handlers]))\n        )\n        raise last_exception  # type: ignore[misc]\n\n    def _do_pixel_data_conversion(self, handler: Any) -> None:\n        \"\"\"Do the actual data conversion using the given handler.\"\"\"\n\n        # Use the handler to get a 1D numpy array of the pixel data\n        # Will raise an exception if no pixel data element\n        arr = handler.get_pixeldata(self)\n        self._pixel_array = reshape_pixel_array(self, arr)\n\n        # Some handler/transfer syntax combinations may need to\n        #   convert the color space from YCbCr to RGB\n        if handler.needs_to_convert_to_RGB(self):\n            self._pixel_array = convert_color_space(\n                self._pixel_array, 'YBR_FULL', 'RGB'\n            )\n\n        self._pixel_id = get_image_pixel_ids(self)\n\n    def compress(\n        self,\n        transfer_syntax_uid: str,\n        arr: Optional[\"numpy.ndarray\"] = None,\n        encoding_plugin: str = '',\n        decoding_plugin: str = '',\n        encapsulate_ext: bool = False,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"Compress and update an uncompressed dataset in-place with the\n        resulting :dcm:`encapsulated<part05/sect_A.4.html>` pixel data.\n\n        .. versionadded:: 2.2\n\n        The dataset must already have the following\n        :dcm:`Image Pixel<part03/sect_C.7.6.3.html>` module elements present\n        with correct values that correspond to the resulting compressed\n        pixel data:\n\n        * (0028,0002) *Samples per Pixel*\n        * (0028,0004) *Photometric Interpretation*\n        * (0028,0008) *Number of Frames* (if more than 1 frame will be present)\n        * (0028,0010) *Rows*\n        * (0028,0011) *Columns*\n        * (0028,0100) *Bits Allocated*\n        * (0028,0101) *Bits Stored*\n        * (0028,0103) *Pixel Representation*\n\n        This method will add the file meta dataset if none is present and add\n        or modify the following elements:\n\n        * (0002,0010) *Transfer Syntax UID*\n        * (7FE0,0010) *Pixel Data*\n\n        If *Samples per Pixel* is greater than 1 then the following element\n        will also be added:\n\n        * (0028,0006) *Planar Configuration*\n\n        If the compressed pixel data is too large for encapsulation using a\n        basic offset table then an :dcm:`extended offset table\n        <part03/sect_C.7.6.3.html>` will also be used, in which case the\n        following elements will also be added:\n\n        * (7FE0,0001) *Extended Offset Table*\n        * (7FE0,0002) *Extended Offset Table Lengths*\n\n        **Supported Transfer Syntax UIDs**\n\n        +----------------------+----------+----------------------------------+\n        | UID                  | Plugins  | Encoding Guide                   |\n        +======================+==========+==================================+\n        | *RLE Lossless* -     |pydicom,  | :doc:`RLE Lossless               |\n        | 1.2.840.10008.1.2.5  |pylibjpeg,| </guides/encoding/rle_lossless>` |\n        |                      |gdcm      |                                  |\n        +----------------------+----------+----------------------------------+\n\n        Examples\n        --------\n\n        Compress the existing uncompressed *Pixel Data* in place:\n\n        >>> from pydicom.data import get_testdata_file\n        >>> from pydicom.uid import RLELossless\n        >>> ds = get_testdata_file(\"CT_small.dcm\", read=True)\n        >>> ds.compress(RLELossless)\n        >>> ds.save_as(\"CT_small_rle.dcm\")\n\n        Parameters\n        ----------\n        transfer_syntax_uid : pydicom.uid.UID\n            The UID of the :dcm:`transfer syntax<part05/chapter_10.html>` to\n            use when compressing the pixel data.\n        arr : numpy.ndarray, optional\n            Compress the uncompressed pixel data in `arr` and use it\n            to set the *Pixel Data*. If `arr` is not used then the\n            existing *Pixel Data* in the dataset will be compressed instead.\n            The :attr:`~numpy.ndarray.shape`, :class:`~numpy.dtype` and\n            contents of the array should match the dataset.\n        encoding_plugin : str, optional\n            Use the `encoding_plugin` to compress the pixel data. See the\n            :doc:`user guide </old/image_data_compression>` for a list of\n            plugins available for each UID and their dependencies. If not\n            specified then all available plugins will be tried (default).\n        decoding_plugin : str, optional\n            Placeholder for future functionality.\n        encapsulate_ext : bool, optional\n            If ``True`` then force the addition of an extended offset table.\n            If ``False`` (default) then an extended offset table\n            will be added if needed for large amounts of compressed *Pixel\n            Data*, otherwise just the basic offset table will be used.\n        **kwargs\n            Optional keyword parameters for the encoding plugin may also be\n            present. See the :doc:`encoding plugins options\n            </guides/encoding/encoder_plugin_options>` for more information.\n        \"\"\"\n        from pydicom.encoders import get_encoder\n\n        uid = UID(transfer_syntax_uid)\n\n        # Raises NotImplementedError if `uid` is not supported\n        encoder = get_encoder(uid)\n        if not encoder.is_available:\n            missing = \"\\n\".join(\n                [f\"    {s}\" for s in encoder.missing_dependencies]\n            )\n            raise RuntimeError(\n                f\"The '{uid.name}' encoder is unavailable because its \"\n                f\"encoding plugins are missing dependencies:\\n\"\n                f\"{missing}\"\n            )\n\n        if arr is None:\n            # Encode the current *Pixel Data*\n            frame_iterator = encoder.iter_encode(\n                self,\n                encoding_plugin=encoding_plugin,\n                decoding_plugin=decoding_plugin,\n                **kwargs\n            )\n        else:\n            # Encode from an uncompressed pixel data array\n            kwargs.update(encoder.kwargs_from_ds(self))\n            frame_iterator = encoder.iter_encode(\n                arr,\n                encoding_plugin=encoding_plugin,\n                **kwargs\n            )\n\n        # Encode!\n        encoded = [f for f in frame_iterator]\n\n        # Encapsulate the encoded *Pixel Data*\n        nr_frames = getattr(self, \"NumberOfFrames\", 1) or 1\n        total = (nr_frames - 1) * 8 + sum([len(f) for f in encoded[:-1]])\n        if encapsulate_ext or total > 2**32 - 1:\n            (self.PixelData,\n             self.ExtendedOffsetTable,\n             self.ExtendedOffsetTableLengths) = encapsulate_extended(encoded)\n        else:\n            self.PixelData = encapsulate(encoded)\n\n        # PS3.5 Annex A.4 - encapsulated pixel data uses undefined length\n        self['PixelData'].is_undefined_length = True\n\n        # PS3.5 Annex A.4 - encapsulated datasets use explicit VR little endian\n        self.is_implicit_VR = False\n        self.is_little_endian = True\n\n        # Set the correct *Transfer Syntax UID*\n        if not hasattr(self, 'file_meta'):\n            self.file_meta = FileMetaDataset()\n\n        self.file_meta.TransferSyntaxUID = uid\n\n        # Add or update any other required elements\n        if self.SamplesPerPixel > 1:\n            self.PlanarConfiguration: int = 1 if uid == RLELossless else 0\n\n    def decompress(self, handler_name: str = '') -> None:\n        \"\"\"Decompresses *Pixel Data* and modifies the :class:`Dataset`\n        in-place.\n\n        .. versionadded:: 1.4\n\n            The `handler_name` keyword argument was added\n\n        If not a compressed transfer syntax, then pixel data is converted\n        to a :class:`numpy.ndarray` internally, but not returned.\n\n        If compressed pixel data, then is decompressed using an image handler,\n        and internal state is updated appropriately:\n\n        - ``Dataset.file_meta.TransferSyntaxUID`` is updated to non-compressed\n          form\n        - :attr:`~pydicom.dataelem.DataElement.is_undefined_length`\n          is ``False`` for the (7FE0,0010) *Pixel Data* element.\n\n        .. versionchanged:: 1.4\n\n            The `handler_name` keyword argument was added\n\n        Parameters\n        ----------\n        handler_name : str, optional\n            The name of the pixel handler that shall be used to\n            decode the data. Supported names are: ``'gdcm'``,\n            ``'pillow'``, ``'jpeg_ls'``, ``'rle'``, ``'numpy'`` and\n            ``'pylibjpeg'``.\n            If not used (the default), a matching handler is used from the\n            handlers configured in :attr:`~pydicom.config.pixel_data_handlers`.\n\n        Returns\n        -------\n        None\n\n        Raises\n        ------\n        NotImplementedError\n            If the pixel data was originally compressed but file is not\n            *Explicit VR Little Endian* as required by the DICOM Standard.\n        \"\"\"\n        self.convert_pixel_data(handler_name)\n        self.is_decompressed = True\n        # May have been undefined length pixel data, but won't be now\n        if 'PixelData' in self:\n            self[0x7fe00010].is_undefined_length = False\n\n        # Make sure correct Transfer Syntax is set\n        # According to the dicom standard PS3.5 section A.4,\n        # all compressed files must have been explicit VR, little endian\n        # First check if was a compressed file\n        if (\n            hasattr(self, 'file_meta')\n            and self.file_meta.TransferSyntaxUID.is_compressed\n        ):\n            # Check that current file as read does match expected\n            if not self.is_little_endian or self.is_implicit_VR:\n                msg = (\"Current dataset does not match expected ExplicitVR \"\n                       \"LittleEndian transfer syntax from a compressed \"\n                       \"transfer syntax\")\n                raise NotImplementedError(msg)\n\n            # All is as expected, updated the Transfer Syntax\n            self.file_meta.TransferSyntaxUID = ExplicitVRLittleEndian\n\n    def overlay_array(self, group: int) -> \"numpy.ndarray\":\n        \"\"\"Return the *Overlay Data* in `group` as a :class:`numpy.ndarray`.\n\n        .. versionadded:: 1.4\n\n        Parameters\n        ----------\n        group : int\n            The group number of the overlay data.\n\n        Returns\n        -------\n        numpy.ndarray\n            The (`group`,3000) *Overlay Data* converted to a\n            :class:`numpy.ndarray`.\n        \"\"\"\n        if group < 0x6000 or group > 0x60FF:\n            raise ValueError(\n                \"The group part of the 'Overlay Data' element tag must be \"\n                \"between 0x6000 and 0x60FF (inclusive)\"\n            )\n\n        from pydicom.config import overlay_data_handlers\n\n        available_handlers = [\n            hh for hh in overlay_data_handlers\n            if hh.is_available()\n        ]\n        if not available_handlers:\n            # For each of the handlers we want to find which\n            #   dependencies are missing\n            msg = (\n                \"The following handlers are available to decode the overlay \"\n                \"data however they are missing required dependencies: \"\n            )\n            pkg_msg = []\n            for hh in overlay_data_handlers:\n                hh_deps = hh.DEPENDENCIES\n                # Missing packages\n                missing = [dd for dd in hh_deps if have_package(dd) is None]\n                # Package names\n                names = [hh_deps[name][1] for name in missing]\n                pkg_msg.append(\n                    f\"{hh.HANDLER_NAME} \"\n                    f\"(req. {', '.join(names)})\"\n                )\n\n            raise RuntimeError(msg + ', '.join(pkg_msg))\n\n        last_exception = None\n        for handler in available_handlers:\n            try:\n                # Use the handler to get an ndarray of the pixel data\n                func = handler.get_overlay_array\n                return cast(\"numpy.ndarray\", func(self, group))\n            except Exception as exc:\n                logger.debug(\n                    \"Exception raised by overlay data handler\", exc_info=exc\n                )\n                last_exception = exc\n\n        logger.info(\n            \"Unable to decode the overlay data using the following handlers: \"\n            \"{}. Please see the list of supported Transfer Syntaxes in the \"\n            \"pydicom documentation for alternative packages that might \"\n            \"be able to decode the data\"\n            .format(\", \".join([str(hh) for hh in available_handlers]))\n        )\n\n        raise last_exception  # type: ignore[misc]\n\n    @property\n    def pixel_array(self) -> \"numpy.ndarray\":\n        \"\"\"Return the pixel data as a :class:`numpy.ndarray`.\n\n        .. versionchanged:: 1.4\n\n            Added support for *Float Pixel Data* and *Double Float Pixel Data*\n\n        Returns\n        -------\n        numpy.ndarray\n            The (7FE0,0008) *Float Pixel Data*, (7FE0,0009) *Double Float\n            Pixel Data* or (7FE0,0010) *Pixel Data* converted to a\n            :class:`numpy.ndarray`.\n        \"\"\"\n        self.convert_pixel_data()\n        return cast(\"numpy.ndarray\", self._pixel_array)\n\n    def waveform_array(self, index: int) -> \"numpy.ndarray\":\n        \"\"\"Return an :class:`~numpy.ndarray` for the multiplex group at\n        `index` in the (5400,0100) *Waveform Sequence*.\n\n        .. versionadded:: 2.1\n\n        Parameters\n        ----------\n        index : int\n            The index of the multiplex group to return the array for.\n\n        Returns\n        ------\n        numpy.ndarray\n            The *Waveform Data* for the multiplex group as an\n            :class:`~numpy.ndarray` with shape (samples, channels). If\n            (003A,0210) *Channel Sensitivity* is present\n            then the values will be in the units specified by the (003A,0211)\n            *Channel Sensitivity Units Sequence*.\n\n        See Also\n        --------\n        :func:`~pydicom.waveforms.numpy_handler.generate_multiplex`\n        :func:`~pydicom.waveforms.numpy_handler.multiplex_array`\n        \"\"\"\n        if not wave_handler.is_available():\n            raise RuntimeError(\"The waveform data handler requires numpy\")\n\n        return wave_handler.multiplex_array(self, index, as_raw=False)\n\n    # Format strings spec'd according to python string formatting options\n    #    See http://docs.python.org/library/stdtypes.html#string-formatting-operations # noqa\n    default_element_format = \"%(tag)s %(name)-35.35s %(VR)s: %(repval)s\"\n    default_sequence_element_format = \"%(tag)s %(name)-35.35s %(VR)s: %(repval)s\"  # noqa\n\n    def formatted_lines(\n        self,\n        element_format: str = default_element_format,\n        sequence_element_format: str = default_sequence_element_format,\n        indent_format: Optional[str] = None\n    ) -> Iterator[str]:\n        \"\"\"Iterate through the :class:`Dataset` yielding formatted :class:`str`\n        for each element.\n\n        Parameters\n        ----------\n        element_format : str\n            The string format to use for non-sequence elements. Formatting uses\n            the attributes of\n            :class:`~pydicom.dataelem.DataElement`. Default is\n            ``\"%(tag)s %(name)-35.35s %(VR)s: %(repval)s\"``.\n        sequence_element_format : str\n            The string format to use for sequence elements. Formatting uses\n            the attributes of\n            :class:`~pydicom.dataelem.DataElement`. Default is\n            ``\"%(tag)s %(name)-35.35s %(VR)s: %(repval)s\"``\n        indent_format : str or None\n            Placeholder for future functionality.\n\n        Yields\n        ------\n        str\n            A string representation of an element.\n        \"\"\"\n        exclusion = (\n            'from_json', 'to_json', 'to_json_dict', 'clear', 'description',\n            'validate',\n        )\n        for elem in self.iterall():\n            # Get all the attributes possible for this data element (e.g.\n            #   gets descriptive text name too)\n            # This is the dictionary of names that can be used in the format\n            #   string\n            elem_dict = {\n                attr: (\n                    getattr(elem, attr)() if callable(getattr(elem, attr))\n                    else getattr(elem, attr)\n                )\n                for attr in dir(elem) if not attr.startswith(\"_\")\n                and attr not in exclusion\n            }\n            if elem.VR == VR_.SQ:\n                yield sequence_element_format % elem_dict\n            else:\n                yield element_format % elem_dict\n\n    def _pretty_str(\n        self, indent: int = 0, top_level_only: bool = False\n    ) -> str:\n        \"\"\"Return a string of the DataElements in the Dataset, with indented\n        levels.\n\n        This private method is called by the ``__str__()`` method for handling\n        print statements or ``str(dataset)``, and the ``__repr__()`` method.\n        It is also used by ``top()``, therefore the `top_level_only` flag.\n        This function recurses, with increasing indentation levels.\n\n        ..versionchanged:: 2.0\n\n            The file meta information is returned in its own section,\n            if :data:`~pydicom.config.show_file_meta` is ``True`` (default)\n\n        Parameters\n        ----------\n        indent : int, optional\n            The indent level offset (default ``0``).\n        top_level_only : bool, optional\n            When True, only create a string for the top level elements, i.e.\n            exclude elements within any Sequences (default ``False``).\n\n        Returns\n        -------\n        str\n            A string representation of the Dataset.\n        \"\"\"\n        strings = []\n        indent_str = self.indent_chars * indent\n        nextindent_str = self.indent_chars * (indent + 1)\n\n        # Display file meta, if configured to do so, and have a non-empty one\n        if (\n            hasattr(self, \"file_meta\") and self.file_meta\n            and pydicom.config.show_file_meta\n        ):\n            strings.append(f\"{'Dataset.file_meta ':-<49}\")\n            for elem in self.file_meta:\n                with tag_in_exception(elem.tag):\n                    strings.append(indent_str + repr(elem))\n            strings.append(f\"{'':-<49}\")\n\n        for elem in self:\n            with tag_in_exception(elem.tag):\n                if elem.VR == VR_.SQ:  # a sequence\n                    strings.append(\n                        f\"{indent_str}{str(elem.tag)}  {elem.name}  \"\n                        f\"{len(elem.value)} item(s) ---- \"\n                    )\n                    if not top_level_only:\n                        for dataset in elem.value:\n                            strings.append(dataset._pretty_str(indent + 1))\n                            strings.append(nextindent_str + \"---------\")\n                else:\n                    strings.append(indent_str + repr(elem))\n        return \"\\n\".join(strings)\n\n    def remove_private_tags(self) -> None:\n        \"\"\"Remove all private elements from the :class:`Dataset`.\"\"\"\n\n        def remove_callback(dataset: \"Dataset\", elem: DataElement) -> None:\n            \"\"\"Internal method to use as callback to walk() method.\"\"\"\n            if elem.tag.is_private:\n                # can't del self[tag] - won't be right dataset on recursion\n                del dataset[elem.tag]\n\n        self.walk(remove_callback)\n\n    def save_as(\n        self,\n        filename: Union[str, \"os.PathLike[AnyStr]\", BinaryIO],\n        write_like_original: bool = True\n    ) -> None:\n        \"\"\"Write the :class:`Dataset` to `filename`.\n\n        Wrapper for pydicom.filewriter.dcmwrite, passing this dataset to it.\n        See documentation for that function for details.\n\n        See Also\n        --------\n        pydicom.filewriter.dcmwrite\n            Write a DICOM file from a :class:`FileDataset` instance.\n        \"\"\"\n        pydicom.dcmwrite(filename, self, write_like_original)\n\n    def ensure_file_meta(self) -> None:\n        \"\"\"Create an empty ``Dataset.file_meta`` if none exists.\n\n        .. versionadded:: 1.2\n        \"\"\"\n        # Changed in v2.0 so does not re-assign self.file_meta with getattr()\n        if not hasattr(self, \"file_meta\"):\n            self.file_meta = FileMetaDataset()\n\n    def fix_meta_info(self, enforce_standard: bool = True) -> None:\n        \"\"\"Ensure the file meta info exists and has the correct values\n        for transfer syntax and media storage UIDs.\n\n        .. versionadded:: 1.2\n\n        .. warning::\n\n            The transfer syntax for ``is_implicit_VR = False`` and\n            ``is_little_endian = True`` is ambiguous and will therefore not\n            be set.\n\n        Parameters\n        ----------\n        enforce_standard : bool, optional\n            If ``True``, a check for incorrect and missing elements is\n            performed (see :func:`~validate_file_meta`).\n        \"\"\"\n        self.ensure_file_meta()\n\n        if self.is_little_endian and self.is_implicit_VR:\n            self.file_meta.TransferSyntaxUID = ImplicitVRLittleEndian\n        elif not self.is_little_endian and not self.is_implicit_VR:\n            self.file_meta.TransferSyntaxUID = ExplicitVRBigEndian\n        elif not self.is_little_endian and self.is_implicit_VR:\n            raise NotImplementedError(\"Implicit VR Big Endian is not a \"\n                                      \"supported Transfer Syntax.\")\n\n        if 'SOPClassUID' in self:\n            self.file_meta.MediaStorageSOPClassUID = self.SOPClassUID\n        if 'SOPInstanceUID' in self:\n            self.file_meta.MediaStorageSOPInstanceUID = self.SOPInstanceUID\n        if enforce_standard:\n            validate_file_meta(self.file_meta, enforce_standard=True)\n\n    def __setattr__(self, name: str, value: Any) -> None:\n        \"\"\"Intercept any attempts to set a value for an instance attribute.\n\n        If name is a DICOM keyword, set the corresponding tag and DataElement.\n        Else, set an instance (python) attribute as any other class would do.\n\n        Parameters\n        ----------\n        name : str\n            The keyword for the element you wish to add/change. If\n            `name` is not a DICOM element keyword then this will be the\n            name of the attribute to be added/changed.\n        value\n            The value for the attribute to be added/changed.\n        \"\"\"\n        tag = tag_for_keyword(name)\n        if tag is not None:  # successfully mapped name to a tag\n            if tag not in self:\n                # don't have this tag yet->create the data_element instance\n                vr = dictionary_VR(tag)\n                data_element = DataElement(tag, vr, value)\n                if vr == VR_.SQ:\n                    # let a sequence know its parent dataset to pass it\n                    # to its items, who may need parent dataset tags\n                    # to resolve ambiguous tags\n                    data_element.parent = self\n            else:\n                # already have this data_element, just changing its value\n                data_element = self[tag]\n                data_element.value = value\n            # Now have data_element - store it in this dict\n            self[tag] = data_element\n        elif repeater_has_keyword(name):\n            # Check if `name` is repeaters element\n            raise ValueError(\n                f\"'{name}' is a DICOM repeating group element and must be \"\n                \"added using the add() or add_new() methods.\"\n            )\n        elif name == \"file_meta\":\n            self._set_file_meta(value)\n        else:\n            # Warn if `name` is camel case but not a keyword\n            if _RE_CAMEL_CASE.match(name):\n                msg = (\n                    f\"Camel case attribute '{name}' used which is not in the \"\n                    \"element keyword data dictionary\"\n                )\n                if config.INVALID_KEYWORD_BEHAVIOR == \"WARN\":\n                    warnings.warn(msg)\n                elif config.INVALID_KEYWORD_BEHAVIOR == \"RAISE\":\n                    raise ValueError(msg)\n\n            # name not in dicom dictionary - setting a non-dicom instance\n            # attribute\n            # XXX note if user mis-spells a dicom data_element - no error!!!\n            object.__setattr__(self, name, value)\n\n    def _set_file_meta(self, value: Optional[\"Dataset\"]) -> None:\n        if value is not None and not isinstance(value, FileMetaDataset):\n            if config._use_future:\n                raise TypeError(\n                    \"Pydicom Future: Dataset.file_meta must be an instance \"\n                    \"of FileMetaDataset\"\n                )\n\n            FileMetaDataset.validate(value)\n            warnings.warn(\n                \"Starting in pydicom 3.0, Dataset.file_meta must be a \"\n                \"FileMetaDataset class instance\",\n                DeprecationWarning\n            )\n\n        self.__dict__[\"file_meta\"] = value\n\n    def __setitem__(\n        self, key: Union[slice, TagType], elem: _DatasetValue\n    ) -> None:\n        \"\"\"Operator for ``Dataset[key] = elem``.\n\n        Parameters\n        ----------\n        key : int or Tuple[int, int] or str\n            The tag for the element to be added to the :class:`Dataset`.\n        elem : dataelem.DataElement or dataelem.RawDataElement\n            The element to add to the :class:`Dataset`.\n\n        Raises\n        ------\n        NotImplementedError\n            If `key` is a :class:`slice`.\n        ValueError\n            If the `key` value doesn't match the corresponding\n            :attr:`DataElement.tag<pydicom.dataelem.tag>`.\n        \"\"\"\n        if isinstance(key, slice):\n            raise NotImplementedError(\n                'Slicing is not supported when setting Dataset items'\n            )\n\n        try:\n            key = Tag(key)\n        except Exception as exc:\n            raise ValueError(\n                f\"Unable to convert the key '{key}' to an element tag\"\n            ) from exc\n\n        if not isinstance(elem, (DataElement, RawDataElement)):\n            raise TypeError(\"Dataset items must be 'DataElement' instances\")\n\n        if isinstance(elem.tag, BaseTag):\n            elem_tag = elem.tag\n        else:\n            elem_tag = Tag(elem.tag)\n\n        if key != elem_tag:\n            raise ValueError(\n                f\"The key '{key}' doesn't match the 'DataElement' tag \"\n                f\"'{elem_tag}'\"\n            )\n\n        if elem_tag.is_private:\n            # See PS 3.5-2008 section 7.8.1 (p. 44) for how blocks are reserved\n            logger.debug(f\"Setting private tag {elem_tag}\")\n            private_block = elem_tag.element >> 8\n            private_creator_tag = Tag(elem_tag.group, private_block)\n            if private_creator_tag in self and elem_tag != private_creator_tag:\n                if isinstance(elem, RawDataElement):\n                    elem = DataElement_from_raw(\n                        elem, self._character_set, self\n                    )\n                elem.private_creator = self[private_creator_tag].value\n\n        self._dict[elem_tag] = elem\n\n    def _slice_dataset(\n        self,\n        start: Optional[TagType],\n        stop: Optional[TagType],\n        step: Optional[int]\n    ) -> List[BaseTag]:\n        \"\"\"Return the element tags in the Dataset that match the slice.\n\n        Parameters\n        ----------\n        start : int or 2-tuple of int or None\n            The slice's starting element tag value, in any format accepted by\n            :func:`~pydicom.tag.Tag`.\n        stop : int or 2-tuple of int or None\n            The slice's stopping element tag value, in any format accepted by\n            :func:`~pydicom.tag.Tag`.\n        step : int or None\n            The slice's step size.\n\n        Returns\n        ------\n        list of BaseTag\n            The tags in the :class:`Dataset` that meet the conditions of the\n            slice.\n        \"\"\"\n        # Check the starting/stopping Tags are valid when used\n        if start is not None:\n            start = Tag(start)\n        if stop is not None:\n            stop = Tag(stop)\n\n        all_tags = sorted(self._dict.keys())\n        # If the Dataset is empty, return an empty list\n        if not all_tags:\n            return []\n\n        # Special case the common situations:\n        #   - start and/or stop are None\n        #   - step is 1\n\n        if start is None:\n            if stop is None:\n                # For step=1 avoid copying the list\n                return all_tags if step == 1 else all_tags[::step]\n            else:  # Have a stop value, get values until that point\n                step1_list = list(takewhile(lambda x: x < stop, all_tags))\n                return step1_list if step == 1 else step1_list[::step]\n\n        # Have a non-None start value.  Find its index\n        i_start = bisect_left(all_tags, start)\n        if stop is None:\n            return all_tags[i_start::step]\n\n        i_stop = bisect_left(all_tags, stop)\n        return all_tags[i_start:i_stop:step]\n\n    def __str__(self) -> str:\n        \"\"\"Handle str(dataset).\n\n        ..versionchanged:: 2.0\n\n            The file meta information was added in its own section,\n            if :data:`pydicom.config.show_file_meta` is ``True``\n\n        \"\"\"\n        return self._pretty_str()\n\n    def top(self) -> str:\n        \"\"\"Return a :class:`str` representation of the top level elements. \"\"\"\n        return self._pretty_str(top_level_only=True)\n\n    def trait_names(self) -> List[str]:\n        \"\"\"Return a :class:`list` of valid names for auto-completion code.\n\n        Used in IPython, so that data element names can be found and offered\n        for autocompletion on the IPython command line.\n        \"\"\"\n        return dir(self)\n\n    def update(self, d: _DatasetType) -> None:\n        \"\"\"Extend :meth:`dict.update` to handle DICOM tags and keywords.\n\n        Parameters\n        ----------\n        d : dict or Dataset\n            The :class:`dict` or :class:`Dataset` to use when updating the\n            current object.\n        \"\"\"\n        for key, value in list(d.items()):\n            if isinstance(key, str):\n                setattr(self, key, value)\n            else:\n                self[Tag(cast(int, key))] = value\n\n    def iterall(self) -> Iterator[DataElement]:\n        \"\"\"Iterate through the :class:`Dataset`, yielding all the elements.\n\n        Unlike ``iter(Dataset)``, this *does* recurse into sequences,\n        and so yields all elements as if dataset were \"flattened\".\n\n        Yields\n        ------\n        dataelem.DataElement\n        \"\"\"\n        for elem in self:\n            yield elem\n            if elem.VR == VR_.SQ:\n                for ds in elem.value:\n                    yield from ds.iterall()\n\n    def walk(\n        self,\n        callback: Callable[[\"Dataset\", DataElement], None],\n        recursive: bool = True\n    ) -> None:\n        \"\"\"Iterate through the :class:`Dataset's<Dataset>` elements and run\n        `callback` on each.\n\n        Visit all elements in the :class:`Dataset`, possibly recursing into\n        sequences and their items. The `callback` function is called for each\n        :class:`~pydicom.dataelem.DataElement` (including elements\n        with a VR of 'SQ'). Can be used to perform an operation on certain\n        types of elements.\n\n        For example,\n        :meth:`~Dataset.remove_private_tags` finds all elements with private\n        tags and deletes them.\n\n        The elements will be returned in order of increasing tag number within\n        their current :class:`Dataset`.\n\n        Parameters\n        ----------\n        callback\n            A callable function that takes two arguments:\n\n            * a :class:`Dataset`\n            * a :class:`~pydicom.dataelem.DataElement` belonging\n              to that :class:`Dataset`\n\n        recursive : bool, optional\n            Flag to indicate whether to recurse into sequences (default\n            ``True``).\n        \"\"\"\n        taglist = sorted(self._dict.keys())\n        for tag in taglist:\n\n            with tag_in_exception(tag):\n                data_element = self[tag]\n                callback(self, data_element)  # self = this Dataset\n                # 'tag in self' below needed in case callback deleted\n                # data_element\n                if recursive and tag in self and data_element.VR == VR_.SQ:\n                    sequence = data_element.value\n                    for dataset in sequence:\n                        dataset.walk(callback)\n\n    @classmethod\n    def from_json(\n        cls: Type[\"Dataset\"],\n        json_dataset: Union[Dict[str, Any], str, bytes, bytearray],\n        bulk_data_uri_handler: Optional[\n            Union[\n                Callable[[str, str, str], Union[None, str, int, float, bytes]],\n                Callable[[str], Union[None, str, int, float, bytes]]\n            ]\n        ] = None\n    ) -> \"Dataset\":\n        \"\"\"Return a :class:`Dataset` from a DICOM JSON Model object.\n\n        .. versionadded:: 1.3\n\n        See the DICOM Standard, Part 18, :dcm:`Annex F<part18/chapter_F.html>`.\n\n        Parameters\n        ----------\n        json_dataset : dict, str, bytes or bytearray\n            :class:`dict`, :class:`str`, :class:`bytes` or :class:`bytearray`\n            representing a DICOM Data Set formatted based on the :dcm:`DICOM\n            JSON Model<part18/chapter_F.html>`.\n        bulk_data_uri_handler : callable, optional\n            Callable function that accepts either the tag, vr and\n            \"BulkDataURI\" value or just the \"BulkDataURI\" value of the JSON\n            representation of a data element and returns the actual value of\n            that data element (retrieved via DICOMweb WADO-RS). If no\n            `bulk_data_uri_handler` is specified (default) then the\n            corresponding element will have an \"empty\" value such as\n            ``\"\"``, ``b\"\"`` or ``None`` depending on the `vr` (i.e. the\n            Value Multiplicity will be 0).\n\n        Returns\n        -------\n        Dataset\n        \"\"\"\n        if isinstance(json_dataset, (str, bytes, bytearray)):\n            json_dataset = cast(Dict[str, Any], json.loads(json_dataset))\n\n        dataset = cls()\n        for tag, mapping in json_dataset.items():\n            # `tag` is an element tag in uppercase hex format as a str\n            # `mapping` is Dict[str, Any] and should have keys 'vr' and at most\n            #   one of ('Value', 'BulkDataURI', 'InlineBinary') but may have\n            #   none of those if the element's VM is 0\n            vr = mapping['vr']\n            unique_value_keys = tuple(\n                set(mapping.keys()) & set(jsonrep.JSON_VALUE_KEYS)\n            )\n            if len(unique_value_keys) == 0:\n                value_key = None\n                value = ['']\n            else:\n                value_key = unique_value_keys[0]\n                value = mapping[value_key]\n            data_element = DataElement.from_json(\n                cls, tag, vr, value, value_key, bulk_data_uri_handler\n            )\n            dataset.add(data_element)\n        return dataset\n\n    def to_json_dict(\n        self,\n        bulk_data_threshold: int = 1024,\n        bulk_data_element_handler: Optional[Callable[[DataElement], str]] = None,  # noqa\n        suppress_invalid_tags: bool = False,\n    ) -> Dict[str, Any]:\n        \"\"\"Return a dictionary representation of the :class:`Dataset`\n        conforming to the DICOM JSON Model as described in the DICOM\n        Standard, Part 18, :dcm:`Annex F<part18/chapter_F.html>`.\n\n        .. versionadded:: 1.4\n\n        Parameters\n        ----------\n        bulk_data_threshold : int, optional\n            Threshold for the length of a base64-encoded binary data element\n            above which the element should be considered bulk data and the\n            value provided as a URI rather than included inline (default:\n            ``1024``). Ignored if no bulk data handler is given.\n        bulk_data_element_handler : callable, optional\n            Callable function that accepts a bulk data element and returns a\n            JSON representation of the data element (dictionary including the\n            \"vr\" key and either the \"InlineBinary\" or the \"BulkDataURI\" key).\n        suppress_invalid_tags : bool, optional\n            Flag to specify if errors while serializing tags should be logged\n            and the tag dropped or if the error should be bubbled up.\n\n        Returns\n        -------\n        dict\n            :class:`Dataset` representation based on the DICOM JSON Model.\n        \"\"\"\n        json_dataset = {}\n        for key in self.keys():\n            json_key = '{:08X}'.format(key)\n            data_element = self[key]\n            try:\n                json_dataset[json_key] = data_element.to_json_dict(\n                    bulk_data_element_handler=bulk_data_element_handler,\n                    bulk_data_threshold=bulk_data_threshold\n                )\n            except Exception as exc:\n                logger.error(f\"Error while processing tag {json_key}\")\n                if not suppress_invalid_tags:\n                    raise exc\n\n        return json_dataset\n\n    def to_json(\n        self,\n        bulk_data_threshold: int = 1024,\n        bulk_data_element_handler: Optional[Callable[[DataElement], str]] = None,  # noqa\n        dump_handler: Optional[Callable[[Dict[str, Any]], str]] = None,\n        suppress_invalid_tags: bool = False,\n    ) -> str:\n        \"\"\"Return a JSON representation of the :class:`Dataset`.\n\n        .. versionadded:: 1.3\n\n        See the DICOM Standard, Part 18, :dcm:`Annex F<part18/chapter_F.html>`.\n\n        Parameters\n        ----------\n        bulk_data_threshold : int, optional\n            Threshold for the length of a base64-encoded binary data element\n            above which the element should be considered bulk data and the\n            value provided as a URI rather than included inline (default:\n            ``1024``). Ignored if no bulk data handler is given.\n        bulk_data_element_handler : callable, optional\n            Callable function that accepts a bulk data element and returns a\n            JSON representation of the data element (dictionary including the\n            \"vr\" key and either the \"InlineBinary\" or the \"BulkDataURI\" key).\n        dump_handler : callable, optional\n            Callable function that accepts a :class:`dict` and returns the\n            serialized (dumped) JSON string (by default uses\n            :func:`json.dumps`).\n\n            .. note:\n\n                Make sure to use a dump handler that sorts the keys (see\n                example below) to create DICOM-conformant JSON.\n        suppress_invalid_tags : bool, optional\n            Flag to specify if errors while serializing tags should be logged\n            and the tag dropped or if the error should be bubbled up.\n\n        Returns\n        -------\n        str\n            :class:`Dataset` serialized into a string based on the DICOM JSON\n            Model.\n\n        Examples\n        --------\n        >>> def my_json_dumps(data):\n        ...     return json.dumps(data, indent=4, sort_keys=True)\n        >>> ds.to_json(dump_handler=my_json_dumps)\n        \"\"\"\n        if dump_handler is None:\n            def json_dump(d: Any) -> str:\n                return json.dumps(d, sort_keys=True)\n\n            dump_handler = json_dump\n\n        return dump_handler(\n            self.to_json_dict(\n                bulk_data_threshold,\n                bulk_data_element_handler,\n                suppress_invalid_tags=suppress_invalid_tags\n            )\n        )\n\n    def __getstate__(self) -> Dict[str, Any]:\n        # pickle cannot handle weakref - remove parent\n        d = self.__dict__.copy()\n        del d['parent']\n        return d\n\n    def __setstate__(self, state: Dict[str, Any]) -> None:\n        self.__dict__.update(state)\n        # re-add parent - it will be set to the parent dataset on demand\n        # if the dataset is in a sequence\n        self.__dict__['parent'] = None\n\n    __repr__ = __str__\n\n\n_FileDataset = TypeVar(\"_FileDataset\", bound=\"FileDataset\")\n\n\nclass FileDataset(Dataset):\n    \"\"\"An extension of :class:`Dataset` to make reading and writing to\n    file-like easier.\n\n    Attributes\n    ----------\n    preamble : str or bytes or None\n        The optional DICOM preamble prepended to the :class:`FileDataset`, if\n        available.\n    file_meta : FileMetaDataset or None\n        The Dataset's file meta information as a :class:`FileMetaDataset`,\n        if available (``None`` if not present).\n        Consists of group ``0x0002`` elements.\n    filename : str or None\n        The filename that the :class:`FileDataset` was read from (if read from\n        file) or ``None`` if the filename is not available (if read from a\n        :class:`io.BytesIO` or  similar).\n    fileobj_type\n        The object type of the file-like the :class:`FileDataset` was read\n        from.\n    is_implicit_VR : bool\n        ``True`` if the dataset encoding is implicit VR, ``False`` otherwise.\n    is_little_endian : bool\n        ``True`` if the dataset encoding is little endian byte ordering,\n        ``False`` otherwise.\n    timestamp : float or None\n        The modification time of the file the :class:`FileDataset` was read\n        from, ``None`` if the modification time is not available.\n    \"\"\"\n\n    def __init__(\n        self,\n        filename_or_obj: Union[PathType, BinaryIO, DicomFileLike],\n        dataset: _DatasetType,\n        preamble: Optional[bytes] = None,\n        file_meta: Optional[\"FileMetaDataset\"] = None,\n        is_implicit_VR: bool = True,\n        is_little_endian: bool = True\n    ) -> None:\n        \"\"\"Initialize a :class:`FileDataset` read from a DICOM file.\n\n        Parameters\n        ----------\n        filename_or_obj : str or PathLike or BytesIO or None\n            Full path and filename to the file, memory buffer object, or\n            ``None`` if is a :class:`io.BytesIO`.\n        dataset : Dataset or dict\n            Some form of dictionary, usually a :class:`Dataset` returned from\n            :func:`~pydicom.filereader.dcmread`.\n        preamble : bytes or str, optional\n            The 128-byte DICOM preamble.\n        file_meta : FileMetaDataset, optional\n            The file meta :class:`FileMetaDataset`, such as the one returned by\n            :func:`~pydicom.filereader.read_file_meta_info`, or an empty\n            :class:`FileMetaDataset` if no file meta information is in the\n            file.\n        is_implicit_VR : bool, optional\n            ``True`` (default) if implicit VR transfer syntax used; ``False``\n            if explicit VR.\n        is_little_endian : bool\n            ``True`` (default) if little-endian transfer syntax used; ``False``\n            if big-endian.\n        \"\"\"\n        Dataset.__init__(self, dataset)\n        self.preamble = preamble\n        self.file_meta: \"FileMetaDataset\" = (\n            file_meta if file_meta is not None else FileMetaDataset()\n        )\n        self.is_implicit_VR: bool = is_implicit_VR\n        self.is_little_endian: bool = is_little_endian\n\n        filename: Optional[str] = None\n        filename_or_obj = path_from_pathlike(filename_or_obj)\n        self.fileobj_type: Any = None\n        self.filename: Union[PathType, BinaryIO] = \"\"\n\n        if isinstance(filename_or_obj, str):\n            filename = filename_or_obj\n            self.fileobj_type = open\n        elif isinstance(filename_or_obj, io.BufferedReader):\n            filename = filename_or_obj.name\n            # This is the appropriate constructor for io.BufferedReader\n            self.fileobj_type = open\n        else:\n            # use __class__ python <2.7?;\n            # http://docs.python.org/reference/datamodel.html\n            self.fileobj_type = filename_or_obj.__class__\n            if hasattr(filename_or_obj, \"name\"):\n                filename = filename_or_obj.name\n            elif hasattr(filename_or_obj, \"filename\"):\n                filename = (\n                    filename_or_obj.filename  # type: ignore[attr-defined]\n                )\n            else:\n                # e.g. came from BytesIO or something file-like\n                self.filename = filename_or_obj\n\n        self.timestamp = None\n        if filename:\n            self.filename = filename\n            if os.path.exists(filename):\n                statinfo = os.stat(filename)\n                self.timestamp = statinfo.st_mtime\n\n    def _copy_implementation(self, copy_function: Callable) -> \"FileDataset\":\n        \"\"\"Implementation of ``__copy__`` and ``__deepcopy__``.\n        Sets the filename to ``None`` if it isn't a string,\n        and copies all other attributes using `copy_function`.\n        \"\"\"\n        copied = self.__class__(\n            self.filename, self, self.preamble, self.file_meta,\n            self.is_implicit_VR, self.is_little_endian\n        )\n        filename = self.filename\n        if filename is not None and not isinstance(filename, str):\n            warnings.warn(\"The 'filename' attribute of the dataset is a \"\n                          \"file-like object and will be set to None \"\n                          \"in the copied object\")\n            self.filename = None  # type: ignore[assignment]\n        for (k, v) in self.__dict__.items():\n            copied.__dict__[k] = copy_function(v)\n\n        self.filename = filename\n\n        return copied\n\n    def __copy__(self) -> \"FileDataset\":\n        \"\"\"Return a shallow copy of the file dataset.\n        Make sure that the filename is not copied in case it is a file-like\n        object.\n\n        Returns\n        -------\n        FileDataset\n            A shallow copy of the file data set.\n        \"\"\"\n        return self._copy_implementation(copy.copy)\n\n    def __deepcopy__(self, _: Optional[Dict[int, Any]]) -> \"FileDataset\":\n        \"\"\"Return a deep copy of the file dataset.\n        Make sure that the filename is not copied in case it is a file-like\n        object.\n\n        Returns\n        -------\n        FileDataset\n            A deep copy of the file data set.\n        \"\"\"\n        return self._copy_implementation(copy.deepcopy)\n\n\ndef validate_file_meta(\n    file_meta: \"FileMetaDataset\", enforce_standard: bool = True\n) -> None:\n    \"\"\"Validate the *File Meta Information* elements in `file_meta`.\n\n    .. versionchanged:: 1.2\n\n        Moved from :mod:`pydicom.filewriter`.\n\n    Parameters\n    ----------\n    file_meta : Dataset\n        The *File Meta Information* data elements.\n    enforce_standard : bool, optional\n        If ``False``, then only a check for invalid elements is performed.\n        If ``True`` (default), the following elements will be added if not\n        already present:\n\n        * (0002,0001) *File Meta Information Version*\n        * (0002,0012) *Implementation Class UID*\n        * (0002,0013) *Implementation Version Name*\n\n        and the following elements will be checked:\n\n        * (0002,0002) *Media Storage SOP Class UID*\n        * (0002,0003) *Media Storage SOP Instance UID*\n        * (0002,0010) *Transfer Syntax UID*\n\n    Raises\n    ------\n    ValueError\n        If `enforce_standard` is ``True`` and any of the checked *File Meta\n        Information* elements are missing from `file_meta`.\n    ValueError\n        If any non-Group 2 Elements are present in `file_meta`.\n    \"\"\"\n    # Check that no non-Group 2 Elements are present\n    for elem in file_meta.elements():\n        if elem.tag.group != 0x0002:\n            raise ValueError(\"Only File Meta Information Group (0002,eeee) \"\n                             \"elements must be present in 'file_meta'.\")\n\n    if enforce_standard:\n        if 'FileMetaInformationVersion' not in file_meta:\n            file_meta.FileMetaInformationVersion = b'\\x00\\x01'\n\n        if 'ImplementationClassUID' not in file_meta:\n            file_meta.ImplementationClassUID = UID(PYDICOM_IMPLEMENTATION_UID)\n\n        if 'ImplementationVersionName' not in file_meta:\n            file_meta.ImplementationVersionName = (\n                'PYDICOM ' + \".\".join(str(x) for x in __version_info__))\n\n        # Check that required File Meta Information elements are present\n        missing = []\n        for element in [0x0002, 0x0003, 0x0010]:\n            if Tag(0x0002, element) not in file_meta:\n                missing.append(Tag(0x0002, element))\n        if missing:\n            msg = (\"Missing required File Meta Information elements from \"\n                   \"'file_meta':\\n\")\n            for tag in missing:\n                msg += '\\t{0} {1}\\n'.format(tag, keyword_for_tag(tag))\n            raise ValueError(msg[:-1])  # Remove final newline\n\n\nclass FileMetaDataset(Dataset):\n    \"\"\"Contains a collection (dictionary) of group 2 DICOM Data Elements.\n\n    .. versionadded:: 2.0\n\n    Derived from :class:`~pydicom.dataset.Dataset`, but only allows\n    Group 2 (File Meta Information) data elements\n    \"\"\"\n\n    def __init__(self, *args: _DatasetType, **kwargs: Any) -> None:\n        \"\"\"Initialize a FileMetaDataset\n\n        Parameters are as per :class:`Dataset`; this overrides the super class\n        only to check that all are group 2 data elements\n\n        Raises\n        ------\n        ValueError\n            If any data elements are not group 2.\n        TypeError\n            If the passed argument is not a :class:`dict` or :class:`Dataset`\n        \"\"\"\n        super().__init__(*args, **kwargs)\n        FileMetaDataset.validate(self._dict)\n\n        # Set type hints for the possible contents - VR, Type (1|1C|3)\n        self.FileMetaInformationGroupLength: int  # UL, 1\n        self.FileMetaInformationVersion: bytes  # OB, 1\n        self.MediaStorageSOPClassUID: UID  # UI, 1\n        self.MediaStorageSOPInstanceUID: UID  # UI, 1\n        self.TransferSyntaxUID: UID  # UI, 1\n        self.ImplementationClassUID: UID  # UI, 1\n        self.ImplementationVersionName: Optional[str]  # SH, 3\n        self.SourceApplicationEntityTitle: Optional[str]  # AE, 3\n        self.SendingApplicationEntityTitle: Optional[str]  # AE, 3\n        self.ReceivingApplicationEntityTitle: Optional[str]  # AE, 3\n        self.SourcePresentationAddress: Optional[str]  # UR, 3\n        self.ReceivingPresentationAddress: Optional[str]  # UR, 3\n        self.PrivateInformationCreatorUID: Optional[UID]  # UI, 3\n        self.PrivateInformation: bytes  # OB, 1C\n\n    @staticmethod\n    def validate(init_value: _DatasetType) -> None:\n        \"\"\"Raise errors if initialization value is not acceptable for file_meta\n\n        Parameters\n        ----------\n        init_value: dict or Dataset\n            The tag:data element pairs to initialize a file meta dataset\n\n        Raises\n        ------\n        TypeError\n            If the passed argument is not a :class:`dict` or :class:`Dataset`\n        ValueError\n            If any data elements passed are not group 2.\n        \"\"\"\n        if init_value is None:\n            return\n\n        if not isinstance(init_value, (Dataset, dict)):\n            raise TypeError(\n                \"Argument must be a dict or Dataset, not {}\".format(\n                    type(init_value)\n                )\n            )\n\n        non_group2 = [\n            Tag(tag) for tag in init_value.keys() if Tag(tag).group != 2\n        ]\n        if non_group2:\n            msg = \"Attempted to set non-group 2 elements: {}\"\n            raise ValueError(msg.format(non_group2))\n\n    def __setitem__(\n        self, key: Union[slice, TagType], value: _DatasetValue\n    ) -> None:\n        \"\"\"Override parent class to only allow setting of group 2 elements.\n\n        Parameters\n        ----------\n        key : int or Tuple[int, int] or str\n            The tag for the element to be added to the Dataset.\n        value : dataelem.DataElement or dataelem.RawDataElement\n            The element to add to the :class:`FileMetaDataset`.\n\n        Raises\n        ------\n        ValueError\n            If `key` is not a DICOM Group 2 tag.\n        \"\"\"\n\n        if isinstance(value.tag, BaseTag):\n            tag = value.tag\n        else:\n            tag = Tag(value.tag)\n\n        if tag.group != 2:\n            raise ValueError(\n                \"Only group 2 data elements are allowed in a FileMetaDataset\"\n            )\n\n        super().__setitem__(key, value)\n\n\n_RE_CAMEL_CASE = re.compile(\n    # Ensure mix of upper and lowercase and digits, no underscores\n    # If first character is lowercase ensure at least one uppercase char\n    \"(?P<start>(^[A-Za-z])((?=.+?[A-Z])[A-Za-z0-9]+)|(^[A-Z])([A-Za-z0-9]+))\"\n    \"(?P<last>[A-Za-z0-9][^_]$)\"  # Last character is alphanumeric\n)\n","new_file_content":"# Copyright 2008-2018 pydicom authors. See LICENSE file for details.\n\"\"\"Define the Dataset and FileDataset classes.\n\nThe Dataset class represents the DICOM Dataset while the FileDataset class\nadds extra functionality to Dataset when data is read from or written to file.\n\nOverview of DICOM object model\n------------------------------\nDataset (dict subclass)\n  Contains DataElement instances, each of which has a tag, VR, VM and value.\n    The DataElement value can be:\n        * A single value, such as a number, string, etc. (i.e. VM = 1)\n        * A list of numbers, strings, etc. (i.e. VM > 1)\n        * A Sequence (list subclass), where each item is a Dataset which\n            contains its own DataElements, and so on in a recursive manner.\n\"\"\"\n\nfrom bisect import bisect_left\nimport io\nimport inspect  # for __dir__\nfrom itertools import takewhile\nimport json\nimport os\nimport os.path\nimport warnings\n\nimport pydicom  # for dcmwrite\nimport pydicom.charset\nimport pydicom.config\nfrom pydicom import datadict, jsonrep\nfrom pydicom._version import __version_info__\nfrom pydicom.charset import default_encoding, convert_encodings\nfrom pydicom.config import logger\nfrom pydicom.datadict import dictionary_VR\nfrom pydicom.datadict import (tag_for_keyword, keyword_for_tag,\n                              repeater_has_keyword)\nfrom pydicom.dataelem import DataElement, DataElement_from_raw, RawDataElement\nfrom pydicom.fileutil import path_from_pathlike\nfrom pydicom.pixel_data_handlers.util import (\n    convert_color_space, reshape_pixel_array, get_image_pixel_ids\n)\nfrom pydicom.tag import Tag, BaseTag, tag_in_exception\nfrom pydicom.uid import (ExplicitVRLittleEndian, ImplicitVRLittleEndian,\n                         ExplicitVRBigEndian, PYDICOM_IMPLEMENTATION_UID)\n\n\nfrom importlib.util import find_spec as have_package\n\n\nclass PrivateBlock:\n    \"\"\"Helper class for a private block in the :class:`Dataset`.\n\n    .. versionadded:: 1.3\n\n    See the DICOM Standard, Part 5,\n    :dcm:`Section 7.8.1<part05/sect_7.8.html#sect_7.8.1>` - Private Data\n    Element Tags\n\n    Attributes\n    ----------\n    group : int\n        The private group where the private block is located as a 32-bit\n        :class:`int`.\n    private_creator : str\n        The private creator string related to the block.\n    dataset : Dataset\n        The parent dataset.\n    block_start : int\n        The start element of the private block as a 32-bit :class:`int`. Note\n        that the 2 low order hex digits of the element are always 0.\n    \"\"\"\n\n    def __init__(self, key, dataset, private_creator_element):\n        \"\"\"Initializes an object corresponding to a private tag block.\n\n        Parameters\n        ----------\n        key : tuple\n            The private (tag group, creator) as ``(int, str)``. The group\n            must be an odd number.\n        dataset : Dataset\n            The parent :class:`Dataset`.\n        private_creator_element : int\n            The element of the private creator tag as a 32-bit :class:`int`.\n        \"\"\"\n        self.group = key[0]\n        self.private_creator = key[1]\n        self.dataset = dataset\n        self.block_start = private_creator_element << 8\n\n    def get_tag(self, element_offset):\n        \"\"\"Return the private tag ID for the given `element_offset`.\n\n        Parameters\n        ----------\n        element_offset : int\n            The lower 16 bits (e.g. 2 hex numbers) of the element tag.\n\n        Returns\n        -------\n            The tag ID defined by the private block location and the\n            given element offset.\n\n        Raises\n        ------\n        ValueError\n            If `element_offset` is too large.\n        \"\"\"\n        if element_offset > 0xff:\n            raise ValueError('Element offset must be less than 256')\n        return Tag(self.group, self.block_start + element_offset)\n\n    def __contains__(self, element_offset):\n        \"\"\"Return ``True`` if the tag with given `element_offset` is in\n        the parent :class:`Dataset`.\n        \"\"\"\n        return self.get_tag(element_offset) in self.dataset\n\n    def __getitem__(self, element_offset):\n        \"\"\"Return the data element in the parent dataset for the given element\n        offset.\n\n        Parameters\n        ----------\n        element_offset : int\n            The lower 16 bits (e.g. 2 hex numbers) of the element tag.\n\n        Returns\n        -------\n            The data element of the tag in the parent dataset defined by the\n            private block location and the given element offset.\n\n        Raises\n        ------\n        ValueError\n            If `element_offset` is too large.\n        KeyError\n            If no data element exists at that offset.\n        \"\"\"\n        return self.dataset.__getitem__(self.get_tag(element_offset))\n\n    def __delitem__(self, element_offset):\n        \"\"\"Delete the tag with the given `element_offset` from the dataset.\n\n        Parameters\n        ----------\n        element_offset : int\n            The lower 16 bits (e.g. 2 hex numbers) of the element tag\n            to be deleted.\n\n        Raises\n        ------\n        ValueError\n            If `element_offset` is too large.\n        KeyError\n            If no data element exists at that offset.\n        \"\"\"\n        del self.dataset[self.get_tag(element_offset)]\n\n    def add_new(self, element_offset, VR, value):\n        \"\"\"Add a private element to the parent :class:`Dataset`.\n\n        Adds the private tag with the given `VR` and `value` to the parent\n        :class:`Dataset` at the tag ID defined by the private block and the\n        given `element_offset`.\n\n        Parameters\n        ----------\n        element_offset : int\n            The lower 16 bits (e.g. 2 hex numbers) of the element tag\n            to be added.\n        VR : str\n            The 2 character DICOM value representation.\n        value\n            The value of the data element. See :meth:`Dataset.add_new()`\n            for a description.\n        \"\"\"\n        tag = self.get_tag(element_offset)\n        self.dataset.add_new(tag, VR, value)\n        self.dataset[tag].private_creator = self.private_creator\n\n\ndef _dict_equal(a, b, exclude=None):\n    \"\"\"Common method for Dataset.__eq__ and FileDataset.__eq__\n\n    Uses .keys() as needed because Dataset iter return items not keys\n    `exclude` is used in FileDataset__eq__ ds.__dict__ compare, which\n    would also compare the wrapped _dict member (entire dataset) again.\n    \"\"\"\n    return (len(a) == len(b) and\n            all(key in b for key in a.keys()) and\n            all(a[key] == b[key] for key in a.keys()\n                if exclude is None or key not in exclude)\n            )\n\n\nclass Dataset(dict):\n    \"\"\"Contains a collection (dictionary) of DICOM Data Elements.\n\n    Behaves like a :class:`dict`.\n\n    .. note::\n\n        :class:`Dataset` is only derived from :class:`dict` to make it work in\n        a NumPy :class:`~numpy.ndarray`. The parent :class:`dict` class\n        is never called, as all :class:`dict` methods are overridden.\n\n    Examples\n    --------\n    Add an element to the :class:`Dataset` (for elements in the DICOM\n    dictionary):\n\n    >>> ds = Dataset()\n    >>> ds.PatientName = \"CITIZEN^Joan\"\n    >>> ds.add_new(0x00100020, 'LO', '12345')\n    >>> ds[0x0010, 0x0030] = DataElement(0x00100030, 'DA', '20010101')\n\n    Add a sequence element to the :class:`Dataset`\n\n    >>> ds.BeamSequence = [Dataset(), Dataset(), Dataset()]\n    >>> ds.BeamSequence[0].Manufacturer = \"Linac, co.\"\n    >>> ds.BeamSequence[1].Manufacturer = \"Linac and Sons, co.\"\n    >>> ds.BeamSequence[2].Manufacturer = \"Linac and Daughters, co.\"\n\n    Add private elements to the :class:`Dataset`\n\n    >>> block = ds.private_block(0x0041, 'My Creator', create=True)\n    >>> block.add_new(0x01, 'LO', '12345')\n\n    Updating and retrieving element values:\n\n    >>> ds.PatientName = \"CITIZEN^Joan\"\n    >>> ds.PatientName\n    'CITIZEN^Joan'\n    >>> ds.PatientName = \"CITIZEN^John\"\n    >>> ds.PatientName\n    'CITIZEN^John'\n\n    Retrieving an element's value from a Sequence:\n\n    >>> ds.BeamSequence[0].Manufacturer\n    'Linac, co.'\n    >>> ds.BeamSequence[1].Manufacturer\n    'Linac and Sons, co.'\n\n    Accessing the :class:`~pydicom.dataelem.DataElement` items:\n\n    >>> elem = ds['PatientName']\n    >>> elem\n    (0010, 0010) Patient's Name                      PN: 'CITIZEN^John'\n    >>> elem = ds[0x00100010]\n    >>> elem\n    (0010, 0010) Patient's Name                      PN: 'CITIZEN^John'\n    >>> elem = ds.data_element('PatientName')\n    >>> elem\n    (0010, 0010) Patient's Name                      PN: 'CITIZEN^John'\n\n    Accessing a private :class:`~pydicom.dataelem.DataElement`\n    item:\n\n    >>> block = ds.private_block(0x0041, 'My Creator')\n    >>> elem = block[0x01]\n    >>> elem\n    (0041, 1001) Private tag data                    LO: '12345'\n    >>> elem.value\n    '12345'\n\n    Alternatively:\n\n    >>> ds.get_private_item(0x0041, 0x01, 'My Creator').value\n    '12345'\n\n    Deleting an element from the :class:`Dataset`\n\n    >>> del ds.PatientID\n    >>> del ds.BeamSequence[1].Manufacturer\n    >>> del ds.BeamSequence[2]\n\n    Deleting a private element from the :class:`Dataset`\n\n    >>> block = ds.private_block(0x0041, 'My Creator')\n    >>> if 0x01 in block:\n    ...     del block[0x01]\n\n    Determining if an element is present in the :class:`Dataset`\n\n    >>> 'PatientName' in ds\n    True\n    >>> 'PatientID' in ds\n    False\n    >>> (0x0010, 0x0030) in ds\n    True\n    >>> 'Manufacturer' in ds.BeamSequence[0]\n    True\n\n    Iterating through the top level of a :class:`Dataset` only (excluding\n    Sequences):\n\n    >>> for elem in ds:\n    ...    print(elem)\n    (0010, 0010) Patient's Name                      PN: 'CITIZEN^John'\n\n    Iterating through the entire :class:`Dataset` (including Sequences):\n\n    >>> for elem in ds.iterall():\n    ...     print(elem)\n    (0010, 0010) Patient's Name                      PN: 'CITIZEN^John'\n\n    Recursively iterate through a :class:`Dataset` (including Sequences):\n\n    >>> def recurse(ds):\n    ...     for elem in ds:\n    ...         if elem.VR == 'SQ':\n    ...             [recurse(item) for item in elem]\n    ...         else:\n    ...             # Do something useful with each DataElement\n\n    Converting the :class:`Dataset` to and from JSON:\n\n    >>> ds = Dataset()\n    >>> ds.PatientName = \"Some^Name\"\n    >>> jsonmodel = ds.to_json()\n    >>> ds2 = Dataset()\n    >>> ds2.from_json(jsonmodel)\n    (0010, 0010) Patient's Name                      PN: 'Some^Name'\n\n    Attributes\n    ----------\n    default_element_format : str\n        The default formatting for string display.\n    default_sequence_element_format : str\n        The default formatting for string display of sequences.\n    indent_chars : str\n        For string display, the characters used to indent nested Sequences.\n        Default is ``\"   \"``.\n    is_little_endian : bool\n        Shall be set before writing with ``write_like_original=False``.\n        The :class:`Dataset` (excluding the pixel data) will be written using\n        the given endianess.\n    is_implicit_VR : bool\n        Shall be set before writing with ``write_like_original=False``.\n        The :class:`Dataset` will be written using the transfer syntax with\n        the given VR handling, e.g *Little Endian Implicit VR* if ``True``,\n        and *Little Endian Explicit VR* or *Big Endian Explicit VR* (depending\n        on ``Dataset.is_little_endian``) if ``False``.\n    \"\"\"\n    indent_chars = \"   \"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Create a new :class:`Dataset` instance.\"\"\"\n        self._parent_encoding = kwargs.get('parent_encoding', default_encoding)\n        if not args:\n            self._dict = {}\n        elif isinstance(args[0], Dataset):\n            self._dict = args[0]._dict\n        else:\n            self._dict = args[0]\n        self.is_decompressed = False\n\n        # the following read_XXX attributes are used internally to store\n        # the properties of the dataset after read from a file\n\n        # set depending on the endianess of the read dataset\n        self.read_little_endian = None\n        # set depending on the VR handling of the read dataset\n        self.read_implicit_vr = None\n        # set to the encoding the dataset had originally\n        self.read_encoding = None\n\n        self.is_little_endian = None\n        self.is_implicit_VR = None\n\n        # the parent data set, if this dataset is a sequence item\n        self.parent = None\n\n        # known private creator blocks\n        self._private_blocks = {}\n\n    def __enter__(self):\n        \"\"\"Method invoked on entry to a with statement.\"\"\"\n        return self\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        \"\"\"Method invoked on exit from a with statement.\"\"\"\n        # Returning False will re-raise any exceptions that occur\n        return False\n\n    def add(self, data_element):\n        \"\"\"Add an element to the :class:`Dataset`.\n\n        Equivalent to ``ds[data_element.tag] = data_element``\n\n        Parameters\n        ----------\n        data_element : dataelem.DataElement\n            The :class:`~pydicom.dataelem.DataElement` to add.\n        \"\"\"\n        self[data_element.tag] = data_element\n\n    def add_new(self, tag, VR, value):\n        \"\"\"Create a new element and add it to the :class:`Dataset`.\n\n        Parameters\n        ----------\n        tag\n            The DICOM (group, element) tag in any form accepted by\n            :func:`~pydicom.tag.Tag` such as ``[0x0010, 0x0010]``,\n            ``(0x10, 0x10)``, ``0x00100010``, etc.\n        VR : str\n            The 2 character DICOM value representation (see DICOM Standard,\n            Part 5, :dcm:`Section 6.2<part05/sect_6.2.html>`).\n        value\n            The value of the data element. One of the following:\n\n            * a single string or number\n            * a :class:`list` or :class:`tuple` with all strings or all numbers\n            * a multi-value string with backslash separator\n            * for a sequence element, an empty :class:`list` or ``list`` of\n              :class:`Dataset`\n        \"\"\"\n\n        data_element = DataElement(tag, VR, value)\n        # use data_element.tag since DataElement verified it\n        self._dict[data_element.tag] = data_element\n\n    def data_element(self, name):\n        \"\"\"Return the element corresponding to the element keyword `name`.\n\n        Parameters\n        ----------\n        name : str\n            A DICOM element keyword.\n\n        Returns\n        -------\n        dataelem.DataElement or None\n            For the given DICOM element `keyword`, return the corresponding\n            :class:`~pydicom.dataelem.DataElement` if present, ``None``\n            otherwise.\n        \"\"\"\n        tag = tag_for_keyword(name)\n        # Test against None as (0000,0000) is a possible tag\n        if tag is not None:\n            return self[tag]\n        return None\n\n    def __contains__(self, name):\n        \"\"\"Simulate dict.__contains__() to handle DICOM keywords.\n\n        Examples\n        --------\n\n        >>> ds = Dataset()\n        >>> ds.SliceLocation = '2'\n        >>> 'SliceLocation' in ds\n        True\n\n        Parameters\n        ----------\n        name : str or int or 2-tuple\n            The element keyword or tag to search for.\n\n        Returns\n        -------\n        bool\n            ``True`` if the corresponding element is in the :class:`Dataset`,\n            ``False`` otherwise.\n        \"\"\"\n        try:\n            tag = Tag(name)\n        except (ValueError, OverflowError):\n            return False\n        # Test against None as (0000,0000) is a possible tag\n        if tag is not None:\n            return tag in self._dict\n        return name in self._dict  # will no doubt raise an exception\n\n    def decode(self):\n        \"\"\"Apply character set decoding to the elements in the\n        :class:`Dataset`.\n\n        See DICOM Standard, Part 5,\n        :dcm:`Section 6.1.1<part05/chapter_6.html#sect_6.1.1>`.\n        \"\"\"\n        # Find specific character set. 'ISO_IR 6' is default\n        # May be multi-valued, but let pydicom.charset handle all logic on that\n        dicom_character_set = self._character_set\n\n        # Shortcut to the decode function in pydicom.charset\n        decode_data_element = pydicom.charset.decode_element\n\n        # Callback for walk(), to decode the chr strings if necessary\n        # This simply calls the pydicom.charset.decode_element function\n        def decode_callback(ds, data_element):\n            \"\"\"Callback to decode `data_element`.\"\"\"\n            if data_element.VR == 'SQ':\n                for dset in data_element.value:\n                    dset._parent_encoding = dicom_character_set\n                    dset.decode()\n            else:\n                decode_data_element(data_element, dicom_character_set)\n\n        self.walk(decode_callback, recursive=False)\n\n    def __delattr__(self, name):\n        \"\"\"Intercept requests to delete an attribute by `name`.\n\n        Examples\n        --------\n\n        >>> ds = Dataset()\n        >>> ds.PatientName = 'foo'\n        >>> ds.some_attribute = True\n\n        If `name` is a DICOM keyword - delete the corresponding\n        :class:`~pydicom.dataelem.DataElement`\n\n        >>> del ds.PatientName\n        >>> 'PatientName' in ds\n        False\n\n        If `name` is another attribute - delete it\n\n        >>> del ds.some_attribute\n        >>> hasattr(ds, 'some_attribute')\n        False\n\n        Parameters\n        ----------\n        name : str\n            The keyword for the DICOM element or the class attribute to delete.\n        \"\"\"\n        # First check if a valid DICOM keyword and if we have that data element\n        tag = tag_for_keyword(name)\n        if tag is not None and tag in self._dict:\n            del self._dict[tag]\n        # If not a DICOM name in this dataset, check for regular instance name\n        #   can't do delete directly, that will call __delattr__ again\n        elif name in self.__dict__:\n            del self.__dict__[name]\n        # Not found, raise an error in same style as python does\n        else:\n            raise AttributeError(name)\n\n    def __delitem__(self, key):\n        \"\"\"Intercept requests to delete an attribute by key.\n\n        Examples\n        --------\n        Indexing using :class:`~pydicom.dataelem.DataElement` tag\n\n        >>> ds = Dataset()\n        >>> ds.CommandGroupLength = 100\n        >>> ds.PatientName = 'CITIZEN^Jan'\n        >>> del ds[0x00000000]\n        >>> ds\n        (0010, 0010) Patient's Name                      PN: 'CITIZEN^Jan'\n\n        Slicing using :class:`~pydicom.dataelem.DataElement` tag\n\n        >>> ds = Dataset()\n        >>> ds.CommandGroupLength = 100\n        >>> ds.SOPInstanceUID = '1.2.3'\n        >>> ds.PatientName = 'CITIZEN^Jan'\n        >>> del ds[:0x00100000]\n        >>> ds\n        (0010, 0010) Patient's Name                      PN: 'CITIZEN^Jan'\n\n        Parameters\n        ----------\n        key\n            The key for the attribute to be deleted. If a ``slice`` is used\n            then the tags matching the slice conditions will be deleted.\n        \"\"\"\n        # If passed a slice, delete the corresponding DataElements\n        if isinstance(key, slice):\n            for tag in self._slice_dataset(key.start, key.stop, key.step):\n                del self._dict[tag]\n                # invalidate private blocks in case a private creator is\n                # deleted - will be re-created on next access\n                if self._private_blocks and BaseTag(tag).is_private_creator:\n                    self._private_blocks = {}\n        else:\n            # Assume is a standard tag (for speed in common case)\n            try:\n                del self._dict[key]\n                if self._private_blocks and BaseTag(key).is_private_creator:\n                    self._private_blocks = {}\n            # If not a standard tag, than convert to Tag and try again\n            except KeyError:\n                tag = Tag(key)\n                del self._dict[tag]\n                if self._private_blocks and tag.is_private_creator:\n                    self._private_blocks = {}\n\n    def __dir__(self):\n        \"\"\"Give a list of attributes available in the :class:`Dataset`.\n\n        List of attributes is used, for example, in auto-completion in editors\n        or command-line environments.\n        \"\"\"\n        # Force zip object into a list\n        meths = set(list(zip(\n            *inspect.getmembers(self.__class__, inspect.isroutine)))[0])\n        props = set(list(zip(\n            *inspect.getmembers(self.__class__, inspect.isdatadescriptor)))[0])\n        dicom_names = set(self.dir())\n        alldir = sorted(props | meths | dicom_names)\n        return alldir\n\n    def dir(self, *filters):\n        \"\"\"Return an alphabetical list of element keywords in the\n        :class:`Dataset`.\n\n        Intended mainly for use in interactive Python sessions. Only lists the\n        element keywords in the current level of the :class:`Dataset` (i.e.\n        the contents of any sequence elements are ignored).\n\n        Parameters\n        ----------\n        filters : str\n            Zero or more string arguments to the function. Used for\n            case-insensitive match to any part of the DICOM keyword.\n\n        Returns\n        -------\n        list of str\n            The matching element keywords in the dataset. If no\n            filters are used then all element keywords are returned.\n        \"\"\"\n        allnames = [keyword_for_tag(tag) for tag in self._dict.keys()]\n        # remove blanks - tags without valid names (e.g. private tags)\n        allnames = [x for x in allnames if x]\n        # Store found names in a dict, so duplicate names appear only once\n        matches = {}\n        for filter_ in filters:\n            filter_ = filter_.lower()\n            match = [x for x in allnames if x.lower().find(filter_) != -1]\n            matches.update(dict([(x, 1) for x in match]))\n        if filters:\n            names = sorted(matches.keys())\n            return names\n        else:\n            return sorted(allnames)\n\n    def __eq__(self, other):\n        \"\"\"Compare `self` and `other` for equality.\n\n        Returns\n        -------\n        bool\n            The result if `self` and `other` are the same class\n        NotImplemented\n            If `other` is not the same class as `self` then returning\n            :class:`NotImplemented` delegates the result to\n            ``superclass.__eq__(subclass)``.\n        \"\"\"\n        # When comparing against self this will be faster\n        if other is self:\n            return True\n\n        if isinstance(other, self.__class__):\n            return _dict_equal(self, other)\n\n        return NotImplemented\n\n    def get(self, key, default=None):\n        \"\"\"Simulate ``dict.get()`` to handle element tags and keywords.\n\n        Parameters\n        ----------\n        key : str or int or Tuple[int, int] or BaseTag\n            The element keyword or tag or the class attribute name to get.\n        default : obj or None, optional\n            If the element or class attribute is not present, return\n            `default` (default ``None``).\n\n        Returns\n        -------\n        value\n            If `key` is the keyword for an element in the :class:`Dataset`\n            then return the element's value.\n        dataelem.DataElement\n            If `key` is a tag for a element in the :class:`Dataset` then\n            return the :class:`~pydicom.dataelem.DataElement`\n            instance.\n        value\n            If `key` is a class attribute then return its value.\n        \"\"\"\n        if isinstance(key, str):\n            try:\n                return getattr(self, key)\n            except AttributeError:\n                return default\n        else:\n            # is not a string, try to make it into a tag and then hand it\n            # off to the underlying dict\n            if not isinstance(key, BaseTag):\n                try:\n                    key = Tag(key)\n                except Exception:\n                    raise TypeError(\"Dataset.get key must be a string or tag\")\n        try:\n            return self.__getitem__(key)\n        except KeyError:\n            return default\n\n    def items(self):\n        \"\"\"Return the :class:`Dataset` items to simulate :meth:`dict.items`.\n\n        Returns\n        -------\n        dict_items\n            The top-level (:class:`~pydicom.tag.BaseTag`,\n            :class:`~pydicom.dataelem.DataElement`) items for the\n            :class:`Dataset`.\n        \"\"\"\n        return self._dict.items()\n\n    def keys(self):\n        \"\"\"Return the :class:`Dataset` keys to simulate :meth:`dict.keys`.\n\n        Returns\n        -------\n        dict_keys\n            The :class:`~pydicom.tag.BaseTag` of all the elements in\n            the :class:`Dataset`.\n        \"\"\"\n        return self._dict.keys()\n\n    def values(self):\n        \"\"\"Return the :class:`Dataset` values to simulate :meth:`dict.values`.\n\n        Returns\n        -------\n        dict_keys\n            The :class:`DataElements<pydicom.dataelem.DataElement>` that make\n            up the values of the :class:`Dataset`.\n        \"\"\"\n        return self._dict.values()\n\n    def __getattr__(self, name):\n        \"\"\"Intercept requests for :class:`Dataset` attribute names.\n\n        If `name` matches a DICOM keyword, return the value for the\n        element with the corresponding tag.\n\n        Parameters\n        ----------\n        name\n            An element keyword or tag or a class attribute name.\n\n        Returns\n        -------\n        value\n              If `name` matches a DICOM keyword, returns the corresponding\n              element's value. Otherwise returns the class attribute's\n              value (if present).\n        \"\"\"\n        tag = tag_for_keyword(name)\n        if tag is not None:  # `name` isn't a DICOM element keyword\n            tag = Tag(tag)\n            if tag in self._dict:  # DICOM DataElement not in the Dataset\n                return self[tag].value\n\n        # no tag or tag not contained in the dataset\n        if name == '_dict':\n            # special handling for contained dict, needed for pickle\n            return {}\n        # Try the base class attribute getter (fix for issue 332)\n        return object.__getattribute__(self, name)\n\n    @property\n    def _character_set(self):\n        \"\"\"The character set used to encode text values.\"\"\"\n        char_set = self.get(BaseTag(0x00080005), None)\n\n        if not char_set:\n            char_set = self._parent_encoding\n        else:\n            char_set = convert_encodings(char_set.value)\n\n        return char_set\n\n    def __getitem__(self, key):\n        \"\"\"Operator for ``Dataset[key]`` request.\n\n        Any deferred data elements will be read in and an attempt will be made\n        to correct any elements with ambiguous VRs.\n\n        Examples\n        --------\n        Indexing using :class:`~pydicom.dataelem.DataElement` tag\n\n        >>> ds = Dataset()\n        >>> ds.SOPInstanceUID = '1.2.3'\n        >>> ds.PatientName = 'CITIZEN^Jan'\n        >>> ds.PatientID = '12345'\n        >>> ds[0x00100010].value\n        'CITIZEN^Jan'\n\n        Slicing using element tags; all group ``0x0010`` elements in\n        the  dataset\n\n        >>> ds[0x00100000:0x00110000]\n        (0010, 0010) Patient's Name                      PN: 'CITIZEN^Jan'\n        (0010, 0020) Patient ID                          LO: '12345'\n\n        All group ``0x0002`` elements in the dataset\n\n        >>> ds[(0x0002, 0x0000):(0x0003, 0x0000)]\n        <BLANKLINE>\n\n        Parameters\n        ----------\n        key\n            The DICOM (group, element) tag in any form accepted by\n            :func:`~pydicom.tag.Tag` such as ``[0x0010, 0x0010]``,\n            ``(0x10, 0x10)``, ``0x00100010``, etc. May also be a :class:`slice`\n            made up of DICOM tags.\n\n        Returns\n        -------\n        dataelem.DataElement or Dataset\n            If a single DICOM element tag is used then returns the\n            corresponding :class:`~pydicom.dataelem.DataElement`.\n            If a :class:`slice` is used then returns a :class:`Dataset` object\n            containing the corresponding\n            :class:`DataElements<pydicom.dataelem.DataElement>`.\n        \"\"\"\n        # If passed a slice, return a Dataset containing the corresponding\n        #   DataElements\n        if isinstance(key, slice):\n            return self._dataset_slice(key)\n\n        if isinstance(key, BaseTag):\n            tag = key\n        else:\n            tag = Tag(key)\n        data_elem = self._dict[tag]\n\n        if isinstance(data_elem, DataElement):\n            if data_elem.VR == 'SQ' and data_elem.value:\n                # let a sequence know its parent dataset, as sequence items\n                # may need parent dataset tags to resolve ambiguous tags\n                data_elem.value.parent = self\n            return data_elem\n        elif isinstance(data_elem, tuple):\n            # If a deferred read, then go get the value now\n            if data_elem.value is None and data_elem.length != 0:\n                from pydicom.filereader import read_deferred_data_element\n                data_elem = read_deferred_data_element(\n                    self.fileobj_type, self.filename, self.timestamp,\n                    data_elem)\n\n            if tag != BaseTag(0x00080005):\n                character_set = self.read_encoding or self._character_set\n            else:\n                character_set = default_encoding\n            # Not converted from raw form read from file yet; do so now\n            self[tag] = DataElement_from_raw(data_elem, character_set)\n\n            # If the Element has an ambiguous VR, try to correct it\n            if 'or' in self[tag].VR:\n                from pydicom.filewriter import correct_ambiguous_vr_element\n                self[tag] = correct_ambiguous_vr_element(\n                    self[tag], self, data_elem[6])\n\n        return self._dict.get(tag)\n\n    def private_block(self, group, private_creator, create=False):\n        \"\"\"Return the block for the given tag `group` and `private_creator`.\n\n        .. versionadded:: 1.3\n\n        If `create` is ``True`` and the `private_creator` does not exist,\n        the private creator tag is added.\n\n        Notes\n        -----\n        We ignore the unrealistic case that no free block is available.\n\n        Parameters\n        ----------\n        group : int\n            The group of the private tag to be found as a 32-bit :class:`int`.\n            Must be an odd number (e.g. a private group).\n        private_creator : str\n            The private creator string associated with the tag.\n        create : bool, optional\n            If ``True`` and `private_creator` does not exist, a new private\n            creator tag is added at the next free block. If ``False``\n            (the default) and `private_creator` does not exist,\n            :class:`KeyError` is raised instead.\n\n        Returns\n        -------\n        PrivateBlock\n            The existing or newly created private block.\n\n        Raises\n        ------\n        ValueError\n            If `group` doesn't belong to a private tag or `private_creator`\n            is empty.\n        KeyError\n            If the private creator tag is not found in the given group and\n            the `create` parameter is ``False``.\n        \"\"\"\n        def new_block(element):\n            block = PrivateBlock(key, self, element)\n            self._private_blocks[key] = block\n            return block\n\n        key = (group, private_creator)\n        if key in self._private_blocks:\n            return self._private_blocks[key]\n\n        if not private_creator:\n            raise ValueError('Private creator must have a value')\n\n        if group % 2 == 0:\n            raise ValueError(\n                'Tag must be private if private creator is given')\n\n        # find block with matching private creator\n        data_el = next((el for el in self[(group, 0x10):(group, 0x100)]\n                        if el.value == private_creator), None)\n        if data_el is not None:\n            return new_block(data_el.tag.element)\n\n        if not create:\n            # not found and shall not be created - raise\n            raise KeyError(\n                \"Private creator '{}' not found\".format(private_creator))\n\n        # private creator not existing - find first unused private block\n        # and add the private creator\n        first_free_el = next(el for el in range(0x10, 0x100)\n                             if Tag(group, el) not in self._dict)\n        self.add_new(Tag(group, first_free_el), 'LO', private_creator)\n        return new_block(first_free_el)\n\n    def private_creators(self, group):\n        \"\"\"Return a list of private creator names in the given group.\n\n        .. versionadded:: 1.3\n\n        Examples\n        --------\n        This can be used to check if a given private creator exists in\n        the group of the dataset:\n\n        >>> ds = Dataset()\n        >>> if 'My Creator' in ds.private_creators(0x0041):\n        ...     block = ds.private_block(0x0041, 'My Creator')\n\n        Parameters\n        ----------\n        group : int\n            The private group as a 32-bit :class:`int`. Must be an odd number.\n\n        Returns\n        -------\n        list of str\n            All private creator names for private blocks in the group.\n\n        Raises\n        ------\n        ValueError\n            If `group` is not a private group.\n        \"\"\"\n        if group % 2 == 0:\n            raise ValueError('Group must be an odd number')\n\n        return [x.value for x in self[(group, 0x10):(group, 0x100)]]\n\n    def get_private_item(self, group, element_offset, private_creator):\n        \"\"\"Return the data element for the given private tag `group`.\n\n        .. versionadded:: 1.3\n\n        This is analogous to ``Dataset.__getitem__()``, but only for private\n        tags. This allows to find the private tag for the correct private\n        creator without the need to add the tag to the private dictionary\n        first.\n\n        Parameters\n        ----------\n        group : int\n            The private tag group where the item is located as a 32-bit int.\n        element_offset : int\n            The lower 16 bits (e.g. 2 hex numbers) of the element tag.\n        private_creator : str\n            The private creator for the tag. Must match the private creator\n            for the tag to be returned.\n\n        Returns\n        -------\n        dataelem.DataElement\n            The corresponding element.\n\n        Raises\n        ------\n        ValueError\n            If `group` is not part of a private tag or `private_creator` is\n            empty.\n        KeyError\n            If the private creator tag is not found in the given group.\n            If the private tag is not found.\n        \"\"\"\n        block = self.private_block(group, private_creator)\n        return self.__getitem__(block.get_tag(element_offset))\n\n    def get_item(self, key):\n        \"\"\"Return the raw data element if possible.\n\n        It will be raw if the user has never accessed the value, or set their\n        own value. Note if the data element is a deferred-read element,\n        then it is read and converted before being returned.\n\n        Parameters\n        ----------\n        key\n            The DICOM (group, element) tag in any form accepted by\n            :func:`~pydicom.tag.Tag` such as ``[0x0010, 0x0010]``,\n            ``(0x10, 0x10)``, ``0x00100010``, etc. May also be a :class:`slice`\n            made up of DICOM tags.\n\n        Returns\n        -------\n        dataelem.DataElement\n            The corresponding element.\n        \"\"\"\n        if isinstance(key, slice):\n            return self._dataset_slice(key)\n\n        if isinstance(key, BaseTag):\n            tag = key\n        else:\n            tag = Tag(key)\n        data_elem = self._dict.get(tag)\n        # If a deferred read, return using __getitem__ to read and convert it\n        if isinstance(data_elem, tuple) and data_elem.value is None:\n            return self[key]\n        return data_elem\n\n    def _dataset_slice(self, slice):\n        \"\"\"Return a slice that has the same properties as the original dataset.\n\n        That includes properties related to endianess and VR handling,\n        and the specific character set. No element conversion is done, e.g.\n        elements of type ``RawDataElement`` are kept.\n        \"\"\"\n        tags = self._slice_dataset(slice.start, slice.stop, slice.step)\n        dataset = Dataset({tag: self.get_item(tag) for tag in tags})\n        dataset.is_little_endian = self.is_little_endian\n        dataset.is_implicit_VR = self.is_implicit_VR\n        dataset.set_original_encoding(self.read_implicit_vr,\n                                      self.read_little_endian,\n                                      self.read_encoding)\n        return dataset\n\n    @property\n    def is_original_encoding(self):\n        \"\"\"Return ``True`` if the encoding to be used for writing is set and\n        is the same as that used to originally encode the  :class:`Dataset`.\n\n        .. versionadded:: 1.1\n\n        This includes properties related to endianess, VR handling and the\n        (0008,0005) *Specific Character Set*.\n        \"\"\"\n        return (self.is_implicit_VR is not None and\n                self.is_little_endian is not None and\n                self.read_implicit_vr == self.is_implicit_VR and\n                self.read_little_endian == self.is_little_endian and\n                self.read_encoding == self._character_set)\n\n    def set_original_encoding(self, is_implicit_vr, is_little_endian,\n                              character_encoding):\n        \"\"\"Set the values for the original transfer syntax and encoding.\n\n        .. versionadded:: 1.2\n\n        Can be used for a :class:`Dataset` with raw data elements to enable\n        optimized writing (e.g. without decoding the data elements).\n        \"\"\"\n        self.read_implicit_vr = is_implicit_vr\n        self.read_little_endian = is_little_endian\n        self.read_encoding = character_encoding\n\n    def group_dataset(self, group):\n        \"\"\"Return a :class:`Dataset` containing only elements of a certain\n        group.\n\n        Parameters\n        ----------\n        group : int\n            The group part of a DICOM (group, element) tag.\n\n        Returns\n        -------\n        Dataset\n            A :class:`Dataset` containing elements of the group specified.\n        \"\"\"\n        return self[(group, 0x0000):(group + 1, 0x0000)]\n\n    def __iter__(self):\n        \"\"\"Iterate through the top-level of the Dataset, yielding DataElements.\n\n        Examples\n        --------\n\n        >>> ds = Dataset()\n        >>> for elem in ds:\n        ...     print(elem)\n\n        The :class:`DataElements<pydicom.dataelem.DataElement>` are returned in\n        increasing tag value order. Sequence items are returned as a single\n        :class:`~pydicom.dataelem.DataElement`, so it is up\n        to the calling code to recurse into the Sequence items if desired.\n\n        Yields\n        ------\n        dataelem.DataElement\n            The :class:`Dataset`'s\n            :class:`DataElements<pydicom.dataelem.DataElement>`, sorted by\n            increasing tag order.\n        \"\"\"\n        # Note this is different than the underlying dict class,\n        #        which returns the key of the key:value mapping.\n        #   Here the value is returned (but data_element.tag has the key)\n        taglist = sorted(self._dict.keys())\n        for tag in taglist:\n            yield self[tag]\n\n    def elements(self):\n        \"\"\"Yield the top-level elements of the :class:`Dataset`.\n\n        .. versionadded:: 1.1\n\n        Examples\n        --------\n\n        >>> ds = Dataset()\n        >>> for elem in ds.elements():\n        ...     print(elem)\n\n        The elements are returned in the same way as in\n        ``Dataset.__getitem__()``.\n\n        Yields\n        ------\n        dataelem.DataElement or dataelem.RawDataElement\n            The unconverted elements sorted by increasing tag order.\n        \"\"\"\n        taglist = sorted(self._dict.keys())\n        for tag in taglist:\n            yield self.get_item(tag)\n\n    def __len__(self):\n        return len(self._dict)\n\n    def __ne__(self, other):\n        \"\"\"Compare `self` and `other` for inequality.\"\"\"\n        return not self == other\n\n    def clear(self):\n        \"\"\"Delete all the elements from the :class:`Dataset`.\"\"\"\n        self._dict.clear()\n\n    def pop(self, key, *args):\n        \"\"\"Emulate :meth:`dict.pop` with support for tags and keywords.\n\n        Removes the element for `key` if it exists and returns it,\n        otherwise returns a default value if given or raises :class:`KeyError`.\n\n        Parameters\n        ----------\n        key : int or str or 2-tuple\n\n            * If :class:`tuple` - the group and element number of the DICOM tag\n            * If :class:`int` - the combined group/element number\n            * If :class:`str` - the DICOM keyword of the tag\n\n        *args : zero or one argument\n            Defines the behavior if no tag exists for `key`: if given,\n            it defines the return value, if not given, :class:`KeyError` is\n            raised\n\n        Returns\n        -------\n        The element for `key` if it exists, or the default value if given.\n\n        Raises\n        ------\n        KeyError\n            If the `key` is not a valid tag or keyword.\n            If the tag does not exist and no default is given.\n        \"\"\"\n        try:\n            tag = Tag(key)\n        except (ValueError, OverflowError):\n            return self._dict.pop(key, *args)\n        return self._dict.pop(tag, *args)\n\n    def popitem(self):\n        return self._dict.popitem()\n\n    def setdefault(self, key, default=None):\n        \"\"\"Emulate :meth:`dict.setdefault` with support for tags and keywords.\n\n        Examples\n        --------\n\n        >>> ds = Dataset()\n        >>> elem = ds.setdefault((0x0010, 0x0010), \"Test\")\n        >>> elem\n        (0010, 0010) Patient's Name                      PN: 'Test'\n        >>> elem.value\n        'Test'\n        >>> elem = ds.setdefault('PatientSex',\n        ...     DataElement(0x00100040, 'CS', 'F'))\n        >>> elem.value\n        'F'\n\n        Parameters\n        ----------\n        key : int or str or 2-tuple\n\n            * If :class:`tuple` - the group and element number of the DICOM tag\n            * If :class:`int` - the combined group/element number\n            * If :class:`str` - the DICOM keyword of the tag\n\n        default : type, optional\n            The default value that is inserted and returned if no data\n            element exists for the given key. If it is not of type\n            :class:`~pydicom.dataelem.DataElement`, one will be\n            constructed instead for the given tag and `default` as value.\n            This is only possible for known tags (e.g. tags found via the\n            dictionary lookup).\n\n        Returns\n        -------\n        DataElement or type\n            The data element for `key` if it exists, or the default value if\n            it is a :class:`~pydicom.dataelem.DataElement` or\n            ``None``, or a :class:`~pydicom.dataelem.DataElement`\n            constructed with `default` as value.\n\n        Raises\n        ------\n        KeyError\n            If the `key` is not a valid tag or keyword.\n            If no tag exists for `key`, default is not a\n            :class:`~pydicom.dataelem.DataElement` and not\n            ``None``, and `key` is not a known DICOM tag.\n        \"\"\"\n        if key in self:\n            return self[key]\n        if default is not None:\n            if not isinstance(default, DataElement):\n                tag = Tag(key)\n                vr = datadict.dictionary_VR(tag)\n                default = DataElement(Tag(key), vr, default)\n            self[key] = default\n        return default\n\n    def convert_pixel_data(self, handler_name=''):\n        \"\"\"Convert pixel data to a :class:`numpy.ndarray` internally.\n\n        Parameters\n        ----------\n        handler_name : str, optional\n            The name of the pixel handler that shall be used to\n            decode the data. Supported names are: ``'gdcm'``,\n            ``'pillow'``, ``'jpeg_ls'``, ``'rle'`` and ``'numpy'``.\n            If not used (the default), a matching handler is used from the\n            handlers configured in :attr:`~pydicom.config.pixel_data_handlers`.\n\n        Returns\n        -------\n        None\n            Converted pixel data is stored internally in the dataset.\n\n        Raises\n        ------\n        ValueError\n            If `handler_name` is not a valid handler name.\n        NotImplementedError\n            If the given handler or any handler, if none given, is unable to\n            decompress pixel data with the current transfer syntax\n        RuntimeError\n            If the given handler, or the handler that has been selected if\n            none given, is not available.\n\n        Notes\n        -----\n        If the pixel data is in a compressed image format, the data is\n        decompressed and any related data elements are changed accordingly.\n        \"\"\"\n        # Check if already have converted to a NumPy array\n        # Also check if pixel data has changed. If so, get new NumPy array\n        already_have = True\n        if not hasattr(self, \"_pixel_array\"):\n            already_have = False\n        elif self._pixel_id != get_image_pixel_ids(self):\n            already_have = False\n\n        if already_have:\n            return\n\n        if handler_name:\n            self._convert_pixel_data_using_handler(handler_name)\n        else:\n            self._convert_pixel_data_without_handler()\n\n    def _convert_pixel_data_using_handler(self, name):\n        \"\"\"Convert the pixel data using handler with the given name.\n        See :meth:`~Dataset.convert_pixel_data` for more information.\n        \"\"\"\n        # handle some variations in name\n        handler_name = name.lower()\n        if not handler_name.endswith('_handler'):\n            handler_name += '_handler'\n        if handler_name == 'numpy_handler':\n            handler_name = 'np_handler'\n        if handler_name == 'jpeg_ls_handler':\n            # the name in config differs from the actual handler name\n            # we allow both\n            handler_name = 'jpegls_handler'\n        if not hasattr(pydicom.config, handler_name):\n            raise ValueError(\"'{}' is not a known handler name\".format(name))\n        handler = getattr(pydicom.config, handler_name)\n\n        transfer_syntax = self.file_meta.TransferSyntaxUID\n        if not handler.supports_transfer_syntax(transfer_syntax):\n            raise NotImplementedError(\n                \"Unable to decode pixel data with a transfer syntax UID\"\n                \" of '{0}' ({1}) using the pixel data handler '{2}'. \"\n                \"Please see the pydicom documentation for information \"\n                \"on supported transfer syntaxes.\".format(\n                    transfer_syntax, transfer_syntax.name, name)\n            )\n        if not handler.is_available():\n            raise RuntimeError(\n                \"The pixel data handler '{0}' is not available on your system.\"\n                \" Please refer to the pydicom documentation for information \"\n                \"on installing needed packages.\".format(name)\n            )\n        # if the conversion fails, the exception is propagated up\n        self._do_pixel_data_conversion(handler)\n\n    def _convert_pixel_data_without_handler(self):\n        \"\"\"Convert the pixel data using the first matching handler.\n        See :meth:`~Dataset.convert_pixel_data` for more information.\n        \"\"\"\n        # Find all possible handlers that support the transfer syntax\n        transfer_syntax = self.file_meta.TransferSyntaxUID\n        possible_handlers = [\n            hh for hh in pydicom.config.pixel_data_handlers\n            if hh.supports_transfer_syntax(transfer_syntax)\n        ]\n\n        # No handlers support the transfer syntax\n        if not possible_handlers:\n            raise NotImplementedError(\n                \"Unable to decode pixel data with a transfer syntax UID of \"\n                \"'{0}' ({1}) as there are no pixel data handlers \"\n                \"available that support it. Please see the pydicom \"\n                \"documentation for information on supported transfer syntaxes \"\n                .format(transfer_syntax, transfer_syntax.name)\n            )\n\n        # Handlers that both support the transfer syntax and have their\n        #   dependencies met\n        available_handlers = [hh for hh in possible_handlers if\n                              hh.is_available()]\n\n        # There are handlers that support the transfer syntax but none of them\n        #   can be used as missing dependencies\n        if not available_handlers:\n            # For each of the possible handlers we want to find which\n            #   dependencies are missing\n            msg = (\n                \"The following handlers are available to decode the pixel \"\n                \"data however they are missing required dependencies: \"\n            )\n            pkg_msg = []\n            for hh in possible_handlers:\n                hh_deps = hh.DEPENDENCIES\n                # Missing packages\n                missing = [dd for dd in hh_deps if have_package(dd) is None]\n                # Package names\n                names = [hh_deps[name][1] for name in missing]\n                pkg_msg.append(\n                    \"{} (req. {})\"\n                    .format(hh.HANDLER_NAME, ', '.join(names))\n                )\n\n            raise RuntimeError(msg + ', '.join(pkg_msg))\n\n        last_exception = None\n        for handler in available_handlers:\n            try:\n                self._do_pixel_data_conversion(handler)\n                return\n            except Exception as exc:\n                logger.debug(\n                    \"Exception raised by pixel data handler\", exc_info=exc\n                )\n                last_exception = exc\n\n        # The only way to get to this point is if we failed to get the pixel\n        #   array because all suitable handlers raised exceptions\n        self._pixel_array = None\n        self._pixel_id = None\n\n        logger.info(\n            \"Unable to decode the pixel data using the following handlers: {}.\"\n            \"Please see the list of supported Transfer Syntaxes in the \"\n            \"pydicom documentation for alternative packages that might \"\n            \"be able to decode the data\"\n            .format(\", \".join([str(hh) for hh in available_handlers]))\n        )\n        raise last_exception\n\n    def _do_pixel_data_conversion(self, handler):\n        \"\"\"Do the actual data conversion using the given handler.\"\"\"\n\n        # Use the handler to get a 1D numpy array of the pixel data\n        # Will raise an exception if no pixel data element\n        arr = handler.get_pixeldata(self)\n        self._pixel_array = reshape_pixel_array(self, arr)\n\n        # Some handler/transfer syntax combinations may need to\n        #   convert the color space from YCbCr to RGB\n        if handler.needs_to_convert_to_RGB(self):\n            self._pixel_array = convert_color_space(\n                self._pixel_array, 'YBR_FULL', 'RGB'\n            )\n\n        self._pixel_id = get_image_pixel_ids(self)\n\n    def decompress(self, handler_name=''):\n        \"\"\"Decompresses *Pixel Data* and modifies the :class:`Dataset`\n        in-place.\n\n        .. versionadded:: 1.4\n\n            The `handler_name` keyword argument was added\n\n        If not a compressed transfer syntax, then pixel data is converted\n        to a :class:`numpy.ndarray` internally, but not returned.\n\n        If compressed pixel data, then is decompressed using an image handler,\n        and internal state is updated appropriately:\n\n        - ``Dataset.file_meta.TransferSyntaxUID`` is updated to non-compressed\n          form\n        - :attr:`~pydicom.dataelem.DataElement.is_undefined_length`\n          is ``False`` for the (7FE0,0010) *Pixel Data* element.\n\n        .. versionchanged:: 1.4\n\n            The `handler_name` keyword argument was added\n\n        Parameters\n        ----------\n        handler_name : str, optional\n            The name of the pixel handler that shall be used to\n            decode the data. Supported names are: ``'gdcm'``,\n            ``'pillow'``, ``'jpeg_ls'``, ``'rle'`` and ``'numpy'``.\n            If not used (the default), a matching handler is used from the\n            handlers configured in :attr:`~pydicom.config.pixel_data_handlers`.\n\n        Returns\n        -------\n        None\n\n        Raises\n        ------\n        NotImplementedError\n            If the pixel data was originally compressed but file is not\n            *Explicit VR Little Endian* as required by the DICOM Standard.\n        \"\"\"\n        self.convert_pixel_data(handler_name)\n        self.is_decompressed = True\n        # May have been undefined length pixel data, but won't be now\n        if 'PixelData' in self:\n            self[0x7fe00010].is_undefined_length = False\n\n        # Make sure correct Transfer Syntax is set\n        # According to the dicom standard PS3.5 section A.4,\n        # all compressed files must have been explicit VR, little endian\n        # First check if was a compressed file\n        if (hasattr(self, 'file_meta') and\n                self.file_meta.TransferSyntaxUID.is_compressed):\n            # Check that current file as read does match expected\n            if not self.is_little_endian or self.is_implicit_VR:\n                msg = (\"Current dataset does not match expected ExplicitVR \"\n                       \"LittleEndian transfer syntax from a compressed \"\n                       \"transfer syntax\")\n                raise NotImplementedError(msg)\n\n            # All is as expected, updated the Transfer Syntax\n            self.file_meta.TransferSyntaxUID = ExplicitVRLittleEndian\n\n    def overlay_array(self, group):\n        \"\"\"Return the *Overlay Data* in `group` as a :class:`numpy.ndarray`.\n\n        .. versionadded:: 1.4\n\n        Returns\n        -------\n        numpy.ndarray\n            The (`group`,3000) *Overlay Data* converted to a\n            :class:`numpy.ndarray`.\n        \"\"\"\n        if group < 0x6000 or group > 0x60FF:\n            raise ValueError(\n                \"The group part of the 'Overlay Data' element tag must be \"\n                \"between 0x6000 and 0x60FF (inclusive)\"\n            )\n\n        # Find all possible handlers that support the transfer syntax\n        transfer_syntax = self.file_meta.TransferSyntaxUID\n        possible_handlers = [hh for hh in pydicom.config.overlay_data_handlers\n                             if hh.supports_transfer_syntax(transfer_syntax)]\n\n        # No handlers support the transfer syntax\n        if not possible_handlers:\n            raise NotImplementedError(\n                \"Unable to decode overlay data with a transfer syntax UID of \"\n                \"'{0}' ({1}) as there are no overlay data handlers \"\n                \"available that support it. Please see the pydicom \"\n                \"documentation for information on supported transfer syntaxes \"\n                .format(self.file_meta.TransferSyntaxUID,\n                        self.file_meta.TransferSyntaxUID.name)\n            )\n\n        # Handlers that both support the transfer syntax and have their\n        #   dependencies met\n        available_handlers = [\n            hh for hh in possible_handlers if hh.is_available()\n        ]\n\n        # There are handlers that support the transfer syntax but none of them\n        #   can be used as missing dependencies\n        if not available_handlers:\n            # For each of the possible handlers we want to find which\n            #   dependencies are missing\n            msg = (\n                \"The following handlers are available to decode the overlay \"\n                \"data however they are missing required dependencies: \"\n            )\n            pkg_msg = []\n            for hh in possible_handlers:\n                hh_deps = hh.DEPENDENCIES\n                # Missing packages\n                missing = [dd for dd in hh_deps if have_package(dd) is None]\n                # Package names\n                names = [hh_deps[name][1] for name in missing]\n                pkg_msg.append(\n                    \"{} (req. {})\"\n                    .format(hh.HANDLER_NAME, ', '.join(names))\n                )\n\n            raise RuntimeError(msg + ', '.join(pkg_msg))\n\n        last_exception = None\n        for handler in available_handlers:\n            try:\n                # Use the handler to get a 1D numpy array of the pixel data\n                return handler.get_overlay_array(self, group)\n            except Exception as exc:\n                logger.debug(\n                    \"Exception raised by overlay data handler\", exc_info=exc\n                )\n                last_exception = exc\n\n        logger.info(\n            \"Unable to decode the overlay data using the following handlers: \"\n            \"{}. Please see the list of supported Transfer Syntaxes in the \"\n            \"pydicom documentation for alternative packages that might \"\n            \"be able to decode the data\"\n            .format(\", \".join([str(hh) for hh in available_handlers]))\n        )\n\n        raise last_exception\n\n    @property\n    def pixel_array(self):\n        \"\"\"Return the pixel data as a :class:`numpy.ndarray`.\n\n        .. versionchanged:: 1.4\n\n            Added support for *Float Pixel Data* and *Double Float Pixel Data*\n\n        Returns\n        -------\n        numpy.ndarray\n            The (7FE0,0008) *Float Pixel Data*, (7FE0,0009) *Double Float\n            Pixel Data* or (7FE0,0010) *Pixel Data* converted to a\n            :class:`numpy.ndarray`.\n        \"\"\"\n        self.convert_pixel_data()\n        return self._pixel_array\n\n    # Format strings spec'd according to python string formatting options\n    #    See http://docs.python.org/library/stdtypes.html#string-formatting-operations # noqa\n    default_element_format = \"%(tag)s %(name)-35.35s %(VR)s: %(repval)s\"\n    default_sequence_element_format = \"%(tag)s %(name)-35.35s %(VR)s: %(repval)s\"  # noqa\n\n    def formatted_lines(\n            self,\n            element_format=default_element_format,\n            sequence_element_format=default_sequence_element_format,\n            indent_format=None):\n        \"\"\"Iterate through the :class:`Dataset` yielding formatted :class:`str`\n        for each element.\n\n        Parameters\n        ----------\n        element_format : str\n            The string format to use for non-sequence elements. Formatting uses\n            the attributes of\n            :class:`~pydicom.dataelem.DataElement`. Default is\n            ``\"%(tag)s %(name)-35.35s %(VR)s: %(repval)s\"``.\n        sequence_element_format : str\n            The string format to use for sequence elements. Formatting uses\n            the attributes of\n            :class:`~pydicom.dataelem.DataElement`. Default is\n            ``\"%(tag)s %(name)-35.35s %(VR)s: %(repval)s\"``\n        indent_format : str or None\n            Placeholder for future functionality.\n\n        Yields\n        ------\n        str\n            A string representation of an element.\n        \"\"\"\n        for data_element in self.iterall():\n            # Get all the attributes possible for this data element (e.g.\n            #   gets descriptive text name too)\n            # This is the dictionary of names that can be used in the format\n            #   string\n            elem_dict = dict([(x, getattr(data_element, x)()\n                               if callable(getattr(data_element, x)) else\n                               getattr(data_element, x))\n                              for x in dir(data_element)\n                              if not x.startswith(\"_\")\n                              and x not in ('from_json', 'to_json',\n                                            'to_json_dict', 'clear')])\n            if data_element.VR == \"SQ\":\n                yield sequence_element_format % elem_dict\n            else:\n                yield element_format % elem_dict\n\n    def _pretty_str(self, indent=0, top_level_only=False):\n        \"\"\"Return a string of the DataElements in the Dataset, with indented\n        levels.\n\n        This private method is called by the ``__str__()`` method for handling\n        print statements or ``str(dataset)``, and the ``__repr__()`` method.\n        It is also used by ``top()``, therefore the `top_level_only` flag.\n        This function recurses, with increasing indentation levels.\n\n        ..versionchanged:: 2.0\n\n            The file meta information is returned in its own section,\n            if :data:`~pydicom.config.show_file_meta` is ``True`` (default)\n\n        Parameters\n        ----------\n        indent : int, optional\n            The indent level offset (default ``0``).\n        top_level_only : bool, optional\n            When True, only create a string for the top level elements, i.e.\n            exclude elements within any Sequences (default ``False``).\n\n        Returns\n        -------\n        str\n            A string representation of the Dataset.\n        \"\"\"\n        strings = []\n        indent_str = self.indent_chars * indent\n        nextindent_str = self.indent_chars * (indent + 1)\n\n        # Display file meta, if configured to do so, and have a non-empty one\n        if (\n            hasattr(self, \"file_meta\")\n            and self.file_meta is not None\n            and len(self.file_meta) > 0\n            and pydicom.config.show_file_meta\n        ):\n            strings.append(\"Dataset.file_meta -------------------------------\")\n            for data_element in self.file_meta:\n                with tag_in_exception(data_element.tag):\n                    strings.append(indent_str + repr(data_element))\n            strings.append(\"-------------------------------------------------\")\n\n        for data_element in self:\n            with tag_in_exception(data_element.tag):\n                if data_element.VR == \"SQ\":  # a sequence\n                    strings.append(indent_str + str(data_element.tag) +\n                                   \"  %s   %i item(s) ---- \" %\n                                   (data_element.description(),\n                                    len(data_element.value)))\n                    if not top_level_only:\n                        for dataset in data_element.value:\n                            strings.append(dataset._pretty_str(indent + 1))\n                            strings.append(nextindent_str + \"---------\")\n                else:\n                    strings.append(indent_str + repr(data_element))\n        return \"\\n\".join(strings)\n\n    def remove_private_tags(self):\n        \"\"\"Remove all private elements from the :class:`Dataset`.\"\"\"\n\n        def RemoveCallback(dataset, data_element):\n            \"\"\"Internal method to use as callback to walk() method.\"\"\"\n            if data_element.tag.is_private:\n                # can't del self[tag] - won't be right dataset on recursion\n                del dataset[data_element.tag]\n\n        self.walk(RemoveCallback)\n\n    def save_as(self, filename, write_like_original=True):\n        \"\"\"Write the :class:`Dataset` to `filename`.\n\n        Wrapper for pydicom.filewriter.dcmwrite, passing this dataset to it.\n        See documentation for that function for details.\n\n        See Also\n        --------\n        pydicom.filewriter.dcmwrite\n            Write a DICOM file from a :class:`FileDataset` instance.\n        \"\"\"\n        pydicom.dcmwrite(filename, self, write_like_original)\n\n    def ensure_file_meta(self):\n        \"\"\"Create an empty ``Dataset.file_meta`` if none exists.\n\n        .. versionadded:: 1.2\n        \"\"\"\n        # Changed in v2.0 so does not re-assign self.file_meta with getattr()\n        if not hasattr(self, \"file_meta\"):\n            self.file_meta = FileMetaDataset()\n\n    def fix_meta_info(self, enforce_standard=True):\n        \"\"\"Ensure the file meta info exists and has the correct values\n        for transfer syntax and media storage UIDs.\n\n        .. versionadded:: 1.2\n\n        .. warning::\n\n            The transfer syntax for ``is_implicit_VR = False`` and\n            ``is_little_endian = True`` is ambiguous and will therefore not\n            be set.\n\n        Parameters\n        ----------\n        enforce_standard : bool, optional\n            If ``True``, a check for incorrect and missing elements is\n            performed (see :func:`~validate_file_meta`).\n        \"\"\"\n        self.ensure_file_meta()\n\n        if self.is_little_endian and self.is_implicit_VR:\n            self.file_meta.TransferSyntaxUID = ImplicitVRLittleEndian\n        elif not self.is_little_endian and not self.is_implicit_VR:\n            self.file_meta.TransferSyntaxUID = ExplicitVRBigEndian\n        elif not self.is_little_endian and self.is_implicit_VR:\n            raise NotImplementedError(\"Implicit VR Big Endian is not a \"\n                                      \"supported Transfer Syntax.\")\n\n        if 'SOPClassUID' in self:\n            self.file_meta.MediaStorageSOPClassUID = self.SOPClassUID\n        if 'SOPInstanceUID' in self:\n            self.file_meta.MediaStorageSOPInstanceUID = self.SOPInstanceUID\n        if enforce_standard:\n            validate_file_meta(self.file_meta, enforce_standard=True)\n\n    def __setattr__(self, name, value):\n        \"\"\"Intercept any attempts to set a value for an instance attribute.\n\n        If name is a DICOM keyword, set the corresponding tag and DataElement.\n        Else, set an instance (python) attribute as any other class would do.\n\n        Parameters\n        ----------\n        name : str\n            The keyword for the element you wish to add/change. If\n            `name` is not a DICOM element keyword then this will be the\n            name of the attribute to be added/changed.\n        value\n            The value for the attribute to be added/changed.\n        \"\"\"\n        tag = tag_for_keyword(name)\n        if tag is not None:  # successfully mapped name to a tag\n            if tag not in self:\n                # don't have this tag yet->create the data_element instance\n                VR = dictionary_VR(tag)\n                data_element = DataElement(tag, VR, value)\n                if VR == 'SQ':\n                    # let a sequence know its parent dataset to pass it\n                    # to its items, who may need parent dataset tags\n                    # to resolve ambiguous tags\n                    data_element.parent = self\n            else:\n                # already have this data_element, just changing its value\n                data_element = self[tag]\n                data_element.value = value\n            # Now have data_element - store it in this dict\n            self[tag] = data_element\n        elif repeater_has_keyword(name):\n            # Check if `name` is repeaters element\n            raise ValueError('{} is a DICOM repeating group '\n                             'element and must be added using '\n                             'the add() or add_new() methods.'\n                             .format(name))\n        elif name == \"file_meta\":\n            self._set_file_meta(value)\n        else:\n            # name not in dicom dictionary - setting a non-dicom instance\n            # attribute\n            # XXX note if user mis-spells a dicom data_element - no error!!!\n            object.__setattr__(self, name, value)\n\n    def _set_file_meta(self, value):\n        if value is not None and not isinstance(value, FileMetaDataset):\n            FileMetaDataset.validate(value)\n            warnings.warn(\n                \"Starting in pydicom 3.0, Dataset.file_meta must be a \"\n                \"FileMetaDataset class instance\",\n                DeprecationWarning\n            )\n\n        self.__dict__[\"file_meta\"] = value\n\n    def __setitem__(self, key, value):\n        \"\"\"Operator for Dataset[key] = value.\n\n        Check consistency, and deal with private tags.\n\n        Parameters\n        ----------\n        key : int or Tuple[int, int] or str\n            The tag for the element to be added to the Dataset.\n        value : dataelem.DataElement or dataelem.RawDataElement\n            The element to add to the :class:`Dataset`.\n\n        Raises\n        ------\n        NotImplementedError\n            If `key` is a ``slice``.\n        ValueError\n            If the `key` value doesn't match ``DataElement.tag``.\n        \"\"\"\n        if isinstance(key, slice):\n            raise NotImplementedError('Slicing is not supported for setting '\n                                      'Dataset elements.')\n\n        # OK if is subclass, e.g. DeferredDataElement\n        if not isinstance(value, (DataElement, RawDataElement)):\n            raise TypeError(\"Dataset contents must be DataElement instances.\")\n        if isinstance(value.tag, BaseTag):\n            tag = value.tag\n        else:\n            tag = Tag(value.tag)\n        if key != tag:\n            raise ValueError(\"DataElement.tag must match the dictionary key\")\n\n        data_element = value\n        if tag.is_private:\n            # See PS 3.5-2008 section 7.8.1 (p. 44) for how blocks are reserved\n            logger.debug(\"Setting private tag %r\" % tag)\n            private_block = tag.elem >> 8\n            private_creator_tag = Tag(tag.group, private_block)\n            if private_creator_tag in self and tag != private_creator_tag:\n                if data_element.is_raw:\n                    data_element = DataElement_from_raw(\n                        data_element, self._character_set)\n                data_element.private_creator = self[private_creator_tag].value\n        self._dict[tag] = data_element\n\n    def _slice_dataset(self, start, stop, step):\n        \"\"\"Return the element tags in the Dataset that match the slice.\n\n        Parameters\n        ----------\n        start : int or 2-tuple of int or None\n            The slice's starting element tag value, in any format accepted by\n            :func:`~pydicom.tag.Tag`.\n        stop : int or 2-tuple of int or None\n            The slice's stopping element tag value, in any format accepted by\n            :func:`~pydicom.tag.Tag`.\n        step : int or None\n            The slice's step size.\n\n        Returns\n        ------\n        list of BaseTag\n            The tags in the :class:`Dataset` that meet the conditions of the\n            slice.\n        \"\"\"\n        # Check the starting/stopping Tags are valid when used\n        if start is not None:\n            start = Tag(start)\n        if stop is not None:\n            stop = Tag(stop)\n\n        all_tags = sorted(self._dict.keys())\n        # If the Dataset is empty, return an empty list\n        if not all_tags:\n            return []\n\n        # Special case the common situations:\n        #   - start and/or stop are None\n        #   - step is 1\n\n        if start is None:\n            if stop is None:\n                # For step=1 avoid copying the list\n                return all_tags if step == 1 else all_tags[::step]\n            else:  # Have a stop value, get values until that point\n                step1_list = list(takewhile(lambda x: x < stop, all_tags))\n                return step1_list if step == 1 else step1_list[::step]\n\n        # Have a non-None start value.  Find its index\n        i_start = bisect_left(all_tags, start)\n        if stop is None:\n            return all_tags[i_start::step]\n        else:\n            i_stop = bisect_left(all_tags, stop)\n            return all_tags[i_start:i_stop:step]\n\n    def __str__(self):\n        \"\"\"Handle str(dataset).\n\n        ..versionchanged:: 2.0\n\n            The file meta information was added in its own section,\n            if :data:`pydicom.config.show_file_meta` is ``True``\n\n        \"\"\"\n        return self._pretty_str()\n\n    def top(self):\n        \"\"\"Return a :class:`str` representation of the top level elements. \"\"\"\n        return self._pretty_str(top_level_only=True)\n\n    def trait_names(self):\n        \"\"\"Return a :class:`list` of valid names for auto-completion code.\n\n        Used in IPython, so that data element names can be found and offered\n        for autocompletion on the IPython command line.\n        \"\"\"\n        return dir(self)  # only valid python >=2.6, else use self.__dir__()\n\n    def update(self, dictionary):\n        \"\"\"Extend :meth:`dict.update` to handle DICOM tags and keywords.\n\n        Parameters\n        ----------\n        dictionary : dict or Dataset\n            The :class:`dict` or :class:`Dataset` to use when updating the\n            current object.\n        \"\"\"\n        for key, value in list(dictionary.items()):\n            if isinstance(key, str):\n                setattr(self, key, value)\n            else:\n                self[Tag(key)] = value\n\n    def iterall(self):\n        \"\"\"Iterate through the :class:`Dataset`, yielding all the elements.\n\n        Unlike ``Dataset.__iter__()``, this *does* recurse into sequences,\n        and so yields all elements as if the file were \"flattened\".\n\n        Yields\n        ------\n        dataelem.DataElement\n        \"\"\"\n        for data_element in self:\n            yield data_element\n            if data_element.VR == \"SQ\":\n                sequence = data_element.value\n                for dataset in sequence:\n                    for elem in dataset.iterall():\n                        yield elem\n\n    def walk(self, callback, recursive=True):\n        \"\"\"Iterate through the :class:`Dataset's<Dataset>` elements and run\n        `callback` on each.\n\n        Visit all elements in the :class:`Dataset`, possibly recursing into\n        sequences and their items. The `callback` function is called for each\n        :class:`~pydicom.dataelem.DataElement` (including elements\n        with a VR of 'SQ'). Can be used to perform an operation on certain\n        types of elements.\n\n        For example,\n        :meth:`~Dataset.remove_private_tags` finds all elements with private\n        tags and deletes them.\n\n        The elements will be returned in order of increasing tag number within\n        their current :class:`Dataset`.\n\n        Parameters\n        ----------\n        callback\n            A callable function that takes two arguments:\n\n            * a :class:`Dataset`\n            * a :class:`~pydicom.dataelem.DataElement` belonging\n              to that :class:`Dataset`\n\n        recursive : bool, optional\n            Flag to indicate whether to recurse into sequences (default\n            ``True``).\n        \"\"\"\n        taglist = sorted(self._dict.keys())\n        for tag in taglist:\n\n            with tag_in_exception(tag):\n                data_element = self[tag]\n                callback(self, data_element)  # self = this Dataset\n                # 'tag in self' below needed in case callback deleted\n                # data_element\n                if recursive and tag in self and data_element.VR == \"SQ\":\n                    sequence = data_element.value\n                    for dataset in sequence:\n                        dataset.walk(callback)\n\n    @classmethod\n    def from_json(cls, json_dataset, bulk_data_uri_handler=None):\n        \"\"\"Add elements to the :class:`Dataset` from DICOM JSON format.\n\n        .. versionadded:: 1.3\n\n        See the DICOM Standard, Part 18, :dcm:`Annex F<part18/chapter_F.html>`.\n\n        Parameters\n        ----------\n        json_dataset : dict or str\n            :class:`dict` or :class:`str` representing a DICOM Data Set\n            formatted based on the DICOM JSON Model.\n        bulk_data_uri_handler : callable, optional\n            Callable function that accepts the \"BulkDataURI\" of the JSON\n            representation of a data element and returns the actual value of\n            data element (retrieved via DICOMweb WADO-RS).\n\n        Returns\n        -------\n        Dataset\n        \"\"\"\n        if not isinstance(json_dataset, dict):\n            json_dataset = json.loads(json_dataset)\n        dataset = cls()\n        for tag, mapping in json_dataset.items():\n            vr = mapping['vr']\n            unique_value_keys = tuple(\n                set(mapping.keys()) & set(jsonrep.JSON_VALUE_KEYS)\n            )\n            if len(unique_value_keys) == 0:\n                value_key = None\n                value = ['']\n            else:\n                value_key = unique_value_keys[0]\n                value = mapping[value_key]\n            data_element = DataElement.from_json(\n                cls, tag, vr, value, value_key, bulk_data_uri_handler\n            )\n            dataset.add(data_element)\n        return dataset\n\n    def to_json_dict(self, bulk_data_threshold=1024,\n                     bulk_data_element_handler=None):\n        \"\"\"Return a dictionary representation of the :class:`Dataset`\n        conforming to the DICOM JSON Model as described in the DICOM\n        Standard, Part 18, :dcm:`Annex F<part18/chapter_F.html>`.\n\n        .. versionadded:: 1.4\n\n        Parameters\n        ----------\n        bulk_data_threshold : int, optional\n            Threshold for the length of a base64-encoded binary data element\n            above which the element should be considered bulk data and the\n            value provided as a URI rather than included inline (default:\n            ``1024``). Ignored if no bulk data handler is given.\n        bulk_data_element_handler : callable, optional\n            Callable function that accepts a bulk data element and returns a\n            JSON representation of the data element (dictionary including the\n            \"vr\" key and either the \"InlineBinary\" or the \"BulkDataURI\" key).\n\n        Returns\n        -------\n        dict\n            :class:`Dataset` representation based on the DICOM JSON Model.\n        \"\"\"\n        json_dataset = {}\n        for key in self.keys():\n            json_key = '{:08X}'.format(key)\n            data_element = self[key]\n            json_dataset[json_key] = data_element.to_json_dict(\n                bulk_data_element_handler=bulk_data_element_handler,\n                bulk_data_threshold=bulk_data_threshold\n            )\n        return json_dataset\n\n    def to_json(self, bulk_data_threshold=1024, bulk_data_element_handler=None,\n                dump_handler=None):\n        \"\"\"Return a JSON representation of the :class:`Dataset`.\n\n        .. versionadded:: 1.3\n\n        See the DICOM Standard, Part 18, :dcm:`Annex F<part18/chapter_F.html>`.\n\n        Parameters\n        ----------\n        bulk_data_threshold : int, optional\n            Threshold for the length of a base64-encoded binary data element\n            above which the element should be considered bulk data and the\n            value provided as a URI rather than included inline (default:\n            ``1024``). Ignored if no bulk data handler is given.\n        bulk_data_element_handler : callable, optional\n            Callable function that accepts a bulk data element and returns a\n            JSON representation of the data element (dictionary including the\n            \"vr\" key and either the \"InlineBinary\" or the \"BulkDataURI\" key).\n        dump_handler : callable, optional\n            Callable function that accepts a :class:`dict` and returns the\n            serialized (dumped) JSON string (by default uses\n            :func:`json.dumps`).\n\n            .. note:\n\n                Make sure to use a dump handler that sorts the keys (see\n                example below) to create DICOM-conformant JSON.\n\n        Returns\n        -------\n        str\n            :class:`Dataset` serialized into a string based on the DICOM JSON\n            Model.\n\n        Examples\n        --------\n        >>> def my_json_dumps(data):\n        ...     return json.dumps(data, indent=4, sort_keys=True)\n        >>> ds.to_json(dump_handler=my_json_dumps)\n        \"\"\"\n        if dump_handler is None:\n            def json_dump(d):\n                return json.dumps(d, sort_keys=True)\n\n            dump_handler = json_dump\n\n        return dump_handler(\n            self.to_json_dict(bulk_data_threshold, bulk_data_element_handler))\n\n    __repr__ = __str__\n\n\nclass FileDataset(Dataset):\n    \"\"\"An extension of :class:`Dataset` to make reading and writing to\n    file-like easier.\n\n    Attributes\n    ----------\n    preamble : str or bytes or None\n        The optional DICOM preamble prepended to the :class:`FileDataset`, if\n        available.\n    file_meta : FileMetaDataset or None\n        The Dataset's file meta information as a :class:`FileMetaDataset`,\n        if available (``None`` if not present).\n        Consists of group ``0x0002`` elements.\n    filename : str or None\n        The filename that the :class:`FileDataset` was read from (if read from\n        file) or ``None`` if the filename is not available (if read from a\n        :class:`io.BytesIO` or  similar).\n    fileobj_type\n        The object type of the file-like the :class:`FileDataset` was read\n        from.\n    is_implicit_VR : bool\n        ``True`` if the dataset encoding is implicit VR, ``False`` otherwise.\n    is_little_endian : bool\n        ``True`` if the dataset encoding is little endian byte ordering,\n        ``False`` otherwise.\n    timestamp : float or None\n        The modification time of the file the :class:`FileDataset` was read\n        from, ``None`` if the modification time is not available.\n    \"\"\"\n\n    def __init__(self,\n                 filename_or_obj,\n                 dataset,\n                 preamble=None,\n                 file_meta=None,\n                 is_implicit_VR=True,\n                 is_little_endian=True):\n        \"\"\"Initialize a :class:`FileDataset` read from a DICOM file.\n\n        Parameters\n        ----------\n        filename_or_obj : str or PathLike or BytesIO or None\n            Full path and filename to the file, memory buffer object, or\n            ``None`` if is a :class:`io.BytesIO`.\n        dataset : Dataset or dict\n            Some form of dictionary, usually a :class:`Dataset` returned from\n            :func:`~pydicom.filereader.dcmread`.\n        preamble : bytes or str, optional\n            The 128-byte DICOM preamble.\n        file_meta : Dataset, optional\n            The file meta :class:`Dataset`, such as the one returned by\n            :func:`~pydicom.filereader.read_file_meta_info`, or an empty\n            :class:`Dataset` if no file meta information is in the file.\n        is_implicit_VR : bool, optional\n            ``True`` (default) if implicit VR transfer syntax used; ``False``\n            if explicit VR.\n        is_little_endian : bool\n            ``True`` (default) if little-endian transfer syntax used; ``False``\n            if big-endian.\n        \"\"\"\n        Dataset.__init__(self, dataset)\n        self.preamble = preamble\n        self.file_meta = file_meta\n        self.is_implicit_VR = is_implicit_VR\n        self.is_little_endian = is_little_endian\n        filename = None\n        filename_or_obj = path_from_pathlike(filename_or_obj)\n        if isinstance(filename_or_obj, str):\n            filename = filename_or_obj\n            self.fileobj_type = open\n        elif isinstance(filename_or_obj, io.BufferedReader):\n            filename = filename_or_obj.name\n            # This is the appropriate constructor for io.BufferedReader\n            self.fileobj_type = open\n        else:\n            # use __class__ python <2.7?;\n            # http://docs.python.org/reference/datamodel.html\n            self.fileobj_type = filename_or_obj.__class__\n            if getattr(filename_or_obj, \"name\", False):\n                filename = filename_or_obj.name\n            elif getattr(filename_or_obj, \"filename\",\n                         False):  # gzip python <2.7?\n                filename = filename_or_obj.filename\n            else:\n                # e.g. came from BytesIO or something file-like\n                self.filename = filename_or_obj\n\n        self.timestamp = None\n        if filename:\n            self.filename = filename\n            if os.path.exists(filename):\n                statinfo = os.stat(filename)\n                self.timestamp = statinfo.st_mtime\n\n    def __eq__(self, other):\n        \"\"\"Compare `self` and `other` for equality.\n\n        Returns\n        -------\n        bool\n            The result if `self` and `other` are the same class\n        NotImplemented\n            If `other` is not the same class as `self` then returning\n            :class:`NotImplemented` delegates the result to\n            ``superclass.__eq__(subclass)``.\n        \"\"\"\n        # When comparing against self this will be faster\n        if other is self:\n            return True\n\n        if isinstance(other, self.__class__):\n            return (_dict_equal(self, other) and\n                    _dict_equal(self.__dict__, other.__dict__,\n                                exclude=['_dict'])\n                    )\n\n        return NotImplemented\n\n\ndef validate_file_meta(file_meta, enforce_standard=True):\n    \"\"\"Validate the *File Meta Information* elements in `file_meta`.\n\n    .. versionchanged:: 1.2\n\n        Moved from :mod:`pydicom.filewriter`.\n\n    Parameters\n    ----------\n    file_meta : Dataset\n        The *File Meta Information* data elements.\n    enforce_standard : bool, optional\n        If ``False``, then only a check for invalid elements is performed.\n        If ``True`` (default), the following elements will be added if not\n        already present:\n\n        * (0002,0001) *File Meta Information Version*\n        * (0002,0012) *Implementation Class UID*\n        * (0002,0013) *Implementation Version Name*\n\n        and the following elements will be checked:\n\n        * (0002,0002) *Media Storage SOP Class UID*\n        * (0002,0003) *Media Storage SOP Instance UID*\n        * (0002,0010) *Transfer Syntax UID*\n\n    Raises\n    ------\n    ValueError\n        If `enforce_standard` is ``True`` and any of the checked *File Meta\n        Information* elements are missing from `file_meta`.\n    ValueError\n        If any non-Group 2 Elements are present in `file_meta`.\n    \"\"\"\n    # Check that no non-Group 2 Elements are present\n    for elem in file_meta.elements():\n        if elem.tag.group != 0x0002:\n            raise ValueError(\"Only File Meta Information Group (0002,eeee) \"\n                             \"elements must be present in 'file_meta'.\")\n\n    if enforce_standard:\n        if 'FileMetaInformationVersion' not in file_meta:\n            file_meta.FileMetaInformationVersion = b'\\x00\\x01'\n\n        if 'ImplementationClassUID' not in file_meta:\n            file_meta.ImplementationClassUID = PYDICOM_IMPLEMENTATION_UID\n\n        if 'ImplementationVersionName' not in file_meta:\n            file_meta.ImplementationVersionName = (\n                'PYDICOM ' + \".\".join(str(x) for x in __version_info__))\n\n        # Check that required File Meta Information elements are present\n        missing = []\n        for element in [0x0002, 0x0003, 0x0010]:\n            if Tag(0x0002, element) not in file_meta:\n                missing.append(Tag(0x0002, element))\n        if missing:\n            msg = (\"Missing required File Meta Information elements from \"\n                   \"'file_meta':\\n\")\n            for tag in missing:\n                msg += '\\t{0} {1}\\n'.format(tag, keyword_for_tag(tag))\n            raise ValueError(msg[:-1])  # Remove final newline\n\n\nclass FileMetaDataset(Dataset):\n    \"\"\"Contains a collection (dictionary) of group 2 DICOM Data Elements.\n\n    .. versionadded:: 2.0\n\n    Derived from :class:`~pydicom.dataset.Dataset`, but only allows\n    Group 2 (File Meta Information) data elements\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Initialize a FileMetaDataset\n\n        Parameters are as per :class:`Dataset`; this overrides the super class\n        only to check that all are group 2 data elements\n\n        Raises\n        ------\n        ValueError\n            If any data elements are not group 2.\n        TypeError\n            If the passed argument is not a :class:`dict` or :class:`Dataset`\n        \"\"\"\n        super().__init__(*args, **kwargs)\n        FileMetaDataset.validate(self._dict)\n\n    @staticmethod\n    def validate(init_value):\n        \"\"\"Raise errors if initialization value is not acceptable for file_meta\n\n        Parameters\n        ----------\n        init_value: dict or Dataset\n            The tag:data element pairs to initialize a file meta dataset\n\n        Raises\n        ------\n        TypeError\n            If the passed argument is not a :class:`dict` or :class:`Dataset`\n        ValueError\n            If any data elements passed are not group 2.\n        \"\"\"\n        if init_value is None:\n            return\n\n        if not isinstance(init_value, (Dataset, dict)):\n            raise TypeError(\n                \"Argument must be a dict or Dataset, not {}\".format(\n                    type(init_value)\n                )\n            )\n\n        non_group2 = [\n            Tag(tag) for tag in init_value.keys() if Tag(tag).group != 2\n        ]\n        if non_group2:\n            msg = \"Attempted to set non-group 2 elements: {}\"\n            raise ValueError(msg.format(non_group2))\n\n    def __setitem__(self, key, value):\n        \"\"\"Override parent class to only allow setting of group 2 elements.\n\n        Parameters\n        ----------\n        key : int or Tuple[int, int] or str\n            The tag for the element to be added to the Dataset.\n        value : dataelem.DataElement or dataelem.RawDataElement\n            The element to add to the :class:`FileMetaDataset`.\n\n        Raises\n        ------\n        ValueError\n            If `key` is not a DICOM Group 2 tag.\n        \"\"\"\n\n        if isinstance(value.tag, BaseTag):\n            tag = value.tag\n        else:\n            tag = Tag(value.tag)\n\n        if tag.group != 2:\n            raise ValueError(\n                \"Only group 2 data elements are allowed in a FileMetaDataset\"\n            )\n\n        super().__setitem__(key, value)\n","header":{"file":{"path":"pydicom/dataset.py"},"misc_line":null},"index_line":null,"is_binary_file":false,"binary_line":null,"minus_file":{"path":"a/pydicom/dataset.py"},"plus_file":{"path":"b/pydicom/dataset.py"},"hunks":[{"descriptor":{"old_range":{"start":2492,"length":8},"new_range":{"start":2492,"length":8},"section":"def to_json_dict("},"line_group":{"all_lines":[{"content":"        json_dataset = {}","type":"context"},{"content":"        for key in self.keys():","type":"context"},{"content":"            json_key = '{:08X}'.format(key)","type":"context"},{"content":"            data_element = self[key]","type":"deleted"},{"content":"            try:","type":"context"},{"content":"                data_element = self[key]","type":"added"},{"content":"                json_dataset[json_key] = data_element.to_json_dict(","type":"context"},{"content":"                    bulk_data_element_handler=bulk_data_element_handler,","type":"context"},{"content":"                    bulk_data_threshold=bulk_data_threshold","type":"context"},{"content":"","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]}]}],"old_commit_hash":"f8cf45b6c121e5a4bf4a43f71aba3bc64af3db9c","new_commit_hash":"2e9301e8801e6e30c71ccf6833ec2562420bfbbd","commit_message":"next() no longer starts iterator","commit_date":"2020-06-29T10:45:31+02:00","metadata":{}}