-
-
Notifications
You must be signed in to change notification settings - Fork 995
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
Add additional docs for importing code with asyncio #2338
Draft
bdraco
wants to merge
6
commits into
master
Choose a base branch
from
imports
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
5a05583
Add additional docs for importing code with asyncio
bdraco 2d9ab44
Add additional docs for importing code with asyncio
bdraco abce36e
Add additional docs for importing code with asyncio
bdraco fc6d890
Add additional docs for importing code with asyncio
bdraco a84ad0a
Add additional docs for importing code with asyncio
bdraco 5563a4d
Add additional docs for importing code with asyncio
bdraco File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
--- | ||
title: "Importing code with asyncio" | ||
--- | ||
|
||
Determining when it is safe to import code when using asyncio can be tricky because two constraints need to be considered: | ||
|
||
- Importing code can do blocking I/O to load the files from the disk | ||
- Importing code in [cpython is not thread-safe](https://github.com/python/cpython/issues/83065) | ||
|
||
## Top-level imports | ||
|
||
Suppose your imports happen at the top-level (nearly all code at indentation level 0). Home Assistant will import your code before the event loop starts or import it in the import executor when your integration is loaded. In this case, you likely do not need to consider whether your imports are safe. | ||
|
||
## Imports outside of top-level | ||
|
||
If your imports are not happening at top-level, you must carefully consider each import, as the import machinery has to read the module from disk which does blocking I/O. If possible, it's usually best to change to a top-level import, as it avoids much complexity and the risk of mistakes. Importing modules is both CPU-intensive and involves blocking I/O, so it is crucial to ensure these operations are executed in the executor. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there are two reasons for doing non module-level imports:
|
||
|
||
If you can be sure that the modules have already been imported, using a bare [`import`](https://docs.python.org/3/reference/simple_stmts.html#import) statement is safe since Python will not load the modules again. | ||
|
||
If the module will only ever be imported in a single place, the standard executor calls can be used: | ||
|
||
- For imports inside of Home Assistant `hass.async_add_executor_job(_function_that_does_late_import)` | ||
- For imports outside of Home Assistant: [`loop.run_in_executor(None, _function_that_does_late_import)`](https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor) | ||
If the same module may be imported concurrently in different parts of the application, use the thread-safe `homeassistant.helpers.importlib.import_module` helper. | ||
|
||
If its possible the module may be imported from multiple different paths, use `async_import_module`: | ||
|
||
Example: | ||
|
||
```python | ||
from homeassistant.helpers.importlib import async_import_module | ||
|
||
platform = await async_import_module(hass, f"homeassistant.components.homeassistant.triggers.{platform_name}") | ||
``` | ||
|
||
## Determining if a module is already loaded | ||
|
||
If you are unsure if a module is already loaded, you can check if the module is already in [`sys.modules`](https://docs.python.org/3/library/sys.html#sys.modules). You should know that the module will appear in `sys.modules` as soon as it begins loading, and [cpython imports are not thread-safe](https://github.com/python/cpython/issues/83065). For this reason, it's important to consider race conditions when code may be imported from multiple paths. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 think the correct term is "module level" since it mentions indentation level 0?
Should we explain there needs to a chain of imports starting from a package's
__init__.py
?