Repository: pyinstaller/pyinstaller

Issue:
ImportError: '__main__' is not a built-in module
## Description of the issue

ImportError: '__main__' is not a built-in module
I'm not sure what else should I write here, I just can't access __main__ using dis

### Context information (for bug reports)

* Output of `pyinstaller --version`: ```4.3```
* Version of Python: 3.7
* Platform: Windows 10 Pro Version 20H2
* How you installed Python: python.org/downloads
* Did you also try this on another platform? Does it work there? -- I have not tried this on another platform but I'm pretty sure it won't work.

```
import dis
import sys

print(sys.modules["__main__"])
print(dis.dis(sys.modules["__main__"].__loader__.get_code("__main__")))
```

### Stacktrace / full error message

```
Traceback (most recent call last):
  File "decompile code.py", line 6, in <module>
  File "<frozen importlib._bootstrap>", line 235, in _requires_builtin_wrapper
ImportError: '__main__' is not a built-in module
[18232] Failed to execute script decompile code
```



Discussion:
I can reproduce this without PyInstaller just by piping that snippet of code to Python rather than running it.
```python
$ cat test.py | python
<module '__main__' (built-in)>
Traceback (most recent call last):
  File "<stdin>", line 5, in <module>
  File "<frozen importlib._bootstrap>", line 243, in _requires_builtin_wrapper
ImportError: '__main__' is not a built-in module

```

I'm guessing that PyInstaller does something more like `exec()`-ing the bytecode rather than doing whatever it's supposed to do to run an entry point script.

Resolving patch:
diff --git a/PyInstaller/loader/pyimod03_importers.py b/PyInstaller/loader/pyimod03_importers.py
--- a/PyInstaller/loader/pyimod03_importers.py
+++ b/PyInstaller/loader/pyimod03_importers.py
@@ -311,9 +311,15 @@ def get_code(self, fullname):
         ImportError should be raised if module not found.
         """
         try:
-            # extract() returns None if fullname not in the archive, thus the
-            # next line will raise an execpion which will be catched just
-            # below and raise the ImportError.
+            if fullname == '__main__':
+                # Special handling for __main__ module; the bootloader
+                # should store code object to _pyi_main_co attribute of
+                # the module.
+                return sys.modules['__main__']._pyi_main_co
+
+            # extract() returns None if fullname not in the archive, and the
+            # subsequent subscription attempt raises exception, which
+            # is turned into ImportError.
             return self._pyz_archive.extract(fullname)[1]
         except Exception as e:
             raise ImportError(
@@ -584,3 +590,10 @@ def install():
                 pathFinders.append(item)
     sys.meta_path.extend(reversed(pathFinders))
     # TODO Do we need for Python 3 _frozen_importlib.FrozenImporter? Could it be also removed?
+
+    # Set the FrozenImporter as loader for __main__, in order for python
+    # to treat __main__ as a module instead of a built-in.
+    try:
+        sys.modules['__main__'].__loader__ = fimp
+    except Exception:
+        pass


Test patch:
diff --git a/tests/functional/test_misc.py b/tests/functional/test_misc.py
--- a/tests/functional/test_misc.py
+++ b/tests/functional/test_misc.py
@@ -53,3 +53,14 @@ def test_inspect_getmodule_from_stackframes(pyi_builder):
         module_names = [module.__name__ for module in modules]
         assert module_names == expected_module_names
         """, pyi_args=['--paths', pathex], run_from_path=True)
+
+
+# Test whether dis can disassemble the __main__ module, as per #5897.
+def test_dis_main(pyi_builder):
+    pyi_builder.test_source(
+        """
+        import dis
+        import sys
+
+        print(dis.dis(sys.modules["__main__"].__loader__.get_code("__main__")))
+        """)