prompt: 
  We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Make PersonName3 iterable
  ```python
  from pydicom import Dataset
  
  ds = Dataset()
  ds.PatientName = 'SomeName'
  
  'S' in ds.PatientName
  ```
  ```
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  TypeError: argument of type 'PersonName3' is not iterable
  ```
  
  I'm not really sure if this is intentional or if PN elements should support `str` methods. And yes I know I can `str(ds.PatientName)` but it's a bit silly, especially when I keep having to write exceptions to my element iterators just for PN elements.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  
  --- BEGIN FILE ---
  ```
  ### pydicom/valuerep.py
  # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
  """Special classes for DICOM value representations (VR)"""
  from copy import deepcopy
  from decimal import Decimal
  import re
  
  from datetime import (date, datetime, time, timedelta, timezone)
  
  # don't import datetime_conversion directly
  from pydicom import config
  from pydicom.multival import MultiValue
  
  # can't import from charset or get circular import
  default_encoding = "iso8859"
  
  # For reading/writing data elements,
  # these ones have longer explicit VR format
  # Taken from PS3.5 Section 7.1.2
  extra_length_VRs = ('OB', 'OD', 'OF', 'OL', 'OW', 'SQ', 'UC', 'UN', 'UR', 'UT')
  
  # VRs that can be affected by character repertoire
  # in (0008,0005) Specific Character Set
  # See PS-3.5 (2011), section 6.1.2 Graphic Characters
  # and PN, but it is handled separately.
  text_VRs = ('SH', 'LO', 'ST', 'LT', 'UC', 'UT')
  
  # Delimiters for text strings and person name that reset the encoding.
  # See PS3.5, Section 6.1.2.5.3
  # Note: We use character codes for Python 3
  # because those are the types yielded if iterating over a byte string.
  
  # Characters/Character codes for text VR delimiters: LF, CR, TAB, FF
  TEXT_VR_DELIMS = {0x0d, 0x0a, 0x09, 0x0c}
  
  # Character/Character code for PN delimiter: name part separator '^'
  # (the component separator '=' is handled separately)
  PN_DELIMS = {0xe5}
  
  
  class DA(date):
      """Store value for an element with VR **DA** as :class:`datetime.date`.
  
      Note that the :class:`datetime.date` base class is immutable.
      """
      __slots__ = ['original_string']
  
      def __getstate__(self):
          return dict((slot, getattr(self, slot)) for slot in self.__slots__
                      if hasattr(self, slot))
  
      def __setstate__(self, state):
          for slot, value in state.items():
              setattr(self, slot, value)
  
      def __reduce__(self):
          return super(DA, self).__reduce__() + (self.__getstate__(),)
  
      def __reduce_ex__(self, protocol):
          return super(DA, self).__reduce__() + (self.__getstate__(),)
  
      def __new__(cls, val):
          """Create an instance of DA object.
  
          Raise an exception if the string cannot be parsed or the argument
          is otherwise incompatible.
  
          Parameters
          ----------
          val : str
              A string conformant to the DA definition in the DICOM Standard,
              Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.
          """
          if isinstance(val, str):
              if len(val) == 8:
                  year = int(val[0:4])
                  month = int(val[4:6])
                  day = int(val[6:8])
                  val = super(DA, cls).__new__(cls, year, month, day)
              elif len(val) == 10 and val[4] == '.' and val[7] == '.':
                  # ACR-NEMA Standard 300, predecessor to DICOM
                  # for compatibility with a few old pydicom example files
                  year = int(val[0:4])
                  month = int(val[5:7])
                  day = int(val[8:10])
                  val = super(DA, cls).__new__(cls, year, month, day)
              elif val == '':
                  val = None  # empty date
              else:
                  try:
                      val = super(DA, cls).__new__(cls, val)
                  except TypeError:
                      raise ValueError("Cannot convert to datetime: '%s'" %
                                       (val))
          elif isinstance(val, date):
              val = super(DA, cls).__new__(cls, val.year, val.month, val.day)
          else:
              val = super(DA, cls).__new__(cls, val)
          return val
  
      def __init__(self, val):
          if isinstance(val, str):
              self.original_string = val
          elif isinstance(val, DA) and hasattr(val, 'original_string'):
              self.original_string = val.original_string
  
      def __str__(self):
          if hasattr(self, 'original_string'):
              return self.original_string
          else:
              return super(DA, self).__str__()
  
      def __repr__(self):
          return "\"" + str(self) + "\""
  
  
  class DT(datetime):
      """Store value for an element with VR **DT** as :class:`datetime.datetime`.
  
      Note that the :class:`datetime.datetime` base class is immutable.
      """
      __slots__ = ['original_string']
      _regex_dt = re.compile(r"((\d{4,14})(\.(\d{1,6}))?)([+-]\d{4})?")
  
      def __getstate__(self):
          return dict((slot, getattr(self, slot)) for slot in self.__slots__
                      if hasattr(self, slot))
  
      def __setstate__(self, state):
          for slot, value in state.items():
              setattr(self, slot, value)
  
      def __reduce__(self):
          return super(DT, self).__reduce__() + (self.__getstate__(),)
  
      def __reduce_ex__(self, protocol):
          return super(DT, self).__reduce__() + (self.__getstate__(),)
  
      @staticmethod
      def _utc_offset(offset, name):
          return timezone(timedelta(seconds=offset), name)
  
      def __new__(cls, val):
          """Create an instance of DT object.
  
          Raise an exception if the string cannot be parsed or the argument
          is otherwise incompatible.
  
          Parameters
          ----------
          val : str
              A string conformant to the DT definition in the DICOM Standard,
              Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.
          """
          if isinstance(val, str):
              match = DT._regex_dt.match(val)
              if match and len(val) <= 26:
                  dt_match = match.group(2)
                  year = int(dt_match[0:4])
                  if len(dt_match) < 6:
                      month = 1
                  else:
                      month = int(dt_match[4:6])
                  if len(dt_match) < 8:
                      day = 1
                  else:
                      day = int(dt_match[6:8])
                  if len(dt_match) < 10:
                      hour = 0
                  else:
                      hour = int(dt_match[8:10])
                  if len(dt_match) < 12:
                      minute = 0
                  else:
                      minute = int(dt_match[10:12])
                  if len(dt_match) < 14:
                      second = 0
                      microsecond = 0
                  else:
                      second = int(dt_match[12:14])
                      ms_match = match.group(4)
                      if ms_match:
                          microsecond = int(ms_match.rstrip().ljust(6, '0'))
                      else:
                          microsecond = 0
                  tz_match = match.group(5)
                  if tz_match:
                      offset1 = int(tz_match[1:3]) * 60
                      offset2 = int(tz_match[3:5])
                      offset = (offset1 + offset2) * 60
                      if tz_match[0] == '-':
                          offset = -offset
                      tzinfo = cls._utc_offset(offset, tz_match)
                  else:
                      tzinfo = None
                  val = super(DT,
                              cls).__new__(cls, year, month, day, hour, minute,
                                           second, microsecond, tzinfo)
              else:
                  try:
                      val = super(DT, cls).__new__(cls, val)
                  except TypeError:
                      raise ValueError("Cannot convert to datetime: '%s'" %
                                       (val))
          elif isinstance(val, datetime):
              val = super(DT, cls).__new__(cls, val.year, val.month, val.day,
                                           val.hour, val.minute, val.second,
                                           val.microsecond, val.tzinfo)
          else:
              val = super(DT, cls).__new__(cls, val)
          return val
  
      def __init__(self, val):
          if isinstance(val, str):
              self.original_string = val
          elif isinstance(val, DT) and hasattr(val, 'original_string'):
              self.original_string = val.original_string
  
      def __str__(self):
          if hasattr(self, 'original_string'):
              return self.original_string
          else:
              return super(DT, self).__str__()
  
      def __repr__(self):
          return "\"" + str(self) + "\""
  
  
  class TM(time):
      """Store value for an element with VR **TM** as :class:`datetime.time`.
  
      Note that the :class:`datetime.time` base class is immutable.
      """
      __slots__ = ['original_string']
      _regex_tm = re.compile(r"(\d{2,6})(\.(\d{1,6}))?")
  
      def __getstate__(self):
          return dict((slot, getattr(self, slot)) for slot in self.__slots__
                      if hasattr(self, slot))
  
      def __setstate__(self, state):
          for slot, value in state.items():
              setattr(self, slot, value)
  
      def __reduce__(self):
          return super(TM, self).__reduce__() + (self.__getstate__(),)
  
      def __reduce_ex__(self, protocol):
          return super(TM, self).__reduce__() + (self.__getstate__(),)
  
      def __new__(cls, val):
          """Create an instance of TM object from a string.
  
          Raise an exception if the string cannot be parsed or the argument
          is otherwise incompatible.
  
          Parameters
          ----------
          val : str
              A string conformant to the TM definition in the DICOM Standard,
              Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.
          """
          if isinstance(val, str):
              match = TM._regex_tm.match(val)
              if match and len(val) <= 16:
                  tm_match = match.group(1)
                  hour = int(tm_match[0:2])
                  if len(tm_match) < 4:
                      minute = 0
                  else:
                      minute = int(tm_match[2:4])
                  if len(tm_match) < 6:
                      second = 0
                      microsecond = 0
                  else:
                      second = int(tm_match[4:6])
                      ms_match = match.group(3)
                      if ms_match:
                          microsecond = int(ms_match.rstrip().ljust(6, '0'))
                      else:
                          microsecond = 0
                  val = super(TM, cls).__new__(cls, hour, minute, second,
                                               microsecond)
              elif val == '':
                  val = None  # empty time
              else:
                  try:
                      val = super(TM, cls).__new__(cls, val)
                  except TypeError:
                      raise ValueError("Cannot convert to datetime: '%s" % (val))
          elif isinstance(val, time):
              val = super(TM, cls).__new__(cls, val.hour, val.minute, val.second,
                                           val.microsecond)
          else:
              val = super(TM, cls).__new__(cls, val)
          return val
  
      def __init__(self, val):
          if isinstance(val, str):
              self.original_string = val
          elif isinstance(val, TM) and hasattr(val, 'original_string'):
              self.original_string = val.original_string
  
      def __str__(self):
          if hasattr(self, 'original_string'):
              return self.original_string
          else:
              return super(TM, self).__str__()
  
      def __repr__(self):
          return "\"" + str(self) + "\""
  
  
  class DSfloat(float):
      """Store value for an element with VR **DS** as :class:`float`.
  
      If constructed from an empty string, return the empty string,
      not an instance of this class.
  
      """
      __slots__ = ['original_string']
  
      def __getstate__(self):
          return dict((slot, getattr(self, slot)) for slot in self.__slots__
                      if hasattr(self, slot))
  
      def __setstate__(self, state):
          for slot, value in state.items():
              setattr(self, slot, value)
  
      def __init__(self, val):
          """Store the original string if one given, for exact write-out of same
          value later.
          """
          # ... also if user changes a data element value, then will get
          # a different object, because float is immutable.
  
          has_attribute = hasattr(val, 'original_string')
          if isinstance(val, str):
              self.original_string = val
          elif isinstance(val, (DSfloat, DSdecimal)) and has_attribute:
              self.original_string = val.original_string
  
      def __str__(self):
          if hasattr(self, 'original_string'):
              return self.original_string
  
          # Issue #937 (Python 3.8 compatibility)
          return repr(self)[1:-1]
  
      def __repr__(self):
          return '"{}"'.format(super(DSfloat, self).__repr__())
  
  
  class DSdecimal(Decimal):
      """Store value for an element with VR **DS** as :class:`decimal.Decimal`.
  
      Notes
      -----
      If constructed from an empty string, returns the empty string, not an
      instance of this class.
      """
      __slots__ = ['original_string']
  
      def __getstate__(self):
          return dict((slot, getattr(self, slot)) for slot in self.__slots__
                      if hasattr(self, slot))
  
      def __setstate__(self, state):
          for slot, value in state.items():
              setattr(self, slot, value)
  
      def __new__(cls, val):
          """Create an instance of DS object, or return a blank string if one is
          passed in, e.g. from a type 2 DICOM blank value.
  
          Parameters
          ----------
          val : str or numeric
              A string or a number type which can be converted to a decimal.
          """
          # Store this value here so that if the input string is actually a valid
          # string but decimal.Decimal transforms it to an invalid string it will
          # still be initialized properly
          enforce_length = config.enforce_valid_values
          # DICOM allows spaces around the string,
          # but python doesn't, so clean it
          if isinstance(val, str):
              val = val.strip()
              # If the input string is actually invalid that we relax the valid
              # value constraint for this particular instance
              if len(val) <= 16:
                  enforce_length = False
          if val == '':
              return val
          if isinstance(val, float) and not config.allow_DS_float:
              msg = ("DS cannot be instantiated with a float value, "
                     "unless config.allow_DS_float is set to True. "
                     "It is recommended to convert to a string instead, "
                     "with the desired number of digits, or use "
                     "Decimal.quantize and pass a Decimal instance.")
              raise TypeError(msg)
          if not isinstance(val, Decimal):
              val = super(DSdecimal, cls).__new__(cls, val)
          if len(str(val)) > 16 and enforce_length:
              msg = ("DS value representation must be <= 16 "
                     "characters by DICOM standard. Initialize with "
                     "a smaller string, or set config.enforce_valid_values "
                     "to False to override, or use Decimal.quantize() and "
                     "initialize with a Decimal instance.")
              raise OverflowError(msg)
          return val
  
      def __init__(self, val):
          """Store the original string if one given, for exact write-out of same
          value later. E.g. if set ``'1.23e2'``, :class:`~decimal.Decimal` would
          write ``'123'``, but :class:`DS` will use the original.
          """
          # ... also if user changes a data element value, then will get
          # a different Decimal, as Decimal is immutable.
          if isinstance(val, str):
              self.original_string = val
          elif isinstance(val, (DSfloat, DSdecimal)) and hasattr(val, 'original_string'):  # noqa
              self.original_string = val.original_string
  
      def __str__(self):
          if hasattr(self, 'original_string') and len(self.original_string) <= 16:  # noqa
              return self.original_string
          else:
              return super(DSdecimal, self).__str__()
  
      def __repr__(self):
          return "\"" + str(self) + "\""
  
  
  # CHOOSE TYPE OF DS
  if config.use_DS_decimal:
      DSclass = DSdecimal
  else:
      DSclass = DSfloat
  
  
  def DS(val):
      """Factory function for creating DS class instances.
  
      Checks for blank string; if so, returns that, else calls :class:`DSfloat`
      or :class:`DSdecimal` to create the class instance. This avoids overriding
      ``DSfloat.__new__()`` (which carries a time penalty for large arrays of
      DS).
  
      Similarly the string clean and check can be avoided and :class:`DSfloat`
      called directly if a string has already been processed.
      """
      if isinstance(val, str):
          val = val.strip()
      if val == '' or val is None:
          return val
      return DSclass(val)
  
  
  class IS(int):
      """Store value for an element with VR **IS** as :class:`int`.
  
      Stores original integer string for exact rewriting of the string
      originally read or stored.
      """
  
      def __new__(cls, val):
          """Create instance if new integer string"""
          if val is None:
              return val
          if isinstance(val, str) and val.strip() == '':
              return ''
  
          newval = super(IS, cls).__new__(cls, val)
  
          # check if a float or Decimal passed in, then could have lost info,
          # and will raise error. E.g. IS(Decimal('1')) is ok, but not IS(1.23)
          if isinstance(val, (float, Decimal)) and newval != val:
              raise TypeError("Could not convert value to integer without loss")
          # Checks in case underlying int is >32 bits, DICOM does not allow this
          check_newval = (newval < -2 ** 31 or newval >= 2 ** 31)
          if check_newval and config.enforce_valid_values:
              dcm_limit = "-2**31 to (2**31 - 1) for IS"
              message = "Value exceeds DICOM limits of %s" % (dcm_limit)
              raise OverflowError(message)
          return newval
  
      def __init__(self, val):
          # If a string passed, then store it
          if isinstance(val, str):
              self.original_string = val
          elif isinstance(val, IS) and hasattr(val, 'original_string'):
              self.original_string = val.original_string
  
      def __str__(self):
          if hasattr(self, 'original_string'):
              return self.original_string
  
          # Issue #937 (Python 3.8 compatibility)
          return repr(self)[1:-1]
  
      def __repr__(self):
          return '"{}"'.format(super(IS, self).__repr__())
  
  
  def MultiString(val, valtype=str):
      """Split a bytestring by delimiters if there are any
  
      Parameters
      ----------
      val : bytes or str
          DICOM byte string to split up.
      valtype
          Default :class:`str`, but can be e.g. :class:`~pydicom.uid.UID` to
          overwrite to a specific type.
  
      Returns
      -------
      valtype or list of valtype
          The split value as `valtype` or a :class:`list` of `valtype`.
      """
      # Remove trailing blank used to pad to even length
      # 2005.05.25: also check for trailing 0, error made
      # in PET files we are converting
  
      while val and (val.endswith(' ') or val.endswith('\x00')):
          val = val[:-1]
      splitup = val.split("\\")
  
      if len(splitup) == 1:
          val = splitup[0]
          return valtype(val) if val else val
      else:
          return MultiValue(valtype, splitup)
  
  
  def _verify_encodings(encodings):
      """Checks the encoding to ensure proper format"""
      if encodings is not None:
          if not isinstance(encodings, (list, tuple)):
              return encodings,
          return tuple(encodings)
      return encodings
  
  
  def _decode_personname(components, encodings):
      """Return a list of decoded person name components.
  
      Parameters
      ----------
      components : list of byte string
          The list of the up to three encoded person name components
      encodings : list of str
          The Python encodings uses to decode `components`.
  
      Returns
      -------
      text type
          The unicode string representing the person name.
          If the decoding of some component parts is not possible using the
          given encodings, they are decoded with the first encoding using
          replacement characters for bytes that cannot be decoded.
      """
      from pydicom.charset import decode_string
  
      if isinstance(components[0], str):
          comps = components
      else:
          comps = [decode_string(comp, encodings, PN_DELIMS)
                   for comp in components]
      # Remove empty elements from the end to avoid trailing '='
      while len(comps) and not comps[-1]:
          comps.pop()
      return tuple(comps)
  
  
  def _encode_personname(components, encodings):
      """Encode a list of text string person name components.
  
      Parameters
      ----------
      components : list of text type
          The list of the up to three unicode person name components
      encodings : list of str
          The Python encodings uses to encode `components`.
  
      Returns
      -------
      byte string
          The byte string that can be written as a PN DICOM tag value.
          If the encoding of some component parts is not possible using the
          given encodings, they are encoded with the first encoding using
          replacement bytes for characters that cannot be encoded.
      """
      from pydicom.charset import encode_string
  
      encoded_comps = []
      for comp in components:
          groups = [encode_string(group, encodings)
                    for group in comp.split('^')]
          encoded_comps.append(b'^'.join(groups))
  
      # Remove empty elements from the end
      while len(encoded_comps) and not encoded_comps[-1]:
          encoded_comps.pop()
      return b'='.join(encoded_comps)
  
  
  class PersonName:
      def __new__(cls, *args, **kwargs):
          # Handle None value by returning None instead of a PersonName object
          if len(args) and args[0] is None:
              return None
          return super(PersonName, cls).__new__(cls)
  
      def __init__(self, val, encodings=None, original_string=None):
          if isinstance(val, PersonName):
              encodings = val.encodings
              self.original_string = val.original_string
              self._components = tuple(str(val).split('='))
          elif isinstance(val, bytes):
              # this is the raw byte string - decode it on demand
              self.original_string = val
              self._components = None
          else:
              # handle None `val` as empty string
              val = val or ''
  
              # this is the decoded string - save the original string if
              # available for easier writing back
              self.original_string = original_string
              components = val.split('=')
              # Remove empty elements from the end to avoid trailing '='
              while len(components) and not components[-1]:
                  components.pop()
              self._components = tuple(components)
  
              # if the encoding is not given, leave it as undefined (None)
          self.encodings = _verify_encodings(encodings)
          self._dict = {}
  
      def _create_dict(self):
          """Creates a dictionary of person name group and component names.
  
          Used exclusively for `formatted` for backwards compatibility.
          """
          if not self._dict:
              for name in ('family_name', 'given_name', 'middle_name',
                           'name_prefix', 'name_suffix',
                           'ideographic', 'phonetic'):
                  self._dict[name] = getattr(self, name, '')
  
      @property
      def components(self):
          """Returns up to three decoded person name components.
  
          .. versionadded:: 1.2
  
          The returned components represent the alphabetic, ideographic and
          phonetic representations as a list of unicode strings.
          """
          if self._components is None:
              groups = self.original_string.split(b'=')
              encodings = self.encodings or [default_encoding]
              self._components = _decode_personname(groups, encodings)
  
          return self._components
  
      def _name_part(self, i):
          try:
              return self.components[0].split('^')[i]
          except IndexError:
              return ''
  
      @property
      def family_name(self):
          """Return the first (family name) group of the alphabetic person name
          representation as a unicode string
  
          .. versionadded:: 1.2
          """
          return self._name_part(0)
  
      @property
      def given_name(self):
          """Return the second (given name) group of the alphabetic person name
          representation as a unicode string
  
          .. versionadded:: 1.2
          """
          return self._name_part(1)
  
      @property
      def middle_name(self):
          """Return the third (middle name) group of the alphabetic person name
          representation as a unicode string
  
          .. versionadded:: 1.2
          """
          return self._name_part(2)
  
      @property
      def name_prefix(self):
          """Return the fourth (name prefix) group of the alphabetic person name
          representation as a unicode string
  
          .. versionadded:: 1.2
          """
          return self._name_part(3)
  
      @property
      def name_suffix(self):
          """Return the fifth (name suffix) group of the alphabetic person name
          representation as a unicode string
  
          .. versionadded:: 1.2
          """
          return self._name_part(4)
  
      @property
      def ideographic(self):
          """Return the second (ideographic) person name component as a
          unicode string
  
          .. versionadded:: 1.2
          """
          try:
              return self.components[1]
          except IndexError:
              return ''
  
      @property
      def phonetic(self):
          """Return the third (phonetic) person name component as a
          unicode string
  
          .. versionadded:: 1.2
          """
          try:
              return self.components[2]
          except IndexError:
              return ''
  
      def __eq__(self, other):
          return str(self) == other
  
      def __ne__(self, other):
          return not self == other
  
      def __str__(self):
          return '='.join(self.components).__str__()
  
      def __repr__(self):
          return '='.join(self.components).__repr__()
  
      def __hash__(self):
          return hash(self.components)
  
      def decode(self, encodings=None):
          """Return the patient name decoded by the given `encodings`.
  
          Parameters
          ----------
          encodings : list of str
              The list of encodings used for decoding the byte string. If not
              given, the initial encodings set in the object are used.
  
          Returns
          -------
          valuerep.PersonName
              A person name object that will return the decoded string with
              the given encodings on demand. If the encodings are not given,
              the current object is returned.
          """
          # in the common case (encoding did not change) we decode on demand
          if encodings is None or encodings == self.encodings:
              return self
          # the encoding was unknown or incorrect - create a new
          # PersonName object with the changed encoding
          encodings = _verify_encodings(encodings)
          if self.original_string is None:
              # if the original encoding was not set, we set it now
              self.original_string = _encode_personname(
                  self.components, self.encodings or [default_encoding])
          return PersonName(self.original_string, encodings)
  
      def encode(self, encodings=None):
          """Return the patient name decoded by the given `encodings`.
  
          Parameters
          ----------
          encodings : list of str
              The list of encodings used for encoding the unicode string. If
              not given, the initial encodings set in the object are used.
  
          Returns
          -------
          bytes
              The person name encoded with the given encodings as a byte string.
              If no encoding is given, the original byte string is returned, if
              available, otherwise each group of the patient name is encoded
              with the first matching of the given encodings.
          """
          encodings = _verify_encodings(encodings) or self.encodings
  
          # if the encoding is not the original encoding, we have to return
          # a re-encoded string (without updating the original string)
          if encodings != self.encodings and self.encodings is not None:
              return _encode_personname(self.components, encodings)
          if self.original_string is None:
              # if the original encoding was not set, we set it now
              self.original_string = _encode_personname(
                  self.components, encodings or [default_encoding])
          return self.original_string
  
      def family_comma_given(self):
          return self.formatted('%(family_name)s, %(given_name)s')
  
      def formatted(self, format_str):
          self._create_dict()
          return format_str % self._dict
  
      def __bool__(self):
          if self.original_string is None:
              return (bool(self._components) and
                      (len(self._components) > 1 or bool(self._components[0])))
          return bool(self.original_string)
  
  
  # Alias old class names for backwards compat in user code
  PersonNameUnicode = PersonName = PersonName
  
  ```
  --- END FILE ---
  
  Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.
  
  Every *SEARCH/REPLACE* edit must use this format:
  1. The file path
  2. The start of search block: <<<<<<< SEARCH
  3. A contiguous chunk of lines to search for in the existing source code
  4. The dividing line: =======
  5. The lines to replace into the source code
  6. The end of the replace block: >>>>>>> REPLACE
  
  Here is an example:
  
  ```python
  ### mathweb/flask/app.py
  <<<<<<< SEARCH
  from flask import Flask
  =======
  import math
  from flask import Flask
  >>>>>>> REPLACE
  ```
  
  Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
  Wrap the *SEARCH/REPLACE* edit in blocks ```python...```.
  
instance: {"FAIL_TO_PASS": "[\"pydicom/tests/test_valuerep.py::TestPersonName::test_next\", \"pydicom/tests/test_valuerep.py::TestPersonName::test_iterator\", \"pydicom/tests/test_valuerep.py::TestPersonName::test_contains\"]", "PASS_TO_PASS": "[\"pydicom/tests/test_valuerep.py::TestTM::test_pickling\", \"pydicom/tests/test_valuerep.py::TestDT::test_pickling\", \"pydicom/tests/test_valuerep.py::TestDA::test_pickling\", \"pydicom/tests/test_valuerep.py::TestDS::test_empty_value\", \"pydicom/tests/test_valuerep.py::TestDS::test_float_values\", \"pydicom/tests/test_valuerep.py::TestDSfloat::test_pickling\", \"pydicom/tests/test_valuerep.py::TestDSfloat::test_str\", \"pydicom/tests/test_valuerep.py::TestDSfloat::test_repr\", \"pydicom/tests/test_valuerep.py::TestDSdecimal::test_pickling\", \"pydicom/tests/test_valuerep.py::TestDSdecimal::test_float_value\", \"pydicom/tests/test_valuerep.py::TestIS::test_empty_value\", \"pydicom/tests/test_valuerep.py::TestIS::test_valid_value\", \"pydicom/tests/test_valuerep.py::TestIS::test_invalid_value\", \"pydicom/tests/test_valuerep.py::TestIS::test_pickling\", \"pydicom/tests/test_valuerep.py::TestIS::test_longint\", \"pydicom/tests/test_valuerep.py::TestIS::test_overflow\", \"pydicom/tests/test_valuerep.py::TestIS::test_str\", \"pydicom/tests/test_valuerep.py::TestIS::test_repr\", \"pydicom/tests/test_valuerep.py::TestBadValueRead::test_read_bad_value_in_VR_default\", \"pydicom/tests/test_valuerep.py::TestBadValueRead::test_read_bad_value_in_VR_enforce_valid_value\", \"pydicom/tests/test_valuerep.py::TestDecimalString::test_DS_decimal_set\", \"pydicom/tests/test_valuerep.py::TestDecimalString::test_valid_decimal_strings\", \"pydicom/tests/test_valuerep.py::TestDecimalString::test_invalid_decimal_strings\", \"pydicom/tests/test_valuerep.py::TestPersonName::test_last_first\", \"pydicom/tests/test_valuerep.py::TestPersonName::test_copy\", \"pydicom/tests/test_valuerep.py::TestPersonName::test_three_component\", \"pydicom/tests/test_valuerep.py::TestPersonName::test_formatting\", \"pydicom/tests/test_valuerep.py::TestPersonName::test_unicode_kr\", \"pydicom/tests/test_valuerep.py::TestPersonName::test_unicode_jp_from_bytes\", \"pydicom/tests/test_valuerep.py::TestPersonName::test_unicode_jp_from_bytes_comp_delimiter\", \"pydicom/tests/test_valuerep.py::TestPersonName::test_unicode_jp_from_bytes_caret_delimiter\", \"pydicom/tests/test_valuerep.py::TestPersonName::test_unicode_jp_from_unicode\", \"pydicom/tests/test_valuerep.py::TestPersonName::test_not_equal\", \"pydicom/tests/test_valuerep.py::TestPersonName::test_encoding_carried\", \"pydicom/tests/test_valuerep.py::TestPersonName::test_hash\", \"pydicom/tests/test_valuerep.py::TestDateTime::test_date\", \"pydicom/tests/test_valuerep.py::TestDateTime::test_date_time\", \"pydicom/tests/test_valuerep.py::TestDateTime::test_time\"]", "base_commit": "b9fb05c177b685bf683f7f57b2d57374eb7d882d", "created_at": "2020-06-26T11:47:17Z", "environment_setup_commit": "9d69811e539774f296c2f289839147e741251716", "hints_text": "I think it is reasonable to support at least some `str` methods (definitely `__contains__` for the example above), but there are many that don't make a lot of sense in this context though - e.g. `join`, `ljust`, `maketrans`, `splitlines` just to name a few, but I suppose each would either never be actually used or would have no effect.\r\n\r\nI have a vague memory that one or more of the `PersonName` classes was at one time subclassed from `str`, or at least that it was discussed... does anyone remember?  Maybe it would be easier now with only Python 3 supported.\n`PersonName` was derived from `str` or `unicode` in Python 2, but that caused a number of problems, which is why you switched to `PersonName3` in Python 3, I think. I agree though that it makes sense to implement `str` methods, either by implementing some of them, or generically by adding `__getattr__` that converts it to `str` and applies the attribute to that string. ", "instance_id": "pydicom__pydicom-1139", "patch": "diff --git a/pydicom/valuerep.py b/pydicom/valuerep.py\n--- a/pydicom/valuerep.py\n+++ b/pydicom/valuerep.py\n@@ -1,6 +1,5 @@\n # Copyright 2008-2018 pydicom authors. See LICENSE file for details.\n \"\"\"Special classes for DICOM value representations (VR)\"\"\"\n-from copy import deepcopy\n from decimal import Decimal\n import re\n \n@@ -750,6 +749,25 @@ def __ne__(self, other):\n     def __str__(self):\n         return '='.join(self.components).__str__()\n \n+    def __next__(self):\n+        # Get next character or stop iteration\n+        if self._i < self._rep_len:\n+            c = self._str_rep[self._i]\n+            self._i += 1\n+            return c\n+        else:\n+            raise StopIteration\n+\n+    def __iter__(self):\n+        # Get string rep. and length, initialize index counter\n+        self._str_rep = self.__str__()\n+        self._rep_len = len(self._str_rep)\n+        self._i = 0\n+        return self\n+\n+    def __contains__(self, x):\n+        return x in self.__str__()\n+\n     def __repr__(self):\n         return '='.join(self.components).__repr__()\n \n", "problem_statement": "Make PersonName3 iterable\n```python\r\nfrom pydicom import Dataset\r\n\r\nds = Dataset()\r\nds.PatientName = 'SomeName'\r\n\r\n'S' in ds.PatientName\r\n```\r\n```\r\nTraceback (most recent call last):\r\n  File \"<stdin>\", line 1, in <module>\r\nTypeError: argument of type 'PersonName3' is not iterable\r\n```\r\n\r\nI'm not really sure if this is intentional or if PN elements should support `str` methods. And yes I know I can `str(ds.PatientName)` but it's a bit silly, especially when I keep having to write exceptions to my element iterators just for PN elements.\n", "repo": "pydicom/pydicom", "test_patch": "diff --git a/pydicom/tests/test_valuerep.py b/pydicom/tests/test_valuerep.py\n--- a/pydicom/tests/test_valuerep.py\n+++ b/pydicom/tests/test_valuerep.py\n@@ -427,6 +427,62 @@ def test_hash(self):\n         )\n         assert hash(pn1) == hash(pn2)\n \n+    def test_next(self):\n+        \"\"\"Test that the next function works on it's own\"\"\"\n+        # Test getting the first character\n+        pn1 = PersonName(\"John^Doe^^Dr\", encodings=default_encoding)\n+        pn1_itr = iter(pn1)\n+        assert next(pn1_itr) == \"J\"\n+\n+        # Test getting multiple characters\n+        pn2 = PersonName(\n+            \"Yamada^Tarou=\u5c71\u7530^\u592a\u90ce=\u3084\u307e\u3060^\u305f\u308d\u3046\", [default_encoding, \"iso2022_jp\"]\n+        )\n+        pn2_itr = iter(pn2)\n+        assert next(pn2_itr) == \"Y\"\n+        assert next(pn2_itr) == \"a\"\n+\n+        # Test getting all characters\n+        pn3 = PersonName(\"SomeName\")\n+        pn3_itr = iter(pn3)\n+        assert next(pn3_itr) == \"S\"\n+        assert next(pn3_itr) == \"o\"\n+        assert next(pn3_itr) == \"m\"\n+        assert next(pn3_itr) == \"e\"\n+        assert next(pn3_itr) == \"N\"\n+        assert next(pn3_itr) == \"a\"\n+        assert next(pn3_itr) == \"m\"\n+        assert next(pn3_itr) == \"e\"\n+\n+        # Attempting to get next characeter should stop the iteration\n+        # I.e. next can only start once\n+        with pytest.raises(StopIteration):\n+            next(pn3_itr)\n+\n+        # Test that next() doesn't work without instantiating an iterator\n+        pn4 = PersonName(\"SomeName\")\n+        with pytest.raises(AttributeError):\n+            next(pn4)\n+\n+    def test_iterator(self):\n+        \"\"\"Test that iterators can be corretly constructed\"\"\"\n+        name_str = \"John^Doe^^Dr\"\n+        pn1 = PersonName(name_str)\n+        \n+        for i, c in enumerate(pn1):\n+            assert name_str[i] == c\n+\n+        # Ensure that multiple iterators can be created on the same variable\n+        for i, c in enumerate(pn1):\n+            assert name_str[i] == c\n+\n+    def test_contains(self):\n+        \"\"\"Test that characters can be check if they are within the name\"\"\"\n+        pn1 = PersonName(\"John^Doe\")\n+        assert (\"J\" in pn1) == True\n+        assert (\"o\" in pn1) == True\n+        assert (\"x\" in pn1) == False\n+\n \n class TestDateTime:\n     \"\"\"Unit tests for DA, DT, TM conversion to datetime objects\"\"\"\n", "version": "2.0"}
parsed_commit_content: {"file_diffs":[{"old_file_content":"# Copyright 2008-2018 pydicom authors. See LICENSE file for details.\n\"\"\"Special classes for DICOM value representations (VR)\"\"\"\nfrom copy import deepcopy\nfrom decimal import Decimal\nimport re\n\nfrom datetime import (date, datetime, time, timedelta, timezone)\n\n# don't import datetime_conversion directly\nfrom pydicom import config\nfrom pydicom.multival import MultiValue\n\n# can't import from charset or get circular import\ndefault_encoding = \"iso8859\"\n\n# For reading/writing data elements,\n# these ones have longer explicit VR format\n# Taken from PS3.5 Section 7.1.2\nextra_length_VRs = ('OB', 'OD', 'OF', 'OL', 'OW', 'SQ', 'UC', 'UN', 'UR', 'UT')\n\n# VRs that can be affected by character repertoire\n# in (0008,0005) Specific Character Set\n# See PS-3.5 (2011), section 6.1.2 Graphic Characters\n# and PN, but it is handled separately.\ntext_VRs = ('SH', 'LO', 'ST', 'LT', 'UC', 'UT')\n\n# Delimiters for text strings and person name that reset the encoding.\n# See PS3.5, Section 6.1.2.5.3\n# Note: We use character codes for Python 3\n# because those are the types yielded if iterating over a byte string.\n\n# Characters/Character codes for text VR delimiters: LF, CR, TAB, FF\nTEXT_VR_DELIMS = {0x0d, 0x0a, 0x09, 0x0c}\n\n# Character/Character code for PN delimiter: name part separator '^'\n# (the component separator '=' is handled separately)\nPN_DELIMS = {0xe5}\n\n\nclass DA(date):\n    \"\"\"Store value for an element with VR **DA** as :class:`datetime.date`.\n\n    Note that the :class:`datetime.date` base class is immutable.\n    \"\"\"\n    __slots__ = ['original_string']\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __reduce__(self):\n        return super(DA, self).__reduce__() + (self.__getstate__(),)\n\n    def __reduce_ex__(self, protocol):\n        return super(DA, self).__reduce__() + (self.__getstate__(),)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of DA object.\n\n        Raise an exception if the string cannot be parsed or the argument\n        is otherwise incompatible.\n\n        Parameters\n        ----------\n        val : str\n            A string conformant to the DA definition in the DICOM Standard,\n            Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.\n        \"\"\"\n        if isinstance(val, str):\n            if len(val) == 8:\n                year = int(val[0:4])\n                month = int(val[4:6])\n                day = int(val[6:8])\n                val = super(DA, cls).__new__(cls, year, month, day)\n            elif len(val) == 10 and val[4] == '.' and val[7] == '.':\n                # ACR-NEMA Standard 300, predecessor to DICOM\n                # for compatibility with a few old pydicom example files\n                year = int(val[0:4])\n                month = int(val[5:7])\n                day = int(val[8:10])\n                val = super(DA, cls).__new__(cls, year, month, day)\n            elif val == '':\n                val = None  # empty date\n            else:\n                try:\n                    val = super(DA, cls).__new__(cls, val)\n                except TypeError:\n                    raise ValueError(\"Cannot convert to datetime: '%s'\" %\n                                     (val))\n        elif isinstance(val, date):\n            val = super(DA, cls).__new__(cls, val.year, val.month, val.day)\n        else:\n            val = super(DA, cls).__new__(cls, val)\n        return val\n\n    def __init__(self, val):\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, DA) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n        else:\n            return super(DA, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\nclass DT(datetime):\n    \"\"\"Store value for an element with VR **DT** as :class:`datetime.datetime`.\n\n    Note that the :class:`datetime.datetime` base class is immutable.\n    \"\"\"\n    __slots__ = ['original_string']\n    _regex_dt = re.compile(r\"((\\d{4,14})(\\.(\\d{1,6}))?)([+-]\\d{4})?\")\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __reduce__(self):\n        return super(DT, self).__reduce__() + (self.__getstate__(),)\n\n    def __reduce_ex__(self, protocol):\n        return super(DT, self).__reduce__() + (self.__getstate__(),)\n\n    @staticmethod\n    def _utc_offset(offset, name):\n        return timezone(timedelta(seconds=offset), name)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of DT object.\n\n        Raise an exception if the string cannot be parsed or the argument\n        is otherwise incompatible.\n\n        Parameters\n        ----------\n        val : str\n            A string conformant to the DT definition in the DICOM Standard,\n            Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.\n        \"\"\"\n        if isinstance(val, str):\n            match = DT._regex_dt.match(val)\n            if match and len(val) <= 26:\n                dt_match = match.group(2)\n                year = int(dt_match[0:4])\n                if len(dt_match) < 6:\n                    month = 1\n                else:\n                    month = int(dt_match[4:6])\n                if len(dt_match) < 8:\n                    day = 1\n                else:\n                    day = int(dt_match[6:8])\n                if len(dt_match) < 10:\n                    hour = 0\n                else:\n                    hour = int(dt_match[8:10])\n                if len(dt_match) < 12:\n                    minute = 0\n                else:\n                    minute = int(dt_match[10:12])\n                if len(dt_match) < 14:\n                    second = 0\n                    microsecond = 0\n                else:\n                    second = int(dt_match[12:14])\n                    ms_match = match.group(4)\n                    if ms_match:\n                        microsecond = int(ms_match.rstrip().ljust(6, '0'))\n                    else:\n                        microsecond = 0\n                tz_match = match.group(5)\n                if tz_match:\n                    offset1 = int(tz_match[1:3]) * 60\n                    offset2 = int(tz_match[3:5])\n                    offset = (offset1 + offset2) * 60\n                    if tz_match[0] == '-':\n                        offset = -offset\n                    tzinfo = cls._utc_offset(offset, tz_match)\n                else:\n                    tzinfo = None\n                val = super(DT,\n                            cls).__new__(cls, year, month, day, hour, minute,\n                                         second, microsecond, tzinfo)\n            else:\n                try:\n                    val = super(DT, cls).__new__(cls, val)\n                except TypeError:\n                    raise ValueError(\"Cannot convert to datetime: '%s'\" %\n                                     (val))\n        elif isinstance(val, datetime):\n            val = super(DT, cls).__new__(cls, val.year, val.month, val.day,\n                                         val.hour, val.minute, val.second,\n                                         val.microsecond, val.tzinfo)\n        else:\n            val = super(DT, cls).__new__(cls, val)\n        return val\n\n    def __init__(self, val):\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, DT) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n        else:\n            return super(DT, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\nclass TM(time):\n    \"\"\"Store value for an element with VR **TM** as :class:`datetime.time`.\n\n    Note that the :class:`datetime.time` base class is immutable.\n    \"\"\"\n    __slots__ = ['original_string']\n    _regex_tm = re.compile(r\"(\\d{2,6})(\\.(\\d{1,6}))?\")\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __reduce__(self):\n        return super(TM, self).__reduce__() + (self.__getstate__(),)\n\n    def __reduce_ex__(self, protocol):\n        return super(TM, self).__reduce__() + (self.__getstate__(),)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of TM object from a string.\n\n        Raise an exception if the string cannot be parsed or the argument\n        is otherwise incompatible.\n\n        Parameters\n        ----------\n        val : str\n            A string conformant to the TM definition in the DICOM Standard,\n            Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.\n        \"\"\"\n        if isinstance(val, str):\n            match = TM._regex_tm.match(val)\n            if match and len(val) <= 16:\n                tm_match = match.group(1)\n                hour = int(tm_match[0:2])\n                if len(tm_match) < 4:\n                    minute = 0\n                else:\n                    minute = int(tm_match[2:4])\n                if len(tm_match) < 6:\n                    second = 0\n                    microsecond = 0\n                else:\n                    second = int(tm_match[4:6])\n                    ms_match = match.group(3)\n                    if ms_match:\n                        microsecond = int(ms_match.rstrip().ljust(6, '0'))\n                    else:\n                        microsecond = 0\n                val = super(TM, cls).__new__(cls, hour, minute, second,\n                                             microsecond)\n            elif val == '':\n                val = None  # empty time\n            else:\n                try:\n                    val = super(TM, cls).__new__(cls, val)\n                except TypeError:\n                    raise ValueError(\"Cannot convert to datetime: '%s\" % (val))\n        elif isinstance(val, time):\n            val = super(TM, cls).__new__(cls, val.hour, val.minute, val.second,\n                                         val.microsecond)\n        else:\n            val = super(TM, cls).__new__(cls, val)\n        return val\n\n    def __init__(self, val):\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, TM) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n        else:\n            return super(TM, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\nclass DSfloat(float):\n    \"\"\"Store value for an element with VR **DS** as :class:`float`.\n\n    If constructed from an empty string, return the empty string,\n    not an instance of this class.\n\n    \"\"\"\n    __slots__ = ['original_string']\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __init__(self, val):\n        \"\"\"Store the original string if one given, for exact write-out of same\n        value later.\n        \"\"\"\n        # ... also if user changes a data element value, then will get\n        # a different object, because float is immutable.\n\n        has_attribute = hasattr(val, 'original_string')\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, (DSfloat, DSdecimal)) and has_attribute:\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n\n        # Issue #937 (Python 3.8 compatibility)\n        return repr(self)[1:-1]\n\n    def __repr__(self):\n        return '\"{}\"'.format(super(DSfloat, self).__repr__())\n\n\nclass DSdecimal(Decimal):\n    \"\"\"Store value for an element with VR **DS** as :class:`decimal.Decimal`.\n\n    Notes\n    -----\n    If constructed from an empty string, returns the empty string, not an\n    instance of this class.\n    \"\"\"\n    __slots__ = ['original_string']\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of DS object, or return a blank string if one is\n        passed in, e.g. from a type 2 DICOM blank value.\n\n        Parameters\n        ----------\n        val : str or numeric\n            A string or a number type which can be converted to a decimal.\n        \"\"\"\n        # Store this value here so that if the input string is actually a valid\n        # string but decimal.Decimal transforms it to an invalid string it will\n        # still be initialized properly\n        enforce_length = config.enforce_valid_values\n        # DICOM allows spaces around the string,\n        # but python doesn't, so clean it\n        if isinstance(val, str):\n            val = val.strip()\n            # If the input string is actually invalid that we relax the valid\n            # value constraint for this particular instance\n            if len(val) <= 16:\n                enforce_length = False\n        if val == '':\n            return val\n        if isinstance(val, float) and not config.allow_DS_float:\n            msg = (\"DS cannot be instantiated with a float value, \"\n                   \"unless config.allow_DS_float is set to True. \"\n                   \"It is recommended to convert to a string instead, \"\n                   \"with the desired number of digits, or use \"\n                   \"Decimal.quantize and pass a Decimal instance.\")\n            raise TypeError(msg)\n        if not isinstance(val, Decimal):\n            val = super(DSdecimal, cls).__new__(cls, val)\n        if len(str(val)) > 16 and enforce_length:\n            msg = (\"DS value representation must be <= 16 \"\n                   \"characters by DICOM standard. Initialize with \"\n                   \"a smaller string, or set config.enforce_valid_values \"\n                   \"to False to override, or use Decimal.quantize() and \"\n                   \"initialize with a Decimal instance.\")\n            raise OverflowError(msg)\n        return val\n\n    def __init__(self, val):\n        \"\"\"Store the original string if one given, for exact write-out of same\n        value later. E.g. if set ``'1.23e2'``, :class:`~decimal.Decimal` would\n        write ``'123'``, but :class:`DS` will use the original.\n        \"\"\"\n        # ... also if user changes a data element value, then will get\n        # a different Decimal, as Decimal is immutable.\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, (DSfloat, DSdecimal)) and hasattr(val, 'original_string'):  # noqa\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string') and len(self.original_string) <= 16:  # noqa\n            return self.original_string\n        else:\n            return super(DSdecimal, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\n# CHOOSE TYPE OF DS\nif config.use_DS_decimal:\n    DSclass = DSdecimal\nelse:\n    DSclass = DSfloat\n\n\ndef DS(val):\n    \"\"\"Factory function for creating DS class instances.\n\n    Checks for blank string; if so, returns that, else calls :class:`DSfloat`\n    or :class:`DSdecimal` to create the class instance. This avoids overriding\n    ``DSfloat.__new__()`` (which carries a time penalty for large arrays of\n    DS).\n\n    Similarly the string clean and check can be avoided and :class:`DSfloat`\n    called directly if a string has already been processed.\n    \"\"\"\n    if isinstance(val, str):\n        val = val.strip()\n    if val == '' or val is None:\n        return val\n    return DSclass(val)\n\n\nclass IS(int):\n    \"\"\"Store value for an element with VR **IS** as :class:`int`.\n\n    Stores original integer string for exact rewriting of the string\n    originally read or stored.\n    \"\"\"\n\n    def __new__(cls, val):\n        \"\"\"Create instance if new integer string\"\"\"\n        if val is None:\n            return val\n        if isinstance(val, str) and val.strip() == '':\n            return ''\n\n        newval = super(IS, cls).__new__(cls, val)\n\n        # check if a float or Decimal passed in, then could have lost info,\n        # and will raise error. E.g. IS(Decimal('1')) is ok, but not IS(1.23)\n        if isinstance(val, (float, Decimal)) and newval != val:\n            raise TypeError(\"Could not convert value to integer without loss\")\n        # Checks in case underlying int is >32 bits, DICOM does not allow this\n        check_newval = (newval < -2 ** 31 or newval >= 2 ** 31)\n        if check_newval and config.enforce_valid_values:\n            dcm_limit = \"-2**31 to (2**31 - 1) for IS\"\n            message = \"Value exceeds DICOM limits of %s\" % (dcm_limit)\n            raise OverflowError(message)\n        return newval\n\n    def __init__(self, val):\n        # If a string passed, then store it\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, IS) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n\n        # Issue #937 (Python 3.8 compatibility)\n        return repr(self)[1:-1]\n\n    def __repr__(self):\n        return '\"{}\"'.format(super(IS, self).__repr__())\n\n\ndef MultiString(val, valtype=str):\n    \"\"\"Split a bytestring by delimiters if there are any\n\n    Parameters\n    ----------\n    val : bytes or str\n        DICOM byte string to split up.\n    valtype\n        Default :class:`str`, but can be e.g. :class:`~pydicom.uid.UID` to\n        overwrite to a specific type.\n\n    Returns\n    -------\n    valtype or list of valtype\n        The split value as `valtype` or a :class:`list` of `valtype`.\n    \"\"\"\n    # Remove trailing blank used to pad to even length\n    # 2005.05.25: also check for trailing 0, error made\n    # in PET files we are converting\n\n    while val and (val.endswith(' ') or val.endswith('\\x00')):\n        val = val[:-1]\n    splitup = val.split(\"\\\\\")\n\n    if len(splitup) == 1:\n        val = splitup[0]\n        return valtype(val) if val else val\n    else:\n        return MultiValue(valtype, splitup)\n\n\ndef _verify_encodings(encodings):\n    \"\"\"Checks the encoding to ensure proper format\"\"\"\n    if encodings is not None:\n        if not isinstance(encodings, (list, tuple)):\n            return encodings,\n        return tuple(encodings)\n    return encodings\n\n\ndef _decode_personname(components, encodings):\n    \"\"\"Return a list of decoded person name components.\n\n    Parameters\n    ----------\n    components : list of byte string\n        The list of the up to three encoded person name components\n    encodings : list of str\n        The Python encodings uses to decode `components`.\n\n    Returns\n    -------\n    text type\n        The unicode string representing the person name.\n        If the decoding of some component parts is not possible using the\n        given encodings, they are decoded with the first encoding using\n        replacement characters for bytes that cannot be decoded.\n    \"\"\"\n    from pydicom.charset import decode_string\n\n    if isinstance(components[0], str):\n        comps = components\n    else:\n        comps = [decode_string(comp, encodings, PN_DELIMS)\n                 for comp in components]\n    # Remove empty elements from the end to avoid trailing '='\n    while len(comps) and not comps[-1]:\n        comps.pop()\n    return tuple(comps)\n\n\ndef _encode_personname(components, encodings):\n    \"\"\"Encode a list of text string person name components.\n\n    Parameters\n    ----------\n    components : list of text type\n        The list of the up to three unicode person name components\n    encodings : list of str\n        The Python encodings uses to encode `components`.\n\n    Returns\n    -------\n    byte string\n        The byte string that can be written as a PN DICOM tag value.\n        If the encoding of some component parts is not possible using the\n        given encodings, they are encoded with the first encoding using\n        replacement bytes for characters that cannot be encoded.\n    \"\"\"\n    from pydicom.charset import encode_string\n\n    encoded_comps = []\n    for comp in components:\n        groups = [encode_string(group, encodings)\n                  for group in comp.split('^')]\n        encoded_comps.append(b'^'.join(groups))\n\n    # Remove empty elements from the end\n    while len(encoded_comps) and not encoded_comps[-1]:\n        encoded_comps.pop()\n    return b'='.join(encoded_comps)\n\n\nclass PersonName:\n    def __new__(cls, *args, **kwargs):\n        # Handle None value by returning None instead of a PersonName object\n        if len(args) and args[0] is None:\n            return None\n        return super(PersonName, cls).__new__(cls)\n\n    def __init__(self, val, encodings=None, original_string=None):\n        if isinstance(val, PersonName):\n            encodings = val.encodings\n            self.original_string = val.original_string\n            self._components = tuple(str(val).split('='))\n        elif isinstance(val, bytes):\n            # this is the raw byte string - decode it on demand\n            self.original_string = val\n            self._components = None\n        else:\n            # handle None `val` as empty string\n            val = val or ''\n\n            # this is the decoded string - save the original string if\n            # available for easier writing back\n            self.original_string = original_string\n            components = val.split('=')\n            # Remove empty elements from the end to avoid trailing '='\n            while len(components) and not components[-1]:\n                components.pop()\n            self._components = tuple(components)\n\n            # if the encoding is not given, leave it as undefined (None)\n        self.encodings = _verify_encodings(encodings)\n        self._dict = {}\n\n    def _create_dict(self):\n        \"\"\"Creates a dictionary of person name group and component names.\n\n        Used exclusively for `formatted` for backwards compatibility.\n        \"\"\"\n        if not self._dict:\n            for name in ('family_name', 'given_name', 'middle_name',\n                         'name_prefix', 'name_suffix',\n                         'ideographic', 'phonetic'):\n                self._dict[name] = getattr(self, name, '')\n\n    @property\n    def components(self):\n        \"\"\"Returns up to three decoded person name components.\n\n        .. versionadded:: 1.2\n\n        The returned components represent the alphabetic, ideographic and\n        phonetic representations as a list of unicode strings.\n        \"\"\"\n        if self._components is None:\n            groups = self.original_string.split(b'=')\n            encodings = self.encodings or [default_encoding]\n            self._components = _decode_personname(groups, encodings)\n\n        return self._components\n\n    def _name_part(self, i):\n        try:\n            return self.components[0].split('^')[i]\n        except IndexError:\n            return ''\n\n    @property\n    def family_name(self):\n        \"\"\"Return the first (family name) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(0)\n\n    @property\n    def given_name(self):\n        \"\"\"Return the second (given name) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(1)\n\n    @property\n    def middle_name(self):\n        \"\"\"Return the third (middle name) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(2)\n\n    @property\n    def name_prefix(self):\n        \"\"\"Return the fourth (name prefix) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(3)\n\n    @property\n    def name_suffix(self):\n        \"\"\"Return the fifth (name suffix) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(4)\n\n    @property\n    def ideographic(self):\n        \"\"\"Return the second (ideographic) person name component as a\n        unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        try:\n            return self.components[1]\n        except IndexError:\n            return ''\n\n    @property\n    def phonetic(self):\n        \"\"\"Return the third (phonetic) person name component as a\n        unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        try:\n            return self.components[2]\n        except IndexError:\n            return ''\n\n    def __eq__(self, other):\n        return str(self) == other\n\n    def __ne__(self, other):\n        return not self == other\n\n    def __str__(self):\n        return '='.join(self.components).__str__()\n\n    def __repr__(self):\n        return '='.join(self.components).__repr__()\n\n    def __hash__(self):\n        return hash(self.components)\n\n    def decode(self, encodings=None):\n        \"\"\"Return the patient name decoded by the given `encodings`.\n\n        Parameters\n        ----------\n        encodings : list of str\n            The list of encodings used for decoding the byte string. If not\n            given, the initial encodings set in the object are used.\n\n        Returns\n        -------\n        valuerep.PersonName\n            A person name object that will return the decoded string with\n            the given encodings on demand. If the encodings are not given,\n            the current object is returned.\n        \"\"\"\n        # in the common case (encoding did not change) we decode on demand\n        if encodings is None or encodings == self.encodings:\n            return self\n        # the encoding was unknown or incorrect - create a new\n        # PersonName object with the changed encoding\n        encodings = _verify_encodings(encodings)\n        if self.original_string is None:\n            # if the original encoding was not set, we set it now\n            self.original_string = _encode_personname(\n                self.components, self.encodings or [default_encoding])\n        return PersonName(self.original_string, encodings)\n\n    def encode(self, encodings=None):\n        \"\"\"Return the patient name decoded by the given `encodings`.\n\n        Parameters\n        ----------\n        encodings : list of str\n            The list of encodings used for encoding the unicode string. If\n            not given, the initial encodings set in the object are used.\n\n        Returns\n        -------\n        bytes\n            The person name encoded with the given encodings as a byte string.\n            If no encoding is given, the original byte string is returned, if\n            available, otherwise each group of the patient name is encoded\n            with the first matching of the given encodings.\n        \"\"\"\n        encodings = _verify_encodings(encodings) or self.encodings\n\n        # if the encoding is not the original encoding, we have to return\n        # a re-encoded string (without updating the original string)\n        if encodings != self.encodings and self.encodings is not None:\n            return _encode_personname(self.components, encodings)\n        if self.original_string is None:\n            # if the original encoding was not set, we set it now\n            self.original_string = _encode_personname(\n                self.components, encodings or [default_encoding])\n        return self.original_string\n\n    def family_comma_given(self):\n        return self.formatted('%(family_name)s, %(given_name)s')\n\n    def formatted(self, format_str):\n        self._create_dict()\n        return format_str % self._dict\n\n    def __bool__(self):\n        if self.original_string is None:\n            return (bool(self._components) and\n                    (len(self._components) > 1 or bool(self._components[0])))\n        return bool(self.original_string)\n\n\n# Alias old class names for backwards compat in user code\nPersonNameUnicode = PersonName = PersonName\n","new_file_content":"# Copyright 2008-2018 pydicom authors. See LICENSE file for details.\n\"\"\"Special classes for DICOM value representations (VR)\"\"\"\nfrom decimal import Decimal\nimport re\n\nfrom datetime import (date, datetime, time, timedelta, timezone)\n\n# don't import datetime_conversion directly\nfrom pydicom import config\nfrom pydicom.multival import MultiValue\n\n# can't import from charset or get circular import\ndefault_encoding = \"iso8859\"\n\n# For reading/writing data elements,\n# these ones have longer explicit VR format\n# Taken from PS3.5 Section 7.1.2\nextra_length_VRs = ('OB', 'OD', 'OF', 'OL', 'OW', 'SQ', 'UC', 'UN', 'UR', 'UT')\n\n# VRs that can be affected by character repertoire\n# in (0008,0005) Specific Character Set\n# See PS-3.5 (2011), section 6.1.2 Graphic Characters\n# and PN, but it is handled separately.\ntext_VRs = ('SH', 'LO', 'ST', 'LT', 'UC', 'UT')\n\n# Delimiters for text strings and person name that reset the encoding.\n# See PS3.5, Section 6.1.2.5.3\n# Note: We use character codes for Python 3\n# because those are the types yielded if iterating over a byte string.\n\n# Characters/Character codes for text VR delimiters: LF, CR, TAB, FF\nTEXT_VR_DELIMS = {0x0d, 0x0a, 0x09, 0x0c}\n\n# Character/Character code for PN delimiter: name part separator '^'\n# (the component separator '=' is handled separately)\nPN_DELIMS = {0xe5}\n\n\nclass DA(date):\n    \"\"\"Store value for an element with VR **DA** as :class:`datetime.date`.\n\n    Note that the :class:`datetime.date` base class is immutable.\n    \"\"\"\n    __slots__ = ['original_string']\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __reduce__(self):\n        return super(DA, self).__reduce__() + (self.__getstate__(),)\n\n    def __reduce_ex__(self, protocol):\n        return super(DA, self).__reduce__() + (self.__getstate__(),)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of DA object.\n\n        Raise an exception if the string cannot be parsed or the argument\n        is otherwise incompatible.\n\n        Parameters\n        ----------\n        val : str\n            A string conformant to the DA definition in the DICOM Standard,\n            Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.\n        \"\"\"\n        if isinstance(val, str):\n            if len(val) == 8:\n                year = int(val[0:4])\n                month = int(val[4:6])\n                day = int(val[6:8])\n                val = super(DA, cls).__new__(cls, year, month, day)\n            elif len(val) == 10 and val[4] == '.' and val[7] == '.':\n                # ACR-NEMA Standard 300, predecessor to DICOM\n                # for compatibility with a few old pydicom example files\n                year = int(val[0:4])\n                month = int(val[5:7])\n                day = int(val[8:10])\n                val = super(DA, cls).__new__(cls, year, month, day)\n            elif val == '':\n                val = None  # empty date\n            else:\n                try:\n                    val = super(DA, cls).__new__(cls, val)\n                except TypeError:\n                    raise ValueError(\"Cannot convert to datetime: '%s'\" %\n                                     (val))\n        elif isinstance(val, date):\n            val = super(DA, cls).__new__(cls, val.year, val.month, val.day)\n        else:\n            val = super(DA, cls).__new__(cls, val)\n        return val\n\n    def __init__(self, val):\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, DA) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n        else:\n            return super(DA, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\nclass DT(datetime):\n    \"\"\"Store value for an element with VR **DT** as :class:`datetime.datetime`.\n\n    Note that the :class:`datetime.datetime` base class is immutable.\n    \"\"\"\n    __slots__ = ['original_string']\n    _regex_dt = re.compile(r\"((\\d{4,14})(\\.(\\d{1,6}))?)([+-]\\d{4})?\")\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __reduce__(self):\n        return super(DT, self).__reduce__() + (self.__getstate__(),)\n\n    def __reduce_ex__(self, protocol):\n        return super(DT, self).__reduce__() + (self.__getstate__(),)\n\n    @staticmethod\n    def _utc_offset(offset, name):\n        return timezone(timedelta(seconds=offset), name)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of DT object.\n\n        Raise an exception if the string cannot be parsed or the argument\n        is otherwise incompatible.\n\n        Parameters\n        ----------\n        val : str\n            A string conformant to the DT definition in the DICOM Standard,\n            Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.\n        \"\"\"\n        if isinstance(val, str):\n            match = DT._regex_dt.match(val)\n            if match and len(val) <= 26:\n                dt_match = match.group(2)\n                year = int(dt_match[0:4])\n                if len(dt_match) < 6:\n                    month = 1\n                else:\n                    month = int(dt_match[4:6])\n                if len(dt_match) < 8:\n                    day = 1\n                else:\n                    day = int(dt_match[6:8])\n                if len(dt_match) < 10:\n                    hour = 0\n                else:\n                    hour = int(dt_match[8:10])\n                if len(dt_match) < 12:\n                    minute = 0\n                else:\n                    minute = int(dt_match[10:12])\n                if len(dt_match) < 14:\n                    second = 0\n                    microsecond = 0\n                else:\n                    second = int(dt_match[12:14])\n                    ms_match = match.group(4)\n                    if ms_match:\n                        microsecond = int(ms_match.rstrip().ljust(6, '0'))\n                    else:\n                        microsecond = 0\n                tz_match = match.group(5)\n                if tz_match:\n                    offset1 = int(tz_match[1:3]) * 60\n                    offset2 = int(tz_match[3:5])\n                    offset = (offset1 + offset2) * 60\n                    if tz_match[0] == '-':\n                        offset = -offset\n                    tzinfo = cls._utc_offset(offset, tz_match)\n                else:\n                    tzinfo = None\n                val = super(DT,\n                            cls).__new__(cls, year, month, day, hour, minute,\n                                         second, microsecond, tzinfo)\n            else:\n                try:\n                    val = super(DT, cls).__new__(cls, val)\n                except TypeError:\n                    raise ValueError(\"Cannot convert to datetime: '%s'\" %\n                                     (val))\n        elif isinstance(val, datetime):\n            val = super(DT, cls).__new__(cls, val.year, val.month, val.day,\n                                         val.hour, val.minute, val.second,\n                                         val.microsecond, val.tzinfo)\n        else:\n            val = super(DT, cls).__new__(cls, val)\n        return val\n\n    def __init__(self, val):\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, DT) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n        else:\n            return super(DT, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\nclass TM(time):\n    \"\"\"Store value for an element with VR **TM** as :class:`datetime.time`.\n\n    Note that the :class:`datetime.time` base class is immutable.\n    \"\"\"\n    __slots__ = ['original_string']\n    _regex_tm = re.compile(r\"(\\d{2,6})(\\.(\\d{1,6}))?\")\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __reduce__(self):\n        return super(TM, self).__reduce__() + (self.__getstate__(),)\n\n    def __reduce_ex__(self, protocol):\n        return super(TM, self).__reduce__() + (self.__getstate__(),)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of TM object from a string.\n\n        Raise an exception if the string cannot be parsed or the argument\n        is otherwise incompatible.\n\n        Parameters\n        ----------\n        val : str\n            A string conformant to the TM definition in the DICOM Standard,\n            Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.\n        \"\"\"\n        if isinstance(val, str):\n            match = TM._regex_tm.match(val)\n            if match and len(val) <= 16:\n                tm_match = match.group(1)\n                hour = int(tm_match[0:2])\n                if len(tm_match) < 4:\n                    minute = 0\n                else:\n                    minute = int(tm_match[2:4])\n                if len(tm_match) < 6:\n                    second = 0\n                    microsecond = 0\n                else:\n                    second = int(tm_match[4:6])\n                    ms_match = match.group(3)\n                    if ms_match:\n                        microsecond = int(ms_match.rstrip().ljust(6, '0'))\n                    else:\n                        microsecond = 0\n                val = super(TM, cls).__new__(cls, hour, minute, second,\n                                             microsecond)\n            elif val == '':\n                val = None  # empty time\n            else:\n                try:\n                    val = super(TM, cls).__new__(cls, val)\n                except TypeError:\n                    raise ValueError(\"Cannot convert to datetime: '%s\" % (val))\n        elif isinstance(val, time):\n            val = super(TM, cls).__new__(cls, val.hour, val.minute, val.second,\n                                         val.microsecond)\n        else:\n            val = super(TM, cls).__new__(cls, val)\n        return val\n\n    def __init__(self, val):\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, TM) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n        else:\n            return super(TM, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\nclass DSfloat(float):\n    \"\"\"Store value for an element with VR **DS** as :class:`float`.\n\n    If constructed from an empty string, return the empty string,\n    not an instance of this class.\n\n    \"\"\"\n    __slots__ = ['original_string']\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __init__(self, val):\n        \"\"\"Store the original string if one given, for exact write-out of same\n        value later.\n        \"\"\"\n        # ... also if user changes a data element value, then will get\n        # a different object, because float is immutable.\n\n        has_attribute = hasattr(val, 'original_string')\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, (DSfloat, DSdecimal)) and has_attribute:\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n\n        # Issue #937 (Python 3.8 compatibility)\n        return repr(self)[1:-1]\n\n    def __repr__(self):\n        return '\"{}\"'.format(super(DSfloat, self).__repr__())\n\n\nclass DSdecimal(Decimal):\n    \"\"\"Store value for an element with VR **DS** as :class:`decimal.Decimal`.\n\n    Notes\n    -----\n    If constructed from an empty string, returns the empty string, not an\n    instance of this class.\n    \"\"\"\n    __slots__ = ['original_string']\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of DS object, or return a blank string if one is\n        passed in, e.g. from a type 2 DICOM blank value.\n\n        Parameters\n        ----------\n        val : str or numeric\n            A string or a number type which can be converted to a decimal.\n        \"\"\"\n        # Store this value here so that if the input string is actually a valid\n        # string but decimal.Decimal transforms it to an invalid string it will\n        # still be initialized properly\n        enforce_length = config.enforce_valid_values\n        # DICOM allows spaces around the string,\n        # but python doesn't, so clean it\n        if isinstance(val, str):\n            val = val.strip()\n            # If the input string is actually invalid that we relax the valid\n            # value constraint for this particular instance\n            if len(val) <= 16:\n                enforce_length = False\n        if val == '':\n            return val\n        if isinstance(val, float) and not config.allow_DS_float:\n            msg = (\"DS cannot be instantiated with a float value, \"\n                   \"unless config.allow_DS_float is set to True. \"\n                   \"It is recommended to convert to a string instead, \"\n                   \"with the desired number of digits, or use \"\n                   \"Decimal.quantize and pass a Decimal instance.\")\n            raise TypeError(msg)\n        if not isinstance(val, Decimal):\n            val = super(DSdecimal, cls).__new__(cls, val)\n        if len(str(val)) > 16 and enforce_length:\n            msg = (\"DS value representation must be <= 16 \"\n                   \"characters by DICOM standard. Initialize with \"\n                   \"a smaller string, or set config.enforce_valid_values \"\n                   \"to False to override, or use Decimal.quantize() and \"\n                   \"initialize with a Decimal instance.\")\n            raise OverflowError(msg)\n        return val\n\n    def __init__(self, val):\n        \"\"\"Store the original string if one given, for exact write-out of same\n        value later. E.g. if set ``'1.23e2'``, :class:`~decimal.Decimal` would\n        write ``'123'``, but :class:`DS` will use the original.\n        \"\"\"\n        # ... also if user changes a data element value, then will get\n        # a different Decimal, as Decimal is immutable.\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, (DSfloat, DSdecimal)) and hasattr(val, 'original_string'):  # noqa\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string') and len(self.original_string) <= 16:  # noqa\n            return self.original_string\n        else:\n            return super(DSdecimal, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\n# CHOOSE TYPE OF DS\nif config.use_DS_decimal:\n    DSclass = DSdecimal\nelse:\n    DSclass = DSfloat\n\n\ndef DS(val):\n    \"\"\"Factory function for creating DS class instances.\n\n    Checks for blank string; if so, returns that, else calls :class:`DSfloat`\n    or :class:`DSdecimal` to create the class instance. This avoids overriding\n    ``DSfloat.__new__()`` (which carries a time penalty for large arrays of\n    DS).\n\n    Similarly the string clean and check can be avoided and :class:`DSfloat`\n    called directly if a string has already been processed.\n    \"\"\"\n    if isinstance(val, str):\n        val = val.strip()\n    if val == '' or val is None:\n        return val\n    return DSclass(val)\n\n\nclass IS(int):\n    \"\"\"Store value for an element with VR **IS** as :class:`int`.\n\n    Stores original integer string for exact rewriting of the string\n    originally read or stored.\n    \"\"\"\n\n    def __new__(cls, val):\n        \"\"\"Create instance if new integer string\"\"\"\n        if val is None:\n            return val\n        if isinstance(val, str) and val.strip() == '':\n            return ''\n\n        newval = super(IS, cls).__new__(cls, val)\n\n        # check if a float or Decimal passed in, then could have lost info,\n        # and will raise error. E.g. IS(Decimal('1')) is ok, but not IS(1.23)\n        if isinstance(val, (float, Decimal)) and newval != val:\n            raise TypeError(\"Could not convert value to integer without loss\")\n        # Checks in case underlying int is >32 bits, DICOM does not allow this\n        check_newval = (newval < -2 ** 31 or newval >= 2 ** 31)\n        if check_newval and config.enforce_valid_values:\n            dcm_limit = \"-2**31 to (2**31 - 1) for IS\"\n            message = \"Value exceeds DICOM limits of %s\" % (dcm_limit)\n            raise OverflowError(message)\n        return newval\n\n    def __init__(self, val):\n        # If a string passed, then store it\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, IS) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n\n        # Issue #937 (Python 3.8 compatibility)\n        return repr(self)[1:-1]\n\n    def __repr__(self):\n        return '\"{}\"'.format(super(IS, self).__repr__())\n\n\ndef MultiString(val, valtype=str):\n    \"\"\"Split a bytestring by delimiters if there are any\n\n    Parameters\n    ----------\n    val : bytes or str\n        DICOM byte string to split up.\n    valtype\n        Default :class:`str`, but can be e.g. :class:`~pydicom.uid.UID` to\n        overwrite to a specific type.\n\n    Returns\n    -------\n    valtype or list of valtype\n        The split value as `valtype` or a :class:`list` of `valtype`.\n    \"\"\"\n    # Remove trailing blank used to pad to even length\n    # 2005.05.25: also check for trailing 0, error made\n    # in PET files we are converting\n\n    while val and (val.endswith(' ') or val.endswith('\\x00')):\n        val = val[:-1]\n    splitup = val.split(\"\\\\\")\n\n    if len(splitup) == 1:\n        val = splitup[0]\n        return valtype(val) if val else val\n    else:\n        return MultiValue(valtype, splitup)\n\n\ndef _verify_encodings(encodings):\n    \"\"\"Checks the encoding to ensure proper format\"\"\"\n    if encodings is not None:\n        if not isinstance(encodings, (list, tuple)):\n            return encodings,\n        return tuple(encodings)\n    return encodings\n\n\ndef _decode_personname(components, encodings):\n    \"\"\"Return a list of decoded person name components.\n\n    Parameters\n    ----------\n    components : list of byte string\n        The list of the up to three encoded person name components\n    encodings : list of str\n        The Python encodings uses to decode `components`.\n\n    Returns\n    -------\n    text type\n        The unicode string representing the person name.\n        If the decoding of some component parts is not possible using the\n        given encodings, they are decoded with the first encoding using\n        replacement characters for bytes that cannot be decoded.\n    \"\"\"\n    from pydicom.charset import decode_string\n\n    if isinstance(components[0], str):\n        comps = components\n    else:\n        comps = [decode_string(comp, encodings, PN_DELIMS)\n                 for comp in components]\n    # Remove empty elements from the end to avoid trailing '='\n    while len(comps) and not comps[-1]:\n        comps.pop()\n    return tuple(comps)\n\n\ndef _encode_personname(components, encodings):\n    \"\"\"Encode a list of text string person name components.\n\n    Parameters\n    ----------\n    components : list of text type\n        The list of the up to three unicode person name components\n    encodings : list of str\n        The Python encodings uses to encode `components`.\n\n    Returns\n    -------\n    byte string\n        The byte string that can be written as a PN DICOM tag value.\n        If the encoding of some component parts is not possible using the\n        given encodings, they are encoded with the first encoding using\n        replacement bytes for characters that cannot be encoded.\n    \"\"\"\n    from pydicom.charset import encode_string\n\n    encoded_comps = []\n    for comp in components:\n        groups = [encode_string(group, encodings)\n                  for group in comp.split('^')]\n        encoded_comps.append(b'^'.join(groups))\n\n    # Remove empty elements from the end\n    while len(encoded_comps) and not encoded_comps[-1]:\n        encoded_comps.pop()\n    return b'='.join(encoded_comps)\n\n\nclass PersonName:\n    def __new__(cls, *args, **kwargs):\n        # Handle None value by returning None instead of a PersonName object\n        if len(args) and args[0] is None:\n            return None\n        return super(PersonName, cls).__new__(cls)\n\n    def __init__(self, val, encodings=None, original_string=None):\n        if isinstance(val, PersonName):\n            encodings = val.encodings\n            self.original_string = val.original_string\n            self._components = tuple(str(val).split('='))\n        elif isinstance(val, bytes):\n            # this is the raw byte string - decode it on demand\n            self.original_string = val\n            self._components = None\n        else:\n            # handle None `val` as empty string\n            val = val or ''\n\n            # this is the decoded string - save the original string if\n            # available for easier writing back\n            self.original_string = original_string\n            components = val.split('=')\n            # Remove empty elements from the end to avoid trailing '='\n            while len(components) and not components[-1]:\n                components.pop()\n            self._components = tuple(components)\n\n            # if the encoding is not given, leave it as undefined (None)\n        self.encodings = _verify_encodings(encodings)\n        self._dict = {}\n\n    def _create_dict(self):\n        \"\"\"Creates a dictionary of person name group and component names.\n\n        Used exclusively for `formatted` for backwards compatibility.\n        \"\"\"\n        if not self._dict:\n            for name in ('family_name', 'given_name', 'middle_name',\n                         'name_prefix', 'name_suffix',\n                         'ideographic', 'phonetic'):\n                self._dict[name] = getattr(self, name, '')\n\n    @property\n    def components(self):\n        \"\"\"Returns up to three decoded person name components.\n\n        .. versionadded:: 1.2\n\n        The returned components represent the alphabetic, ideographic and\n        phonetic representations as a list of unicode strings.\n        \"\"\"\n        if self._components is None:\n            groups = self.original_string.split(b'=')\n            encodings = self.encodings or [default_encoding]\n            self._components = _decode_personname(groups, encodings)\n\n        return self._components\n\n    def _name_part(self, i):\n        try:\n            return self.components[0].split('^')[i]\n        except IndexError:\n            return ''\n\n    @property\n    def family_name(self):\n        \"\"\"Return the first (family name) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(0)\n\n    @property\n    def given_name(self):\n        \"\"\"Return the second (given name) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(1)\n\n    @property\n    def middle_name(self):\n        \"\"\"Return the third (middle name) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(2)\n\n    @property\n    def name_prefix(self):\n        \"\"\"Return the fourth (name prefix) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(3)\n\n    @property\n    def name_suffix(self):\n        \"\"\"Return the fifth (name suffix) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(4)\n\n    @property\n    def ideographic(self):\n        \"\"\"Return the second (ideographic) person name component as a\n        unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        try:\n            return self.components[1]\n        except IndexError:\n            return ''\n\n    @property\n    def phonetic(self):\n        \"\"\"Return the third (phonetic) person name component as a\n        unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        try:\n            return self.components[2]\n        except IndexError:\n            return ''\n\n    def __eq__(self, other):\n        return str(self) == other\n\n    def __ne__(self, other):\n        return not self == other\n\n    def __str__(self):\n        return '='.join(self.components).__str__()\n\n    def __next__(self):\n        # Get next character or stop iteration\n        if self._i < self._rep_len:\n            c = self._str_rep[self._i]\n            self._i += 1\n            return c\n        else:\n            raise StopIteration\n\n    def __iter__(self):\n        # Get string rep. and length, initialize index counter\n        self._str_rep = self.__str__()\n        self._rep_len = len(self._str_rep)\n        self._i = 0\n        return self\n\n    def __contains__(self, x):\n        return x in self.__str__()\n\n    def __repr__(self):\n        return '='.join(self.components).__repr__()\n\n    def __hash__(self):\n        return hash(self.components)\n\n    def decode(self, encodings=None):\n        \"\"\"Return the patient name decoded by the given `encodings`.\n\n        Parameters\n        ----------\n        encodings : list of str\n            The list of encodings used for decoding the byte string. If not\n            given, the initial encodings set in the object are used.\n\n        Returns\n        -------\n        valuerep.PersonName\n            A person name object that will return the decoded string with\n            the given encodings on demand. If the encodings are not given,\n            the current object is returned.\n        \"\"\"\n        # in the common case (encoding did not change) we decode on demand\n        if encodings is None or encodings == self.encodings:\n            return self\n        # the encoding was unknown or incorrect - create a new\n        # PersonName object with the changed encoding\n        encodings = _verify_encodings(encodings)\n        if self.original_string is None:\n            # if the original encoding was not set, we set it now\n            self.original_string = _encode_personname(\n                self.components, self.encodings or [default_encoding])\n        return PersonName(self.original_string, encodings)\n\n    def encode(self, encodings=None):\n        \"\"\"Return the patient name decoded by the given `encodings`.\n\n        Parameters\n        ----------\n        encodings : list of str\n            The list of encodings used for encoding the unicode string. If\n            not given, the initial encodings set in the object are used.\n\n        Returns\n        -------\n        bytes\n            The person name encoded with the given encodings as a byte string.\n            If no encoding is given, the original byte string is returned, if\n            available, otherwise each group of the patient name is encoded\n            with the first matching of the given encodings.\n        \"\"\"\n        encodings = _verify_encodings(encodings) or self.encodings\n\n        # if the encoding is not the original encoding, we have to return\n        # a re-encoded string (without updating the original string)\n        if encodings != self.encodings and self.encodings is not None:\n            return _encode_personname(self.components, encodings)\n        if self.original_string is None:\n            # if the original encoding was not set, we set it now\n            self.original_string = _encode_personname(\n                self.components, encodings or [default_encoding])\n        return self.original_string\n\n    def family_comma_given(self):\n        return self.formatted('%(family_name)s, %(given_name)s')\n\n    def formatted(self, format_str):\n        self._create_dict()\n        return format_str % self._dict\n\n    def __bool__(self):\n        if self.original_string is None:\n            return (bool(self._components) and\n                    (len(self._components) > 1 or bool(self._components[0])))\n        return bool(self.original_string)\n\n\n# Alias old class names for backwards compat in user code\nPersonNameUnicode = PersonName = PersonName\n","header":{"file":{"path":"pydicom/valuerep.py"},"misc_line":null},"index_line":null,"is_binary_file":false,"binary_line":null,"minus_file":{"path":"a/pydicom/valuerep.py"},"plus_file":{"path":"b/pydicom/valuerep.py"},"hunks":[{"descriptor":{"old_range":{"start":1,"length":6},"new_range":{"start":1,"length":5},"section":""},"line_group":{"all_lines":[{"content":"# Copyright 2008-2018 pydicom authors. See LICENSE file for details.","type":"context"},{"content":"\"\"\"Special classes for DICOM value representations (VR)\"\"\"","type":"context"},{"content":"from copy import deepcopy","type":"deleted"},{"content":"from decimal import Decimal","type":"context"},{"content":"import re","type":"context"},{"content":"","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]},{"descriptor":{"old_range":{"start":750,"length":6},"new_range":{"start":749,"length":25},"section":"def __ne__(self, other):"},"line_group":{"all_lines":[{"content":"    def __str__(self):","type":"context"},{"content":"        return '='.join(self.components).__str__()","type":"context"},{"content":"","type":"context"},{"content":"    def __next__(self):","type":"added"},{"content":"        # Get next character or stop iteration","type":"added"},{"content":"        if self._i < self._rep_len:","type":"added"},{"content":"            c = self._str_rep[self._i]","type":"added"},{"content":"            self._i += 1","type":"added"},{"content":"            return c","type":"added"},{"content":"        else:","type":"added"},{"content":"            raise StopIteration","type":"added"},{"content":"","type":"added"},{"content":"    def __iter__(self):","type":"added"},{"content":"        # Get string rep. and length, initialize index counter","type":"added"},{"content":"        self._str_rep = self.__str__()","type":"added"},{"content":"        self._rep_len = len(self._str_rep)","type":"added"},{"content":"        self._i = 0","type":"added"},{"content":"        return self","type":"added"},{"content":"","type":"added"},{"content":"    def __contains__(self, x):","type":"added"},{"content":"        return x in self.__str__()","type":"added"},{"content":"","type":"added"},{"content":"    def __repr__(self):","type":"context"},{"content":"        return '='.join(self.components).__repr__()","type":"context"},{"content":"","type":"context"},{"content":"","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]}]}],"old_commit_hash":"b9fb05c177b685bf683f7f57b2d57374eb7d882d","new_commit_hash":"2e9301e8801e6e30c71ccf6833ec2562420bfbbd","commit_message":"next() no longer starts iterator","commit_date":"2020-06-29T10:45:31+02:00","metadata":{}}
problem_statement: Make PersonName3 iterable
  ```python
  from pydicom import Dataset
  
  ds = Dataset()
  ds.PatientName = 'SomeName'
  
  'S' in ds.PatientName
  ```
  ```
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  TypeError: argument of type 'PersonName3' is not iterable
  ```
  
  I'm not really sure if this is intentional or if PN elements should support `str` methods. And yes I know I can `str(ds.PatientName)` but it's a bit silly, especially when I keep having to write exceptions to my element iterators just for PN elements.
  
patch: diff --git a/pydicom/valuerep.py b/pydicom/valuerep.py
  --- a/pydicom/valuerep.py
  +++ b/pydicom/valuerep.py
  @@ -1,6 +1,5 @@
   # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
   """Special classes for DICOM value representations (VR)"""
  -from copy import deepcopy
   from decimal import Decimal
   import re
   
  @@ -750,6 +749,25 @@ def __ne__(self, other):
       def __str__(self):
           return '='.join(self.components).__str__()
   
  +    def __next__(self):
  +        # Get next character or stop iteration
  +        if self._i < self._rep_len:
  +            c = self._str_rep[self._i]
  +            self._i += 1
  +            return c
  +        else:
  +            raise StopIteration
  +
  +    def __iter__(self):
  +        # Get string rep. and length, initialize index counter
  +        self._str_rep = self.__str__()
  +        self._rep_len = len(self._str_rep)
  +        self._i = 0
  +        return self
  +
  +    def __contains__(self, x):
  +        return x in self.__str__()
  +
       def __repr__(self):
           return '='.join(self.components).__repr__()
   
   
  
file_context: {"pydicom/valuerep.py": "# Copyright 2008-2018 pydicom authors. See LICENSE file for details.\n\"\"\"Special classes for DICOM value representations (VR)\"\"\"\nfrom copy import deepcopy\nfrom decimal import Decimal\nimport re\n\nfrom datetime import (date, datetime, time, timedelta, timezone)\n\n# don't import datetime_conversion directly\nfrom pydicom import config\nfrom pydicom.multival import MultiValue\n\n# can't import from charset or get circular import\ndefault_encoding = \"iso8859\"\n\n# For reading/writing data elements,\n# these ones have longer explicit VR format\n# Taken from PS3.5 Section 7.1.2\nextra_length_VRs = ('OB', 'OD', 'OF', 'OL', 'OW', 'SQ', 'UC', 'UN', 'UR', 'UT')\n\n# VRs that can be affected by character repertoire\n# in (0008,0005) Specific Character Set\n# See PS-3.5 (2011), section 6.1.2 Graphic Characters\n# and PN, but it is handled separately.\ntext_VRs = ('SH', 'LO', 'ST', 'LT', 'UC', 'UT')\n\n# Delimiters for text strings and person name that reset the encoding.\n# See PS3.5, Section 6.1.2.5.3\n# Note: We use character codes for Python 3\n# because those are the types yielded if iterating over a byte string.\n\n# Characters/Character codes for text VR delimiters: LF, CR, TAB, FF\nTEXT_VR_DELIMS = {0x0d, 0x0a, 0x09, 0x0c}\n\n# Character/Character code for PN delimiter: name part separator '^'\n# (the component separator '=' is handled separately)\nPN_DELIMS = {0xe5}\n\n\nclass DA(date):\n    \"\"\"Store value for an element with VR **DA** as :class:`datetime.date`.\n\n    Note that the :class:`datetime.date` base class is immutable.\n    \"\"\"\n    __slots__ = ['original_string']\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __reduce__(self):\n        return super(DA, self).__reduce__() + (self.__getstate__(),)\n\n    def __reduce_ex__(self, protocol):\n        return super(DA, self).__reduce__() + (self.__getstate__(),)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of DA object.\n\n        Raise an exception if the string cannot be parsed or the argument\n        is otherwise incompatible.\n\n        Parameters\n        ----------\n        val : str\n            A string conformant to the DA definition in the DICOM Standard,\n            Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.\n        \"\"\"\n        if isinstance(val, str):\n            if len(val) == 8:\n                year = int(val[0:4])\n                month = int(val[4:6])\n                day = int(val[6:8])\n                val = super(DA, cls).__new__(cls, year, month, day)\n            elif len(val) == 10 and val[4] == '.' and val[7] == '.':\n                # ACR-NEMA Standard 300, predecessor to DICOM\n                # for compatibility with a few old pydicom example files\n                year = int(val[0:4])\n                month = int(val[5:7])\n                day = int(val[8:10])\n                val = super(DA, cls).__new__(cls, year, month, day)\n            elif val == '':\n                val = None  # empty date\n            else:\n                try:\n                    val = super(DA, cls).__new__(cls, val)\n                except TypeError:\n                    raise ValueError(\"Cannot convert to datetime: '%s'\" %\n                                     (val))\n        elif isinstance(val, date):\n            val = super(DA, cls).__new__(cls, val.year, val.month, val.day)\n        else:\n            val = super(DA, cls).__new__(cls, val)\n        return val\n\n    def __init__(self, val):\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, DA) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n        else:\n            return super(DA, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\nclass DT(datetime):\n    \"\"\"Store value for an element with VR **DT** as :class:`datetime.datetime`.\n\n    Note that the :class:`datetime.datetime` base class is immutable.\n    \"\"\"\n    __slots__ = ['original_string']\n    _regex_dt = re.compile(r\"((\\d{4,14})(\\.(\\d{1,6}))?)([+-]\\d{4})?\")\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __reduce__(self):\n        return super(DT, self).__reduce__() + (self.__getstate__(),)\n\n    def __reduce_ex__(self, protocol):\n        return super(DT, self).__reduce__() + (self.__getstate__(),)\n\n    @staticmethod\n    def _utc_offset(offset, name):\n        return timezone(timedelta(seconds=offset), name)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of DT object.\n\n        Raise an exception if the string cannot be parsed or the argument\n        is otherwise incompatible.\n\n        Parameters\n        ----------\n        val : str\n            A string conformant to the DT definition in the DICOM Standard,\n            Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.\n        \"\"\"\n        if isinstance(val, str):\n            match = DT._regex_dt.match(val)\n            if match and len(val) <= 26:\n                dt_match = match.group(2)\n                year = int(dt_match[0:4])\n                if len(dt_match) < 6:\n                    month = 1\n                else:\n                    month = int(dt_match[4:6])\n                if len(dt_match) < 8:\n                    day = 1\n                else:\n                    day = int(dt_match[6:8])\n                if len(dt_match) < 10:\n                    hour = 0\n                else:\n                    hour = int(dt_match[8:10])\n                if len(dt_match) < 12:\n                    minute = 0\n                else:\n                    minute = int(dt_match[10:12])\n                if len(dt_match) < 14:\n                    second = 0\n                    microsecond = 0\n                else:\n                    second = int(dt_match[12:14])\n                    ms_match = match.group(4)\n                    if ms_match:\n                        microsecond = int(ms_match.rstrip().ljust(6, '0'))\n                    else:\n                        microsecond = 0\n                tz_match = match.group(5)\n                if tz_match:\n                    offset1 = int(tz_match[1:3]) * 60\n                    offset2 = int(tz_match[3:5])\n                    offset = (offset1 + offset2) * 60\n                    if tz_match[0] == '-':\n                        offset = -offset\n                    tzinfo = cls._utc_offset(offset, tz_match)\n                else:\n                    tzinfo = None\n                val = super(DT,\n                            cls).__new__(cls, year, month, day, hour, minute,\n                                         second, microsecond, tzinfo)\n            else:\n                try:\n                    val = super(DT, cls).__new__(cls, val)\n                except TypeError:\n                    raise ValueError(\"Cannot convert to datetime: '%s'\" %\n                                     (val))\n        elif isinstance(val, datetime):\n            val = super(DT, cls).__new__(cls, val.year, val.month, val.day,\n                                         val.hour, val.minute, val.second,\n                                         val.microsecond, val.tzinfo)\n        else:\n            val = super(DT, cls).__new__(cls, val)\n        return val\n\n    def __init__(self, val):\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, DT) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n        else:\n            return super(DT, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\nclass TM(time):\n    \"\"\"Store value for an element with VR **TM** as :class:`datetime.time`.\n\n    Note that the :class:`datetime.time` base class is immutable.\n    \"\"\"\n    __slots__ = ['original_string']\n    _regex_tm = re.compile(r\"(\\d{2,6})(\\.(\\d{1,6}))?\")\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __reduce__(self):\n        return super(TM, self).__reduce__() + (self.__getstate__(),)\n\n    def __reduce_ex__(self, protocol):\n        return super(TM, self).__reduce__() + (self.__getstate__(),)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of TM object from a string.\n\n        Raise an exception if the string cannot be parsed or the argument\n        is otherwise incompatible.\n\n        Parameters\n        ----------\n        val : str\n            A string conformant to the TM definition in the DICOM Standard,\n            Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.\n        \"\"\"\n        if isinstance(val, str):\n            match = TM._regex_tm.match(val)\n            if match and len(val) <= 16:\n                tm_match = match.group(1)\n                hour = int(tm_match[0:2])\n                if len(tm_match) < 4:\n                    minute = 0\n                else:\n                    minute = int(tm_match[2:4])\n                if len(tm_match) < 6:\n                    second = 0\n                    microsecond = 0\n                else:\n                    second = int(tm_match[4:6])\n                    ms_match = match.group(3)\n                    if ms_match:\n                        microsecond = int(ms_match.rstrip().ljust(6, '0'))\n                    else:\n                        microsecond = 0\n                val = super(TM, cls).__new__(cls, hour, minute, second,\n                                             microsecond)\n            elif val == '':\n                val = None  # empty time\n            else:\n                try:\n                    val = super(TM, cls).__new__(cls, val)\n                except TypeError:\n                    raise ValueError(\"Cannot convert to datetime: '%s\" % (val))\n        elif isinstance(val, time):\n            val = super(TM, cls).__new__(cls, val.hour, val.minute, val.second,\n                                         val.microsecond)\n        else:\n            val = super(TM, cls).__new__(cls, val)\n        return val\n\n    def __init__(self, val):\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, TM) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n        else:\n            return super(TM, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\nclass DSfloat(float):\n    \"\"\"Store value for an element with VR **DS** as :class:`float`.\n\n    If constructed from an empty string, return the empty string,\n    not an instance of this class.\n\n    \"\"\"\n    __slots__ = ['original_string']\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __init__(self, val):\n        \"\"\"Store the original string if one given, for exact write-out of same\n        value later.\n        \"\"\"\n        # ... also if user changes a data element value, then will get\n        # a different object, because float is immutable.\n\n        has_attribute = hasattr(val, 'original_string')\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, (DSfloat, DSdecimal)) and has_attribute:\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n\n        # Issue #937 (Python 3.8 compatibility)\n        return repr(self)[1:-1]\n\n    def __repr__(self):\n        return '\"{}\"'.format(super(DSfloat, self).__repr__())\n\n\nclass DSdecimal(Decimal):\n    \"\"\"Store value for an element with VR **DS** as :class:`decimal.Decimal`.\n\n    Notes\n    -----\n    If constructed from an empty string, returns the empty string, not an\n    instance of this class.\n    \"\"\"\n    __slots__ = ['original_string']\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of DS object, or return a blank string if one is\n        passed in, e.g. from a type 2 DICOM blank value.\n\n        Parameters\n        ----------\n        val : str or numeric\n            A string or a number type which can be converted to a decimal.\n        \"\"\"\n        # Store this value here so that if the input string is actually a valid\n        # string but decimal.Decimal transforms it to an invalid string it will\n        # still be initialized properly\n        enforce_length = config.enforce_valid_values\n        # DICOM allows spaces around the string,\n        # but python doesn't, so clean it\n        if isinstance(val, str):\n            val = val.strip()\n            # If the input string is actually invalid that we relax the valid\n            # value constraint for this particular instance\n            if len(val) <= 16:\n                enforce_length = False\n        if val == '':\n            return val\n        if isinstance(val, float) and not config.allow_DS_float:\n            msg = (\"DS cannot be instantiated with a float value, \"\n                   \"unless config.allow_DS_float is set to True. \"\n                   \"It is recommended to convert to a string instead, \"\n                   \"with the desired number of digits, or use \"\n                   \"Decimal.quantize and pass a Decimal instance.\")\n            raise TypeError(msg)\n        if not isinstance(val, Decimal):\n            val = super(DSdecimal, cls).__new__(cls, val)\n        if len(str(val)) > 16 and enforce_length:\n            msg = (\"DS value representation must be <= 16 \"\n                   \"characters by DICOM standard. Initialize with \"\n                   \"a smaller string, or set config.enforce_valid_values \"\n                   \"to False to override, or use Decimal.quantize() and \"\n                   \"initialize with a Decimal instance.\")\n            raise OverflowError(msg)\n        return val\n\n    def __init__(self, val):\n        \"\"\"Store the original string if one given, for exact write-out of same\n        value later. E.g. if set ``'1.23e2'``, :class:`~decimal.Decimal` would\n        write ``'123'``, but :class:`DS` will use the original.\n        \"\"\"\n        # ... also if user changes a data element value, then will get\n        # a different Decimal, as Decimal is immutable.\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, (DSfloat, DSdecimal)) and hasattr(val, 'original_string'):  # noqa\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string') and len(self.original_string) <= 16:  # noqa\n            return self.original_string\n        else:\n            return super(DSdecimal, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\n# CHOOSE TYPE OF DS\nif config.use_DS_decimal:\n    DSclass = DSdecimal\nelse:\n    DSclass = DSfloat\n\n\ndef DS(val):\n    \"\"\"Factory function for creating DS class instances.\n\n    Checks for blank string; if so, returns that, else calls :class:`DSfloat`\n    or :class:`DSdecimal` to create the class instance. This avoids overriding\n    ``DSfloat.__new__()`` (which carries a time penalty for large arrays of\n    DS).\n\n    Similarly the string clean and check can be avoided and :class:`DSfloat`\n    called directly if a string has already been processed.\n    \"\"\"\n    if isinstance(val, str):\n        val = val.strip()\n    if val == '' or val is None:\n        return val\n    return DSclass(val)\n\n\nclass IS(int):\n    \"\"\"Store value for an element with VR **IS** as :class:`int`.\n\n    Stores original integer string for exact rewriting of the string\n    originally read or stored.\n    \"\"\"\n\n    def __new__(cls, val):\n        \"\"\"Create instance if new integer string\"\"\"\n        if val is None:\n            return val\n        if isinstance(val, str) and val.strip() == '':\n            return ''\n\n        newval = super(IS, cls).__new__(cls, val)\n\n        # check if a float or Decimal passed in, then could have lost info,\n        # and will raise error. E.g. IS(Decimal('1')) is ok, but not IS(1.23)\n        if isinstance(val, (float, Decimal)) and newval != val:\n            raise TypeError(\"Could not convert value to integer without loss\")\n        # Checks in case underlying int is >32 bits, DICOM does not allow this\n        check_newval = (newval < -2 ** 31 or newval >= 2 ** 31)\n        if check_newval and config.enforce_valid_values:\n            dcm_limit = \"-2**31 to (2**31 - 1) for IS\"\n            message = \"Value exceeds DICOM limits of %s\" % (dcm_limit)\n            raise OverflowError(message)\n        return newval\n\n    def __init__(self, val):\n        # If a string passed, then store it\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, IS) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n\n        # Issue #937 (Python 3.8 compatibility)\n        return repr(self)[1:-1]\n\n    def __repr__(self):\n        return '\"{}\"'.format(super(IS, self).__repr__())\n\n\ndef MultiString(val, valtype=str):\n    \"\"\"Split a bytestring by delimiters if there are any\n\n    Parameters\n    ----------\n    val : bytes or str\n        DICOM byte string to split up.\n    valtype\n        Default :class:`str`, but can be e.g. :class:`~pydicom.uid.UID` to\n        overwrite to a specific type.\n\n    Returns\n    -------\n    valtype or list of valtype\n        The split value as `valtype` or a :class:`list` of `valtype`.\n    \"\"\"\n    # Remove trailing blank used to pad to even length\n    # 2005.05.25: also check for trailing 0, error made\n    # in PET files we are converting\n\n    while val and (val.endswith(' ') or val.endswith('\\x00')):\n        val = val[:-1]\n    splitup = val.split(\"\\\\\")\n\n    if len(splitup) == 1:\n        val = splitup[0]\n        return valtype(val) if val else val\n    else:\n        return MultiValue(valtype, splitup)\n\n\ndef _verify_encodings(encodings):\n    \"\"\"Checks the encoding to ensure proper format\"\"\"\n    if encodings is not None:\n        if not isinstance(encodings, (list, tuple)):\n            return encodings,\n        return tuple(encodings)\n    return encodings\n\n\ndef _decode_personname(components, encodings):\n    \"\"\"Return a list of decoded person name components.\n\n    Parameters\n    ----------\n    components : list of byte string\n        The list of the up to three encoded person name components\n    encodings : list of str\n        The Python encodings uses to decode `components`.\n\n    Returns\n    -------\n    text type\n        The unicode string representing the person name.\n        If the decoding of some component parts is not possible using the\n        given encodings, they are decoded with the first encoding using\n        replacement characters for bytes that cannot be decoded.\n    \"\"\"\n    from pydicom.charset import decode_string\n\n    if isinstance(components[0], str):\n        comps = components\n    else:\n        comps = [decode_string(comp, encodings, PN_DELIMS)\n                 for comp in components]\n    # Remove empty elements from the end to avoid trailing '='\n    while len(comps) and not comps[-1]:\n        comps.pop()\n    return tuple(comps)\n\n\ndef _encode_personname(components, encodings):\n    \"\"\"Encode a list of text string person name components.\n\n    Parameters\n    ----------\n    components : list of text type\n        The list of the up to three unicode person name components\n    encodings : list of str\n        The Python encodings uses to encode `components`.\n\n    Returns\n    -------\n    byte string\n        The byte string that can be written as a PN DICOM tag value.\n        If the encoding of some component parts is not possible using the\n        given encodings, they are encoded with the first encoding using\n        replacement bytes for characters that cannot be encoded.\n    \"\"\"\n    from pydicom.charset import encode_string\n\n    encoded_comps = []\n    for comp in components:\n        groups = [encode_string(group, encodings)\n                  for group in comp.split('^')]\n        encoded_comps.append(b'^'.join(groups))\n\n    # Remove empty elements from the end\n    while len(encoded_comps) and not encoded_comps[-1]:\n        encoded_comps.pop()\n    return b'='.join(encoded_comps)\n\n\nclass PersonName:\n    def __new__(cls, *args, **kwargs):\n        # Handle None value by returning None instead of a PersonName object\n        if len(args) and args[0] is None:\n            return None\n        return super(PersonName, cls).__new__(cls)\n\n    def __init__(self, val, encodings=None, original_string=None):\n        if isinstance(val, PersonName):\n            encodings = val.encodings\n            self.original_string = val.original_string\n            self._components = tuple(str(val).split('='))\n        elif isinstance(val, bytes):\n            # this is the raw byte string - decode it on demand\n            self.original_string = val\n            self._components = None\n        else:\n            # handle None `val` as empty string\n            val = val or ''\n\n            # this is the decoded string - save the original string if\n            # available for easier writing back\n            self.original_string = original_string\n            components = val.split('=')\n            # Remove empty elements from the end to avoid trailing '='\n            while len(components) and not components[-1]:\n                components.pop()\n            self._components = tuple(components)\n\n            # if the encoding is not given, leave it as undefined (None)\n        self.encodings = _verify_encodings(encodings)\n        self._dict = {}\n\n    def _create_dict(self):\n        \"\"\"Creates a dictionary of person name group and component names.\n\n        Used exclusively for `formatted` for backwards compatibility.\n        \"\"\"\n        if not self._dict:\n            for name in ('family_name', 'given_name', 'middle_name',\n                         'name_prefix', 'name_suffix',\n                         'ideographic', 'phonetic'):\n                self._dict[name] = getattr(self, name, '')\n\n    @property\n    def components(self):\n        \"\"\"Returns up to three decoded person name components.\n\n        .. versionadded:: 1.2\n\n        The returned components represent the alphabetic, ideographic and\n        phonetic representations as a list of unicode strings.\n        \"\"\"\n        if self._components is None:\n            groups = self.original_string.split(b'=')\n            encodings = self.encodings or [default_encoding]\n            self._components = _decode_personname(groups, encodings)\n\n        return self._components\n\n    def _name_part(self, i):\n        try:\n            return self.components[0].split('^')[i]\n        except IndexError:\n            return ''\n\n    @property\n    def family_name(self):\n        \"\"\"Return the first (family name) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(0)\n\n    @property\n    def given_name(self):\n        \"\"\"Return the second (given name) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(1)\n\n    @property\n    def middle_name(self):\n        \"\"\"Return the third (middle name) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(2)\n\n    @property\n    def name_prefix(self):\n        \"\"\"Return the fourth (name prefix) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(3)\n\n    @property\n    def name_suffix(self):\n        \"\"\"Return the fifth (name suffix) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(4)\n\n    @property\n    def ideographic(self):\n        \"\"\"Return the second (ideographic) person name component as a\n        unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        try:\n            return self.components[1]\n        except IndexError:\n            return ''\n\n    @property\n    def phonetic(self):\n        \"\"\"Return the third (phonetic) person name component as a\n        unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        try:\n            return self.components[2]\n        except IndexError:\n            return ''\n\n    def __eq__(self, other):\n        return str(self) == other\n\n    def __ne__(self, other):\n        return not self == other\n\n    def __str__(self):\n        return '='.join(self.components).__str__()\n\n    def __repr__(self):\n        return '='.join(self.components).__repr__()\n\n    def __hash__(self):\n        return hash(self.components)\n\n    def decode(self, encodings=None):\n        \"\"\"Return the patient name decoded by the given `encodings`.\n\n        Parameters\n        ----------\n        encodings : list of str\n            The list of encodings used for decoding the byte string. If not\n            given, the initial encodings set in the object are used.\n\n        Returns\n        -------\n        valuerep.PersonName\n            A person name object that will return the decoded string with\n            the given encodings on demand. If the encodings are not given,\n            the current object is returned.\n        \"\"\"\n        # in the common case (encoding did not change) we decode on demand\n        if encodings is None or encodings == self.encodings:\n            return self\n        # the encoding was unknown or incorrect - create a new\n        # PersonName object with the changed encoding\n        encodings = _verify_encodings(encodings)\n        if self.original_string is None:\n            # if the original encoding was not set, we set it now\n            self.original_string = _encode_personname(\n                self.components, self.encodings or [default_encoding])\n        return PersonName(self.original_string, encodings)\n\n    def encode(self, encodings=None):\n        \"\"\"Return the patient name decoded by the given `encodings`.\n\n        Parameters\n        ----------\n        encodings : list of str\n            The list of encodings used for encoding the unicode string. If\n            not given, the initial encodings set in the object are used.\n\n        Returns\n        -------\n        bytes\n            The person name encoded with the given encodings as a byte string.\n            If no encoding is given, the original byte string is returned, if\n            available, otherwise each group of the patient name is encoded\n            with the first matching of the given encodings.\n        \"\"\"\n        encodings = _verify_encodings(encodings) or self.encodings\n\n        # if the encoding is not the original encoding, we have to return\n        # a re-encoded string (without updating the original string)\n        if encodings != self.encodings and self.encodings is not None:\n            return _encode_personname(self.components, encodings)\n        if self.original_string is None:\n            # if the original encoding was not set, we set it now\n            self.original_string = _encode_personname(\n                self.components, encodings or [default_encoding])\n        return self.original_string\n\n    def family_comma_given(self):\n        return self.formatted('%(family_name)s, %(given_name)s')\n\n    def formatted(self, format_str):\n        self._create_dict()\n        return format_str % self._dict\n\n    def __bool__(self):\n        if self.original_string is None:\n            return (bool(self._components) and\n                    (len(self._components) > 1 or bool(self._components[0])))\n        return bool(self.original_string)\n\n\n# Alias old class names for backwards compat in user code\nPersonNameUnicode = PersonName = PersonName\n"}
filelevel_patches: {"pydicom/valuerep.py": "@@ -1,6 +1,5 @@\n # Copyright 2008-2018 pydicom authors. See LICENSE file for details.\n \"\"\"Special classes for DICOM value representations (VR)\"\"\"\n-from copy import deepcopy\n from decimal import Decimal\n import re\n@@ -750,6 +749,25 @@ def __ne__(self, other):\n     def __str__(self):\n         return '='.join(self.components).__str__()\n \n+    def __next__(self):\n+        # Get next character or stop iteration\n+        if self._i < self._rep_len:\n+            c = self._str_rep[self._i]\n+            self._i += 1\n+            return c\n+        else:\n+            raise StopIteration\n+\n+    def __iter__(self):\n+        # Get string rep. and length, initialize index counter\n+        self._str_rep = self.__str__()\n+        self._rep_len = len(self._str_rep)\n+        self._i = 0\n+        return self\n+\n+    def __contains__(self, x):\n+        return x in self.__str__()\n+\n     def __repr__(self):\n         return '='.join(self.components).__repr__()"}
messages.content: 
  We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Make PersonName3 iterable
  ```python
  from pydicom import Dataset
  
  ds = Dataset()
  ds.PatientName = 'SomeName'
  
  'S' in ds.PatientName
  ```
  ```
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  TypeError: argument of type 'PersonName3' is not iterable
  ```
  
  I'm not really sure if this is intentional or if PN elements should support `str` methods. And yes I know I can `str(ds.PatientName)` but it's a bit silly, especially when I keep having to write exceptions to my element iterators just for PN elements.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  
  --- BEGIN FILE ---
  ```
  ### pydicom/valuerep.py
  # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
  """Special classes for DICOM value representations (VR)"""
  from copy import deepcopy
  from decimal import Decimal
  import re
  
  from datetime import (date, datetime, time, timedelta, timezone)
  
  # don't import datetime_conversion directly
  from pydicom import config
  from pydicom.multival import MultiValue
  
  # can't import from charset or get circular import
  default_encoding = "iso8859"
  
  # For reading/writing data elements,
  # these ones have longer explicit VR format
  # Taken from PS3.5 Section 7.1.2
  extra_length_VRs = ('OB', 'OD', 'OF', 'OL', 'OW', 'SQ', 'UC', 'UN', 'UR', 'UT')
  
  # VRs that can be affected by character repertoire
  # in (0008,0005) Specific Character Set
  # See PS-3.5 (2011), section 6.1.2 Graphic Characters
  # and PN, but it is handled separately.
  text_VRs = ('SH', 'LO', 'ST', 'LT', 'UC', 'UT')
  
  # Delimiters for text strings and person name that reset the encoding.
  # See PS3.5, Section 6.1.2.5.3
  # Note: We use character codes for Python 3
  # because those are the types yielded if iterating over a byte string.
  
  # Characters/Character codes for text VR delimiters: LF, CR, TAB, FF
  TEXT_VR_DELIMS = {0x0d, 0x0a, 0x09, 0x0c}
  
  # Character/Character code for PN delimiter: name part separator '^'
  # (the component separator '=' is handled separately)
  PN_DELIMS = {0xe5}
  
  
  class DA(date):
      """Store value for an element with VR **DA** as :class:`datetime.date`.
  
      Note that the :class:`datetime.date` base class is immutable.
      """
      __slots__ = ['original_string']
  
      def __getstate__(self):
          return dict((slot, getattr(self, slot)) for slot in self.__slots__
                      if hasattr(self, slot))
  
      def __setstate__(self, state):
          for slot, value in state.items():
              setattr(self, slot, value)
  
      def __reduce__(self):
          return super(DA, self).__reduce__() + (self.__getstate__(),)
  
      def __reduce_ex__(self, protocol):
          return super(DA, self).__reduce__() + (self.__getstate__(),)
  
      def __new__(cls, val):
          """Create an instance of DA object.
  
          Raise an exception if the string cannot be parsed or the argument
          is otherwise incompatible.
  
          Parameters
          ----------
          val : str
              A string conformant to the DA definition in the DICOM Standard,
              Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.
          """
          if isinstance(val, str):
              if len(val) == 8:
                  year = int(val[0:4])
                  month = int(val[4:6])
                  day = int(val[6:8])
                  val = super(DA, cls).__new__(cls, year, month, day)
              elif len(val) == 10 and val[4] == '.' and val[7] == '.':
                  # ACR-NEMA Standard 300, predecessor to DICOM
                  # for compatibility with a few old pydicom example files
                  year = int(val[0:4])
                  month = int(val[5:7])
                  day = int(val[8:10])
                  val = super(DA, cls).__new__(cls, year, month, day)
              elif val == '':
                  val = None  # empty date
              else:
                  try:
                      val = super(DA, cls).__new__(cls, val)
                  except TypeError:
                      raise ValueError("Cannot convert to datetime: '%s'" %
                                       (val))
          elif isinstance(val, date):
              val = super(DA, cls).__new__(cls, val.year, val.month, val.day)
          else:
              val = super(DA, cls).__new__(cls, val)
          return val
  
      def __init__(self, val):
          if isinstance(val, str):
              self.original_string = val
          elif isinstance(val, DA) and hasattr(val, 'original_string'):
              self.original_string = val.original_string
  
      def __str__(self):
          if hasattr(self, 'original_string'):
              return self.original_string
          else:
              return super(DA, self).__str__()
  
      def __repr__(self):
          return "\"" + str(self) + "\""
  
  
  class DT(datetime):
      """Store value for an element with VR **DT** as :class:`datetime.datetime`.
  
      Note that the :class:`datetime.datetime` base class is immutable.
      """
      __slots__ = ['original_string']
      _regex_dt = re.compile(r"((\d{4,14})(\.(\d{1,6}))?)([+-]\d{4})?")
  
      def __getstate__(self):
          return dict((slot, getattr(self, slot)) for slot in self.__slots__
                      if hasattr(self, slot))
  
      def __setstate__(self, state):
          for slot, value in state.items():
              setattr(self, slot, value)
  
      def __reduce__(self):
          return super(DT, self).__reduce__() + (self.__getstate__(),)
  
      def __reduce_ex__(self, protocol):
          return super(DT, self).__reduce__() + (self.__getstate__(),)
  
      @staticmethod
      def _utc_offset(offset, name):
          return timezone(timedelta(seconds=offset), name)
  
      def __new__(cls, val):
          """Create an instance of DT object.
  
          Raise an exception if the string cannot be parsed or the argument
          is otherwise incompatible.
  
          Parameters
          ----------
          val : str
              A string conformant to the DT definition in the DICOM Standard,
              Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.
          """
          if isinstance(val, str):
              match = DT._regex_dt.match(val)
              if match and len(val) <= 26:
                  dt_match = match.group(2)
                  year = int(dt_match[0:4])
                  if len(dt_match) < 6:
                      month = 1
                  else:
                      month = int(dt_match[4:6])
                  if len(dt_match) < 8:
                      day = 1
                  else:
                      day = int(dt_match[6:8])
                  if len(dt_match) < 10:
                      hour = 0
                  else:
                      hour = int(dt_match[8:10])
                  if len(dt_match) < 12:
                      minute = 0
                  else:
                      minute = int(dt_match[10:12])
                  if len(dt_match) < 14:
                      second = 0
                      microsecond = 0
                  else:
                      second = int(dt_match[12:14])
                      ms_match = match.group(4)
                      if ms_match:
                          microsecond = int(ms_match.rstrip().ljust(6, '0'))
                      else:
                          microsecond = 0
                  tz_match = match.group(5)
                  if tz_match:
                      offset1 = int(tz_match[1:3]) * 60
                      offset2 = int(tz_match[3:5])
                      offset = (offset1 + offset2) * 60
                      if tz_match[0] == '-':
                          offset = -offset
                      tzinfo = cls._utc_offset(offset, tz_match)
                  else:
                      tzinfo = None
                  val = super(DT,
                              cls).__new__(cls, year, month, day, hour, minute,
                                           second, microsecond, tzinfo)
              else:
                  try:
                      val = super(DT, cls).__new__(cls, val)
                  except TypeError:
                      raise ValueError("Cannot convert to datetime: '%s'" %
                                       (val))
          elif isinstance(val, datetime):
              val = super(DT, cls).__new__(cls, val.year, val.month, val.day,
                                           val.hour, val.minute, val.second,
                                           val.microsecond, val.tzinfo)
          else:
              val = super(DT, cls).__new__(cls, val)
          return val
  
      def __init__(self, val):
          if isinstance(val, str):
              self.original_string = val
          elif isinstance(val, DT) and hasattr(val, 'original_string'):
              self.original_string = val.original_string
  
      def __str__(self):
          if hasattr(self, 'original_string'):
              return self.original_string
          else:
              return super(DT, self).__str__()
  
      def __repr__(self):
          return "\"" + str(self) + "\""
  
  
  class TM(time):
      """Store value for an element with VR **TM** as :class:`datetime.time`.
  
      Note that the :class:`datetime.time` base class is immutable.
      """
      __slots__ = ['original_string']
      _regex_tm = re.compile(r"(\d{2,6})(\.(\d{1,6}))?")
  
      def __getstate__(self):
          return dict((slot, getattr(self, slot)) for slot in self.__slots__
                      if hasattr(self, slot))
  
      def __setstate__(self, state):
          for slot, value in state.items():
              setattr(self, slot, value)
  
      def __reduce__(self):
          return super(TM, self).__reduce__() + (self.__getstate__(),)
  
      def __reduce_ex__(self, protocol):
          return super(TM, self).__reduce__() + (self.__getstate__(),)
  
      def __new__(cls, val):
          """Create an instance of TM object from a string.
  
          Raise an exception if the string cannot be parsed or the argument
          is otherwise incompatible.
  
          Parameters
          ----------
          val : str
              A string conformant to the TM definition in the DICOM Standard,
              Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.
          """
          if isinstance(val, str):
              match = TM._regex_tm.match(val)
              if match and len(val) <= 16:
                  tm_match = match.group(1)
                  hour = int(tm_match[0:2])
                  if len(tm_match) < 4:
                      minute = 0
                  else:
                      minute = int(tm_match[2:4])
                  if len(tm_match) < 6:
                      second = 0
                      microsecond = 0
                  else:
                      second = int(tm_match[4:6])
                      ms_match = match.group(3)
                      if ms_match:
                          microsecond = int(ms_match.rstrip().ljust(6, '0'))
                      else:
                          microsecond = 0
                  val = super(TM, cls).__new__(cls, hour, minute, second,
                                               microsecond)
              elif val == '':
                  val = None  # empty time
              else:
                  try:
                      val = super(TM, cls).__new__(cls, val)
                  except TypeError:
                      raise ValueError("Cannot convert to datetime: '%s" % (val))
          elif isinstance(val, time):
              val = super(TM, cls).__new__(cls, val.hour, val.minute, val.second,
                                           val.microsecond)
          else:
              val = super(TM, cls).__new__(cls, val)
          return val
  
      def __init__(self, val):
          if isinstance(val, str):
              self.original_string = val
          elif isinstance(val, TM) and hasattr(val, 'original_string'):
              self.original_string = val.original_string
  
      def __str__(self):
          if hasattr(self, 'original_string'):
              return self.original_string
          else:
              return super(TM, self).__str__()
  
      def __repr__(self):
          return "\"" + str(self) + "\""
  
  
  class DSfloat(float):
      """Store value for an element with VR **DS** as :class:`float`.
  
      If constructed from an empty string, return the empty string,
      not an instance of this class.
  
      """
      __slots__ = ['original_string']
  
      def __getstate__(self):
          return dict((slot, getattr(self, slot)) for slot in self.__slots__
                      if hasattr(self, slot))
  
      def __setstate__(self, state):
          for slot, value in state.items():
              setattr(self, slot, value)
  
      def __init__(self, val):
          """Store the original string if one given, for exact write-out of same
          value later.
          """
          # ... also if user changes a data element value, then will get
          # a different object, because float is immutable.
  
          has_attribute = hasattr(val, 'original_string')
          if isinstance(val, str):
              self.original_string = val
          elif isinstance(val, (DSfloat, DSdecimal)) and has_attribute:
              self.original_string = val.original_string
  
      def __str__(self):
          if hasattr(self, 'original_string'):
              return self.original_string
  
          # Issue #937 (Python 3.8 compatibility)
          return repr(self)[1:-1]
  
      def __repr__(self):
          return '"{}"'.format(super(DSfloat, self).__repr__())
  
  
  class DSdecimal(Decimal):
      """Store value for an element with VR **DS** as :class:`decimal.Decimal`.
  
      Notes
      -----
      If constructed from an empty string, returns the empty string, not an
      instance of this class.
      """
      __slots__ = ['original_string']
  
      def __getstate__(self):
          return dict((slot, getattr(self, slot)) for slot in self.__slots__
                      if hasattr(self, slot))
  
      def __setstate__(self, state):
          for slot, value in state.items():
              setattr(self, slot, value)
  
      def __new__(cls, val):
          """Create an instance of DS object, or return a blank string if one is
          passed in, e.g. from a type 2 DICOM blank value.
  
          Parameters
          ----------
          val : str or numeric
              A string or a number type which can be converted to a decimal.
          """
          # Store this value here so that if the input string is actually a valid
          # string but decimal.Decimal transforms it to an invalid string it will
          # still be initialized properly
          enforce_length = config.enforce_valid_values
          # DICOM allows spaces around the string,
          # but python doesn't, so clean it
          if isinstance(val, str):
              val = val.strip()
              # If the input string is actually invalid that we relax the valid
              # value constraint for this particular instance
              if len(val) <= 16:
                  enforce_length = False
          if val == '':
              return val
          if isinstance(val, float) and not config.allow_DS_float:
              msg = ("DS cannot be instantiated with a float value, "
                     "unless config.allow_DS_float is set to True. "
                     "It is recommended to convert to a string instead, "
                     "with the desired number of digits, or use "
                     "Decimal.quantize and pass a Decimal instance.")
              raise TypeError(msg)
          if not isinstance(val, Decimal):
              val = super(DSdecimal, cls).__new__(cls, val)
          if len(str(val)) > 16 and enforce_length:
              msg = ("DS value representation must be <= 16 "
                     "characters by DICOM standard. Initialize with "
                     "a smaller string, or set config.enforce_valid_values "
                     "to False to override, or use Decimal.quantize() and "
                     "initialize with a Decimal instance.")
              raise OverflowError(msg)
          return val
  
      def __init__(self, val):
          """Store the original string if one given, for exact write-out of same
          value later. E.g. if set ``'1.23e2'``, :class:`~decimal.Decimal` would
          write ``'123'``, but :class:`DS` will use the original.
          """
          # ... also if user changes a data element value, then will get
          # a different Decimal, as Decimal is immutable.
          if isinstance(val, str):
              self.original_string = val
          elif isinstance(val, (DSfloat, DSdecimal)) and hasattr(val, 'original_string'):  # noqa
              self.original_string = val.original_string
  
      def __str__(self):
          if hasattr(self, 'original_string') and len(self.original_string) <= 16:  # noqa
              return self.original_string
          else:
              return super(DSdecimal, self).__str__()
  
      def __repr__(self):
          return "\"" + str(self) + "\""
  
  
  # CHOOSE TYPE OF DS
  if config.use_DS_decimal:
      DSclass = DSdecimal
  else:
      DSclass = DSfloat
  
  
  def DS(val):
      """Factory function for creating DS class instances.
  
      Checks for blank string; if so, returns that, else calls :class:`DSfloat`
      or :class:`DSdecimal` to create the class instance. This avoids overriding
      ``DSfloat.__new__()`` (which carries a time penalty for large arrays of
      DS).
  
      Similarly the string clean and check can be avoided and :class:`DSfloat`
      called directly if a string has already been processed.
      """
      if isinstance(val, str):
          val = val.strip()
      if val == '' or val is None:
          return val
      return DSclass(val)
  
  
  class IS(int):
      """Store value for an element with VR **IS** as :class:`int`.
  
      Stores original integer string for exact rewriting of the string
      originally read or stored.
      """
  
      def __new__(cls, val):
          """Create instance if new integer string"""
          if val is None:
              return val
          if isinstance(val, str) and val.strip() == '':
              return ''
  
          newval = super(IS, cls).__new__(cls, val)
  
          # check if a float or Decimal passed in, then could have lost info,
          # and will raise error. E.g. IS(Decimal('1')) is ok, but not IS(1.23)
          if isinstance(val, (float, Decimal)) and newval != val:
              raise TypeError("Could not convert value to integer without loss")
          # Checks in case underlying int is >32 bits, DICOM does not allow this
          check_newval = (newval < -2 ** 31 or newval >= 2 ** 31)
          if check_newval and config.enforce_valid_values:
              dcm_limit = "-2**31 to (2**31 - 1) for IS"
              message = "Value exceeds DICOM limits of %s" % (dcm_limit)
              raise OverflowError(message)
          return newval
  
      def __init__(self, val):
          # If a string passed, then store it
          if isinstance(val, str):
              self.original_string = val
          elif isinstance(val, IS) and hasattr(val, 'original_string'):
              self.original_string = val.original_string
  
      def __str__(self):
          if hasattr(self, 'original_string'):
              return self.original_string
  
          # Issue #937 (Python 3.8 compatibility)
          return repr(self)[1:-1]
  
      def __repr__(self):
          return '"{}"'.format(super(IS, self).__repr__())
  
  
  def MultiString(val, valtype=str):
      """Split a bytestring by delimiters if there are any
  
      Parameters
      ----------
      val : bytes or str
          DICOM byte string to split up.
      valtype
          Default :class:`str`, but can be e.g. :class:`~pydicom.uid.UID` to
          overwrite to a specific type.
  
      Returns
      -------
      valtype or list of valtype
          The split value as `valtype` or a :class:`list` of `valtype`.
      """
      # Remove trailing blank used to pad to even length
      # 2005.05.25: also check for trailing 0, error made
      # in PET files we are converting
  
      while val and (val.endswith(' ') or val.endswith('\x00')):
          val = val[:-1]
      splitup = val.split("\\")
  
      if len(splitup) == 1:
          val = splitup[0]
          return valtype(val) if val else val
      else:
          return MultiValue(valtype, splitup)
  
  
  def _verify_encodings(encodings):
      """Checks the encoding to ensure proper format"""
      if encodings is not None:
          if not isinstance(encodings, (list, tuple)):
              return encodings,
          return tuple(encodings)
      return encodings
  
  
  def _decode_personname(components, encodings):
      """Return a list of decoded person name components.
  
      Parameters
      ----------
      components : list of byte string
          The list of the up to three encoded person name components
      encodings : list of str
          The Python encodings uses to decode `components`.
  
      Returns
      -------
      text type
          The unicode string representing the person name.
          If the decoding of some component parts is not possible using the
          given encodings, they are decoded with the first encoding using
          replacement characters for bytes that cannot be decoded.
      """
      from pydicom.charset import decode_string
  
      if isinstance(components[0], str):
          comps = components
      else:
          comps = [decode_string(comp, encodings, PN_DELIMS)
                   for comp in components]
      # Remove empty elements from the end to avoid trailing '='
      while len(comps) and not comps[-1]:
          comps.pop()
      return tuple(comps)
  
  
  def _encode_personname(components, encodings):
      """Encode a list of text string person name components.
  
      Parameters
      ----------
      components : list of text type
          The list of the up to three unicode person name components
      encodings : list of str
          The Python encodings uses to encode `components`.
  
      Returns
      -------
      byte string
          The byte string that can be written as a PN DICOM tag value.
          If the encoding of some component parts is not possible using the
          given encodings, they are encoded with the first encoding using
          replacement bytes for characters that cannot be encoded.
      """
      from pydicom.charset import encode_string
  
      encoded_comps = []
      for comp in components:
          groups = [encode_string(group, encodings)
                    for group in comp.split('^')]
          encoded_comps.append(b'^'.join(groups))
  
      # Remove empty elements from the end
      while len(encoded_comps) and not encoded_comps[-1]:
          encoded_comps.pop()
      return b'='.join(encoded_comps)
  
  
  class PersonName:
      def __new__(cls, *args, **kwargs):
          # Handle None value by returning None instead of a PersonName object
          if len(args) and args[0] is None:
              return None
          return super(PersonName, cls).__new__(cls)
  
      def __init__(self, val, encodings=None, original_string=None):
          if isinstance(val, PersonName):
              encodings = val.encodings
              self.original_string = val.original_string
              self._components = tuple(str(val).split('='))
          elif isinstance(val, bytes):
              # this is the raw byte string - decode it on demand
              self.original_string = val
              self._components = None
          else:
              # handle None `val` as empty string
              val = val or ''
  
              # this is the decoded string - save the original string if
              # available for easier writing back
              self.original_string = original_string
              components = val.split('=')
              # Remove empty elements from the end to avoid trailing '='
              while len(components) and not components[-1]:
                  components.pop()
              self._components = tuple(components)
  
              # if the encoding is not given, leave it as undefined (None)
          self.encodings = _verify_encodings(encodings)
          self._dict = {}
  
      def _create_dict(self):
          """Creates a dictionary of person name group and component names.
  
          Used exclusively for `formatted` for backwards compatibility.
          """
          if not self._dict:
              for name in ('family_name', 'given_name', 'middle_name',
                           'name_prefix', 'name_suffix',
                           'ideographic', 'phonetic'):
                  self._dict[name] = getattr(self, name, '')
  
      @property
      def components(self):
          """Returns up to three decoded person name components.
  
          .. versionadded:: 1.2
  
          The returned components represent the alphabetic, ideographic and
          phonetic representations as a list of unicode strings.
          """
          if self._components is None:
              groups = self.original_string.split(b'=')
              encodings = self.encodings or [default_encoding]
              self._components = _decode_personname(groups, encodings)
  
          return self._components
  
      def _name_part(self, i):
          try:
              return self.components[0].split('^')[i]
          except IndexError:
              return ''
  
      @property
      def family_name(self):
          """Return the first (family name) group of the alphabetic person name
          representation as a unicode string
  
          .. versionadded:: 1.2
          """
          return self._name_part(0)
  
      @property
      def given_name(self):
          """Return the second (given name) group of the alphabetic person name
          representation as a unicode string
  
          .. versionadded:: 1.2
          """
          return self._name_part(1)
  
      @property
      def middle_name(self):
          """Return the third (middle name) group of the alphabetic person name
          representation as a unicode string
  
          .. versionadded:: 1.2
          """
          return self._name_part(2)
  
      @property
      def name_prefix(self):
          """Return the fourth (name prefix) group of the alphabetic person name
          representation as a unicode string
  
          .. versionadded:: 1.2
          """
          return self._name_part(3)
  
      @property
      def name_suffix(self):
          """Return the fifth (name suffix) group of the alphabetic person name
          representation as a unicode string
  
          .. versionadded:: 1.2
          """
          return self._name_part(4)
  
      @property
      def ideographic(self):
          """Return the second (ideographic) person name component as a
          unicode string
  
          .. versionadded:: 1.2
          """
          try:
              return self.components[1]
          except IndexError:
              return ''
  
      @property
      def phonetic(self):
          """Return the third (phonetic) person name component as a
          unicode string
  
          .. versionadded:: 1.2
          """
          try:
              return self.components[2]
          except IndexError:
              return ''
  
      def __eq__(self, other):
          return str(self) == other
  
      def __ne__(self, other):
          return not self == other
  
      def __str__(self):
          return '='.join(self.components).__str__()
  
      def __repr__(self):
          return '='.join(self.components).__repr__()
  
      def __hash__(self):
          return hash(self.components)
  
      def decode(self, encodings=None):
          """Return the patient name decoded by the given `encodings`.
  
          Parameters
          ----------
          encodings : list of str
              The list of encodings used for decoding the byte string. If not
              given, the initial encodings set in the object are used.
  
          Returns
          -------
          valuerep.PersonName
              A person name object that will return the decoded string with
              the given encodings on demand. If the encodings are not given,
              the current object is returned.
          """
          # in the common case (encoding did not change) we decode on demand
          if encodings is None or encodings == self.encodings:
              return self
          # the encoding was unknown or incorrect - create a new
          # PersonName object with the changed encoding
          encodings = _verify_encodings(encodings)
          if self.original_string is None:
              # if the original encoding was not set, we set it now
              self.original_string = _encode_personname(
                  self.components, self.encodings or [default_encoding])
          return PersonName(self.original_string, encodings)
  
      def encode(self, encodings=None):
          """Return the patient name decoded by the given `encodings`.
  
          Parameters
          ----------
          encodings : list of str
              The list of encodings used for encoding the unicode string. If
              not given, the initial encodings set in the object are used.
  
          Returns
          -------
          bytes
              The person name encoded with the given encodings as a byte string.
              If no encoding is given, the original byte string is returned, if
              available, otherwise each group of the patient name is encoded
              with the first matching of the given encodings.
          """
          encodings = _verify_encodings(encodings) or self.encodings
  
          # if the encoding is not the original encoding, we have to return
          # a re-encoded string (without updating the original string)
          if encodings != self.encodings and self.encodings is not None:
              return _encode_personname(self.components, encodings)
          if self.original_string is None:
              # if the original encoding was not set, we set it now
              self.original_string = _encode_personname(
                  self.components, encodings or [default_encoding])
          return self.original_string
  
      def family_comma_given(self):
          return self.formatted('%(family_name)s, %(given_name)s')
  
      def formatted(self, format_str):
          self._create_dict()
          return format_str % self._dict
  
      def __bool__(self):
          if self.original_string is None:
              return (bool(self._components) and
                      (len(self._components) > 1 or bool(self._components[0])))
          return bool(self.original_string)
  
  
  # Alias old class names for backwards compat in user code
  PersonNameUnicode = PersonName = PersonName
  
  ```
  --- END FILE ---
  
  Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.
  
  Every *SEARCH/REPLACE* edit must use this format:
  1. The file path
  2. The start of search block: <<<<<<< SEARCH
  3. A contiguous chunk of lines to search for in the existing source code
  4. The dividing line: =======
  5. The lines to replace into the source code
  6. The end of the replace block: >>>>>>> REPLACE
  
  Here is an example:
  
  ```python
  ### mathweb/flask/app.py
  <<<<<<< SEARCH
  from flask import Flask
  =======
  import math
  from flask import Flask
  >>>>>>> REPLACE
  ```
  
  Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
  Wrap the *SEARCH/REPLACE* edit in blocks ```python...```.
  
messages.role: user
verification_info: {"file_context": {"pydicom/valuerep.py": "# Copyright 2008-2018 pydicom authors. See LICENSE file for details.\n\"\"\"Special classes for DICOM value representations (VR)\"\"\"\nfrom copy import deepcopy\nfrom decimal import Decimal\nimport re\n\nfrom datetime import (date, datetime, time, timedelta, timezone)\n\n# don't import datetime_conversion directly\nfrom pydicom import config\nfrom pydicom.multival import MultiValue\n\n# can't import from charset or get circular import\ndefault_encoding = \"iso8859\"\n\n# For reading/writing data elements,\n# these ones have longer explicit VR format\n# Taken from PS3.5 Section 7.1.2\nextra_length_VRs = ('OB', 'OD', 'OF', 'OL', 'OW', 'SQ', 'UC', 'UN', 'UR', 'UT')\n\n# VRs that can be affected by character repertoire\n# in (0008,0005) Specific Character Set\n# See PS-3.5 (2011), section 6.1.2 Graphic Characters\n# and PN, but it is handled separately.\ntext_VRs = ('SH', 'LO', 'ST', 'LT', 'UC', 'UT')\n\n# Delimiters for text strings and person name that reset the encoding.\n# See PS3.5, Section 6.1.2.5.3\n# Note: We use character codes for Python 3\n# because those are the types yielded if iterating over a byte string.\n\n# Characters/Character codes for text VR delimiters: LF, CR, TAB, FF\nTEXT_VR_DELIMS = {0x0d, 0x0a, 0x09, 0x0c}\n\n# Character/Character code for PN delimiter: name part separator '^'\n# (the component separator '=' is handled separately)\nPN_DELIMS = {0xe5}\n\n\nclass DA(date):\n    \"\"\"Store value for an element with VR **DA** as :class:`datetime.date`.\n\n    Note that the :class:`datetime.date` base class is immutable.\n    \"\"\"\n    __slots__ = ['original_string']\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __reduce__(self):\n        return super(DA, self).__reduce__() + (self.__getstate__(),)\n\n    def __reduce_ex__(self, protocol):\n        return super(DA, self).__reduce__() + (self.__getstate__(),)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of DA object.\n\n        Raise an exception if the string cannot be parsed or the argument\n        is otherwise incompatible.\n\n        Parameters\n        ----------\n        val : str\n            A string conformant to the DA definition in the DICOM Standard,\n            Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.\n        \"\"\"\n        if isinstance(val, str):\n            if len(val) == 8:\n                year = int(val[0:4])\n                month = int(val[4:6])\n                day = int(val[6:8])\n                val = super(DA, cls).__new__(cls, year, month, day)\n            elif len(val) == 10 and val[4] == '.' and val[7] == '.':\n                # ACR-NEMA Standard 300, predecessor to DICOM\n                # for compatibility with a few old pydicom example files\n                year = int(val[0:4])\n                month = int(val[5:7])\n                day = int(val[8:10])\n                val = super(DA, cls).__new__(cls, year, month, day)\n            elif val == '':\n                val = None  # empty date\n            else:\n                try:\n                    val = super(DA, cls).__new__(cls, val)\n                except TypeError:\n                    raise ValueError(\"Cannot convert to datetime: '%s'\" %\n                                     (val))\n        elif isinstance(val, date):\n            val = super(DA, cls).__new__(cls, val.year, val.month, val.day)\n        else:\n            val = super(DA, cls).__new__(cls, val)\n        return val\n\n    def __init__(self, val):\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, DA) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n        else:\n            return super(DA, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\nclass DT(datetime):\n    \"\"\"Store value for an element with VR **DT** as :class:`datetime.datetime`.\n\n    Note that the :class:`datetime.datetime` base class is immutable.\n    \"\"\"\n    __slots__ = ['original_string']\n    _regex_dt = re.compile(r\"((\\d{4,14})(\\.(\\d{1,6}))?)([+-]\\d{4})?\")\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __reduce__(self):\n        return super(DT, self).__reduce__() + (self.__getstate__(),)\n\n    def __reduce_ex__(self, protocol):\n        return super(DT, self).__reduce__() + (self.__getstate__(),)\n\n    @staticmethod\n    def _utc_offset(offset, name):\n        return timezone(timedelta(seconds=offset), name)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of DT object.\n\n        Raise an exception if the string cannot be parsed or the argument\n        is otherwise incompatible.\n\n        Parameters\n        ----------\n        val : str\n            A string conformant to the DT definition in the DICOM Standard,\n            Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.\n        \"\"\"\n        if isinstance(val, str):\n            match = DT._regex_dt.match(val)\n            if match and len(val) <= 26:\n                dt_match = match.group(2)\n                year = int(dt_match[0:4])\n                if len(dt_match) < 6:\n                    month = 1\n                else:\n                    month = int(dt_match[4:6])\n                if len(dt_match) < 8:\n                    day = 1\n                else:\n                    day = int(dt_match[6:8])\n                if len(dt_match) < 10:\n                    hour = 0\n                else:\n                    hour = int(dt_match[8:10])\n                if len(dt_match) < 12:\n                    minute = 0\n                else:\n                    minute = int(dt_match[10:12])\n                if len(dt_match) < 14:\n                    second = 0\n                    microsecond = 0\n                else:\n                    second = int(dt_match[12:14])\n                    ms_match = match.group(4)\n                    if ms_match:\n                        microsecond = int(ms_match.rstrip().ljust(6, '0'))\n                    else:\n                        microsecond = 0\n                tz_match = match.group(5)\n                if tz_match:\n                    offset1 = int(tz_match[1:3]) * 60\n                    offset2 = int(tz_match[3:5])\n                    offset = (offset1 + offset2) * 60\n                    if tz_match[0] == '-':\n                        offset = -offset\n                    tzinfo = cls._utc_offset(offset, tz_match)\n                else:\n                    tzinfo = None\n                val = super(DT,\n                            cls).__new__(cls, year, month, day, hour, minute,\n                                         second, microsecond, tzinfo)\n            else:\n                try:\n                    val = super(DT, cls).__new__(cls, val)\n                except TypeError:\n                    raise ValueError(\"Cannot convert to datetime: '%s'\" %\n                                     (val))\n        elif isinstance(val, datetime):\n            val = super(DT, cls).__new__(cls, val.year, val.month, val.day,\n                                         val.hour, val.minute, val.second,\n                                         val.microsecond, val.tzinfo)\n        else:\n            val = super(DT, cls).__new__(cls, val)\n        return val\n\n    def __init__(self, val):\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, DT) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n        else:\n            return super(DT, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\nclass TM(time):\n    \"\"\"Store value for an element with VR **TM** as :class:`datetime.time`.\n\n    Note that the :class:`datetime.time` base class is immutable.\n    \"\"\"\n    __slots__ = ['original_string']\n    _regex_tm = re.compile(r\"(\\d{2,6})(\\.(\\d{1,6}))?\")\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __reduce__(self):\n        return super(TM, self).__reduce__() + (self.__getstate__(),)\n\n    def __reduce_ex__(self, protocol):\n        return super(TM, self).__reduce__() + (self.__getstate__(),)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of TM object from a string.\n\n        Raise an exception if the string cannot be parsed or the argument\n        is otherwise incompatible.\n\n        Parameters\n        ----------\n        val : str\n            A string conformant to the TM definition in the DICOM Standard,\n            Part 5, :dcm:`Table 6.2-1<part05/sect_6.2.html#table_6.2-1>`.\n        \"\"\"\n        if isinstance(val, str):\n            match = TM._regex_tm.match(val)\n            if match and len(val) <= 16:\n                tm_match = match.group(1)\n                hour = int(tm_match[0:2])\n                if len(tm_match) < 4:\n                    minute = 0\n                else:\n                    minute = int(tm_match[2:4])\n                if len(tm_match) < 6:\n                    second = 0\n                    microsecond = 0\n                else:\n                    second = int(tm_match[4:6])\n                    ms_match = match.group(3)\n                    if ms_match:\n                        microsecond = int(ms_match.rstrip().ljust(6, '0'))\n                    else:\n                        microsecond = 0\n                val = super(TM, cls).__new__(cls, hour, minute, second,\n                                             microsecond)\n            elif val == '':\n                val = None  # empty time\n            else:\n                try:\n                    val = super(TM, cls).__new__(cls, val)\n                except TypeError:\n                    raise ValueError(\"Cannot convert to datetime: '%s\" % (val))\n        elif isinstance(val, time):\n            val = super(TM, cls).__new__(cls, val.hour, val.minute, val.second,\n                                         val.microsecond)\n        else:\n            val = super(TM, cls).__new__(cls, val)\n        return val\n\n    def __init__(self, val):\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, TM) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n        else:\n            return super(TM, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\nclass DSfloat(float):\n    \"\"\"Store value for an element with VR **DS** as :class:`float`.\n\n    If constructed from an empty string, return the empty string,\n    not an instance of this class.\n\n    \"\"\"\n    __slots__ = ['original_string']\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __init__(self, val):\n        \"\"\"Store the original string if one given, for exact write-out of same\n        value later.\n        \"\"\"\n        # ... also if user changes a data element value, then will get\n        # a different object, because float is immutable.\n\n        has_attribute = hasattr(val, 'original_string')\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, (DSfloat, DSdecimal)) and has_attribute:\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n\n        # Issue #937 (Python 3.8 compatibility)\n        return repr(self)[1:-1]\n\n    def __repr__(self):\n        return '\"{}\"'.format(super(DSfloat, self).__repr__())\n\n\nclass DSdecimal(Decimal):\n    \"\"\"Store value for an element with VR **DS** as :class:`decimal.Decimal`.\n\n    Notes\n    -----\n    If constructed from an empty string, returns the empty string, not an\n    instance of this class.\n    \"\"\"\n    __slots__ = ['original_string']\n\n    def __getstate__(self):\n        return dict((slot, getattr(self, slot)) for slot in self.__slots__\n                    if hasattr(self, slot))\n\n    def __setstate__(self, state):\n        for slot, value in state.items():\n            setattr(self, slot, value)\n\n    def __new__(cls, val):\n        \"\"\"Create an instance of DS object, or return a blank string if one is\n        passed in, e.g. from a type 2 DICOM blank value.\n\n        Parameters\n        ----------\n        val : str or numeric\n            A string or a number type which can be converted to a decimal.\n        \"\"\"\n        # Store this value here so that if the input string is actually a valid\n        # string but decimal.Decimal transforms it to an invalid string it will\n        # still be initialized properly\n        enforce_length = config.enforce_valid_values\n        # DICOM allows spaces around the string,\n        # but python doesn't, so clean it\n        if isinstance(val, str):\n            val = val.strip()\n            # If the input string is actually invalid that we relax the valid\n            # value constraint for this particular instance\n            if len(val) <= 16:\n                enforce_length = False\n        if val == '':\n            return val\n        if isinstance(val, float) and not config.allow_DS_float:\n            msg = (\"DS cannot be instantiated with a float value, \"\n                   \"unless config.allow_DS_float is set to True. \"\n                   \"It is recommended to convert to a string instead, \"\n                   \"with the desired number of digits, or use \"\n                   \"Decimal.quantize and pass a Decimal instance.\")\n            raise TypeError(msg)\n        if not isinstance(val, Decimal):\n            val = super(DSdecimal, cls).__new__(cls, val)\n        if len(str(val)) > 16 and enforce_length:\n            msg = (\"DS value representation must be <= 16 \"\n                   \"characters by DICOM standard. Initialize with \"\n                   \"a smaller string, or set config.enforce_valid_values \"\n                   \"to False to override, or use Decimal.quantize() and \"\n                   \"initialize with a Decimal instance.\")\n            raise OverflowError(msg)\n        return val\n\n    def __init__(self, val):\n        \"\"\"Store the original string if one given, for exact write-out of same\n        value later. E.g. if set ``'1.23e2'``, :class:`~decimal.Decimal` would\n        write ``'123'``, but :class:`DS` will use the original.\n        \"\"\"\n        # ... also if user changes a data element value, then will get\n        # a different Decimal, as Decimal is immutable.\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, (DSfloat, DSdecimal)) and hasattr(val, 'original_string'):  # noqa\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string') and len(self.original_string) <= 16:  # noqa\n            return self.original_string\n        else:\n            return super(DSdecimal, self).__str__()\n\n    def __repr__(self):\n        return \"\\\"\" + str(self) + \"\\\"\"\n\n\n# CHOOSE TYPE OF DS\nif config.use_DS_decimal:\n    DSclass = DSdecimal\nelse:\n    DSclass = DSfloat\n\n\ndef DS(val):\n    \"\"\"Factory function for creating DS class instances.\n\n    Checks for blank string; if so, returns that, else calls :class:`DSfloat`\n    or :class:`DSdecimal` to create the class instance. This avoids overriding\n    ``DSfloat.__new__()`` (which carries a time penalty for large arrays of\n    DS).\n\n    Similarly the string clean and check can be avoided and :class:`DSfloat`\n    called directly if a string has already been processed.\n    \"\"\"\n    if isinstance(val, str):\n        val = val.strip()\n    if val == '' or val is None:\n        return val\n    return DSclass(val)\n\n\nclass IS(int):\n    \"\"\"Store value for an element with VR **IS** as :class:`int`.\n\n    Stores original integer string for exact rewriting of the string\n    originally read or stored.\n    \"\"\"\n\n    def __new__(cls, val):\n        \"\"\"Create instance if new integer string\"\"\"\n        if val is None:\n            return val\n        if isinstance(val, str) and val.strip() == '':\n            return ''\n\n        newval = super(IS, cls).__new__(cls, val)\n\n        # check if a float or Decimal passed in, then could have lost info,\n        # and will raise error. E.g. IS(Decimal('1')) is ok, but not IS(1.23)\n        if isinstance(val, (float, Decimal)) and newval != val:\n            raise TypeError(\"Could not convert value to integer without loss\")\n        # Checks in case underlying int is >32 bits, DICOM does not allow this\n        check_newval = (newval < -2 ** 31 or newval >= 2 ** 31)\n        if check_newval and config.enforce_valid_values:\n            dcm_limit = \"-2**31 to (2**31 - 1) for IS\"\n            message = \"Value exceeds DICOM limits of %s\" % (dcm_limit)\n            raise OverflowError(message)\n        return newval\n\n    def __init__(self, val):\n        # If a string passed, then store it\n        if isinstance(val, str):\n            self.original_string = val\n        elif isinstance(val, IS) and hasattr(val, 'original_string'):\n            self.original_string = val.original_string\n\n    def __str__(self):\n        if hasattr(self, 'original_string'):\n            return self.original_string\n\n        # Issue #937 (Python 3.8 compatibility)\n        return repr(self)[1:-1]\n\n    def __repr__(self):\n        return '\"{}\"'.format(super(IS, self).__repr__())\n\n\ndef MultiString(val, valtype=str):\n    \"\"\"Split a bytestring by delimiters if there are any\n\n    Parameters\n    ----------\n    val : bytes or str\n        DICOM byte string to split up.\n    valtype\n        Default :class:`str`, but can be e.g. :class:`~pydicom.uid.UID` to\n        overwrite to a specific type.\n\n    Returns\n    -------\n    valtype or list of valtype\n        The split value as `valtype` or a :class:`list` of `valtype`.\n    \"\"\"\n    # Remove trailing blank used to pad to even length\n    # 2005.05.25: also check for trailing 0, error made\n    # in PET files we are converting\n\n    while val and (val.endswith(' ') or val.endswith('\\x00')):\n        val = val[:-1]\n    splitup = val.split(\"\\\\\")\n\n    if len(splitup) == 1:\n        val = splitup[0]\n        return valtype(val) if val else val\n    else:\n        return MultiValue(valtype, splitup)\n\n\ndef _verify_encodings(encodings):\n    \"\"\"Checks the encoding to ensure proper format\"\"\"\n    if encodings is not None:\n        if not isinstance(encodings, (list, tuple)):\n            return encodings,\n        return tuple(encodings)\n    return encodings\n\n\ndef _decode_personname(components, encodings):\n    \"\"\"Return a list of decoded person name components.\n\n    Parameters\n    ----------\n    components : list of byte string\n        The list of the up to three encoded person name components\n    encodings : list of str\n        The Python encodings uses to decode `components`.\n\n    Returns\n    -------\n    text type\n        The unicode string representing the person name.\n        If the decoding of some component parts is not possible using the\n        given encodings, they are decoded with the first encoding using\n        replacement characters for bytes that cannot be decoded.\n    \"\"\"\n    from pydicom.charset import decode_string\n\n    if isinstance(components[0], str):\n        comps = components\n    else:\n        comps = [decode_string(comp, encodings, PN_DELIMS)\n                 for comp in components]\n    # Remove empty elements from the end to avoid trailing '='\n    while len(comps) and not comps[-1]:\n        comps.pop()\n    return tuple(comps)\n\n\ndef _encode_personname(components, encodings):\n    \"\"\"Encode a list of text string person name components.\n\n    Parameters\n    ----------\n    components : list of text type\n        The list of the up to three unicode person name components\n    encodings : list of str\n        The Python encodings uses to encode `components`.\n\n    Returns\n    -------\n    byte string\n        The byte string that can be written as a PN DICOM tag value.\n        If the encoding of some component parts is not possible using the\n        given encodings, they are encoded with the first encoding using\n        replacement bytes for characters that cannot be encoded.\n    \"\"\"\n    from pydicom.charset import encode_string\n\n    encoded_comps = []\n    for comp in components:\n        groups = [encode_string(group, encodings)\n                  for group in comp.split('^')]\n        encoded_comps.append(b'^'.join(groups))\n\n    # Remove empty elements from the end\n    while len(encoded_comps) and not encoded_comps[-1]:\n        encoded_comps.pop()\n    return b'='.join(encoded_comps)\n\n\nclass PersonName:\n    def __new__(cls, *args, **kwargs):\n        # Handle None value by returning None instead of a PersonName object\n        if len(args) and args[0] is None:\n            return None\n        return super(PersonName, cls).__new__(cls)\n\n    def __init__(self, val, encodings=None, original_string=None):\n        if isinstance(val, PersonName):\n            encodings = val.encodings\n            self.original_string = val.original_string\n            self._components = tuple(str(val).split('='))\n        elif isinstance(val, bytes):\n            # this is the raw byte string - decode it on demand\n            self.original_string = val\n            self._components = None\n        else:\n            # handle None `val` as empty string\n            val = val or ''\n\n            # this is the decoded string - save the original string if\n            # available for easier writing back\n            self.original_string = original_string\n            components = val.split('=')\n            # Remove empty elements from the end to avoid trailing '='\n            while len(components) and not components[-1]:\n                components.pop()\n            self._components = tuple(components)\n\n            # if the encoding is not given, leave it as undefined (None)\n        self.encodings = _verify_encodings(encodings)\n        self._dict = {}\n\n    def _create_dict(self):\n        \"\"\"Creates a dictionary of person name group and component names.\n\n        Used exclusively for `formatted` for backwards compatibility.\n        \"\"\"\n        if not self._dict:\n            for name in ('family_name', 'given_name', 'middle_name',\n                         'name_prefix', 'name_suffix',\n                         'ideographic', 'phonetic'):\n                self._dict[name] = getattr(self, name, '')\n\n    @property\n    def components(self):\n        \"\"\"Returns up to three decoded person name components.\n\n        .. versionadded:: 1.2\n\n        The returned components represent the alphabetic, ideographic and\n        phonetic representations as a list of unicode strings.\n        \"\"\"\n        if self._components is None:\n            groups = self.original_string.split(b'=')\n            encodings = self.encodings or [default_encoding]\n            self._components = _decode_personname(groups, encodings)\n\n        return self._components\n\n    def _name_part(self, i):\n        try:\n            return self.components[0].split('^')[i]\n        except IndexError:\n            return ''\n\n    @property\n    def family_name(self):\n        \"\"\"Return the first (family name) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(0)\n\n    @property\n    def given_name(self):\n        \"\"\"Return the second (given name) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(1)\n\n    @property\n    def middle_name(self):\n        \"\"\"Return the third (middle name) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(2)\n\n    @property\n    def name_prefix(self):\n        \"\"\"Return the fourth (name prefix) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(3)\n\n    @property\n    def name_suffix(self):\n        \"\"\"Return the fifth (name suffix) group of the alphabetic person name\n        representation as a unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        return self._name_part(4)\n\n    @property\n    def ideographic(self):\n        \"\"\"Return the second (ideographic) person name component as a\n        unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        try:\n            return self.components[1]\n        except IndexError:\n            return ''\n\n    @property\n    def phonetic(self):\n        \"\"\"Return the third (phonetic) person name component as a\n        unicode string\n\n        .. versionadded:: 1.2\n        \"\"\"\n        try:\n            return self.components[2]\n        except IndexError:\n            return ''\n\n    def __eq__(self, other):\n        return str(self) == other\n\n    def __ne__(self, other):\n        return not self == other\n\n    def __str__(self):\n        return '='.join(self.components).__str__()\n\n    def __repr__(self):\n        return '='.join(self.components).__repr__()\n\n    def __hash__(self):\n        return hash(self.components)\n\n    def decode(self, encodings=None):\n        \"\"\"Return the patient name decoded by the given `encodings`.\n\n        Parameters\n        ----------\n        encodings : list of str\n            The list of encodings used for decoding the byte string. If not\n            given, the initial encodings set in the object are used.\n\n        Returns\n        -------\n        valuerep.PersonName\n            A person name object that will return the decoded string with\n            the given encodings on demand. If the encodings are not given,\n            the current object is returned.\n        \"\"\"\n        # in the common case (encoding did not change) we decode on demand\n        if encodings is None or encodings == self.encodings:\n            return self\n        # the encoding was unknown or incorrect - create a new\n        # PersonName object with the changed encoding\n        encodings = _verify_encodings(encodings)\n        if self.original_string is None:\n            # if the original encoding was not set, we set it now\n            self.original_string = _encode_personname(\n                self.components, self.encodings or [default_encoding])\n        return PersonName(self.original_string, encodings)\n\n    def encode(self, encodings=None):\n        \"\"\"Return the patient name decoded by the given `encodings`.\n\n        Parameters\n        ----------\n        encodings : list of str\n            The list of encodings used for encoding the unicode string. If\n            not given, the initial encodings set in the object are used.\n\n        Returns\n        -------\n        bytes\n            The person name encoded with the given encodings as a byte string.\n            If no encoding is given, the original byte string is returned, if\n            available, otherwise each group of the patient name is encoded\n            with the first matching of the given encodings.\n        \"\"\"\n        encodings = _verify_encodings(encodings) or self.encodings\n\n        # if the encoding is not the original encoding, we have to return\n        # a re-encoded string (without updating the original string)\n        if encodings != self.encodings and self.encodings is not None:\n            return _encode_personname(self.components, encodings)\n        if self.original_string is None:\n            # if the original encoding was not set, we set it now\n            self.original_string = _encode_personname(\n                self.components, encodings or [default_encoding])\n        return self.original_string\n\n    def family_comma_given(self):\n        return self.formatted('%(family_name)s, %(given_name)s')\n\n    def formatted(self, format_str):\n        self._create_dict()\n        return format_str % self._dict\n\n    def __bool__(self):\n        if self.original_string is None:\n            return (bool(self._components) and\n                    (len(self._components) > 1 or bool(self._components[0])))\n        return bool(self.original_string)\n\n\n# Alias old class names for backwards compat in user code\nPersonNameUnicode = PersonName = PersonName\n"}, "filelevel_patches": {"pydicom/valuerep.py": "@@ -1,6 +1,5 @@\n # Copyright 2008-2018 pydicom authors. See LICENSE file for details.\n \"\"\"Special classes for DICOM value representations (VR)\"\"\"\n-from copy import deepcopy\n from decimal import Decimal\n import re\n@@ -750,6 +749,25 @@ def __ne__(self, other):\n     def __str__(self):\n         return '='.join(self.components).__str__()\n \n+    def __next__(self):\n+        # Get next character or stop iteration\n+        if self._i < self._rep_len:\n+            c = self._str_rep[self._i]\n+            self._i += 1\n+            return c\n+        else:\n+            raise StopIteration\n+\n+    def __iter__(self):\n+        # Get string rep. and length, initialize index counter\n+        self._str_rep = self.__str__()\n+        self._rep_len = len(self._str_rep)\n+        self._i = 0\n+        return self\n+\n+    def __contains__(self, x):\n+        return x in self.__str__()\n+\n     def __repr__(self):\n         return '='.join(self.components).__repr__()"}}