-
Notifications
You must be signed in to change notification settings - Fork 306
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use jupyter_client's AsyncKernelManager #191
Use jupyter_client's AsyncKernelManager #191
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for adding this in @davidbrochart - this will be extremely useful to have prior to moving to kernel providers. This also appears to be a general gen.coroutine/yield -> async/await sweep - or at least a start - which is really nice!
I only had a few minor comments.
) | ||
# py2-compat | ||
raise gen.Return(kernel_id) | ||
kernel_id = await ensure_async(self.kernel_manager.start_kernel(path=kernel_path, kernel_name=kernel_name)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need the ensure_async()
wrapper here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, and this involves some changes in the tests too.
👍 Thanks, @davidbrochart. The failing AppVeyor test is due to a Github webhook that needed to be deleted. I just removed it, so it should drop from the test list. |
93180d3
to
88b7e15
Compare
Not sure about these errors on Windows for python3.5 and 3.6. |
Trigger CI. |
Now the error is only on Windows/python3.5. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks David!
I recall seeing the Windows issue when working with kernel providers. Unfortunately, I don't recall the solution. I was hoping this issue would provide some hints, but IIRC this was following my encounter with the invalid handle issue. I'll google around and see if that rings any bells.
Hmm - Windows 3.5 is sounding more familiar and I definitely recall this google hit: https://bugs.python.org/issue37380. Still trying to remove the cobwebs. |
…oroutine/yield to async/await, remove run_blocking
Thx @davidbrochart @kevin-bates When the kernel provider will be merged, my understanding is that this async kernel-client implementation will be completely replaced by the kernel-protocol code. Is this correct? |
88b7e15
to
b471f27
Compare
@echarles - yes, that's correct. We'll want to get that client implementation up on async. I'm fairly certain @davidbrochart is aware of that: jupyter/jupyter_client#428 (comment) |
b471f27
to
cc55f28
Compare
This is not going to be fixed for python3.5 and 3.6 on Windows, and I don't have any workaround. |
I don't think there is anything to do in jupyter_kernel_mgmt, it already has an async client (it's |
By golly - I didn't realize that. I knew it required changes to interact with the async kernel manager, but I never looked closely at the pure 'client' portion. If you say its good to go, then I'm good. Looking just now, it doesn't appear to have a mixture of async/await and gen.coroutine/yield and it seems like we should convert the latter at some point. |
So what are our options here?
Is that right? And if we choose the former, we should probably add a table to the README with "supported" Python versions+platforms. |
We even need python>=3.7 for Windows. I would go for option 1. |
jupyter_server/utils.py
Outdated
def ensure_async(obj): | ||
"""Convert a non-async object to a coroutine if needed. | ||
""" | ||
if inspect.isawaitable(obj): | ||
return asyncio.ensure_future(obj) | ||
elif isinstance(obj, concurrent.futures.Future): | ||
return asyncio.wrap_future(obj) | ||
else: | ||
# not awaitable, wrap scalar in future | ||
f = asyncio.Future() | ||
f.set_result(obj) | ||
return f | ||
if asyncio.iscoroutine(obj): | ||
return obj | ||
if type(obj) is asyncio.Future: | ||
return obj | ||
|
||
async def _(): | ||
return obj | ||
|
||
return _() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
It might be worth one more set of eyes to specifically approve this change (maybe @kevin-bates).
It LGTM, but I'm not super familiar with the async stuff. I want to make sure we're not missing any key edge cases that might lead to cryptic error messaging or bugs. Should we create a set of new tests specifically for this function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, async is not easy, so any help would be appreciated here, including ways to test this function.
jupyter_server/serverapp.py
Outdated
@@ -1039,7 +1039,7 @@ def template_file_path(self): | |||
) | |||
|
|||
kernel_manager_class = Type( | |||
default_value=MappingKernelManager, | |||
default_value=AsyncMappingKernelManager, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this changes the default manager class name, I think we need to add logic that addresses user config. If any traits of MappingKernelManager
are configurable, some users may have config that will no longer be loaded by this new class, and thus, silently ignore their settings.
I see two ways to address this:
- If those traits are still valid for this new class, we can write an empty configurable
MappingKernelManager
class thatAsyncMappingKernelManager
inherits and thus loads the traits as a subclass. - Throw warnings every time a
MappingKernelManager
trait pops up in the config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pointing that out @Zsailer. I think option 1 is the best.
Why are the 3.6 Windows tests passing, but not the 3.5? |
What I'm not understanding is why JKM is working on WIndows 3.5, 3.6? It's generally the same code since we can't use the async subprocess stuff on Windows there either. |
The tests randomly pass on Windows/python3.6, and they seem to always fail with python3.5. This issue says that the fix has been back-ported to python 3.7 only, not beyond. |
I believe this is ready to merge. I can't recall what option we should use. Deferring to @Zsailer. |
I think the history of this PR is useful to keep around—so I'm going to merge directly (not squash-and-merge). This was a lot of work that's work tracking. Thanks @kevin-bates and @davidbrochart! Great work, here! |
I hate to bring this up, but in working on the NB 4479 PR, I'm finding the checks for Python 3.5 should be |
Good catch Kevin, thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks David. I think we're getting very close here.
jupyter_server/gateway/managers.py
Outdated
|
||
|
||
class GatewayKernelManager(MappingKernelManager): | ||
class GatewayKernelManager(AsyncMappingKernelManager): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be changed back to MappingKernelManager
, otherwise we've disabled the use of a gateway on 3.5. As mentioned in the previous comment, the superclass is not critical since GatewayKernelManager
serves as a proxy.
Thanks again Kevin! |
Hmm. That condition is impossible, by definition, so how can it be considered valid for the test? I think it might be good to understand what's going on. The 3.5 no-async-kernel-manager test is failing because the trailet for the kernel_manager_class can't be resolved...
and this is impossible in the real world because |
I need to take a break and look more closely. |
tests/services/kernels/test_api.py
Outdated
@@ -284,7 +285,7 @@ def no_async_mapping_kernel_manager(monkeypatch): | |||
|
|||
@pytest.mark.skipif( | |||
sys.version_info < (3, 6), | |||
reason="Kernel manager is AsyncMappingKernelManager, Python version < 3.6" | |||
reason="Testing no AsyncMappingKernelManager on Python >=3.6 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need trailing quotes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great David - thank you!
Congrats, y'all! Great stuff! |
* Use jupyter_client's AsyncKernelManager * Rename MappingKernelManage to AsyncMappingKernelManage, convert gen.coroutine/yield to async/await, remove run_blocking * Fix Windows subprocess handle issue * Restrict Windows to python>=3.7 * Fix GH actions matrix exclusion * Make AsyncMappingKernelManager a subclass of MappingKernelManager for configuration back-compatibility * Make AsyncKernelManager an opt-in * Pin jupyter_core and jupyter_client a bit higher * Remove async from MappingKernelManager.shutdown_kernel * Hard-code super() in MappingKernelManager and AsyncMappingKernelManager * Add argv fixture to enable MappingKernelManager and AsyncMappingKernelManager * Rewrite ensure_async to not await already awaited coroutines * Add async shutdown_kernel to AsyncMappingKernelManager, keep MappingKernelManager.shutdown_kernel blocking * Add restart kwarg to shutdown_kernel * Add log message when starting (async) kernel manager * Bump jupyter_client 6.1.1 * Rename super attribute to pinned_superclass * Prevent using AsyncMappingKernelManager on python<=3.5 (at run-time and in tests) * Ignore last_activity and execution_state when comparing sessions * Replace newsession with new_session * Fix Python version check * Fix skipping of tests * GatewayKernelManager inherits from MappingKernelManager to keep python3.5 compatibility * Added back removal of kernelmanager.AsyncMappingKernelManager * Don't test absence of AsyncMultiKernelManager
No description provided.