Repository: pydicom/pydicom

Issue:
Add VR type check when element values are being set
We should add a VR type check on setting element values to ensure they're valid. This should help users when an invalid value is used and with maintenance as it will make it easier to reason what types should be expected.


Discussion:
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/pydicom/pydicom/pull/2094?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 98.33%. Comparing base [(`884aed6`)](https://app.codecov.io/gh/pydicom/pydicom/commit/884aed6ba277123f25f46e240c0613ddf4f25e20?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom) to head [(`3ce8200`)](https://app.codecov.io/gh/pydicom/pydicom/commit/3ce82009e6969463bdca3a8509e5bdd14b0025ca?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom).
> Report is 2 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main    #2094   +/-   ##
=======================================
  Coverage   98.33%   98.33%           
=======================================
  Files          76       76           
  Lines       13100    13103    +3     
=======================================
+ Hits        12882    12885    +3     
  Misses        218      218           
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/pydicom/pydicom/pull/2094?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pydicom).

scaramallion: Too fast @mrbean-bremen! I think I need more types than `bytes` (definitely `bytearray`, maybe `memoryview`?)
scaramallion: OK done, although I only ended up adding `bytearray`
mrbean-bremen: > OK done, although I only ended up adding bytearray

I think that's sufficient. `memoryview` can always be added later if really needed.

Patch:
diff --git a/doc/release_notes/v3.0.0.rst b/doc/release_notes/v3.0.0.rst
index 2c315b058..08632c594 100644
--- a/doc/release_notes/v3.0.0.rst
+++ b/doc/release_notes/v3.0.0.rst
@@ -234,6 +234,8 @@ Enhancements
   prior to conversion to a :class:`~pydicom.dataelem.DataElement` (:issue:`1739`).
 * Added support for using :class:`io.BufferedIOBase` subclasses to set the value for
   elements with O* VRs such as **OB** and **OW** (:issue:`1913`).
+* Added elements with **OB**,  **OD**, **OF**, **OL**, **OW**, **OV** VRs to the type
+  validation checking when setting :class:`~pydicom.dataelem.DataElement` values (:issue:`1414`).
 
 
 Fixes
diff --git a/src/pydicom/valuerep.py b/src/pydicom/valuerep.py
index f5b8385c5..e74785e22 100644
--- a/src/pydicom/valuerep.py
+++ b/src/pydicom/valuerep.py
@@ -377,6 +377,12 @@ VALIDATORS = {
     "IS": validate_length_and_type_and_regex,
     "LO": validate_type_and_length,
     "LT": validate_type_and_length,
+    "OB": lambda vr, value: validate_type(vr, value, (bytes, bytearray)),
+    "OD": lambda vr, value: validate_type(vr, value, (bytes, bytearray)),
+    "OF": lambda vr, value: validate_type(vr, value, (bytes, bytearray)),
+    "OL": lambda vr, value: validate_type(vr, value, (bytes, bytearray)),
+    "OW": lambda vr, value: validate_type(vr, value, (bytes, bytearray)),
+    "OV": lambda vr, value: validate_type(vr, value, (bytes, bytearray)),
     "PN": validate_pn,
     "SH": validate_type_and_length,
     "SL": lambda vr, value: validate_number(vr, value, -0x80000000, 0x7FFFFFFF),


Test patch:
diff --git a/tests/test_dataelem.py b/tests/test_dataelem.py
index a4cccd70c..004c0ae35 100644
--- a/tests/test_dataelem.py
+++ b/tests/test_dataelem.py
@@ -1262,6 +1262,25 @@ class TestDataElementValidation:
 
         assert ds.PixelData == b"\x00\x01"
 
+    @pytest.mark.parametrize("value", (None, b"", b"\x00", b"\x00\x01\x02\x03"))
+    def test_valid_o_star_bytes(self, value):
+        for vr in ("OB", "OD", "OF", "OL", "OW", "OV"):
+            DataElement(0x00410001, "vr", value, validation_mode=config.RAISE)
+
+    @pytest.mark.parametrize("value", (bytearray(), bytearray(b"\x00\x01\x02\x03")))
+    def test_valid_o_star_bytearray(self, value):
+        for vr in ("OB", "OD", "OF", "OL", "OW", "OV"):
+            DataElement(0x00410001, "vr", value, validation_mode=config.RAISE)
+
+    @pytest.mark.parametrize("value", (-2, 4294967300))
+    def test_invalid_o_star_value(self, value):
+        for vr in ("OB", "OD", "OF", "OL", "OW", "OV"):
+            msg = f"A value of type 'int' cannot be assigned to a tag with VR {vr}"
+            with pytest.warns(UserWarning, match=msg):
+                DataElement(0x00410001, vr, value, validation_mode=config.WARN)
+            with pytest.raises(ValueError, match=msg):
+                DataElement(0x00410001, vr, value, validation_mode=config.RAISE)
+
 
 class TestBufferedDataElement:
     """Tests setting a DataElement value to a buffer"""