Suppress FileNotFoundError when deleting keys in the obstore adapter - #3140

Merged
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main
Jun 25, 2025
Merged

Suppress FileNotFoundError when deleting keys in the obstore adapter#3140
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main

Conversation

@lukasbindreiter

@lukasbindreiterlukasbindreiter commented Jun 18, 2025

Copy link
Copy Markdown
Contributor

Suppress FileNotFoundError in delete operation of the obstore adapter.

Since some underlying stores allow this, while others raise an error, supressing the error results in consistent behaviour across all stores. This also mimics how the same thing is implemented in the fsspec adapter.

Fixes#3136

TODO:

  • Add unit tests and/or doctests in docstrings
  • Changes documented as a new file in changes/
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@github-actionsgithub-actionsBot added needs release notes Automatically applied to PRs which haven't added release notes and removed needs release notes Automatically applied to PRs which haven't added release notes labels Jun 18, 2025
@dstansby

Copy link
Copy Markdown
Contributor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

@d-v-b

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key, and for the caller of the store method to handle that exception specifically in the context of attempting to remove an empty chunk. But this fix also works!

@kylebarron

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key

From the obstore side I don't have total control over that. The upstream s3 implementation does not raise an error: https://docs.rs/object_store/latest/object_store/trait.ObjectStore.html#method.delete_stream

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

Yes this seems to be the behaviour across stores:

so I believe it makes sense to do the same for obstore as well.

And when thinking about the main purpose of the function (to clear chunks) this behaviour makes sense - it seems the function isn't really about deleting an object, instead it is to make sure that an object doesn't exist in the store.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

Good idea, I've moved the test now to StoreTests 👍

Across stores is a bit ambiguous in this context though - there is the zarr adapter stores (fsspec, local, memory, obstore) - the test now runs across all of those.

However the issue / bugfix was only for the obstore adapter, since there is inconsistent behaviour across obstore stores (S3, GCS, Azure, Local, InMemory) - but as @kylebarron has mentioned that seems to be out of control of obstore itself.

Comment threadsrc/zarr/storage/_obstore.py Outdated

@maxrjonesmaxrjones left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My approval doesn't mean anything really, but I'm submitting it because I ran into this issue and tested your branch locally to confirm that it solved the problem. I also made two code suggestions to apply Kyle's recommendation for convenience.

Comment threadsrc/zarr/storage/_obstore.py Outdated
Comment threadsrc/zarr/storage/_obstore.py Outdated
@kylebarron

Copy link
Copy Markdown
Contributor

In developmentseed/obstore#487 I propose deprecating the obstore.exceptions.NotFoundError class

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks @maxrjones and @kylebarron for the review - I've now updated the comment and removed the obstore.exceptions.NotFoundError again

@d-v-b
d-v-b enabled auto-merge (squash) June 24, 2025 19:45
@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

@d-v-b Thanks for enabling the merge.

I checked the failing test for the windows-latest py3.11 run, which is this one.

deftest_sync_timeout() ->None:
duration=0.02asyncdeffoo() ->None:
awaitasyncio.sleep(duration)
withpytest.raises(asyncio.TimeoutError):
sync(foo(), timeout=duration/10)

It seems completely unrelated to the changes in the PR, probably a flaky failure? Could you potentially retry it?

@d-v-b
d-v-b merged commit 27615fd into zarr-developers:mainJun 25, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@lukasbindreiter the flaky test theory seems valid! thanks for this contribution.

(I accidentally posted this in #3136 (comment))

@d-v-bd-v-b added this to the 3.0.9 milestone Jun 30, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@meeseeksdev backport to 3.0.9

meeseeksmachine pushed a commit to meeseeksmachine/zarr-python that referenced this pull request Jun 30, 2025
d-v-b pushed a commit that referenced this pull request Jun 30, 2025
…he obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
d-v-b added a commit that referenced this pull request Jul 9, 2025
* Enable tests on 3.0.x branch (#3135)
* Changelog for 3.0.9
* Backport PR #3149: Add GroupNotFound error to API docs (#3179)
Co-authored-by: David Stansby <dstansby@gmail.com>
* Backport PR #3140: Suppress FileNotFoundError when deleting keys in the obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
* Backport PR #3138: Add with_read_only() convenience method to store (#3181)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* Create read only copy if needed when opening a store path (#3156) (#3182)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
* Update src/zarr/storage/_common.py
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
* Improve code coverage
---------
(cherry picked from commit 5731c6c)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193) (#3203)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
(cherry picked from commit 5a24487)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
* Auto backport of pr 3195 on 3.0.10 (#3204)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
* 3.0.9 release notes (#3183)
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* release notes
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* release notes
---------
Co-authored-by: Lumberbot (aka Jack) <39504233+meeseeksmachine@users.noreply.github.com>
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
@codecov

codecovBot commented Sep 23, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.48%. Comparing base (5731c6c) to head (a6fa2c5).
⚠️ Report is 130 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #3140 +/- ##
=======================================
Coverage 94.47% 94.48% =======================================
Files 78 78 Lines 8585 8590 +5 =======================================
+ Hits 8111 8116 +5 
Misses 474 474 
Files with missing linesCoverage Δ
src/zarr/storage/_obstore.py94.17% <100.00%> (+0.02%)⬆️
src/zarr/testing/store.py100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FileNotFoundError when writing an array that contains empty chunks

5 participants

@lukasbindreiter@dstansby@d-v-b@kylebarron@maxrjones
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Suppress FileNotFoundError when deleting keys in the obstore adapter - #3140

Merged
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main
Jun 25, 2025
Merged

Suppress FileNotFoundError when deleting keys in the obstore adapter#3140
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main

Conversation

@lukasbindreiter

@lukasbindreiterlukasbindreiter commented Jun 18, 2025

Copy link
Copy Markdown
Contributor

Suppress FileNotFoundError in delete operation of the obstore adapter.

Since some underlying stores allow this, while others raise an error, supressing the error results in consistent behaviour across all stores. This also mimics how the same thing is implemented in the fsspec adapter.

Fixes#3136

TODO:

  • Add unit tests and/or doctests in docstrings
  • Changes documented as a new file in changes/
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@github-actionsgithub-actionsBot added needs release notes Automatically applied to PRs which haven't added release notes and removed needs release notes Automatically applied to PRs which haven't added release notes labels Jun 18, 2025
@dstansby

Copy link
Copy Markdown
Contributor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

@d-v-b

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key, and for the caller of the store method to handle that exception specifically in the context of attempting to remove an empty chunk. But this fix also works!

@kylebarron

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key

From the obstore side I don't have total control over that. The upstream s3 implementation does not raise an error: https://docs.rs/object_store/latest/object_store/trait.ObjectStore.html#method.delete_stream

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

Yes this seems to be the behaviour across stores:

so I believe it makes sense to do the same for obstore as well.

And when thinking about the main purpose of the function (to clear chunks) this behaviour makes sense - it seems the function isn't really about deleting an object, instead it is to make sure that an object doesn't exist in the store.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

Good idea, I've moved the test now to StoreTests 👍

Across stores is a bit ambiguous in this context though - there is the zarr adapter stores (fsspec, local, memory, obstore) - the test now runs across all of those.

However the issue / bugfix was only for the obstore adapter, since there is inconsistent behaviour across obstore stores (S3, GCS, Azure, Local, InMemory) - but as @kylebarron has mentioned that seems to be out of control of obstore itself.

Comment threadsrc/zarr/storage/_obstore.py Outdated

@maxrjonesmaxrjones left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My approval doesn't mean anything really, but I'm submitting it because I ran into this issue and tested your branch locally to confirm that it solved the problem. I also made two code suggestions to apply Kyle's recommendation for convenience.

Comment threadsrc/zarr/storage/_obstore.py Outdated
Comment threadsrc/zarr/storage/_obstore.py Outdated
@kylebarron

Copy link
Copy Markdown
Contributor

In developmentseed/obstore#487 I propose deprecating the obstore.exceptions.NotFoundError class

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks @maxrjones and @kylebarron for the review - I've now updated the comment and removed the obstore.exceptions.NotFoundError again

@d-v-b
d-v-b enabled auto-merge (squash) June 24, 2025 19:45
@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

@d-v-b Thanks for enabling the merge.

I checked the failing test for the windows-latest py3.11 run, which is this one.

deftest_sync_timeout() ->None:
duration=0.02asyncdeffoo() ->None:
awaitasyncio.sleep(duration)
withpytest.raises(asyncio.TimeoutError):
sync(foo(), timeout=duration/10)

It seems completely unrelated to the changes in the PR, probably a flaky failure? Could you potentially retry it?

@d-v-b
d-v-b merged commit 27615fd into zarr-developers:mainJun 25, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@lukasbindreiter the flaky test theory seems valid! thanks for this contribution.

(I accidentally posted this in #3136 (comment))

@d-v-bd-v-b added this to the 3.0.9 milestone Jun 30, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@meeseeksdev backport to 3.0.9

meeseeksmachine pushed a commit to meeseeksmachine/zarr-python that referenced this pull request Jun 30, 2025
d-v-b pushed a commit that referenced this pull request Jun 30, 2025
…he obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
d-v-b added a commit that referenced this pull request Jul 9, 2025
* Enable tests on 3.0.x branch (#3135)
* Changelog for 3.0.9
* Backport PR #3149: Add GroupNotFound error to API docs (#3179)
Co-authored-by: David Stansby <dstansby@gmail.com>
* Backport PR #3140: Suppress FileNotFoundError when deleting keys in the obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
* Backport PR #3138: Add with_read_only() convenience method to store (#3181)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* Create read only copy if needed when opening a store path (#3156) (#3182)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
* Update src/zarr/storage/_common.py
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
* Improve code coverage
---------
(cherry picked from commit 5731c6c)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193) (#3203)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
(cherry picked from commit 5a24487)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
* Auto backport of pr 3195 on 3.0.10 (#3204)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
* 3.0.9 release notes (#3183)
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* release notes
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* release notes
---------
Co-authored-by: Lumberbot (aka Jack) <39504233+meeseeksmachine@users.noreply.github.com>
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
@codecov

codecovBot commented Sep 23, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.48%. Comparing base (5731c6c) to head (a6fa2c5).
⚠️ Report is 130 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #3140 +/- ##
=======================================
Coverage 94.47% 94.48% =======================================
Files 78 78 Lines 8585 8590 +5 =======================================
+ Hits 8111 8116 +5 
Misses 474 474 
Files with missing linesCoverage Δ
src/zarr/storage/_obstore.py94.17% <100.00%> (+0.02%)⬆️
src/zarr/testing/store.py100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FileNotFoundError when writing an array that contains empty chunks

5 participants

@lukasbindreiter@dstansby@d-v-b@kylebarron@maxrjones
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Suppress FileNotFoundError when deleting keys in the obstore adapter - #3140

Merged
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main
Jun 25, 2025
Merged

Suppress FileNotFoundError when deleting keys in the obstore adapter#3140
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main

Conversation

@lukasbindreiter

@lukasbindreiterlukasbindreiter commented Jun 18, 2025

Copy link
Copy Markdown
Contributor

Suppress FileNotFoundError in delete operation of the obstore adapter.

Since some underlying stores allow this, while others raise an error, supressing the error results in consistent behaviour across all stores. This also mimics how the same thing is implemented in the fsspec adapter.

Fixes#3136

TODO:

  • Add unit tests and/or doctests in docstrings
  • Changes documented as a new file in changes/
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@github-actionsgithub-actionsBot added needs release notes Automatically applied to PRs which haven't added release notes and removed needs release notes Automatically applied to PRs which haven't added release notes labels Jun 18, 2025
@dstansby

Copy link
Copy Markdown
Contributor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

@d-v-b

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key, and for the caller of the store method to handle that exception specifically in the context of attempting to remove an empty chunk. But this fix also works!

@kylebarron

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key

From the obstore side I don't have total control over that. The upstream s3 implementation does not raise an error: https://docs.rs/object_store/latest/object_store/trait.ObjectStore.html#method.delete_stream

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

Yes this seems to be the behaviour across stores:

so I believe it makes sense to do the same for obstore as well.

And when thinking about the main purpose of the function (to clear chunks) this behaviour makes sense - it seems the function isn't really about deleting an object, instead it is to make sure that an object doesn't exist in the store.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

Good idea, I've moved the test now to StoreTests 👍

Across stores is a bit ambiguous in this context though - there is the zarr adapter stores (fsspec, local, memory, obstore) - the test now runs across all of those.

However the issue / bugfix was only for the obstore adapter, since there is inconsistent behaviour across obstore stores (S3, GCS, Azure, Local, InMemory) - but as @kylebarron has mentioned that seems to be out of control of obstore itself.

Comment threadsrc/zarr/storage/_obstore.py Outdated

@maxrjonesmaxrjones left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My approval doesn't mean anything really, but I'm submitting it because I ran into this issue and tested your branch locally to confirm that it solved the problem. I also made two code suggestions to apply Kyle's recommendation for convenience.

Comment threadsrc/zarr/storage/_obstore.py Outdated
Comment threadsrc/zarr/storage/_obstore.py Outdated
@kylebarron

Copy link
Copy Markdown
Contributor

In developmentseed/obstore#487 I propose deprecating the obstore.exceptions.NotFoundError class

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks @maxrjones and @kylebarron for the review - I've now updated the comment and removed the obstore.exceptions.NotFoundError again

@d-v-b
d-v-b enabled auto-merge (squash) June 24, 2025 19:45
@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

@d-v-b Thanks for enabling the merge.

I checked the failing test for the windows-latest py3.11 run, which is this one.

deftest_sync_timeout() ->None:
duration=0.02asyncdeffoo() ->None:
awaitasyncio.sleep(duration)
withpytest.raises(asyncio.TimeoutError):
sync(foo(), timeout=duration/10)

It seems completely unrelated to the changes in the PR, probably a flaky failure? Could you potentially retry it?

@d-v-b
d-v-b merged commit 27615fd into zarr-developers:mainJun 25, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@lukasbindreiter the flaky test theory seems valid! thanks for this contribution.

(I accidentally posted this in #3136 (comment))

@d-v-bd-v-b added this to the 3.0.9 milestone Jun 30, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@meeseeksdev backport to 3.0.9

meeseeksmachine pushed a commit to meeseeksmachine/zarr-python that referenced this pull request Jun 30, 2025
d-v-b pushed a commit that referenced this pull request Jun 30, 2025
…he obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
d-v-b added a commit that referenced this pull request Jul 9, 2025
* Enable tests on 3.0.x branch (#3135)
* Changelog for 3.0.9
* Backport PR #3149: Add GroupNotFound error to API docs (#3179)
Co-authored-by: David Stansby <dstansby@gmail.com>
* Backport PR #3140: Suppress FileNotFoundError when deleting keys in the obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
* Backport PR #3138: Add with_read_only() convenience method to store (#3181)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* Create read only copy if needed when opening a store path (#3156) (#3182)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
* Update src/zarr/storage/_common.py
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
* Improve code coverage
---------
(cherry picked from commit 5731c6c)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193) (#3203)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
(cherry picked from commit 5a24487)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
* Auto backport of pr 3195 on 3.0.10 (#3204)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
* 3.0.9 release notes (#3183)
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* release notes
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* release notes
---------
Co-authored-by: Lumberbot (aka Jack) <39504233+meeseeksmachine@users.noreply.github.com>
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
@codecov

codecovBot commented Sep 23, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.48%. Comparing base (5731c6c) to head (a6fa2c5).
⚠️ Report is 130 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #3140 +/- ##
=======================================
Coverage 94.47% 94.48% =======================================
Files 78 78 Lines 8585 8590 +5 =======================================
+ Hits 8111 8116 +5 
Misses 474 474 
Files with missing linesCoverage Δ
src/zarr/storage/_obstore.py94.17% <100.00%> (+0.02%)⬆️
src/zarr/testing/store.py100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FileNotFoundError when writing an array that contains empty chunks

5 participants

@lukasbindreiter@dstansby@d-v-b@kylebarron@maxrjones
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Suppress FileNotFoundError when deleting keys in the obstore adapter - #3140

Merged
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main
Jun 25, 2025
Merged

Suppress FileNotFoundError when deleting keys in the obstore adapter#3140
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main

Conversation

@lukasbindreiter

@lukasbindreiterlukasbindreiter commented Jun 18, 2025

Copy link
Copy Markdown
Contributor

Suppress FileNotFoundError in delete operation of the obstore adapter.

Since some underlying stores allow this, while others raise an error, supressing the error results in consistent behaviour across all stores. This also mimics how the same thing is implemented in the fsspec adapter.

Fixes#3136

TODO:

  • Add unit tests and/or doctests in docstrings
  • Changes documented as a new file in changes/
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@github-actionsgithub-actionsBot added needs release notes Automatically applied to PRs which haven't added release notes and removed needs release notes Automatically applied to PRs which haven't added release notes labels Jun 18, 2025
@dstansby

Copy link
Copy Markdown
Contributor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

@d-v-b

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key, and for the caller of the store method to handle that exception specifically in the context of attempting to remove an empty chunk. But this fix also works!

@kylebarron

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key

From the obstore side I don't have total control over that. The upstream s3 implementation does not raise an error: https://docs.rs/object_store/latest/object_store/trait.ObjectStore.html#method.delete_stream

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

Yes this seems to be the behaviour across stores:

so I believe it makes sense to do the same for obstore as well.

And when thinking about the main purpose of the function (to clear chunks) this behaviour makes sense - it seems the function isn't really about deleting an object, instead it is to make sure that an object doesn't exist in the store.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

Good idea, I've moved the test now to StoreTests 👍

Across stores is a bit ambiguous in this context though - there is the zarr adapter stores (fsspec, local, memory, obstore) - the test now runs across all of those.

However the issue / bugfix was only for the obstore adapter, since there is inconsistent behaviour across obstore stores (S3, GCS, Azure, Local, InMemory) - but as @kylebarron has mentioned that seems to be out of control of obstore itself.

Comment threadsrc/zarr/storage/_obstore.py Outdated

@maxrjonesmaxrjones left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My approval doesn't mean anything really, but I'm submitting it because I ran into this issue and tested your branch locally to confirm that it solved the problem. I also made two code suggestions to apply Kyle's recommendation for convenience.

Comment threadsrc/zarr/storage/_obstore.py Outdated
Comment threadsrc/zarr/storage/_obstore.py Outdated
@kylebarron

Copy link
Copy Markdown
Contributor

In developmentseed/obstore#487 I propose deprecating the obstore.exceptions.NotFoundError class

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks @maxrjones and @kylebarron for the review - I've now updated the comment and removed the obstore.exceptions.NotFoundError again

@d-v-b
d-v-b enabled auto-merge (squash) June 24, 2025 19:45
@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

@d-v-b Thanks for enabling the merge.

I checked the failing test for the windows-latest py3.11 run, which is this one.

deftest_sync_timeout() ->None:
duration=0.02asyncdeffoo() ->None:
awaitasyncio.sleep(duration)
withpytest.raises(asyncio.TimeoutError):
sync(foo(), timeout=duration/10)

It seems completely unrelated to the changes in the PR, probably a flaky failure? Could you potentially retry it?

@d-v-b
d-v-b merged commit 27615fd into zarr-developers:mainJun 25, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@lukasbindreiter the flaky test theory seems valid! thanks for this contribution.

(I accidentally posted this in #3136 (comment))

@d-v-bd-v-b added this to the 3.0.9 milestone Jun 30, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@meeseeksdev backport to 3.0.9

meeseeksmachine pushed a commit to meeseeksmachine/zarr-python that referenced this pull request Jun 30, 2025
d-v-b pushed a commit that referenced this pull request Jun 30, 2025
…he obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
d-v-b added a commit that referenced this pull request Jul 9, 2025
* Enable tests on 3.0.x branch (#3135)
* Changelog for 3.0.9
* Backport PR #3149: Add GroupNotFound error to API docs (#3179)
Co-authored-by: David Stansby <dstansby@gmail.com>
* Backport PR #3140: Suppress FileNotFoundError when deleting keys in the obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
* Backport PR #3138: Add with_read_only() convenience method to store (#3181)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* Create read only copy if needed when opening a store path (#3156) (#3182)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
* Update src/zarr/storage/_common.py
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
* Improve code coverage
---------
(cherry picked from commit 5731c6c)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193) (#3203)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
(cherry picked from commit 5a24487)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
* Auto backport of pr 3195 on 3.0.10 (#3204)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
* 3.0.9 release notes (#3183)
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* release notes
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* release notes
---------
Co-authored-by: Lumberbot (aka Jack) <39504233+meeseeksmachine@users.noreply.github.com>
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
@codecov

codecovBot commented Sep 23, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.48%. Comparing base (5731c6c) to head (a6fa2c5).
⚠️ Report is 130 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #3140 +/- ##
=======================================
Coverage 94.47% 94.48% =======================================
Files 78 78 Lines 8585 8590 +5 =======================================
+ Hits 8111 8116 +5 
Misses 474 474 
Files with missing linesCoverage Δ
src/zarr/storage/_obstore.py94.17% <100.00%> (+0.02%)⬆️
src/zarr/testing/store.py100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FileNotFoundError when writing an array that contains empty chunks

5 participants

@lukasbindreiter@dstansby@d-v-b@kylebarron@maxrjones
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Suppress FileNotFoundError when deleting keys in the obstore adapter - #3140

Merged
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main
Jun 25, 2025
Merged

Suppress FileNotFoundError when deleting keys in the obstore adapter#3140
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main

Conversation

@lukasbindreiter

@lukasbindreiterlukasbindreiter commented Jun 18, 2025

Copy link
Copy Markdown
Contributor

Suppress FileNotFoundError in delete operation of the obstore adapter.

Since some underlying stores allow this, while others raise an error, supressing the error results in consistent behaviour across all stores. This also mimics how the same thing is implemented in the fsspec adapter.

Fixes#3136

TODO:

  • Add unit tests and/or doctests in docstrings
  • Changes documented as a new file in changes/
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@github-actionsgithub-actionsBot added needs release notes Automatically applied to PRs which haven't added release notes and removed needs release notes Automatically applied to PRs which haven't added release notes labels Jun 18, 2025
@dstansby

Copy link
Copy Markdown
Contributor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

@d-v-b

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key, and for the caller of the store method to handle that exception specifically in the context of attempting to remove an empty chunk. But this fix also works!

@kylebarron

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key

From the obstore side I don't have total control over that. The upstream s3 implementation does not raise an error: https://docs.rs/object_store/latest/object_store/trait.ObjectStore.html#method.delete_stream

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

Yes this seems to be the behaviour across stores:

so I believe it makes sense to do the same for obstore as well.

And when thinking about the main purpose of the function (to clear chunks) this behaviour makes sense - it seems the function isn't really about deleting an object, instead it is to make sure that an object doesn't exist in the store.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

Good idea, I've moved the test now to StoreTests 👍

Across stores is a bit ambiguous in this context though - there is the zarr adapter stores (fsspec, local, memory, obstore) - the test now runs across all of those.

However the issue / bugfix was only for the obstore adapter, since there is inconsistent behaviour across obstore stores (S3, GCS, Azure, Local, InMemory) - but as @kylebarron has mentioned that seems to be out of control of obstore itself.

Comment threadsrc/zarr/storage/_obstore.py Outdated

@maxrjonesmaxrjones left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My approval doesn't mean anything really, but I'm submitting it because I ran into this issue and tested your branch locally to confirm that it solved the problem. I also made two code suggestions to apply Kyle's recommendation for convenience.

Comment threadsrc/zarr/storage/_obstore.py Outdated
Comment threadsrc/zarr/storage/_obstore.py Outdated
@kylebarron

Copy link
Copy Markdown
Contributor

In developmentseed/obstore#487 I propose deprecating the obstore.exceptions.NotFoundError class

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks @maxrjones and @kylebarron for the review - I've now updated the comment and removed the obstore.exceptions.NotFoundError again

@d-v-b
d-v-b enabled auto-merge (squash) June 24, 2025 19:45
@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

@d-v-b Thanks for enabling the merge.

I checked the failing test for the windows-latest py3.11 run, which is this one.

deftest_sync_timeout() ->None:
duration=0.02asyncdeffoo() ->None:
awaitasyncio.sleep(duration)
withpytest.raises(asyncio.TimeoutError):
sync(foo(), timeout=duration/10)

It seems completely unrelated to the changes in the PR, probably a flaky failure? Could you potentially retry it?

@d-v-b
d-v-b merged commit 27615fd into zarr-developers:mainJun 25, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@lukasbindreiter the flaky test theory seems valid! thanks for this contribution.

(I accidentally posted this in #3136 (comment))

@d-v-bd-v-b added this to the 3.0.9 milestone Jun 30, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@meeseeksdev backport to 3.0.9

meeseeksmachine pushed a commit to meeseeksmachine/zarr-python that referenced this pull request Jun 30, 2025
d-v-b pushed a commit that referenced this pull request Jun 30, 2025
…he obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
d-v-b added a commit that referenced this pull request Jul 9, 2025
* Enable tests on 3.0.x branch (#3135)
* Changelog for 3.0.9
* Backport PR #3149: Add GroupNotFound error to API docs (#3179)
Co-authored-by: David Stansby <dstansby@gmail.com>
* Backport PR #3140: Suppress FileNotFoundError when deleting keys in the obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
* Backport PR #3138: Add with_read_only() convenience method to store (#3181)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* Create read only copy if needed when opening a store path (#3156) (#3182)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
* Update src/zarr/storage/_common.py
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
* Improve code coverage
---------
(cherry picked from commit 5731c6c)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193) (#3203)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
(cherry picked from commit 5a24487)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
* Auto backport of pr 3195 on 3.0.10 (#3204)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
* 3.0.9 release notes (#3183)
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* release notes
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* release notes
---------
Co-authored-by: Lumberbot (aka Jack) <39504233+meeseeksmachine@users.noreply.github.com>
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
@codecov

codecovBot commented Sep 23, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.48%. Comparing base (5731c6c) to head (a6fa2c5).
⚠️ Report is 130 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #3140 +/- ##
=======================================
Coverage 94.47% 94.48% =======================================
Files 78 78 Lines 8585 8590 +5 =======================================
+ Hits 8111 8116 +5 
Misses 474 474 
Files with missing linesCoverage Δ
src/zarr/storage/_obstore.py94.17% <100.00%> (+0.02%)⬆️
src/zarr/testing/store.py100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FileNotFoundError when writing an array that contains empty chunks

5 participants

@lukasbindreiter@dstansby@d-v-b@kylebarron@maxrjones
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Suppress FileNotFoundError when deleting keys in the obstore adapter - #3140

Merged
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main
Jun 25, 2025
Merged

Suppress FileNotFoundError when deleting keys in the obstore adapter#3140
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main

Conversation

@lukasbindreiter

@lukasbindreiterlukasbindreiter commented Jun 18, 2025

Copy link
Copy Markdown
Contributor

Suppress FileNotFoundError in delete operation of the obstore adapter.

Since some underlying stores allow this, while others raise an error, supressing the error results in consistent behaviour across all stores. This also mimics how the same thing is implemented in the fsspec adapter.

Fixes#3136

TODO:

  • Add unit tests and/or doctests in docstrings
  • Changes documented as a new file in changes/
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@github-actionsgithub-actionsBot added needs release notes Automatically applied to PRs which haven't added release notes and removed needs release notes Automatically applied to PRs which haven't added release notes labels Jun 18, 2025
@dstansby

Copy link
Copy Markdown
Contributor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

@d-v-b

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key, and for the caller of the store method to handle that exception specifically in the context of attempting to remove an empty chunk. But this fix also works!

@kylebarron

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key

From the obstore side I don't have total control over that. The upstream s3 implementation does not raise an error: https://docs.rs/object_store/latest/object_store/trait.ObjectStore.html#method.delete_stream

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

Yes this seems to be the behaviour across stores:

so I believe it makes sense to do the same for obstore as well.

And when thinking about the main purpose of the function (to clear chunks) this behaviour makes sense - it seems the function isn't really about deleting an object, instead it is to make sure that an object doesn't exist in the store.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

Good idea, I've moved the test now to StoreTests 👍

Across stores is a bit ambiguous in this context though - there is the zarr adapter stores (fsspec, local, memory, obstore) - the test now runs across all of those.

However the issue / bugfix was only for the obstore adapter, since there is inconsistent behaviour across obstore stores (S3, GCS, Azure, Local, InMemory) - but as @kylebarron has mentioned that seems to be out of control of obstore itself.

Comment threadsrc/zarr/storage/_obstore.py Outdated

@maxrjonesmaxrjones left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My approval doesn't mean anything really, but I'm submitting it because I ran into this issue and tested your branch locally to confirm that it solved the problem. I also made two code suggestions to apply Kyle's recommendation for convenience.

Comment threadsrc/zarr/storage/_obstore.py Outdated
Comment threadsrc/zarr/storage/_obstore.py Outdated
@kylebarron

Copy link
Copy Markdown
Contributor

In developmentseed/obstore#487 I propose deprecating the obstore.exceptions.NotFoundError class

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks @maxrjones and @kylebarron for the review - I've now updated the comment and removed the obstore.exceptions.NotFoundError again

@d-v-b
d-v-b enabled auto-merge (squash) June 24, 2025 19:45
@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

@d-v-b Thanks for enabling the merge.

I checked the failing test for the windows-latest py3.11 run, which is this one.

deftest_sync_timeout() ->None:
duration=0.02asyncdeffoo() ->None:
awaitasyncio.sleep(duration)
withpytest.raises(asyncio.TimeoutError):
sync(foo(), timeout=duration/10)

It seems completely unrelated to the changes in the PR, probably a flaky failure? Could you potentially retry it?

@d-v-b
d-v-b merged commit 27615fd into zarr-developers:mainJun 25, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@lukasbindreiter the flaky test theory seems valid! thanks for this contribution.

(I accidentally posted this in #3136 (comment))

@d-v-bd-v-b added this to the 3.0.9 milestone Jun 30, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@meeseeksdev backport to 3.0.9

meeseeksmachine pushed a commit to meeseeksmachine/zarr-python that referenced this pull request Jun 30, 2025
d-v-b pushed a commit that referenced this pull request Jun 30, 2025
…he obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
d-v-b added a commit that referenced this pull request Jul 9, 2025
* Enable tests on 3.0.x branch (#3135)
* Changelog for 3.0.9
* Backport PR #3149: Add GroupNotFound error to API docs (#3179)
Co-authored-by: David Stansby <dstansby@gmail.com>
* Backport PR #3140: Suppress FileNotFoundError when deleting keys in the obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
* Backport PR #3138: Add with_read_only() convenience method to store (#3181)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* Create read only copy if needed when opening a store path (#3156) (#3182)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
* Update src/zarr/storage/_common.py
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
* Improve code coverage
---------
(cherry picked from commit 5731c6c)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193) (#3203)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
(cherry picked from commit 5a24487)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
* Auto backport of pr 3195 on 3.0.10 (#3204)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
* 3.0.9 release notes (#3183)
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* release notes
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* release notes
---------
Co-authored-by: Lumberbot (aka Jack) <39504233+meeseeksmachine@users.noreply.github.com>
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
@codecov

codecovBot commented Sep 23, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.48%. Comparing base (5731c6c) to head (a6fa2c5).
⚠️ Report is 130 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #3140 +/- ##
=======================================
Coverage 94.47% 94.48% =======================================
Files 78 78 Lines 8585 8590 +5 =======================================
+ Hits 8111 8116 +5 
Misses 474 474 
Files with missing linesCoverage Δ
src/zarr/storage/_obstore.py94.17% <100.00%> (+0.02%)⬆️
src/zarr/testing/store.py100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FileNotFoundError when writing an array that contains empty chunks

5 participants

@lukasbindreiter@dstansby@d-v-b@kylebarron@maxrjones
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Suppress FileNotFoundError when deleting keys in the obstore adapter - #3140

Merged
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main
Jun 25, 2025
Merged

Suppress FileNotFoundError when deleting keys in the obstore adapter#3140
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main

Conversation

@lukasbindreiter

@lukasbindreiterlukasbindreiter commented Jun 18, 2025

Copy link
Copy Markdown
Contributor

Suppress FileNotFoundError in delete operation of the obstore adapter.

Since some underlying stores allow this, while others raise an error, supressing the error results in consistent behaviour across all stores. This also mimics how the same thing is implemented in the fsspec adapter.

Fixes#3136

TODO:

  • Add unit tests and/or doctests in docstrings
  • Changes documented as a new file in changes/
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@github-actionsgithub-actionsBot added needs release notes Automatically applied to PRs which haven't added release notes and removed needs release notes Automatically applied to PRs which haven't added release notes labels Jun 18, 2025
@dstansby

Copy link
Copy Markdown
Contributor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

@d-v-b

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key, and for the caller of the store method to handle that exception specifically in the context of attempting to remove an empty chunk. But this fix also works!

@kylebarron

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key

From the obstore side I don't have total control over that. The upstream s3 implementation does not raise an error: https://docs.rs/object_store/latest/object_store/trait.ObjectStore.html#method.delete_stream

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

Yes this seems to be the behaviour across stores:

so I believe it makes sense to do the same for obstore as well.

And when thinking about the main purpose of the function (to clear chunks) this behaviour makes sense - it seems the function isn't really about deleting an object, instead it is to make sure that an object doesn't exist in the store.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

Good idea, I've moved the test now to StoreTests 👍

Across stores is a bit ambiguous in this context though - there is the zarr adapter stores (fsspec, local, memory, obstore) - the test now runs across all of those.

However the issue / bugfix was only for the obstore adapter, since there is inconsistent behaviour across obstore stores (S3, GCS, Azure, Local, InMemory) - but as @kylebarron has mentioned that seems to be out of control of obstore itself.

Comment threadsrc/zarr/storage/_obstore.py Outdated

@maxrjonesmaxrjones left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My approval doesn't mean anything really, but I'm submitting it because I ran into this issue and tested your branch locally to confirm that it solved the problem. I also made two code suggestions to apply Kyle's recommendation for convenience.

Comment threadsrc/zarr/storage/_obstore.py Outdated
Comment threadsrc/zarr/storage/_obstore.py Outdated
@kylebarron

Copy link
Copy Markdown
Contributor

In developmentseed/obstore#487 I propose deprecating the obstore.exceptions.NotFoundError class

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks @maxrjones and @kylebarron for the review - I've now updated the comment and removed the obstore.exceptions.NotFoundError again

@d-v-b
d-v-b enabled auto-merge (squash) June 24, 2025 19:45
@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

@d-v-b Thanks for enabling the merge.

I checked the failing test for the windows-latest py3.11 run, which is this one.

deftest_sync_timeout() ->None:
duration=0.02asyncdeffoo() ->None:
awaitasyncio.sleep(duration)
withpytest.raises(asyncio.TimeoutError):
sync(foo(), timeout=duration/10)

It seems completely unrelated to the changes in the PR, probably a flaky failure? Could you potentially retry it?

@d-v-b
d-v-b merged commit 27615fd into zarr-developers:mainJun 25, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@lukasbindreiter the flaky test theory seems valid! thanks for this contribution.

(I accidentally posted this in #3136 (comment))

@d-v-bd-v-b added this to the 3.0.9 milestone Jun 30, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@meeseeksdev backport to 3.0.9

meeseeksmachine pushed a commit to meeseeksmachine/zarr-python that referenced this pull request Jun 30, 2025
d-v-b pushed a commit that referenced this pull request Jun 30, 2025
…he obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
d-v-b added a commit that referenced this pull request Jul 9, 2025
* Enable tests on 3.0.x branch (#3135)
* Changelog for 3.0.9
* Backport PR #3149: Add GroupNotFound error to API docs (#3179)
Co-authored-by: David Stansby <dstansby@gmail.com>
* Backport PR #3140: Suppress FileNotFoundError when deleting keys in the obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
* Backport PR #3138: Add with_read_only() convenience method to store (#3181)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* Create read only copy if needed when opening a store path (#3156) (#3182)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
* Update src/zarr/storage/_common.py
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
* Improve code coverage
---------
(cherry picked from commit 5731c6c)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193) (#3203)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
(cherry picked from commit 5a24487)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
* Auto backport of pr 3195 on 3.0.10 (#3204)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
* 3.0.9 release notes (#3183)
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* release notes
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* release notes
---------
Co-authored-by: Lumberbot (aka Jack) <39504233+meeseeksmachine@users.noreply.github.com>
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
@codecov

codecovBot commented Sep 23, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.48%. Comparing base (5731c6c) to head (a6fa2c5).
⚠️ Report is 130 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #3140 +/- ##
=======================================
Coverage 94.47% 94.48% =======================================
Files 78 78 Lines 8585 8590 +5 =======================================
+ Hits 8111 8116 +5 
Misses 474 474 
Files with missing linesCoverage Δ
src/zarr/storage/_obstore.py94.17% <100.00%> (+0.02%)⬆️
src/zarr/testing/store.py100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FileNotFoundError when writing an array that contains empty chunks

5 participants

@lukasbindreiter@dstansby@d-v-b@kylebarron@maxrjones
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Suppress FileNotFoundError when deleting keys in the obstore adapter - #3140

Merged
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main
Jun 25, 2025
Merged

Suppress FileNotFoundError when deleting keys in the obstore adapter#3140
d-v-b merged 7 commits into
zarr-developers:mainfrom
lukasbindreiter:main

Conversation

@lukasbindreiter

@lukasbindreiterlukasbindreiter commented Jun 18, 2025

Copy link
Copy Markdown
Contributor

Suppress FileNotFoundError in delete operation of the obstore adapter.

Since some underlying stores allow this, while others raise an error, supressing the error results in consistent behaviour across all stores. This also mimics how the same thing is implemented in the fsspec adapter.

Fixes#3136

TODO:

  • Add unit tests and/or doctests in docstrings
  • Changes documented as a new file in changes/
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@github-actionsgithub-actionsBot added needs release notes Automatically applied to PRs which haven't added release notes and removed needs release notes Automatically applied to PRs which haven't added release notes labels Jun 18, 2025
@dstansby

Copy link
Copy Markdown
Contributor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

@d-v-b

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key, and for the caller of the store method to handle that exception specifically in the context of attempting to remove an empty chunk. But this fix also works!

@kylebarron

Copy link
Copy Markdown
Contributor

I think a better long-term solution would be for the stores to all raise the same exception when attempting to delete a missing key

From the obstore side I don't have total control over that. The upstream s3 implementation does not raise an error: https://docs.rs/object_store/latest/object_store/trait.ObjectStore.html#method.delete_stream

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks for the PR/fix! This is slightly surprising behaviour to me - I would expect trying to delete a non-existent file to raise an error. But I guess if this is existing behaviour/design across other stores, this is good.

Yes this seems to be the behaviour across stores:

so I believe it makes sense to do the same for obstore as well.

And when thinking about the main purpose of the function (to clear chunks) this behaviour makes sense - it seems the function isn't really about deleting an object, instead it is to make sure that an object doesn't exist in the store.

To be sure that we're getting consistent behaviour across stores, could you move the test you added to the StoreTests class, so it's run across all stores that are tested?

Good idea, I've moved the test now to StoreTests 👍

Across stores is a bit ambiguous in this context though - there is the zarr adapter stores (fsspec, local, memory, obstore) - the test now runs across all of those.

However the issue / bugfix was only for the obstore adapter, since there is inconsistent behaviour across obstore stores (S3, GCS, Azure, Local, InMemory) - but as @kylebarron has mentioned that seems to be out of control of obstore itself.

Comment threadsrc/zarr/storage/_obstore.py Outdated

@maxrjonesmaxrjones left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My approval doesn't mean anything really, but I'm submitting it because I ran into this issue and tested your branch locally to confirm that it solved the problem. I also made two code suggestions to apply Kyle's recommendation for convenience.

Comment threadsrc/zarr/storage/_obstore.py Outdated
Comment threadsrc/zarr/storage/_obstore.py Outdated
@kylebarron

Copy link
Copy Markdown
Contributor

In developmentseed/obstore#487 I propose deprecating the obstore.exceptions.NotFoundError class

@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

Thanks @maxrjones and @kylebarron for the review - I've now updated the comment and removed the obstore.exceptions.NotFoundError again

@d-v-b
d-v-b enabled auto-merge (squash) June 24, 2025 19:45
@lukasbindreiter

Copy link
Copy Markdown
ContributorAuthor

@d-v-b Thanks for enabling the merge.

I checked the failing test for the windows-latest py3.11 run, which is this one.

deftest_sync_timeout() ->None:
duration=0.02asyncdeffoo() ->None:
awaitasyncio.sleep(duration)
withpytest.raises(asyncio.TimeoutError):
sync(foo(), timeout=duration/10)

It seems completely unrelated to the changes in the PR, probably a flaky failure? Could you potentially retry it?

@d-v-b
d-v-b merged commit 27615fd into zarr-developers:mainJun 25, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@lukasbindreiter the flaky test theory seems valid! thanks for this contribution.

(I accidentally posted this in #3136 (comment))

@d-v-bd-v-b added this to the 3.0.9 milestone Jun 30, 2025
@d-v-b

Copy link
Copy Markdown
Contributor

@meeseeksdev backport to 3.0.9

meeseeksmachine pushed a commit to meeseeksmachine/zarr-python that referenced this pull request Jun 30, 2025
d-v-b pushed a commit that referenced this pull request Jun 30, 2025
…he obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
d-v-b added a commit that referenced this pull request Jul 9, 2025
* Enable tests on 3.0.x branch (#3135)
* Changelog for 3.0.9
* Backport PR #3149: Add GroupNotFound error to API docs (#3179)
Co-authored-by: David Stansby <dstansby@gmail.com>
* Backport PR #3140: Suppress FileNotFoundError when deleting keys in the obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
* Backport PR #3138: Add with_read_only() convenience method to store (#3181)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* Create read only copy if needed when opening a store path (#3156) (#3182)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
* Update src/zarr/storage/_common.py
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
* Improve code coverage
---------
(cherry picked from commit 5731c6c)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193) (#3203)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
(cherry picked from commit 5a24487)
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
* Auto backport of pr 3195 on 3.0.10 (#3204)
* Remove breaking check about `auto_mkdir` for FSSpecStore (#3193)
* Remove breaking check from _make_async
* Update expected error
* Change import structure to protect against AttributeError
* changelog
* add test to ensure that we can create a read-only copy of the store with auto_mkdir=False
* only test if the async wrapper is available
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
(cherry picked from commit 5a24487)
* Add missing import for AsyncFileSystemWrapper for `_make_async` in `_fsspec.py` (#3195)
* Add missing import for AsyncFileSystemWrapper in `_fsspec.py`
* Add missing changelog entry for AsyncFileSystemWrapper import fix
* Move AsyncFileSystemWrapper import past the version check in `_fsspec.py`
* Add newline after AsyncFileSystemWrapper import in `_fsspec.py`
* Simplify import statement for AsyncFileSystemWrapper in `_fsspec.py`
---------
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
(cherry picked from commit 97aa42f)
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
* 3.0.9 release notes (#3183)
* Create read only copy if needed when opening a store path (#3156)
* Create read only copy if needed when opening a store path
* Add ValueError to Raises section
* Update expected warning
* Update src/zarr/storage/_common.py
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
* Use ANY_ACCESS_MODE
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update src/zarr/storage/_common.py
Co-authored-by: David Stansby <dstansby@gmail.com>
* Update changes
* Try using get_args on definition
* Revert "Try using get_args on definition"
This reverts commit 7ad760f.
* Add test
* Remove warning
* Apply suggestion for try; except shortening
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* Improve code coverage
---------
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
(cherry picked from commit 5731c6c)
* release notes
---------
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: David Stansby <dstansby@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
* release notes
---------
Co-authored-by: Lumberbot (aka Jack) <39504233+meeseeksmachine@users.noreply.github.com>
Co-authored-by: Lukas Bindreiter <lukas.bindreiter@tilebox.com>
Co-authored-by: Max Jones <14077947+maxrjones@users.noreply.github.com>
Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
Co-authored-by: Tom Nicholas <tom@earthmover.io>
Co-authored-by: Altay Sansal <tasansal@users.noreply.github.com>
Co-authored-by: Altay Sansal <altay.sansal@tgs.com>
@codecov

codecovBot commented Sep 23, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.48%. Comparing base (5731c6c) to head (a6fa2c5).
⚠️ Report is 130 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #3140 +/- ##
=======================================
Coverage 94.47% 94.48% =======================================
Files 78 78 Lines 8585 8590 +5 =======================================
+ Hits 8111 8116 +5 
Misses 474 474 
Files with missing linesCoverage Δ
src/zarr/storage/_obstore.py94.17% <100.00%> (+0.02%)⬆️
src/zarr/testing/store.py100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FileNotFoundError when writing an array that contains empty chunks

5 participants

@lukasbindreiter@dstansby@d-v-b@kylebarron@maxrjones