|  | 
| 14 | 14 | # KIND, either express or implied.  See the License for the | 
| 15 | 15 | # specific language governing permissions and limitations | 
| 16 | 16 | # under the License. | 
|  | 17 | +import json | 
|  | 18 | + | 
| 17 | 19 | from pyiceberg.catalog.rest.expression import ( | 
| 18 | 20 |     AndOrExpression, | 
| 19 | 21 |     Expression, | 
| 20 | 22 |     LiteralExpression, | 
| 21 | 23 |     Term, | 
| 22 | 24 | ) | 
| 23 | 25 | from pyiceberg.catalog.rest.planning_models import ( | 
|  | 26 | +    AsyncPlanningResult, | 
|  | 27 | +    CancelledPlanningResult, | 
|  | 28 | +    CompletedPlanningWithIDResult, | 
| 24 | 29 |     DataFile, | 
| 25 | 30 |     DeleteFile, | 
| 26 | 31 |     EqualityDeleteFile, | 
|  | 32 | +    FailedPlanningResult, | 
| 27 | 33 |     FileScanTask, | 
| 28 | 34 |     PlanTableScanRequest, | 
|  | 35 | +    PlanTableScanResult, | 
| 29 | 36 |     PositionDeleteFile, | 
| 30 | 37 |     ScanTasks, | 
| 31 | 38 | ) | 
|  | 39 | +from pyiceberg.catalog.rest.response import ErrorResponseMessage | 
| 32 | 40 | 
 | 
| 33 | 41 | 
 | 
| 34 | 42 | def test_serialize_plan_table_scan_request() -> None: | 
| @@ -165,3 +173,118 @@ def snapshot_json_for_plan_table_scan_request() -> str: | 
| 165 | 173 | 
 | 
| 166 | 174 | def snapshot_json_for_scan_tasks() -> str: | 
| 167 | 175 |     return """{"delete-files":[{"content":"position-deletes","file-path":"/path/to/delete-a.parquet","file-format":"parquet","spec-id":0,"partition":[],"file-size-in-bytes":256,"record-count":10},{"content":"equality-deletes","file-path":"/path/to/delete-b.parquet","file-format":"parquet","spec-id":0,"partition":[],"file-size-in-bytes":256,"record-count":10,"equality-ids":[1,2]}],"file-scan-tasks":[{"data-file":{"content":"data","file-path":"/path/to/data-a.parquet","file-format":"parquet","spec-id":0,"partition":[],"file-size-in-bytes":1024,"record-count":56},"delete-file-references":[0,1]}]}""" | 
|  | 176 | + | 
|  | 177 | + | 
|  | 178 | +def test_deserialize_async_planning_result() -> None: | 
|  | 179 | +    """Test deserializing a dict to an AsyncPlanningResult""" | 
|  | 180 | +    result = PlanTableScanResult.model_validate_json(snapshot_json_for_async_planning_result()) | 
|  | 181 | +    expected = AsyncPlanningResult(status="submitted", plan_id="plan-123") | 
|  | 182 | +    # Assert that deserialized dict == Python object | 
|  | 183 | +    assert result.root == expected | 
|  | 184 | + | 
|  | 185 | + | 
|  | 186 | +def test_serialize_async_planning_result() -> None: | 
|  | 187 | +    """Test serializing an AsyncPlanningResult to a dict""" | 
|  | 188 | +    result = PlanTableScanResult(root=AsyncPlanningResult(status="submitted", plan_id="plan-123")) | 
|  | 189 | +    # Assert that JSON matches | 
|  | 190 | +    assert json.loads(result.model_dump_json(by_alias=True)) == json.loads(snapshot_json_for_async_planning_result()) | 
|  | 191 | + | 
|  | 192 | + | 
|  | 193 | +def snapshot_json_for_async_planning_result() -> str: | 
|  | 194 | +    return """{"status":"submitted","plan-id":"plan-123"}""" | 
|  | 195 | + | 
|  | 196 | + | 
|  | 197 | +def test_deserialize_failed_planning_result() -> None: | 
|  | 198 | +    """Test deserializing a dict to a FailedPlanningResult""" | 
|  | 199 | +    result = PlanTableScanResult.model_validate_json(snapshot_json_for_failed_planning_result()) | 
|  | 200 | +    expected = FailedPlanningResult( | 
|  | 201 | +        status="failed", | 
|  | 202 | +        error=ErrorResponseMessage( | 
|  | 203 | +            message="The plan is invalid", | 
|  | 204 | +            type="NoSuchPlanException", | 
|  | 205 | +            code=404, | 
|  | 206 | +        ), | 
|  | 207 | +    ) | 
|  | 208 | +    # Assert that deserialized dict == Python object | 
|  | 209 | +    assert result.root == expected | 
|  | 210 | + | 
|  | 211 | + | 
|  | 212 | +def test_serialize_failed_planning_result() -> None: | 
|  | 213 | +    """Test serializing a FailedPlanningResult to a dict""" | 
|  | 214 | +    result = PlanTableScanResult( | 
|  | 215 | +        root=FailedPlanningResult( | 
|  | 216 | +            status="failed", | 
|  | 217 | +            error=ErrorResponseMessage( | 
|  | 218 | +                message="The plan is invalid", | 
|  | 219 | +                type="NoSuchPlanException", | 
|  | 220 | +                code=404, | 
|  | 221 | +            ), | 
|  | 222 | +        ) | 
|  | 223 | +    ) | 
|  | 224 | +    # Assert that JSON matches | 
|  | 225 | +    assert json.loads(result.model_dump_json(by_alias=True, exclude_none=True)) == json.loads( | 
|  | 226 | +        snapshot_json_for_failed_planning_result() | 
|  | 227 | +    ) | 
|  | 228 | + | 
|  | 229 | + | 
|  | 230 | +def snapshot_json_for_failed_planning_result() -> str: | 
|  | 231 | +    return """{"status":"failed","error":{"message":"The plan is invalid","type":"NoSuchPlanException","code":404}}""" | 
|  | 232 | + | 
|  | 233 | + | 
|  | 234 | +def test_deserialize_cancelled_planning_result() -> None: | 
|  | 235 | +    """Test deserializing a dict to an CancelledPlanningResult""" | 
|  | 236 | +    result = PlanTableScanResult.model_validate_json(snapshot_json_for_cancelled_planning_result()) | 
|  | 237 | +    expected = CancelledPlanningResult(status="cancelled") | 
|  | 238 | +    # Assert that deserialized dict == Python object | 
|  | 239 | +    assert result.root == expected | 
|  | 240 | + | 
|  | 241 | + | 
|  | 242 | +def test_serialize_cancelled_planning_result() -> None: | 
|  | 243 | +    """Test serializing an CancelledPlanningResult to a dict""" | 
|  | 244 | +    result = PlanTableScanResult(root=CancelledPlanningResult(status="cancelled")) | 
|  | 245 | +    # Assert that JSON matches | 
|  | 246 | +    assert json.loads(result.model_dump_json(by_alias=True)) == json.loads(snapshot_json_for_cancelled_planning_result()) | 
|  | 247 | + | 
|  | 248 | + | 
|  | 249 | +def snapshot_json_for_cancelled_planning_result() -> str: | 
|  | 250 | +    return """{"status":"cancelled"}""" | 
|  | 251 | + | 
|  | 252 | + | 
|  | 253 | +def test_deserialize_completed_planning_with_id_result() -> None: | 
|  | 254 | +    """Test deserializing a dict to a CompletedPlanningWithIDResult""" | 
|  | 255 | +    scan_tasks_dict = json.loads(snapshot_json_for_scan_tasks()) | 
|  | 256 | +    scan_tasks_dict["status"] = "completed" | 
|  | 257 | +    scan_tasks_dict["plan-id"] = "plan-456" | 
|  | 258 | +    json_str = json.dumps(scan_tasks_dict) | 
|  | 259 | + | 
|  | 260 | +    result = PlanTableScanResult.model_validate_json(json_str) | 
|  | 261 | +    expected_scan_tasks = ScanTasks.model_validate_json(snapshot_json_for_scan_tasks()) | 
|  | 262 | + | 
|  | 263 | +    expected = CompletedPlanningWithIDResult( | 
|  | 264 | +        status="completed", | 
|  | 265 | +        plan_id="plan-456", | 
|  | 266 | +        file_scan_tasks=expected_scan_tasks.file_scan_tasks, | 
|  | 267 | +        delete_files=expected_scan_tasks.delete_files, | 
|  | 268 | +    ) | 
|  | 269 | +    # Assert that deserialized dict == Python object | 
|  | 270 | +    assert result.root == expected | 
|  | 271 | + | 
|  | 272 | + | 
|  | 273 | +def test_serialize_completed_planning_with_id_result() -> None: | 
|  | 274 | +    """Test serializing a CompletedPlanningWithIDResult to a dict""" | 
|  | 275 | +    expected_scan_tasks = ScanTasks.model_validate_json(snapshot_json_for_scan_tasks()) | 
|  | 276 | +    result = PlanTableScanResult( | 
|  | 277 | +        root=CompletedPlanningWithIDResult( | 
|  | 278 | +            status="completed", | 
|  | 279 | +            plan_id="plan-456", | 
|  | 280 | +            file_scan_tasks=expected_scan_tasks.file_scan_tasks, | 
|  | 281 | +            delete_files=expected_scan_tasks.delete_files, | 
|  | 282 | +        ) | 
|  | 283 | +    ) | 
|  | 284 | + | 
|  | 285 | +    scan_tasks_dict = json.loads(snapshot_json_for_scan_tasks()) | 
|  | 286 | +    scan_tasks_dict["status"] = "completed" | 
|  | 287 | +    scan_tasks_dict["plan-id"] = "plan-456" | 
|  | 288 | + | 
|  | 289 | +    # Assert that JSON matches | 
|  | 290 | +    assert json.loads(result.model_dump_json(exclude_none=True, by_alias=True)) == scan_tasks_dict | 
0 commit comments