Fix DirectoryStore - #773

Merged
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore
Aug 20, 2021
Merged

Fix DirectoryStore#773
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore

Conversation

@joshmoore

Copy link
Copy Markdown
Member

fix#769

Permit DirectoryStore to open Zarr filesets which have been saved with {"dimension_separator": "/"}. Currently they silently fallback to using the fill_value.

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)

Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
@codecov

codecovBot commented Jun 14, 2021

Copy link
Copy Markdown

Codecov Report

Merging #773 (a5f1811) into master (ce04aaa) will decrease coverage by 0.08%.
The diff coverage is 98.41%.

@@ Coverage Diff @@## master #773 +/- ##
==========================================
- Coverage 99.94% 99.85% -0.09% 
==========================================
Files 30 31 +1 Lines 10586 10613 +27 ==========================================
+ Hits 10580 10598 +18 - Misses 6 15 +9 
Impacted FilesCoverage Δ
zarr/tests/test_dim_separator.py97.56% <97.56%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/n5.py100.00% <100.00%> (ø)
zarr/storage.py99.30% <100.00%> (-0.70%)⬇️
zarr/tests/test_storage.py100.00% <100.00%> (ø)

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Build failures are unrelated. See #774

store['0.0'] = b'xxx'
assert b'xxx' == store['0.0']
assert b'xxx' == store['0/0']
# assert b'xxx' == store['0/0']

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.

Why did we loose there? Doesn't the store normalise "." -> "/" anyway?

@joshmoorejoshmooreJun 15, 2021

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.

I tried to describe in the commit message on e183566, at least to the best of my understanding:

Previous tests (now commented out) used logic in the store classes to convert "0/0" keys into "0.0" keys, forcing the store to be aware of array details. This tries to swap the logic so that stores are responsible for passing dimension separator values down to the arrays only. Since arrays can also get the dimension_separator value from a .zarray file they are now in charge.

@jakirkham

Copy link
Copy Markdown
Member

Build failures are unrelated. See #774

That's merged. Would merge master back into this PR (as I don't think GH Actions does that itself)

@pep8speaks

pep8speaks commented Jun 17, 2021

Copy link
Copy Markdown

Hello @joshmoore! 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 2021-08-19 13:55:46 UTC

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Pushed more tests based on the blurb from @martindurant in #769. Note that without the fix in this PR these are the failures:

zarr/tests/test_dim_separator.py::test_nested[static_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_default] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_default] FAILED

@joshmoore
joshmoore marked this pull request as ready for review August 17, 2021 11:55
@joshmoorejoshmoore mentioned this pull request Aug 17, 2021
5 tasks
Comment threadzarr/core.py

def _chunk_key(self, chunk_coords):
return self._key_prefix + '.'.join(map(str, chunk_coords))
return self._key_prefix + self._dimension_separator.join(map(str, chunk_coords))

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.

Can you explain how this change is compatible with FSStore._normalize_key? https://github.com/zarr-developers/zarr-python/blob/master/zarr/storage.py#L1076

FSStore._normalize_key assumes that all chunk keys are formatted foo/bar/0.0.0 -- this assumption is the basis of splitting the chunk key into a prefix and a chunk ID via key.split('/'). As I understand it, this change breaks this assumption.

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.

Reading the flat and nested fixtures from this repo (zarr.open(f"file:///tmp/{x}")[:]) with some sloppy debugging in place shows:

| | Array._chunk_key | FSStore._normalize_keys |
|---------------|------------------|-------------------------|
| master:nested | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| master:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| PR:nested | (0, 0) --> 0/0 | 0/0 --> 0/0 |
| PR:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |

which likely points to some logic in FSStore being ripe for removal since the Store is basically just accepting what what the Array has detected. Now, how it is that that's working with your PR, I still haven't figured out.

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.

Right, as your test shows this is fine for FSStore (and maybe we don't need this code in the store at all if the chunk keys come pre-normalized). But this situation is dire for N5Stores, which need to be able to re-order the chunk keys before writing to storage.

joshmoore added a commit to joshmoore/zarr-python that referenced this pull request Aug 19, 2021
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: zarr-developers#773zarr-developers#793
@joshmoore

Copy link
Copy Markdown
MemberAuthor

See the extended discussion with @d-v-b at https://gitter.im/zarr-developers/community?at=611e5f31a1ffab59400448cc. Current proposal is to have N5 stores act like they are still using "." internally in order to allow them to differentiate between Zarr-like keys and N5-like keys and then convert to "/"-based keys just before writing. A result of this is that you can hack access to the true N5 locations by using "/"-based keys as questioned by @martindurant in #773 (comment)

joshmoore added a commit to joshmoore/zarr_implementations that referenced this pull request Aug 19, 2021
@joshmoore

Copy link
Copy Markdown
MemberAuthor

Please see the additional evidence of zarr-developers/zarr_implementations#47 (and please ignore the code coverage failure behind the curtain... 🧙🏽 )

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Taking @d-v-b's 👍 on #773 (comment) as a sign-off. Merging and starting to prep a release.

@joshmoore
joshmoore merged commit da88aa3 into zarr-developers:masterAug 20, 2021
@joshmoore
joshmoore deleted the fix-dstore branch August 20, 2021 13:33
@joshmoorejoshmoore mentioned this pull request Aug 20, 2021
joshmoore added a commit that referenced this pull request Sep 19, 2021
* Drop skip_if_nested_chunks from test_storage.py
* Add failing nested test
* Make DirectoryStore dimension_separator aware
* Migrate key logic to core rather than storage
Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
* Fix linting in new test
* Extend the test suite for dim_sep
* add n5fsstore and tests
* slightly smarter kwarg interception
* remove outdated unittest ref and fix the name of a test func
* fix massive string block and fix default key_separator kwarg for FSStore
* flake8
* promote n5store to toplevel import and fix examples in docstring
* Try fsspec 2021.7 (see #802)
* Revert "Try fsspec 2021.7 (see #802)"
This reverts commit 68adca5.
* Add missing core tests for N5FSStore, and rchanges required for making them pass
* tmp: debug
* uncomment N5 chunk ordering test
* more commented tests get uncommented
* add dimension_separator to array metadata adaptor
* Revert "tmp: debug"
This reverts commit ee9cdbc.
* Attempt failed: keeping '.' and switching
* Revert "Attempt failed: keeping '.' and switching"
This reverts commit 51b3109.
* regex: attempt failed due to slight diff in files
* Revert "regex: attempt failed due to slight diff in files"
This reverts commit 3daea7c.
* N5: use "." internally for dimension separation
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: #773#793
* move FSSpec import guard
* remove os.path.sep concatenation in listdir that was erroring a test, and add a mea culpa docstring about the dimension_separator for n5 stores
* resolve merge conflicts in favor of upstream
* make listdir implementation for n5fsstore look more like fsstore's listdir, and add crucial lstrip
* Update hexdigest tests for N5Stores to account for the presence of the dimension_separator keyword now present in metadata
* Add tests for dimension_separator in array meta for N5Stores
* N5FSStore: try to increase code coverage
* Adds a test for the dimension_separator warning
* uses the parent test_complex for listdir
* "nocover" the import error since fsspec is ever present
* flake8
* add chunk nesting test to N5FSStore test suite
* make array_meta_key, group_meta_key, attrs_key private
* N5FSStore: Remove ImportError test
FSStore only throws ModuleNotFoundError on initialization
rather than on import. Therefore N5FSStore does the same.
If this *weren't* the case, then the import in zarr/init
would need to test the import as well, which isn't the case.
Co-authored-by: jmoore <josh@glencoesoftware.com>
Co-authored-by: Josh Moore <j.a.moore@dundee.ac.uk>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Confusion about the dimension_separator keyword

5 participants

@joshmoore@jakirkham@pep8speaks@d-v-b@martindurant
, '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

Fix DirectoryStore - #773

Merged
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore
Aug 20, 2021
Merged

Fix DirectoryStore#773
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore

Conversation

@joshmoore

Copy link
Copy Markdown
Member

fix#769

Permit DirectoryStore to open Zarr filesets which have been saved with {"dimension_separator": "/"}. Currently they silently fallback to using the fill_value.

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)

Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
@codecov

codecovBot commented Jun 14, 2021

Copy link
Copy Markdown

Codecov Report

Merging #773 (a5f1811) into master (ce04aaa) will decrease coverage by 0.08%.
The diff coverage is 98.41%.

@@ Coverage Diff @@## master #773 +/- ##
==========================================
- Coverage 99.94% 99.85% -0.09% 
==========================================
Files 30 31 +1 Lines 10586 10613 +27 ==========================================
+ Hits 10580 10598 +18 - Misses 6 15 +9 
Impacted FilesCoverage Δ
zarr/tests/test_dim_separator.py97.56% <97.56%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/n5.py100.00% <100.00%> (ø)
zarr/storage.py99.30% <100.00%> (-0.70%)⬇️
zarr/tests/test_storage.py100.00% <100.00%> (ø)

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Build failures are unrelated. See #774

store['0.0'] = b'xxx'
assert b'xxx' == store['0.0']
assert b'xxx' == store['0/0']
# assert b'xxx' == store['0/0']

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.

Why did we loose there? Doesn't the store normalise "." -> "/" anyway?

@joshmoorejoshmooreJun 15, 2021

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.

I tried to describe in the commit message on e183566, at least to the best of my understanding:

Previous tests (now commented out) used logic in the store classes to convert "0/0" keys into "0.0" keys, forcing the store to be aware of array details. This tries to swap the logic so that stores are responsible for passing dimension separator values down to the arrays only. Since arrays can also get the dimension_separator value from a .zarray file they are now in charge.

@jakirkham

Copy link
Copy Markdown
Member

Build failures are unrelated. See #774

That's merged. Would merge master back into this PR (as I don't think GH Actions does that itself)

@pep8speaks

pep8speaks commented Jun 17, 2021

Copy link
Copy Markdown

Hello @joshmoore! 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 2021-08-19 13:55:46 UTC

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Pushed more tests based on the blurb from @martindurant in #769. Note that without the fix in this PR these are the failures:

zarr/tests/test_dim_separator.py::test_nested[static_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_default] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_default] FAILED

@joshmoore
joshmoore marked this pull request as ready for review August 17, 2021 11:55
@joshmoorejoshmoore mentioned this pull request Aug 17, 2021
5 tasks
Comment threadzarr/core.py

def _chunk_key(self, chunk_coords):
return self._key_prefix + '.'.join(map(str, chunk_coords))
return self._key_prefix + self._dimension_separator.join(map(str, chunk_coords))

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.

Can you explain how this change is compatible with FSStore._normalize_key? https://github.com/zarr-developers/zarr-python/blob/master/zarr/storage.py#L1076

FSStore._normalize_key assumes that all chunk keys are formatted foo/bar/0.0.0 -- this assumption is the basis of splitting the chunk key into a prefix and a chunk ID via key.split('/'). As I understand it, this change breaks this assumption.

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.

Reading the flat and nested fixtures from this repo (zarr.open(f"file:///tmp/{x}")[:]) with some sloppy debugging in place shows:

| | Array._chunk_key | FSStore._normalize_keys |
|---------------|------------------|-------------------------|
| master:nested | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| master:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| PR:nested | (0, 0) --> 0/0 | 0/0 --> 0/0 |
| PR:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |

which likely points to some logic in FSStore being ripe for removal since the Store is basically just accepting what what the Array has detected. Now, how it is that that's working with your PR, I still haven't figured out.

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.

Right, as your test shows this is fine for FSStore (and maybe we don't need this code in the store at all if the chunk keys come pre-normalized). But this situation is dire for N5Stores, which need to be able to re-order the chunk keys before writing to storage.

joshmoore added a commit to joshmoore/zarr-python that referenced this pull request Aug 19, 2021
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: zarr-developers#773zarr-developers#793
@joshmoore

Copy link
Copy Markdown
MemberAuthor

See the extended discussion with @d-v-b at https://gitter.im/zarr-developers/community?at=611e5f31a1ffab59400448cc. Current proposal is to have N5 stores act like they are still using "." internally in order to allow them to differentiate between Zarr-like keys and N5-like keys and then convert to "/"-based keys just before writing. A result of this is that you can hack access to the true N5 locations by using "/"-based keys as questioned by @martindurant in #773 (comment)

joshmoore added a commit to joshmoore/zarr_implementations that referenced this pull request Aug 19, 2021
@joshmoore

Copy link
Copy Markdown
MemberAuthor

Please see the additional evidence of zarr-developers/zarr_implementations#47 (and please ignore the code coverage failure behind the curtain... 🧙🏽 )

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Taking @d-v-b's 👍 on #773 (comment) as a sign-off. Merging and starting to prep a release.

@joshmoore
joshmoore merged commit da88aa3 into zarr-developers:masterAug 20, 2021
@joshmoore
joshmoore deleted the fix-dstore branch August 20, 2021 13:33
@joshmoorejoshmoore mentioned this pull request Aug 20, 2021
joshmoore added a commit that referenced this pull request Sep 19, 2021
* Drop skip_if_nested_chunks from test_storage.py
* Add failing nested test
* Make DirectoryStore dimension_separator aware
* Migrate key logic to core rather than storage
Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
* Fix linting in new test
* Extend the test suite for dim_sep
* add n5fsstore and tests
* slightly smarter kwarg interception
* remove outdated unittest ref and fix the name of a test func
* fix massive string block and fix default key_separator kwarg for FSStore
* flake8
* promote n5store to toplevel import and fix examples in docstring
* Try fsspec 2021.7 (see #802)
* Revert "Try fsspec 2021.7 (see #802)"
This reverts commit 68adca5.
* Add missing core tests for N5FSStore, and rchanges required for making them pass
* tmp: debug
* uncomment N5 chunk ordering test
* more commented tests get uncommented
* add dimension_separator to array metadata adaptor
* Revert "tmp: debug"
This reverts commit ee9cdbc.
* Attempt failed: keeping '.' and switching
* Revert "Attempt failed: keeping '.' and switching"
This reverts commit 51b3109.
* regex: attempt failed due to slight diff in files
* Revert "regex: attempt failed due to slight diff in files"
This reverts commit 3daea7c.
* N5: use "." internally for dimension separation
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: #773#793
* move FSSpec import guard
* remove os.path.sep concatenation in listdir that was erroring a test, and add a mea culpa docstring about the dimension_separator for n5 stores
* resolve merge conflicts in favor of upstream
* make listdir implementation for n5fsstore look more like fsstore's listdir, and add crucial lstrip
* Update hexdigest tests for N5Stores to account for the presence of the dimension_separator keyword now present in metadata
* Add tests for dimension_separator in array meta for N5Stores
* N5FSStore: try to increase code coverage
* Adds a test for the dimension_separator warning
* uses the parent test_complex for listdir
* "nocover" the import error since fsspec is ever present
* flake8
* add chunk nesting test to N5FSStore test suite
* make array_meta_key, group_meta_key, attrs_key private
* N5FSStore: Remove ImportError test
FSStore only throws ModuleNotFoundError on initialization
rather than on import. Therefore N5FSStore does the same.
If this *weren't* the case, then the import in zarr/init
would need to test the import as well, which isn't the case.
Co-authored-by: jmoore <josh@glencoesoftware.com>
Co-authored-by: Josh Moore <j.a.moore@dundee.ac.uk>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Confusion about the dimension_separator keyword

5 participants

@joshmoore@jakirkham@pep8speaks@d-v-b@martindurant
, '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

Fix DirectoryStore - #773

Merged
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore
Aug 20, 2021
Merged

Fix DirectoryStore#773
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore

Conversation

@joshmoore

Copy link
Copy Markdown
Member

fix#769

Permit DirectoryStore to open Zarr filesets which have been saved with {"dimension_separator": "/"}. Currently they silently fallback to using the fill_value.

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)

Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
@codecov

codecovBot commented Jun 14, 2021

Copy link
Copy Markdown

Codecov Report

Merging #773 (a5f1811) into master (ce04aaa) will decrease coverage by 0.08%.
The diff coverage is 98.41%.

@@ Coverage Diff @@## master #773 +/- ##
==========================================
- Coverage 99.94% 99.85% -0.09% 
==========================================
Files 30 31 +1 Lines 10586 10613 +27 ==========================================
+ Hits 10580 10598 +18 - Misses 6 15 +9 
Impacted FilesCoverage Δ
zarr/tests/test_dim_separator.py97.56% <97.56%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/n5.py100.00% <100.00%> (ø)
zarr/storage.py99.30% <100.00%> (-0.70%)⬇️
zarr/tests/test_storage.py100.00% <100.00%> (ø)

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Build failures are unrelated. See #774

store['0.0'] = b'xxx'
assert b'xxx' == store['0.0']
assert b'xxx' == store['0/0']
# assert b'xxx' == store['0/0']

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.

Why did we loose there? Doesn't the store normalise "." -> "/" anyway?

@joshmoorejoshmooreJun 15, 2021

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.

I tried to describe in the commit message on e183566, at least to the best of my understanding:

Previous tests (now commented out) used logic in the store classes to convert "0/0" keys into "0.0" keys, forcing the store to be aware of array details. This tries to swap the logic so that stores are responsible for passing dimension separator values down to the arrays only. Since arrays can also get the dimension_separator value from a .zarray file they are now in charge.

@jakirkham

Copy link
Copy Markdown
Member

Build failures are unrelated. See #774

That's merged. Would merge master back into this PR (as I don't think GH Actions does that itself)

@pep8speaks

pep8speaks commented Jun 17, 2021

Copy link
Copy Markdown

Hello @joshmoore! 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 2021-08-19 13:55:46 UTC

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Pushed more tests based on the blurb from @martindurant in #769. Note that without the fix in this PR these are the failures:

zarr/tests/test_dim_separator.py::test_nested[static_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_default] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_default] FAILED

@joshmoore
joshmoore marked this pull request as ready for review August 17, 2021 11:55
@joshmoorejoshmoore mentioned this pull request Aug 17, 2021
5 tasks
Comment threadzarr/core.py

def _chunk_key(self, chunk_coords):
return self._key_prefix + '.'.join(map(str, chunk_coords))
return self._key_prefix + self._dimension_separator.join(map(str, chunk_coords))

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.

Can you explain how this change is compatible with FSStore._normalize_key? https://github.com/zarr-developers/zarr-python/blob/master/zarr/storage.py#L1076

FSStore._normalize_key assumes that all chunk keys are formatted foo/bar/0.0.0 -- this assumption is the basis of splitting the chunk key into a prefix and a chunk ID via key.split('/'). As I understand it, this change breaks this assumption.

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.

Reading the flat and nested fixtures from this repo (zarr.open(f"file:///tmp/{x}")[:]) with some sloppy debugging in place shows:

| | Array._chunk_key | FSStore._normalize_keys |
|---------------|------------------|-------------------------|
| master:nested | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| master:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| PR:nested | (0, 0) --> 0/0 | 0/0 --> 0/0 |
| PR:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |

which likely points to some logic in FSStore being ripe for removal since the Store is basically just accepting what what the Array has detected. Now, how it is that that's working with your PR, I still haven't figured out.

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.

Right, as your test shows this is fine for FSStore (and maybe we don't need this code in the store at all if the chunk keys come pre-normalized). But this situation is dire for N5Stores, which need to be able to re-order the chunk keys before writing to storage.

joshmoore added a commit to joshmoore/zarr-python that referenced this pull request Aug 19, 2021
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: zarr-developers#773zarr-developers#793
@joshmoore

Copy link
Copy Markdown
MemberAuthor

See the extended discussion with @d-v-b at https://gitter.im/zarr-developers/community?at=611e5f31a1ffab59400448cc. Current proposal is to have N5 stores act like they are still using "." internally in order to allow them to differentiate between Zarr-like keys and N5-like keys and then convert to "/"-based keys just before writing. A result of this is that you can hack access to the true N5 locations by using "/"-based keys as questioned by @martindurant in #773 (comment)

joshmoore added a commit to joshmoore/zarr_implementations that referenced this pull request Aug 19, 2021
@joshmoore

Copy link
Copy Markdown
MemberAuthor

Please see the additional evidence of zarr-developers/zarr_implementations#47 (and please ignore the code coverage failure behind the curtain... 🧙🏽 )

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Taking @d-v-b's 👍 on #773 (comment) as a sign-off. Merging and starting to prep a release.

@joshmoore
joshmoore merged commit da88aa3 into zarr-developers:masterAug 20, 2021
@joshmoore
joshmoore deleted the fix-dstore branch August 20, 2021 13:33
@joshmoorejoshmoore mentioned this pull request Aug 20, 2021
joshmoore added a commit that referenced this pull request Sep 19, 2021
* Drop skip_if_nested_chunks from test_storage.py
* Add failing nested test
* Make DirectoryStore dimension_separator aware
* Migrate key logic to core rather than storage
Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
* Fix linting in new test
* Extend the test suite for dim_sep
* add n5fsstore and tests
* slightly smarter kwarg interception
* remove outdated unittest ref and fix the name of a test func
* fix massive string block and fix default key_separator kwarg for FSStore
* flake8
* promote n5store to toplevel import and fix examples in docstring
* Try fsspec 2021.7 (see #802)
* Revert "Try fsspec 2021.7 (see #802)"
This reverts commit 68adca5.
* Add missing core tests for N5FSStore, and rchanges required for making them pass
* tmp: debug
* uncomment N5 chunk ordering test
* more commented tests get uncommented
* add dimension_separator to array metadata adaptor
* Revert "tmp: debug"
This reverts commit ee9cdbc.
* Attempt failed: keeping '.' and switching
* Revert "Attempt failed: keeping '.' and switching"
This reverts commit 51b3109.
* regex: attempt failed due to slight diff in files
* Revert "regex: attempt failed due to slight diff in files"
This reverts commit 3daea7c.
* N5: use "." internally for dimension separation
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: #773#793
* move FSSpec import guard
* remove os.path.sep concatenation in listdir that was erroring a test, and add a mea culpa docstring about the dimension_separator for n5 stores
* resolve merge conflicts in favor of upstream
* make listdir implementation for n5fsstore look more like fsstore's listdir, and add crucial lstrip
* Update hexdigest tests for N5Stores to account for the presence of the dimension_separator keyword now present in metadata
* Add tests for dimension_separator in array meta for N5Stores
* N5FSStore: try to increase code coverage
* Adds a test for the dimension_separator warning
* uses the parent test_complex for listdir
* "nocover" the import error since fsspec is ever present
* flake8
* add chunk nesting test to N5FSStore test suite
* make array_meta_key, group_meta_key, attrs_key private
* N5FSStore: Remove ImportError test
FSStore only throws ModuleNotFoundError on initialization
rather than on import. Therefore N5FSStore does the same.
If this *weren't* the case, then the import in zarr/init
would need to test the import as well, which isn't the case.
Co-authored-by: jmoore <josh@glencoesoftware.com>
Co-authored-by: Josh Moore <j.a.moore@dundee.ac.uk>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Confusion about the dimension_separator keyword

5 participants

@joshmoore@jakirkham@pep8speaks@d-v-b@martindurant
, '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

Fix DirectoryStore - #773

Merged
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore
Aug 20, 2021
Merged

Fix DirectoryStore#773
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore

Conversation

@joshmoore

Copy link
Copy Markdown
Member

fix#769

Permit DirectoryStore to open Zarr filesets which have been saved with {"dimension_separator": "/"}. Currently they silently fallback to using the fill_value.

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)

Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
@codecov

codecovBot commented Jun 14, 2021

Copy link
Copy Markdown

Codecov Report

Merging #773 (a5f1811) into master (ce04aaa) will decrease coverage by 0.08%.
The diff coverage is 98.41%.

@@ Coverage Diff @@## master #773 +/- ##
==========================================
- Coverage 99.94% 99.85% -0.09% 
==========================================
Files 30 31 +1 Lines 10586 10613 +27 ==========================================
+ Hits 10580 10598 +18 - Misses 6 15 +9 
Impacted FilesCoverage Δ
zarr/tests/test_dim_separator.py97.56% <97.56%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/n5.py100.00% <100.00%> (ø)
zarr/storage.py99.30% <100.00%> (-0.70%)⬇️
zarr/tests/test_storage.py100.00% <100.00%> (ø)

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Build failures are unrelated. See #774

store['0.0'] = b'xxx'
assert b'xxx' == store['0.0']
assert b'xxx' == store['0/0']
# assert b'xxx' == store['0/0']

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.

Why did we loose there? Doesn't the store normalise "." -> "/" anyway?

@joshmoorejoshmooreJun 15, 2021

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.

I tried to describe in the commit message on e183566, at least to the best of my understanding:

Previous tests (now commented out) used logic in the store classes to convert "0/0" keys into "0.0" keys, forcing the store to be aware of array details. This tries to swap the logic so that stores are responsible for passing dimension separator values down to the arrays only. Since arrays can also get the dimension_separator value from a .zarray file they are now in charge.

@jakirkham

Copy link
Copy Markdown
Member

Build failures are unrelated. See #774

That's merged. Would merge master back into this PR (as I don't think GH Actions does that itself)

@pep8speaks

pep8speaks commented Jun 17, 2021

Copy link
Copy Markdown

Hello @joshmoore! 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 2021-08-19 13:55:46 UTC

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Pushed more tests based on the blurb from @martindurant in #769. Note that without the fix in this PR these are the failures:

zarr/tests/test_dim_separator.py::test_nested[static_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_default] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_default] FAILED

@joshmoore
joshmoore marked this pull request as ready for review August 17, 2021 11:55
@joshmoorejoshmoore mentioned this pull request Aug 17, 2021
5 tasks
Comment threadzarr/core.py

def _chunk_key(self, chunk_coords):
return self._key_prefix + '.'.join(map(str, chunk_coords))
return self._key_prefix + self._dimension_separator.join(map(str, chunk_coords))

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.

Can you explain how this change is compatible with FSStore._normalize_key? https://github.com/zarr-developers/zarr-python/blob/master/zarr/storage.py#L1076

FSStore._normalize_key assumes that all chunk keys are formatted foo/bar/0.0.0 -- this assumption is the basis of splitting the chunk key into a prefix and a chunk ID via key.split('/'). As I understand it, this change breaks this assumption.

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.

Reading the flat and nested fixtures from this repo (zarr.open(f"file:///tmp/{x}")[:]) with some sloppy debugging in place shows:

| | Array._chunk_key | FSStore._normalize_keys |
|---------------|------------------|-------------------------|
| master:nested | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| master:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| PR:nested | (0, 0) --> 0/0 | 0/0 --> 0/0 |
| PR:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |

which likely points to some logic in FSStore being ripe for removal since the Store is basically just accepting what what the Array has detected. Now, how it is that that's working with your PR, I still haven't figured out.

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.

Right, as your test shows this is fine for FSStore (and maybe we don't need this code in the store at all if the chunk keys come pre-normalized). But this situation is dire for N5Stores, which need to be able to re-order the chunk keys before writing to storage.

joshmoore added a commit to joshmoore/zarr-python that referenced this pull request Aug 19, 2021
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: zarr-developers#773zarr-developers#793
@joshmoore

Copy link
Copy Markdown
MemberAuthor

See the extended discussion with @d-v-b at https://gitter.im/zarr-developers/community?at=611e5f31a1ffab59400448cc. Current proposal is to have N5 stores act like they are still using "." internally in order to allow them to differentiate between Zarr-like keys and N5-like keys and then convert to "/"-based keys just before writing. A result of this is that you can hack access to the true N5 locations by using "/"-based keys as questioned by @martindurant in #773 (comment)

joshmoore added a commit to joshmoore/zarr_implementations that referenced this pull request Aug 19, 2021
@joshmoore

Copy link
Copy Markdown
MemberAuthor

Please see the additional evidence of zarr-developers/zarr_implementations#47 (and please ignore the code coverage failure behind the curtain... 🧙🏽 )

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Taking @d-v-b's 👍 on #773 (comment) as a sign-off. Merging and starting to prep a release.

@joshmoore
joshmoore merged commit da88aa3 into zarr-developers:masterAug 20, 2021
@joshmoore
joshmoore deleted the fix-dstore branch August 20, 2021 13:33
@joshmoorejoshmoore mentioned this pull request Aug 20, 2021
joshmoore added a commit that referenced this pull request Sep 19, 2021
* Drop skip_if_nested_chunks from test_storage.py
* Add failing nested test
* Make DirectoryStore dimension_separator aware
* Migrate key logic to core rather than storage
Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
* Fix linting in new test
* Extend the test suite for dim_sep
* add n5fsstore and tests
* slightly smarter kwarg interception
* remove outdated unittest ref and fix the name of a test func
* fix massive string block and fix default key_separator kwarg for FSStore
* flake8
* promote n5store to toplevel import and fix examples in docstring
* Try fsspec 2021.7 (see #802)
* Revert "Try fsspec 2021.7 (see #802)"
This reverts commit 68adca5.
* Add missing core tests for N5FSStore, and rchanges required for making them pass
* tmp: debug
* uncomment N5 chunk ordering test
* more commented tests get uncommented
* add dimension_separator to array metadata adaptor
* Revert "tmp: debug"
This reverts commit ee9cdbc.
* Attempt failed: keeping '.' and switching
* Revert "Attempt failed: keeping '.' and switching"
This reverts commit 51b3109.
* regex: attempt failed due to slight diff in files
* Revert "regex: attempt failed due to slight diff in files"
This reverts commit 3daea7c.
* N5: use "." internally for dimension separation
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: #773#793
* move FSSpec import guard
* remove os.path.sep concatenation in listdir that was erroring a test, and add a mea culpa docstring about the dimension_separator for n5 stores
* resolve merge conflicts in favor of upstream
* make listdir implementation for n5fsstore look more like fsstore's listdir, and add crucial lstrip
* Update hexdigest tests for N5Stores to account for the presence of the dimension_separator keyword now present in metadata
* Add tests for dimension_separator in array meta for N5Stores
* N5FSStore: try to increase code coverage
* Adds a test for the dimension_separator warning
* uses the parent test_complex for listdir
* "nocover" the import error since fsspec is ever present
* flake8
* add chunk nesting test to N5FSStore test suite
* make array_meta_key, group_meta_key, attrs_key private
* N5FSStore: Remove ImportError test
FSStore only throws ModuleNotFoundError on initialization
rather than on import. Therefore N5FSStore does the same.
If this *weren't* the case, then the import in zarr/init
would need to test the import as well, which isn't the case.
Co-authored-by: jmoore <josh@glencoesoftware.com>
Co-authored-by: Josh Moore <j.a.moore@dundee.ac.uk>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Confusion about the dimension_separator keyword

5 participants

@joshmoore@jakirkham@pep8speaks@d-v-b@martindurant
, '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

Fix DirectoryStore - #773

Merged
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore
Aug 20, 2021
Merged

Fix DirectoryStore#773
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore

Conversation

@joshmoore

Copy link
Copy Markdown
Member

fix#769

Permit DirectoryStore to open Zarr filesets which have been saved with {"dimension_separator": "/"}. Currently they silently fallback to using the fill_value.

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)

Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
@codecov

codecovBot commented Jun 14, 2021

Copy link
Copy Markdown

Codecov Report

Merging #773 (a5f1811) into master (ce04aaa) will decrease coverage by 0.08%.
The diff coverage is 98.41%.

@@ Coverage Diff @@## master #773 +/- ##
==========================================
- Coverage 99.94% 99.85% -0.09% 
==========================================
Files 30 31 +1 Lines 10586 10613 +27 ==========================================
+ Hits 10580 10598 +18 - Misses 6 15 +9 
Impacted FilesCoverage Δ
zarr/tests/test_dim_separator.py97.56% <97.56%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/n5.py100.00% <100.00%> (ø)
zarr/storage.py99.30% <100.00%> (-0.70%)⬇️
zarr/tests/test_storage.py100.00% <100.00%> (ø)

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Build failures are unrelated. See #774

store['0.0'] = b'xxx'
assert b'xxx' == store['0.0']
assert b'xxx' == store['0/0']
# assert b'xxx' == store['0/0']

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.

Why did we loose there? Doesn't the store normalise "." -> "/" anyway?

@joshmoorejoshmooreJun 15, 2021

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.

I tried to describe in the commit message on e183566, at least to the best of my understanding:

Previous tests (now commented out) used logic in the store classes to convert "0/0" keys into "0.0" keys, forcing the store to be aware of array details. This tries to swap the logic so that stores are responsible for passing dimension separator values down to the arrays only. Since arrays can also get the dimension_separator value from a .zarray file they are now in charge.

@jakirkham

Copy link
Copy Markdown
Member

Build failures are unrelated. See #774

That's merged. Would merge master back into this PR (as I don't think GH Actions does that itself)

@pep8speaks

pep8speaks commented Jun 17, 2021

Copy link
Copy Markdown

Hello @joshmoore! 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 2021-08-19 13:55:46 UTC

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Pushed more tests based on the blurb from @martindurant in #769. Note that without the fix in this PR these are the failures:

zarr/tests/test_dim_separator.py::test_nested[static_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_default] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_default] FAILED

@joshmoore
joshmoore marked this pull request as ready for review August 17, 2021 11:55
@joshmoorejoshmoore mentioned this pull request Aug 17, 2021
5 tasks
Comment threadzarr/core.py

def _chunk_key(self, chunk_coords):
return self._key_prefix + '.'.join(map(str, chunk_coords))
return self._key_prefix + self._dimension_separator.join(map(str, chunk_coords))

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.

Can you explain how this change is compatible with FSStore._normalize_key? https://github.com/zarr-developers/zarr-python/blob/master/zarr/storage.py#L1076

FSStore._normalize_key assumes that all chunk keys are formatted foo/bar/0.0.0 -- this assumption is the basis of splitting the chunk key into a prefix and a chunk ID via key.split('/'). As I understand it, this change breaks this assumption.

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.

Reading the flat and nested fixtures from this repo (zarr.open(f"file:///tmp/{x}")[:]) with some sloppy debugging in place shows:

| | Array._chunk_key | FSStore._normalize_keys |
|---------------|------------------|-------------------------|
| master:nested | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| master:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| PR:nested | (0, 0) --> 0/0 | 0/0 --> 0/0 |
| PR:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |

which likely points to some logic in FSStore being ripe for removal since the Store is basically just accepting what what the Array has detected. Now, how it is that that's working with your PR, I still haven't figured out.

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.

Right, as your test shows this is fine for FSStore (and maybe we don't need this code in the store at all if the chunk keys come pre-normalized). But this situation is dire for N5Stores, which need to be able to re-order the chunk keys before writing to storage.

joshmoore added a commit to joshmoore/zarr-python that referenced this pull request Aug 19, 2021
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: zarr-developers#773zarr-developers#793
@joshmoore

Copy link
Copy Markdown
MemberAuthor

See the extended discussion with @d-v-b at https://gitter.im/zarr-developers/community?at=611e5f31a1ffab59400448cc. Current proposal is to have N5 stores act like they are still using "." internally in order to allow them to differentiate between Zarr-like keys and N5-like keys and then convert to "/"-based keys just before writing. A result of this is that you can hack access to the true N5 locations by using "/"-based keys as questioned by @martindurant in #773 (comment)

joshmoore added a commit to joshmoore/zarr_implementations that referenced this pull request Aug 19, 2021
@joshmoore

Copy link
Copy Markdown
MemberAuthor

Please see the additional evidence of zarr-developers/zarr_implementations#47 (and please ignore the code coverage failure behind the curtain... 🧙🏽 )

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Taking @d-v-b's 👍 on #773 (comment) as a sign-off. Merging and starting to prep a release.

@joshmoore
joshmoore merged commit da88aa3 into zarr-developers:masterAug 20, 2021
@joshmoore
joshmoore deleted the fix-dstore branch August 20, 2021 13:33
@joshmoorejoshmoore mentioned this pull request Aug 20, 2021
joshmoore added a commit that referenced this pull request Sep 19, 2021
* Drop skip_if_nested_chunks from test_storage.py
* Add failing nested test
* Make DirectoryStore dimension_separator aware
* Migrate key logic to core rather than storage
Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
* Fix linting in new test
* Extend the test suite for dim_sep
* add n5fsstore and tests
* slightly smarter kwarg interception
* remove outdated unittest ref and fix the name of a test func
* fix massive string block and fix default key_separator kwarg for FSStore
* flake8
* promote n5store to toplevel import and fix examples in docstring
* Try fsspec 2021.7 (see #802)
* Revert "Try fsspec 2021.7 (see #802)"
This reverts commit 68adca5.
* Add missing core tests for N5FSStore, and rchanges required for making them pass
* tmp: debug
* uncomment N5 chunk ordering test
* more commented tests get uncommented
* add dimension_separator to array metadata adaptor
* Revert "tmp: debug"
This reverts commit ee9cdbc.
* Attempt failed: keeping '.' and switching
* Revert "Attempt failed: keeping '.' and switching"
This reverts commit 51b3109.
* regex: attempt failed due to slight diff in files
* Revert "regex: attempt failed due to slight diff in files"
This reverts commit 3daea7c.
* N5: use "." internally for dimension separation
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: #773#793
* move FSSpec import guard
* remove os.path.sep concatenation in listdir that was erroring a test, and add a mea culpa docstring about the dimension_separator for n5 stores
* resolve merge conflicts in favor of upstream
* make listdir implementation for n5fsstore look more like fsstore's listdir, and add crucial lstrip
* Update hexdigest tests for N5Stores to account for the presence of the dimension_separator keyword now present in metadata
* Add tests for dimension_separator in array meta for N5Stores
* N5FSStore: try to increase code coverage
* Adds a test for the dimension_separator warning
* uses the parent test_complex for listdir
* "nocover" the import error since fsspec is ever present
* flake8
* add chunk nesting test to N5FSStore test suite
* make array_meta_key, group_meta_key, attrs_key private
* N5FSStore: Remove ImportError test
FSStore only throws ModuleNotFoundError on initialization
rather than on import. Therefore N5FSStore does the same.
If this *weren't* the case, then the import in zarr/init
would need to test the import as well, which isn't the case.
Co-authored-by: jmoore <josh@glencoesoftware.com>
Co-authored-by: Josh Moore <j.a.moore@dundee.ac.uk>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Confusion about the dimension_separator keyword

5 participants

@joshmoore@jakirkham@pep8speaks@d-v-b@martindurant
, '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

Fix DirectoryStore - #773

Merged
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore
Aug 20, 2021
Merged

Fix DirectoryStore#773
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore

Conversation

@joshmoore

Copy link
Copy Markdown
Member

fix#769

Permit DirectoryStore to open Zarr filesets which have been saved with {"dimension_separator": "/"}. Currently they silently fallback to using the fill_value.

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)

Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
@codecov

codecovBot commented Jun 14, 2021

Copy link
Copy Markdown

Codecov Report

Merging #773 (a5f1811) into master (ce04aaa) will decrease coverage by 0.08%.
The diff coverage is 98.41%.

@@ Coverage Diff @@## master #773 +/- ##
==========================================
- Coverage 99.94% 99.85% -0.09% 
==========================================
Files 30 31 +1 Lines 10586 10613 +27 ==========================================
+ Hits 10580 10598 +18 - Misses 6 15 +9 
Impacted FilesCoverage Δ
zarr/tests/test_dim_separator.py97.56% <97.56%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/n5.py100.00% <100.00%> (ø)
zarr/storage.py99.30% <100.00%> (-0.70%)⬇️
zarr/tests/test_storage.py100.00% <100.00%> (ø)

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Build failures are unrelated. See #774

store['0.0'] = b'xxx'
assert b'xxx' == store['0.0']
assert b'xxx' == store['0/0']
# assert b'xxx' == store['0/0']

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.

Why did we loose there? Doesn't the store normalise "." -> "/" anyway?

@joshmoorejoshmooreJun 15, 2021

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.

I tried to describe in the commit message on e183566, at least to the best of my understanding:

Previous tests (now commented out) used logic in the store classes to convert "0/0" keys into "0.0" keys, forcing the store to be aware of array details. This tries to swap the logic so that stores are responsible for passing dimension separator values down to the arrays only. Since arrays can also get the dimension_separator value from a .zarray file they are now in charge.

@jakirkham

Copy link
Copy Markdown
Member

Build failures are unrelated. See #774

That's merged. Would merge master back into this PR (as I don't think GH Actions does that itself)

@pep8speaks

pep8speaks commented Jun 17, 2021

Copy link
Copy Markdown

Hello @joshmoore! 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 2021-08-19 13:55:46 UTC

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Pushed more tests based on the blurb from @martindurant in #769. Note that without the fix in this PR these are the failures:

zarr/tests/test_dim_separator.py::test_nested[static_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_default] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_default] FAILED

@joshmoore
joshmoore marked this pull request as ready for review August 17, 2021 11:55
@joshmoorejoshmoore mentioned this pull request Aug 17, 2021
5 tasks
Comment threadzarr/core.py

def _chunk_key(self, chunk_coords):
return self._key_prefix + '.'.join(map(str, chunk_coords))
return self._key_prefix + self._dimension_separator.join(map(str, chunk_coords))

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.

Can you explain how this change is compatible with FSStore._normalize_key? https://github.com/zarr-developers/zarr-python/blob/master/zarr/storage.py#L1076

FSStore._normalize_key assumes that all chunk keys are formatted foo/bar/0.0.0 -- this assumption is the basis of splitting the chunk key into a prefix and a chunk ID via key.split('/'). As I understand it, this change breaks this assumption.

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.

Reading the flat and nested fixtures from this repo (zarr.open(f"file:///tmp/{x}")[:]) with some sloppy debugging in place shows:

| | Array._chunk_key | FSStore._normalize_keys |
|---------------|------------------|-------------------------|
| master:nested | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| master:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| PR:nested | (0, 0) --> 0/0 | 0/0 --> 0/0 |
| PR:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |

which likely points to some logic in FSStore being ripe for removal since the Store is basically just accepting what what the Array has detected. Now, how it is that that's working with your PR, I still haven't figured out.

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.

Right, as your test shows this is fine for FSStore (and maybe we don't need this code in the store at all if the chunk keys come pre-normalized). But this situation is dire for N5Stores, which need to be able to re-order the chunk keys before writing to storage.

joshmoore added a commit to joshmoore/zarr-python that referenced this pull request Aug 19, 2021
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: zarr-developers#773zarr-developers#793
@joshmoore

Copy link
Copy Markdown
MemberAuthor

See the extended discussion with @d-v-b at https://gitter.im/zarr-developers/community?at=611e5f31a1ffab59400448cc. Current proposal is to have N5 stores act like they are still using "." internally in order to allow them to differentiate between Zarr-like keys and N5-like keys and then convert to "/"-based keys just before writing. A result of this is that you can hack access to the true N5 locations by using "/"-based keys as questioned by @martindurant in #773 (comment)

joshmoore added a commit to joshmoore/zarr_implementations that referenced this pull request Aug 19, 2021
@joshmoore

Copy link
Copy Markdown
MemberAuthor

Please see the additional evidence of zarr-developers/zarr_implementations#47 (and please ignore the code coverage failure behind the curtain... 🧙🏽 )

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Taking @d-v-b's 👍 on #773 (comment) as a sign-off. Merging and starting to prep a release.

@joshmoore
joshmoore merged commit da88aa3 into zarr-developers:masterAug 20, 2021
@joshmoore
joshmoore deleted the fix-dstore branch August 20, 2021 13:33
@joshmoorejoshmoore mentioned this pull request Aug 20, 2021
joshmoore added a commit that referenced this pull request Sep 19, 2021
* Drop skip_if_nested_chunks from test_storage.py
* Add failing nested test
* Make DirectoryStore dimension_separator aware
* Migrate key logic to core rather than storage
Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
* Fix linting in new test
* Extend the test suite for dim_sep
* add n5fsstore and tests
* slightly smarter kwarg interception
* remove outdated unittest ref and fix the name of a test func
* fix massive string block and fix default key_separator kwarg for FSStore
* flake8
* promote n5store to toplevel import and fix examples in docstring
* Try fsspec 2021.7 (see #802)
* Revert "Try fsspec 2021.7 (see #802)"
This reverts commit 68adca5.
* Add missing core tests for N5FSStore, and rchanges required for making them pass
* tmp: debug
* uncomment N5 chunk ordering test
* more commented tests get uncommented
* add dimension_separator to array metadata adaptor
* Revert "tmp: debug"
This reverts commit ee9cdbc.
* Attempt failed: keeping '.' and switching
* Revert "Attempt failed: keeping '.' and switching"
This reverts commit 51b3109.
* regex: attempt failed due to slight diff in files
* Revert "regex: attempt failed due to slight diff in files"
This reverts commit 3daea7c.
* N5: use "." internally for dimension separation
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: #773#793
* move FSSpec import guard
* remove os.path.sep concatenation in listdir that was erroring a test, and add a mea culpa docstring about the dimension_separator for n5 stores
* resolve merge conflicts in favor of upstream
* make listdir implementation for n5fsstore look more like fsstore's listdir, and add crucial lstrip
* Update hexdigest tests for N5Stores to account for the presence of the dimension_separator keyword now present in metadata
* Add tests for dimension_separator in array meta for N5Stores
* N5FSStore: try to increase code coverage
* Adds a test for the dimension_separator warning
* uses the parent test_complex for listdir
* "nocover" the import error since fsspec is ever present
* flake8
* add chunk nesting test to N5FSStore test suite
* make array_meta_key, group_meta_key, attrs_key private
* N5FSStore: Remove ImportError test
FSStore only throws ModuleNotFoundError on initialization
rather than on import. Therefore N5FSStore does the same.
If this *weren't* the case, then the import in zarr/init
would need to test the import as well, which isn't the case.
Co-authored-by: jmoore <josh@glencoesoftware.com>
Co-authored-by: Josh Moore <j.a.moore@dundee.ac.uk>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Confusion about the dimension_separator keyword

5 participants

@joshmoore@jakirkham@pep8speaks@d-v-b@martindurant
, '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

Fix DirectoryStore - #773

Merged
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore
Aug 20, 2021
Merged

Fix DirectoryStore#773
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore

Conversation

@joshmoore

Copy link
Copy Markdown
Member

fix#769

Permit DirectoryStore to open Zarr filesets which have been saved with {"dimension_separator": "/"}. Currently they silently fallback to using the fill_value.

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)

Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
@codecov

codecovBot commented Jun 14, 2021

Copy link
Copy Markdown

Codecov Report

Merging #773 (a5f1811) into master (ce04aaa) will decrease coverage by 0.08%.
The diff coverage is 98.41%.

@@ Coverage Diff @@## master #773 +/- ##
==========================================
- Coverage 99.94% 99.85% -0.09% 
==========================================
Files 30 31 +1 Lines 10586 10613 +27 ==========================================
+ Hits 10580 10598 +18 - Misses 6 15 +9 
Impacted FilesCoverage Δ
zarr/tests/test_dim_separator.py97.56% <97.56%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/n5.py100.00% <100.00%> (ø)
zarr/storage.py99.30% <100.00%> (-0.70%)⬇️
zarr/tests/test_storage.py100.00% <100.00%> (ø)

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Build failures are unrelated. See #774

store['0.0'] = b'xxx'
assert b'xxx' == store['0.0']
assert b'xxx' == store['0/0']
# assert b'xxx' == store['0/0']

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.

Why did we loose there? Doesn't the store normalise "." -> "/" anyway?

@joshmoorejoshmooreJun 15, 2021

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.

I tried to describe in the commit message on e183566, at least to the best of my understanding:

Previous tests (now commented out) used logic in the store classes to convert "0/0" keys into "0.0" keys, forcing the store to be aware of array details. This tries to swap the logic so that stores are responsible for passing dimension separator values down to the arrays only. Since arrays can also get the dimension_separator value from a .zarray file they are now in charge.

@jakirkham

Copy link
Copy Markdown
Member

Build failures are unrelated. See #774

That's merged. Would merge master back into this PR (as I don't think GH Actions does that itself)

@pep8speaks

pep8speaks commented Jun 17, 2021

Copy link
Copy Markdown

Hello @joshmoore! 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 2021-08-19 13:55:46 UTC

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Pushed more tests based on the blurb from @martindurant in #769. Note that without the fix in this PR these are the failures:

zarr/tests/test_dim_separator.py::test_nested[static_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_default] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_default] FAILED

@joshmoore
joshmoore marked this pull request as ready for review August 17, 2021 11:55
@joshmoorejoshmoore mentioned this pull request Aug 17, 2021
5 tasks
Comment threadzarr/core.py

def _chunk_key(self, chunk_coords):
return self._key_prefix + '.'.join(map(str, chunk_coords))
return self._key_prefix + self._dimension_separator.join(map(str, chunk_coords))

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.

Can you explain how this change is compatible with FSStore._normalize_key? https://github.com/zarr-developers/zarr-python/blob/master/zarr/storage.py#L1076

FSStore._normalize_key assumes that all chunk keys are formatted foo/bar/0.0.0 -- this assumption is the basis of splitting the chunk key into a prefix and a chunk ID via key.split('/'). As I understand it, this change breaks this assumption.

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.

Reading the flat and nested fixtures from this repo (zarr.open(f"file:///tmp/{x}")[:]) with some sloppy debugging in place shows:

| | Array._chunk_key | FSStore._normalize_keys |
|---------------|------------------|-------------------------|
| master:nested | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| master:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| PR:nested | (0, 0) --> 0/0 | 0/0 --> 0/0 |
| PR:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |

which likely points to some logic in FSStore being ripe for removal since the Store is basically just accepting what what the Array has detected. Now, how it is that that's working with your PR, I still haven't figured out.

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.

Right, as your test shows this is fine for FSStore (and maybe we don't need this code in the store at all if the chunk keys come pre-normalized). But this situation is dire for N5Stores, which need to be able to re-order the chunk keys before writing to storage.

joshmoore added a commit to joshmoore/zarr-python that referenced this pull request Aug 19, 2021
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: zarr-developers#773zarr-developers#793
@joshmoore

Copy link
Copy Markdown
MemberAuthor

See the extended discussion with @d-v-b at https://gitter.im/zarr-developers/community?at=611e5f31a1ffab59400448cc. Current proposal is to have N5 stores act like they are still using "." internally in order to allow them to differentiate between Zarr-like keys and N5-like keys and then convert to "/"-based keys just before writing. A result of this is that you can hack access to the true N5 locations by using "/"-based keys as questioned by @martindurant in #773 (comment)

joshmoore added a commit to joshmoore/zarr_implementations that referenced this pull request Aug 19, 2021
@joshmoore

Copy link
Copy Markdown
MemberAuthor

Please see the additional evidence of zarr-developers/zarr_implementations#47 (and please ignore the code coverage failure behind the curtain... 🧙🏽 )

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Taking @d-v-b's 👍 on #773 (comment) as a sign-off. Merging and starting to prep a release.

@joshmoore
joshmoore merged commit da88aa3 into zarr-developers:masterAug 20, 2021
@joshmoore
joshmoore deleted the fix-dstore branch August 20, 2021 13:33
@joshmoorejoshmoore mentioned this pull request Aug 20, 2021
joshmoore added a commit that referenced this pull request Sep 19, 2021
* Drop skip_if_nested_chunks from test_storage.py
* Add failing nested test
* Make DirectoryStore dimension_separator aware
* Migrate key logic to core rather than storage
Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
* Fix linting in new test
* Extend the test suite for dim_sep
* add n5fsstore and tests
* slightly smarter kwarg interception
* remove outdated unittest ref and fix the name of a test func
* fix massive string block and fix default key_separator kwarg for FSStore
* flake8
* promote n5store to toplevel import and fix examples in docstring
* Try fsspec 2021.7 (see #802)
* Revert "Try fsspec 2021.7 (see #802)"
This reverts commit 68adca5.
* Add missing core tests for N5FSStore, and rchanges required for making them pass
* tmp: debug
* uncomment N5 chunk ordering test
* more commented tests get uncommented
* add dimension_separator to array metadata adaptor
* Revert "tmp: debug"
This reverts commit ee9cdbc.
* Attempt failed: keeping '.' and switching
* Revert "Attempt failed: keeping '.' and switching"
This reverts commit 51b3109.
* regex: attempt failed due to slight diff in files
* Revert "regex: attempt failed due to slight diff in files"
This reverts commit 3daea7c.
* N5: use "." internally for dimension separation
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: #773#793
* move FSSpec import guard
* remove os.path.sep concatenation in listdir that was erroring a test, and add a mea culpa docstring about the dimension_separator for n5 stores
* resolve merge conflicts in favor of upstream
* make listdir implementation for n5fsstore look more like fsstore's listdir, and add crucial lstrip
* Update hexdigest tests for N5Stores to account for the presence of the dimension_separator keyword now present in metadata
* Add tests for dimension_separator in array meta for N5Stores
* N5FSStore: try to increase code coverage
* Adds a test for the dimension_separator warning
* uses the parent test_complex for listdir
* "nocover" the import error since fsspec is ever present
* flake8
* add chunk nesting test to N5FSStore test suite
* make array_meta_key, group_meta_key, attrs_key private
* N5FSStore: Remove ImportError test
FSStore only throws ModuleNotFoundError on initialization
rather than on import. Therefore N5FSStore does the same.
If this *weren't* the case, then the import in zarr/init
would need to test the import as well, which isn't the case.
Co-authored-by: jmoore <josh@glencoesoftware.com>
Co-authored-by: Josh Moore <j.a.moore@dundee.ac.uk>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Confusion about the dimension_separator keyword

5 participants

@joshmoore@jakirkham@pep8speaks@d-v-b@martindurant
, '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

Fix DirectoryStore - #773

Merged
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore
Aug 20, 2021
Merged

Fix DirectoryStore#773
joshmoore merged 12 commits into
zarr-developers:masterfrom
joshmoore:fix-dstore

Conversation

@joshmoore

Copy link
Copy Markdown
Member

fix#769

Permit DirectoryStore to open Zarr filesets which have been saved with {"dimension_separator": "/"}. Currently they silently fallback to using the fill_value.

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)

Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
@codecov

codecovBot commented Jun 14, 2021

Copy link
Copy Markdown

Codecov Report

Merging #773 (a5f1811) into master (ce04aaa) will decrease coverage by 0.08%.
The diff coverage is 98.41%.

@@ Coverage Diff @@## master #773 +/- ##
==========================================
- Coverage 99.94% 99.85% -0.09% 
==========================================
Files 30 31 +1 Lines 10586 10613 +27 ==========================================
+ Hits 10580 10598 +18 - Misses 6 15 +9 
Impacted FilesCoverage Δ
zarr/tests/test_dim_separator.py97.56% <97.56%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/n5.py100.00% <100.00%> (ø)
zarr/storage.py99.30% <100.00%> (-0.70%)⬇️
zarr/tests/test_storage.py100.00% <100.00%> (ø)

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Build failures are unrelated. See #774

store['0.0'] = b'xxx'
assert b'xxx' == store['0.0']
assert b'xxx' == store['0/0']
# assert b'xxx' == store['0/0']

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.

Why did we loose there? Doesn't the store normalise "." -> "/" anyway?

@joshmoorejoshmooreJun 15, 2021

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.

I tried to describe in the commit message on e183566, at least to the best of my understanding:

Previous tests (now commented out) used logic in the store classes to convert "0/0" keys into "0.0" keys, forcing the store to be aware of array details. This tries to swap the logic so that stores are responsible for passing dimension separator values down to the arrays only. Since arrays can also get the dimension_separator value from a .zarray file they are now in charge.

@jakirkham

Copy link
Copy Markdown
Member

Build failures are unrelated. See #774

That's merged. Would merge master back into this PR (as I don't think GH Actions does that itself)

@pep8speaks

pep8speaks commented Jun 17, 2021

Copy link
Copy Markdown

Hello @joshmoore! 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 2021-08-19 13:55:46 UTC

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Pushed more tests based on the blurb from @martindurant in #769. Note that without the fix in this PR these are the failures:

zarr/tests/test_dim_separator.py::test_nested[static_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[directory_default] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_flat] FAILED
zarr/tests/test_dim_separator.py::test_nested[fs_default] FAILED

@joshmoore
joshmoore marked this pull request as ready for review August 17, 2021 11:55
@joshmoorejoshmoore mentioned this pull request Aug 17, 2021
5 tasks
Comment threadzarr/core.py

def _chunk_key(self, chunk_coords):
return self._key_prefix + '.'.join(map(str, chunk_coords))
return self._key_prefix + self._dimension_separator.join(map(str, chunk_coords))

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.

Can you explain how this change is compatible with FSStore._normalize_key? https://github.com/zarr-developers/zarr-python/blob/master/zarr/storage.py#L1076

FSStore._normalize_key assumes that all chunk keys are formatted foo/bar/0.0.0 -- this assumption is the basis of splitting the chunk key into a prefix and a chunk ID via key.split('/'). As I understand it, this change breaks this assumption.

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.

Reading the flat and nested fixtures from this repo (zarr.open(f"file:///tmp/{x}")[:]) with some sloppy debugging in place shows:

| | Array._chunk_key | FSStore._normalize_keys |
|---------------|------------------|-------------------------|
| master:nested | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| master:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |
| PR:nested | (0, 0) --> 0/0 | 0/0 --> 0/0 |
| PR:flat | (0, 0) --> 0.0 | 0.0 --> 0.0 |

which likely points to some logic in FSStore being ripe for removal since the Store is basically just accepting what what the Array has detected. Now, how it is that that's working with your PR, I still haven't figured out.

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.

Right, as your test shows this is fine for FSStore (and maybe we don't need this code in the store at all if the chunk keys come pre-normalized). But this situation is dire for N5Stores, which need to be able to re-order the chunk keys before writing to storage.

joshmoore added a commit to joshmoore/zarr-python that referenced this pull request Aug 19, 2021
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: zarr-developers#773zarr-developers#793
@joshmoore

Copy link
Copy Markdown
MemberAuthor

See the extended discussion with @d-v-b at https://gitter.im/zarr-developers/community?at=611e5f31a1ffab59400448cc. Current proposal is to have N5 stores act like they are still using "." internally in order to allow them to differentiate between Zarr-like keys and N5-like keys and then convert to "/"-based keys just before writing. A result of this is that you can hack access to the true N5 locations by using "/"-based keys as questioned by @martindurant in #773 (comment)

joshmoore added a commit to joshmoore/zarr_implementations that referenced this pull request Aug 19, 2021
@joshmoore

Copy link
Copy Markdown
MemberAuthor

Please see the additional evidence of zarr-developers/zarr_implementations#47 (and please ignore the code coverage failure behind the curtain... 🧙🏽 )

@joshmoore

Copy link
Copy Markdown
MemberAuthor

Taking @d-v-b's 👍 on #773 (comment) as a sign-off. Merging and starting to prep a release.

@joshmoore
joshmoore merged commit da88aa3 into zarr-developers:masterAug 20, 2021
@joshmoore
joshmoore deleted the fix-dstore branch August 20, 2021 13:33
@joshmoorejoshmoore mentioned this pull request Aug 20, 2021
joshmoore added a commit that referenced this pull request Sep 19, 2021
* Drop skip_if_nested_chunks from test_storage.py
* Add failing nested test
* Make DirectoryStore dimension_separator aware
* Migrate key logic to core rather than storage
Previous tests (now commented out) used logic in the store
classes to convert "0/0" keys into "0.0" keys, forcing the
store to be aware of array details. This tries to swap the
logic so that stores are responsible for passing dimension
separator values down to the arrays only. Since arrays can
also get the dimension_separator value from a .zarray file
they are now in charge.
* Fix linting in new test
* Extend the test suite for dim_sep
* add n5fsstore and tests
* slightly smarter kwarg interception
* remove outdated unittest ref and fix the name of a test func
* fix massive string block and fix default key_separator kwarg for FSStore
* flake8
* promote n5store to toplevel import and fix examples in docstring
* Try fsspec 2021.7 (see #802)
* Revert "Try fsspec 2021.7 (see #802)"
This reverts commit 68adca5.
* Add missing core tests for N5FSStore, and rchanges required for making them pass
* tmp: debug
* uncomment N5 chunk ordering test
* more commented tests get uncommented
* add dimension_separator to array metadata adaptor
* Revert "tmp: debug"
This reverts commit ee9cdbc.
* Attempt failed: keeping '.' and switching
* Revert "Attempt failed: keeping '.' and switching"
This reverts commit 51b3109.
* regex: attempt failed due to slight diff in files
* Revert "regex: attempt failed due to slight diff in files"
This reverts commit 3daea7c.
* N5: use "." internally for dimension separation
This allows N5 to detect the split between key and chunks
and pre-process them (re-ordering and changing the separator).
see: #773#793
* move FSSpec import guard
* remove os.path.sep concatenation in listdir that was erroring a test, and add a mea culpa docstring about the dimension_separator for n5 stores
* resolve merge conflicts in favor of upstream
* make listdir implementation for n5fsstore look more like fsstore's listdir, and add crucial lstrip
* Update hexdigest tests for N5Stores to account for the presence of the dimension_separator keyword now present in metadata
* Add tests for dimension_separator in array meta for N5Stores
* N5FSStore: try to increase code coverage
* Adds a test for the dimension_separator warning
* uses the parent test_complex for listdir
* "nocover" the import error since fsspec is ever present
* flake8
* add chunk nesting test to N5FSStore test suite
* make array_meta_key, group_meta_key, attrs_key private
* N5FSStore: Remove ImportError test
FSStore only throws ModuleNotFoundError on initialization
rather than on import. Therefore N5FSStore does the same.
If this *weren't* the case, then the import in zarr/init
would need to test the import as well, which isn't the case.
Co-authored-by: jmoore <josh@glencoesoftware.com>
Co-authored-by: Josh Moore <j.a.moore@dundee.ac.uk>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Confusion about the dimension_separator keyword

5 participants

@joshmoore@jakirkham@pep8speaks@d-v-b@martindurant