AsyncGenerator → AsyncIterator - #2381

Merged
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async
Nov 8, 2024
Merged

AsyncGenerator → AsyncIterator#2381
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async

Conversation

@DimitriPapadopoulos

@DimitriPapadopoulosDimitriPapadopoulos commented Oct 15, 2024

Copy link
Copy Markdown
Contributor

Fixes#2377.

See microsoft/pyright#4741.

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)

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from e86ee25 to 694af4bCompareOctober 16, 2024 06:23
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review October 16, 2024 06:29
@paraseba

Copy link
Copy Markdown
Contributor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

Most implementations probably won't need these functions to be async, but it's a more general type for some implementation that may need it.

Comment threadsrc/zarr/abc/store.py Outdated
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 46dc84b to 52e66c9CompareOctober 16, 2024 12:13
@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

The roadmap defines the Store API as follows and should be updated:

asyncdeflist(self) ->List[str]:
... # required for listable storesasyncdeflist_prefix(self, prefix: str) ->List[str]:
... # required for listable storesasyncdeflist_dir(self, prefix: str) ->List[str]:
... # required for listable stores

All current child classes use the prefix argument. I don't think it should be removed.

As for the return value, not sure why it changed from List[str] to AsyncGenerator[str, None] in #1844. Switch back to AsyncGenerator[str]?

@paraseba

Copy link
Copy Markdown
Contributor

All current child classes use the prefix argument. I don't think it should be removed.

Sorry, I just missed the argument in the example, definitely we shouldn't drop it. My point was about returning AsyncIterator instead of AsyncGenerator, the later is more of an implementation detail. We definitely don't want list because that would force the whole thing to live in memory at once.

@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Meanwhile, I tried to revert the return type from AsyncGenerator[str, None] to AsyncGenerator[str], to see what happens.

As for the AsyncGeneratorAsyncIterator change, how about addressing it in an issue and a separate PR?

@paraseba

Copy link
Copy Markdown
Contributor

As for the AsyncGenerator → AsyncIterator change, how about addressing it in an issue and a separate PR?

It's definitely not a big deal, AsyncGenerator[str] also works. But, doing it in separate PR would require changing the abc and every implementation twice.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

OK, let me try then. It's just that's I'll have to modify all child classes.

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 4 times, most recently from 844ccad to 8d3ead3CompareOctober 16, 2024 21:02
Comment threadsrc/zarr/abc/store.py Outdated
Comment threadsrc/zarr/storage/local.py Outdated
if p.is_file():
yield str(p).replace(to_strip, "")
allfiles = [str(p).replace(to_strip, "") for p in self.root.rglob("*") if p.is_file()]
return (onefile for onefile in allfiles)

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.

we don't want to materialize the full allfiles list in memory. Can you use async for instead? Here is an example of how you could do this:

fromcollections.abcimportAsyncIteratorfromabcimportABC, abstractmethodclassFoo(ABC):
@abstractmethodasyncdeffoo(self) ->AsyncIterator[str]:
...
classBar(Foo):
asyncdefhelper(self) ->AsyncIterator[str]:
raiseValueError("")
asyncdeffoo(self) ->AsyncIterator[str]:
return (xasyncforxinawaitself.helper())

This code should work and mypy successfully, and doesn't materialize the results of calling helper.

@DimitriPapadopoulosDimitriPapadopoulosOct 19, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm a little bit lost here.

  • What we have here are functions that yield. That's a generator. Why create an iterator?
  • I'm afraid I don't have enough experience with async and no time to learn it in the short term. For example, I'm not even sure how to identify iterables and awaitables.

I suggest We keep AsyncGenerator for now. What would be the benefit of an AsyncIterator in this context?

@jhamman

Copy link
Copy Markdown
Member

@DimitriPapadopoulos - are you planning to return to this?

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 80c5fff to 655a149CompareNovember 5, 2024 06:34
@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

I tried briefly, but I cannot get typing to work after rebasing. I need to take a thorough look.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from 113e9cd to 6c8dd5cCompareNovember 7, 2024 15:22
@DimitriPapadopoulosDimitriPapadopoulos changed the title Make methods of abstract base class asyncAsyncGenerator → AsyncIteratorNov 7, 2024
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 1a824a5 to 3fa0e1dCompareNovember 7, 2024 17:31
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review November 7, 2024 17:31

@jhammanjhamman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm happy here (except for the requested docstring changes).

Comment threadsrc/zarr/abc/store.py Outdated
Comment on lines +339 to +343
Notes
-----
This method should be async,
`How to correctly specify type hints with AsyncGenerator and AsyncContextManager <https://stackoverflow.com/questions/68905848/how-to-correctly-specify-type-hints-with-asyncgenerator-and-asynccontextmanager>`_
explains why it is not.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to move this to a comment rather than the public docstring. Most implementations will inherit this and end users don't need to know about this implementation detail.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, I wasn't sure about it. I put it in the documentation because it documents an inconsistency in function signatures.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ideally, I would document this using something similar to disabling Pylint warning W0236:

# pylint: disable=invalid-overridden-method

Unfortunately there's no equivalent rule in ruff, as far as I can see.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed.

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.

Thanks.

@jhamman
jhamman merged commit 693e11c into zarr-developers:mainNov 8, 2024
@jhammanjhamman mentioned this pull request Dec 3, 2024
6 tasks
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.

Inconsistent overridden method

3 participants

@DimitriPapadopoulos@paraseba@jhamman
, '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

AsyncGenerator → AsyncIterator - #2381

Merged
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async
Nov 8, 2024
Merged

AsyncGenerator → AsyncIterator#2381
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async

Conversation

@DimitriPapadopoulos

@DimitriPapadopoulosDimitriPapadopoulos commented Oct 15, 2024

Copy link
Copy Markdown
Contributor

Fixes#2377.

See microsoft/pyright#4741.

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)

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from e86ee25 to 694af4bCompareOctober 16, 2024 06:23
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review October 16, 2024 06:29
@paraseba

Copy link
Copy Markdown
Contributor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

Most implementations probably won't need these functions to be async, but it's a more general type for some implementation that may need it.

Comment threadsrc/zarr/abc/store.py Outdated
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 46dc84b to 52e66c9CompareOctober 16, 2024 12:13
@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

The roadmap defines the Store API as follows and should be updated:

asyncdeflist(self) ->List[str]:
... # required for listable storesasyncdeflist_prefix(self, prefix: str) ->List[str]:
... # required for listable storesasyncdeflist_dir(self, prefix: str) ->List[str]:
... # required for listable stores

All current child classes use the prefix argument. I don't think it should be removed.

As for the return value, not sure why it changed from List[str] to AsyncGenerator[str, None] in #1844. Switch back to AsyncGenerator[str]?

@paraseba

Copy link
Copy Markdown
Contributor

All current child classes use the prefix argument. I don't think it should be removed.

Sorry, I just missed the argument in the example, definitely we shouldn't drop it. My point was about returning AsyncIterator instead of AsyncGenerator, the later is more of an implementation detail. We definitely don't want list because that would force the whole thing to live in memory at once.

@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Meanwhile, I tried to revert the return type from AsyncGenerator[str, None] to AsyncGenerator[str], to see what happens.

As for the AsyncGeneratorAsyncIterator change, how about addressing it in an issue and a separate PR?

@paraseba

Copy link
Copy Markdown
Contributor

As for the AsyncGenerator → AsyncIterator change, how about addressing it in an issue and a separate PR?

It's definitely not a big deal, AsyncGenerator[str] also works. But, doing it in separate PR would require changing the abc and every implementation twice.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

OK, let me try then. It's just that's I'll have to modify all child classes.

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 4 times, most recently from 844ccad to 8d3ead3CompareOctober 16, 2024 21:02
Comment threadsrc/zarr/abc/store.py Outdated
Comment threadsrc/zarr/storage/local.py Outdated
if p.is_file():
yield str(p).replace(to_strip, "")
allfiles = [str(p).replace(to_strip, "") for p in self.root.rglob("*") if p.is_file()]
return (onefile for onefile in allfiles)

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.

we don't want to materialize the full allfiles list in memory. Can you use async for instead? Here is an example of how you could do this:

fromcollections.abcimportAsyncIteratorfromabcimportABC, abstractmethodclassFoo(ABC):
@abstractmethodasyncdeffoo(self) ->AsyncIterator[str]:
...
classBar(Foo):
asyncdefhelper(self) ->AsyncIterator[str]:
raiseValueError("")
asyncdeffoo(self) ->AsyncIterator[str]:
return (xasyncforxinawaitself.helper())

This code should work and mypy successfully, and doesn't materialize the results of calling helper.

@DimitriPapadopoulosDimitriPapadopoulosOct 19, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm a little bit lost here.

  • What we have here are functions that yield. That's a generator. Why create an iterator?
  • I'm afraid I don't have enough experience with async and no time to learn it in the short term. For example, I'm not even sure how to identify iterables and awaitables.

I suggest We keep AsyncGenerator for now. What would be the benefit of an AsyncIterator in this context?

@jhamman

Copy link
Copy Markdown
Member

@DimitriPapadopoulos - are you planning to return to this?

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 80c5fff to 655a149CompareNovember 5, 2024 06:34
@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

I tried briefly, but I cannot get typing to work after rebasing. I need to take a thorough look.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from 113e9cd to 6c8dd5cCompareNovember 7, 2024 15:22
@DimitriPapadopoulosDimitriPapadopoulos changed the title Make methods of abstract base class asyncAsyncGenerator → AsyncIteratorNov 7, 2024
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 1a824a5 to 3fa0e1dCompareNovember 7, 2024 17:31
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review November 7, 2024 17:31

@jhammanjhamman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm happy here (except for the requested docstring changes).

Comment threadsrc/zarr/abc/store.py Outdated
Comment on lines +339 to +343
Notes
-----
This method should be async,
`How to correctly specify type hints with AsyncGenerator and AsyncContextManager <https://stackoverflow.com/questions/68905848/how-to-correctly-specify-type-hints-with-asyncgenerator-and-asynccontextmanager>`_
explains why it is not.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to move this to a comment rather than the public docstring. Most implementations will inherit this and end users don't need to know about this implementation detail.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, I wasn't sure about it. I put it in the documentation because it documents an inconsistency in function signatures.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ideally, I would document this using something similar to disabling Pylint warning W0236:

# pylint: disable=invalid-overridden-method

Unfortunately there's no equivalent rule in ruff, as far as I can see.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed.

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.

Thanks.

@jhamman
jhamman merged commit 693e11c into zarr-developers:mainNov 8, 2024
@jhammanjhamman mentioned this pull request Dec 3, 2024
6 tasks
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.

Inconsistent overridden method

3 participants

@DimitriPapadopoulos@paraseba@jhamman
, '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

AsyncGenerator → AsyncIterator - #2381

Merged
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async
Nov 8, 2024
Merged

AsyncGenerator → AsyncIterator#2381
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async

Conversation

@DimitriPapadopoulos

@DimitriPapadopoulosDimitriPapadopoulos commented Oct 15, 2024

Copy link
Copy Markdown
Contributor

Fixes#2377.

See microsoft/pyright#4741.

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)

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from e86ee25 to 694af4bCompareOctober 16, 2024 06:23
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review October 16, 2024 06:29
@paraseba

Copy link
Copy Markdown
Contributor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

Most implementations probably won't need these functions to be async, but it's a more general type for some implementation that may need it.

Comment threadsrc/zarr/abc/store.py Outdated
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 46dc84b to 52e66c9CompareOctober 16, 2024 12:13
@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

The roadmap defines the Store API as follows and should be updated:

asyncdeflist(self) ->List[str]:
... # required for listable storesasyncdeflist_prefix(self, prefix: str) ->List[str]:
... # required for listable storesasyncdeflist_dir(self, prefix: str) ->List[str]:
... # required for listable stores

All current child classes use the prefix argument. I don't think it should be removed.

As for the return value, not sure why it changed from List[str] to AsyncGenerator[str, None] in #1844. Switch back to AsyncGenerator[str]?

@paraseba

Copy link
Copy Markdown
Contributor

All current child classes use the prefix argument. I don't think it should be removed.

Sorry, I just missed the argument in the example, definitely we shouldn't drop it. My point was about returning AsyncIterator instead of AsyncGenerator, the later is more of an implementation detail. We definitely don't want list because that would force the whole thing to live in memory at once.

@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Meanwhile, I tried to revert the return type from AsyncGenerator[str, None] to AsyncGenerator[str], to see what happens.

As for the AsyncGeneratorAsyncIterator change, how about addressing it in an issue and a separate PR?

@paraseba

Copy link
Copy Markdown
Contributor

As for the AsyncGenerator → AsyncIterator change, how about addressing it in an issue and a separate PR?

It's definitely not a big deal, AsyncGenerator[str] also works. But, doing it in separate PR would require changing the abc and every implementation twice.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

OK, let me try then. It's just that's I'll have to modify all child classes.

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 4 times, most recently from 844ccad to 8d3ead3CompareOctober 16, 2024 21:02
Comment threadsrc/zarr/abc/store.py Outdated
Comment threadsrc/zarr/storage/local.py Outdated
if p.is_file():
yield str(p).replace(to_strip, "")
allfiles = [str(p).replace(to_strip, "") for p in self.root.rglob("*") if p.is_file()]
return (onefile for onefile in allfiles)

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.

we don't want to materialize the full allfiles list in memory. Can you use async for instead? Here is an example of how you could do this:

fromcollections.abcimportAsyncIteratorfromabcimportABC, abstractmethodclassFoo(ABC):
@abstractmethodasyncdeffoo(self) ->AsyncIterator[str]:
...
classBar(Foo):
asyncdefhelper(self) ->AsyncIterator[str]:
raiseValueError("")
asyncdeffoo(self) ->AsyncIterator[str]:
return (xasyncforxinawaitself.helper())

This code should work and mypy successfully, and doesn't materialize the results of calling helper.

@DimitriPapadopoulosDimitriPapadopoulosOct 19, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm a little bit lost here.

  • What we have here are functions that yield. That's a generator. Why create an iterator?
  • I'm afraid I don't have enough experience with async and no time to learn it in the short term. For example, I'm not even sure how to identify iterables and awaitables.

I suggest We keep AsyncGenerator for now. What would be the benefit of an AsyncIterator in this context?

@jhamman

Copy link
Copy Markdown
Member

@DimitriPapadopoulos - are you planning to return to this?

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 80c5fff to 655a149CompareNovember 5, 2024 06:34
@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

I tried briefly, but I cannot get typing to work after rebasing. I need to take a thorough look.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from 113e9cd to 6c8dd5cCompareNovember 7, 2024 15:22
@DimitriPapadopoulosDimitriPapadopoulos changed the title Make methods of abstract base class asyncAsyncGenerator → AsyncIteratorNov 7, 2024
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 1a824a5 to 3fa0e1dCompareNovember 7, 2024 17:31
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review November 7, 2024 17:31

@jhammanjhamman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm happy here (except for the requested docstring changes).

Comment threadsrc/zarr/abc/store.py Outdated
Comment on lines +339 to +343
Notes
-----
This method should be async,
`How to correctly specify type hints with AsyncGenerator and AsyncContextManager <https://stackoverflow.com/questions/68905848/how-to-correctly-specify-type-hints-with-asyncgenerator-and-asynccontextmanager>`_
explains why it is not.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to move this to a comment rather than the public docstring. Most implementations will inherit this and end users don't need to know about this implementation detail.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, I wasn't sure about it. I put it in the documentation because it documents an inconsistency in function signatures.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ideally, I would document this using something similar to disabling Pylint warning W0236:

# pylint: disable=invalid-overridden-method

Unfortunately there's no equivalent rule in ruff, as far as I can see.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed.

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.

Thanks.

@jhamman
jhamman merged commit 693e11c into zarr-developers:mainNov 8, 2024
@jhammanjhamman mentioned this pull request Dec 3, 2024
6 tasks
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.

Inconsistent overridden method

3 participants

@DimitriPapadopoulos@paraseba@jhamman
, '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

AsyncGenerator → AsyncIterator - #2381

Merged
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async
Nov 8, 2024
Merged

AsyncGenerator → AsyncIterator#2381
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async

Conversation

@DimitriPapadopoulos

@DimitriPapadopoulosDimitriPapadopoulos commented Oct 15, 2024

Copy link
Copy Markdown
Contributor

Fixes#2377.

See microsoft/pyright#4741.

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)

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from e86ee25 to 694af4bCompareOctober 16, 2024 06:23
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review October 16, 2024 06:29
@paraseba

Copy link
Copy Markdown
Contributor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

Most implementations probably won't need these functions to be async, but it's a more general type for some implementation that may need it.

Comment threadsrc/zarr/abc/store.py Outdated
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 46dc84b to 52e66c9CompareOctober 16, 2024 12:13
@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

The roadmap defines the Store API as follows and should be updated:

asyncdeflist(self) ->List[str]:
... # required for listable storesasyncdeflist_prefix(self, prefix: str) ->List[str]:
... # required for listable storesasyncdeflist_dir(self, prefix: str) ->List[str]:
... # required for listable stores

All current child classes use the prefix argument. I don't think it should be removed.

As for the return value, not sure why it changed from List[str] to AsyncGenerator[str, None] in #1844. Switch back to AsyncGenerator[str]?

@paraseba

Copy link
Copy Markdown
Contributor

All current child classes use the prefix argument. I don't think it should be removed.

Sorry, I just missed the argument in the example, definitely we shouldn't drop it. My point was about returning AsyncIterator instead of AsyncGenerator, the later is more of an implementation detail. We definitely don't want list because that would force the whole thing to live in memory at once.

@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Meanwhile, I tried to revert the return type from AsyncGenerator[str, None] to AsyncGenerator[str], to see what happens.

As for the AsyncGeneratorAsyncIterator change, how about addressing it in an issue and a separate PR?

@paraseba

Copy link
Copy Markdown
Contributor

As for the AsyncGenerator → AsyncIterator change, how about addressing it in an issue and a separate PR?

It's definitely not a big deal, AsyncGenerator[str] also works. But, doing it in separate PR would require changing the abc and every implementation twice.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

OK, let me try then. It's just that's I'll have to modify all child classes.

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 4 times, most recently from 844ccad to 8d3ead3CompareOctober 16, 2024 21:02
Comment threadsrc/zarr/abc/store.py Outdated
Comment threadsrc/zarr/storage/local.py Outdated
if p.is_file():
yield str(p).replace(to_strip, "")
allfiles = [str(p).replace(to_strip, "") for p in self.root.rglob("*") if p.is_file()]
return (onefile for onefile in allfiles)

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.

we don't want to materialize the full allfiles list in memory. Can you use async for instead? Here is an example of how you could do this:

fromcollections.abcimportAsyncIteratorfromabcimportABC, abstractmethodclassFoo(ABC):
@abstractmethodasyncdeffoo(self) ->AsyncIterator[str]:
...
classBar(Foo):
asyncdefhelper(self) ->AsyncIterator[str]:
raiseValueError("")
asyncdeffoo(self) ->AsyncIterator[str]:
return (xasyncforxinawaitself.helper())

This code should work and mypy successfully, and doesn't materialize the results of calling helper.

@DimitriPapadopoulosDimitriPapadopoulosOct 19, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm a little bit lost here.

  • What we have here are functions that yield. That's a generator. Why create an iterator?
  • I'm afraid I don't have enough experience with async and no time to learn it in the short term. For example, I'm not even sure how to identify iterables and awaitables.

I suggest We keep AsyncGenerator for now. What would be the benefit of an AsyncIterator in this context?

@jhamman

Copy link
Copy Markdown
Member

@DimitriPapadopoulos - are you planning to return to this?

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 80c5fff to 655a149CompareNovember 5, 2024 06:34
@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

I tried briefly, but I cannot get typing to work after rebasing. I need to take a thorough look.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from 113e9cd to 6c8dd5cCompareNovember 7, 2024 15:22
@DimitriPapadopoulosDimitriPapadopoulos changed the title Make methods of abstract base class asyncAsyncGenerator → AsyncIteratorNov 7, 2024
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 1a824a5 to 3fa0e1dCompareNovember 7, 2024 17:31
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review November 7, 2024 17:31

@jhammanjhamman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm happy here (except for the requested docstring changes).

Comment threadsrc/zarr/abc/store.py Outdated
Comment on lines +339 to +343
Notes
-----
This method should be async,
`How to correctly specify type hints with AsyncGenerator and AsyncContextManager <https://stackoverflow.com/questions/68905848/how-to-correctly-specify-type-hints-with-asyncgenerator-and-asynccontextmanager>`_
explains why it is not.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to move this to a comment rather than the public docstring. Most implementations will inherit this and end users don't need to know about this implementation detail.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, I wasn't sure about it. I put it in the documentation because it documents an inconsistency in function signatures.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ideally, I would document this using something similar to disabling Pylint warning W0236:

# pylint: disable=invalid-overridden-method

Unfortunately there's no equivalent rule in ruff, as far as I can see.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed.

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.

Thanks.

@jhamman
jhamman merged commit 693e11c into zarr-developers:mainNov 8, 2024
@jhammanjhamman mentioned this pull request Dec 3, 2024
6 tasks
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.

Inconsistent overridden method

3 participants

@DimitriPapadopoulos@paraseba@jhamman
, '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

AsyncGenerator → AsyncIterator - #2381

Merged
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async
Nov 8, 2024
Merged

AsyncGenerator → AsyncIterator#2381
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async

Conversation

@DimitriPapadopoulos

@DimitriPapadopoulosDimitriPapadopoulos commented Oct 15, 2024

Copy link
Copy Markdown
Contributor

Fixes#2377.

See microsoft/pyright#4741.

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)

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from e86ee25 to 694af4bCompareOctober 16, 2024 06:23
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review October 16, 2024 06:29
@paraseba

Copy link
Copy Markdown
Contributor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

Most implementations probably won't need these functions to be async, but it's a more general type for some implementation that may need it.

Comment threadsrc/zarr/abc/store.py Outdated
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 46dc84b to 52e66c9CompareOctober 16, 2024 12:13
@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

The roadmap defines the Store API as follows and should be updated:

asyncdeflist(self) ->List[str]:
... # required for listable storesasyncdeflist_prefix(self, prefix: str) ->List[str]:
... # required for listable storesasyncdeflist_dir(self, prefix: str) ->List[str]:
... # required for listable stores

All current child classes use the prefix argument. I don't think it should be removed.

As for the return value, not sure why it changed from List[str] to AsyncGenerator[str, None] in #1844. Switch back to AsyncGenerator[str]?

@paraseba

Copy link
Copy Markdown
Contributor

All current child classes use the prefix argument. I don't think it should be removed.

Sorry, I just missed the argument in the example, definitely we shouldn't drop it. My point was about returning AsyncIterator instead of AsyncGenerator, the later is more of an implementation detail. We definitely don't want list because that would force the whole thing to live in memory at once.

@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Meanwhile, I tried to revert the return type from AsyncGenerator[str, None] to AsyncGenerator[str], to see what happens.

As for the AsyncGeneratorAsyncIterator change, how about addressing it in an issue and a separate PR?

@paraseba

Copy link
Copy Markdown
Contributor

As for the AsyncGenerator → AsyncIterator change, how about addressing it in an issue and a separate PR?

It's definitely not a big deal, AsyncGenerator[str] also works. But, doing it in separate PR would require changing the abc and every implementation twice.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

OK, let me try then. It's just that's I'll have to modify all child classes.

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 4 times, most recently from 844ccad to 8d3ead3CompareOctober 16, 2024 21:02
Comment threadsrc/zarr/abc/store.py Outdated
Comment threadsrc/zarr/storage/local.py Outdated
if p.is_file():
yield str(p).replace(to_strip, "")
allfiles = [str(p).replace(to_strip, "") for p in self.root.rglob("*") if p.is_file()]
return (onefile for onefile in allfiles)

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.

we don't want to materialize the full allfiles list in memory. Can you use async for instead? Here is an example of how you could do this:

fromcollections.abcimportAsyncIteratorfromabcimportABC, abstractmethodclassFoo(ABC):
@abstractmethodasyncdeffoo(self) ->AsyncIterator[str]:
...
classBar(Foo):
asyncdefhelper(self) ->AsyncIterator[str]:
raiseValueError("")
asyncdeffoo(self) ->AsyncIterator[str]:
return (xasyncforxinawaitself.helper())

This code should work and mypy successfully, and doesn't materialize the results of calling helper.

@DimitriPapadopoulosDimitriPapadopoulosOct 19, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm a little bit lost here.

  • What we have here are functions that yield. That's a generator. Why create an iterator?
  • I'm afraid I don't have enough experience with async and no time to learn it in the short term. For example, I'm not even sure how to identify iterables and awaitables.

I suggest We keep AsyncGenerator for now. What would be the benefit of an AsyncIterator in this context?

@jhamman

Copy link
Copy Markdown
Member

@DimitriPapadopoulos - are you planning to return to this?

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 80c5fff to 655a149CompareNovember 5, 2024 06:34
@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

I tried briefly, but I cannot get typing to work after rebasing. I need to take a thorough look.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from 113e9cd to 6c8dd5cCompareNovember 7, 2024 15:22
@DimitriPapadopoulosDimitriPapadopoulos changed the title Make methods of abstract base class asyncAsyncGenerator → AsyncIteratorNov 7, 2024
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 1a824a5 to 3fa0e1dCompareNovember 7, 2024 17:31
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review November 7, 2024 17:31

@jhammanjhamman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm happy here (except for the requested docstring changes).

Comment threadsrc/zarr/abc/store.py Outdated
Comment on lines +339 to +343
Notes
-----
This method should be async,
`How to correctly specify type hints with AsyncGenerator and AsyncContextManager <https://stackoverflow.com/questions/68905848/how-to-correctly-specify-type-hints-with-asyncgenerator-and-asynccontextmanager>`_
explains why it is not.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to move this to a comment rather than the public docstring. Most implementations will inherit this and end users don't need to know about this implementation detail.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, I wasn't sure about it. I put it in the documentation because it documents an inconsistency in function signatures.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ideally, I would document this using something similar to disabling Pylint warning W0236:

# pylint: disable=invalid-overridden-method

Unfortunately there's no equivalent rule in ruff, as far as I can see.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed.

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.

Thanks.

@jhamman
jhamman merged commit 693e11c into zarr-developers:mainNov 8, 2024
@jhammanjhamman mentioned this pull request Dec 3, 2024
6 tasks
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.

Inconsistent overridden method

3 participants

@DimitriPapadopoulos@paraseba@jhamman
, '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

AsyncGenerator → AsyncIterator - #2381

Merged
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async
Nov 8, 2024
Merged

AsyncGenerator → AsyncIterator#2381
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async

Conversation

@DimitriPapadopoulos

@DimitriPapadopoulosDimitriPapadopoulos commented Oct 15, 2024

Copy link
Copy Markdown
Contributor

Fixes#2377.

See microsoft/pyright#4741.

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)

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from e86ee25 to 694af4bCompareOctober 16, 2024 06:23
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review October 16, 2024 06:29
@paraseba

Copy link
Copy Markdown
Contributor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

Most implementations probably won't need these functions to be async, but it's a more general type for some implementation that may need it.

Comment threadsrc/zarr/abc/store.py Outdated
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 46dc84b to 52e66c9CompareOctober 16, 2024 12:13
@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

The roadmap defines the Store API as follows and should be updated:

asyncdeflist(self) ->List[str]:
... # required for listable storesasyncdeflist_prefix(self, prefix: str) ->List[str]:
... # required for listable storesasyncdeflist_dir(self, prefix: str) ->List[str]:
... # required for listable stores

All current child classes use the prefix argument. I don't think it should be removed.

As for the return value, not sure why it changed from List[str] to AsyncGenerator[str, None] in #1844. Switch back to AsyncGenerator[str]?

@paraseba

Copy link
Copy Markdown
Contributor

All current child classes use the prefix argument. I don't think it should be removed.

Sorry, I just missed the argument in the example, definitely we shouldn't drop it. My point was about returning AsyncIterator instead of AsyncGenerator, the later is more of an implementation detail. We definitely don't want list because that would force the whole thing to live in memory at once.

@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Meanwhile, I tried to revert the return type from AsyncGenerator[str, None] to AsyncGenerator[str], to see what happens.

As for the AsyncGeneratorAsyncIterator change, how about addressing it in an issue and a separate PR?

@paraseba

Copy link
Copy Markdown
Contributor

As for the AsyncGenerator → AsyncIterator change, how about addressing it in an issue and a separate PR?

It's definitely not a big deal, AsyncGenerator[str] also works. But, doing it in separate PR would require changing the abc and every implementation twice.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

OK, let me try then. It's just that's I'll have to modify all child classes.

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 4 times, most recently from 844ccad to 8d3ead3CompareOctober 16, 2024 21:02
Comment threadsrc/zarr/abc/store.py Outdated
Comment threadsrc/zarr/storage/local.py Outdated
if p.is_file():
yield str(p).replace(to_strip, "")
allfiles = [str(p).replace(to_strip, "") for p in self.root.rglob("*") if p.is_file()]
return (onefile for onefile in allfiles)

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.

we don't want to materialize the full allfiles list in memory. Can you use async for instead? Here is an example of how you could do this:

fromcollections.abcimportAsyncIteratorfromabcimportABC, abstractmethodclassFoo(ABC):
@abstractmethodasyncdeffoo(self) ->AsyncIterator[str]:
...
classBar(Foo):
asyncdefhelper(self) ->AsyncIterator[str]:
raiseValueError("")
asyncdeffoo(self) ->AsyncIterator[str]:
return (xasyncforxinawaitself.helper())

This code should work and mypy successfully, and doesn't materialize the results of calling helper.

@DimitriPapadopoulosDimitriPapadopoulosOct 19, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm a little bit lost here.

  • What we have here are functions that yield. That's a generator. Why create an iterator?
  • I'm afraid I don't have enough experience with async and no time to learn it in the short term. For example, I'm not even sure how to identify iterables and awaitables.

I suggest We keep AsyncGenerator for now. What would be the benefit of an AsyncIterator in this context?

@jhamman

Copy link
Copy Markdown
Member

@DimitriPapadopoulos - are you planning to return to this?

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 80c5fff to 655a149CompareNovember 5, 2024 06:34
@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

I tried briefly, but I cannot get typing to work after rebasing. I need to take a thorough look.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from 113e9cd to 6c8dd5cCompareNovember 7, 2024 15:22
@DimitriPapadopoulosDimitriPapadopoulos changed the title Make methods of abstract base class asyncAsyncGenerator → AsyncIteratorNov 7, 2024
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 1a824a5 to 3fa0e1dCompareNovember 7, 2024 17:31
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review November 7, 2024 17:31

@jhammanjhamman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm happy here (except for the requested docstring changes).

Comment threadsrc/zarr/abc/store.py Outdated
Comment on lines +339 to +343
Notes
-----
This method should be async,
`How to correctly specify type hints with AsyncGenerator and AsyncContextManager <https://stackoverflow.com/questions/68905848/how-to-correctly-specify-type-hints-with-asyncgenerator-and-asynccontextmanager>`_
explains why it is not.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to move this to a comment rather than the public docstring. Most implementations will inherit this and end users don't need to know about this implementation detail.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, I wasn't sure about it. I put it in the documentation because it documents an inconsistency in function signatures.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ideally, I would document this using something similar to disabling Pylint warning W0236:

# pylint: disable=invalid-overridden-method

Unfortunately there's no equivalent rule in ruff, as far as I can see.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed.

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.

Thanks.

@jhamman
jhamman merged commit 693e11c into zarr-developers:mainNov 8, 2024
@jhammanjhamman mentioned this pull request Dec 3, 2024
6 tasks
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.

Inconsistent overridden method

3 participants

@DimitriPapadopoulos@paraseba@jhamman
, '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

AsyncGenerator → AsyncIterator - #2381

Merged
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async
Nov 8, 2024
Merged

AsyncGenerator → AsyncIterator#2381
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async

Conversation

@DimitriPapadopoulos

@DimitriPapadopoulosDimitriPapadopoulos commented Oct 15, 2024

Copy link
Copy Markdown
Contributor

Fixes#2377.

See microsoft/pyright#4741.

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)

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from e86ee25 to 694af4bCompareOctober 16, 2024 06:23
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review October 16, 2024 06:29
@paraseba

Copy link
Copy Markdown
Contributor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

Most implementations probably won't need these functions to be async, but it's a more general type for some implementation that may need it.

Comment threadsrc/zarr/abc/store.py Outdated
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 46dc84b to 52e66c9CompareOctober 16, 2024 12:13
@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

The roadmap defines the Store API as follows and should be updated:

asyncdeflist(self) ->List[str]:
... # required for listable storesasyncdeflist_prefix(self, prefix: str) ->List[str]:
... # required for listable storesasyncdeflist_dir(self, prefix: str) ->List[str]:
... # required for listable stores

All current child classes use the prefix argument. I don't think it should be removed.

As for the return value, not sure why it changed from List[str] to AsyncGenerator[str, None] in #1844. Switch back to AsyncGenerator[str]?

@paraseba

Copy link
Copy Markdown
Contributor

All current child classes use the prefix argument. I don't think it should be removed.

Sorry, I just missed the argument in the example, definitely we shouldn't drop it. My point was about returning AsyncIterator instead of AsyncGenerator, the later is more of an implementation detail. We definitely don't want list because that would force the whole thing to live in memory at once.

@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Meanwhile, I tried to revert the return type from AsyncGenerator[str, None] to AsyncGenerator[str], to see what happens.

As for the AsyncGeneratorAsyncIterator change, how about addressing it in an issue and a separate PR?

@paraseba

Copy link
Copy Markdown
Contributor

As for the AsyncGenerator → AsyncIterator change, how about addressing it in an issue and a separate PR?

It's definitely not a big deal, AsyncGenerator[str] also works. But, doing it in separate PR would require changing the abc and every implementation twice.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

OK, let me try then. It's just that's I'll have to modify all child classes.

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 4 times, most recently from 844ccad to 8d3ead3CompareOctober 16, 2024 21:02
Comment threadsrc/zarr/abc/store.py Outdated
Comment threadsrc/zarr/storage/local.py Outdated
if p.is_file():
yield str(p).replace(to_strip, "")
allfiles = [str(p).replace(to_strip, "") for p in self.root.rglob("*") if p.is_file()]
return (onefile for onefile in allfiles)

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.

we don't want to materialize the full allfiles list in memory. Can you use async for instead? Here is an example of how you could do this:

fromcollections.abcimportAsyncIteratorfromabcimportABC, abstractmethodclassFoo(ABC):
@abstractmethodasyncdeffoo(self) ->AsyncIterator[str]:
...
classBar(Foo):
asyncdefhelper(self) ->AsyncIterator[str]:
raiseValueError("")
asyncdeffoo(self) ->AsyncIterator[str]:
return (xasyncforxinawaitself.helper())

This code should work and mypy successfully, and doesn't materialize the results of calling helper.

@DimitriPapadopoulosDimitriPapadopoulosOct 19, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm a little bit lost here.

  • What we have here are functions that yield. That's a generator. Why create an iterator?
  • I'm afraid I don't have enough experience with async and no time to learn it in the short term. For example, I'm not even sure how to identify iterables and awaitables.

I suggest We keep AsyncGenerator for now. What would be the benefit of an AsyncIterator in this context?

@jhamman

Copy link
Copy Markdown
Member

@DimitriPapadopoulos - are you planning to return to this?

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 80c5fff to 655a149CompareNovember 5, 2024 06:34
@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

I tried briefly, but I cannot get typing to work after rebasing. I need to take a thorough look.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from 113e9cd to 6c8dd5cCompareNovember 7, 2024 15:22
@DimitriPapadopoulosDimitriPapadopoulos changed the title Make methods of abstract base class asyncAsyncGenerator → AsyncIteratorNov 7, 2024
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 1a824a5 to 3fa0e1dCompareNovember 7, 2024 17:31
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review November 7, 2024 17:31

@jhammanjhamman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm happy here (except for the requested docstring changes).

Comment threadsrc/zarr/abc/store.py Outdated
Comment on lines +339 to +343
Notes
-----
This method should be async,
`How to correctly specify type hints with AsyncGenerator and AsyncContextManager <https://stackoverflow.com/questions/68905848/how-to-correctly-specify-type-hints-with-asyncgenerator-and-asynccontextmanager>`_
explains why it is not.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to move this to a comment rather than the public docstring. Most implementations will inherit this and end users don't need to know about this implementation detail.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, I wasn't sure about it. I put it in the documentation because it documents an inconsistency in function signatures.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ideally, I would document this using something similar to disabling Pylint warning W0236:

# pylint: disable=invalid-overridden-method

Unfortunately there's no equivalent rule in ruff, as far as I can see.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed.

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.

Thanks.

@jhamman
jhamman merged commit 693e11c into zarr-developers:mainNov 8, 2024
@jhammanjhamman mentioned this pull request Dec 3, 2024
6 tasks
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.

Inconsistent overridden method

3 participants

@DimitriPapadopoulos@paraseba@jhamman
, '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

AsyncGenerator → AsyncIterator - #2381

Merged
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async
Nov 8, 2024
Merged

AsyncGenerator → AsyncIterator#2381
jhamman merged 1 commit into
zarr-developers:mainfrom
DimitriPapadopoulos:async

Conversation

@DimitriPapadopoulos

@DimitriPapadopoulosDimitriPapadopoulos commented Oct 15, 2024

Copy link
Copy Markdown
Contributor

Fixes#2377.

See microsoft/pyright#4741.

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)

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from e86ee25 to 694af4bCompareOctober 16, 2024 06:23
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review October 16, 2024 06:29
@paraseba

Copy link
Copy Markdown
Contributor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

Most implementations probably won't need these functions to be async, but it's a more general type for some implementation that may need it.

Comment threadsrc/zarr/abc/store.py Outdated
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 46dc84b to 52e66c9CompareOctober 16, 2024 12:13
@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

I think a better type for these functions would be:

asyncdeflist(self) ->AsyncIterator[str]:

The roadmap defines the Store API as follows and should be updated:

asyncdeflist(self) ->List[str]:
... # required for listable storesasyncdeflist_prefix(self, prefix: str) ->List[str]:
... # required for listable storesasyncdeflist_dir(self, prefix: str) ->List[str]:
... # required for listable stores

All current child classes use the prefix argument. I don't think it should be removed.

As for the return value, not sure why it changed from List[str] to AsyncGenerator[str, None] in #1844. Switch back to AsyncGenerator[str]?

@paraseba

Copy link
Copy Markdown
Contributor

All current child classes use the prefix argument. I don't think it should be removed.

Sorry, I just missed the argument in the example, definitely we shouldn't drop it. My point was about returning AsyncIterator instead of AsyncGenerator, the later is more of an implementation detail. We definitely don't want list because that would force the whole thing to live in memory at once.

@DimitriPapadopoulos

DimitriPapadopoulos commented Oct 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Meanwhile, I tried to revert the return type from AsyncGenerator[str, None] to AsyncGenerator[str], to see what happens.

As for the AsyncGeneratorAsyncIterator change, how about addressing it in an issue and a separate PR?

@paraseba

Copy link
Copy Markdown
Contributor

As for the AsyncGenerator → AsyncIterator change, how about addressing it in an issue and a separate PR?

It's definitely not a big deal, AsyncGenerator[str] also works. But, doing it in separate PR would require changing the abc and every implementation twice.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

OK, let me try then. It's just that's I'll have to modify all child classes.

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 4 times, most recently from 844ccad to 8d3ead3CompareOctober 16, 2024 21:02
Comment threadsrc/zarr/abc/store.py Outdated
Comment threadsrc/zarr/storage/local.py Outdated
if p.is_file():
yield str(p).replace(to_strip, "")
allfiles = [str(p).replace(to_strip, "") for p in self.root.rglob("*") if p.is_file()]
return (onefile for onefile in allfiles)

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.

we don't want to materialize the full allfiles list in memory. Can you use async for instead? Here is an example of how you could do this:

fromcollections.abcimportAsyncIteratorfromabcimportABC, abstractmethodclassFoo(ABC):
@abstractmethodasyncdeffoo(self) ->AsyncIterator[str]:
...
classBar(Foo):
asyncdefhelper(self) ->AsyncIterator[str]:
raiseValueError("")
asyncdeffoo(self) ->AsyncIterator[str]:
return (xasyncforxinawaitself.helper())

This code should work and mypy successfully, and doesn't materialize the results of calling helper.

@DimitriPapadopoulosDimitriPapadopoulosOct 19, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I'm a little bit lost here.

  • What we have here are functions that yield. That's a generator. Why create an iterator?
  • I'm afraid I don't have enough experience with async and no time to learn it in the short term. For example, I'm not even sure how to identify iterables and awaitables.

I suggest We keep AsyncGenerator for now. What would be the benefit of an AsyncIterator in this context?

@jhamman

Copy link
Copy Markdown
Member

@DimitriPapadopoulos - are you planning to return to this?

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 80c5fff to 655a149CompareNovember 5, 2024 06:34
@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

I tried briefly, but I cannot get typing to work after rebasing. I need to take a thorough look.

@DimitriPapadopoulos

Copy link
Copy Markdown
ContributorAuthor

@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 3 times, most recently from 113e9cd to 6c8dd5cCompareNovember 7, 2024 15:22
@DimitriPapadopoulosDimitriPapadopoulos changed the title Make methods of abstract base class asyncAsyncGenerator → AsyncIteratorNov 7, 2024
@DimitriPapadopoulos
DimitriPapadopoulosforce-pushed the async branch 2 times, most recently from 1a824a5 to 3fa0e1dCompareNovember 7, 2024 17:31
@DimitriPapadopoulos
DimitriPapadopoulos marked this pull request as ready for review November 7, 2024 17:31

@jhammanjhamman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm happy here (except for the requested docstring changes).

Comment threadsrc/zarr/abc/store.py Outdated
Comment on lines +339 to +343
Notes
-----
This method should be async,
`How to correctly specify type hints with AsyncGenerator and AsyncContextManager <https://stackoverflow.com/questions/68905848/how-to-correctly-specify-type-hints-with-asyncgenerator-and-asynccontextmanager>`_
explains why it is not.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to move this to a comment rather than the public docstring. Most implementations will inherit this and end users don't need to know about this implementation detail.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, I wasn't sure about it. I put it in the documentation because it documents an inconsistency in function signatures.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ideally, I would document this using something similar to disabling Pylint warning W0236:

# pylint: disable=invalid-overridden-method

Unfortunately there's no equivalent rule in ruff, as far as I can see.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed.

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.

Thanks.

@jhamman
jhamman merged commit 693e11c into zarr-developers:mainNov 8, 2024
@jhammanjhamman mentioned this pull request Dec 3, 2024
6 tasks
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.

Inconsistent overridden method

3 participants

@DimitriPapadopoulos@paraseba@jhamman