Repository navigation
Document that copies of a delete-marker source version raise OSError(EINVAL) (GH-1346) #1348
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
5addecd
247bf10
d3ae3a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -399,8 +399,10 @@ operation sends one request (one per page for the iterators and | |
| described below, send several, and `generate_presigned_url()` signs a URL locally | ||
| without a request. The requests are sent with the retry policy. An operation raises | ||
| `FileNotFoundError` for a missing bucket or multipart upload, or for a missing object or | ||
| version that it reads, and caches nothing. Requests sent through `fs.core` do not | ||
| invalidate the filesystem's cache: call | ||
| version that it reads, and caches nothing. `copy_object()` and `upload_part_copy()` with | ||
| a source version that is a delete marker raise `OSError` with `EINVAL`, while the | ||
| filesystem's `cp_file()` raises `FileNotFoundError` for it, as for a missing file. | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Self-review round one (behavior of the documented paths, simplicity), base Finding 1 (docs/filesystem.md:403 at 247bf10). The paragraph said that
Repair: only |
||
| Requests sent through `fs.core` do not invalidate the filesystem's cache: call | ||
| `fs.invalidate_cache()` after a change, or make it through the filesystem. | ||
|
|
||
| ```python | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -501,7 +501,9 @@ class S3Core: | |
| :class:`~pyathena.filesystem.s3_errors.S3ClientError`): a missing bucket | ||
| or multipart upload, or a missing object or version that an operation | ||
| reads, raises ``FileNotFoundError``, and a denied request | ||
| ``PermissionError``. | ||
| ``PermissionError``. :meth:`copy_object` and :meth:`upload_part_copy` | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Round one, finding 2 (my pass, at 5addecd). The class docstring said "a copy whose source names a delete-marker version" raises Not taken: removing the sentence and relying on the method Raises sections ( |
||
| with a source version that is a delete marker raise ``OSError`` with | ||
| ``EINVAL``. | ||
| As in S3, deleting a missing key is not an error. Nothing is cached. | ||
|
|
||
| Example: | ||
|
|
@@ -1019,6 +1021,10 @@ def upload_part_copy( | |
| Raises: | ||
| ValueError: If the upload has no bucket, key, or upload ID, or the | ||
| source has no key. | ||
| FileNotFoundError: If the upload, or the source object or version, | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Round one, finding 3. |
||
| does not exist. | ||
| OSError: With ``EINVAL`` for an invalid request, such as a source | ||
| version that is a delete marker. | ||
| """ | ||
| request = self._multipart_upload_request(upload) | ||
| if not source.key: | ||
|
|
@@ -1176,6 +1182,10 @@ def copy_object(self, source: S3Path, destination: S3Path, **params) -> None: | |
| Raises: | ||
| ValueError: If the source or the destination has no key, or the | ||
| destination has a version ID, which a write cannot replace. | ||
| FileNotFoundError: If a bucket, or the source object or version, | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Round one, finding 4 (
Repair: "If a bucket, or the source object or version, does not exist", and "With Deferred or rejected:
|
||
| does not exist. | ||
| OSError: With ``EINVAL`` for an invalid request, such as a source | ||
| version that is a delete marker. | ||
| """ | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Independent review (relayed result), static only.
Result: CLEAN. No findings were introduced, and no pre-existing actionable issue was found in the reviewed context. The reviewer reports that:
The snapshot and the PR worktree were unchanged after the review. |
||
| if not source.key: | ||
| raise ValueError(f"The source has no key: {source.uri}.") | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Self-review round two (claims, documentation reader, existing callers, evidence), base
1a6a0d6c3f137d47bbe96e274ecd467e016fcb38, headd3ae3a9ce8b101673332a7af18bc68d49af5ea98. Result: FINDINGS (PR description wording), corrected. No change to tracked files.Claims checked:
InvalidRequestwithout the header. Measured live on 10/27 (temporary versioned bucket, deleted afterwards), andS3Core.copy_object()raisedOSError [Errno 22]at 1a6a0d6.FileNotFoundErrorfor a missing bucket, upload, source object or source version. Measured for both operations: removed source version404 NoSuchVersion, missing source key404 NoSuchKey. The missing upload and bucket follow the existingNoSuchUpload/NoSuchBucketmappings (s3_errors.py).EINVALfor an invalid request, such as a delete-marker source. A generic 400 maps toEINVAL(_HTTP_STATUS_CODE_TO_ERRNO, pinned bytest_os_error_by_http_status_code[400]). A malformed version ID gives the same (measured CopyObjectInvalidRequest), which is why the entry no longer reads as identifying a delete marker.cp_file()raisesFileNotFoundErrorfor it. Measured live (sync). The aio_copy_filecalls_info()first (s3_async.py:576); read in the code only.copy()/mv()are not named (PR body). The first wording attributed both to fsspec.mv()is PyAthena's own (s3.py:1356), and theexpand_path()drop applies only withrecursive=True(s3.py:934). Corrected. I checked offline with a scriptedS3Core: one delete-marker source raisesFileNotFoundErrorfromcopy/mvwith and withoutrecursive. With several sources it is dropped silently.uv run sphinx-build docs <tmp>at d3ae3a9: 173 warnings, the same asorigin/master.just docs buildbuilds committed refs only.just docs lint: 0 errors.Documentation reader: the error-translation table (
docs/filesystem.md:239-251) and theS3ClientErrordocstring are unaffected, since the 400 is not a PyAthena-specific translation. No other page states copy errors.Existing callers: no behavior change, since the PR touches only docstrings and Markdown.