Repository: pydicom/pydicom

Issue:
Unlisted Dicom tags cause KeyError, and failure for all other purposes
_From [hans.j.j...@gmail.com](https://code.google.com/u/102769889520564422744/) on September 18, 2010 09:27:51_

What steps will reproduce the problem? 1.  For dicom files with tags that are not listed in the _dicom_dict.py file, the files can not be read, even if the dicom tags are not of any use to the application.
2.  Try to read a dicom file that has a tag (FFFF,FFFF) or (3F03,1001)  (I don't know or care what those tags hold) What is the expected output? What do you see instead? I would expect the program to ignore these tags, or to fill them out with some clearly bogus placeholders to indicate that they are going to silently be ignored.

What I see instead is that the dicom.file_read() throws a KeyError stating that the key is not in the pre-defined dictionary, and the parts of the file that are extractable are not available for querying. What version of the product are you using? I tried both 0.9.4 and 0.9.5rc1. Please provide any additional information below. A hack that works for one of the data sets that was causing problems was to add the missing values to the dictionary.  This is not very satisfying because I can not anticipate all the other instances of not reported tags that will encountered in the future.
[johnsonhj@neuron mpy-svn-stats]$ tail -4 /Library/Python/2.6/site-packages/dicom/_dicom_dict.py
'7Fxx0040': ('OW', '1', "Variable Coefficients SDDN", 'Retired'),
'3F031001': ('NONE', '1', "Unknown Item", ''),
'FFFFFFFF': ('NONE', '1', "Unknown Item", ''),
}
# 

Proposal:

In dicom/datadict.py

replace: 
 41 def get_entry(tag):
 42     """Return the tuple (VR, VM, name, is_retired) from the DICOM dictionary
 43 ····
 44     If the entry is not in the main dictionary, check the masked ones,
 45     e.g. repeating groups like 50xx, etc.
 46     """
 47     tag = Tag(tag)
 48     try:
 49         return DicomDictionary[tag]
 50     except KeyError:
 51         mask_x = mask_match(tag)
 52         if mask_x:
 53             return RepeatersDictionary[mask_x]
 54         else:
**55**          raise KeyError, "Tag &#37;s not found in DICOM dictionary" &#37; Tag(tag)
 56

=============  with =======================================
 41 def get_entry(tag):
 42     """Return the tuple (VR, VM, name, is_retired) from the DICOM dictionary
 43 ····
 44     If the entry is not in the main dictionary, check the masked ones,
 45     e.g. repeating groups like 50xx, etc.
 46     """
 47     tag = Tag(tag)
 48     try:
 49         return DicomDictionary[tag]
 50     except KeyError:
 51         mask_x = mask_match(tag)
 52         if mask_x:
 53             return RepeatersDictionary[mask_x]
 54         else:
**55**          return ('NONE', '1', "Unknown Item : "+str(tag), '')
 56

_Original issue: http://code.google.com/p/pydicom/issues/detail?id=91_


Discussion:
pep8speaks: Hello @scaramallion! Thanks for submitting the PR.

 - In the file [`pydicom/dataset.py`](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py), following are the PEP8 issues :

> [Line 32:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L32): [E101](https://duckduckgo.com/?q=pep8%20E101) indentation contains mixed spaces and tabs
> [Line 32:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L32): [W191](https://duckduckgo.com/?q=pep8%20W191) indentation contains tabs
> [Line 32:8](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L32): [E128](https://duckduckgo.com/?q=pep8%20E128) continuation line under-indented for visual indent
> [Line 39:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L39): [E101](https://duckduckgo.com/?q=pep8%20E101) indentation contains mixed spaces and tabs
> [Line 723:80](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L723): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (87 > 79 characters)
> [Line 750:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L750): [E101](https://duckduckgo.com/?q=pep8%20E101) indentation contains mixed spaces and tabs
> [Line 750:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L750): [W191](https://duckduckgo.com/?q=pep8%20W191) indentation contains tabs
> [Line 751:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L751): [W191](https://duckduckgo.com/?q=pep8%20W191) indentation contains tabs
> [Line 753:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L753): [W191](https://duckduckgo.com/?q=pep8%20W191) indentation contains tabs
> [Line 754:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L754): [W191](https://duckduckgo.com/?q=pep8%20W191) indentation contains tabs
> [Line 755:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L755): [W191](https://duckduckgo.com/?q=pep8%20W191) indentation contains tabs
> [Line 755:3](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L755): [E101](https://duckduckgo.com/?q=pep8%20E101) indentation contains mixed spaces and tabs
> [Line 756:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L756): [W191](https://duckduckgo.com/?q=pep8%20W191) indentation contains tabs
> [Line 758:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L758): [E101](https://duckduckgo.com/?q=pep8%20E101) indentation contains mixed spaces and tabs
> [Line 762:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L762): [E101](https://duckduckgo.com/?q=pep8%20E101) indentation contains mixed spaces and tabs
> [Line 762:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L762): [W191](https://duckduckgo.com/?q=pep8%20W191) indentation contains tabs
> [Line 763:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L763): [E101](https://duckduckgo.com/?q=pep8%20E101) indentation contains mixed spaces and tabs
> [Line 766:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L766): [E101](https://duckduckgo.com/?q=pep8%20E101) indentation contains mixed spaces and tabs
> [Line 766:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L766): [W191](https://duckduckgo.com/?q=pep8%20W191) indentation contains tabs
> [Line 767:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L767): [E101](https://duckduckgo.com/?q=pep8%20E101) indentation contains mixed spaces and tabs
> [Line 770:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L770): [E101](https://duckduckgo.com/?q=pep8%20E101) indentation contains mixed spaces and tabs
> [Line 770:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L770): [W191](https://duckduckgo.com/?q=pep8%20W191) indentation contains tabs
> [Line 770:3](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L770): [E116](https://duckduckgo.com/?q=pep8%20E116) unexpected indentation (comment)
> [Line 771:1](https://github.com/pydicom/pydicom/blob/f241e8e0592818a4d4a9c728d7f67bbb03e3edcb/pydicom/dataset.py#L771): [E101](https://duckduckgo.com/?q=pep8%20E101) indentation contains mixed spaces and tabs







Patch:
diff --git a/LICENSE b/LICENSE
index 23ca9e731..853630cfe 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 License file for pydicom, a pure-python DICOM library
 
-Copyright (c) 2008-2017 Darcy Mason and pydicom contributors
+Copyright (c) 2008-2018 Darcy Mason and pydicom contributors
 
 Except for portions outlined below, pydicom is released under an MIT license:
 
diff --git a/dicom.py b/dicom.py
new file mode 100644
index 000000000..f4fef0c63
--- /dev/null
+++ b/dicom.py
@@ -0,0 +1,11 @@
+msg = """
+Pydicom via 'import dicom' has been removed in pydicom version 1.0.
+Please install the `dicom` package to restore function of code relying
+on pydicom 0.9.9 or earlier. E.g. `pip install dicom`.
+Alternatively, most code can easily be converted to pydicom > 1.0 by
+changing import lines from 'import dicom' to 'import pydicom'.
+See the Transition Guide at
+https://pydicom.github.io/pydicom/stable/transition_to_pydicom1.html.
+"""
+
+raise ImportError(msg)
diff --git a/pydicom/dataset.py b/pydicom/dataset.py
index 1052b8587..a3f2da9d7 100644
--- a/pydicom/dataset.py
+++ b/pydicom/dataset.py
@@ -28,8 +28,8 @@ from pydicom.datadict import (tag_for_keyword, keyword_for_tag,
                               repeater_has_keyword)
 from pydicom.tag import Tag, BaseTag, tag_in_exception
 from pydicom.dataelem import DataElement, DataElement_from_raw, RawDataElement
-from pydicom.uid import (UncompressedPixelTransferSyntaxes, 
-						 ExplicitVRLittleEndian)
+from pydicom.uid import (UncompressedPixelTransferSyntaxes,
+                         ExplicitVRLittleEndian)
 import pydicom  # for dcmwrite
 import pydicom.charset
 from pydicom.config import logger
@@ -400,14 +400,13 @@ class Dataset(dict):
             return True
 
         if isinstance(other, self.__class__):
-            # Compare Elements using values() and class variables using
-            # __dict__
+            # Compare Elements using values()
             # Convert values() to a list for compatibility between
             #   python 2 and 3
             # Sort values() by element tag
             self_elem = sorted(list(self.values()), key=lambda x: x.tag)
             other_elem = sorted(list(other.values()), key=lambda x: x.tag)
-            return self_elem == other_elem and self.__dict__ == other.__dict__
+            return self_elem == other_elem
 
         return NotImplemented
 
@@ -697,9 +696,9 @@ class Dataset(dict):
 
         Returns
         -------
-        None  
+        None
             Converted pixel data is stored internally in the dataset.
-            
+
         If a compressed image format, the image is  decompressed,
         and any related data elements are changed accordingly.
         """
@@ -720,7 +719,9 @@ class Dataset(dict):
                     pixel_array = x.get_pixeldata(self)
                     self._pixel_array = self._reshape_pixel_array(pixel_array)
                     if x.needs_to_convert_to_RGB(self):
-                        self._pixel_array = self._convert_YBR_to_RGB(self._pixel_array)
+                        self._pixel_array = self._convert_YBR_to_RGB(
+                            self._pixel_array
+                        )
                     successfully_read_pixel_data = True
                     break
                 except Exception as e:
@@ -743,31 +744,31 @@ class Dataset(dict):
                     raise NotImplementedError(msg)
             # is this guaranteed to work if memory is re-used??
             self._pixel_id = id(self.PixelData)
-            
+
     def decompress(self):
         """Decompresses pixel data and modifies the Dataset in-place
 
-		If not a compressed tranfer syntax, then pixel data is converted
-		to a numpy array internally, but not returned.
-		
-		If compressed pixel data, then is decompressed using an image handler,
-		and internal state is updated appropriately:
-		    - TransferSyntax is updated to non-compressed form
-			- is_undefined_length for pixel data is set False
+        If not a compressed tranfer syntax, then pixel data is converted
+        to a numpy array internally, but not returned.
+
+        If compressed pixel data, then is decompressed using an image handler,
+        and internal state is updated appropriately:
+            - TransferSyntax is updated to non-compressed form
+            - is_undefined_length for pixel data is set False
 
         Returns
         -------
         None
 
-		Raises
+        Raises
         ------
         NotImplementedError
             If the pixel data was originally compressed but file is not
-			ExplicitVR LittleEndian as required by Dicom standard
-        """		
+            ExplicitVR LittleEndian as required by Dicom standard
+        """
         self.convert_pixel_data()
         self.is_decompressed = True
-		# May have been undefined length pixel data, but won't be now
+        # May have been undefined length pixel data, but won't be now
         if 'PixelData' in self:
             self[0x7fe00010].is_undefined_length = False
 
@@ -780,14 +781,13 @@ class Dataset(dict):
             # Check that current file as read does match expected
             if not self.is_little_endian or self.is_implicit_VR:
                 msg = ("Current dataset does not match expected ExplicitVR "
-                       "LittleEndian transfer syntax from a compressed " 
+                       "LittleEndian transfer syntax from a compressed "
                        "transfer syntax")
                 raise NotImplementedError(msg)
-                
+
             # All is as expected, updated the Transfer Syntax
             self.file_meta.TransferSyntaxUID = ExplicitVRLittleEndian
 
-
     @property
     def pixel_array(self):
         """Return the Pixel Data as a NumPy array.
@@ -1044,10 +1044,12 @@ class Dataset(dict):
 
         Parameters
         ----------
-        start : int or None
-            The slice's starting element tag value.
-        stop : int or None
-            The slice's stopping element tag value.
+        start : int or 2-tuple of int or None
+            The slice's starting element tag value, in any format accepted by
+            pydicom.tag.Tag.
+        stop : int or 2-tuple of int or None
+            The slice's stopping element tag value, in any format accepted by
+            pydicom.tag.Tag.
         step : int or None
             The slice's step size.
 
@@ -1073,7 +1075,18 @@ class Dataset(dict):
         if stop is None:
             stop = all_tags[-1] + 1
 
-        slice_tags = [tag for tag in all_tags if Tag(start) <= tag < Tag(stop)]
+        # Issue 92: if `stop` is None then 0xFFFFFFFF + 1 causes overflow in
+        # Tag. The only this occurs if the `stop` parameter value is None
+        # and the dataset contains an (0xFFFF, 0xFFFF) element
+        if stop == 0x100000000:
+            slice_tags = [
+                tag for tag in all_tags if Tag(start) <= tag <= Tag(stop - 1)
+            ]
+        else:
+            slice_tags = [
+                tag for tag in all_tags if Tag(start) <= tag < Tag(stop)
+            ]
+
         return slice_tags[::step]
 
     def __str__(self):
@@ -1233,3 +1246,29 @@ class FileDataset(Dataset):
         if self.filename and os.path.exists(self.filename):
             statinfo = os.stat(self.filename)
             self.timestamp = statinfo.st_mtime
+
+    def __eq__(self, other):
+        """Compare `self` and `other` for equality.
+
+        Returns
+        -------
+        bool
+            The result if `self` and `other` are the same class
+        NotImplemented
+            If `other` is not the same class as `self` then returning
+            NotImplemented delegates the result to superclass.__eq__(subclass)
+        """
+        # When comparing against self this will be faster
+        if other is self:
+            return True
+
+        if isinstance(other, self.__class__):
+            # Compare Elements using values() and class members using __dict__
+            # Convert values() to a list for compatibility between
+            #   python 2 and 3
+            # Sort values() by element tag
+            self_elem = sorted(list(self.values()), key=lambda x: x.tag)
+            other_elem = sorted(list(other.values()), key=lambda x: x.tag)
+            return self_elem == other_elem and self.__dict__ == other.__dict__
+
+        return NotImplemented
diff --git a/pydicom/filewriter.py b/pydicom/filewriter.py
index ceb809915..01d9a4911 100644
--- a/pydicom/filewriter.py
+++ b/pydicom/filewriter.py
@@ -226,7 +226,10 @@ def write_PN(fp, data_element, padding=b' ', encoding=None):
         val = data_element.value
 
     if isinstance(val[0], compat.text_type) or not in_py2:
-        val = [elem.encode(encoding) for elem in val]
+        try:
+            val = [elem.encode(encoding) for elem in val]
+        except TypeError:
+            val = [elem.encode(encoding[0]) for elem in val]
 
     val = b'\\'.join(val)
 
diff --git a/setup.py b/setup.py
index 579d38952..69f5ac2f5 100755
--- a/setup.py
+++ b/setup.py
@@ -1,12 +1,20 @@
 #!/usr/bin/env python
 
 import os
+import os.path
 import sys
 from glob import glob
 from setuptools import setup, find_packages
 
+have_dicom = True
+try:
+    import dicom
+except ImportError:
+    have_dicom = False
+
 # get __version__ from _version.py
-ver_file = os.path.join('pydicom', '_version.py')
+base_dir = os.path.dirname(os.path.realpath(__file__))
+ver_file = os.path.join(base_dir, 'pydicom', '_version.py')
 with open(ver_file) as f:
     exec(f.read())
 
@@ -32,6 +40,9 @@ an overview of how to use the pydicom library.
 
 needs_pytest = {'pytest', 'test', 'ptr'}.intersection(sys.argv)
 pytest_runner = ['pytest-runner'] if needs_pytest else []
+_py_modules = []
+if not have_dicom:
+    _py_modules = ['dicom']
 
 CLASSIFIERS = [
     "License :: OSI Approved :: MIT License",
@@ -94,6 +105,7 @@ opts = dict(name=NAME,
             keywords=KEYWORDS,
             classifiers=CLASSIFIERS,
             packages=find_packages(),
+            py_modules=_py_modules,
             package_data=PACKAGE_DATA,
             include_package_data=True,
             install_requires=REQUIRES,


Test patch:
diff --git a/pydicom/tests/test_dataset.py b/pydicom/tests/test_dataset.py
index fee7082bc..9fe4e4851 100644
--- a/pydicom/tests/test_dataset.py
+++ b/pydicom/tests/test_dataset.py
@@ -403,32 +403,35 @@ class DatasetTests(unittest.TestCase):
 
     def testEqualityNoSequence(self):
         """Dataset: equality returns correct value with simple dataset"""
+        # Test empty dataset
+        assert Dataset() == Dataset()
+
         d = Dataset()
         d.SOPInstanceUID = '1.2.3.4'
         d.PatientName = 'Test'
-        self.assertTrue(d == d)
+        assert d == d
 
         e = Dataset()
         e.PatientName = 'Test'
         e.SOPInstanceUID = '1.2.3.4'
-        self.assertTrue(d == e)
+        assert d == e
 
         e.SOPInstanceUID = '1.2.3.5'
-        self.assertFalse(d == e)
+        assert not d == e
 
         # Check VR
         del e.SOPInstanceUID
         e.add(DataElement(0x00080018, 'PN', '1.2.3.4'))
-        self.assertFalse(d == e)
+        assert not d == e
 
         # Check Tag
         del e.SOPInstanceUID
         e.StudyInstanceUID = '1.2.3.4'
-        self.assertFalse(d == e)
+        assert not d == e
 
         # Check missing Element in self
         e.SOPInstanceUID = '1.2.3.4'
-        self.assertFalse(d == e)
+        assert not d == e
 
         # Check missing Element in other
         d = Dataset()
@@ -437,7 +440,7 @@ class DatasetTests(unittest.TestCase):
 
         e = Dataset()
         e.SOPInstanceUID = '1.2.3.4'
-        self.assertFalse(d == e)
+        assert not d == e
 
     def testEqualityPrivate(self):
         """Dataset: equality returns correct value"""
@@ -500,16 +503,14 @@ class DatasetTests(unittest.TestCase):
 
     def testEqualityUnknown(self):
         """Dataset: equality returns correct value with extra members """
+        # Non-element class members are ignored in equality testing
         d = Dataset()
         d.SOPEustaceUID = '1.2.3.4'
-        self.assertTrue(d == d)
+        assert d == d
 
         e = Dataset()
-        e.SOPEustaceUID = '1.2.3.4'
-        self.assertTrue(d == e)
-
         e.SOPEustaceUID = '1.2.3.5'
-        self.assertFalse(d == e)
+        assert d == e
 
     def testEqualityInheritance(self):
         """Dataset: equality returns correct value for subclass """
@@ -529,6 +530,19 @@ class DatasetTests(unittest.TestCase):
         self.assertFalse(d == e)
         self.assertFalse(e == d)
 
+    def test_equality_elements(self):
+        """Test that Dataset equality only checks DataElements."""
+        d = Dataset()
+        d.SOPInstanceUID = '1.2.3.4'
+        d.PatientName = 'Test'
+        d.foo = 'foo'
+        assert d == d
+
+        e = Dataset()
+        e.PatientName = 'Test'
+        e.SOPInstanceUID = '1.2.3.4'
+        assert d == e
+
     def test_inequality(self):
         """Test inequality operator"""
         d = Dataset()
@@ -682,6 +696,26 @@ class DatasetTests(unittest.TestCase):
         self.assertTrue(
             'SOPInstanceUID' in ds['0x00080018':'0x00080019'])
 
+    def test_getitem_slice_ffff(self):
+        """Test slicing with (FFFF,FFFF)"""
+        # Issue #92
+        ds = Dataset()
+        ds.CommandGroupLength = 120  # 0000,0000
+        ds.CommandLengthToEnd = 111  # 0000,0001
+        ds.Overlays = 12  # 0000,51B0
+        ds.LengthToEnd = 12  # 0008,0001
+        ds.SOPInstanceUID = '1.2.3.4'  # 0008,0018
+        ds.SkipFrameRangeFlag = 'TEST'  # 0008,9460
+        ds.add_new(0xFFFF0001, 'PN', 'CITIZEN^1')
+        ds.add_new(0xFFFF0002, 'PN', 'CITIZEN^2')
+        ds.add_new(0xFFFF0003, 'PN', 'CITIZEN^3')
+        ds.add_new(0xFFFFFFFE, 'PN', 'CITIZEN^4')
+        ds.add_new(0xFFFFFFFF, 'PN', 'CITIZEN^5')
+
+        assert ds[:][0xFFFFFFFF].value == 'CITIZEN^5'
+        assert 0xFFFFFFFF not in ds[0x1000:0xFFFFFFFF]
+        assert 0xFFFFFFFF not in ds[(0x1000):(0xFFFF, 0xFFFF)]
+
     def test_delitem_slice(self):
         """Test Dataset.__delitem__ using slices."""
         ds = Dataset()
diff --git a/pydicom/tests/test_filewriter.py b/pydicom/tests/test_filewriter.py
index 9ed2347ea..f2bac9a81 100644
--- a/pydicom/tests/test_filewriter.py
+++ b/pydicom/tests/test_filewriter.py
@@ -180,6 +180,20 @@ class WriteFileTests(unittest.TestCase):
         ds.TransferSyntaxUID = '1.1'
         self.assertRaises(ValueError, ds.save_as, self.file_out)
 
+    def test_write_ffff_ffff(self):
+        """Test writing element (FFFF, FFFF) to file #92"""
+        fp = DicomBytesIO()
+        ds = Dataset()
+        ds.file_meta = Dataset()
+        ds.is_little_endian = True
+        ds.is_implicit_VR = True
+        ds.add_new(0xFFFFFFFF, 'LO', '123456')
+        ds.save_as(fp, write_like_original=True)
+
+        fp.seek(0)
+        ds = dcmread(fp, force=True)
+        assert ds[0xFFFFFFFF].value == b'123456'
+
 
 class ScratchWriteDateTimeTests(WriteFileTests):
     """Write and reread simple or multi-value DA/DT/TM data elements"""
@@ -1826,7 +1840,6 @@ class TestWriteNumbers(object):
 
 class TestWritePN(object):
     """Test filewriter.write_PN"""
-    @pytest.mark.skip("Raises exception due to issue #489")
     def test_no_encoding_unicode(self):
         """If PN element has no encoding info, default is used"""
         fp = DicomBytesIO()
@@ -1979,12 +1992,11 @@ class TestWriteNumbers(object):
 
 class TestWritePN(object):
     """Test filewriter.write_PN"""
-    @pytest.mark.skip("Raises exception due to issue #489")
     def test_no_encoding_unicode(self):
         """If PN element as no encoding info, default is used"""
         fp = DicomBytesIO()
         fp.is_little_endian = True
-        elem = DataElement(0x00100010, 'PN', u'\u03b8')
+        elem = DataElement(0x00100010, 'PN', u'\u00e8')
         write_PN(fp, elem)
 
     def test_no_encoding(self):