Repository: newAM/monitorcontrol

Issue:
ValueError: 33 is not a valid InputSource
* Monitor manufacturer and model number: MSI Optix MAG342CQRV
* Input source (HDMI, VGA, display port, ect.): HDMI1
* Output device (video card, discrete graphics, ect.): 6800XT
* Operating system: Windows 10 21H1 19043.1466
* Python version: 3.9.9
* monitorcontrol version (`monitorcontrol --version`): 2.5.1

# Steps to Reproduce
```python
import monitorcontrol as mc
monitors = mc.get_monitors()
for monitor in monitors:
	with monitor:
		c = monitor.get_vcp_capabilities()
```
This code crashes with `ValueError: 33 is not a valid InputSource` and I don't get any return from that function.

For more information, on the problematic monitor, `monitor.vcp.get_vcp_capabilities()` returns
```
(prot(monitor)type(lcd)model(MAG342CQRV)cmds(01 02 03 07 0C E3 F3)vcp(02 04 05 08 0B 0C 10 12 14(04 05 08 0B) 16 18 1A 60(00 11 12 0F 21 22 2F 31) CC(02 03 04 05 07 08 09 0A 0C 0D 01 06 0B 0E 12 14 16 17 1A 1E 24) D6(01 04 05) DF FF)mswhql(1)asset_eep(40)mccs_ver(2.2))
```
And indeed in the input source section there is OFF,HDMI1,HDMI2,DP1 (as expected), then there is 21,22,2F,31 and these are not in the enum (and at least the first one crashes).

Are these not standard values?

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7858c84..4992caa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@ as of version 2.1.1.
 
 ### Changed
 - Updated pyudev from 0.22 to 0.23.
+- Changed `get_vcp_capabilities()["inputs"]` from `List[str]` to `Union[InputSource, int]`.
 
 ### Removed
 - Removed support for python 3.6 and 3.7.
diff --git a/monitorcontrol/monitorcontrol.py b/monitorcontrol/monitorcontrol.py
index 71c0630..ae76baa 100644
--- a/monitorcontrol/monitorcontrol.py
+++ b/monitorcontrol/monitorcontrol.py
@@ -190,7 +190,13 @@ class Monitor:
                             2: [],
                             96: [15, 17, 18],
                     },
-                    "inputs": ["DP1", "HDMI1", "HDMI2"],
+                    "inputs": [
+                        InputSource.DP1,
+                        InputSource.HDMI1,
+                        InputSource.HDMI2
+                        # this may return integers for out-of-spec values,
+                        # such as USB Type-C monitors
+                    ],
                 }
         """
         assert (
@@ -596,6 +602,11 @@ def _parse_capabilities(caps_str: str) -> dict:
         input_val_list.sort()
 
         for val in input_val_list:
-            caps_dict["inputs"].append(InputSource(val).name)
+            try:
+                input_source = InputSource(val)
+            except ValueError:
+                input_source = val
+
+            caps_dict["inputs"].append(input_source)
 
     return caps_dict


Test patch:
diff --git a/tests/test_monitorcontrol.py b/tests/test_monitorcontrol.py
index 10d369d..e65438a 100644
--- a/tests/test_monitorcontrol.py
+++ b/tests/test_monitorcontrol.py
@@ -34,9 +34,10 @@ class UnitTestVCP(vcp.VCP):
         return (
             "(prot(monitor)type(LCD)model(ACER VG271U)cmds(01 02 03 07 0C"
             " E3 F3)vcp(04 10 12 14(05 06 08 0B) 16 18 1A 59 5A 5B 5C 5D"
-            " 5E 60(0F 11 12)62 9B 9C 9D 9E 9F A0 D6 E0(00 04 05 06) E1(00"
-            " 01 02)E2(00 01 02 03 05 06 07 0B 10 11 12)E3 E4 E5 E7(00 01"
-            " 02) E8(00 01 02 03 04)) mswhql(1)asset_eep(40)mccs_ver(2.2))"
+            " 5E 60(00 0F 11 12 24)62 9B 9C 9D 9E 9F A0 D6 E0(00 04 05 06)"
+            "E1(00 01 02)E2(00 01 02 03 05 06 07 0B 10 11 12)E3 E4 E5"
+            " E7(00 01 02) E8(00 01 02 03 04))"
+            " mswhql(1)asset_eep(40)mccs_ver(2.2))"
         )
 
     def __enter__(self):
@@ -171,7 +172,7 @@ def test_power_mode(
             monitor.set_power_mode(mode)
 
 
-# ASUS VG27A when set to a mode that doesnt exist returnd analog1 (0x1)
+# ASUS VG27A when set to a mode that doesnt exist returned analog1 (0x1)
 @pytest.mark.skipif(
     USE_ATTACHED_MONITORS, reason="Real monitors dont support all input types"
 )
@@ -239,11 +240,14 @@ def test_get_vcp_capabilities(monitor: Monitor):
     monitors_dict = monitor.get_vcp_capabilities()
     model = monitors_dict["model"]
     inputs = monitors_dict["inputs"]
-    print(inputs)
-    if model != "ACER VG271U":
-        raise AssertionError("Could not parse model")
-    if set(inputs) != {"DP1", "HDMI1", "HDMI2"}:
-        raise AssertionError("Could not parse input sources")
+    assert model == "ACER VG271U"
+    assert inputs == [
+        InputSource.OFF,
+        InputSource.DP1,
+        InputSource.HDMI1,
+        InputSource.HDMI2,
+        36,
+    ]
 
 
 def test_convert_to_dict():