Basic working FsspecStore - #1785

Merged
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec
Jun 11, 2024
Merged

Basic working FsspecStore#1785
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec

Conversation

@martindurant

Copy link
Copy Markdown
Member

This works.

  • We don't have any list methods, do we need them?
  • We don't have a bulk delete
  • No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

Fixes#1757

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@martindurant

Copy link
Copy Markdown
MemberAuthor

@jhamman@d-v-b , for discussion

@pep8speaks

pep8speaks commented Apr 11, 2024

Copy link
Copy Markdown

Hello @martindurant! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2024-04-14 01:40:25 UTC

@d-v-b

Copy link
Copy Markdown
Contributor

thanks for this @martindurant, I will see if I have time to play with this locally.

No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

I don't think we have expectations at this point. I will try to get a distillation from the v2 issues around this topic. What do you think we should do here?

@martindurant

Copy link
Copy Markdown
MemberAuthor

I see we have no storage tests, so don't know how to push this any further.

@d-v-b

Copy link
Copy Markdown
Contributor

I will get some tests for you shortly

@jhammanjhamman added the V3 label Apr 22, 2024
@jhammanjhamman added this to the 3.0.0.alpha milestone Apr 22, 2024
@jhamman

Copy link
Copy Markdown
Member

@martindurant - the test suite is in a better place now. Are you up for picking this up?

@martindurant

Copy link
Copy Markdown
MemberAuthor

For testing ... I could set up a mock s3 or gcs with some pain and CI overhead. Also, I could wrap the fsspec memoryFS in async stuff, but that would not really be testing the async-ness and depends no me doing that correctly. None of the other stores are actually async, right?

@jhamman

Copy link
Copy Markdown
Member

@martindurant - which fsspec implementations have an async-api available?

For now, a mocked s3 backend seems like the way to go.

@martindurant

Copy link
Copy Markdown
MemberAuthor

which fsspec implementations have an async-api

I think this is a complete list

  • s3
  • gcs
  • azure (both blob and datalake2)
  • http
  • sshfs (not the builtin ssh/sftp)
  • anaconda (released version is still sync)

The following can pass through async, if they wrap an async FS:

  • generic
  • reference
  • dir/prefix

@jhamman

Copy link
Copy Markdown
Member

Got it. Makes sense. For now, let's target a mocked test against s3. We can add a few others as we approach a full release.

@martindurant

Copy link
Copy Markdown
MemberAuthor

a mocked test against s3

Well, I would use the moto server as s3fs does, which is a real S3 implementation with most of the functionality of the real one (minus permissions, object lifetimes and other unimportant things).

@jhammanjhamman 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.

@martindurant -- this is coming together. I took it for a spin today and ended up needing to make a few changes (suggestions below). But it works!

Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py
Comment threadsrc/zarr/store/remote.py
@jhammanjhamman mentioned this pull request Jun 1, 2024
@martindurant

Copy link
Copy Markdown
MemberAuthor

I merged from v3 and the suggestions above. I cannot get mypy to play.

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

Comment threadsrc/zarr/store/remote.py Outdated
@jhamman

Copy link
Copy Markdown
Member

@martindurant -- thanks for pushing this forward...

I merged from v3 and the suggestions above. I cannot get mypy to play.

I'm hoping @dstansby can take a look... we can find a way!

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

cc @madsbk, @akshaysubr, @normanrz

@martindurant

Copy link
Copy Markdown
MemberAuthor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

@d-v-b

Copy link
Copy Markdown
Contributor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

That's great insight, thank you. Please let me know if there's anything about the StoreTests design that we should change to make this process simpler.

@jhammanjhamman 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.

I see ✅!

Thanks @martindurant for working out the kinks here! (and @d-v-b and @dstansby for chipping in)

@martindurant

Copy link
Copy Markdown
MemberAuthor

Highlighting this line, which works around tests passing offset-length for data which is b"". Python allows you to slice bytes like that (b""[1:2] == b""), but remote stores do not allow this.

Comment threadsrc/zarr/store/remote.py Outdated
if byte_range
else fs._cat_file(path)
if byte_range:
# fsspec uses start/end, not start/length

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I count this as additional evidence that we should switch to start/end semantics for the rest of the stores

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Kerchunk is the exception, storing start/length, mostly because length is generally smaller for chunks in big files.

except self.exceptions:
return None
except OSError as e:
if "not satisfiable" in str(e):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

flagging this as s3 abstraction leakage that we might want to address later on by making an s3-specific storage class

Comment on lines +161 to +162
# TODO: expectations for exceptions or missing keys?
res = await self._fs._cat_ranges(list(paths), starts, stops, on_error="return")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i think returning the exceptions is the right thing here

assert [] == store.listdir(self.root + "c/d/y")
assert [] == store.listdir(self.root + "c/d/y/z")
assert [] == store.listdir(self.root + "c/e/f")
# the following is listdir(filepath), for which fsspec gives [filepath]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what's the advantage of going with POSIX semantics here?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fsspec tries to adhere to posix as much as possible. If we want to exclude the [file] case, we'd have to code that special case into our store.



@pytest.fixture(autouse=True, scope="function")
def s3(s3_base):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@martindurant could you explain what's happening in this test fixture? e.g., why do we need to manipulate the cache, why do we need to create an instance of S3FileSystem?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

pytest-asyncio creates a new event loop for each async test. When an async-mode s3fs instance is made from async, it will be assigned to the loop from which it is made. That means that if you use s3fs again from a subsequent test, you will have the same identical instance, but be running on a different loop - which fails.

For the rest: it's very convenient to clean up the state of the store between tests, make sure we start off blank each time.

@d-v-bd-v-b left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

looks good, thank you @martindurant et al

@jhamman
jhamman merged commit 7ded5d6 into zarr-developers:v3Jun 11, 2024
AdamWill added a commit to AdamWill/zarr-python that referenced this pull request Jun 17, 2024
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
dcherian added a commit to dcherian/zarr-python that referenced this pull request Jun 25, 2024
* v3: (22 commits)
[v3] `Buffer` ensure correct subclass based on the `BufferPrototype` argument (zarr-developers#1974)
Fix doc build (zarr-developers#1987)
Fix doc build warnings (zarr-developers#1985)
Automatically generate API reference docs (zarr-developers#1918)
Update `RemoteStore.__str__` and add UPath tests (zarr-developers#1964)
[v3] Elevate codec pipeline (zarr-developers#1932)
0 dim arrays: indexing (zarr-developers#1980)
`parse_shapelike` allows 0 (zarr-developers#1979)
Clean up typing and docs for indexing (zarr-developers#1961)
add json indentation to config (zarr-developers#1952)
chore: update pre-commit hooks (zarr-developers#1973)
Bump pypa/gh-action-pypi-publish in the actions group (zarr-developers#1969)
chore: update pre-commit hooks (zarr-developers#1957)
Update release.rst (zarr-developers#1960)
doc: update release notes for 3.0.0.alpha (zarr-developers#1959)
Basic working FsspecStore (zarr-developers#1785)
Feature: Top level V3 API (zarr-developers#1884)
Buffer Prototype Argument (zarr-developers#1910)
Create issue-metrics.yml
fixes bug in transpose (zarr-developers#1949)
...
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Jan 21, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Aug 23, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[v3] remote store support (s3, gcs, azure, http)

6 participants

@martindurant@pep8speaks@d-v-b@jhamman@dstansby@normanrz
, '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

Basic working FsspecStore - #1785

Merged
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec
Jun 11, 2024
Merged

Basic working FsspecStore#1785
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec

Conversation

@martindurant

Copy link
Copy Markdown
Member

This works.

  • We don't have any list methods, do we need them?
  • We don't have a bulk delete
  • No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

Fixes#1757

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@martindurant

Copy link
Copy Markdown
MemberAuthor

@jhamman@d-v-b , for discussion

@pep8speaks

pep8speaks commented Apr 11, 2024

Copy link
Copy Markdown

Hello @martindurant! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2024-04-14 01:40:25 UTC

@d-v-b

Copy link
Copy Markdown
Contributor

thanks for this @martindurant, I will see if I have time to play with this locally.

No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

I don't think we have expectations at this point. I will try to get a distillation from the v2 issues around this topic. What do you think we should do here?

@martindurant

Copy link
Copy Markdown
MemberAuthor

I see we have no storage tests, so don't know how to push this any further.

@d-v-b

Copy link
Copy Markdown
Contributor

I will get some tests for you shortly

@jhammanjhamman added the V3 label Apr 22, 2024
@jhammanjhamman added this to the 3.0.0.alpha milestone Apr 22, 2024
@jhamman

Copy link
Copy Markdown
Member

@martindurant - the test suite is in a better place now. Are you up for picking this up?

@martindurant

Copy link
Copy Markdown
MemberAuthor

For testing ... I could set up a mock s3 or gcs with some pain and CI overhead. Also, I could wrap the fsspec memoryFS in async stuff, but that would not really be testing the async-ness and depends no me doing that correctly. None of the other stores are actually async, right?

@jhamman

Copy link
Copy Markdown
Member

@martindurant - which fsspec implementations have an async-api available?

For now, a mocked s3 backend seems like the way to go.

@martindurant

Copy link
Copy Markdown
MemberAuthor

which fsspec implementations have an async-api

I think this is a complete list

  • s3
  • gcs
  • azure (both blob and datalake2)
  • http
  • sshfs (not the builtin ssh/sftp)
  • anaconda (released version is still sync)

The following can pass through async, if they wrap an async FS:

  • generic
  • reference
  • dir/prefix

@jhamman

Copy link
Copy Markdown
Member

Got it. Makes sense. For now, let's target a mocked test against s3. We can add a few others as we approach a full release.

@martindurant

Copy link
Copy Markdown
MemberAuthor

a mocked test against s3

Well, I would use the moto server as s3fs does, which is a real S3 implementation with most of the functionality of the real one (minus permissions, object lifetimes and other unimportant things).

@jhammanjhamman 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.

@martindurant -- this is coming together. I took it for a spin today and ended up needing to make a few changes (suggestions below). But it works!

Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py
Comment threadsrc/zarr/store/remote.py
@jhammanjhamman mentioned this pull request Jun 1, 2024
@martindurant

Copy link
Copy Markdown
MemberAuthor

I merged from v3 and the suggestions above. I cannot get mypy to play.

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

Comment threadsrc/zarr/store/remote.py Outdated
@jhamman

Copy link
Copy Markdown
Member

@martindurant -- thanks for pushing this forward...

I merged from v3 and the suggestions above. I cannot get mypy to play.

I'm hoping @dstansby can take a look... we can find a way!

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

cc @madsbk, @akshaysubr, @normanrz

@martindurant

Copy link
Copy Markdown
MemberAuthor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

@d-v-b

Copy link
Copy Markdown
Contributor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

That's great insight, thank you. Please let me know if there's anything about the StoreTests design that we should change to make this process simpler.

@jhammanjhamman 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.

I see ✅!

Thanks @martindurant for working out the kinks here! (and @d-v-b and @dstansby for chipping in)

@martindurant

Copy link
Copy Markdown
MemberAuthor

Highlighting this line, which works around tests passing offset-length for data which is b"". Python allows you to slice bytes like that (b""[1:2] == b""), but remote stores do not allow this.

Comment threadsrc/zarr/store/remote.py Outdated
if byte_range
else fs._cat_file(path)
if byte_range:
# fsspec uses start/end, not start/length

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I count this as additional evidence that we should switch to start/end semantics for the rest of the stores

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Kerchunk is the exception, storing start/length, mostly because length is generally smaller for chunks in big files.

except self.exceptions:
return None
except OSError as e:
if "not satisfiable" in str(e):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

flagging this as s3 abstraction leakage that we might want to address later on by making an s3-specific storage class

Comment on lines +161 to +162
# TODO: expectations for exceptions or missing keys?
res = await self._fs._cat_ranges(list(paths), starts, stops, on_error="return")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i think returning the exceptions is the right thing here

assert [] == store.listdir(self.root + "c/d/y")
assert [] == store.listdir(self.root + "c/d/y/z")
assert [] == store.listdir(self.root + "c/e/f")
# the following is listdir(filepath), for which fsspec gives [filepath]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what's the advantage of going with POSIX semantics here?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fsspec tries to adhere to posix as much as possible. If we want to exclude the [file] case, we'd have to code that special case into our store.



@pytest.fixture(autouse=True, scope="function")
def s3(s3_base):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@martindurant could you explain what's happening in this test fixture? e.g., why do we need to manipulate the cache, why do we need to create an instance of S3FileSystem?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

pytest-asyncio creates a new event loop for each async test. When an async-mode s3fs instance is made from async, it will be assigned to the loop from which it is made. That means that if you use s3fs again from a subsequent test, you will have the same identical instance, but be running on a different loop - which fails.

For the rest: it's very convenient to clean up the state of the store between tests, make sure we start off blank each time.

@d-v-bd-v-b left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

looks good, thank you @martindurant et al

@jhamman
jhamman merged commit 7ded5d6 into zarr-developers:v3Jun 11, 2024
AdamWill added a commit to AdamWill/zarr-python that referenced this pull request Jun 17, 2024
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
dcherian added a commit to dcherian/zarr-python that referenced this pull request Jun 25, 2024
* v3: (22 commits)
[v3] `Buffer` ensure correct subclass based on the `BufferPrototype` argument (zarr-developers#1974)
Fix doc build (zarr-developers#1987)
Fix doc build warnings (zarr-developers#1985)
Automatically generate API reference docs (zarr-developers#1918)
Update `RemoteStore.__str__` and add UPath tests (zarr-developers#1964)
[v3] Elevate codec pipeline (zarr-developers#1932)
0 dim arrays: indexing (zarr-developers#1980)
`parse_shapelike` allows 0 (zarr-developers#1979)
Clean up typing and docs for indexing (zarr-developers#1961)
add json indentation to config (zarr-developers#1952)
chore: update pre-commit hooks (zarr-developers#1973)
Bump pypa/gh-action-pypi-publish in the actions group (zarr-developers#1969)
chore: update pre-commit hooks (zarr-developers#1957)
Update release.rst (zarr-developers#1960)
doc: update release notes for 3.0.0.alpha (zarr-developers#1959)
Basic working FsspecStore (zarr-developers#1785)
Feature: Top level V3 API (zarr-developers#1884)
Buffer Prototype Argument (zarr-developers#1910)
Create issue-metrics.yml
fixes bug in transpose (zarr-developers#1949)
...
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Jan 21, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Aug 23, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[v3] remote store support (s3, gcs, azure, http)

6 participants

@martindurant@pep8speaks@d-v-b@jhamman@dstansby@normanrz
, '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

Basic working FsspecStore - #1785

Merged
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec
Jun 11, 2024
Merged

Basic working FsspecStore#1785
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec

Conversation

@martindurant

Copy link
Copy Markdown
Member

This works.

  • We don't have any list methods, do we need them?
  • We don't have a bulk delete
  • No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

Fixes#1757

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@martindurant

Copy link
Copy Markdown
MemberAuthor

@jhamman@d-v-b , for discussion

@pep8speaks

pep8speaks commented Apr 11, 2024

Copy link
Copy Markdown

Hello @martindurant! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2024-04-14 01:40:25 UTC

@d-v-b

Copy link
Copy Markdown
Contributor

thanks for this @martindurant, I will see if I have time to play with this locally.

No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

I don't think we have expectations at this point. I will try to get a distillation from the v2 issues around this topic. What do you think we should do here?

@martindurant

Copy link
Copy Markdown
MemberAuthor

I see we have no storage tests, so don't know how to push this any further.

@d-v-b

Copy link
Copy Markdown
Contributor

I will get some tests for you shortly

@jhammanjhamman added the V3 label Apr 22, 2024
@jhammanjhamman added this to the 3.0.0.alpha milestone Apr 22, 2024
@jhamman

Copy link
Copy Markdown
Member

@martindurant - the test suite is in a better place now. Are you up for picking this up?

@martindurant

Copy link
Copy Markdown
MemberAuthor

For testing ... I could set up a mock s3 or gcs with some pain and CI overhead. Also, I could wrap the fsspec memoryFS in async stuff, but that would not really be testing the async-ness and depends no me doing that correctly. None of the other stores are actually async, right?

@jhamman

Copy link
Copy Markdown
Member

@martindurant - which fsspec implementations have an async-api available?

For now, a mocked s3 backend seems like the way to go.

@martindurant

Copy link
Copy Markdown
MemberAuthor

which fsspec implementations have an async-api

I think this is a complete list

  • s3
  • gcs
  • azure (both blob and datalake2)
  • http
  • sshfs (not the builtin ssh/sftp)
  • anaconda (released version is still sync)

The following can pass through async, if they wrap an async FS:

  • generic
  • reference
  • dir/prefix

@jhamman

Copy link
Copy Markdown
Member

Got it. Makes sense. For now, let's target a mocked test against s3. We can add a few others as we approach a full release.

@martindurant

Copy link
Copy Markdown
MemberAuthor

a mocked test against s3

Well, I would use the moto server as s3fs does, which is a real S3 implementation with most of the functionality of the real one (minus permissions, object lifetimes and other unimportant things).

@jhammanjhamman 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.

@martindurant -- this is coming together. I took it for a spin today and ended up needing to make a few changes (suggestions below). But it works!

Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py
Comment threadsrc/zarr/store/remote.py
@jhammanjhamman mentioned this pull request Jun 1, 2024
@martindurant

Copy link
Copy Markdown
MemberAuthor

I merged from v3 and the suggestions above. I cannot get mypy to play.

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

Comment threadsrc/zarr/store/remote.py Outdated
@jhamman

Copy link
Copy Markdown
Member

@martindurant -- thanks for pushing this forward...

I merged from v3 and the suggestions above. I cannot get mypy to play.

I'm hoping @dstansby can take a look... we can find a way!

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

cc @madsbk, @akshaysubr, @normanrz

@martindurant

Copy link
Copy Markdown
MemberAuthor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

@d-v-b

Copy link
Copy Markdown
Contributor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

That's great insight, thank you. Please let me know if there's anything about the StoreTests design that we should change to make this process simpler.

@jhammanjhamman 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.

I see ✅!

Thanks @martindurant for working out the kinks here! (and @d-v-b and @dstansby for chipping in)

@martindurant

Copy link
Copy Markdown
MemberAuthor

Highlighting this line, which works around tests passing offset-length for data which is b"". Python allows you to slice bytes like that (b""[1:2] == b""), but remote stores do not allow this.

Comment threadsrc/zarr/store/remote.py Outdated
if byte_range
else fs._cat_file(path)
if byte_range:
# fsspec uses start/end, not start/length

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I count this as additional evidence that we should switch to start/end semantics for the rest of the stores

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Kerchunk is the exception, storing start/length, mostly because length is generally smaller for chunks in big files.

except self.exceptions:
return None
except OSError as e:
if "not satisfiable" in str(e):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

flagging this as s3 abstraction leakage that we might want to address later on by making an s3-specific storage class

Comment on lines +161 to +162
# TODO: expectations for exceptions or missing keys?
res = await self._fs._cat_ranges(list(paths), starts, stops, on_error="return")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i think returning the exceptions is the right thing here

assert [] == store.listdir(self.root + "c/d/y")
assert [] == store.listdir(self.root + "c/d/y/z")
assert [] == store.listdir(self.root + "c/e/f")
# the following is listdir(filepath), for which fsspec gives [filepath]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what's the advantage of going with POSIX semantics here?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fsspec tries to adhere to posix as much as possible. If we want to exclude the [file] case, we'd have to code that special case into our store.



@pytest.fixture(autouse=True, scope="function")
def s3(s3_base):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@martindurant could you explain what's happening in this test fixture? e.g., why do we need to manipulate the cache, why do we need to create an instance of S3FileSystem?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

pytest-asyncio creates a new event loop for each async test. When an async-mode s3fs instance is made from async, it will be assigned to the loop from which it is made. That means that if you use s3fs again from a subsequent test, you will have the same identical instance, but be running on a different loop - which fails.

For the rest: it's very convenient to clean up the state of the store between tests, make sure we start off blank each time.

@d-v-bd-v-b left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

looks good, thank you @martindurant et al

@jhamman
jhamman merged commit 7ded5d6 into zarr-developers:v3Jun 11, 2024
AdamWill added a commit to AdamWill/zarr-python that referenced this pull request Jun 17, 2024
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
dcherian added a commit to dcherian/zarr-python that referenced this pull request Jun 25, 2024
* v3: (22 commits)
[v3] `Buffer` ensure correct subclass based on the `BufferPrototype` argument (zarr-developers#1974)
Fix doc build (zarr-developers#1987)
Fix doc build warnings (zarr-developers#1985)
Automatically generate API reference docs (zarr-developers#1918)
Update `RemoteStore.__str__` and add UPath tests (zarr-developers#1964)
[v3] Elevate codec pipeline (zarr-developers#1932)
0 dim arrays: indexing (zarr-developers#1980)
`parse_shapelike` allows 0 (zarr-developers#1979)
Clean up typing and docs for indexing (zarr-developers#1961)
add json indentation to config (zarr-developers#1952)
chore: update pre-commit hooks (zarr-developers#1973)
Bump pypa/gh-action-pypi-publish in the actions group (zarr-developers#1969)
chore: update pre-commit hooks (zarr-developers#1957)
Update release.rst (zarr-developers#1960)
doc: update release notes for 3.0.0.alpha (zarr-developers#1959)
Basic working FsspecStore (zarr-developers#1785)
Feature: Top level V3 API (zarr-developers#1884)
Buffer Prototype Argument (zarr-developers#1910)
Create issue-metrics.yml
fixes bug in transpose (zarr-developers#1949)
...
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Jan 21, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Aug 23, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[v3] remote store support (s3, gcs, azure, http)

6 participants

@martindurant@pep8speaks@d-v-b@jhamman@dstansby@normanrz
, '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

Basic working FsspecStore - #1785

Merged
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec
Jun 11, 2024
Merged

Basic working FsspecStore#1785
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec

Conversation

@martindurant

Copy link
Copy Markdown
Member

This works.

  • We don't have any list methods, do we need them?
  • We don't have a bulk delete
  • No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

Fixes#1757

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@martindurant

Copy link
Copy Markdown
MemberAuthor

@jhamman@d-v-b , for discussion

@pep8speaks

pep8speaks commented Apr 11, 2024

Copy link
Copy Markdown

Hello @martindurant! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2024-04-14 01:40:25 UTC

@d-v-b

Copy link
Copy Markdown
Contributor

thanks for this @martindurant, I will see if I have time to play with this locally.

No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

I don't think we have expectations at this point. I will try to get a distillation from the v2 issues around this topic. What do you think we should do here?

@martindurant

Copy link
Copy Markdown
MemberAuthor

I see we have no storage tests, so don't know how to push this any further.

@d-v-b

Copy link
Copy Markdown
Contributor

I will get some tests for you shortly

@jhammanjhamman added the V3 label Apr 22, 2024
@jhammanjhamman added this to the 3.0.0.alpha milestone Apr 22, 2024
@jhamman

Copy link
Copy Markdown
Member

@martindurant - the test suite is in a better place now. Are you up for picking this up?

@martindurant

Copy link
Copy Markdown
MemberAuthor

For testing ... I could set up a mock s3 or gcs with some pain and CI overhead. Also, I could wrap the fsspec memoryFS in async stuff, but that would not really be testing the async-ness and depends no me doing that correctly. None of the other stores are actually async, right?

@jhamman

Copy link
Copy Markdown
Member

@martindurant - which fsspec implementations have an async-api available?

For now, a mocked s3 backend seems like the way to go.

@martindurant

Copy link
Copy Markdown
MemberAuthor

which fsspec implementations have an async-api

I think this is a complete list

  • s3
  • gcs
  • azure (both blob and datalake2)
  • http
  • sshfs (not the builtin ssh/sftp)
  • anaconda (released version is still sync)

The following can pass through async, if they wrap an async FS:

  • generic
  • reference
  • dir/prefix

@jhamman

Copy link
Copy Markdown
Member

Got it. Makes sense. For now, let's target a mocked test against s3. We can add a few others as we approach a full release.

@martindurant

Copy link
Copy Markdown
MemberAuthor

a mocked test against s3

Well, I would use the moto server as s3fs does, which is a real S3 implementation with most of the functionality of the real one (minus permissions, object lifetimes and other unimportant things).

@jhammanjhamman 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.

@martindurant -- this is coming together. I took it for a spin today and ended up needing to make a few changes (suggestions below). But it works!

Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py
Comment threadsrc/zarr/store/remote.py
@jhammanjhamman mentioned this pull request Jun 1, 2024
@martindurant

Copy link
Copy Markdown
MemberAuthor

I merged from v3 and the suggestions above. I cannot get mypy to play.

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

Comment threadsrc/zarr/store/remote.py Outdated
@jhamman

Copy link
Copy Markdown
Member

@martindurant -- thanks for pushing this forward...

I merged from v3 and the suggestions above. I cannot get mypy to play.

I'm hoping @dstansby can take a look... we can find a way!

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

cc @madsbk, @akshaysubr, @normanrz

@martindurant

Copy link
Copy Markdown
MemberAuthor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

@d-v-b

Copy link
Copy Markdown
Contributor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

That's great insight, thank you. Please let me know if there's anything about the StoreTests design that we should change to make this process simpler.

@jhammanjhamman 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.

I see ✅!

Thanks @martindurant for working out the kinks here! (and @d-v-b and @dstansby for chipping in)

@martindurant

Copy link
Copy Markdown
MemberAuthor

Highlighting this line, which works around tests passing offset-length for data which is b"". Python allows you to slice bytes like that (b""[1:2] == b""), but remote stores do not allow this.

Comment threadsrc/zarr/store/remote.py Outdated
if byte_range
else fs._cat_file(path)
if byte_range:
# fsspec uses start/end, not start/length

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I count this as additional evidence that we should switch to start/end semantics for the rest of the stores

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Kerchunk is the exception, storing start/length, mostly because length is generally smaller for chunks in big files.

except self.exceptions:
return None
except OSError as e:
if "not satisfiable" in str(e):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

flagging this as s3 abstraction leakage that we might want to address later on by making an s3-specific storage class

Comment on lines +161 to +162
# TODO: expectations for exceptions or missing keys?
res = await self._fs._cat_ranges(list(paths), starts, stops, on_error="return")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i think returning the exceptions is the right thing here

assert [] == store.listdir(self.root + "c/d/y")
assert [] == store.listdir(self.root + "c/d/y/z")
assert [] == store.listdir(self.root + "c/e/f")
# the following is listdir(filepath), for which fsspec gives [filepath]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what's the advantage of going with POSIX semantics here?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fsspec tries to adhere to posix as much as possible. If we want to exclude the [file] case, we'd have to code that special case into our store.



@pytest.fixture(autouse=True, scope="function")
def s3(s3_base):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@martindurant could you explain what's happening in this test fixture? e.g., why do we need to manipulate the cache, why do we need to create an instance of S3FileSystem?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

pytest-asyncio creates a new event loop for each async test. When an async-mode s3fs instance is made from async, it will be assigned to the loop from which it is made. That means that if you use s3fs again from a subsequent test, you will have the same identical instance, but be running on a different loop - which fails.

For the rest: it's very convenient to clean up the state of the store between tests, make sure we start off blank each time.

@d-v-bd-v-b left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

looks good, thank you @martindurant et al

@jhamman
jhamman merged commit 7ded5d6 into zarr-developers:v3Jun 11, 2024
AdamWill added a commit to AdamWill/zarr-python that referenced this pull request Jun 17, 2024
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
dcherian added a commit to dcherian/zarr-python that referenced this pull request Jun 25, 2024
* v3: (22 commits)
[v3] `Buffer` ensure correct subclass based on the `BufferPrototype` argument (zarr-developers#1974)
Fix doc build (zarr-developers#1987)
Fix doc build warnings (zarr-developers#1985)
Automatically generate API reference docs (zarr-developers#1918)
Update `RemoteStore.__str__` and add UPath tests (zarr-developers#1964)
[v3] Elevate codec pipeline (zarr-developers#1932)
0 dim arrays: indexing (zarr-developers#1980)
`parse_shapelike` allows 0 (zarr-developers#1979)
Clean up typing and docs for indexing (zarr-developers#1961)
add json indentation to config (zarr-developers#1952)
chore: update pre-commit hooks (zarr-developers#1973)
Bump pypa/gh-action-pypi-publish in the actions group (zarr-developers#1969)
chore: update pre-commit hooks (zarr-developers#1957)
Update release.rst (zarr-developers#1960)
doc: update release notes for 3.0.0.alpha (zarr-developers#1959)
Basic working FsspecStore (zarr-developers#1785)
Feature: Top level V3 API (zarr-developers#1884)
Buffer Prototype Argument (zarr-developers#1910)
Create issue-metrics.yml
fixes bug in transpose (zarr-developers#1949)
...
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Jan 21, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Aug 23, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[v3] remote store support (s3, gcs, azure, http)

6 participants

@martindurant@pep8speaks@d-v-b@jhamman@dstansby@normanrz
, '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

Basic working FsspecStore - #1785

Merged
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec
Jun 11, 2024
Merged

Basic working FsspecStore#1785
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec

Conversation

@martindurant

Copy link
Copy Markdown
Member

This works.

  • We don't have any list methods, do we need them?
  • We don't have a bulk delete
  • No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

Fixes#1757

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@martindurant

Copy link
Copy Markdown
MemberAuthor

@jhamman@d-v-b , for discussion

@pep8speaks

pep8speaks commented Apr 11, 2024

Copy link
Copy Markdown

Hello @martindurant! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2024-04-14 01:40:25 UTC

@d-v-b

Copy link
Copy Markdown
Contributor

thanks for this @martindurant, I will see if I have time to play with this locally.

No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

I don't think we have expectations at this point. I will try to get a distillation from the v2 issues around this topic. What do you think we should do here?

@martindurant

Copy link
Copy Markdown
MemberAuthor

I see we have no storage tests, so don't know how to push this any further.

@d-v-b

Copy link
Copy Markdown
Contributor

I will get some tests for you shortly

@jhammanjhamman added the V3 label Apr 22, 2024
@jhammanjhamman added this to the 3.0.0.alpha milestone Apr 22, 2024
@jhamman

Copy link
Copy Markdown
Member

@martindurant - the test suite is in a better place now. Are you up for picking this up?

@martindurant

Copy link
Copy Markdown
MemberAuthor

For testing ... I could set up a mock s3 or gcs with some pain and CI overhead. Also, I could wrap the fsspec memoryFS in async stuff, but that would not really be testing the async-ness and depends no me doing that correctly. None of the other stores are actually async, right?

@jhamman

Copy link
Copy Markdown
Member

@martindurant - which fsspec implementations have an async-api available?

For now, a mocked s3 backend seems like the way to go.

@martindurant

Copy link
Copy Markdown
MemberAuthor

which fsspec implementations have an async-api

I think this is a complete list

  • s3
  • gcs
  • azure (both blob and datalake2)
  • http
  • sshfs (not the builtin ssh/sftp)
  • anaconda (released version is still sync)

The following can pass through async, if they wrap an async FS:

  • generic
  • reference
  • dir/prefix

@jhamman

Copy link
Copy Markdown
Member

Got it. Makes sense. For now, let's target a mocked test against s3. We can add a few others as we approach a full release.

@martindurant

Copy link
Copy Markdown
MemberAuthor

a mocked test against s3

Well, I would use the moto server as s3fs does, which is a real S3 implementation with most of the functionality of the real one (minus permissions, object lifetimes and other unimportant things).

@jhammanjhamman 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.

@martindurant -- this is coming together. I took it for a spin today and ended up needing to make a few changes (suggestions below). But it works!

Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py
Comment threadsrc/zarr/store/remote.py
@jhammanjhamman mentioned this pull request Jun 1, 2024
@martindurant

Copy link
Copy Markdown
MemberAuthor

I merged from v3 and the suggestions above. I cannot get mypy to play.

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

Comment threadsrc/zarr/store/remote.py Outdated
@jhamman

Copy link
Copy Markdown
Member

@martindurant -- thanks for pushing this forward...

I merged from v3 and the suggestions above. I cannot get mypy to play.

I'm hoping @dstansby can take a look... we can find a way!

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

cc @madsbk, @akshaysubr, @normanrz

@martindurant

Copy link
Copy Markdown
MemberAuthor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

@d-v-b

Copy link
Copy Markdown
Contributor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

That's great insight, thank you. Please let me know if there's anything about the StoreTests design that we should change to make this process simpler.

@jhammanjhamman 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.

I see ✅!

Thanks @martindurant for working out the kinks here! (and @d-v-b and @dstansby for chipping in)

@martindurant

Copy link
Copy Markdown
MemberAuthor

Highlighting this line, which works around tests passing offset-length for data which is b"". Python allows you to slice bytes like that (b""[1:2] == b""), but remote stores do not allow this.

Comment threadsrc/zarr/store/remote.py Outdated
if byte_range
else fs._cat_file(path)
if byte_range:
# fsspec uses start/end, not start/length

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I count this as additional evidence that we should switch to start/end semantics for the rest of the stores

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Kerchunk is the exception, storing start/length, mostly because length is generally smaller for chunks in big files.

except self.exceptions:
return None
except OSError as e:
if "not satisfiable" in str(e):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

flagging this as s3 abstraction leakage that we might want to address later on by making an s3-specific storage class

Comment on lines +161 to +162
# TODO: expectations for exceptions or missing keys?
res = await self._fs._cat_ranges(list(paths), starts, stops, on_error="return")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i think returning the exceptions is the right thing here

assert [] == store.listdir(self.root + "c/d/y")
assert [] == store.listdir(self.root + "c/d/y/z")
assert [] == store.listdir(self.root + "c/e/f")
# the following is listdir(filepath), for which fsspec gives [filepath]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what's the advantage of going with POSIX semantics here?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fsspec tries to adhere to posix as much as possible. If we want to exclude the [file] case, we'd have to code that special case into our store.



@pytest.fixture(autouse=True, scope="function")
def s3(s3_base):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@martindurant could you explain what's happening in this test fixture? e.g., why do we need to manipulate the cache, why do we need to create an instance of S3FileSystem?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

pytest-asyncio creates a new event loop for each async test. When an async-mode s3fs instance is made from async, it will be assigned to the loop from which it is made. That means that if you use s3fs again from a subsequent test, you will have the same identical instance, but be running on a different loop - which fails.

For the rest: it's very convenient to clean up the state of the store between tests, make sure we start off blank each time.

@d-v-bd-v-b left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

looks good, thank you @martindurant et al

@jhamman
jhamman merged commit 7ded5d6 into zarr-developers:v3Jun 11, 2024
AdamWill added a commit to AdamWill/zarr-python that referenced this pull request Jun 17, 2024
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
dcherian added a commit to dcherian/zarr-python that referenced this pull request Jun 25, 2024
* v3: (22 commits)
[v3] `Buffer` ensure correct subclass based on the `BufferPrototype` argument (zarr-developers#1974)
Fix doc build (zarr-developers#1987)
Fix doc build warnings (zarr-developers#1985)
Automatically generate API reference docs (zarr-developers#1918)
Update `RemoteStore.__str__` and add UPath tests (zarr-developers#1964)
[v3] Elevate codec pipeline (zarr-developers#1932)
0 dim arrays: indexing (zarr-developers#1980)
`parse_shapelike` allows 0 (zarr-developers#1979)
Clean up typing and docs for indexing (zarr-developers#1961)
add json indentation to config (zarr-developers#1952)
chore: update pre-commit hooks (zarr-developers#1973)
Bump pypa/gh-action-pypi-publish in the actions group (zarr-developers#1969)
chore: update pre-commit hooks (zarr-developers#1957)
Update release.rst (zarr-developers#1960)
doc: update release notes for 3.0.0.alpha (zarr-developers#1959)
Basic working FsspecStore (zarr-developers#1785)
Feature: Top level V3 API (zarr-developers#1884)
Buffer Prototype Argument (zarr-developers#1910)
Create issue-metrics.yml
fixes bug in transpose (zarr-developers#1949)
...
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Jan 21, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Aug 23, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[v3] remote store support (s3, gcs, azure, http)

6 participants

@martindurant@pep8speaks@d-v-b@jhamman@dstansby@normanrz
, '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

Basic working FsspecStore - #1785

Merged
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec
Jun 11, 2024
Merged

Basic working FsspecStore#1785
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec

Conversation

@martindurant

Copy link
Copy Markdown
Member

This works.

  • We don't have any list methods, do we need them?
  • We don't have a bulk delete
  • No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

Fixes#1757

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@martindurant

Copy link
Copy Markdown
MemberAuthor

@jhamman@d-v-b , for discussion

@pep8speaks

pep8speaks commented Apr 11, 2024

Copy link
Copy Markdown

Hello @martindurant! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2024-04-14 01:40:25 UTC

@d-v-b

Copy link
Copy Markdown
Contributor

thanks for this @martindurant, I will see if I have time to play with this locally.

No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

I don't think we have expectations at this point. I will try to get a distillation from the v2 issues around this topic. What do you think we should do here?

@martindurant

Copy link
Copy Markdown
MemberAuthor

I see we have no storage tests, so don't know how to push this any further.

@d-v-b

Copy link
Copy Markdown
Contributor

I will get some tests for you shortly

@jhammanjhamman added the V3 label Apr 22, 2024
@jhammanjhamman added this to the 3.0.0.alpha milestone Apr 22, 2024
@jhamman

Copy link
Copy Markdown
Member

@martindurant - the test suite is in a better place now. Are you up for picking this up?

@martindurant

Copy link
Copy Markdown
MemberAuthor

For testing ... I could set up a mock s3 or gcs with some pain and CI overhead. Also, I could wrap the fsspec memoryFS in async stuff, but that would not really be testing the async-ness and depends no me doing that correctly. None of the other stores are actually async, right?

@jhamman

Copy link
Copy Markdown
Member

@martindurant - which fsspec implementations have an async-api available?

For now, a mocked s3 backend seems like the way to go.

@martindurant

Copy link
Copy Markdown
MemberAuthor

which fsspec implementations have an async-api

I think this is a complete list

  • s3
  • gcs
  • azure (both blob and datalake2)
  • http
  • sshfs (not the builtin ssh/sftp)
  • anaconda (released version is still sync)

The following can pass through async, if they wrap an async FS:

  • generic
  • reference
  • dir/prefix

@jhamman

Copy link
Copy Markdown
Member

Got it. Makes sense. For now, let's target a mocked test against s3. We can add a few others as we approach a full release.

@martindurant

Copy link
Copy Markdown
MemberAuthor

a mocked test against s3

Well, I would use the moto server as s3fs does, which is a real S3 implementation with most of the functionality of the real one (minus permissions, object lifetimes and other unimportant things).

@jhammanjhamman 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.

@martindurant -- this is coming together. I took it for a spin today and ended up needing to make a few changes (suggestions below). But it works!

Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py
Comment threadsrc/zarr/store/remote.py
@jhammanjhamman mentioned this pull request Jun 1, 2024
@martindurant

Copy link
Copy Markdown
MemberAuthor

I merged from v3 and the suggestions above. I cannot get mypy to play.

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

Comment threadsrc/zarr/store/remote.py Outdated
@jhamman

Copy link
Copy Markdown
Member

@martindurant -- thanks for pushing this forward...

I merged from v3 and the suggestions above. I cannot get mypy to play.

I'm hoping @dstansby can take a look... we can find a way!

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

cc @madsbk, @akshaysubr, @normanrz

@martindurant

Copy link
Copy Markdown
MemberAuthor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

@d-v-b

Copy link
Copy Markdown
Contributor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

That's great insight, thank you. Please let me know if there's anything about the StoreTests design that we should change to make this process simpler.

@jhammanjhamman 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.

I see ✅!

Thanks @martindurant for working out the kinks here! (and @d-v-b and @dstansby for chipping in)

@martindurant

Copy link
Copy Markdown
MemberAuthor

Highlighting this line, which works around tests passing offset-length for data which is b"". Python allows you to slice bytes like that (b""[1:2] == b""), but remote stores do not allow this.

Comment threadsrc/zarr/store/remote.py Outdated
if byte_range
else fs._cat_file(path)
if byte_range:
# fsspec uses start/end, not start/length

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I count this as additional evidence that we should switch to start/end semantics for the rest of the stores

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Kerchunk is the exception, storing start/length, mostly because length is generally smaller for chunks in big files.

except self.exceptions:
return None
except OSError as e:
if "not satisfiable" in str(e):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

flagging this as s3 abstraction leakage that we might want to address later on by making an s3-specific storage class

Comment on lines +161 to +162
# TODO: expectations for exceptions or missing keys?
res = await self._fs._cat_ranges(list(paths), starts, stops, on_error="return")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i think returning the exceptions is the right thing here

assert [] == store.listdir(self.root + "c/d/y")
assert [] == store.listdir(self.root + "c/d/y/z")
assert [] == store.listdir(self.root + "c/e/f")
# the following is listdir(filepath), for which fsspec gives [filepath]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what's the advantage of going with POSIX semantics here?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fsspec tries to adhere to posix as much as possible. If we want to exclude the [file] case, we'd have to code that special case into our store.



@pytest.fixture(autouse=True, scope="function")
def s3(s3_base):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@martindurant could you explain what's happening in this test fixture? e.g., why do we need to manipulate the cache, why do we need to create an instance of S3FileSystem?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

pytest-asyncio creates a new event loop for each async test. When an async-mode s3fs instance is made from async, it will be assigned to the loop from which it is made. That means that if you use s3fs again from a subsequent test, you will have the same identical instance, but be running on a different loop - which fails.

For the rest: it's very convenient to clean up the state of the store between tests, make sure we start off blank each time.

@d-v-bd-v-b left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

looks good, thank you @martindurant et al

@jhamman
jhamman merged commit 7ded5d6 into zarr-developers:v3Jun 11, 2024
AdamWill added a commit to AdamWill/zarr-python that referenced this pull request Jun 17, 2024
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
dcherian added a commit to dcherian/zarr-python that referenced this pull request Jun 25, 2024
* v3: (22 commits)
[v3] `Buffer` ensure correct subclass based on the `BufferPrototype` argument (zarr-developers#1974)
Fix doc build (zarr-developers#1987)
Fix doc build warnings (zarr-developers#1985)
Automatically generate API reference docs (zarr-developers#1918)
Update `RemoteStore.__str__` and add UPath tests (zarr-developers#1964)
[v3] Elevate codec pipeline (zarr-developers#1932)
0 dim arrays: indexing (zarr-developers#1980)
`parse_shapelike` allows 0 (zarr-developers#1979)
Clean up typing and docs for indexing (zarr-developers#1961)
add json indentation to config (zarr-developers#1952)
chore: update pre-commit hooks (zarr-developers#1973)
Bump pypa/gh-action-pypi-publish in the actions group (zarr-developers#1969)
chore: update pre-commit hooks (zarr-developers#1957)
Update release.rst (zarr-developers#1960)
doc: update release notes for 3.0.0.alpha (zarr-developers#1959)
Basic working FsspecStore (zarr-developers#1785)
Feature: Top level V3 API (zarr-developers#1884)
Buffer Prototype Argument (zarr-developers#1910)
Create issue-metrics.yml
fixes bug in transpose (zarr-developers#1949)
...
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Jan 21, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Aug 23, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[v3] remote store support (s3, gcs, azure, http)

6 participants

@martindurant@pep8speaks@d-v-b@jhamman@dstansby@normanrz
, '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

Basic working FsspecStore - #1785

Merged
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec
Jun 11, 2024
Merged

Basic working FsspecStore#1785
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec

Conversation

@martindurant

Copy link
Copy Markdown
Member

This works.

  • We don't have any list methods, do we need them?
  • We don't have a bulk delete
  • No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

Fixes#1757

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@martindurant

Copy link
Copy Markdown
MemberAuthor

@jhamman@d-v-b , for discussion

@pep8speaks

pep8speaks commented Apr 11, 2024

Copy link
Copy Markdown

Hello @martindurant! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2024-04-14 01:40:25 UTC

@d-v-b

Copy link
Copy Markdown
Contributor

thanks for this @martindurant, I will see if I have time to play with this locally.

No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

I don't think we have expectations at this point. I will try to get a distillation from the v2 issues around this topic. What do you think we should do here?

@martindurant

Copy link
Copy Markdown
MemberAuthor

I see we have no storage tests, so don't know how to push this any further.

@d-v-b

Copy link
Copy Markdown
Contributor

I will get some tests for you shortly

@jhammanjhamman added the V3 label Apr 22, 2024
@jhammanjhamman added this to the 3.0.0.alpha milestone Apr 22, 2024
@jhamman

Copy link
Copy Markdown
Member

@martindurant - the test suite is in a better place now. Are you up for picking this up?

@martindurant

Copy link
Copy Markdown
MemberAuthor

For testing ... I could set up a mock s3 or gcs with some pain and CI overhead. Also, I could wrap the fsspec memoryFS in async stuff, but that would not really be testing the async-ness and depends no me doing that correctly. None of the other stores are actually async, right?

@jhamman

Copy link
Copy Markdown
Member

@martindurant - which fsspec implementations have an async-api available?

For now, a mocked s3 backend seems like the way to go.

@martindurant

Copy link
Copy Markdown
MemberAuthor

which fsspec implementations have an async-api

I think this is a complete list

  • s3
  • gcs
  • azure (both blob and datalake2)
  • http
  • sshfs (not the builtin ssh/sftp)
  • anaconda (released version is still sync)

The following can pass through async, if they wrap an async FS:

  • generic
  • reference
  • dir/prefix

@jhamman

Copy link
Copy Markdown
Member

Got it. Makes sense. For now, let's target a mocked test against s3. We can add a few others as we approach a full release.

@martindurant

Copy link
Copy Markdown
MemberAuthor

a mocked test against s3

Well, I would use the moto server as s3fs does, which is a real S3 implementation with most of the functionality of the real one (minus permissions, object lifetimes and other unimportant things).

@jhammanjhamman 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.

@martindurant -- this is coming together. I took it for a spin today and ended up needing to make a few changes (suggestions below). But it works!

Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py
Comment threadsrc/zarr/store/remote.py
@jhammanjhamman mentioned this pull request Jun 1, 2024
@martindurant

Copy link
Copy Markdown
MemberAuthor

I merged from v3 and the suggestions above. I cannot get mypy to play.

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

Comment threadsrc/zarr/store/remote.py Outdated
@jhamman

Copy link
Copy Markdown
Member

@martindurant -- thanks for pushing this forward...

I merged from v3 and the suggestions above. I cannot get mypy to play.

I'm hoping @dstansby can take a look... we can find a way!

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

cc @madsbk, @akshaysubr, @normanrz

@martindurant

Copy link
Copy Markdown
MemberAuthor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

@d-v-b

Copy link
Copy Markdown
Contributor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

That's great insight, thank you. Please let me know if there's anything about the StoreTests design that we should change to make this process simpler.

@jhammanjhamman 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.

I see ✅!

Thanks @martindurant for working out the kinks here! (and @d-v-b and @dstansby for chipping in)

@martindurant

Copy link
Copy Markdown
MemberAuthor

Highlighting this line, which works around tests passing offset-length for data which is b"". Python allows you to slice bytes like that (b""[1:2] == b""), but remote stores do not allow this.

Comment threadsrc/zarr/store/remote.py Outdated
if byte_range
else fs._cat_file(path)
if byte_range:
# fsspec uses start/end, not start/length

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I count this as additional evidence that we should switch to start/end semantics for the rest of the stores

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Kerchunk is the exception, storing start/length, mostly because length is generally smaller for chunks in big files.

except self.exceptions:
return None
except OSError as e:
if "not satisfiable" in str(e):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

flagging this as s3 abstraction leakage that we might want to address later on by making an s3-specific storage class

Comment on lines +161 to +162
# TODO: expectations for exceptions or missing keys?
res = await self._fs._cat_ranges(list(paths), starts, stops, on_error="return")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i think returning the exceptions is the right thing here

assert [] == store.listdir(self.root + "c/d/y")
assert [] == store.listdir(self.root + "c/d/y/z")
assert [] == store.listdir(self.root + "c/e/f")
# the following is listdir(filepath), for which fsspec gives [filepath]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what's the advantage of going with POSIX semantics here?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fsspec tries to adhere to posix as much as possible. If we want to exclude the [file] case, we'd have to code that special case into our store.



@pytest.fixture(autouse=True, scope="function")
def s3(s3_base):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@martindurant could you explain what's happening in this test fixture? e.g., why do we need to manipulate the cache, why do we need to create an instance of S3FileSystem?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

pytest-asyncio creates a new event loop for each async test. When an async-mode s3fs instance is made from async, it will be assigned to the loop from which it is made. That means that if you use s3fs again from a subsequent test, you will have the same identical instance, but be running on a different loop - which fails.

For the rest: it's very convenient to clean up the state of the store between tests, make sure we start off blank each time.

@d-v-bd-v-b left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

looks good, thank you @martindurant et al

@jhamman
jhamman merged commit 7ded5d6 into zarr-developers:v3Jun 11, 2024
AdamWill added a commit to AdamWill/zarr-python that referenced this pull request Jun 17, 2024
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
dcherian added a commit to dcherian/zarr-python that referenced this pull request Jun 25, 2024
* v3: (22 commits)
[v3] `Buffer` ensure correct subclass based on the `BufferPrototype` argument (zarr-developers#1974)
Fix doc build (zarr-developers#1987)
Fix doc build warnings (zarr-developers#1985)
Automatically generate API reference docs (zarr-developers#1918)
Update `RemoteStore.__str__` and add UPath tests (zarr-developers#1964)
[v3] Elevate codec pipeline (zarr-developers#1932)
0 dim arrays: indexing (zarr-developers#1980)
`parse_shapelike` allows 0 (zarr-developers#1979)
Clean up typing and docs for indexing (zarr-developers#1961)
add json indentation to config (zarr-developers#1952)
chore: update pre-commit hooks (zarr-developers#1973)
Bump pypa/gh-action-pypi-publish in the actions group (zarr-developers#1969)
chore: update pre-commit hooks (zarr-developers#1957)
Update release.rst (zarr-developers#1960)
doc: update release notes for 3.0.0.alpha (zarr-developers#1959)
Basic working FsspecStore (zarr-developers#1785)
Feature: Top level V3 API (zarr-developers#1884)
Buffer Prototype Argument (zarr-developers#1910)
Create issue-metrics.yml
fixes bug in transpose (zarr-developers#1949)
...
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Jan 21, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Aug 23, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[v3] remote store support (s3, gcs, azure, http)

6 participants

@martindurant@pep8speaks@d-v-b@jhamman@dstansby@normanrz
, '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

Basic working FsspecStore - #1785

Merged
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec
Jun 11, 2024
Merged

Basic working FsspecStore#1785
jhamman merged 36 commits into
zarr-developers:v3from
martindurant:v3_fsspec

Conversation

@martindurant

Copy link
Copy Markdown
Member

This works.

  • We don't have any list methods, do we need them?
  • We don't have a bulk delete
  • No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

Fixes#1757

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@martindurant

Copy link
Copy Markdown
MemberAuthor

@jhamman@d-v-b , for discussion

@pep8speaks

pep8speaks commented Apr 11, 2024

Copy link
Copy Markdown

Hello @martindurant! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2024-04-14 01:40:25 UTC

@d-v-b

Copy link
Copy Markdown
Contributor

thanks for this @martindurant, I will see if I have time to play with this locally.

No exception handling is done here, which has been a thorny issue. Shall we do the same as in v2 with expected exceptions -> KeyError? I don't see in Store's API what the expectation is.

I don't think we have expectations at this point. I will try to get a distillation from the v2 issues around this topic. What do you think we should do here?

@martindurant

Copy link
Copy Markdown
MemberAuthor

I see we have no storage tests, so don't know how to push this any further.

@d-v-b

Copy link
Copy Markdown
Contributor

I will get some tests for you shortly

@jhammanjhamman added the V3 label Apr 22, 2024
@jhammanjhamman added this to the 3.0.0.alpha milestone Apr 22, 2024
@jhamman

Copy link
Copy Markdown
Member

@martindurant - the test suite is in a better place now. Are you up for picking this up?

@martindurant

Copy link
Copy Markdown
MemberAuthor

For testing ... I could set up a mock s3 or gcs with some pain and CI overhead. Also, I could wrap the fsspec memoryFS in async stuff, but that would not really be testing the async-ness and depends no me doing that correctly. None of the other stores are actually async, right?

@jhamman

Copy link
Copy Markdown
Member

@martindurant - which fsspec implementations have an async-api available?

For now, a mocked s3 backend seems like the way to go.

@martindurant

Copy link
Copy Markdown
MemberAuthor

which fsspec implementations have an async-api

I think this is a complete list

  • s3
  • gcs
  • azure (both blob and datalake2)
  • http
  • sshfs (not the builtin ssh/sftp)
  • anaconda (released version is still sync)

The following can pass through async, if they wrap an async FS:

  • generic
  • reference
  • dir/prefix

@jhamman

Copy link
Copy Markdown
Member

Got it. Makes sense. For now, let's target a mocked test against s3. We can add a few others as we approach a full release.

@martindurant

Copy link
Copy Markdown
MemberAuthor

a mocked test against s3

Well, I would use the moto server as s3fs does, which is a real S3 implementation with most of the functionality of the real one (minus permissions, object lifetimes and other unimportant things).

@jhammanjhamman 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.

@martindurant -- this is coming together. I took it for a spin today and ended up needing to make a few changes (suggestions below). But it works!

Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py Outdated
Comment threadsrc/zarr/store/remote.py
Comment threadsrc/zarr/store/remote.py
@jhammanjhamman mentioned this pull request Jun 1, 2024
@martindurant

Copy link
Copy Markdown
MemberAuthor

I merged from v3 and the suggestions above. I cannot get mypy to play.

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

Comment threadsrc/zarr/store/remote.py Outdated
@jhamman

Copy link
Copy Markdown
Member

@martindurant -- thanks for pushing this forward...

I merged from v3 and the suggestions above. I cannot get mypy to play.

I'm hoping @dstansby can take a look... we can find a way!

By the way, I would suggest that memoryview() and bytes() really ought to work as expected for a Buffer.

cc @madsbk, @akshaysubr, @normanrz

@martindurant

Copy link
Copy Markdown
MemberAuthor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

@d-v-b

Copy link
Copy Markdown
Contributor

OK, so the problem with the tests, is that they call get/set in blocking sync code, but the store implementation works in async mode. The test instance is created in sync mode, and gets put on a dedicated fsspec IO thread; but then the async store on the main thread calls the same instance in async mode. Note that moto3 is also running on a thread, to complicate things. I am looking at it.

That's great insight, thank you. Please let me know if there's anything about the StoreTests design that we should change to make this process simpler.

@jhammanjhamman 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.

I see ✅!

Thanks @martindurant for working out the kinks here! (and @d-v-b and @dstansby for chipping in)

@martindurant

Copy link
Copy Markdown
MemberAuthor

Highlighting this line, which works around tests passing offset-length for data which is b"". Python allows you to slice bytes like that (b""[1:2] == b""), but remote stores do not allow this.

Comment threadsrc/zarr/store/remote.py Outdated
if byte_range
else fs._cat_file(path)
if byte_range:
# fsspec uses start/end, not start/length

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I count this as additional evidence that we should switch to start/end semantics for the rest of the stores

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Kerchunk is the exception, storing start/length, mostly because length is generally smaller for chunks in big files.

except self.exceptions:
return None
except OSError as e:
if "not satisfiable" in str(e):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

flagging this as s3 abstraction leakage that we might want to address later on by making an s3-specific storage class

Comment on lines +161 to +162
# TODO: expectations for exceptions or missing keys?
res = await self._fs._cat_ranges(list(paths), starts, stops, on_error="return")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i think returning the exceptions is the right thing here

assert [] == store.listdir(self.root + "c/d/y")
assert [] == store.listdir(self.root + "c/d/y/z")
assert [] == store.listdir(self.root + "c/e/f")
# the following is listdir(filepath), for which fsspec gives [filepath]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what's the advantage of going with POSIX semantics here?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fsspec tries to adhere to posix as much as possible. If we want to exclude the [file] case, we'd have to code that special case into our store.



@pytest.fixture(autouse=True, scope="function")
def s3(s3_base):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@martindurant could you explain what's happening in this test fixture? e.g., why do we need to manipulate the cache, why do we need to create an instance of S3FileSystem?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

pytest-asyncio creates a new event loop for each async test. When an async-mode s3fs instance is made from async, it will be assigned to the loop from which it is made. That means that if you use s3fs again from a subsequent test, you will have the same identical instance, but be running on a different loop - which fails.

For the rest: it's very convenient to clean up the state of the store between tests, make sure we start off blank each time.

@d-v-bd-v-b left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

looks good, thank you @martindurant et al

@jhamman
jhamman merged commit 7ded5d6 into zarr-developers:v3Jun 11, 2024
AdamWill added a commit to AdamWill/zarr-python that referenced this pull request Jun 17, 2024
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
dcherian added a commit to dcherian/zarr-python that referenced this pull request Jun 25, 2024
* v3: (22 commits)
[v3] `Buffer` ensure correct subclass based on the `BufferPrototype` argument (zarr-developers#1974)
Fix doc build (zarr-developers#1987)
Fix doc build warnings (zarr-developers#1985)
Automatically generate API reference docs (zarr-developers#1918)
Update `RemoteStore.__str__` and add UPath tests (zarr-developers#1964)
[v3] Elevate codec pipeline (zarr-developers#1932)
0 dim arrays: indexing (zarr-developers#1980)
`parse_shapelike` allows 0 (zarr-developers#1979)
Clean up typing and docs for indexing (zarr-developers#1961)
add json indentation to config (zarr-developers#1952)
chore: update pre-commit hooks (zarr-developers#1973)
Bump pypa/gh-action-pypi-publish in the actions group (zarr-developers#1969)
chore: update pre-commit hooks (zarr-developers#1957)
Update release.rst (zarr-developers#1960)
doc: update release notes for 3.0.0.alpha (zarr-developers#1959)
Basic working FsspecStore (zarr-developers#1785)
Feature: Top level V3 API (zarr-developers#1884)
Buffer Prototype Argument (zarr-developers#1910)
Create issue-metrics.yml
fixes bug in transpose (zarr-developers#1949)
...
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Jan 21, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
QuLogic pushed a commit to QuLogic/zarr that referenced this pull request Aug 23, 2025
…r-developers#1679)
This is adapted from the fixes that were rolled into
zarr-developers#1785 for the
v3 branch.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[v3] remote store support (s3, gcs, azure, http)

6 participants

@martindurant@pep8speaks@d-v-b@jhamman@dstansby@normanrz