Repository: pydicom/pydicom

Issue:
Unable to assign single element list to PN field
I am getting `AttributeError` while trying to assign a list of single element to a `PN` field.
It's converting `val` to a 2D array [here](https://github.com/pydicom/pydicom/blob/master/pydicom/filewriter.py#L328) when `VM` is 1. 

**Code**
```
>>> from pydicom import dcmread, dcmwrite
>>> a = ["name1"]
>>> b = ["name1", "name2"]
>>> ds.PatientName = a
>>> dcmwrite("out.dcm", ds)     # throws the error below
>>> ds.PatientName = b
>>> dcmwrite("out.dcm", ds)     # works fine
```

**Error**
```
Traceback (most recent call last):
  File "/Users/neonbulb/virtualenv/deid/lib/python3.8/site-packages/pydicom/tag.py", line 28, in tag_in_exception
    yield
  File "/Users/neonbulb/virtualenv/deid/lib/python3.8/site-packages/pydicom/filewriter.py", line 662, in write_dataset
    write_data_element(fp, dataset.get_item(tag), dataset_encoding)
  File "/Users/neonbulb/virtualenv/deid/lib/python3.8/site-packages/pydicom/filewriter.py", line 562, in write_data_element
    fn(buffer, elem, encodings=encodings)  # type: ignore[operator]
  File "/Users/neonbulb/virtualenv/deid/lib/python3.8/site-packages/pydicom/filewriter.py", line 333, in write_PN
    enc = b'\\'.join([elem.encode(encodings) for elem in val])
  File "/Users/neonbulb/virtualenv/deid/lib/python3.8/site-packages/pydicom/filewriter.py", line 333, in <listcomp>
    enc = b'\\'.join([elem.encode(encodings) for elem in val])
AttributeError: 'MultiValue' object has no attribute 'encode'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/neonbulb/virtualenv/deid/lib/python3.8/site-packages/pydicom/filewriter.py", line 1153, in dcmwrite
    _write_dataset(fp, dataset, write_like_original)
  File "/Users/neonbulb/virtualenv/deid/lib/python3.8/site-packages/pydicom/filewriter.py", line 889, in _write_dataset
    write_dataset(fp, get_item(dataset, slice(0x00010000, None)))
  File "/Users/neonbulb/virtualenv/deid/lib/python3.8/site-packages/pydicom/filewriter.py", line 662, in write_dataset
    write_data_element(fp, dataset.get_item(tag), dataset_encoding)
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/contextlib.py", line 131, in __exit__
    self.gen.throw(type, value, traceback)
  File "/Users/neonbulb/virtualenv/deid/lib/python3.8/site-packages/pydicom/tag.py", line 32, in tag_in_exception
    raise type(exc)(msg) from exc
AttributeError: With tag (0010, 0010) got exception: 'MultiValue' object has no attribute 'encode'
Traceback (most recent call last):
  File "/Users/neonbulb/virtualenv/deid/lib/python3.8/site-packages/pydicom/tag.py", line 28, in tag_in_exception
    yield
  File "/Users/neonbulb/virtualenv/deid/lib/python3.8/site-packages/pydicom/filewriter.py", line 662, in write_dataset
    write_data_element(fp, dataset.get_item(tag), dataset_encoding)
  File "/Users/neonbulb/virtualenv/deid/lib/python3.8/site-packages/pydicom/filewriter.py", line 562, in write_data_element
    fn(buffer, elem, encodings=encodings)  # type: ignore[operator]
  File "/Users/neonbulb/virtualenv/deid/lib/python3.8/site-packages/pydicom/filewriter.py", line 333, in write_PN
    enc = b'\\'.join([elem.encode(encodings) for elem in val])
  File "/Users/neonbulb/virtualenv/deid/lib/python3.8/site-packages/pydicom/filewriter.py", line 333, in <listcomp>
    enc = b'\\'.join([elem.encode(encodings) for elem in val])
AttributeError: 'MultiValue' object has no attribute 'encode'
```

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/pydicom/pydicom/pull/1608?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom) Report
> Merging [#1608](https://codecov.io/gh/pydicom/pydicom/pull/1608?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom) (6347b8a) into [master](https://codecov.io/gh/pydicom/pydicom/commit/37dd49e2754a10db22e7cde2ac18aa8afc1f3af6?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom) (37dd49e) will **decrease** coverage by `9.42%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/pydicom/pydicom/pull/1608/graphs/tree.svg?width=650&height=150&src=pr&token=YciLV15Lwr&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom)](https://codecov.io/gh/pydicom/pydicom/pull/1608?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom)

```diff
@@            Coverage Diff             @@
##           master    #1608      +/-   ##
==========================================
- Coverage   97.56%   88.13%   -9.43%     
==========================================
  Files          66       66              
  Lines       10643    10412     -231     
==========================================
- Hits        10384     9177    -1207     
- Misses        259     1235     +976     
```


| [Impacted Files](https://codecov.io/gh/pydicom/pydicom/pull/1608?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom) | Coverage Δ | |
|---|---|---|
| [pydicom/dataelem.py](https://codecov.io/gh/pydicom/pydicom/pull/1608/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom#diff-cHlkaWNvbS9kYXRhZWxlbS5weQ==) | `98.07% <100.00%> (-0.32%)` | :arrow_down: |
| [pydicom/pixel\_data\_handlers/util.py](https://codecov.io/gh/pydicom/pydicom/pull/1608/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom#diff-cHlkaWNvbS9waXhlbF9kYXRhX2hhbmRsZXJzL3V0aWwucHk=) | `17.93% <0.00%> (-82.07%)` | :arrow_down: |
| [pydicom/waveforms/numpy\_handler.py](https://codecov.io/gh/pydicom/pydicom/pull/1608/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom#diff-cHlkaWNvbS93YXZlZm9ybXMvbnVtcHlfaGFuZGxlci5weQ==) | `20.31% <0.00%> (-79.69%)` | :arrow_down: |
| [pydicom/encoders/gdcm.py](https://codecov.io/gh/pydicom/pydicom/pull/1608/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom#diff-cHlkaWNvbS9lbmNvZGVycy9nZGNtLnB5) | `20.96% <0.00%> (-75.81%)` | :arrow_down: |
| [pydicom/pixel\_data\_handlers/numpy\_handler.py](https://codecov.io/gh/pydicom/pydicom/pull/1608/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom#diff-cHlkaWNvbS9waXhlbF9kYXRhX2hhbmRsZXJzL251bXB5X2hhbmRsZXIucHk=) | `27.14% <0.00%> (-72.86%)` | :arrow_down: |
| [pydicom/pixel\_data\_handlers/gdcm\_handler.py](https://codecov.io/gh/pydicom/pydicom/pull/1608/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom#diff-cHlkaWNvbS9waXhlbF9kYXRhX2hhbmRsZXJzL2dkY21faGFuZGxlci5weQ==) | `26.22% <0.00%> (-66.46%)` | :arrow_down: |
| [pydicom/overlays/numpy\_handler.py](https://codecov.io/gh/pydicom/pydicom/pull/1608/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom#diff-cHlkaWNvbS9vdmVybGF5cy9udW1weV9oYW5kbGVyLnB5) | `35.18% <0.00%> (-64.82%)` | :arrow_down: |
| [pydicom/pixel\_data\_handlers/pillow\_handler.py](https://codecov.io/gh/pydicom/pydicom/pull/1608/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom#diff-cHlkaWNvbS9waXhlbF9kYXRhX2hhbmRsZXJzL3BpbGxvd19oYW5kbGVyLnB5) | `31.73% <0.00%> (-64.43%)` | :arrow_down: |
| [pydicom/pixel\_data\_handlers/rle\_handler.py](https://codecov.io/gh/pydicom/pydicom/pull/1608/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom#diff-cHlkaWNvbS9waXhlbF9kYXRhX2hhbmRsZXJzL3JsZV9oYW5kbGVyLnB5) | `36.97% <0.00%> (-63.03%)` | :arrow_down: |
| [pydicom/pixel\_data\_handlers/pylibjpeg\_handler.py](https://codecov.io/gh/pydicom/pydicom/pull/1608/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom#diff-cHlkaWNvbS9waXhlbF9kYXRhX2hhbmRsZXJzL3B5bGlianBlZ19oYW5kbGVyLnB5) | `40.74% <0.00%> (-57.41%)` | :arrow_down: |
| ... and [16 more](https://codecov.io/gh/pydicom/pydicom/pull/1608/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pydicom/pydicom/pull/1608?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pydicom/pydicom/pull/1608?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom). Last update [37dd49e...6347b8a](https://codecov.io/gh/pydicom/pydicom/pull/1608?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom).


Patch:
diff --git a/doc/release_notes/v2.3.0.rst b/doc/release_notes/v2.3.0.rst
index 86c2c8342..0b3f7fee5 100644
--- a/doc/release_notes/v2.3.0.rst
+++ b/doc/release_notes/v2.3.0.rst
@@ -47,3 +47,6 @@ Fixes
 * Fixed bad DICOMDIR offsets when using :meth:`FileSet.write()
   <pydicom.fileset.FileSet.write>` with a *Directory Record Sequence* using
   undefined length items (:issue:`1596`)
+* Assigning a list of length one as tag value is now correctly handled as
+  assigning the single value (:issue:`1606`)
+
diff --git a/pydicom/dataelem.py b/pydicom/dataelem.py
index 2359df1a6..992972cc0 100644
--- a/pydicom/dataelem.py
+++ b/pydicom/dataelem.py
@@ -512,9 +512,10 @@ class DataElement:
             val.append
         except AttributeError:  # not a list
             return self._convert(val)
-        else:
-            return MultiValue(self._convert, val,
-                              validation_mode=self.validation_mode)
+        if len(val) == 1:
+            return self._convert(val[0])
+        return MultiValue(self._convert, val,
+                          validation_mode=self.validation_mode)
 
     def _convert(self, val: Any) -> Any:
         """Convert `val` to an appropriate type for the element's VR."""


Test patch:
diff --git a/pydicom/tests/test_json.py b/pydicom/tests/test_json.py
index 1ed32f382..0b2cbeff6 100644
--- a/pydicom/tests/test_json.py
+++ b/pydicom/tests/test_json.py
@@ -1,6 +1,7 @@
 # -*- coding: utf-8 -*-
 # Copyright 2008-2019 pydicom authors. See LICENSE file for details.
 import json
+from unittest import mock
 
 import pytest
 
@@ -271,13 +272,14 @@ class TestDataSetToJson:
         assert ds_json.index('"00100020"') < ds_json.index('"00100030"')
         assert ds_json.index('"00100030"') < ds_json.index('"00100040"')
 
-    def test_suppress_invalid_tags(self):
+    @mock.patch("pydicom.DataElement.to_json_dict", side_effect=ValueError)
+    def test_suppress_invalid_tags(self, _):
         """Test tags that raise exceptions don't if suppress_invalid_tags True.
         """
         ds = Dataset()
-        ds.add_new(0x00100010, 'PN', ['Jane^Doe'])
+        ds.add_new(0x00100010, 'PN', 'Jane^Doe')
 
-        with pytest.raises(Exception):
+        with pytest.raises(ValueError):
             ds.to_json_dict()
 
         ds_json = ds.to_json_dict(suppress_invalid_tags=True)
diff --git a/pydicom/tests/test_valuerep.py b/pydicom/tests/test_valuerep.py
index 01e33edd0..a6968e206 100644
--- a/pydicom/tests/test_valuerep.py
+++ b/pydicom/tests/test_valuerep.py
@@ -1540,20 +1540,27 @@ def test_set_value(vr, pytype, vm0, vmN, keyword, disable_value_validation):
         assert value == elem.value
 
     # Test VM = 1
+    if vr != 'SQ':
+        ds = Dataset()
+        value = vmN[0]
+        setattr(ds, keyword, value)
+        elem = ds[keyword]
+        assert elem.value == value
+        assert value == elem.value
+
+    # Test VM = 1 as list
     ds = Dataset()
     value = vmN[0]
+    setattr(ds, keyword, [value])
+    elem = ds[keyword]
     if vr == 'SQ':
-        setattr(ds, keyword, [value])
-        elem = ds[keyword]
         assert elem.value[0] == value
         assert value == elem.value[0]
     else:
-        setattr(ds, keyword, value)
-        elem = ds[keyword]
         assert elem.value == value
         assert value == elem.value
 
-    if vr[0] == 'O':
+    if vr[0] == 'O' or vr == 'UN':
         return
 
     # Test VM > 1