Repository: microsoft/electionguard-python

Issue:
🐞 Error Occurs Exporting Ballots if No Spoiled Ballots
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Current Behavior

If there are no spoiled ballots and you export an election record it will produce this error:

```
DEBUG:eel_log_service.py.debug:#L35: getting ballots for 62ff94aa397efaddb14ac8db
Traceback (most recent call last):
  File "C:\dev\ElectionGuard\electionguard-python\.venv\lib\site-packages\eel\__init__.py", line 281, in _process_message
    return_val = _exposed_functions[message['name']](*message['args'])
  File "C:\dev\ElectionGuard\electionguard-python\src\electionguard_gui\components\export_election_record_component.py", line 64, in export_election_record
    spoiled_ballots = decryption.get_plaintext_spoiled_ballots()
  File "C:\dev\ElectionGuard\electionguard-python\src\electionguard_gui\models\decryption_dto.py", line 136, in get_plaintext_spoiled_ballots
    raise ValueError("No plaintext spoiled ballots found")
ValueError: No plaintext spoiled ballots found
```

### Expected Behavior

_No response_

### Steps To Reproduce

_No response_

### Environment

```markdown
- OS:
```


### Anything else?

_No response_

Comments:

Patch:
diff --git a/src/electionguard_gui/models/decryption_dto.py b/src/electionguard_gui/models/decryption_dto.py
index 9326cf7..2d12795 100644
--- a/src/electionguard_gui/models/decryption_dto.py
+++ b/src/electionguard_gui/models/decryption_dto.py
@@ -49,7 +49,7 @@ class DecryptionDto:
     can_join: Optional[bool]
     decryption_shares: list[Any]
     plaintext_tally: Optional[str]
-    plaintext_spoiled_ballots: Optional[dict[str, str]]
+    plaintext_spoiled_ballots: dict[str, str]
     lagrange_coefficients: Optional[str]
     ciphertext_tally: Optional[str]
     completed_at_utc: Optional[datetime]
@@ -69,7 +69,9 @@ class DecryptionDto:
         self.guardians_joined = _get_list(decryption, "guardians_joined")
         self.decryption_shares = _get_list(decryption, "decryption_shares")
         self.plaintext_tally = decryption.get("plaintext_tally")
-        self.plaintext_spoiled_ballots = decryption.get("plaintext_spoiled_ballots")
+        self.plaintext_spoiled_ballots = _get_dict(
+            decryption, "plaintext_spoiled_ballots"
+        )
         self.lagrange_coefficients = decryption.get("lagrange_coefficients")
         self.ciphertext_tally = decryption.get("ciphertext_tally")
         self.completed_at_utc = decryption.get("completed_at")
@@ -132,8 +134,6 @@ class DecryptionDto:
         return from_raw(PlaintextTally, self.plaintext_tally)
 
     def get_plaintext_spoiled_ballots(self) -> list[PlaintextTally]:
-        if not self.plaintext_spoiled_ballots:
-            raise ValueError("No plaintext spoiled ballots found")
         return [
             from_raw(PlaintextTally, tally)
             for tally in self.plaintext_spoiled_ballots.values()
@@ -157,6 +157,13 @@ def _get_list(decryption: dict[str, Any], name: str) -> list:
     return []
 
 
+def _get_dict(decryption: dict[str, Any], name: str) -> dict:
+    value = decryption.get(name)
+    if value:
+        return dict(value)
+    return {}
+
+
 def _get_int(decryption: dict[str, Any], name: str, default: int) -> int:
     value = decryption.get(name)
     if value:


Test patch:
diff --git a/tests/unit/electionguard_gui/test_decryption_dto.py b/tests/unit/electionguard_gui/test_decryption_dto.py
index 6ff8786..190fb11 100644
--- a/tests/unit/electionguard_gui/test_decryption_dto.py
+++ b/tests/unit/electionguard_gui/test_decryption_dto.py
@@ -9,6 +9,16 @@ from tests.base_test_case import BaseTestCase
 class TestDecryptionDto(BaseTestCase):
     """Test the DecryptionDto class"""
 
+    def test_no_spoiled_ballots(self) -> None:
+        # ARRANGE
+        decryption_dto = DecryptionDto({})
+
+        # ACT
+        spoiled_ballots = decryption_dto.get_plaintext_spoiled_ballots()
+
+        # ASSERT
+        self.assertEqual(0, len(spoiled_ballots))
+
     def test_get_status_with_no_guardians(self) -> None:
         # ARRANGE
         decryption_dto = DecryptionDto(