dash icon indicating copy to clipboard operation
dash copied to clipboard

Fix pkgutil.find_loader deprecation warning

Open ndrezn opened this issue 10 months ago • 2 comments

Users might encounter:

'pkgutil.find_loader' is deprecated and slated for removal in Python 3.14; use importlib.util.find_spec() instead.

in Dash. To ensure forwards compatibility we should update to the new recommended method.

ndrezn avatar Jan 29 '25 14:01 ndrezn

Python 3.14 is expected to arrive in October 2025

alexcjohnson avatar Jan 29 '25 14:01 alexcjohnson

I can use this patch fix AttributeError: module 'pkgutil' has no attribute 'find_loader' in dash 3.0.4(python v3.14.0b2:12d3f88)

--- .venv/Lib/site-packages/dash/dash.py.orig	2024-01-01 00:00:00.000000000 +0000
+++ .venv/Lib/site-packages/dash/dash.py	2024-01-01 00:00:01.000000000 +0000
@@ -1888,18 +1888,20 @@
         if dev_tools.hot_reload:
             _reload = self._hot_reload
             _reload.hash = generate_hash()
 
-            # find_loader should return None on __main__ but doesn't
+            # find_spec should return None on __main__ but doesn't
             # on some Python versions https://bugs.python.org/issue14710
             packages = [
-                pkgutil.find_loader(x)
+                importlib.util.find_spec(x)
                 for x in list(ComponentRegistry.registry)
                 if x != "__main__"
             ]
 
             # # additional condition to account for AssertionRewritingHook object
             # # loader when running pytest
 
+            dash_test_path = None  # Initialize to prevent UnboundLocalError
             if "_pytest" in sys.modules:
                 from _pytest.assertion.rewrite import (  # pylint: disable=import-outside-toplevel
                     AssertionRewritingHook,  # type: ignore[reportPrivateImportUsage]
                 )
 
@@ -1911,8 +1913,10 @@
                         packages[index] = dash_spec
 
             component_packages_dist = [
-                dash_test_path  # type: ignore[reportPossiblyUnboundVariable]
-                if isinstance(package, ModuleSpec)
+                dash_test_path
+                if isinstance(package, ModuleSpec) and dash_test_path is not None
+                else os.path.dirname(package.origin)  # type: ignore[reportAttributeAccessIssue]
+                if hasattr(package, "origin") and package.origin
                 else os.path.dirname(package.path)  # type: ignore[reportAttributeAccessIssue]
                 if hasattr(package, "path")
                 else os.path.dirname(
@@ -1924,11 +1928,15 @@
             ]
 
             for i, package in enumerate(packages):
-                if hasattr(package, "path") and "dash/dash" in os.path.dirname(
-                    package.path  # type: ignore[reportAttributeAccessIssue]
-                ):
+                package_path = None
+                if hasattr(package, "origin") and package.origin:
+                    package_path = package.origin
+                elif hasattr(package, "path"):
+                    package_path = package.path  # type: ignore[reportAttributeAccessIssue]
+                
+                if package_path and "dash/dash" in os.path.dirname(package_path):
                     component_packages_dist[i : i + 1] = [
-                        os.path.join(os.path.dirname(package.path), x)  # type: ignore[reportAttributeAccessIssue]
+                        os.path.join(os.path.dirname(package_path), x)
                         for x in ["dcc", "html", "dash_table"]
                     ]
 

vex87 avatar Jun 06 '25 01:06 vex87

A friendly bump, to put additional attention to this. Python 3.14 is almost out. Originally reported in #3136 at the end of Jan.

@vex87 , I don't understand everything in the patch, but it looks like you solved the problem already pretty thoroughly. Could you be able to put together a PR?

Personally I see this DeprecationWarning float by 20~50 times a day (every hot-reload), so it is a bit of a distraction. Thanks.

ghaarsma avatar Aug 21 '25 16:08 ghaarsma

Another bump. We give 3.3.0rc0 a try. The issue is still not resolved.

Package operations: 0 installs, 1 update, 0 removals

  - Updating dash (3.2.0 -> 3.3.0rc0)

Writing lock file
(venv) PS C:\Users\gxvh\Python\dwsc-site> flask run
2025-09-26 09:08:10 - INFO - Settings class: dwsc.config.LocalDevelopmentConfig
C:\Users\xxxx\Python\site\venv\Lib\site-packages\dash\dash.py:2055: DeprecationWarning:

'pkgutil.find_loader' is deprecated and slated for removal in Python 3.14; use importlib.util.find_spec() instead

Callback Map: Len=228, Inputs=358, States=149, Outputs=413

ghaarsma avatar Sep 26 '25 14:09 ghaarsma

@ghaarsma not planned for 3.3.0 yet but this is absolutely on our radar 🫡

ndrezn avatar Sep 29 '25 16:09 ndrezn

What's the change of this making it into 3.3.0? Its all that's keeping me from updating my project to python 3.14 :(

MarMariMarisa avatar Oct 10 '25 14:10 MarMariMarisa

Officially deprecated, had to downgrade project

 File ".venv/lib/python3.14/site-packages/dash/dash.py", line 1990, in enable_dev_tools
    pkgutil.find_loader(x)
    ^^^^^^^^^^^^^^^^^^^
AttributeError: module 'pkgutil' has no attribute 'find_loader'

katyaslepoy1 avatar Nov 03 '25 13:11 katyaslepoy1