-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This moves `pyface.ui.qt4.*` to `pyface.ui.qt` and helps with gradually deprecating all uses of "qt4". The current state is internal consistency, optional hooks for backwards compatibility for applications that depend on Pyface. Changes for downstream libraries and applications should be fairly simple: replacing `qt` with `qt4` in appropriate import statements. But there are some circumstances where this may not be feasible: - where the end-user doesn't control the code-base (eg. someone who pip-installs Mayavi and gets the new version of Pyface automatically) - where an application developer needs to make a newer version of pyface work with code they don't control that imports from `pyface.ui.qt4.*` - where a library developer wants to be compatible with newer and older versions of pyface This PR solves two of these problems by providing opt-in import hooks that replace imports of `pyface.ui.qt4.*` with corresponding imports of `pyface.ui.qt.*` so that `sys.modules` points to the new location (avoiding issues with duplicated objects and modules which would happen with some other strategies). These hooks are not available by default, but can be accessed in a number of ways: - end-users can set environment variables to turn it on: `ETS_QT4_IMPORTS` to directly turn on the import hooks, and `ETS_TOOLKIT=qt4` (as opposed to `ETS_TOOLKIT=qt`) with the assumption that this is an older environment - application developers can either set `ETSConfig.toolkit = "qt4"` (as opposed to `ETSConfig.toolkit = "qt"`) with the assumption that this is flagging that this is an application made with older assumptions about import locations; or if they need more control, they can install the import hooks into `sys.meta_path` in a way that works best for them and any other import hooks that they might be using. The third case of a library developer who wants to support newer and older versions should be done through the usual mechanisms (eg. try importing `pyface.ui.qt.foo` and if it fails import `pyface.ui.qt4.foo`; or looking at pyface version numbers). An alternative which will work in almost all cases is to instead use `toolkit_object()` to get the thing that they want, which will automatically get it from the right place. Done: - [x] check about pickle compatibility with mementos: Tasks and Workbench mementos are independent of toolkit - [x] migration documentation (added to toolkits section) Note: This ended up taking about a day longer than expected because the original working version of the code was using a deprecated API that would be removed in Python 3.12, so it needed re-implementation after digging in to understand what the new importlib API was doing. In doing so it has been generalized a bit, since we expect to also do this in TraitsUI at a minimum. Fixes #560 --------- Co-authored-by: Mark Dickinson <mdickinson@enthought.com>
- Loading branch information
1 parent
44ec41e
commit a9bf026
Showing
146 changed files
with
563 additions
and
61 deletions.
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
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
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
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
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
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
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
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
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,113 @@ | ||
# (C) Copyright 2005-2023 Enthought, Inc., Austin, TX | ||
# All rights reserved. | ||
# | ||
# This software is provided without warranty under the terms of the BSD | ||
# license included in LICENSE.txt and may be redistributed only under | ||
# the conditions described in the aforementioned license. The license | ||
# is also available online at http://www.enthought.com/licenses/BSD.txt | ||
# | ||
# Thanks for using Enthought open source! | ||
|
||
from importlib import import_module | ||
from importlib.abc import MetaPathFinder, Loader | ||
from importlib.machinery import ModuleSpec | ||
from importlib.util import find_spec | ||
import sys | ||
|
||
|
||
# Import hooks for loading pyface.ui.qt.* in place of a pyface.ui.qt4.* | ||
# This is just the implementation, it is not connected in this module, but | ||
# is available for applications which want to install it themselves. | ||
# It is here rather than in pyface.ui.qt4 so it can be imported and used | ||
# without generating the warnings from pyface.ui.qt4 | ||
# | ||
# To use manually: | ||
# | ||
# import sys | ||
# sys.meta_path.append(ShadowedModuleFinder()) | ||
|
||
class ShadowedModuleLoader(Loader): | ||
"""This loads another module into sys.modules with a given name. | ||
Parameters | ||
---------- | ||
fullname : str | ||
The full name of the module we're trying to import. | ||
Eg. "pyface.ui.qt4.foo" | ||
new_name : str | ||
The full name of the corresponding "real" module. | ||
Eg. "pyface.ui.qt.foo" | ||
new_spec : ModuleSpec instance | ||
The spec object for the corresponding "real" module. | ||
""" | ||
|
||
def __init__(self, fullname, new_name, new_spec): | ||
self.fullname = fullname | ||
self.new_name = new_name | ||
self.new_spec = new_spec | ||
|
||
def create_module(self, spec): | ||
"""Create the module object. | ||
This doesn't create the module object directly, rather it gets the | ||
underlying "real" module's object, importing it if needed. This object | ||
is then returned as the "new" module. | ||
""" | ||
if self.new_name not in sys.modules: | ||
import_module(self.new_name) | ||
return sys.modules[self.new_name] | ||
|
||
def exec_module(self, module): | ||
"""Execute code for the module. | ||
This is given a module which has already been executed, so we don't | ||
need to execute anything. However we do need to remove the __spec__ | ||
that the importlibs machinery has injected into the module and | ||
replace it with the original spec for the underlying "real" module. | ||
""" | ||
# patch up the __spec__ with the true module's original __spec__ | ||
if self.new_spec: | ||
module.__spec__ = self.new_spec | ||
self.new_spec = None | ||
|
||
|
||
class ShadowedModuleFinder(MetaPathFinder): | ||
"""MetaPathFinder for shadowing modules in a package | ||
This finds modules with names that match a package but arranges loading | ||
from a different package. By default this is matches imports from any | ||
path starting with pyface.ui.qt4. and returns a loader which will instead | ||
load from pyface.ui.qt.* | ||
The end result is that sys.modules has two entries for pointing to the | ||
same module object. | ||
This may be hooked up by code in pyface.ui.qt4, but it can also be | ||
installed manually with:: | ||
import sys | ||
sys.meta_path.append(ShadowedModuleFinder()) | ||
Parameters | ||
---------- | ||
package : str | ||
The prefix of the "shadow" package. | ||
true_package : str | ||
The prefix of the "real" package which contains the actual code. | ||
""" | ||
|
||
def __init__(self, package="pyface.ui.qt4.", true_package="pyface.ui.qt."): | ||
self.package = package | ||
self.true_package = true_package | ||
|
||
def find_spec(self, fullname, path, target=None): | ||
if fullname.startswith(self.package): | ||
new_name = fullname.replace(self.package, self.true_package, 1) | ||
new_spec = find_spec(new_name) | ||
if new_spec is None: | ||
return None | ||
return ModuleSpec( | ||
name=fullname, | ||
loader=ShadowedModuleLoader(fullname, new_name, new_spec), | ||
is_package=(new_spec.submodule_search_locations is not None), | ||
) |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
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
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
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
File renamed without changes.
File renamed without changes.
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
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
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
File renamed without changes.
File renamed without changes.
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
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
Oops, something went wrong.