Skip to content
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

Lazy imports #17

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Lazy imports #17

wants to merge 1 commit into from

Conversation

Kronuz
Copy link
Owner

@Kronuz Kronuz commented Sep 6, 2022

Lazy Imports

This implements Lazy Imports (PEP 690) on CPython main branch.

Most significant changes are in the following files:

Python/import.c - ~800 changes
Objects/dictobject.c - 600 changes
Python/ceval.c - ~300 changes
Objects/lazyimportobject.c - ~200 new lines


Python/import.c

  • Implements the lazy imports basic functions for resolving objects and creating PyLazyImportObject objects.
  • Implements: _PyImport_LazyImportName(), _PyImport_EagerImportName(), _PyImport_ImportFrom(), PyImport_LoadLazyImport() and _imp._maybe_set_submodule_attribute()
  • Adds the C API and Python (_imp) API: PyImport_SetLazyImports(), PyImport_SetLazyImportsInModule(), PyImport_IsLazyImportsEnabled()

Objects/dictobject.c

  • Makes necessary changes to dictionary internals to support lazy values.
  • Resolved objects from a dictionary immediately and automatically replace the lazy objects that represented them in the dictionary (as long as it's possible). In the case where the value in the dictionary can't be immediately replaced by the resolved object (because maybe the resolution of the object triggered a dictionary mutation), the next time the lazy value it's accessed it'll use an internal cached version of the resolved object and attempt substituting the lazy value with the resolved one again.
  • Values in a dictionary are resolved only when is needed, otherwise they remain lazy for as long as possible.
    • Merging, copying, dict.keys(), etc. all maintain lazy values inside a dictionary.
  • _Py_dict_lookup() can now return DKIX_VALUE_ERROR in case the resolution of a lazy object resulted in an error.
  • Adds *_keep_lazy/*KeepLazy (e.g. _Py_dict_lookup_keep_lazy(), _PyDict_GetItemKeepLazy()) to force returning lazy objects without being resolved.
  • Adds PyDict_NextWithError(), which works the same way as PyDict_Next() with the exception it propagates any errors to the caller by returning 0 and setting an exception. Caller should use if (PyErr_Ocurred()) to check for any errors.
  • Implements _PyDict_HasLazyImports()
  • PyDict_Next() and PyDict_NextWithError() resolve all the lazy objects in the dictionary if it has them and if the passed pos is zero. Returns 0 on errors or if objects can't be resolved.
  • Implements PyDict_ResolveLazyImports() to resolve all lazy values in a dictionary.
    • If there are no lazy objects in a dictionary it does nothing, otherwise it walks the whole dictionary trying to resolve each value and retrying if the dictionary mutated halfway.
    • It's used by dictionary views, PyDict_Next(), dict.values(), dict.items() before starting to iterate through the dictionary, to ensure returned values are all resolved and that the dictionary doesn't mutate midway due to import side effects produced by resolving the values.
    • The primary reason we need dk_lazy_imports is to be able to make this call efficient for dictionaries without lazy values.
  • Implements PyDict_IsLazyImport() to check if a given key in a dictionary is a lazy object.

Python/ceval.c

  • Implements EAGER_IMPORT_NAME and IMPORT_NAME to create PyLazyImportObject objects when the feature is enabled.
  • It also resolves some lazy import objects on specialized opcodes.
  • import_name() and import_from() were moved to Python/import.c, and mostly only renamed to _PyImport_EagerImportName() and _PyImport_ImportFrom(), respectively.

Objects/lazyimportobject.c

  • Adds the implementation for PyLazyImportObject object via PyLazyImport_Type.
  • Adds _PyLazyImport_NewModule(), _PyLazyImport_NewObject(), _PyLazyImport_GetName(), PyLazyImport_CheckExact()

@Kronuz Kronuz force-pushed the lazy_imports branch 9 times, most recently from 350c456 to 1bd0372 Compare September 26, 2022 21:29
@Kronuz Kronuz force-pushed the lazy_imports branch 4 times, most recently from 17b139d to f3cf727 Compare September 30, 2022 19:39
@Kronuz Kronuz force-pushed the lazy_imports branch 5 times, most recently from 77213f7 to 44b7e9b Compare October 14, 2022 18:41
@Kronuz Kronuz force-pushed the lazy_imports branch 2 times, most recently from 27bd975 to ae3ff4a Compare October 30, 2022 18:49
@@ -571,6 +571,8 @@
added = '3.2'
[function.PyDict_GetItemWithError]
added = '3.2'
[function.PyDict_IsLazyImport]
added = '3.12'
Copy link

Choose a reason for hiding this comment

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

I don't think the new API should be in the Stable ABI, at least initially. The few (hopefully) modules that need these can import and call importlib functions.
Except for PyDict_NextWithError -- that's an improvement, independent of lazy imports. In fact, if you add it now I'd be happy to review the PR.

Also: new items are generally added at the end of stable_abi.toml.

@github-actions
Copy link

This PR is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label Dec 15, 2022
@Kronuz Kronuz force-pushed the lazy_imports branch 4 times, most recently from b7bcf2f to 2dcb749 Compare March 20, 2023 21:27
@Kronuz Kronuz force-pushed the lazy_imports branch 2 times, most recently from 48d2d19 to ed3867c Compare March 29, 2023 17:57
@Kronuz Kronuz force-pushed the lazy_imports branch 2 times, most recently from e0ade32 to c4494be Compare May 12, 2023 18:37
@Kronuz Kronuz force-pushed the lazy_imports branch 3 times, most recently from a678bb4 to ccb30d7 Compare October 26, 2023 18:58
@Kronuz
Copy link
Owner Author

Kronuz commented Oct 26, 2023

Rebased on top of CPython 3.12 stable.

@Kronuz Kronuz force-pushed the lazy_imports branch 8 times, most recently from 2e1acda to 1d8292c Compare October 27, 2023 20:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants