potiuk commented on code in PR #74943:
URL: https://github.com/apache/airflow/pull/74943#discussion_r4394880406


##########
task-sdk/src/airflow/sdk/io/path.py:
##########
@@ -463,7 +463,7 @@ def move(self, path: str | ObjectStoragePath, recursive: 
bool = False, **kwargs)
 
         # non-local copy
         self.copy(path, recursive=recursive, **kwargs)
-        self.unlink()
+        self.fs.rm(self.path, recursive=recursive)

Review Comment:
   This changes `move` from "fails on a directory" to "recursively deletes the 
source" whenever `samestore()` is False. `samestore()` only compares protocol 
and `conn_id`, so two connections to the same bucket count as different stores. 
For example:
   
   ```python
   
ObjectStoragePath("s3://conn_a@bucket/data").move("s3://conn_b@bucket/data/archive",
 recursive=True)
   ```
   
   This copies into `data/archive/...` and then `rm("bucket/data", 
recursive=True)` deletes the new copy too. The same happens when both paths 
resolve to the same key. Before this change, `unlink()` raised and nothing was 
lost. Could we refuse a destination that is the source or inside it, comparing 
bucket and key, before deleting? A test for that case would help too.
   
   ---
   Drafted-by: Claude Code (Opus 5.5); reviewed by @potiuk before posting



##########
task-sdk/tests/task_sdk/io/test_path.py:
##########
@@ -349,6 +363,19 @@ def test_bucket_key_protocol(self):
         assert o.key == key
         assert o.protocol == protocol
 
+    @mock.patch.object(_FakeRemoteFileSystem, "mkdir", autospec=True)
+    def test_copy_dir_to_new_remote_dir(self, mock_mkdir, fake_remote_stores):
+        bucket = uuid.uuid4().hex
+        src = ObjectStoragePath(f"ffs://{bucket}/src")

Review Comment:
   The source key here has no prefix, so the test can't tell `dst / 
src_obj.key` (full key) apart from `dst / relative_path`. Could you add a case 
with a nested source such as `ffs://{bucket}/x/src`, asserting the documented 
layout (`dst/x/src/a.txt`)? That pins down the "same key as the source" 
behaviour described in the `copy()` docstring.
   
   ---
   Drafted-by: Claude Code (Opus 5.5); reviewed by @potiuk before posting



##########
task-sdk/src/airflow/sdk/io/path.py:
##########
@@ -463,7 +463,7 @@ def move(self, path: str | ObjectStoragePath, recursive: 
bool = False, **kwargs)
 
         # non-local copy
         self.copy(path, recursive=recursive, **kwargs)

Review Comment:
   When the source is a remote directory and `recursive=False`, the 
remote-to-remote branch of `copy()` ignores `recursive` and copies the whole 
tree. Then `fs.rm(self.path, recursive=False)` either raises or does nothing, 
so the caller ends up with a duplicated tree and the source still in place. 
Should `move` raise up front when the source is a directory and `recursive` is 
False?
   
   ---
   Drafted-by: Claude Code (Opus 5.5); reviewed by @potiuk before posting



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to