Repository: pydicom/pydicom

Issue:
test_pillow_pixel_data.py  AssertionError (76, 255, 28) == (255, 0, 0)
First encountered while building a debian package in a clean env and then reproduced on my laptop.
```
=================================== FAILURES ===================================
__________________________ test_PI_RGB[JPEG_RGB_RGB] ___________________________

test_with_pillow = [<module 'pydicom.pixel_data_handlers.numpy_handler' from '/home/yoh/deb/gits/p...build/cpython2_2.7_pydicom/build/pyd...handler' from '/home/yoh/deb/gits/pk...ybuild/cpython2_2.7_pydicom/build/pydicom/pixel_data_handlers/gdcm_handler.py'>]
image = '/home/yoh/deb/gits/pkg-exppsy/build-area/pydicom-1.1.0/.pybuild/cpython2_2.7_pydicom/build/pydicom/data/test_files/SC_rgb_dcmtk_+eb+cr.dcm'
PhotometricInterpretation = 'RGB'
results = [(255, 0, 0), (255, 128, 128), (0, 255, 0), (128, 255, 128), (0, 0, 255), (128, 128, 255), ...]
ground_truth = '/home/yoh/deb/gits/pkg-exppsy/build-area/pydicom-1.1.0/.pybuild/cpython2_2.7_pydicom/build/pydicom/data/test_files/SC_rgb_dcmtk_ebcr_dcmd.dcm'

    @pytest.mark.skipif(
        not test_pillow_jpeg_decoder,
        reason=pillow_missing_message)
    @pytest.mark.parametrize(
        "image,PhotometricInterpretation,results,ground_truth",
        testdata,
        ids=test_ids)
    def test_PI_RGB(test_with_pillow,
                    image,
                    PhotometricInterpretation,
                    results,
                    ground_truth):
        t = dcmread(image)
        assert t.PhotometricInterpretation == PhotometricInterpretation
        a = t.pixel_array
        assert a.shape == (100, 100, 3)
        """
        This complete test never gave a different result than
        just the 10 point test below
    
        gt = dcmread(ground_truth)
        b = gt.pixel_array
        for x in range(100):
            for y in range(100):
                assert tuple(a[x, y]) == tuple(b[x, y])
        """
        # this test points are from the ImageComments tag
>       assert tuple(a[5, 50, :]) == results[0]
E       assert (76, 255, 28) == (255, 0, 0)
E         At index 0 diff: 76 != 255
E         Use -v to get the full diff

pydicom/tests/test_pillow_pixel_data.py:591: AssertionError
=== 1 failed, 675 passed, 27 skipped, 5 xfailed, 2 xpassed in 10.30 seconds ====
E: pybuild pybuild:336: test: plugin distutils failed with: exit code=1: cd /home/yoh/deb/gits/pkg-exppsy/build-area/pydicom-1.1.0/.pybuild/cpython2_2.7_pydicom/build; python2.7 -m pytest 
```

any hints on what/where to dig would be appreciated!

#### Versions
<!--
Please run the following snippet and paste the output below.
import platform; print(platform.platform())
import sys; print("Python", sys.version)
import pydicom; print("pydicom", pydicom.__version__)
-->
```
Linux-4.15.0-2-amd64-x86_64-with-debian-buster-sid
('Python', '2.7.14+ (default, Mar 13 2018, 15:23:44) \n[GCC 7.3.0]')
('pydicom', '1.1.0')
```
PIL is 5.0.0-1 on the laptop and probably was 5.1.0 in the clean env (if relevant):


Discussion:

Patch:
diff --git a/.travis.yml b/.travis.yml
index d5ebe6f4e..8a8b03462 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,37 +14,40 @@ matrix:
     - env: DISTRIB="conda" PYTHON_VERSION="2.7" NUMPY=false PILLOW=false JPEG2000=false JPEG_LS=false GDCM=false
     - env: DISTRIB="conda" PYTHON_VERSION="2.7" NUMPY=true  PILLOW=false JPEG2000=false JPEG_LS=false GDCM=false
     - env: DISTRIB="conda" PYTHON_VERSION="2.7" NUMPY=true  PILLOW=false JPEG2000=false JPEG_LS=false GDCM=true
-    - env: DISTRIB="conda" PYTHON_VERSION="2.7" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=false GDCM=false
-    - env: DISTRIB="conda" PYTHON_VERSION="2.7" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=true  GDCM=false
-    - env: DISTRIB="conda" PYTHON_VERSION="2.7" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=true  GDCM=true
+    - env: DISTRIB="conda" PYTHON_VERSION="2.7" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=false GDCM=false
+    - env: DISTRIB="conda" PYTHON_VERSION="2.7" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=true  GDCM=false
+    - env: DISTRIB="conda" PYTHON_VERSION="2.7" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=true  GDCM=true
 
     - env: DISTRIB="conda" PYTHON_VERSION="3.4" NUMPY=false PILLOW=false JPEG2000=false JPEG_LS=false GDCM=false
     - env: DISTRIB="conda" PYTHON_VERSION="3.4" NUMPY=true  PILLOW=false JPEG2000=false JPEG_LS=false GDCM=false
     - env: DISTRIB="conda" PYTHON_VERSION="3.4" NUMPY=true  PILLOW=false JPEG2000=false JPEG_LS=false GDCM=true
-    - env: DISTRIB="conda" PYTHON_VERSION="3.4" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=false GDCM=false
-    - env: DISTRIB="conda" PYTHON_VERSION="3.4" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=true  GDCM=false
-    - env: DISTRIB="conda" PYTHON_VERSION="3.4" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=true  GDCM=true
+    - env: DISTRIB="conda" PYTHON_VERSION="3.4" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=false GDCM=false
+    - env: DISTRIB="conda" PYTHON_VERSION="3.4" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=true  GDCM=false
+    - env: DISTRIB="conda" PYTHON_VERSION="3.4" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=true  GDCM=true
 
     - env: DISTRIB="conda" PYTHON_VERSION="3.5" NUMPY=false PILLOW=false JPEG2000=false JPEG_LS=false GDCM=false
     - env: DISTRIB="conda" PYTHON_VERSION="3.5" NUMPY=true  PILLOW=false JPEG2000=false JPEG_LS=false GDCM=false
     - env: DISTRIB="conda" PYTHON_VERSION="3.5" NUMPY=true  PILLOW=false JPEG2000=false JPEG_LS=false GDCM=true
-    - env: DISTRIB="conda" PYTHON_VERSION="3.5" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=false GDCM=false
-    - env: DISTRIB="conda" PYTHON_VERSION="3.5" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=true  GDCM=false
-    - env: DISTRIB="conda" PYTHON_VERSION="3.5" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=true  GDCM=true
+    - env: DISTRIB="conda" PYTHON_VERSION="3.5" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=false GDCM=false
+    - env: DISTRIB="conda" PYTHON_VERSION="3.5" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=true  GDCM=false
+    - env: DISTRIB="conda" PYTHON_VERSION="3.5" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=true  GDCM=true
 
     - env: DISTRIB="conda" PYTHON_VERSION="3.6" NUMPY=false PILLOW=false JPEG2000=false JPEG_LS=false GDCM=false
     - env: DISTRIB="conda" PYTHON_VERSION="3.6" NUMPY=true  PILLOW=false JPEG2000=false JPEG_LS=false GDCM=false
     - env: DISTRIB="conda" PYTHON_VERSION="3.6" NUMPY=true  PILLOW=false JPEG2000=false JPEG_LS=false GDCM=true
-    - env: DISTRIB="conda" PYTHON_VERSION="3.6" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=false GDCM=false
-    - env: DISTRIB="conda" PYTHON_VERSION="3.6" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=true  GDCM=false
-    - env: DISTRIB="conda" PYTHON_VERSION="3.6" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=true  GDCM=true
+    - env: DISTRIB="conda" PYTHON_VERSION="3.6" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=false GDCM=false
+    - env: DISTRIB="conda" PYTHON_VERSION="3.6" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=true  GDCM=false
+    - env: DISTRIB="conda" PYTHON_VERSION="3.6" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=true  GDCM=true
 
     - env: DISTRIB="conda" PYTHON_VERSION="3.7" NUMPY=false PILLOW=false JPEG2000=false JPEG_LS=false GDCM=false
     - env: DISTRIB="conda" PYTHON_VERSION="3.7" NUMPY=true  PILLOW=false JPEG2000=false JPEG_LS=false GDCM=false
     - env: DISTRIB="conda" PYTHON_VERSION="3.7" NUMPY=true  PILLOW=false JPEG2000=false JPEG_LS=false GDCM=true
-    - env: DISTRIB="conda" PYTHON_VERSION="3.7" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=false GDCM=false
-    - env: DISTRIB="conda" PYTHON_VERSION="3.7" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=true  GDCM=false
-    - env: DISTRIB="conda" PYTHON_VERSION="3.7" NUMPY=true  PILLOW=true  JPEG2000=false JPEG_LS=true  GDCM=true
+    - env: DISTRIB="conda" PYTHON_VERSION="3.7" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=false GDCM=false
+    - env: DISTRIB="conda" PYTHON_VERSION="3.7" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=true  GDCM=false
+    - env: DISTRIB="conda" PYTHON_VERSION="3.7" NUMPY=true  PILLOW=both  JPEG2000=false JPEG_LS=true  GDCM=true
+
+    - env: DISTRIB="conda" PYTHON_VERSION="2.7" NUMPY=true  PILLOW=jpeg  JPEG2000=false JPEG_LS=false GDCM=false
+    - env: DISTRIB="conda" PYTHON_VERSION="3.7" NUMPY=true  PILLOW=jpeg  JPEG2000=false JPEG_LS=false GDCM=false
 
     - env: DISTRIB="pypy" PYTHON_VERSION="2.7" NUMPY=false
     - env: DISTRIB="pypy" PYTHON_VERSION="2.7" NUMPY=true
diff --git a/build_tools/travis/install.sh b/build_tools/travis/install.sh
index fb10f6ec5..7140934e6 100755
--- a/build_tools/travis/install.sh
+++ b/build_tools/travis/install.sh
@@ -45,8 +45,14 @@ if [[ "$DISTRIB" == "conda" ]]; then
     if [[ "$JPEG2000" == "true" ]]; then
         sudo apt-get install libopenjp2-7 libopenjp2-7-dev
     fi
-    if [[ "$PILLOW" == "true" ]]; then
+    if [[ "$PILLOW" == "both" ]]; then
         conda install --yes pillow jpeg
+        python -c "from PIL import _imaging; print('JPEG plugin:', hasattr(_imaging, 'jpeg_decoder'))"
+        python -c "from PIL import _imaging; print('JPEG2k plugin:', hasattr(_imaging, 'jpeg2k_decoder'))"
+    elif [[ "$PILLOW" == "jpeg" ]]; then
+        pip install pillow --global-option="build_ext" --global-option="--disable-jpeg2000"
+        python -c "from PIL import _imaging; print('JPEG plugin:', hasattr(_imaging, 'jpeg_decoder'))"
+        python -c "from PIL import _imaging; print('JPEG2k plugin:', hasattr(_imaging, 'jpeg2k_decoder'))"
     fi
     if [[ "$JPEG_LS" == "true" ]]; then
         conda install --yes cython
diff --git a/pydicom/charset.py b/pydicom/charset.py
index bb0d397e3..0ed0d7260 100644
--- a/pydicom/charset.py
+++ b/pydicom/charset.py
@@ -1,5 +1,7 @@
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
 """Handle alternate character sets for character strings."""
+import re
+import warnings
 
 from pydicom import compat
 from pydicom.valuerep import PersonNameUnicode, text_VRs
@@ -90,10 +92,26 @@ def convert_encodings(encodings):
     try:
         encodings = [python_encoding[x] for x in encodings]
 
-    # Assume that it is already the python encoding
-    # (is there a way to check this?)
     except KeyError:
-        pass
+        # check for some common mistakes in encodings
+        patched_encodings = []
+        patched = {}
+        for x in encodings:
+            if re.match('^ISO.IR', x):
+                patched[x] = 'ISO_IR' + x[6:]
+                patched_encodings.append(patched[x])
+            else:
+                patched_encodings.append(x)
+        if patched:
+            try:
+                encodings = [python_encoding[x] for x in patched_encodings]
+                for old, new in patched.items():
+                    warnings.warn("Incorrect value for Specific Character "
+                                  "Set '{}' - assuming '{}'".format(old, new))
+            except KeyError:
+                # assume that it is already a python encoding
+                # otherwise, a LookupError will be raised in the using code
+                pass
 
     if len(encodings) == 1:
         encodings = [encodings[0]] * 3
diff --git a/pydicom/datadict.py b/pydicom/datadict.py
index cedf560b8..434168c3b 100644
--- a/pydicom/datadict.py
+++ b/pydicom/datadict.py
@@ -135,11 +135,11 @@ def get_entry(tag):
     try:
         return DicomDictionary[tag]
     except KeyError:
-        mask_x = mask_match(tag)
-        if mask_x:
-            return RepeatersDictionary[mask_x]
-        else:
-            raise KeyError("Tag {0} not found in DICOM dictionary".format(tag))
+        if not tag.is_private:
+            mask_x = mask_match(tag)
+            if mask_x:
+                return RepeatersDictionary[mask_x]
+        raise KeyError("Tag {0} not found in DICOM dictionary".format(tag))
 
 
 def dictionary_is_retired(tag):
@@ -254,9 +254,11 @@ def get_private_entry(tag, private_creator):
         elem_str = "%04x" % tag.elem
         key = "%sxx%s" % (group_str, elem_str[-2:])
         if key not in private_dict:
-            msg = ("Tag {0} not in private dictionary "
-                   "for private creator {1}".format(key, private_creator))
-            raise KeyError(msg)
+            key = "%sxxxx%s" % (group_str[:2], elem_str[-2:])
+            if key not in private_dict:
+                msg = ("Tag {0} not in private dictionary "
+                       "for private creator {1}".format(key, private_creator))
+                raise KeyError(msg)
         dict_entry = private_dict[key]
     return dict_entry
 
diff --git a/pydicom/dataelem.py b/pydicom/dataelem.py
index 105b75266..7383c874e 100644
--- a/pydicom/dataelem.py
+++ b/pydicom/dataelem.py
@@ -348,9 +348,7 @@ class DataElement(object):
 
     def description(self):
         """Return the DICOM dictionary name for the element."""
-        if dictionary_has_tag(self.tag) or repeater_has_tag(self.tag):
-            name = dictionary_description(self.tag)
-        elif self.tag.is_private:
+        if self.tag.is_private:
             name = "Private tag data"  # default
             if hasattr(self, 'private_creator'):
                 try:
@@ -364,6 +362,8 @@ class DataElement(object):
                     pass
             elif self.tag.elem >> 8 == 0:
                 name = "Private Creator"
+        elif dictionary_has_tag(self.tag) or repeater_has_tag(self.tag):
+            name = dictionary_description(self.tag)
 
         # implied Group Length dicom versions < 3
         elif self.tag.element == 0:
diff --git a/pydicom/dataset.py b/pydicom/dataset.py
index 06dc507b3..24dca240c 100644
--- a/pydicom/dataset.py
+++ b/pydicom/dataset.py
@@ -646,11 +646,11 @@ class Dataset(dict):
         """
         tags = self._slice_dataset(slice.start, slice.stop, slice.step)
         dataset = Dataset({tag: self.get_item(tag) for tag in tags})
-        dataset.read_implicit_vr = self.read_implicit_vr
-        dataset.read_little_endian = self.read_little_endian
         dataset.is_little_endian = self.is_little_endian
         dataset.is_implicit_VR = self.is_implicit_VR
-        dataset.read_encoding = self.read_encoding
+        dataset.set_original_encoding(self.read_implicit_vr,
+                                      self.read_little_endian,
+                                      self.read_encoding)
         return dataset
 
     @property
@@ -666,6 +666,16 @@ class Dataset(dict):
                 self.read_little_endian == self.is_little_endian and
                 self.read_encoding == self._character_set)
 
+    def set_original_encoding(self, is_implicit_vr, is_little_endian,
+                              character_encoding):
+        """Set the values for the original transfer syntax and encoding.
+        Can be used for a dataset with raw data elements to enable
+        optimized writing (e.g. without decoding the data elements).
+        """
+        self.read_implicit_vr = is_implicit_vr
+        self.read_little_endian = is_little_endian
+        self.read_encoding = character_encoding
+
     def group_dataset(self, group):
         """Return a Dataset containing only DataElements of a certain group.
 
diff --git a/pydicom/filereader.py b/pydicom/filereader.py
index 1389b0c7b..172df90c8 100644
--- a/pydicom/filereader.py
+++ b/pydicom/filereader.py
@@ -17,7 +17,8 @@ from pydicom.charset import (default_encoding, convert_encodings)
 from pydicom.compat import in_py2
 from pydicom.config import logger
 from pydicom.datadict import dictionary_VR, tag_for_keyword
-from pydicom.dataelem import (DataElement, RawDataElement)
+from pydicom.dataelem import (DataElement, RawDataElement,
+                              DataElement_from_raw)
 from pydicom.dataset import (Dataset, FileDataset)
 from pydicom.dicomdir import DicomDir
 from pydicom.errors import InvalidDicomError
@@ -417,7 +418,14 @@ def read_dataset(fp, is_implicit_VR, is_little_endian, bytelength=None,
     except NotImplementedError as details:
         logger.error(details)
 
-    return Dataset(raw_data_elements)
+    ds = Dataset(raw_data_elements)
+    if 0x00080005 in raw_data_elements:
+        char_set = DataElement_from_raw(raw_data_elements[0x00080005])
+        encoding = convert_encodings(char_set)
+    else:
+        encoding = parent_encoding
+    ds.set_original_encoding(is_implicit_VR, is_little_endian, encoding)
+    return ds
 
 
 def read_sequence(fp, is_implicit_VR, is_little_endian, bytelength, encoding,
@@ -773,9 +781,8 @@ def read_partial(fileobj, stop_when=None, defer_size=None,
     new_dataset = dataset_class(fileobj, dataset, preamble, file_meta_dataset,
                                 is_implicit_VR, is_little_endian)
     # save the originally read transfer syntax properties in the dataset
-    new_dataset.read_little_endian = is_little_endian
-    new_dataset.read_implicit_vr = is_implicit_VR
-    new_dataset.read_encoding = dataset._character_set
+    new_dataset.set_original_encoding(is_implicit_VR, is_little_endian,
+                                      dataset._character_set)
     return new_dataset
 
 
diff --git a/pydicom/pixel_data_handlers/pillow_handler.py b/pydicom/pixel_data_handlers/pillow_handler.py
index d7331508a..d16481dc6 100644
--- a/pydicom/pixel_data_handlers/pillow_handler.py
+++ b/pydicom/pixel_data_handlers/pillow_handler.py
@@ -160,10 +160,8 @@ def get_pixeldata(dicom_dataset):
         if dicom_dataset.BitsAllocated > 8:
             raise NotImplementedError("JPEG Lossy only supported if "
                                       "Bits Allocated = 8")
-        generic_jpeg_file_header = (
-            b'\xff\xd8\xff\xe0\x00\x10'
-            b'JFIF\x00\x01\x01\x01\x00\x01\x00\x01\x00\x00')
-        frame_start_from = 2
+        generic_jpeg_file_header = b''
+        frame_start_from = 0
     elif (dicom_dataset.file_meta.TransferSyntaxUID in
           PillowJPEG2000TransferSyntaxes):
         logger.debug("This is a JPEG 2000 format")
@@ -175,6 +173,7 @@ def get_pixeldata(dicom_dataset):
         logger.debug("This is a another pillow supported format")
         generic_jpeg_file_header = b''
         frame_start_from = 0
+
     try:
         UncompressedPixelData = bytearray()
         if ('NumberOfFrames' in dicom_dataset and


Test patch:
diff --git a/pydicom/tests/test_charset.py b/pydicom/tests/test_charset.py
index dbd5f1b88..22f8f70f8 100644
--- a/pydicom/tests/test_charset.py
+++ b/pydicom/tests/test_charset.py
@@ -3,12 +3,13 @@
 
 import unittest
 
+import pytest
+
 from pydicom.data import get_charset_files
 from pydicom.data import get_testdata_files
 import pydicom.charset
-from pydicom.dataelem import DataElement
-from pydicom import dcmread
-
+from pydicom.dataelem import DataElement, RawDataElement, DataElement_from_raw
+from pydicom import dcmread, Dataset
 
 latin1_file = get_charset_files("chrFren.dcm")[0]
 jp_file = get_charset_files("chrH31.dcm")[0]
@@ -114,6 +115,38 @@ class CharsetTests(unittest.TestCase):
         pydicom.charset.decode(elem, [])
         assert 'iso8859' in elem.value.encodings
 
+    def test_patched_charset(self):
+        """Test some commonly misspelled charset values"""
+        elem = DataElement(0x00100010, 'PN', b'Buc^J\xc3\xa9r\xc3\xb4me')
+        pydicom.charset.decode(elem, ['ISO_IR 192'])
+        # correct encoding
+        assert u'Buc^J\xe9r\xf4me' == elem.value
+
+        # patched encoding shall behave correctly, but a warning is issued
+        elem = DataElement(0x00100010, 'PN', b'Buc^J\xc3\xa9r\xc3\xb4me')
+        with pytest.warns(UserWarning,
+                          match='Incorrect value for Specific Character Set '
+                                "'ISO IR 192' - assuming 'ISO_IR 192'"):
+            pydicom.charset.decode(elem, ['ISO IR 192'])
+            assert u'Buc^J\xe9r\xf4me' == elem.value
+
+        elem = DataElement(0x00100010, 'PN', b'Buc^J\xc3\xa9r\xc3\xb4me')
+        with pytest.warns(UserWarning,
+                          match='Incorrect value for Specific Character Set '
+                                "'ISO-IR 192' - assuming 'ISO_IR 192'"):
+            pydicom.charset.decode(elem, ['ISO-IR 192'])
+            assert u'Buc^J\xe9r\xf4me' == elem.value
+
+        # not patched incorrect encoding raises
+        elem = DataElement(0x00100010, 'PN', b'Buc^J\xc3\xa9r\xc3\xb4me')
+        with pytest.raises(LookupError):
+            pydicom.charset.decode(elem, ['ISOIR 192'])
+
+        # Python encoding also can be used directly
+        elem = DataElement(0x00100010, 'PN', b'Buc^J\xc3\xa9r\xc3\xb4me')
+        pydicom.charset.decode(elem, ['utf8'])
+        assert u'Buc^J\xe9r\xf4me' == elem.value
+
 
 if __name__ == "__main__":
     # This is called if run alone, but not if loaded through run_tests.py
diff --git a/pydicom/tests/test_dataelem.py b/pydicom/tests/test_dataelem.py
index a69bd6fed..52ea34371 100644
--- a/pydicom/tests/test_dataelem.py
+++ b/pydicom/tests/test_dataelem.py
@@ -328,6 +328,40 @@ class DataElementTests(unittest.TestCase):
         with pytest.raises(TypeError):
             elem[0]
 
+    def test_private_tag_in_repeater_range(self):
+        """Test that an unknown private tag (e.g. a tag not in the private
+        dictionary) in the repeater range is not handled as a repeater tag
+        if using Implicit Little Endian transfer syntax."""
+        # regression test for #689
+        ds = Dataset()
+        ds[0x50f10010] = RawDataElement(
+            Tag(0x50f10010), None, 8, b'FDMS 1.0', 0, True, True)
+        ds[0x50f1100a] = RawDataElement(
+            Tag(0x50f1100a), None, 6, b'ACC0.6', 0, True, True)
+        private_creator_data_elem = ds[0x50f10010]
+        assert 'Private Creator' == private_creator_data_elem.name
+        assert 'LO' == private_creator_data_elem.VR
+
+        private_data_elem = ds[0x50f1100a]
+        assert '[FNC Parameters]' == private_data_elem.name
+        assert 'UN' == private_data_elem.VR
+
+    def test_private_repeater_tag(self):
+        """Test that a known private tag in the repeater range is correctly
+        handled using Implicit Little Endian transfer syntax."""
+        ds = Dataset()
+        ds[0x60210012] = RawDataElement(
+            Tag(0x60210012), None, 12, b'PAPYRUS 3.0 ', 0, True, True)
+        ds[0x60211200] = RawDataElement(
+            Tag(0x60211200), None, 6, b'123456', 0, True, True)
+        private_creator_data_elem = ds[0x60210012]
+        assert 'Private Creator' == private_creator_data_elem.name
+        assert 'LO' == private_creator_data_elem.VR
+
+        private_data_elem = ds[0x60211200]
+        assert '[Overlay ID]' == private_data_elem.name
+        assert 'UN' == private_data_elem.VR
+
 
 class RawDataElementTests(unittest.TestCase):
     def testKeyError(self):
diff --git a/pydicom/tests/test_dataset.py b/pydicom/tests/test_dataset.py
index 2d9e32b57..9b625a4ac 100644
--- a/pydicom/tests/test_dataset.py
+++ b/pydicom/tests/test_dataset.py
@@ -889,9 +889,7 @@ class DatasetTests(unittest.TestCase):
 
         # simulate reading
         ds.SpecificCharacterSet = 'ISO_IR 100'
-        ds.read_little_endian = True
-        ds.read_implicit_vr = True
-        ds.read_encoding = ['latin_1', 'latin_1', 'latin_1']
+        ds.set_original_encoding(True, True, ['latin_1', 'latin_1', 'latin_1'])
         assert not ds.is_original_encoding
 
         ds.is_little_endian = True
diff --git a/pydicom/tests/test_filewriter.py b/pydicom/tests/test_filewriter.py
index 2d7999f40..5c66ba64b 100644
--- a/pydicom/tests/test_filewriter.py
+++ b/pydicom/tests/test_filewriter.py
@@ -950,9 +950,12 @@ class WriteAmbiguousVRTests(unittest.TestCase):
         file_ds.save_as(fp, write_like_original=True)
         fp.seek(0)
 
-        ds = read_dataset(fp, False, True)
-        self.assertEqual(ds.SmallestValidPixelValue, 256)
-        self.assertEqual(ds[0x00280104].VR, 'US')
+        ds = read_dataset(fp, False, True, parent_encoding='latin1')
+        assert 256 == ds.SmallestValidPixelValue
+        assert 'US' == ds[0x00280104].VR
+        assert not ds.read_implicit_vr
+        assert ds.read_little_endian
+        assert ds.read_encoding == 'latin1'
 
     def test_write_explicit_vr_big_endian(self):
         """Test writing explicit big data for ambiguous elements."""
@@ -960,6 +963,7 @@ class WriteAmbiguousVRTests(unittest.TestCase):
         ref_ds = Dataset()
         ref_ds.PixelRepresentation = 1
         ref_ds.SmallestValidPixelValue = b'\x00\x01'  # Big endian 1
+        ref_ds.SpecificCharacterSet = b'ISO_IR 192'
 
         fp = BytesIO()
         file_ds = FileDataset(fp, ref_ds)
@@ -969,8 +973,11 @@ class WriteAmbiguousVRTests(unittest.TestCase):
         fp.seek(0)
 
         ds = read_dataset(fp, False, False)
-        self.assertEqual(ds.SmallestValidPixelValue, 1)
-        self.assertEqual(ds[0x00280104].VR, 'SS')
+        assert 1 == ds.SmallestValidPixelValue
+        assert 'SS' == ds[0x00280104].VR
+        assert not ds.read_implicit_vr
+        assert not ds.read_little_endian
+        assert ['UTF8', 'UTF8', 'UTF8'] == ds.read_encoding
 
 
 class ScratchWriteTests(unittest.TestCase):
@@ -1755,6 +1762,7 @@ class TestWriteNonStandard(unittest.TestCase):
 
         self.fp.seek(0)
         ds_out = dcmread(self.fp, force=True)
+        self.ensure_no_raw_data_elements(ds)
         self.ensure_no_raw_data_elements(ds_out)
 
         self.assertEqual(ds.file_meta[:], ds_out.file_meta[:])
diff --git a/pydicom/tests/test_pillow_pixel_data.py b/pydicom/tests/test_pillow_pixel_data.py
index 27fedb781..2cf185fd3 100644
--- a/pydicom/tests/test_pillow_pixel_data.py
+++ b/pydicom/tests/test_pillow_pixel_data.py
@@ -1,46 +1,40 @@
 # Copyright 2008-2018 pydicom authors. See LICENSE file for details.
 
-import unittest
 import os
 import sys
+
 import pytest
+
 import pydicom
 from pydicom.filereader import dcmread
 from pydicom.data import get_testdata_files
 from pydicom.tag import Tag
-pillow_missing_message = ("pillow is not available "
-                          "in this test environment")
-pillow_present_message = "pillow is being tested"
-pillow_handler = None
-have_pillow_handler = True
-numpy_handler = None
-have_numpy_handler = True
-have_pillow_jpeg_plugin = False
-have_pillow_jpeg2000_plugin = False
-have_numpy_testing = True
-try:
-    import numpy.testing
-except ImportError as e:
-    have_numpy_testing = False
 
 # Python 3.4 pytest does not have pytest.param?
-have_pytest_param = True
-try:
-    x = pytest.param
-except AttributeError:
-    have_pytest_param = False
+have_pytest_param = hasattr(pytest, 'param')
 
 try:
-    import pydicom.pixel_data_handlers.numpy_handler as numpy_handler
+    from pydicom.pixel_data_handlers import numpy_handler
+    have_numpy_handler = True
 except ImportError:
     have_numpy_handler = False
+    numpy_handler = None
+
 try:
-    import pydicom.pixel_data_handlers.pillow_handler as pillow_handler
+    from pydicom.pixel_data_handlers import pillow_handler
+    have_pillow_handler = True
     have_pillow_jpeg_plugin = pillow_handler.have_pillow_jpeg_plugin
-    have_pillow_jpeg2000_plugin = \
-        pillow_handler.have_pillow_jpeg2000_plugin
+    have_pillow_jpeg2000_plugin = pillow_handler.have_pillow_jpeg2000_plugin
+    import numpy as np
 except ImportError:
+    pillow_handler = None
     have_pillow_handler = False
+    have_pillow_jpeg_plugin = False
+    have_pillow_jpeg2000_plugin = False
+
+
+pillow_missing_message = ("pillow is not available "
+                          "in this test environment")
 
 test_pillow_decoder = have_numpy_handler and have_pillow_handler
 test_pillow_jpeg_decoder = (test_pillow_decoder and
@@ -129,159 +123,157 @@ dir_name = os.path.dirname(sys.argv[0])
 save_dir = os.getcwd()
 
 
-class pillow_JPEG_LS_Tests_no_pillow(unittest.TestCase):
-    def setUp(self):
+class Test_JPEGLS_no_pillow(object):
+    """Tests for decoding JPEG LS if pillow pixel handler is missing."""
+    def setup(self):
+        """Setup the test datasets."""
         self.jpeg_ls_lossless = dcmread(jpeg_ls_lossless_name)
-        self.mr_small = dcmread(mr_name)
         self.emri_jpeg_ls_lossless = dcmread(emri_jpeg_ls_lossless)
-        self.emri_small = dcmread(emri_name)
         self.original_handlers = pydicom.config.image_handlers
         pydicom.config.image_handlers = [None, numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
+        """Reset the pixel data handlers."""
         pydicom.config.image_handlers = self.original_handlers
 
     def test_JPEG_LS_PixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_ls_lossless.pixel_array
+        """Test decoding JPEG LS with only numpy fails."""
+        with pytest.raises(NotImplementedError):
+            self.jpeg_ls_lossless.pixel_array
 
     def test_emri_JPEG_LS_PixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.emri_jpeg_ls_lossless.pixel_array
+        """Test decoding JPEG LS with only numpy fails."""
+        with pytest.raises(NotImplementedError):
+            self.emri_jpeg_ls_lossless.pixel_array
 
 
-class pillow_JPEG2000Tests_no_pillow(unittest.TestCase):
-    def setUp(self):
+class Test_JPEG2000Tests_no_pillow(object):
+    """Tests for decoding JPEG2K if pillow pixel handler is missing."""
+    def setup(self):
+        """Setup the test datasets."""
         self.jpeg_2k = dcmread(jpeg2000_name)
         self.jpeg_2k_lossless = dcmread(jpeg2000_lossless_name)
-        self.mr_small = dcmread(mr_name)
         self.emri_jpeg_2k_lossless = dcmread(emri_jpeg_2k_lossless)
-        self.emri_small = dcmread(emri_name)
         self.sc_rgb_jpeg2k_gdcm_KY = dcmread(sc_rgb_jpeg2k_gdcm_KY)
         self.original_handlers = pydicom.config.image_handlers
         pydicom.config.image_handlers = [None, numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
+        """Reset the pixel data handlers."""
         pydicom.config.image_handlers = self.original_handlers
 
     def testJPEG2000(self):
-        """JPEG2000: Returns correct values for sample data elements"""
+        """Test reading element values works OK without Pillow."""
         # XX also tests multiple-valued AT data element
-        expected = [Tag(0x0054, 0x0010), Tag(0x0054, 0x0020)]
-        got = self.jpeg_2k.FrameIncrementPointer
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG2000 file, Frame Increment Pointer: "
-            "expected %s, got %s" % (expected, got))
+        elem = self.jpeg_2k.FrameIncrementPointer
+        assert [Tag(0x0054, 0x0010), Tag(0x0054, 0x0020)] == elem
 
-        got = self.jpeg_2k.DerivationCodeSequence[0].CodeMeaning
-        expected = 'Lossy Compression'
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG200 file, Code Meaning got %s, "
-            "expected %s" % (got, expected))
+        elem = self.jpeg_2k.DerivationCodeSequence[0].CodeMeaning
+        assert 'Lossy Compression' == elem
 
     def testJPEG2000PixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_2k_lossless.pixel_array
+        """Test decoding JPEG2K with only numpy fails."""
+        with pytest.raises(NotImplementedError):
+            self.jpeg_2k_lossless.pixel_array
 
     def test_emri_JPEG2000PixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.emri_jpeg_2k_lossless.pixel_array
+        """Test decoding JPEG2K with only numpy fails."""
+        with pytest.raises(NotImplementedError):
+            self.emri_jpeg_2k_lossless.pixel_array
 
     def test_jpeg2000_lossy(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.sc_rgb_jpeg2k_gdcm_KY.pixel_array
-
+        """Test decoding JPEG2K with only numpy fails."""
+        with pytest.raises(NotImplementedError):
+            self.sc_rgb_jpeg2k_gdcm_KY.pixel_array
 
-class pillow_JPEGlossyTests_no_pillow(unittest.TestCase):
 
-    def setUp(self):
+class Test_JPEGlossyTests_no_pillow(object):
+    """Tests for decoding JPEG lossy if pillow pixel handler is missing."""
+    def setup(self):
+        """Setup the test datasets."""
         self.jpeg_lossy = dcmread(jpeg_lossy_name)
         self.color_3d_jpeg = dcmread(color_3d_jpeg_baseline)
         self.original_handlers = pydicom.config.image_handlers
         pydicom.config.image_handlers = [None, numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
+        """Reset the pixel data handlers."""
         pydicom.config.image_handlers = self.original_handlers
 
     def testJPEGlossy(self):
-        """JPEG-lossy: Returns correct values for sample data elements"""
-        got = self.jpeg_lossy.DerivationCodeSequence[0].CodeMeaning
-        expected = 'Lossy Compression'
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG-lossy file, Code Meaning got %s, "
-            "expected %s" % (got, expected))
+        """Test reading element values works OK without Pillow."""
+        elem = self.jpeg_lossy.DerivationCodeSequence[0].CodeMeaning
+        assert 'Lossy Compression' == elem
 
     def testJPEGlossyPixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_lossy.pixel_array
+        """Test decoding JPEG lossy with only numpy fails."""
+        with pytest.raises(NotImplementedError):
+            self.jpeg_lossy.pixel_array
 
     def testJPEGBaselineColor3DPixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.color_3d_jpeg.pixel_array
+        """Test decoding JPEG lossy with only numpy fails."""
+        with pytest.raises(NotImplementedError):
+            self.color_3d_jpeg.pixel_array
 
 
-class pillow_JPEGlosslessTests_no_pillow(unittest.TestCase):
-    def setUp(self):
+class Test_JPEGlosslessTests_no_pillow(object):
+    """Tests for decoding JPEG lossless if pillow pixel handler is missing."""
+    def setup(self):
+        """Setup the test datasets."""
         self.jpeg_lossless = dcmread(jpeg_lossless_name)
         self.original_handlers = pydicom.config.image_handlers
         pydicom.config.image_handlers = [None, numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
+        """Reset the pixel data handlers."""
         pydicom.config.image_handlers = self.original_handlers
 
     def testJPEGlossless(self):
-        """JPEGlossless: Returns correct values for sample data elements"""
-        got = self.\
-            jpeg_lossless.\
-            SourceImageSequence[0].\
-            PurposeOfReferenceCodeSequence[0].CodeMeaning
-        expected = 'Uncompressed predecessor'
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG-lossless file, Code Meaning got %s, "
-            "expected %s" % (got, expected))
+        """Test reading element values works OK without Pillow."""
+        elem = self.jpeg_lossless.SourceImageSequence[0]
+        elem = elem.PurposeOfReferenceCodeSequence[0].CodeMeaning
+        assert 'Uncompressed predecessor' == elem
 
     def testJPEGlosslessPixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_lossless.pixel_array
+        """Test decoding JPEG lossless with only numpy fails."""
+        with pytest.raises(NotImplementedError):
+            self.jpeg_lossless.pixel_array
 
 
 @pytest.mark.skipif(
     not test_pillow_decoder,
     reason=pillow_missing_message)
-class pillow_JPEG_LS_Tests_with_pillow(unittest.TestCase):
-    def setUp(self):
+class Test_JPEG_LS_with_pillow(object):
+    """Tests for decoding JPEG LS if pillow pixel handler is available."""
+    def setup(self):
+        """Setup the test datasets."""
         self.jpeg_ls_lossless = dcmread(jpeg_ls_lossless_name)
-        self.mr_small = dcmread(mr_name)
         self.emri_jpeg_ls_lossless = dcmread(emri_jpeg_ls_lossless)
-        self.emri_small = dcmread(emri_name)
         self.original_handlers = pydicom.config.image_handlers
         pydicom.config.image_handlers = [pillow_handler, numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
+        """Reset the pixel data handlers."""
         pydicom.config.image_handlers = self.original_handlers
 
     def test_JPEG_LS_PixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_ls_lossless.pixel_array
+        """Test decoding JPEG LS with pillow handler fails."""
+        with pytest.raises(NotImplementedError):
+            self.jpeg_ls_lossless.pixel_array
 
     def test_emri_JPEG_LS_PixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.emri_jpeg_ls_lossless.pixel_array
+        """Test decoding JPEG LS with pillow handler fails."""
+        with pytest.raises(NotImplementedError):
+            self.emri_jpeg_ls_lossless.pixel_array
 
 
 @pytest.mark.skipif(
     not test_pillow_jpeg2000_decoder,
     reason=pillow_missing_message)
-class pillow_JPEG2000Tests_with_pillow(unittest.TestCase):
-    def setUp(self):
+class Test_JPEG2000Tests_with_pillow(object):
+    """Test decoding JPEG2K if pillow JPEG2K plugin is available."""
+    def setup(self):
+        """Setup the test datasets."""
         self.jpeg_2k = dcmread(jpeg2000_name)
         self.jpeg_2k_lossless = dcmread(jpeg2000_lossless_name)
         self.mr_small = dcmread(mr_name)
@@ -293,72 +285,55 @@ class pillow_JPEG2000Tests_with_pillow(unittest.TestCase):
         self.original_handlers = pydicom.config.image_handlers
         pydicom.config.image_handlers = [pillow_handler, numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
+        """Reset the pixel data handlers."""
         pydicom.config.image_handlers = self.original_handlers
 
     def testJPEG2000(self):
-        """JPEG2000: Returns correct values for sample data elements"""
+        """Test reading element values works OK with pillow pixel handler."""
         # XX also tests multiple-valued AT data element
-        expected = [Tag(0x0054, 0x0010), Tag(0x0054, 0x0020)]
         got = self.jpeg_2k.FrameIncrementPointer
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG2000 file, Frame Increment Pointer: "
-            "expected %s, got %s" % (expected, got))
+        assert [Tag(0x0054, 0x0010), Tag(0x0054, 0x0020)] == got
 
         got = self.jpeg_2k.DerivationCodeSequence[0].CodeMeaning
-        expected = 'Lossy Compression'
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG200 file, Code Meaning got %s, "
-            "expected %s" % (got, expected))
+        assert 'Lossy Compression' == got
 
     def testJPEG2000PixelArray(self):
+        """Test decoding JPEG2K with pillow handler succeeds."""
         a = self.jpeg_2k_lossless.pixel_array
         b = self.mr_small.pixel_array
-        if have_numpy_testing:
-            numpy.testing.assert_array_equal(a, b)
-        else:
-            self.assertEqual(
-                a.mean(),
-                b.mean(),
-                "Decoded pixel data is not all {0} "
-                "(mean == {1})".format(b.mean(), a.mean()))
+        assert np.array_equal(a, b)
 
     def test_emri_JPEG2000PixelArray(self):
+        """Test decoding JPEG2K with pillow handler succeeds."""
         a = self.emri_jpeg_2k_lossless.pixel_array
         b = self.emri_small.pixel_array
-        if have_numpy_testing:
-            numpy.testing.assert_array_equal(a, b)
-        else:
-            self.assertEqual(
-                a.mean(),
-                b.mean(),
-                "Decoded pixel data is not all {0} "
-                "(mean == {1})".format(b.mean(), a.mean()))
+        assert np.array_equal(a, b)
 
     def test_jpeg2000_lossy(self):
+        """Test decoding JPEG2K lossy with pillow handler fails."""
         with pytest.raises(NotImplementedError):
-            _ = self.sc_rgb_jpeg2k_gdcm_KY.pixel_array
+            self.sc_rgb_jpeg2k_gdcm_KY.pixel_array
 
 
 @pytest.mark.skipif(
     not test_pillow_jpeg_decoder,
     reason=pillow_missing_message)
-class pillow_JPEGlossyTests_with_pillow(unittest.TestCase):
-
-    def setUp(self):
+class Test_JPEGlossyTests_with_pillow(object):
+    """Test decoding JPEG if pillow JPEG plugin is available."""
+    def setup(self):
+        """Setup the test datasets."""
         self.jpeg_lossy = dcmread(jpeg_lossy_name)
         self.color_3d_jpeg = dcmread(color_3d_jpeg_baseline)
         self.original_handlers = pydicom.config.image_handlers
         pydicom.config.image_handlers = [pillow_handler, numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
+        """Reset the pixel data handlers."""
         pydicom.config.image_handlers = self.original_handlers
 
     def testJPEGlossless_odd_data_size(self):
+        """Test decoding JPEG with pillow handler succeeds."""
         test_file = get_testdata_files('SC_rgb_small_odd_jpeg.dcm')[0]
         ds = dcmread(test_file)
         pixel_data = ds.pixel_array
@@ -366,31 +341,26 @@ class pillow_JPEGlossyTests_with_pillow(unittest.TestCase):
         assert pixel_data.shape == (3, 3, 3)
 
     def testJPEGlossy(self):
-        """JPEG-lossy: Returns correct values for sample data elements"""
+        """Test reading element values works OK with pillow pixel handler."""
         got = self.jpeg_lossy.DerivationCodeSequence[0].CodeMeaning
-        expected = 'Lossy Compression'
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG-lossy file, Code Meaning got %s, "
-            "expected %s" % (got, expected))
+        assert 'Lossy Compression' == got
 
     def testJPEGlossyPixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_lossy.pixel_array
+        """Test decoding JPEG lossy with pillow handler fails."""
+        with pytest.raises(NotImplementedError):
+            self.jpeg_lossy.pixel_array
 
     def testJPEGBaselineColor3DPixelArray(self):
-        self.assertEqual(
-            self.color_3d_jpeg.PhotometricInterpretation,
-            "YBR_FULL_422")
+        """Test decoding JPEG with pillow handler succeeds."""
+        assert "YBR_FULL_422" == self.color_3d_jpeg.PhotometricInterpretation
+
         a = self.color_3d_jpeg.pixel_array
-        self.assertEqual(a.shape, (120, 480, 640, 3))
+        assert (120, 480, 640, 3) == a.shape
         # this test points were manually identified in Osirix viewer
-        self.assertEqual(tuple(a[3, 159, 290, :]), (41, 41, 41))
-        self.assertEqual(tuple(a[3, 169, 290, :]), (57, 57, 57))
-        self.assertEqual(
-            self.color_3d_jpeg.PhotometricInterpretation,
-            "YBR_FULL_422")
+        assert (41, 41, 41) == tuple(a[3, 159, 290, :])
+        assert (57, 57, 57) == tuple(a[3, 169, 290, :])
+
+        assert "YBR_FULL_422" == self.color_3d_jpeg.PhotometricInterpretation
 
 
 @pytest.fixture(scope="module")
@@ -606,28 +576,25 @@ def test_PI_RGB(test_with_pillow,
 @pytest.mark.skipif(
     not test_pillow_jpeg_decoder,
     reason=pillow_missing_message)
-class pillow_JPEGlosslessTests_with_pillow(unittest.TestCase):
-    def setUp(self):
+class Test_JPEGlosslessTests_with_pillow(object):
+    """Test decoding JPEG lossless if pillow JPEG plugin is available."""
+    def setup(self):
+        """Setup the test datasets."""
         self.jpeg_lossless = dcmread(jpeg_lossless_name)
         self.original_handlers = pydicom.config.image_handlers
         pydicom.config.image_handlers = [pillow_handler, numpy_handler]
 
-    def tearDown(self):
+    def teardown(self):
+        """Reset the pixel data handlers."""
         pydicom.config.image_handlers = self.original_handlers
 
     def testJPEGlossless(self):
-        """JPEGlossless: Returns correct values for sample data elements"""
-        got = self.\
-            jpeg_lossless.\
-            SourceImageSequence[0].\
-            PurposeOfReferenceCodeSequence[0].CodeMeaning
-        expected = 'Uncompressed predecessor'
-        self.assertEqual(
-            got,
-            expected,
-            "JPEG-lossless file, Code Meaning got %s, "
-            "expected %s" % (got, expected))
+        """Test reading element values works OK with pillow pixel handler."""
+        got = self.jpeg_lossless.SourceImageSequence[0]
+        got = got.PurposeOfReferenceCodeSequence[0].CodeMeaning
+        assert 'Uncompressed predecessor' == got
 
     def testJPEGlosslessPixelArray(self):
-        with self.assertRaises((NotImplementedError, )):
-            _ = self.jpeg_lossless.pixel_array
+        """Test decoding JPEG lossless with pillow handler fails."""
+        with pytest.raises(NotImplementedError):
+            self.jpeg_lossless.pixel_array