File: test_filereader.py

package info (click to toggle)
pydicom 2.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, sid
  • size: 65,208 kB
  • sloc: python: 116,343; sh: 222; makefile: 193
file content (1511 lines) | stat: -rw-r--r-- 57,460 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
# Copyright 2008-2018 pydicom authors. See LICENSE file for details.
# -*- coding: utf-8 -*-
"""Unit tests for the pydicom.filereader module."""

import gzip
import io
from io import BytesIO
import os
import shutil
from pathlib import Path
from struct import unpack
import sys
import tempfile

import pytest

import pydicom.config
from pydicom import config
from pydicom.dataset import Dataset, FileDataset, FileMetaDataset
from pydicom.data import get_testdata_file
from pydicom.datadict import add_dict_entries
from pydicom.filereader import dcmread, read_dataset
from pydicom.dataelem import DataElement, DataElement_from_raw
from pydicom.errors import InvalidDicomError
from pydicom.filebase import DicomBytesIO
from pydicom.filereader import data_element_generator
from pydicom.multival import MultiValue
from pydicom.sequence import Sequence
from pydicom.tag import Tag, TupleTag
from pydicom.uid import ImplicitVRLittleEndian
import pydicom.valuerep
from pydicom import values


from pydicom.pixel_data_handlers import gdcm_handler

have_gdcm_handler = gdcm_handler.is_available()

have_numpy = pydicom.config.have_numpy
if have_numpy:
    import numpy  # NOQA

try:
    import jpeg_ls
except ImportError:
    jpeg_ls = None

try:
    from PIL import Image as PILImg
except ImportError:
    # If that failed, try the alternate import syntax for PIL.
    try:
        import Image as PILImg
    except ImportError:
        # Neither worked, so it's likely not installed.
        PILImg = None

have_jpeg_ls = jpeg_ls is not None
have_pillow = PILImg is not None

empty_number_tags_name = get_testdata_file(
    "reportsi_with_empty_number_tags.dcm"
)
rtplan_name = get_testdata_file("rtplan.dcm")
rtdose_name = get_testdata_file("rtdose.dcm")
ct_name = get_testdata_file("CT_small.dcm")
mr_name = get_testdata_file("MR_small.dcm")
truncated_mr_name = get_testdata_file("MR_truncated.dcm")
jpeg2000_name = get_testdata_file("JPEG2000.dcm")
jpeg2000_lossless_name = get_testdata_file("MR_small_jp2klossless.dcm")
jpeg_ls_lossless_name = get_testdata_file("MR_small_jpeg_ls_lossless.dcm")
jpeg_lossy_name = get_testdata_file("JPEG-lossy.dcm")
jpeg_lossless_name = get_testdata_file("JPEG-LL.dcm")
deflate_name = get_testdata_file("image_dfl.dcm")
rtstruct_name = get_testdata_file("rtstruct.dcm")
priv_SQ_name = get_testdata_file("priv_SQ.dcm")
nested_priv_SQ_name = get_testdata_file("nested_priv_SQ.dcm")
meta_missing_tsyntax_name = get_testdata_file("meta_missing_tsyntax.dcm")
no_meta_group_length = get_testdata_file("no_meta_group_length.dcm")
gzip_name = get_testdata_file("zipMR.gz")
color_px_name = get_testdata_file("color-px.dcm")
color_pl_name = get_testdata_file("color-pl.dcm")
explicit_vr_le_no_meta = get_testdata_file("ExplVR_LitEndNoMeta.dcm")
explicit_vr_be_no_meta = get_testdata_file("ExplVR_BigEndNoMeta.dcm")
emri_name = get_testdata_file("emri_small.dcm")
emri_big_endian_name = get_testdata_file("emri_small_big_endian.dcm")
emri_jpeg_ls_lossless = get_testdata_file("emri_small_jpeg_ls_lossless.dcm")
emri_jpeg_2k_lossless = get_testdata_file("emri_small_jpeg_2k_lossless.dcm")
emri_jpeg_2k_lossless_too_short = get_testdata_file(
    "emri_small_jpeg_2k_lossless_too_short.dcm"
)
color_3d_jpeg_baseline = get_testdata_file("color3d_jpeg_baseline.dcm")
dir_name = os.path.dirname(sys.argv[0])
save_dir = os.getcwd()


class TestReader:
    def teardown(self):
        config.enforce_valid_values = False
        config.replace_un_with_known_vr = True

    def test_empty_numbers_tag(self):
        """Test that an empty tag with a number VR (FL, UL, SL, US,
        SS, FL, FD, OF) reads as ``None``."""
        empty_number_tags_ds = dcmread(empty_number_tags_name)
        assert empty_number_tags_ds.ExaminedBodyThickness is None
        assert empty_number_tags_ds.SimpleFrameList is None
        assert empty_number_tags_ds.ReferencePixelX0 is None
        assert empty_number_tags_ds.PhysicalUnitsXDirection is None
        assert empty_number_tags_ds.TagAngleSecondAxis is None
        assert empty_number_tags_ds.TagSpacingSecondDimension is None
        assert empty_number_tags_ds.VectorGridData is None

    def test_UTF8_filename(self):
        utf8_filename = os.path.join(tempfile.gettempdir(), "DICOM.dcm")
        shutil.copyfile(rtdose_name, utf8_filename)
        ds = dcmread(utf8_filename)
        os.remove(utf8_filename)
        assert ds is not None

    def test_pathlib_path_filename(self):
        """Check that file can be read using pathlib.Path"""
        ds = dcmread(Path(priv_SQ_name))

    def test_RTPlan(self):
        """Returns correct values for sample data elements in test
        RT Plan file.
        """
        orig_use_numpy = config.use_DS_numpy
        config.use_DS_numpy = False
        plan = dcmread(rtplan_name)
        beam = plan.BeamSequence[0]
        # if not two controlpoints, then this would raise exception
        cp0, cp1 = beam.ControlPointSequence

        assert "unit001" == beam.TreatmentMachineName
        assert beam[0x300A, 0x00B2].value == beam.TreatmentMachineName

        got = cp1.ReferencedDoseReferenceSequence[
            0
        ].CumulativeDoseReferenceCoefficient
        DS = pydicom.valuerep.DS
        expected = DS("0.9990268")
        assert expected == got
        got = cp0.BeamLimitingDevicePositionSequence[0].LeafJawPositions
        assert [DS("-100"), DS("100.0")] == got
        config.use_DS_numpy = orig_use_numpy

    def test_RTDose(self):
        """Returns correct values for sample data elements in test
        RT Dose file"""
        dose = dcmread(rtdose_name)
        assert Tag((0x3004, 0x000C)) == dose.FrameIncrementPointer
        assert dose[0x28, 9].value == dose.FrameIncrementPointer

        # try a value that is nested the deepest
        # (so deep I break it into two steps!)
        fract = dose.ReferencedRTPlanSequence[
            0
        ].ReferencedFractionGroupSequence[0]
        assert 1 == fract.ReferencedBeamSequence[0].ReferencedBeamNumber

    def test_CT(self):
        """Returns correct values for sample data elements in test CT file."""
        ct = dcmread(ct_name)
        assert "1.3.6.1.4.1.5962.2" == ct.file_meta.ImplementationClassUID
        value = ct.file_meta[0x2, 0x12].value
        assert value == ct.file_meta.ImplementationClassUID

        # (0020, 0032) Image Position (Patient)
        # [-158.13580300000001, -179.035797, -75.699996999999996]
        got = ct.ImagePositionPatient
        DS = pydicom.valuerep.DS
        if have_numpy and config.use_DS_numpy:
            expected = numpy.array([-158.135803, -179.035797, -75.699997])
            assert numpy.allclose(got, expected)
        else:
            expected = [DS("-158.135803"), DS("-179.035797"), DS("-75.699997")]
            assert got == expected

        assert 128 == ct.Rows
        assert 128 == ct.Columns
        assert 16 == ct.BitsStored
        assert 128 * 128 * 2 == len(ct.PixelData)

        # Also test private elements name can be resolved:
        got = ct[(0x0043, 0x104E)].name
        assert "[Duration of X-ray on]" == got

    @pytest.mark.skipif(not have_numpy, reason="Numpy not installed")
    def test_CT_PixelData(self):
        """Check that we can read pixel data.
        Tests that we get last one in array.
        """
        ct = dcmread(ct_name)
        assert 909 == ct.pixel_array[-1][-1]

    def test_no_force(self):
        """Raises exception if missing DICOM header and force==False."""
        with pytest.raises(InvalidDicomError):
            dcmread(rtstruct_name)

    def test_RTStruct(self):
        """Returns correct values for sample elements in test RTSTRUCT file."""
        # RTSTRUCT test file has complex nested sequences
        # -- see rtstruct.dump file
        # Also has no DICOM header ... so tests 'force' argument of dcmread

        rtss = dcmread(rtstruct_name, force=True)
        frame_of_ref = rtss.ReferencedFrameOfReferenceSequence[0]
        study = frame_of_ref.RTReferencedStudySequence[0]
        uid = study.RTReferencedSeriesSequence[0].SeriesInstanceUID
        assert "1.2.826.0.1.3680043.8.498.2010020400001.2.1.1" == uid

        got = rtss.ROIContourSequence[0].ContourSequence[2].ContourNumber
        assert 3 == got

        obs_seq0 = rtss.RTROIObservationsSequence[0]
        got = obs_seq0.ROIPhysicalPropertiesSequence[0].ROIPhysicalProperty
        assert "REL_ELEC_DENSITY" == got

    def test_dir(self):
        """Returns correct dir attributes for both Dataset and DICOM names
        (python >= 2.6).."""
        # Only python >= 2.6 calls __dir__ for dir() call
        rtss = dcmread(rtstruct_name, force=True)
        # sample some expected 'dir' values
        got_dir = dir(rtss)
        expect_in_dir = [
            "pixel_array",
            "add_new",
            "ROIContourSequence",
            "StructureSetDate",
        ]
        for name in expect_in_dir:
            assert name in got_dir

        # Now check for some items in dir() of a nested item
        roi0 = rtss.ROIContourSequence[0]
        got_dir = dir(roi0)
        expect_in_dir = [
            "pixel_array",
            "add_new",
            "ReferencedROINumber",
            "ROIDisplayColor",
        ]
        for name in expect_in_dir:
            assert name in got_dir

    def test_MR(self):
        """Returns correct values for sample data elements in test MR file."""
        mr = dcmread(mr_name)
        # (0010, 0010) Patient's Name           'CompressedSamples^MR1'
        mr.decode()
        assert "CompressedSamples^MR1" == mr.PatientName
        assert mr[0x10, 0x10].value == mr.PatientName

        DS = pydicom.valuerep.DS

        if have_numpy and config.use_DS_numpy:
            expected = numpy.array([0.3125, 0.3125])
            assert numpy.allclose(mr.PixelSpacing, expected)
        else:
            assert [DS("0.3125"), DS("0.3125")] == mr.PixelSpacing

    def test_deflate(self):
        """Returns correct values for sample data elements in test compressed
         (zlib deflate) file
         """
        # Everything after group 2 is compressed.
        # If we can read anything else, the decompression must have been ok.
        ds = dcmread(deflate_name)
        assert "WSD" == ds.ConversionType

    def test_bad_sequence(self):
        """Test that automatic UN conversion can be switched off."""
        with pytest.raises(NotImplementedError):
            ds = dcmread(get_testdata_file("bad_sequence.dcm"))
            # accessing the elements of the faulty sequence raises
            str(ds.CTDIPhantomTypeCodeSequence)

        config.replace_un_with_known_vr = False
        ds = dcmread(get_testdata_file("bad_sequence.dcm"))
        str(ds.CTDIPhantomTypeCodeSequence)

    def test_no_pixels_read(self):
        """Returns all data elements before pixels using
        stop_before_pixels=False.
        """
        # Just check the tags, and a couple of values
        ctpartial = dcmread(ct_name, stop_before_pixels=True)
        ctpartial_tags = sorted(ctpartial.keys())
        ctfull = dcmread(ct_name)
        ctfull_tags = sorted(ctfull.keys())
        missing = [Tag(0x7FE0, 0x10), Tag(0xFFFC, 0xFFFC)]
        assert ctfull_tags == ctpartial_tags + missing

    def test_specific_tags(self):
        """Returns only tags specified by user."""
        ctspecific = dcmread(
            ct_name,
            specific_tags=[
                Tag(0x0010, 0x0010),
                "PatientID",
                "ImageType",
                "ViewName",
            ],
        )
        ctspecific_tags = sorted(ctspecific.keys())
        expected = [
            # SpecificCharacterSet is always added
            # ViewName does not exist in the data set
            Tag(0x0008, 0x0005),
            Tag(0x0008, 0x0008),
            Tag(0x0010, 0x0010),
            Tag(0x0010, 0x0020),
        ]
        assert expected == ctspecific_tags

    def test_specific_tags_with_unknown_length_SQ(self):
        """Returns only tags specified by user."""
        unknown_len_sq_tag = Tag(0x3F03, 0x1001)
        tags = dcmread(priv_SQ_name, specific_tags=[unknown_len_sq_tag])
        tags = sorted(tags.keys())
        assert [unknown_len_sq_tag] == tags

        tags = dcmread(priv_SQ_name, specific_tags=["PatientName"])
        tags = sorted(tags.keys())
        assert [] == tags

    def test_specific_tags_with_unknown_length_tag(self):
        """Returns only tags specified by user."""
        unknown_len_tag = Tag(0x7FE0, 0x0010)  # Pixel Data
        tags = dcmread(emri_jpeg_2k_lossless, specific_tags=[unknown_len_tag])
        tags = sorted(tags.keys())
        # SpecificCharacterSet is always added
        assert [Tag(0x08, 0x05), unknown_len_tag] == tags

        tags = dcmread(
            emri_jpeg_2k_lossless, specific_tags=["SpecificCharacterSet"]
        )
        tags = sorted(tags.keys())
        assert [Tag(0x08, 0x05)] == tags

    def test_tag_with_unknown_length_tag_too_short(self):
        """Tests handling of incomplete sequence value."""
        # the data set is the same as emri_jpeg_2k_lossless,
        # with the last 8 bytes removed to provoke the EOF error
        unknown_len_tag = Tag(0x7FE0, 0x0010)  # Pixel Data
        with pytest.warns(UserWarning, match="End of file reached*"):
            dcmread(
                emri_jpeg_2k_lossless_too_short,
                specific_tags=[unknown_len_tag],
            )

        config.enforce_valid_values = True
        with pytest.raises(EOFError, match="End of file reached*"):
            dcmread(
                emri_jpeg_2k_lossless_too_short,
                specific_tags=[unknown_len_tag],
            )

    def test_private_SQ(self):
        """Can read private undefined length SQ without error."""
        # From issues 91, 97, 98. Bug introduced by fast reading, due to
        #    VR=None in raw data elements, then an undefined length private
        #    item VR is looked up, and there is no such tag,
        #    generating an exception

        # Simply read the file, in 0.9.5 this generated an exception
        dcmread(priv_SQ_name)

    def test_nested_private_SQ(self):
        """Can successfully read a private SQ which contains additional SQs."""
        # From issue 113. When a private SQ of undefined length is used, the
        #   sequence is read in and the length of the SQ is determined upon
        #   identification of the SQ termination sequence. When using nested
        #   Sequences, the first termination sequence encountered actually
        #   belongs to the nested Sequence not the parent, therefore the
        #   remainder of the file is not read in properly
        ds = dcmread(nested_priv_SQ_name)

        # Make sure that the entire dataset was read in
        pixel_data_tag = TupleTag((0x7FE0, 0x10))
        assert pixel_data_tag in ds

        # Check that the DataElement is indeed a Sequence
        tag = TupleTag((0x01, 0x01))
        seq0 = ds[tag]
        assert "SQ" == seq0.VR

        # Now verify the presence of the nested private SQ
        seq1 = seq0[0][tag]
        assert "SQ" == seq1.VR

        # Now make sure the values that are parsed are correct
        assert b"Double Nested SQ" == seq1[0][tag].value
        assert b"Nested SQ" == seq0[0][0x01, 0x02].value

    def test_no_meta_group_length(self):
        """Read file with no group length in file meta."""
        # Issue 108 -- iView example file with no group length (0002,0002)
        # Originally crashed, now check no exception, but also check one item
        #     in file_meta, and second one in followinsg dataset
        ds = dcmread(no_meta_group_length)
        assert "20111130" == ds.InstanceCreationDate

    def test_no_transfer_syntax_in_meta(self):
        """Read file with file_meta, but has no TransferSyntaxUID in it."""
        # From issue 258: if file has file_meta but no TransferSyntaxUID in it,
        #   should assume default transfer syntax
        ds = dcmread(meta_missing_tsyntax_name)  # is default transfer syntax

        # Repeat one test from nested private sequence test to maker sure
        #    file was read correctly
        pixel_data_tag = TupleTag((0x7FE0, 0x10))
        assert pixel_data_tag in ds

    def test_explicit_VR_little_endian_no_meta(self):
        """Read file without file meta with Little Endian Explicit VR dataset.
        """
        # Example file from CMS XiO 5.0 and above
        # Still need to force read data since there is no 'DICM' marker present
        ds = dcmread(explicit_vr_le_no_meta, force=True)
        assert "20150529" == ds.InstanceCreationDate

    def test_explicit_VR_big_endian_no_meta(self):
        """Read file without file meta with Big Endian Explicit VR dataset."""
        # Example file from CMS XiO 5.0 and above
        # Still need to force read data since there is no 'DICM' marker present
        ds = dcmread(explicit_vr_be_no_meta, force=True)
        assert "20150529" == ds.InstanceCreationDate

    def test_planar_config(self):
        px_data_ds = dcmread(color_px_name)
        pl_data_ds = dcmread(color_pl_name)
        assert px_data_ds.PlanarConfiguration != pl_data_ds.PlanarConfiguration
        if have_numpy:
            px_data = px_data_ds.pixel_array
            pl_data = pl_data_ds.pixel_array
            assert numpy.all(px_data == pl_data)

    def test_correct_ambiguous_vr(self):
        """Test correcting ambiguous VR elements read from file"""
        ds = Dataset()
        ds.PixelRepresentation = 0
        ds.add(DataElement(0x00280108, "US", 10))
        ds.add(DataElement(0x00280109, "US", 500))

        fp = BytesIO()
        file_ds = FileDataset(fp, ds)
        file_ds.is_implicit_VR = True
        file_ds.is_little_endian = True
        file_ds.save_as(fp, write_like_original=True)

        ds = dcmread(fp, force=True)
        assert "US" == ds[0x00280108].VR
        assert 10 == ds.SmallestPixelValueInSeries

    def test_correct_ambiguous_explicit_vr(self):
        """Test correcting ambiguous VR elements read from file"""
        ds = Dataset()
        ds.PixelRepresentation = 0
        ds.add(DataElement(0x00280108, "US", 10))
        ds.add(DataElement(0x00280109, "US", 500))

        fp = BytesIO()
        file_ds = FileDataset(fp, ds)
        file_ds.is_implicit_VR = False
        file_ds.is_little_endian = True
        file_ds.save_as(fp, write_like_original=True)

        ds = dcmread(fp, force=True)
        assert "US" == ds[0x00280108].VR
        assert 10 == ds.SmallestPixelValueInSeries

    def test_correct_ambiguous_vr_compressed(self):
        """Test correcting compressed Pixel Data read from file"""
        # Create an implicit VR compressed dataset
        ds = dcmread(jpeg_lossless_name)
        fp = BytesIO()
        file_ds = FileDataset(fp, ds)
        file_ds.is_implicit_VR = True
        file_ds.is_little_endian = True
        file_ds.save_as(fp, write_like_original=True)

        ds = dcmread(fp, force=True)
        assert "OB" == ds[0x7FE00010].VR

    def test_long_specific_char_set(self):
        """Test that specific character set is read even if it is longer
         than defer_size"""
        ds = Dataset()

        long_specific_char_set_value = ["ISO 2022IR 100"] * 9
        ds.add(DataElement(0x00080005, "CS", long_specific_char_set_value))

        msg = (
            r"Unknown encoding 'ISO 2022IR 100' - using default encoding "
            r"instead"
        )

        fp = BytesIO()
        file_ds = FileDataset(fp, ds)
        with pytest.warns(UserWarning, match=msg):
            file_ds.save_as(fp, write_like_original=True)

        with pytest.warns(UserWarning, match=msg):
            ds = dcmread(fp, defer_size=65, force=True)
            assert long_specific_char_set_value == ds[0x00080005].value

    def test_no_preamble_file_meta_dataset(self):
        """Test correct read of group 2 elements with no preamble."""
        bytestream = (
            b"\x02\x00\x02\x00\x55\x49\x16\x00\x31\x2e\x32\x2e"
            b"\x38\x34\x30\x2e\x31\x30\x30\x30\x38\x2e\x35\x2e"
            b"\x31\x2e\x31\x2e\x39\x00\x02\x00\x10\x00\x55\x49"
            b"\x12\x00\x31\x2e\x32\x2e\x38\x34\x30\x2e\x31\x30"
            b"\x30\x30\x38\x2e\x31\x2e\x32\x00\x20\x20\x10\x00"
            b"\x02\x00\x00\x00\x01\x00\x20\x20\x20\x00\x06\x00"
            b"\x00\x00\x4e\x4f\x52\x4d\x41\x4c"
        )

        fp = BytesIO(bytestream)
        ds = dcmread(fp, force=True)
        assert "MediaStorageSOPClassUID" in ds.file_meta
        assert ImplicitVRLittleEndian == ds.file_meta.TransferSyntaxUID
        assert "NORMAL" == ds.Polarity
        assert 1 == ds.ImageBoxPosition

    def test_no_preamble_command_group_dataset(self):
        """Test correct read of group 0 and 2 elements with no preamble."""
        bytestream = (
            b"\x02\x00\x02\x00\x55\x49\x16\x00\x31\x2e\x32\x2e"
            b"\x38\x34\x30\x2e\x31\x30\x30\x30\x38\x2e\x35\x2e"
            b"\x31\x2e\x31\x2e\x39\x00\x02\x00\x10\x00\x55\x49"
            b"\x12\x00\x31\x2e\x32\x2e\x38\x34\x30\x2e\x31\x30"
            b"\x30\x30\x38\x2e\x31\x2e\x32\x00"
            b"\x20\x20\x10\x00\x02\x00\x00\x00\x01\x00\x20\x20"
            b"\x20\x00\x06\x00\x00\x00\x4e\x4f\x52\x4d\x41\x4c"
            b"\x00\x00\x10\x01\x02\x00\x00\x00\x03\x00"
        )

        fp = BytesIO(bytestream)
        ds = dcmread(fp, force=True)
        assert "MediaStorageSOPClassUID" in ds.file_meta
        assert ImplicitVRLittleEndian == ds.file_meta.TransferSyntaxUID
        assert "NORMAL" == ds.Polarity
        assert 1 == ds.ImageBoxPosition
        assert 3 == ds.MessageID

    def test_group_length_wrong(self):
        """Test file is read correctly even if FileMetaInformationGroupLength
        is incorrect.
        """
        bytestream = (
            b"\x02\x00\x00\x00\x55\x4C\x04\x00\x0A\x00\x00\x00"
            b"\x02\x00\x02\x00\x55\x49\x16\x00\x31\x2e\x32\x2e"
            b"\x38\x34\x30\x2e\x31\x30\x30\x30\x38\x2e\x35\x2e"
            b"\x31\x2e\x31\x2e\x39\x00\x02\x00\x10\x00\x55\x49"
            b"\x12\x00\x31\x2e\x32\x2e\x38\x34\x30\x2e\x31\x30"
            b"\x30\x30\x38\x2e\x31\x2e\x32\x00"
            b"\x20\x20\x10\x00\x02\x00\x00\x00\x01\x00\x20\x20"
            b"\x20\x00\x06\x00\x00\x00\x4e\x4f\x52\x4d\x41\x4c"
        )
        fp = BytesIO(bytestream)
        ds = dcmread(fp, force=True)
        value = ds.file_meta.FileMetaInformationGroupLength
        assert not len(bytestream) - 12 == value
        assert 10 == ds.file_meta.FileMetaInformationGroupLength
        assert "MediaStorageSOPClassUID" in ds.file_meta
        assert ImplicitVRLittleEndian == ds.file_meta.TransferSyntaxUID
        assert "NORMAL" == ds.Polarity
        assert 1 == ds.ImageBoxPosition

    def test_preamble_command_meta_no_dataset(self):
        """Test reading only preamble, command and meta elements"""
        preamble = b"\x00" * 128
        prefix = b"DICM"
        command = (
            b"\x00\x00\x00\x00\x04\x00\x00\x00\x38"
            b"\x00\x00\x00\x00\x00\x02\x00\x12\x00\x00"
            b"\x00\x31\x2e\x32\x2e\x38\x34\x30\x2e\x31"
            b"\x30\x30\x30\x38\x2e\x31\x2e\x31\x00\x00"
            b"\x00\x00\x01\x02\x00\x00\x00\x30\x00\x00"
            b"\x00\x10\x01\x02\x00\x00\x00\x07\x00\x00"
            b"\x00\x00\x08\x02\x00\x00\x00\x01\x01"
        )
        meta = (
            b"\x02\x00\x00\x00\x55\x4C\x04\x00\x0A\x00\x00\x00"
            b"\x02\x00\x02\x00\x55\x49\x16\x00\x31\x2e\x32\x2e"
            b"\x38\x34\x30\x2e\x31\x30\x30\x30\x38\x2e\x35\x2e"
            b"\x31\x2e\x31\x2e\x39\x00\x02\x00\x10\x00\x55\x49"
            b"\x12\x00\x31\x2e\x32\x2e\x38\x34\x30\x2e\x31\x30"
            b"\x30\x30\x38\x2e\x31\x2e\x32\x00"
        )

        bytestream = preamble + prefix + meta + command
        fp = BytesIO(bytestream)
        ds = dcmread(fp, force=True)
        assert "TransferSyntaxUID" in ds.file_meta
        assert "MessageID" in ds

    def test_preamble_meta_no_dataset(self):
        """Test reading only preamble and meta elements"""
        preamble = b"\x00" * 128
        prefix = b"DICM"
        meta = (
            b"\x02\x00\x00\x00\x55\x4C\x04\x00\x0A\x00\x00\x00"
            b"\x02\x00\x02\x00\x55\x49\x16\x00\x31\x2e\x32\x2e"
            b"\x38\x34\x30\x2e\x31\x30\x30\x30\x38\x2e\x35\x2e"
            b"\x31\x2e\x31\x2e\x39\x00\x02\x00\x10\x00\x55\x49"
            b"\x12\x00\x31\x2e\x32\x2e\x38\x34\x30\x2e\x31\x30"
            b"\x30\x30\x38\x2e\x31\x2e\x32\x00"
        )

        bytestream = preamble + prefix + meta
        fp = BytesIO(bytestream)
        ds = dcmread(fp, force=True)
        assert b"\x00" * 128 == ds.preamble
        assert "TransferSyntaxUID" in ds.file_meta
        assert Dataset() == ds[:]

    def test_preamble_commandset_no_dataset(self):
        """Test reading only preamble and command set"""
        preamble = b"\x00" * 128
        prefix = b"DICM"
        command = (
            b"\x00\x00\x00\x00\x04\x00\x00\x00\x38"
            b"\x00\x00\x00\x00\x00\x02\x00\x12\x00\x00"
            b"\x00\x31\x2e\x32\x2e\x38\x34\x30\x2e\x31"
            b"\x30\x30\x30\x38\x2e\x31\x2e\x31\x00\x00"
            b"\x00\x00\x01\x02\x00\x00\x00\x30\x00\x00"
            b"\x00\x10\x01\x02\x00\x00\x00\x07\x00\x00"
            b"\x00\x00\x08\x02\x00\x00\x00\x01\x01"
        )
        bytestream = preamble + prefix + command

        fp = BytesIO(bytestream)
        ds = dcmread(fp, force=True)
        assert "MessageID" in ds
        assert Dataset() == ds.file_meta

    def test_meta_no_dataset(self):
        """Test reading only meta elements"""
        bytestream = (
            b"\x02\x00\x00\x00\x55\x4C\x04\x00\x0A\x00\x00\x00"
            b"\x02\x00\x02\x00\x55\x49\x16\x00\x31\x2e\x32\x2e"
            b"\x38\x34\x30\x2e\x31\x30\x30\x30\x38\x2e\x35\x2e"
            b"\x31\x2e\x31\x2e\x39\x00\x02\x00\x10\x00\x55\x49"
            b"\x12\x00\x31\x2e\x32\x2e\x38\x34\x30\x2e\x31\x30"
            b"\x30\x30\x38\x2e\x31\x2e\x32\x00"
        )
        fp = BytesIO(bytestream)
        ds = dcmread(fp, force=True)
        assert "TransferSyntaxUID" in ds.file_meta
        assert Dataset() == ds[:]

    def test_commandset_no_dataset(self):
        """Test reading only command set elements"""
        bytestream = (
            b"\x00\x00\x00\x00\x04\x00\x00\x00\x38"
            b"\x00\x00\x00\x00\x00\x02\x00\x12\x00\x00"
            b"\x00\x31\x2e\x32\x2e\x38\x34\x30\x2e\x31"
            b"\x30\x30\x30\x38\x2e\x31\x2e\x31\x00\x00"
            b"\x00\x00\x01\x02\x00\x00\x00\x30\x00\x00"
            b"\x00\x10\x01\x02\x00\x00\x00\x07\x00\x00"
            b"\x00\x00\x08\x02\x00\x00\x00\x01\x01"
        )
        fp = BytesIO(bytestream)
        ds = dcmread(fp, force=True)
        assert "MessageID" in ds
        assert ds.preamble is None
        assert Dataset() == ds.file_meta

    def test_file_meta_dataset_implicit_vr(self):
        """Test reading a file meta dataset that is implicit VR"""

        bytestream = (
            b"\x02\x00\x10\x00\x12\x00\x00\x00"
            b"\x31\x2e\x32\x2e\x38\x34\x30\x2e"
            b"\x31\x30\x30\x30\x38\x2e\x31\x2e"
            b"\x32\x00"
        )
        fp = BytesIO(bytestream)
        with pytest.warns(UserWarning):
            ds = dcmread(fp, force=True)
        assert "TransferSyntaxUID" in ds.file_meta

    def test_no_dataset(self):
        """Test reading no elements or preamble produces empty Dataset"""
        bytestream = b""
        fp = BytesIO(bytestream)
        ds = dcmread(fp, force=True)
        assert ds.preamble is None
        assert Dataset() == ds.file_meta
        assert Dataset() == ds[:]

    def test_empty_file(self):
        """Test reading no elements from file produces empty Dataset"""
        with tempfile.NamedTemporaryFile() as f:
            ds = dcmread(f, force=True)
            assert ds.preamble is None
            assert Dataset() == ds.file_meta
            assert Dataset() == ds[:]

    def test_empty_specific_character_set(self):
        """Test that an empty Specific Character Set is handled correctly.
        Regression test for #1038"""
        ds = dcmread(get_testdata_file("empty_charset_LEI.dcm"))
        assert ds.read_encoding == ["iso8859"]

    def test_dcmread_does_not_raise(self):
        """Test that reading from DicomBytesIO does not raise on EOF.
        Regression test for #358."""
        ds = dcmread(mr_name)
        fp = DicomBytesIO()
        ds.save_as(fp, write_like_original=True)
        fp.seek(0)
        de_gen = data_element_generator(fp, False, True)
        try:
            while True:
                next(de_gen)
        except StopIteration:
            pass
        except EOFError:
            self.fail("Unexpected EOFError raised")

    def test_lut_descriptor(self):
        """Regression test for #942: incorrect first value"""
        prefixes = [
            b"\x28\x00\x01\x11",
            b"\x28\x00\x02\x11",
            b"\x28\x00\x03\x11",
            b"\x28\x00\x02\x30",
        ]
        suffix = b"\x53\x53\x06\x00\x00\xf5\x00\xf8\x10\x00"

        for raw_tag in prefixes:
            tag = unpack("<2H", raw_tag)
            bs = DicomBytesIO(raw_tag + suffix)
            bs.is_little_endian = True
            bs.is_implicit_VR = False

            ds = dcmread(bs, force=True)
            elem = ds[tag]
            assert elem.VR == "SS"
            assert elem.value == [62720, -2048, 16]

    def test_lut_descriptor_empty(self):
        """Regression test for #1049: LUT empty raises."""
        bs = DicomBytesIO(b"\x28\x00\x01\x11\x53\x53\x00\x00")
        bs.is_little_endian = True
        bs.is_implicit_VR = False
        ds = dcmread(bs, force=True)
        elem = ds[0x00281101]
        assert elem.value is None
        assert elem.VR == "SS"

    def test_lut_descriptor_singleton(self):
        """Test LUT Descriptor with VM = 1"""
        bs = DicomBytesIO(b"\x28\x00\x01\x11\x53\x53\x02\x00\x00\xf5")
        bs.is_little_endian = True
        bs.is_implicit_VR = False
        ds = dcmread(bs, force=True)
        elem = ds[0x00281101]
        # No conversion to US if not a triplet
        assert elem.value == -2816
        assert elem.VR == "SS"

    def test_reading_of(self):
        """Test reading a dataset with OF element."""
        bs = DicomBytesIO(
            b"\x28\x00\x01\x11\x53\x53\x06\x00\x00\xf5\x00\xf8\x10\x00"
            b"\xe0\x7f\x08\x00\x4F\x46\x00\x00\x04\x00\x00\x00\x00\x01\x02\x03"
        )
        bs.is_little_endian = True
        bs.is_implicit_VR = False

        ds = dcmread(bs, force=True)
        elem = ds["FloatPixelData"]
        assert "OF" == elem.VR
        assert b"\x00\x01\x02\x03" == elem.value


class TestIncorrectVR:
    def setup(self):
        config.enforce_valid_values = False
        self.ds_explicit = BytesIO(
            b"\x08\x00\x05\x00CS\x0a\x00ISO_IR 100"  # SpecificCharacterSet
            b"\x08\x00\x20\x00DA\x08\x0020000101"  # StudyDate
        )
        self.ds_implicit = BytesIO(
            b"\x08\x00\x05\x00\x0a\x00\x00\x00ISO_IR 100"
            b"\x08\x00\x20\x00\x08\x00\x00\x0020000101"
        )

    def teardown(self):
        config.enforce_valid_values = False

    def test_implicit_vr_expected_explicit_used(self):
        msg = (
            "Expected implicit VR, but found explicit VR - "
            "using explicit VR for reading"
        )

        with pytest.warns(UserWarning, match=msg):
            ds = read_dataset(
                self.ds_explicit, is_implicit_VR=True, is_little_endian=True
            )
        assert "ISO_IR 100" == ds.SpecificCharacterSet
        assert "20000101" == ds.StudyDate

    def test_implicit_vr_expected_explicit_used_strict(self):
        config.enforce_valid_values = True
        msg = (
            "Expected implicit VR, but found explicit VR - "
            "using explicit VR for reading"
        )

        with pytest.raises(InvalidDicomError, match=msg):
            read_dataset(
                self.ds_explicit, is_implicit_VR=True, is_little_endian=True
            )

    def test_explicit_vr_expected_implicit_used(self):
        msg = (
            "Expected explicit VR, but found implicit VR - "
            "using implicit VR for reading"
        )

        with pytest.warns(UserWarning, match=msg):
            ds = read_dataset(
                self.ds_implicit, is_implicit_VR=False, is_little_endian=True
            )
        assert "ISO_IR 100" == ds.SpecificCharacterSet
        assert "20000101" == ds.StudyDate

    def test_explicit_vr_expected_implicit_used_strict(self):
        config.enforce_valid_values = True
        msg = (
            "Expected explicit VR, but found implicit VR - "
            "using implicit VR for reading"
        )
        with pytest.raises(InvalidDicomError, match=msg):
            read_dataset(
                self.ds_implicit, is_implicit_VR=False, is_little_endian=True
            )

    def test_seq_item_looks_like_explicit_VR(self):
        # For issue 999.

        # Set up an implicit VR dataset with a "normal" group 8 tag,
        # followed by a sequence with an item (dataset) having
        # a data element length that looks like a potential valid VR
        ds = Dataset()
        ds.file_meta = FileMetaDataset()
        ds.file_meta.MediaStorageSOPClassUID = "1.1.1"
        ds.file_meta.MediaStorageSOPInstanceUID = "2.2.2"
        ds.is_implicit_VR = True
        ds.is_little_endian = True
        ds.SOPClassUID = "9.9.9"  # First item group 8 in top-level dataset
        seq = Sequence()
        seq_ds = Dataset()
        seq_ds.BadPixelImage = b"\3" * 0x5244  # length looks like "DR"
        seq.append(seq_ds)
        ds.ReferencedImageSequence = seq

        dbio = DicomBytesIO()
        ds.save_as(dbio, write_like_original=False)

        # Now read the constructed dataset back in
        # In original issue, shows warning that has detected what appears
        # to be Explicit VR, then throws NotImplemented for the unknown VR
        dbio.seek(0)
        ds = dcmread(dbio)
        ds.remove_private_tags()  # forces it to actually parse SQ


class TestUnknownVR:
    @pytest.mark.parametrize(
        "vr_bytes, str_output",
        [
            # Test limits of char values
            (b"\x00\x41", "0x00 0x41"),  # 000/A
            (b"\x40\x41", "0x40 0x41"),  # 064/A
            (b"\x5B\x41", "0x5b 0x41"),  # 091/A
            (b"\x60\x41", "0x60 0x41"),  # 096/A
            (b"\x7B\x41", "0x7b 0x41"),  # 123/A
            (b"\xFF\x41", "0xff 0x41"),  # 255/A
            # Test good/bad
            (b"\x41\x00", "0x41 0x00"),  # A/-
            (b"\x5A\x00", "0x5a 0x00"),  # Z/-
            # Test not quite good/bad
            (b"\x61\x00", "0x61 0x00"),  # a/-
            (b"\x7A\x00", "0x7a 0x00"),  # z/-
            # Test bad/good
            (b"\x00\x41", "0x00 0x41"),  # -/A
            (b"\x00\x5A", "0x00 0x5a"),  # -/Z
            # Test bad/not quite good
            (b"\x00\x61", "0x00 0x61"),  # -/a
            (b"\x00\x7A", "0x00 0x7a"),  # -/z
            # Test good/good
            (b"\x41\x41", "AA"),  # A/A
            (b"\x41\x5A", "AZ"),  # A/Z
            (b"\x5A\x41", "ZA"),  # Z/A
            (b"\x5A\x5A", "ZZ"),  # Z/Z
            # Test not quite good
            (b"\x41\x61", "Aa"),  # A/a
            (b"\x41\x7A", "Az"),  # A/z
            (b"\x61\x41", "aA"),  # a/A
            (b"\x61\x5A", "aZ"),  # a/Z
            (b"\x61\x61", "aa"),  # a/a
            (b"\x61\x7A", "az"),  # a/z
            (b"\x5A\x61", "Za"),  # Z/a
            (b"\x5A\x7A", "Zz"),  # Z/z
            (b"\x7A\x41", "zA"),  # z/A
            (b"\x7A\x5A", "zZ"),  # z/Z
            (b"\x7A\x61", "za"),  # z/a
            (b"\x7A\x7A", "zz"),  # z/z
        ],
    )
    def test_fail_decode_msg(self, vr_bytes, str_output):
        """Regression test for #791."""
        # start the dataset with a valid tag (SpecificCharacterSet),
        # as the first tag is used to check the VR
        ds = read_dataset(
            BytesIO(
                b"\x08\x00\x05\x00CS\x0a\x00ISO_IR 100"
                b"\x08\x00\x06\x00" + vr_bytes + b"\x00\x00\x00\x08\x00\x49"
            ),
            False,
            True,
        )
        msg = r"Unknown Value Representation '{}' in tag \(0008, 0006\)"
        msg = msg.format(str_output)
        with pytest.raises(NotImplementedError, match=msg):
            print(ds)


class TestReadDataElement:
    def setup(self):
        ds = Dataset()
        ds.DoubleFloatPixelData = (
            b"\x00\x01\x02\x03\x04\x05\x06\x07"
            b"\x01\x01\x02\x03\x04\x05\x06\x07"
        )  # OD
        ds.SelectorOLValue = (
            b"\x00\x01\x02\x03\x04\x05\x06\x07" b"\x01\x01\x02\x03"
        )  # VR of OL
        ds.PotentialReasonsForProcedure = [
            "A",
            "B",
            "C",
        ]  # VR of UC, odd length
        ds.StrainDescription = "Test"  # Even length
        ds.URNCodeValue = "http://test.com"  # VR of UR
        ds.RetrieveURL = "ftp://test.com  "  # Test trailing spaces ignored
        ds.DestinationAE = "    TEST  12    "  # 16 characters max for AE
        # 8-byte values
        ds.ExtendedOffsetTable = (  # VR of OV
            b"\x00\x00\x00\x00\x00\x00\x00\x00"
            b"\x01\x02\x03\x04\x05\x06\x07\x08"
        )

        # No public elements with VR of SV or UV yet...
        add_dict_entries(
            {
                0xFFFE0001: (
                    "SV",
                    "1",
                    "SV Element Minimum",
                    "",
                    "SVElementMinimum",
                ),
                0xFFFE0002: (
                    "SV",
                    "1",
                    "SV Element Maximum",
                    "",
                    "SVElementMaximum",
                ),
                0xFFFE0003: (
                    "UV",
                    "1",
                    "UV Element Minimum",
                    "",
                    "UVElementMinimum",
                ),
                0xFFFE0004: (
                    "UV",
                    "1",
                    "UV Element Maximum",
                    "",
                    "UVElementMaximum",
                ),
            }
        )
        ds.SVElementMinimum = -(2 ** 63)
        ds.SVElementMaximum = 2 ** 63 - 1
        ds.UVElementMinimum = 0
        ds.UVElementMaximum = 2 ** 64 - 1

        self.fp = BytesIO()  # Implicit little
        file_ds = FileDataset(self.fp, ds)
        file_ds.is_implicit_VR = True
        file_ds.is_little_endian = True
        file_ds.save_as(self.fp, write_like_original=True)

        self.fp_ex = BytesIO()  # Explicit little
        file_ds = FileDataset(self.fp_ex, ds)
        file_ds.is_implicit_VR = False
        file_ds.is_little_endian = True
        file_ds.save_as(self.fp_ex, write_like_original=True)

    def test_read_OD_implicit_little(self):
        """Check creation of OD DataElement from byte data works correctly."""
        ds = dcmread(self.fp, force=True)
        ref_elem = ds.get(0x7FE00009)
        elem = DataElement(
            0x7FE00009,
            "OD",
            b"\x00\x01\x02\x03\x04\x05\x06\x07"
            b"\x01\x01\x02\x03\x04\x05\x06\x07",
        )
        assert ref_elem == elem

    def test_read_OD_explicit_little(self):
        """Check creation of OD DataElement from byte data works correctly."""
        ds = dcmread(self.fp_ex, force=True)
        ref_elem = ds.get(0x7FE00009)
        elem = DataElement(
            0x7FE00009,
            "OD",
            b"\x00\x01\x02\x03\x04\x05\x06\x07"
            b"\x01\x01\x02\x03\x04\x05\x06\x07",
        )
        assert ref_elem == elem

    def test_read_OL_implicit_little(self):
        """Check creation of OL DataElement from byte data works correctly."""
        ds = dcmread(self.fp, force=True)
        ref_elem = ds.get(0x00720075)
        elem = DataElement(
            0x00720075,
            "OL",
            b"\x00\x01\x02\x03\x04\x05\x06\x07" b"\x01\x01\x02\x03",
        )
        assert ref_elem == elem

    def test_read_OL_explicit_little(self):
        """Check creation of OL DataElement from byte data works correctly."""
        ds = dcmread(self.fp_ex, force=True)
        ref_elem = ds.get(0x00720075)
        elem = DataElement(
            0x00720075,
            "OL",
            b"\x00\x01\x02\x03\x04\x05\x06\x07" b"\x01\x01\x02\x03",
        )
        assert ref_elem == elem

    def test_read_UC_implicit_little(self):
        """Check creation of DataElement from byte data works correctly."""
        ds = dcmread(self.fp, force=True)
        ref_elem = ds.get(0x00189908)
        elem = DataElement(0x00189908, "UC", ["A", "B", "C"])
        assert ref_elem == elem

        ds = dcmread(self.fp, force=True)
        ref_elem = ds.get(0x00100212)
        elem = DataElement(0x00100212, "UC", "Test")
        assert ref_elem == elem

    def test_read_UC_explicit_little(self):
        """Check creation of DataElement from byte data works correctly."""
        ds = dcmread(self.fp_ex, force=True)
        ref_elem = ds.get(0x00189908)
        elem = DataElement(0x00189908, "UC", ["A", "B", "C"])
        assert ref_elem == elem

        ds = dcmread(self.fp_ex, force=True)
        ref_elem = ds.get(0x00100212)
        elem = DataElement(0x00100212, "UC", "Test")
        assert ref_elem == elem

    def test_read_UR_implicit_little(self):
        """Check creation of DataElement from byte data works correctly."""
        ds = dcmread(self.fp, force=True)
        ref_elem = ds.get(0x00080120)  # URNCodeValue
        elem = DataElement(0x00080120, "UR", "http://test.com")
        assert ref_elem == elem

        # Test trailing spaces ignored
        ref_elem = ds.get(0x00081190)  # RetrieveURL
        elem = DataElement(0x00081190, "UR", "ftp://test.com")
        assert ref_elem == elem

    def test_read_UR_explicit_little(self):
        """Check creation of DataElement from byte data works correctly."""
        ds = dcmread(self.fp_ex, force=True)
        ref_elem = ds.get(0x00080120)  # URNCodeValue
        elem = DataElement(0x00080120, "UR", "http://test.com")
        assert ref_elem == elem

        # Test trailing spaces ignored
        ref_elem = ds.get(0x00081190)  # RetrieveURL
        elem = DataElement(0x00081190, "UR", "ftp://test.com")
        assert ref_elem == elem

    def test_read_AE(self):
        """Check creation of AE DataElement from byte data works correctly."""
        ds = dcmread(self.fp, force=True)
        assert "TEST  12" == ds.DestinationAE

    def test_read_OV_implicit_little(self):
        """Check reading element with VR of OV encoded as implicit"""
        ds = dcmread(self.fp, force=True)
        val = (
            b"\x00\x00\x00\x00\x00\x00\x00\x00"
            b"\x01\x02\x03\x04\x05\x06\x07\x08"
        )
        elem = ds["ExtendedOffsetTable"]
        assert "OV" == elem.VR
        assert 0x7FE00001 == elem.tag
        assert val == elem.value

        new = DataElement(0x7FE00001, "OV", val)
        assert elem == new

    def test_read_OV_explicit_little(self):
        """Check reading element with VR of OV encoded as explicit"""
        ds = dcmread(self.fp_ex, force=True)
        val = (
            b"\x00\x00\x00\x00\x00\x00\x00\x00"
            b"\x01\x02\x03\x04\x05\x06\x07\x08"
        )
        elem = ds["ExtendedOffsetTable"]
        assert "OV" == elem.VR
        assert 0x7FE00001 == elem.tag
        assert val == elem.value

        new = DataElement(0x7FE00001, "OV", val)
        assert elem == new

    def test_read_SV_implicit_little(self):
        """Check reading element with VR of SV encoded as implicit"""
        ds = dcmread(self.fp, force=True)
        elem = ds["SVElementMinimum"]
        assert "SV" == elem.VR
        assert 0xFFFE0001 == elem.tag
        assert -(2 ** 63) == elem.value

        new = DataElement(0xFFFE0001, "SV", -(2 ** 63))
        assert elem == new

        elem = ds["SVElementMaximum"]
        assert "SV" == elem.VR
        assert 0xFFFE0002 == elem.tag
        assert 2 ** 63 - 1 == elem.value

        new = DataElement(0xFFFE0002, "SV", 2 ** 63 - 1)
        assert elem == new

    @pytest.mark.skip("No public elements with VR of SV")
    def test_read_SV_explicit_little(self):
        """Check reading element with VR of SV encoded as explicit"""
        ds = dcmread(self.fp_ex, force=True)
        elem = ds["SVElementMinimum"]
        assert "SV" == elem.VR
        assert 0xFFFE0001 == elem.tag
        assert -(2 ** 63) == elem.value

        new = DataElement(0xFFFE0001, "SV", -(2 ** 63))
        assert elem == new

        elem = ds["SVElementMaximum"]
        assert "SV" == elem.VR
        assert 0xFFFE0002 == elem.tag
        assert 2 ** 63 - 1 == elem.value

        new = DataElement(0xFFFE0002, "SV", 2 ** 63 - 1)
        assert elem == new

    def test_read_UV_implicit_little(self):
        """Check reading element with VR of UV encoded as implicit"""
        ds = dcmread(self.fp, force=True)
        elem = ds["UVElementMinimum"]
        assert "UV" == elem.VR
        assert 0xFFFE0003 == elem.tag
        assert 0 == elem.value

        new = DataElement(0xFFFE0003, "UV", 0)
        assert elem == new

        elem = ds["UVElementMaximum"]
        assert "UV" == elem.VR
        assert 0xFFFE0004 == elem.tag
        assert 2 ** 64 - 1 == elem.value

        new = DataElement(0xFFFE0004, "UV", 2 ** 64 - 1)
        assert elem == new

    def test_read_UV_explicit_little(self):
        """Check reading element with VR of UV encoded as explicit"""
        ds = dcmread(self.fp_ex, force=True)
        elem = ds["UVElementMinimum"]
        assert "UV" == elem.VR
        assert 0xFFFE0003 == elem.tag
        assert 0 == elem.value

        new = DataElement(0xFFFE0003, "UV", 0)
        assert elem == new

        elem = ds["UVElementMaximum"]
        assert "UV" == elem.VR
        assert 0xFFFE0004 == elem.tag
        assert 2 ** 64 - 1 == elem.value

        new = DataElement(0xFFFE0004, "UV", 2 ** 64 - 1)
        assert elem == new


class TestDSISnumpy:
    def setup(self):
        self.orig_IS_numpy = config.use_IS_numpy
        self.orig_DS_numpy = config.use_DS_numpy
        self.orig_DS_decimal = config.use_DS_decimal

    def teardown(self):
        config.use_IS_numpy = self.orig_IS_numpy
        config.DS_decimal(self.orig_DS_decimal)
        config.DS_numpy(self.orig_DS_numpy)

    @pytest.mark.skipif(have_numpy, reason="Testing import error")
    def test_IS_numpy_import_error(self):
        config.use_IS_numpy = True
        rtss = dcmread(rtstruct_name, force=True)
        # no numpy, then trying to use numpy raises error
        with pytest.raises(ImportError):
            col = rtss.ROIContourSequence[0].ROIDisplayColor  # VR is IS

    @pytest.mark.skipif(not have_numpy, reason="Testing with numpy only")
    def test_IS_numpy_class(self):
        config.use_IS_numpy = True
        rtss = dcmread(rtstruct_name, force=True)
        col = rtss.ROIContourSequence[0].ROIDisplayColor  # VR is IS
        assert isinstance(col, numpy.ndarray)
        assert "int64" == col.dtype

        # Check a conversion with only a single value
        roi_num = rtss.ROIContourSequence[0].ReferencedROINumber
        assert isinstance(roi_num, numpy.int64)

    def test_IS_not_numpy(self):
        """Test class of the object matches the config,
        when the config is changed"""
        config.use_IS_numpy = False
        rtss = dcmread(rtstruct_name, force=True)
        col = rtss.ROIContourSequence[0].ROIDisplayColor  # VR is IS
        assert isinstance(col, MultiValue)

    @pytest.mark.skipif(have_numpy, reason="Testing import error")
    def test_DS_numpy_import_error(self):
        config.use_DS_numpy = True
        rtss = dcmread(rtstruct_name, force=True)
        # no numpy, then trying to use numpy raises error
        with pytest.raises(ImportError):
            cd = rtss.ROIContourSequence[0].ContourSequence[0].ContourData

    @pytest.mark.skipif(not have_numpy, reason="Testing with numpy only")
    def test_DS_numpy_class(self):
        config.use_DS_numpy = True
        rtss = dcmread(rtstruct_name, force=True)
        # ContourData has VR of DS
        cd = rtss.ROIContourSequence[0].ContourSequence[0].ContourData
        assert isinstance(cd, numpy.ndarray)
        assert "float64" == cd.dtype

        # Check conversion with only a single value
        roi_vol = rtss.StructureSetROISequence[0].ROIVolume
        assert isinstance(roi_vol, numpy.float64)

    def test_DS_not_numpy(self):
        """Test class of the object matches the config."""
        config.use_DS_numpy = False
        rtss = dcmread(rtstruct_name, force=True)
        # ContourData has VR of DS
        cd = rtss.ROIContourSequence[0].ContourSequence[0].ContourData
        assert isinstance(cd, MultiValue)

    @pytest.mark.skipif(not have_numpy, reason="numpy not installed")
    def test_DS_conflict_config(self):
        config.DS_decimal(True)
        with pytest.raises(ValueError):
            config.DS_numpy(True)

    @pytest.mark.skipif(not have_numpy, reason="numpy not installed")
    def test_DS_conflict_config2(self):
        config.DS_numpy(True)
        with pytest.raises(ValueError):
            config.DS_decimal(True)

    @pytest.mark.skipif(not have_numpy, reason="numpy not installed")
    def test_DS_bad_chars(self):
        config.DS_numpy(True)
        with pytest.raises(ValueError):
            values.convert_DS_string(b"123.1b", True)

    @pytest.mark.skipif(not have_numpy, reason="numpy not installed")
    def test_IS_bad_chars(self):
        config.use_IS_numpy = True
        with pytest.raises(ValueError):
            values.convert_IS_string(b"123b", True)

    @pytest.mark.skipif(have_numpy, reason="testing numpy ImportError")
    def test_numpy_import_warning(self):
        config.DS_numpy(True)
        config.use_IS_numpy = True
        with pytest.raises(ImportError):
            values.convert_DS_string(b"123.1", True)
        with pytest.raises(ImportError):
            values.convert_IS_string(b"123", True)


class TestDeferredRead:
    """Test that deferred data element reading (for large size)
    works as expected
    """

    # Copy one of test files and use temporarily, then later remove.
    def setup(self):
        self.testfile_name = ct_name + ".tmp"
        shutil.copyfile(ct_name, self.testfile_name)

    def teardown(self):
        if os.path.exists(self.testfile_name):
            os.remove(self.testfile_name)

    def test_time_check(self):
        """Deferred read warns if file has been modified"""
        ds = dcmread(self.testfile_name, defer_size="2 kB")
        from time import sleep

        sleep(0.1)
        with open(self.testfile_name, "r+") as f:
            f.write("\0")  # "touch" the file

        msg = r"Deferred read warning -- file modification time has changed"
        with pytest.warns(UserWarning, match=msg):
            ds.PixelData

    def test_file_exists(self):
        """Deferred read raises error if file no longer exists."""
        ds = dcmread(self.testfile_name, defer_size=2000)
        os.remove(self.testfile_name)
        with pytest.raises(IOError):
            ds.PixelData

    def test_values_identical(self):
        """Deferred values exactly matches normal read."""
        ds_norm = dcmread(self.testfile_name)
        ds_defer = dcmread(self.testfile_name, defer_size=2000)
        for data_elem in ds_norm:
            tag = data_elem.tag

            if have_numpy and isinstance(data_elem.value, numpy.ndarray):
                assert numpy.allclose(data_elem.value, ds_defer[tag].value)
            else:
                assert data_elem.value == ds_defer[tag].value

    def test_zipped_deferred(self):
        """Deferred values from a gzipped file works."""
        # Arose from issue 103 "Error for defer_size read of gzip file object"
        fobj = gzip.open(gzip_name)
        ds = dcmread(fobj, defer_size=1)
        fobj.close()
        # before the fix, this threw an error as file reading was not in
        # the right place, it was re-opened as a normal file, not a zip file
        ds.InstanceNumber

    def test_filelike_deferred(self):
        """Deferred values work with file-like objects."""
        with open(ct_name, "rb") as fp:
            data = fp.read()
        filelike = io.BytesIO(data)
        dataset = pydicom.dcmread(filelike, defer_size=1024)
        assert 32768 == len(dataset.PixelData)


class TestReadTruncatedFile:
    def testReadFileWithMissingPixelData(self):
        mr = dcmread(truncated_mr_name)
        mr.decode()
        assert "CompressedSamples^MR1" == mr.PatientName
        assert mr.PatientName == mr[0x10, 0x10].value
        DS = pydicom.valuerep.DS

        if have_numpy and config.use_DS_numpy:
            expected = numpy.array([0.3125, 0.3125])
            assert numpy.allclose(mr.PixelSpacing, expected)
        else:
            assert [DS("0.3125"), DS("0.3125")] == mr.PixelSpacing

    @pytest.mark.skipif(
        not have_numpy or have_gdcm_handler,
        reason="Missing numpy or GDCM present",
    )
    def testReadFileWithMissingPixelDataArray(self):
        mr = dcmread(truncated_mr_name)
        mr.decode()
        # Need to escape brackets
        msg = (
            r"The length of the pixel data in the dataset \(8130 bytes\) "
            r"doesn't match the expected length \(8192 bytes\). "
            r"The dataset may be corrupted or there may be an issue with "
            r"the pixel data handler."
        )
        with pytest.raises(ValueError, match=msg):
            mr.pixel_array


class TestFileLike:
    """Test that can read DICOM files with file-like object rather than
    filename
    """

    def test_read_file_given_file_object(self):
        """filereader: can read using already opened file............"""
        f = open(ct_name, "rb")
        ct = dcmread(f)
        # XXX Tests here simply repeat testCT -- perhaps should collapse
        # the code together?
        DS = pydicom.valuerep.DS

        got = ct.ImagePositionPatient
        if have_numpy and config.use_DS_numpy:
            expected = numpy.array([-158.135803, -179.035797, -75.699997])
            assert numpy.allclose(got, expected)
        else:
            expected = [DS("-158.135803"), DS("-179.035797"), DS("-75.699997")]
            assert expected == got

        assert "1.3.6.1.4.1.5962.2" == ct.file_meta.ImplementationClassUID
        value = ct.file_meta[0x2, 0x12].value
        assert ct.file_meta.ImplementationClassUID == value

        assert 128 == ct.Rows
        assert 128 == ct.Columns
        assert 16 == ct.BitsStored
        assert 128 * 128 * 2 == len(ct.PixelData)

        # Should also be able to close the file ourselves without
        # exception raised:
        f.close()

    def test_read_file_given_file_like_object(self):
        """filereader: can read using a file-like (BytesIO) file...."""
        with open(ct_name, "rb") as f:
            file_like = BytesIO(f.read())
        ct = dcmread(file_like)
        # Tests here simply repeat some of testCT test
        got = ct.ImagePositionPatient
        DS = pydicom.valuerep.DS

        if have_numpy and config.use_DS_numpy:
            expected = numpy.array([-158.135803, -179.035797, -75.699997])
            assert numpy.allclose(got, expected)
        else:
            expected = [DS("-158.135803"), DS("-179.035797"), DS("-75.699997")]
            assert expected == got

        assert 128 * 128 * 2 == len(ct.PixelData)

        # Should also be able to close the file ourselves without
        # exception raised:
        file_like.close()


class TestDataElementGenerator:
    """Test filereader.data_element_generator"""

    def test_little_endian_explicit(self):
        """Test reading little endian explicit VR data"""
        # (0010, 0010) PatientName PN 6 ABCDEF
        bytestream = b"\x10\x00\x10\x00" b"PN" b"\x06\x00" b"ABCDEF"
        fp = BytesIO(bytestream)
        # fp, is_implicit_VR, is_little_endian,
        gen = data_element_generator(fp, False, True)
        elem = DataElement(0x00100010, "PN", "ABCDEF")
        assert elem == DataElement_from_raw(next(gen), "ISO_IR 100")

    def test_little_endian_implicit(self):
        """Test reading little endian implicit VR data"""
        # (0010, 0010) PatientName PN 6 ABCDEF
        bytestream = b"\x10\x00\x10\x00" b"\x06\x00\x00\x00" b"ABCDEF"
        fp = BytesIO(bytestream)
        gen = data_element_generator(
            fp, is_implicit_VR=True, is_little_endian=True
        )
        elem = DataElement(0x00100010, "PN", "ABCDEF")
        assert elem == DataElement_from_raw(next(gen), "ISO_IR 100")

    def test_big_endian_explicit(self):
        """Test reading big endian explicit VR data"""
        # (0010, 0010) PatientName PN 6 ABCDEF
        bytestream = b"\x00\x10\x00\x10" b"PN" b"\x00\x06" b"ABCDEF"
        fp = BytesIO(bytestream)
        # fp, is_implicit_VR, is_little_endian,
        gen = data_element_generator(fp, False, False)
        elem = DataElement(0x00100010, "PN", "ABCDEF")
        assert elem == DataElement_from_raw(next(gen), "ISO_IR 100")