Repository: omnivector-solutions/jobbergate (language: python)

Issue:
fix(api): make empty string on `execution_directory` be None
#### What
Turn `execution_directory` into `None` when an empty string is provided as value.

#### Why
It was causing problems downstream since:
```python
>>> from pathlib import Path
>>> Path("")
PosixPath('.')
```

With that, the default value was not applied on the Agent side.

---

#### Peer Review
Please follow the upstream omnivector documentation concerning
[peer-review guidelines](https://github.com/omnivector-solutions/Documentation/blob/main/Contributing/pr_review_standards.md#peer-review).



Discussion / hints:

Fix patch:
diff --git a/jobbergate-api/CHANGELOG.md b/jobbergate-api/CHANGELOG.md
index 6e4fc36e..8b1ef75b 100644
--- a/jobbergate-api/CHANGELOG.md
+++ b/jobbergate-api/CHANGELOG.md
@@ -4,6 +4,8 @@ This file keeps track of all notable changes to jobbergate-api
 
 ## Unreleased
 
+- Fixed a bug when an empty string is passed as a value for `execution_directory` on job submissions
+
 ## 4.4.0 -- 2024-03-19
 
 - Removed SQL savepoints for auto-sessions
diff --git a/jobbergate-api/jobbergate_api/apps/job_submissions/schemas.py b/jobbergate-api/jobbergate_api/apps/job_submissions/schemas.py
index ffbc573d..f7429785 100644
--- a/jobbergate-api/jobbergate_api/apps/job_submissions/schemas.py
+++ b/jobbergate-api/jobbergate_api/apps/job_submissions/schemas.py
@@ -1,8 +1,8 @@
 """
 JobSubmission resource schema.
 """
+
 import re
-from pathlib import Path
 from typing import Dict, List, Literal, Optional
 
 from pydantic import BaseModel, Extra, Field, NonNegativeInt, validator
@@ -363,6 +363,11 @@ class JobSubmissionCreateRequest(BaseModel):
     client_id: Optional[LengthLimitedStr]
     execution_parameters: JobProperties = Field(default_factory=JobProperties)
 
+    @validator("execution_directory", pre=True, always=True)
+    def empty_str_to_none(cls, v):
+        """Ensure empty strings are converted to None to avoid problems with Path downstream."""
+        return v or None
+
     class Config:
         schema_extra = job_submission_meta_mapper
 
@@ -377,6 +382,11 @@ class JobSubmissionUpdateRequest(BaseModel):
     execution_directory: Optional[LengthLimitedStr]
     status: Optional[JobSubmissionStatus]
 
+    @validator("execution_directory", pre=True, always=True)
+    def empty_str_to_none(cls, v):
+        """Ensure empty strings are converted to None to avoid problems with Path downstream."""
+        return v or None
+
     class Config:
         schema_extra = job_submission_meta_mapper
 
@@ -403,7 +413,7 @@ class JobSubmissionDetailedView(JobSubmissionListView):
     Complete model to match the database for the JobSubmission resource.
     """
 
-    execution_directory: Optional[Path]
+    execution_directory: Optional[str]
     report_message: Optional[str]
     execution_parameters: Optional[JobProperties]
     slurm_job_info: Optional[str]
@@ -419,7 +429,7 @@ class PendingJobSubmission(BaseModel):
     id: int
     name: str
     owner_email: str
-    execution_directory: Optional[Path]
+    execution_directory: Optional[str]
     execution_parameters: dict = Field(default_factory=dict)
     job_script: JobScriptDetailedView
 


Test patch:
diff --git a/jobbergate-api/tests/apps/job_submissions/test_schemas.py b/jobbergate-api/tests/apps/job_submissions/test_schemas.py
new file mode 100644
index 00000000..95569bbb
--- /dev/null
+++ b/jobbergate-api/tests/apps/job_submissions/test_schemas.py
@@ -0,0 +1,23 @@
+import pytest
+from jobbergate_api.apps.job_submissions.schemas import JobSubmissionCreateRequest, JobSubmissionUpdateRequest
+
+
+@pytest.mark.parametrize(
+    "schema",
+    [
+        JobSubmissionCreateRequest(name="test", job_script_id=1, execution_directory=""),
+        JobSubmissionUpdateRequest(execution_directory=""),
+    ],
+)
+def test_empty_string_to_none(schema):
+    """
+    Assert that an empty string on execution_directory is converted to None.
+
+    It was causing problems downstream since:
+    >>> from pathlib import Path
+    >>> Path("")
+    PosixPath('.')
+
+    With that, the default value was not applied on the Agent side.
+    """
+    assert schema.execution_directory is None