We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
site-packages\django\contrib\sites has managment.py file which is conflicting with managment directory and causing a issue in tree get issue in _pyi_pkgutil_iter_modules as dirretory name and file are same 
When I execute a generated exe from pyinstaller, it is failing as django.contrib.sites has mangment.py file which is conflicting with package which by default will have management as directory.

as technically there is no management folder but when find_commands whose iterator is override by _pyi_pkgutil_iter_modules id expecting a tree node with dict but it has a file with managment.py so it is failing as str error.

If any app has management folder and also managment.py it will yield in to this issue. We can rename custom apps to avoid the file name duplication with management folder but how to deal with standard dajngo apps like django.contrib.sites

here is the stack trace 



-> for pkg_name_part in pkg_prefix.parts:
(Pdb) pkg_prefix.parts
('django', 'contrib', 'sites', 'management', 'commands')          ====>    management here is expected a dict , as dict is not there it will be there in toc but as a file is there. it finds the file as str instead of dict and so is the assert.
(Pdb) c
Traceback (most recent call last):
  File "manage.py", line 19, in <module>
    execute_from_command_line(sys.argv)
  File "django\core\management\__init__.py", line 442, in execute_from_command_line
  File "django\core\management\__init__.py", line 424, in execute
  File "django\core\management\__init__.py", line 222, in main_help_text
  File "django\core\management\__init__.py", line 78, in get_commands
  File "django\core\management\__init__.py", line 35, in find_commands
  File "django\core\management\__init__.py", line 35, in <listcomp>
  File "C:\PythonWebCode\testone\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py", line 102, in _pyi_pkgutil_iter_modules
    for pkg_name_part in pkg_prefix.parts:
AttributeError: 'str' object has no attribute 'get'

How can we address this issue ?



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `PyInstaller/utils/hooks/django.py`
Content:
```
1 # ----------------------------------------------------------------------------
2 # Copyright (c) 2005-2023, PyInstaller Development Team.
3 #
4 # Distributed under the terms of the GNU General Public License (version 2
5 # or later) with exception for distributing the bootloader.
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #
9 # SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
10 # ----------------------------------------------------------------------------
11 import os
12 
13 from PyInstaller import isolated
14 
15 
16 @isolated.decorate
17 def django_dottedstring_imports(django_root_dir):
18     """
19     An isolated helper that returns list of all Django dependencies, parsed from the `mysite.settings` module.
20 
21     NOTE: With newer version of Django this is most likely the part of PyInstaller that will be broken.
22 
23     Tested with Django 2.2
24     """
25 
26     import sys
27     import os
28 
29     import PyInstaller.utils.misc
30     from PyInstaller.utils import hooks as hookutils
31 
32     # Extra search paths to add to sys.path:
33     #  - parent directory of the django_root_dir
34     #  - django_root_dir itself; often, Django users do not specify absolute imports in the settings module.
35     search_paths = [
36         PyInstaller.utils.misc.get_path_to_toplevel_modules(django_root_dir),
37         django_root_dir,
38     ]
39     sys.path += search_paths
40 
41     # Set the path to project's settings module
42     default_settings_module = os.path.basename(django_root_dir) + '.settings'
43     settings_module = os.environ.get('DJANGO_SETTINGS_MODULE', default_settings_module)
44     os.environ['DJANGO_SETTINGS_MODULE'] = settings_module
45 
46     # Calling django.setup() avoids the exception AppRegistryNotReady() and also reads the user settings
47     # from DJANGO_SETTINGS_MODULE.
48     # https://stackoverflow.com/questions/24793351/django-appregistrynotready
49     import django  # noqa: E402
50 
51     django.setup()
52 
53     # This allows to access all django settings even from the settings.py module.
54     from django.conf import settings  # noqa: E402
55 
56     hiddenimports = list(settings.INSTALLED_APPS)
57 
58     # Do not fail script when settings does not have such attributes.
59     if hasattr(settings, 'TEMPLATE_CONTEXT_PROCESSORS'):
60         hiddenimports += list(settings.TEMPLATE_CONTEXT_PROCESSORS)
61 
62     if hasattr(settings, 'TEMPLATE_LOADERS'):
63         hiddenimports += list(settings.TEMPLATE_LOADERS)
64 
65     hiddenimports += [settings.ROOT_URLCONF]
66 
67     def _remove_class(class_name):
68         return '.'.join(class_name.split('.')[0:-1])
69 
70     #-- Changes in Django 1.7.
71 
72     # Remove class names and keep just modules.
73     if hasattr(settings, 'AUTHENTICATION_BACKENDS'):
74         for cl in settings.AUTHENTICATION_BACKENDS:
75             cl = _remove_class(cl)
76             hiddenimports.append(cl)
77     if hasattr(settings, 'DEFAULT_FILE_STORAGE'):
78         cl = _remove_class(settings.DEFAULT_FILE_STORAGE)
79         hiddenimports.append(cl)
80     if hasattr(settings, 'FILE_UPLOAD_HANDLERS'):
81         for cl in settings.FILE_UPLOAD_HANDLERS:
82             cl = _remove_class(cl)
83             hiddenimports.append(cl)
84     if hasattr(settings, 'MIDDLEWARE_CLASSES'):
85         for cl in settings.MIDDLEWARE_CLASSES:
86             cl = _remove_class(cl)
87             hiddenimports.append(cl)
88     # Templates is a dict:
89     if hasattr(settings, 'TEMPLATES'):
90         for templ in settings.TEMPLATES:
91             backend = _remove_class(templ['BACKEND'])
92             hiddenimports += backend
93             # Include context_processors.
94             if hasattr(templ, 'OPTIONS'):
95                 if hasattr(templ['OPTIONS'], 'context_processors'):
96                     # Context processors are functions - strip last word.
97                     mods = templ['OPTIONS']['context_processors']
98                     mods = [_remove_class(x) for x in mods]
99                     hiddenimports += mods
100     # Include database backends - it is a dict.
101     for v in settings.DATABASES.values():
102         hiddenimports.append(v['ENGINE'])
103 
104     # Add templatetags and context processors for each installed app.
105     for app in settings.INSTALLED_APPS:
106         app_templatetag_module = app + '.templatetags'
107         app_ctx_proc_module = app + '.context_processors'
108         hiddenimports.append(app_templatetag_module)
109         hiddenimports += hookutils.collect_submodules(app_templatetag_module)
110         hiddenimports.append(app_ctx_proc_module)
111 
112     # Deduplicate imports.
113     hiddenimports = list(set(hiddenimports))
114 
115     # Return the hidden imports
116     return hiddenimports
117 
118 
119 def django_find_root_dir():
120     """
121     Return path to directory (top-level Python package) that contains main django files. Return None if no directory
122     was detected.
123 
124     Main Django project directory contain files like '__init__.py', 'settings.py' and 'url.py'.
125 
126     In Django 1.4+ the script 'manage.py' is not in the directory with 'settings.py' but usually one level up. We
127     need to detect this special case too.
128     """
129     # 'PyInstaller.config' cannot be imported as other top-level modules.
130     from PyInstaller.config import CONF
131 
132     # Get the directory with manage.py. Manage.py is supplied to PyInstaller as the first main executable script.
133     manage_py = CONF['main_script']
134     manage_dir = os.path.dirname(os.path.abspath(manage_py))
135 
136     # Get the Django root directory. The directory that contains settings.py and url.py. It could be the directory
137     # containing manage.py or any of its subdirectories.
138     settings_dir = None
139     files = set(os.listdir(manage_dir))
140     if ('settings.py' in files or 'settings' in files) and 'urls.py' in files:
141         settings_dir = manage_dir
142     else:
143         for f in files:
144             if os.path.isdir(os.path.join(manage_dir, f)):
145                 subfiles = os.listdir(os.path.join(manage_dir, f))
146                 # Subdirectory contains critical files.
147                 if ('settings.py' in subfiles or 'settings' in subfiles) and 'urls.py' in subfiles:
148                     settings_dir = os.path.join(manage_dir, f)
149                     break  # Find the first directory.
150 
151     return settings_dir
152
```

Path: `PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py`
Content:
```
1 #-----------------------------------------------------------------------------
2 # Copyright (c) 2021-2023, PyInstaller Development Team.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #
9 # SPDX-License-Identifier: Apache-2.0
10 #-----------------------------------------------------------------------------
11 #
12 # This rthook overrides pkgutil.iter_modules with custom implementation that uses PyInstaller's PyiFrozenImporter to
13 # list sub-modules embedded in the PYZ archive. The non-embedded modules (binary extensions, or .pyc modules in
14 # noarchive build) are handled by original pkgutil iter_modules implementation (and consequently, python's FileFinder).
15 #
16 # The preferred way of adding support for iter_modules would be adding non-standard iter_modules() method to
17 # PyiFrozenImporter itself. However, that seems to work only for path entry finders (for use with sys.path_hooks), while
18 # PyInstaller's PyiFrozenImporter is registered as meta path finders (for use with sys.meta_path). Turning
19 # PyiFrozenImporter into path entry finder, would seemingly require the latter to support on-filesystem resources
20 # (e.g., extension modules) in addition to PYZ-embedded ones.
21 #
22 # Therefore, we instead opt for overriding pkgutil.iter_modules with custom implementation that augments the output of
23 # original implementation with contents of PYZ archive from PyiFrozenImporter's TOC.
24 
25 
26 def _pyi_rthook():
27     import pathlib
28     import pkgutil
29     import sys
30 
31     from pyimod02_importers import PyiFrozenImporter
32     from _pyi_rth_utils import is_macos_app_bundle
33 
34     _orig_pkgutil_iter_modules = pkgutil.iter_modules
35 
36     def _pyi_pkgutil_iter_modules(path=None, prefix=''):
37         # Use original implementation to discover on-filesystem modules (binary extensions in regular builds, or both
38         # binary extensions and compiled pyc modules in noarchive debug builds).
39         yield from _orig_pkgutil_iter_modules(path, prefix)
40 
41         # Find the instance of PyInstaller's PyiFrozenImporter.
42         for importer in pkgutil.iter_importers():
43             if isinstance(importer, PyiFrozenImporter):
44                 break
45         else:
46             return
47 
48         if path is None:
49             # Search for all top-level packages/modules in the PyiFrozenImporter's prefix tree.
50             for entry_name, entry_data in importer.toc_tree.items():
51                 # Package nodes have dict for data, module nodes (leaves) have (empty) strings.
52                 is_pkg = isinstance(entry_data, dict)
53                 yield pkgutil.ModuleInfo(importer, prefix + entry_name, is_pkg)
54         else:
55             # Fully resolve sys._MEIPASS, in order to avoid path mis-matches when the given search paths also contain
56             # symbolic links and are already fully resolved. See #6537 for an example of such a problem with onefile
57             # build on macOS, where the temporary directory is placed under /var, which is actually a symbolic link
58             # to /private/var.
59             MEIPASS = pathlib.Path(sys._MEIPASS).resolve()
60 
61             # For macOS .app bundles, the "true" sys._MEIPASS is `name.app/Contents/Frameworks`, but due to
62             # cross-linking, we must also consider `name.app/Contents/Resources`. See #7884.
63             if is_macos_app_bundle:
64                 ALT_MEIPASS = (pathlib.Path(sys._MEIPASS).parent / "Resources").resolve()
65 
66             # Process all given paths
67             seen_pkg_prefices = set()
68             for pkg_path in path:
69                 # Fully resolve the given path, in case it contains symbolic links.
70                 pkg_path = pathlib.Path(pkg_path).resolve()
71 
72                 # Try to compute package prefix, which is the remainder of the given path, relative to the sys._MEIPASS.
73                 pkg_prefix = None
74                 try:
75                     pkg_prefix = pkg_path.relative_to(MEIPASS)
76                 except ValueError:  # ValueError: 'a' is not in the subpath of 'b'
77                     pass
78 
79                 # For macOS .app bundle, try the alternative sys._MEIPASS
80                 if pkg_prefix is None and is_macos_app_bundle:
81                     try:
82                         pkg_prefix = pkg_path.relative_to(ALT_MEIPASS)
83                     except ValueError:
84                         pass
85 
86                 # Given path is outside of sys._MEIPASS; ignore it.
87                 if pkg_prefix is None:
88                     continue
89 
90                 # If we are given multiple paths and they are either duplicated or resolve to the same package prefix,
91                 # prevent duplication.
92                 if pkg_prefix in seen_pkg_prefices:
93                     continue
94                 seen_pkg_prefices.add(pkg_prefix)
95 
96                 # Traverse the PyiFrozenImporter's prefix tree using components of the relative package path, starting
97                 # at the tree root. This implicitly handles the case where the given path was actually sys._MEIPASS
98                 # itself, as in this case pkg_prefix is pathlib.Path(".") with empty parts tuple.
99                 tree_node = importer.toc_tree
100                 for pkg_name_part in pkg_prefix.parts:
101                     tree_node = tree_node.get(pkg_name_part)
102                     if tree_node is None:
103                         tree_node = {}
104                         break
105 
106                 # List entries from the target node.
107                 for entry_name, entry_data in tree_node.items():
108                     is_pkg = isinstance(entry_data, dict)
109                     yield pkgutil.ModuleInfo(importer, prefix + entry_name, is_pkg)
110 
111     pkgutil.iter_modules = _pyi_pkgutil_iter_modules
112 
113 
114 _pyi_rthook()
115 del _pyi_rthook
116
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py b/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py
--- a/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py
+++ b/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py
@@ -99,7 +99,10 @@
                 tree_node = importer.toc_tree
                 for pkg_name_part in pkg_prefix.parts:
                     tree_node = tree_node.get(pkg_name_part)
-                    if tree_node is None:
+                    if not isinstance(tree_node, dict):
+                        # This check handles two cases:
+                        #  a) path does not exist (`tree_node` is `None`)
+                        #  b) path corresponds to a module instead of a package (`tree_node` is a leaf node (`str`)).
                         tree_node = {}
                         break
 
diff --git a/PyInstaller/utils/hooks/django.py b/PyInstaller/utils/hooks/django.py
--- a/PyInstaller/utils/hooks/django.py
+++ b/PyInstaller/utils/hooks/django.py
@@ -89,7 +89,7 @@
     if hasattr(settings, 'TEMPLATES'):
         for templ in settings.TEMPLATES:
             backend = _remove_class(templ['BACKEND'])
-            hiddenimports += backend
+            hiddenimports.append(backend)
             # Include context_processors.
             if hasattr(templ, 'OPTIONS'):
                 if hasattr(templ['OPTIONS'], 'context_processors'):

{"golden_diff": "diff --git a/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py b/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py\n--- a/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py\n+++ b/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py\n@@ -99,7 +99,10 @@\n                 tree_node = importer.toc_tree\n                 for pkg_name_part in pkg_prefix.parts:\n                     tree_node = tree_node.get(pkg_name_part)\n-                    if tree_node is None:\n+                    if not isinstance(tree_node, dict):\n+                        # This check handles two cases:\n+                        #  a) path does not exist (`tree_node` is `None`)\n+                        #  b) path corresponds to a module instead of a package (`tree_node` is a leaf node (`str`)).\n                         tree_node = {}\n                         break\n \ndiff --git a/PyInstaller/utils/hooks/django.py b/PyInstaller/utils/hooks/django.py\n--- a/PyInstaller/utils/hooks/django.py\n+++ b/PyInstaller/utils/hooks/django.py\n@@ -89,7 +89,7 @@\n     if hasattr(settings, 'TEMPLATES'):\n         for templ in settings.TEMPLATES:\n             backend = _remove_class(templ['BACKEND'])\n-            hiddenimports += backend\n+            hiddenimports.append(backend)\n             # Include context_processors.\n             if hasattr(templ, 'OPTIONS'):\n                 if hasattr(templ['OPTIONS'], 'context_processors'):\n", "issue": "site-packages\\django\\contrib\\sites has managment.py file which is conflicting with managment directory and causing a issue in tree get issue in _pyi_pkgutil_iter_modules as dirretory name and file are same \nWhen I execute a generated exe from pyinstaller, it is failing as django.contrib.sites has mangment.py file which is conflicting with package which by default will have management as directory.\r\n\r\nas technically there is no management folder but when find_commands whose iterator is override by _pyi_pkgutil_iter_modules id expecting a tree node with dict but it has a file with managment.py so it is failing as str error.\r\n\r\nIf any app has management folder and also managment.py it will yield in to this issue. We can rename custom apps to avoid the file name duplication with management folder but how to deal with standard dajngo apps like django.contrib.sites\r\n\r\nhere is the stack trace \r\n\r\n\r\n\r\n-> for pkg_name_part in pkg_prefix.parts:\r\n(Pdb) pkg_prefix.parts\r\n('django', 'contrib', 'sites', 'management', 'commands')          ====>    management here is expected a dict , as dict is not there it will be there in toc but as a file is there. it finds the file as str instead of dict and so is the assert.\r\n(Pdb) c\r\nTraceback (most recent call last):\r\n  File \"manage.py\", line 19, in <module>\r\n    execute_from_command_line(sys.argv)\r\n  File \"django\\core\\management\\__init__.py\", line 442, in execute_from_command_line\r\n  File \"django\\core\\management\\__init__.py\", line 424, in execute\r\n  File \"django\\core\\management\\__init__.py\", line 222, in main_help_text\r\n  File \"django\\core\\management\\__init__.py\", line 78, in get_commands\r\n  File \"django\\core\\management\\__init__.py\", line 35, in find_commands\r\n  File \"django\\core\\management\\__init__.py\", line 35, in <listcomp>\r\n  File \"C:\\PythonWebCode\\testone\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py\", line 102, in _pyi_pkgutil_iter_modules\r\n    for pkg_name_part in pkg_prefix.parts:\r\nAttributeError: 'str' object has no attribute 'get'\r\n\r\nHow can we address this issue ?\r\n\r\n\n", "before_files": [{"content": "# ----------------------------------------------------------------------------\n# Copyright (c) 2005-2023, PyInstaller Development Team.\n#\n# Distributed under the terms of the GNU General Public License (version 2\n# or later) with exception for distributing the bootloader.\n#\n# The full license is in the file COPYING.txt, distributed with this software.\n#\n# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)\n# ----------------------------------------------------------------------------\nimport os\n\nfrom PyInstaller import isolated\n\n\n@isolated.decorate\ndef django_dottedstring_imports(django_root_dir):\n    \"\"\"\n    An isolated helper that returns list of all Django dependencies, parsed from the `mysite.settings` module.\n\n    NOTE: With newer version of Django this is most likely the part of PyInstaller that will be broken.\n\n    Tested with Django 2.2\n    \"\"\"\n\n    import sys\n    import os\n\n    import PyInstaller.utils.misc\n    from PyInstaller.utils import hooks as hookutils\n\n    # Extra search paths to add to sys.path:\n    #  - parent directory of the django_root_dir\n    #  - django_root_dir itself; often, Django users do not specify absolute imports in the settings module.\n    search_paths = [\n        PyInstaller.utils.misc.get_path_to_toplevel_modules(django_root_dir),\n        django_root_dir,\n    ]\n    sys.path += search_paths\n\n    # Set the path to project's settings module\n    default_settings_module = os.path.basename(django_root_dir) + '.settings'\n    settings_module = os.environ.get('DJANGO_SETTINGS_MODULE', default_settings_module)\n    os.environ['DJANGO_SETTINGS_MODULE'] = settings_module\n\n    # Calling django.setup() avoids the exception AppRegistryNotReady() and also reads the user settings\n    # from DJANGO_SETTINGS_MODULE.\n    # https://stackoverflow.com/questions/24793351/django-appregistrynotready\n    import django  # noqa: E402\n\n    django.setup()\n\n    # This allows to access all django settings even from the settings.py module.\n    from django.conf import settings  # noqa: E402\n\n    hiddenimports = list(settings.INSTALLED_APPS)\n\n    # Do not fail script when settings does not have such attributes.\n    if hasattr(settings, 'TEMPLATE_CONTEXT_PROCESSORS'):\n        hiddenimports += list(settings.TEMPLATE_CONTEXT_PROCESSORS)\n\n    if hasattr(settings, 'TEMPLATE_LOADERS'):\n        hiddenimports += list(settings.TEMPLATE_LOADERS)\n\n    hiddenimports += [settings.ROOT_URLCONF]\n\n    def _remove_class(class_name):\n        return '.'.join(class_name.split('.')[0:-1])\n\n    #-- Changes in Django 1.7.\n\n    # Remove class names and keep just modules.\n    if hasattr(settings, 'AUTHENTICATION_BACKENDS'):\n        for cl in settings.AUTHENTICATION_BACKENDS:\n            cl = _remove_class(cl)\n            hiddenimports.append(cl)\n    if hasattr(settings, 'DEFAULT_FILE_STORAGE'):\n        cl = _remove_class(settings.DEFAULT_FILE_STORAGE)\n        hiddenimports.append(cl)\n    if hasattr(settings, 'FILE_UPLOAD_HANDLERS'):\n        for cl in settings.FILE_UPLOAD_HANDLERS:\n            cl = _remove_class(cl)\n            hiddenimports.append(cl)\n    if hasattr(settings, 'MIDDLEWARE_CLASSES'):\n        for cl in settings.MIDDLEWARE_CLASSES:\n            cl = _remove_class(cl)\n            hiddenimports.append(cl)\n    # Templates is a dict:\n    if hasattr(settings, 'TEMPLATES'):\n        for templ in settings.TEMPLATES:\n            backend = _remove_class(templ['BACKEND'])\n            hiddenimports += backend\n            # Include context_processors.\n            if hasattr(templ, 'OPTIONS'):\n                if hasattr(templ['OPTIONS'], 'context_processors'):\n                    # Context processors are functions - strip last word.\n                    mods = templ['OPTIONS']['context_processors']\n                    mods = [_remove_class(x) for x in mods]\n                    hiddenimports += mods\n    # Include database backends - it is a dict.\n    for v in settings.DATABASES.values():\n        hiddenimports.append(v['ENGINE'])\n\n    # Add templatetags and context processors for each installed app.\n    for app in settings.INSTALLED_APPS:\n        app_templatetag_module = app + '.templatetags'\n        app_ctx_proc_module = app + '.context_processors'\n        hiddenimports.append(app_templatetag_module)\n        hiddenimports += hookutils.collect_submodules(app_templatetag_module)\n        hiddenimports.append(app_ctx_proc_module)\n\n    # Deduplicate imports.\n    hiddenimports = list(set(hiddenimports))\n\n    # Return the hidden imports\n    return hiddenimports\n\n\ndef django_find_root_dir():\n    \"\"\"\n    Return path to directory (top-level Python package) that contains main django files. Return None if no directory\n    was detected.\n\n    Main Django project directory contain files like '__init__.py', 'settings.py' and 'url.py'.\n\n    In Django 1.4+ the script 'manage.py' is not in the directory with 'settings.py' but usually one level up. We\n    need to detect this special case too.\n    \"\"\"\n    # 'PyInstaller.config' cannot be imported as other top-level modules.\n    from PyInstaller.config import CONF\n\n    # Get the directory with manage.py. Manage.py is supplied to PyInstaller as the first main executable script.\n    manage_py = CONF['main_script']\n    manage_dir = os.path.dirname(os.path.abspath(manage_py))\n\n    # Get the Django root directory. The directory that contains settings.py and url.py. It could be the directory\n    # containing manage.py or any of its subdirectories.\n    settings_dir = None\n    files = set(os.listdir(manage_dir))\n    if ('settings.py' in files or 'settings' in files) and 'urls.py' in files:\n        settings_dir = manage_dir\n    else:\n        for f in files:\n            if os.path.isdir(os.path.join(manage_dir, f)):\n                subfiles = os.listdir(os.path.join(manage_dir, f))\n                # Subdirectory contains critical files.\n                if ('settings.py' in subfiles or 'settings' in subfiles) and 'urls.py' in subfiles:\n                    settings_dir = os.path.join(manage_dir, f)\n                    break  # Find the first directory.\n\n    return settings_dir\n", "path": "PyInstaller/utils/hooks/django.py"}, {"content": "#-----------------------------------------------------------------------------\n# Copyright (c) 2021-2023, PyInstaller Development Team.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n#\n# The full license is in the file COPYING.txt, distributed with this software.\n#\n# SPDX-License-Identifier: Apache-2.0\n#-----------------------------------------------------------------------------\n#\n# This rthook overrides pkgutil.iter_modules with custom implementation that uses PyInstaller's PyiFrozenImporter to\n# list sub-modules embedded in the PYZ archive. The non-embedded modules (binary extensions, or .pyc modules in\n# noarchive build) are handled by original pkgutil iter_modules implementation (and consequently, python's FileFinder).\n#\n# The preferred way of adding support for iter_modules would be adding non-standard iter_modules() method to\n# PyiFrozenImporter itself. However, that seems to work only for path entry finders (for use with sys.path_hooks), while\n# PyInstaller's PyiFrozenImporter is registered as meta path finders (for use with sys.meta_path). Turning\n# PyiFrozenImporter into path entry finder, would seemingly require the latter to support on-filesystem resources\n# (e.g., extension modules) in addition to PYZ-embedded ones.\n#\n# Therefore, we instead opt for overriding pkgutil.iter_modules with custom implementation that augments the output of\n# original implementation with contents of PYZ archive from PyiFrozenImporter's TOC.\n\n\ndef _pyi_rthook():\n    import pathlib\n    import pkgutil\n    import sys\n\n    from pyimod02_importers import PyiFrozenImporter\n    from _pyi_rth_utils import is_macos_app_bundle\n\n    _orig_pkgutil_iter_modules = pkgutil.iter_modules\n\n    def _pyi_pkgutil_iter_modules(path=None, prefix=''):\n        # Use original implementation to discover on-filesystem modules (binary extensions in regular builds, or both\n        # binary extensions and compiled pyc modules in noarchive debug builds).\n        yield from _orig_pkgutil_iter_modules(path, prefix)\n\n        # Find the instance of PyInstaller's PyiFrozenImporter.\n        for importer in pkgutil.iter_importers():\n            if isinstance(importer, PyiFrozenImporter):\n                break\n        else:\n            return\n\n        if path is None:\n            # Search for all top-level packages/modules in the PyiFrozenImporter's prefix tree.\n            for entry_name, entry_data in importer.toc_tree.items():\n                # Package nodes have dict for data, module nodes (leaves) have (empty) strings.\n                is_pkg = isinstance(entry_data, dict)\n                yield pkgutil.ModuleInfo(importer, prefix + entry_name, is_pkg)\n        else:\n            # Fully resolve sys._MEIPASS, in order to avoid path mis-matches when the given search paths also contain\n            # symbolic links and are already fully resolved. See #6537 for an example of such a problem with onefile\n            # build on macOS, where the temporary directory is placed under /var, which is actually a symbolic link\n            # to /private/var.\n            MEIPASS = pathlib.Path(sys._MEIPASS).resolve()\n\n            # For macOS .app bundles, the \"true\" sys._MEIPASS is `name.app/Contents/Frameworks`, but due to\n            # cross-linking, we must also consider `name.app/Contents/Resources`. See #7884.\n            if is_macos_app_bundle:\n                ALT_MEIPASS = (pathlib.Path(sys._MEIPASS).parent / \"Resources\").resolve()\n\n            # Process all given paths\n            seen_pkg_prefices = set()\n            for pkg_path in path:\n                # Fully resolve the given path, in case it contains symbolic links.\n                pkg_path = pathlib.Path(pkg_path).resolve()\n\n                # Try to compute package prefix, which is the remainder of the given path, relative to the sys._MEIPASS.\n                pkg_prefix = None\n                try:\n                    pkg_prefix = pkg_path.relative_to(MEIPASS)\n                except ValueError:  # ValueError: 'a' is not in the subpath of 'b'\n                    pass\n\n                # For macOS .app bundle, try the alternative sys._MEIPASS\n                if pkg_prefix is None and is_macos_app_bundle:\n                    try:\n                        pkg_prefix = pkg_path.relative_to(ALT_MEIPASS)\n                    except ValueError:\n                        pass\n\n                # Given path is outside of sys._MEIPASS; ignore it.\n                if pkg_prefix is None:\n                    continue\n\n                # If we are given multiple paths and they are either duplicated or resolve to the same package prefix,\n                # prevent duplication.\n                if pkg_prefix in seen_pkg_prefices:\n                    continue\n                seen_pkg_prefices.add(pkg_prefix)\n\n                # Traverse the PyiFrozenImporter's prefix tree using components of the relative package path, starting\n                # at the tree root. This implicitly handles the case where the given path was actually sys._MEIPASS\n                # itself, as in this case pkg_prefix is pathlib.Path(\".\") with empty parts tuple.\n                tree_node = importer.toc_tree\n                for pkg_name_part in pkg_prefix.parts:\n                    tree_node = tree_node.get(pkg_name_part)\n                    if tree_node is None:\n                        tree_node = {}\n                        break\n\n                # List entries from the target node.\n                for entry_name, entry_data in tree_node.items():\n                    is_pkg = isinstance(entry_data, dict)\n                    yield pkgutil.ModuleInfo(importer, prefix + entry_name, is_pkg)\n\n    pkgutil.iter_modules = _pyi_pkgutil_iter_modules\n\n\n_pyi_rthook()\ndel _pyi_rthook\n", "path": "PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py"}], "after_files": [{"content": "# ----------------------------------------------------------------------------\n# Copyright (c) 2005-2023, PyInstaller Development Team.\n#\n# Distributed under the terms of the GNU General Public License (version 2\n# or later) with exception for distributing the bootloader.\n#\n# The full license is in the file COPYING.txt, distributed with this software.\n#\n# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)\n# ----------------------------------------------------------------------------\nimport os\n\nfrom PyInstaller import isolated\n\n\n@isolated.decorate\ndef django_dottedstring_imports(django_root_dir):\n    \"\"\"\n    An isolated helper that returns list of all Django dependencies, parsed from the `mysite.settings` module.\n\n    NOTE: With newer version of Django this is most likely the part of PyInstaller that will be broken.\n\n    Tested with Django 2.2\n    \"\"\"\n\n    import sys\n    import os\n\n    import PyInstaller.utils.misc\n    from PyInstaller.utils import hooks as hookutils\n\n    # Extra search paths to add to sys.path:\n    #  - parent directory of the django_root_dir\n    #  - django_root_dir itself; often, Django users do not specify absolute imports in the settings module.\n    search_paths = [\n        PyInstaller.utils.misc.get_path_to_toplevel_modules(django_root_dir),\n        django_root_dir,\n    ]\n    sys.path += search_paths\n\n    # Set the path to project's settings module\n    default_settings_module = os.path.basename(django_root_dir) + '.settings'\n    settings_module = os.environ.get('DJANGO_SETTINGS_MODULE', default_settings_module)\n    os.environ['DJANGO_SETTINGS_MODULE'] = settings_module\n\n    # Calling django.setup() avoids the exception AppRegistryNotReady() and also reads the user settings\n    # from DJANGO_SETTINGS_MODULE.\n    # https://stackoverflow.com/questions/24793351/django-appregistrynotready\n    import django  # noqa: E402\n\n    django.setup()\n\n    # This allows to access all django settings even from the settings.py module.\n    from django.conf import settings  # noqa: E402\n\n    hiddenimports = list(settings.INSTALLED_APPS)\n\n    # Do not fail script when settings does not have such attributes.\n    if hasattr(settings, 'TEMPLATE_CONTEXT_PROCESSORS'):\n        hiddenimports += list(settings.TEMPLATE_CONTEXT_PROCESSORS)\n\n    if hasattr(settings, 'TEMPLATE_LOADERS'):\n        hiddenimports += list(settings.TEMPLATE_LOADERS)\n\n    hiddenimports += [settings.ROOT_URLCONF]\n\n    def _remove_class(class_name):\n        return '.'.join(class_name.split('.')[0:-1])\n\n    #-- Changes in Django 1.7.\n\n    # Remove class names and keep just modules.\n    if hasattr(settings, 'AUTHENTICATION_BACKENDS'):\n        for cl in settings.AUTHENTICATION_BACKENDS:\n            cl = _remove_class(cl)\n            hiddenimports.append(cl)\n    if hasattr(settings, 'DEFAULT_FILE_STORAGE'):\n        cl = _remove_class(settings.DEFAULT_FILE_STORAGE)\n        hiddenimports.append(cl)\n    if hasattr(settings, 'FILE_UPLOAD_HANDLERS'):\n        for cl in settings.FILE_UPLOAD_HANDLERS:\n            cl = _remove_class(cl)\n            hiddenimports.append(cl)\n    if hasattr(settings, 'MIDDLEWARE_CLASSES'):\n        for cl in settings.MIDDLEWARE_CLASSES:\n            cl = _remove_class(cl)\n            hiddenimports.append(cl)\n    # Templates is a dict:\n    if hasattr(settings, 'TEMPLATES'):\n        for templ in settings.TEMPLATES:\n            backend = _remove_class(templ['BACKEND'])\n            hiddenimports.append(backend)\n            # Include context_processors.\n            if hasattr(templ, 'OPTIONS'):\n                if hasattr(templ['OPTIONS'], 'context_processors'):\n                    # Context processors are functions - strip last word.\n                    mods = templ['OPTIONS']['context_processors']\n                    mods = [_remove_class(x) for x in mods]\n                    hiddenimports += mods\n    # Include database backends - it is a dict.\n    for v in settings.DATABASES.values():\n        hiddenimports.append(v['ENGINE'])\n\n    # Add templatetags and context processors for each installed app.\n    for app in settings.INSTALLED_APPS:\n        app_templatetag_module = app + '.templatetags'\n        app_ctx_proc_module = app + '.context_processors'\n        hiddenimports.append(app_templatetag_module)\n        hiddenimports += hookutils.collect_submodules(app_templatetag_module)\n        hiddenimports.append(app_ctx_proc_module)\n\n    # Deduplicate imports.\n    hiddenimports = list(set(hiddenimports))\n\n    # Return the hidden imports\n    return hiddenimports\n\n\ndef django_find_root_dir():\n    \"\"\"\n    Return path to directory (top-level Python package) that contains main django files. Return None if no directory\n    was detected.\n\n    Main Django project directory contain files like '__init__.py', 'settings.py' and 'url.py'.\n\n    In Django 1.4+ the script 'manage.py' is not in the directory with 'settings.py' but usually one level up. We\n    need to detect this special case too.\n    \"\"\"\n    # 'PyInstaller.config' cannot be imported as other top-level modules.\n    from PyInstaller.config import CONF\n\n    # Get the directory with manage.py. Manage.py is supplied to PyInstaller as the first main executable script.\n    manage_py = CONF['main_script']\n    manage_dir = os.path.dirname(os.path.abspath(manage_py))\n\n    # Get the Django root directory. The directory that contains settings.py and url.py. It could be the directory\n    # containing manage.py or any of its subdirectories.\n    settings_dir = None\n    files = set(os.listdir(manage_dir))\n    if ('settings.py' in files or 'settings' in files) and 'urls.py' in files:\n        settings_dir = manage_dir\n    else:\n        for f in files:\n            if os.path.isdir(os.path.join(manage_dir, f)):\n                subfiles = os.listdir(os.path.join(manage_dir, f))\n                # Subdirectory contains critical files.\n                if ('settings.py' in subfiles or 'settings' in subfiles) and 'urls.py' in subfiles:\n                    settings_dir = os.path.join(manage_dir, f)\n                    break  # Find the first directory.\n\n    return settings_dir\n", "path": "PyInstaller/utils/hooks/django.py"}, {"content": "#-----------------------------------------------------------------------------\n# Copyright (c) 2021-2023, PyInstaller Development Team.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n#\n# The full license is in the file COPYING.txt, distributed with this software.\n#\n# SPDX-License-Identifier: Apache-2.0\n#-----------------------------------------------------------------------------\n#\n# This rthook overrides pkgutil.iter_modules with custom implementation that uses PyInstaller's PyiFrozenImporter to\n# list sub-modules embedded in the PYZ archive. The non-embedded modules (binary extensions, or .pyc modules in\n# noarchive build) are handled by original pkgutil iter_modules implementation (and consequently, python's FileFinder).\n#\n# The preferred way of adding support for iter_modules would be adding non-standard iter_modules() method to\n# PyiFrozenImporter itself. However, that seems to work only for path entry finders (for use with sys.path_hooks), while\n# PyInstaller's PyiFrozenImporter is registered as meta path finders (for use with sys.meta_path). Turning\n# PyiFrozenImporter into path entry finder, would seemingly require the latter to support on-filesystem resources\n# (e.g., extension modules) in addition to PYZ-embedded ones.\n#\n# Therefore, we instead opt for overriding pkgutil.iter_modules with custom implementation that augments the output of\n# original implementation with contents of PYZ archive from PyiFrozenImporter's TOC.\n\n\ndef _pyi_rthook():\n    import pathlib\n    import pkgutil\n    import sys\n\n    from pyimod02_importers import PyiFrozenImporter\n    from _pyi_rth_utils import is_macos_app_bundle\n\n    _orig_pkgutil_iter_modules = pkgutil.iter_modules\n\n    def _pyi_pkgutil_iter_modules(path=None, prefix=''):\n        # Use original implementation to discover on-filesystem modules (binary extensions in regular builds, or both\n        # binary extensions and compiled pyc modules in noarchive debug builds).\n        yield from _orig_pkgutil_iter_modules(path, prefix)\n\n        # Find the instance of PyInstaller's PyiFrozenImporter.\n        for importer in pkgutil.iter_importers():\n            if isinstance(importer, PyiFrozenImporter):\n                break\n        else:\n            return\n\n        if path is None:\n            # Search for all top-level packages/modules in the PyiFrozenImporter's prefix tree.\n            for entry_name, entry_data in importer.toc_tree.items():\n                # Package nodes have dict for data, module nodes (leaves) have (empty) strings.\n                is_pkg = isinstance(entry_data, dict)\n                yield pkgutil.ModuleInfo(importer, prefix + entry_name, is_pkg)\n        else:\n            # Fully resolve sys._MEIPASS, in order to avoid path mis-matches when the given search paths also contain\n            # symbolic links and are already fully resolved. See #6537 for an example of such a problem with onefile\n            # build on macOS, where the temporary directory is placed under /var, which is actually a symbolic link\n            # to /private/var.\n            MEIPASS = pathlib.Path(sys._MEIPASS).resolve()\n\n            # For macOS .app bundles, the \"true\" sys._MEIPASS is `name.app/Contents/Frameworks`, but due to\n            # cross-linking, we must also consider `name.app/Contents/Resources`. See #7884.\n            if is_macos_app_bundle:\n                ALT_MEIPASS = (pathlib.Path(sys._MEIPASS).parent / \"Resources\").resolve()\n\n            # Process all given paths\n            seen_pkg_prefices = set()\n            for pkg_path in path:\n                # Fully resolve the given path, in case it contains symbolic links.\n                pkg_path = pathlib.Path(pkg_path).resolve()\n\n                # Try to compute package prefix, which is the remainder of the given path, relative to the sys._MEIPASS.\n                pkg_prefix = None\n                try:\n                    pkg_prefix = pkg_path.relative_to(MEIPASS)\n                except ValueError:  # ValueError: 'a' is not in the subpath of 'b'\n                    pass\n\n                # For macOS .app bundle, try the alternative sys._MEIPASS\n                if pkg_prefix is None and is_macos_app_bundle:\n                    try:\n                        pkg_prefix = pkg_path.relative_to(ALT_MEIPASS)\n                    except ValueError:\n                        pass\n\n                # Given path is outside of sys._MEIPASS; ignore it.\n                if pkg_prefix is None:\n                    continue\n\n                # If we are given multiple paths and they are either duplicated or resolve to the same package prefix,\n                # prevent duplication.\n                if pkg_prefix in seen_pkg_prefices:\n                    continue\n                seen_pkg_prefices.add(pkg_prefix)\n\n                # Traverse the PyiFrozenImporter's prefix tree using components of the relative package path, starting\n                # at the tree root. This implicitly handles the case where the given path was actually sys._MEIPASS\n                # itself, as in this case pkg_prefix is pathlib.Path(\".\") with empty parts tuple.\n                tree_node = importer.toc_tree\n                for pkg_name_part in pkg_prefix.parts:\n                    tree_node = tree_node.get(pkg_name_part)\n                    if not isinstance(tree_node, dict):\n                        # This check handles two cases:\n                        #  a) path does not exist (`tree_node` is `None`)\n                        #  b) path corresponds to a module instead of a package (`tree_node` is a leaf node (`str`)).\n                        tree_node = {}\n                        break\n\n                # List entries from the target node.\n                for entry_name, entry_data in tree_node.items():\n                    is_pkg = isinstance(entry_data, dict)\n                    yield pkgutil.ModuleInfo(importer, prefix + entry_name, is_pkg)\n\n    pkgutil.iter_modules = _pyi_pkgutil_iter_modules\n\n\n_pyi_rthook()\ndel _pyi_rthook\n", "path": "PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py"}]}