We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
AssertionError when using PyInstaller. Fixed when following line is commented in modulegraph.py: assert prev_insts[-2].opname == 'LOAD_CONST'
<!--
Welcome to the PyInstaller issue tracker! Before creating an issue, please heed the following:

1. This tracker should only be used to report bugs and request features / enhancements to PyInstaller
    - For questions and general support, use the mailing list, see
	  <http://www.pyinstaller.org/support.html#mailing-list>
2. Use the search function before creating a new issue. Duplicates will be closed and directed to
   the original discussion.
3. When making a bug report, make sure you provide all required information. The easier it is for
   maintainers to reproduce, the faster it'll be fixed.
-->

<!-- +++ ONLY TEXT +++ DO NOT POST IMAGES +++ -->

The following was posted on the google groups discussion and was suggested by @Legorooj to post it here:

PyInstaller version: 4.10
Version of Python: 3.6.8
Platform: Windows 10
Python installed from: [python.org](http://python.org/)
Didn't try on another platform.
Will try development version if necessary.

Clean installation.
Ran program from command window
Used --onedir mode

Error:
```\site-packages\PyInstaller\lib\modulegraph\modulegraph.py, line 2771, in _scan_bytecode()`
    assert prev_insts[-2].opname == 'LOAD_CONST'
AssertionError```

Command line used: `pyinstaller -F --clean --paths {paths --collect-all {name1} --collect-all {name2} script.py`

### Quick overview
The problem arises when using `.pyc` files for the modules in `name1` and `name2`.
The problem does not occur when I comment out [this](https://github.com/pyinstaller/pyinstaller/blob/3ea48fd875e786ecbb3c160209791aa11d55ae99/PyInstaller/lib/modulegraph/modulegraph.py#L2764) line in modulegraph.py.
When I run pyinstaller without line 2764 (linked above), everything runs to completion and the executable generated works as intended.
I've been trying to look through previous commits to try and understand the reason for the assert statement and why it is necessary. Could it perhaps no longer be necessary?

Root cause: `The prev_insts[-2].opname` variable is equal to `EXTENDED_ARG` thus causing the assert statement to fail.

There's been a few issues before related to `EXTENDED_ARG` (but not my exact problem) as well as commits.

- [Link](https://github.com/pyinstaller/pyinstaller/pull/5830)
- [Link](https://github.com/pyinstaller/pyinstaller/issues/6301#issuecomment-962519524)
- And this [link](https://github.com/pyinstaller/pyinstaller/commit/ed732c92eded85e6bca4232eedefee2906bbfa52) seems to be the commit for the first variation of the LOAD_CONST assert but it's not clear to me why it's there.

Based on what I found in PyInstaller's current [bytecode.py](https://github.com/pyinstaller/pyinstaller/blob/1e6a8d53f150cf24b574c32085f3745cbd2afaa6/PyInstaller/depend/bytecode.py#L13), it seems like it might need to be expanded on:

> The biggest clarity killer here is the ``EXTENDED_ARG`` opcode which can appear almost anywhere and therefore needs to be tiptoed around at every step. If this code needs to expand significantly, I would recommend an upgrade to a regex-based grammar parsing library such as Reparse. This way, little steps like unpacking ``EXTENDED_ARGS`` can be defined once then simply referenced forming a nice hierarchy rather than copied everywhere its needed.


Could you please provide some information about why this type of opcode requires an exception to be thrown and why PyInstaller works when the assertion is removed? Or just confirm with me whether or not it is safe for me to continue on with the line removed? Or even just a way to avoid running into this exception?

[Reference](https://docs.python.org/3/library/dis.html?highlight=load_const#opcode-LOAD_CONST) to extended_arg from dis.py.

Thank you,

Eduardo

--- 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/lib/modulegraph/util.py`
Content:
```
1 
2 # Filter DeprecationWarnings until the code has been revised
3 import warnings
4 warnings.filterwarnings("ignore", "the imp module is deprecated in")
5 warnings.filterwarnings("ignore", "imp_walk will be removed in a future")
6 
7 import os
8 import imp
9 import sys
10 import re
11 import marshal
12 import warnings
13 import inspect
14 
15 try:
16     unicode
17 except NameError:
18     unicode = str
19 
20 from ._compat import StringIO, BytesIO, get_instructions, _READ_MODE
21 
22 
23 def imp_find_module(name, path=None):
24     """
25     same as imp.find_module, but handles dotted names
26     """
27     names = name.split('.')
28     if path is not None:
29         if isinstance(path, (str, unicode)):
30             path = [os.path.realpath(path)]
31     for name in names:
32         result = imp.find_module(name, path)
33         if result[0] is not None:
34             result[0].close()
35         path = [result[1]]
36     return result
37 
38 
39 def _check_importer_for_path(name, path_item):
40     try:
41         importer = sys.path_importer_cache[path_item]
42     except KeyError:
43         for path_hook in sys.path_hooks:
44             try:
45                 importer = path_hook(path_item)
46                 break
47             except ImportError:
48                 pass
49         else:
50             importer = None
51         sys.path_importer_cache.setdefault(path_item, importer)
52 
53     if importer is None:
54         try:
55             return imp.find_module(name, [path_item])
56         except ImportError:
57             return None
58     return importer.find_module(name)
59 
60 
61 def imp_walk(name):
62     """
63     yields namepart, tuple_or_importer for each path item
64 
65     raise ImportError if a name can not be found.
66     """
67     warnings.warn(
68         "imp_walk will be removed in a future version",
69         DeprecationWarning)
70 
71     if name in sys.builtin_module_names:
72         yield name, (None, None, ("", "", imp.C_BUILTIN))
73         return
74     paths = sys.path
75     res = None
76     for namepart in name.split('.'):
77         for path_item in paths:
78             res = _check_importer_for_path(namepart, path_item)
79             if hasattr(res, 'load_module'):
80                 if res.path.endswith('.py') or res.path.endswith('.pyw'):
81                     fp = StringIO(res.get_source(namepart))
82                     res = (fp, res.path, ('.py', _READ_MODE, imp.PY_SOURCE))
83                 elif res.path.endswith('.pyc') or res.path.endswith('.pyo'):
84                     co = res.get_code(namepart)
85                     fp = BytesIO(
86                         imp.get_magic() + b'\0\0\0\0' + marshal.dumps(co))
87                     res = (fp, res.path, ('.pyc', 'rb', imp.PY_COMPILED))
88 
89                 else:
90                     res = (
91                         None,
92                         res.path,
93                         (
94                             os.path.splitext(res.path)[-1],
95                             'rb',
96                             imp.C_EXTENSION
97                         )
98                     )
99 
100                 break
101             elif isinstance(res, tuple):
102                 break
103         else:
104             break
105 
106         yield namepart, res
107         paths = [os.path.join(path_item, namepart)]
108     else:
109         return
110 
111     raise ImportError('No module named %s' % (name,))
112 
113 
114 cookie_re = re.compile(br"coding[:=]\s*([-\w.]+)")
115 if sys.version_info[0] == 2:
116     default_encoding = 'ascii'
117 else:
118     default_encoding = 'utf-8'
119 
120 
121 def guess_encoding(fp):
122 
123     for i in range(2):
124         ln = fp.readline()
125 
126         m = cookie_re.search(ln)
127         if m is not None:
128             return m.group(1).decode('ascii')
129 
130     return default_encoding
131 
132 
133 def iterate_instructions(code_object):
134     """Delivers the byte-code instructions as a continuous stream.
135 
136     Yields `dis.Instruction`. After each code-block (`co_code`), `None` is
137     yielded to mark the end of the block and to interrupt the steam.
138     """
139     yield from get_instructions(code_object)
140 
141     yield None
142 
143     # For each constant in this code object that is itself a code object,
144     # parse this constant in the same manner.
145     for constant in code_object.co_consts:
146         if inspect.iscode(constant):
147             yield from iterate_instructions(constant)
148
```
--- 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/lib/modulegraph/util.py b/PyInstaller/lib/modulegraph/util.py
--- a/PyInstaller/lib/modulegraph/util.py
+++ b/PyInstaller/lib/modulegraph/util.py
@@ -136,7 +136,9 @@
     Yields `dis.Instruction`. After each code-block (`co_code`), `None` is
     yielded to mark the end of the block and to interrupt the steam.
     """
-    yield from get_instructions(code_object)
+    # The arg extension the EXTENDED_ARG opcode represents is automatically handled by get_instructions() but the
+    # instruction is left in. Get rid of it to make subsequent parsing easier/safer.
+    yield from (i for i in get_instructions(code_object) if i.opname != "EXTENDED_ARG")
 
     yield None

{"golden_diff": "diff --git a/PyInstaller/lib/modulegraph/util.py b/PyInstaller/lib/modulegraph/util.py\n--- a/PyInstaller/lib/modulegraph/util.py\n+++ b/PyInstaller/lib/modulegraph/util.py\n@@ -136,7 +136,9 @@\n     Yields `dis.Instruction`. After each code-block (`co_code`), `None` is\n     yielded to mark the end of the block and to interrupt the steam.\n     \"\"\"\n-    yield from get_instructions(code_object)\n+    # The arg extension the EXTENDED_ARG opcode represents is automatically handled by get_instructions() but the\n+    # instruction is left in. Get rid of it to make subsequent parsing easier/safer.\n+    yield from (i for i in get_instructions(code_object) if i.opname != \"EXTENDED_ARG\")\n \n     yield None\n", "issue": "AssertionError when using PyInstaller. Fixed when following line is commented in modulegraph.py: assert prev_insts[-2].opname == 'LOAD_CONST'\n<!--\r\nWelcome to the PyInstaller issue tracker! Before creating an issue, please heed the following:\r\n\r\n1. This tracker should only be used to report bugs and request features / enhancements to PyInstaller\r\n    - For questions and general support, use the mailing list, see\r\n\t  <http://www.pyinstaller.org/support.html#mailing-list>\r\n2. Use the search function before creating a new issue. Duplicates will be closed and directed to\r\n   the original discussion.\r\n3. When making a bug report, make sure you provide all required information. The easier it is for\r\n   maintainers to reproduce, the faster it'll be fixed.\r\n-->\r\n\r\n<!-- +++ ONLY TEXT +++ DO NOT POST IMAGES +++ -->\r\n\r\nThe following was posted on the google groups discussion and was suggested by @Legorooj to post it here:\r\n\r\nPyInstaller version: 4.10\r\nVersion of Python: 3.6.8\r\nPlatform: Windows 10\r\nPython installed from: [python.org](http://python.org/)\r\nDidn't try on another platform.\r\nWill try development version if necessary.\r\n\r\nClean installation.\r\nRan program from command window\r\nUsed --onedir mode\r\n\r\nError:\r\n```\\site-packages\\PyInstaller\\lib\\modulegraph\\modulegraph.py, line 2771, in _scan_bytecode()`\r\n    assert prev_insts[-2].opname == 'LOAD_CONST'\r\nAssertionError```\r\n\r\nCommand line used: `pyinstaller -F --clean --paths {paths --collect-all {name1} --collect-all {name2} script.py`\r\n\r\n### Quick overview\r\nThe problem arises when using `.pyc` files for the modules in `name1` and `name2`.\r\nThe problem does not occur when I comment out [this](https://github.com/pyinstaller/pyinstaller/blob/3ea48fd875e786ecbb3c160209791aa11d55ae99/PyInstaller/lib/modulegraph/modulegraph.py#L2764) line in modulegraph.py.\r\nWhen I run pyinstaller without line 2764 (linked above), everything runs to completion and the executable generated works as intended.\r\nI've been trying to look through previous commits to try and understand the reason for the assert statement and why it is necessary. Could it perhaps no longer be necessary?\r\n\r\nRoot cause: `The prev_insts[-2].opname` variable is equal to `EXTENDED_ARG` thus causing the assert statement to fail.\r\n\r\nThere's been a few issues before related to `EXTENDED_ARG` (but not my exact problem) as well as commits.\r\n\r\n- [Link](https://github.com/pyinstaller/pyinstaller/pull/5830)\r\n- [Link](https://github.com/pyinstaller/pyinstaller/issues/6301#issuecomment-962519524)\r\n- And this [link](https://github.com/pyinstaller/pyinstaller/commit/ed732c92eded85e6bca4232eedefee2906bbfa52) seems to be the commit for the first variation of the LOAD_CONST assert but it's not clear to me why it's there.\r\n\r\nBased on what I found in PyInstaller's current [bytecode.py](https://github.com/pyinstaller/pyinstaller/blob/1e6a8d53f150cf24b574c32085f3745cbd2afaa6/PyInstaller/depend/bytecode.py#L13), it seems like it might need to be expanded on:\r\n\r\n> The biggest clarity killer here is the ``EXTENDED_ARG`` opcode which can appear almost anywhere and therefore needs to be tiptoed around at every step. If this code needs to expand significantly, I would recommend an upgrade to a regex-based grammar parsing library such as Reparse. This way, little steps like unpacking ``EXTENDED_ARGS`` can be defined once then simply referenced forming a nice hierarchy rather than copied everywhere its needed.\r\n\r\n\r\nCould you please provide some information about why this type of opcode requires an exception to be thrown and why PyInstaller works when the assertion is removed? Or just confirm with me whether or not it is safe for me to continue on with the line removed? Or even just a way to avoid running into this exception?\r\n\r\n[Reference](https://docs.python.org/3/library/dis.html?highlight=load_const#opcode-LOAD_CONST) to extended_arg from dis.py.\r\n\r\nThank you,\r\n\r\nEduardo\n", "before_files": [{"content": "\n# Filter DeprecationWarnings until the code has been revised\nimport warnings\nwarnings.filterwarnings(\"ignore\", \"the imp module is deprecated in\")\nwarnings.filterwarnings(\"ignore\", \"imp_walk will be removed in a future\")\n\nimport os\nimport imp\nimport sys\nimport re\nimport marshal\nimport warnings\nimport inspect\n\ntry:\n    unicode\nexcept NameError:\n    unicode = str\n\nfrom ._compat import StringIO, BytesIO, get_instructions, _READ_MODE\n\n\ndef imp_find_module(name, path=None):\n    \"\"\"\n    same as imp.find_module, but handles dotted names\n    \"\"\"\n    names = name.split('.')\n    if path is not None:\n        if isinstance(path, (str, unicode)):\n            path = [os.path.realpath(path)]\n    for name in names:\n        result = imp.find_module(name, path)\n        if result[0] is not None:\n            result[0].close()\n        path = [result[1]]\n    return result\n\n\ndef _check_importer_for_path(name, path_item):\n    try:\n        importer = sys.path_importer_cache[path_item]\n    except KeyError:\n        for path_hook in sys.path_hooks:\n            try:\n                importer = path_hook(path_item)\n                break\n            except ImportError:\n                pass\n        else:\n            importer = None\n        sys.path_importer_cache.setdefault(path_item, importer)\n\n    if importer is None:\n        try:\n            return imp.find_module(name, [path_item])\n        except ImportError:\n            return None\n    return importer.find_module(name)\n\n\ndef imp_walk(name):\n    \"\"\"\n    yields namepart, tuple_or_importer for each path item\n\n    raise ImportError if a name can not be found.\n    \"\"\"\n    warnings.warn(\n        \"imp_walk will be removed in a future version\",\n        DeprecationWarning)\n\n    if name in sys.builtin_module_names:\n        yield name, (None, None, (\"\", \"\", imp.C_BUILTIN))\n        return\n    paths = sys.path\n    res = None\n    for namepart in name.split('.'):\n        for path_item in paths:\n            res = _check_importer_for_path(namepart, path_item)\n            if hasattr(res, 'load_module'):\n                if res.path.endswith('.py') or res.path.endswith('.pyw'):\n                    fp = StringIO(res.get_source(namepart))\n                    res = (fp, res.path, ('.py', _READ_MODE, imp.PY_SOURCE))\n                elif res.path.endswith('.pyc') or res.path.endswith('.pyo'):\n                    co = res.get_code(namepart)\n                    fp = BytesIO(\n                        imp.get_magic() + b'\\0\\0\\0\\0' + marshal.dumps(co))\n                    res = (fp, res.path, ('.pyc', 'rb', imp.PY_COMPILED))\n\n                else:\n                    res = (\n                        None,\n                        res.path,\n                        (\n                            os.path.splitext(res.path)[-1],\n                            'rb',\n                            imp.C_EXTENSION\n                        )\n                    )\n\n                break\n            elif isinstance(res, tuple):\n                break\n        else:\n            break\n\n        yield namepart, res\n        paths = [os.path.join(path_item, namepart)]\n    else:\n        return\n\n    raise ImportError('No module named %s' % (name,))\n\n\ncookie_re = re.compile(br\"coding[:=]\\s*([-\\w.]+)\")\nif sys.version_info[0] == 2:\n    default_encoding = 'ascii'\nelse:\n    default_encoding = 'utf-8'\n\n\ndef guess_encoding(fp):\n\n    for i in range(2):\n        ln = fp.readline()\n\n        m = cookie_re.search(ln)\n        if m is not None:\n            return m.group(1).decode('ascii')\n\n    return default_encoding\n\n\ndef iterate_instructions(code_object):\n    \"\"\"Delivers the byte-code instructions as a continuous stream.\n\n    Yields `dis.Instruction`. After each code-block (`co_code`), `None` is\n    yielded to mark the end of the block and to interrupt the steam.\n    \"\"\"\n    yield from get_instructions(code_object)\n\n    yield None\n\n    # For each constant in this code object that is itself a code object,\n    # parse this constant in the same manner.\n    for constant in code_object.co_consts:\n        if inspect.iscode(constant):\n            yield from iterate_instructions(constant)\n", "path": "PyInstaller/lib/modulegraph/util.py"}], "after_files": [{"content": "\n# Filter DeprecationWarnings until the code has been revised\nimport warnings\nwarnings.filterwarnings(\"ignore\", \"the imp module is deprecated in\")\nwarnings.filterwarnings(\"ignore\", \"imp_walk will be removed in a future\")\n\nimport os\nimport imp\nimport sys\nimport re\nimport marshal\nimport warnings\nimport inspect\n\ntry:\n    unicode\nexcept NameError:\n    unicode = str\n\nfrom ._compat import StringIO, BytesIO, get_instructions, _READ_MODE\n\n\ndef imp_find_module(name, path=None):\n    \"\"\"\n    same as imp.find_module, but handles dotted names\n    \"\"\"\n    names = name.split('.')\n    if path is not None:\n        if isinstance(path, (str, unicode)):\n            path = [os.path.realpath(path)]\n    for name in names:\n        result = imp.find_module(name, path)\n        if result[0] is not None:\n            result[0].close()\n        path = [result[1]]\n    return result\n\n\ndef _check_importer_for_path(name, path_item):\n    try:\n        importer = sys.path_importer_cache[path_item]\n    except KeyError:\n        for path_hook in sys.path_hooks:\n            try:\n                importer = path_hook(path_item)\n                break\n            except ImportError:\n                pass\n        else:\n            importer = None\n        sys.path_importer_cache.setdefault(path_item, importer)\n\n    if importer is None:\n        try:\n            return imp.find_module(name, [path_item])\n        except ImportError:\n            return None\n    return importer.find_module(name)\n\n\ndef imp_walk(name):\n    \"\"\"\n    yields namepart, tuple_or_importer for each path item\n\n    raise ImportError if a name can not be found.\n    \"\"\"\n    warnings.warn(\n        \"imp_walk will be removed in a future version\",\n        DeprecationWarning)\n\n    if name in sys.builtin_module_names:\n        yield name, (None, None, (\"\", \"\", imp.C_BUILTIN))\n        return\n    paths = sys.path\n    res = None\n    for namepart in name.split('.'):\n        for path_item in paths:\n            res = _check_importer_for_path(namepart, path_item)\n            if hasattr(res, 'load_module'):\n                if res.path.endswith('.py') or res.path.endswith('.pyw'):\n                    fp = StringIO(res.get_source(namepart))\n                    res = (fp, res.path, ('.py', _READ_MODE, imp.PY_SOURCE))\n                elif res.path.endswith('.pyc') or res.path.endswith('.pyo'):\n                    co = res.get_code(namepart)\n                    fp = BytesIO(\n                        imp.get_magic() + b'\\0\\0\\0\\0' + marshal.dumps(co))\n                    res = (fp, res.path, ('.pyc', 'rb', imp.PY_COMPILED))\n\n                else:\n                    res = (\n                        None,\n                        res.path,\n                        (\n                            os.path.splitext(res.path)[-1],\n                            'rb',\n                            imp.C_EXTENSION\n                        )\n                    )\n\n                break\n            elif isinstance(res, tuple):\n                break\n        else:\n            break\n\n        yield namepart, res\n        paths = [os.path.join(path_item, namepart)]\n    else:\n        return\n\n    raise ImportError('No module named %s' % (name,))\n\n\ncookie_re = re.compile(br\"coding[:=]\\s*([-\\w.]+)\")\nif sys.version_info[0] == 2:\n    default_encoding = 'ascii'\nelse:\n    default_encoding = 'utf-8'\n\n\ndef guess_encoding(fp):\n\n    for i in range(2):\n        ln = fp.readline()\n\n        m = cookie_re.search(ln)\n        if m is not None:\n            return m.group(1).decode('ascii')\n\n    return default_encoding\n\n\ndef iterate_instructions(code_object):\n    \"\"\"Delivers the byte-code instructions as a continuous stream.\n\n    Yields `dis.Instruction`. After each code-block (`co_code`), `None` is\n    yielded to mark the end of the block and to interrupt the steam.\n    \"\"\"\n    # The arg extension the EXTENDED_ARG opcode represents is automatically handled by get_instructions() but the\n    # instruction is left in. Get rid of it to make subsequent parsing easier/safer.\n    yield from (i for i in get_instructions(code_object) if i.opname != \"EXTENDED_ARG\")\n\n    yield None\n\n    # For each constant in this code object that is itself a code object,\n    # parse this constant in the same manner.\n    for constant in code_object.co_consts:\n        if inspect.iscode(constant):\n            yield from iterate_instructions(constant)\n", "path": "PyInstaller/lib/modulegraph/util.py"}]}