Repository: nvaccess/nvda

Issue:
Update to py2exe 0.10.2.0 or later
### Is your feature request related to a problem? Please describe.
Currently we;re using py2exe 0.10.1.0. While it is okay for now as we are stuck on Python 3.7 as soon as we need to upgrade to Python 3.10 or later we would need to move to the newer version of py2exe. Unfortunately it is impossible to freeze NVDA with any version newer than 0.10.1.0. The  traceback (taken with 0.10.4.0 so the most recent version at the time of this writing) is as follows:
```
call py -m SCons launcher
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
<lambda>(["dist"], ["source", "user_docs"])
cd source && D:\testmiscdeps\nvda\.venv\Scripts\python.exe -bb setup.py -vv build --build-base D:\testmiscdeps\nvda\build py2exe --dist-dir D:\testmiscdeps\nvda\dist
D:\testmiscdeps\nvda\.venv\lib\site-packages\setuptools\dist.py:472: UserWarning: The version specified ('source-master-f392c23') is an invalid version, this may not work as expected with newer
versions of setuptools, pip, and PyPI. Please see PEP 440 for more details.
  "details." % version
running build
running py2exe
Traceback (most recent call last):
  File "setup.py", line 284, in <module>
    + getRecursiveDataFiles('documentation', '../user_docs', excludes=('*.t2t', '*.t2tconf', '*/developerGuide.*'))
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\setuptools\__init__.py", line 144, in setup
    return distutils.core.setup(**attrs)
  File "C:\Python37\lib\distutils\core.py", line 148, in setup
    dist.run_commands()
  File "C:\Python37\lib\distutils\dist.py", line 966, in run_commands
    self.run_command(cmd)
  File "C:\Python37\lib\distutils\dist.py", line 985, in run_command
    cmd_obj.run()
  File "setup.py", line 114, in run
    super(py2exe, self).run()
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\distutils_buildexe.py", line 192, in run
    self._run()
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\distutils_buildexe.py", line 272, in _run
    builder.analyze()
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\runtime.py", line 172, in analyze
    mf.import_package(modname)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 68, in import_package
    self.safe_import_hook(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 122, in safe_import_hook
    self.import_hook(name, caller, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 104, in import_hook
    module = self._gcd_import(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 258, in _gcd_import
    return self._find_and_load(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 348, in _find_and_load
    self._scan_code(module.__code__, module)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 386, in _scan_code
    self.safe_import_hook(name, mod, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 122, in safe_import_hook
    self.import_hook(name, caller, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 104, in import_hook
    module = self._gcd_import(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 258, in _gcd_import
    return self._find_and_load(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 348, in _find_and_load
    self._scan_code(module.__code__, module)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 393, in _scan_code
    self._scan_code(c, mod)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 393, in _scan_code
    self._scan_code(c, mod)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 386, in _scan_code
    self.safe_import_hook(name, mod, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 122, in safe_import_hook
    self.import_hook(name, caller, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 104, in import_hook
    module = self._gcd_import(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 258, in _gcd_import
    return self._find_and_load(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 348, in _find_and_load
    self._scan_code(module.__code__, module)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 386, in _scan_code
    self.safe_import_hook(name, mod, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 122, in safe_import_hook
    self.import_hook(name, caller, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 104, in import_hook
    module = self._gcd_import(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 258, in _gcd_import
    return self._find_and_load(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 348, in _find_and_load
    self._scan_code(module.__code__, module)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 386, in _scan_code
    self.safe_import_hook(name, mod, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 122, in safe_import_hook
    self.import_hook(name, caller, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 104, in import_hook
    module = self._gcd_import(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 258, in _gcd_import
    return self._find_and_load(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 348, in _find_and_load
    self._scan_code(module.__code__, module)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 386, in _scan_code
    self.safe_import_hook(name, mod, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 122, in safe_import_hook
    self.import_hook(name, caller, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 104, in import_hook
    module = self._gcd_import(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 258, in _gcd_import
    return self._find_and_load(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 348, in _find_and_load
    self._scan_code(module.__code__, module)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 386, in _scan_code
    self.safe_import_hook(name, mod, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 122, in safe_import_hook
    self.import_hook(name, caller, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 104, in import_hook
    module = self._gcd_import(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 258, in _gcd_import
    return self._find_and_load(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 348, in _find_and_load
    self._scan_code(module.__code__, module)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 393, in _scan_code
    self._scan_code(c, mod)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 393, in _scan_code
    self._scan_code(c, mod)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 386, in _scan_code
    self.safe_import_hook(name, mod, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 122, in safe_import_hook
    self.import_hook(name, caller, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 104, in import_hook
    module = self._gcd_import(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 258, in _gcd_import
    return self._find_and_load(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 348, in _find_and_load
    self._scan_code(module.__code__, module)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 386, in _scan_code
    self.safe_import_hook(name, mod, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 122, in safe_import_hook
    self.import_hook(name, caller, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 104, in import_hook
    module = self._gcd_import(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 258, in _gcd_import
    return self._find_and_load(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 348, in _find_and_load
    self._scan_code(module.__code__, module)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 386, in _scan_code
    self.safe_import_hook(name, mod, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 122, in safe_import_hook
    self.import_hook(name, caller, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 104, in import_hook
    module = self._gcd_import(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 258, in _gcd_import
    return self._find_and_load(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 348, in _find_and_load
    self._scan_code(module.__code__, module)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 386, in _scan_code
    self.safe_import_hook(name, mod, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 122, in safe_import_hook
    self.import_hook(name, caller, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 104, in import_hook
    module = self._gcd_import(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 258, in _gcd_import
    return self._find_and_load(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 348, in _find_and_load
    self._scan_code(module.__code__, module)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 386, in _scan_code
    self.safe_import_hook(name, mod, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 122, in safe_import_hook
    self.import_hook(name, caller, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 104, in import_hook
    module = self._gcd_import(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 258, in _gcd_import
    return self._find_and_load(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 348, in _find_and_load
    self._scan_code(module.__code__, module)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 393, in _scan_code
    self._scan_code(c, mod)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 386, in _scan_code
    self.safe_import_hook(name, mod, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 122, in safe_import_hook
    self.import_hook(name, caller, fromlist, level)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 104, in import_hook
    module = self._gcd_import(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 258, in _gcd_import
    return self._find_and_load(name)
  File "D:\testmiscdeps\nvda\.venv\lib\site-packages\py2exe\mf34.py", line 303, in _find_and_load
    spec = importlib.util.find_spec(name, path)
  File "C:\Python37\lib\importlib\util.py", line 94, in find_spec
    parent = __import__(parent_name, fromlist=['__path__'])
  File "D:\testmiscdeps\nvda\source\speech\__init__.py", line 15, in <module>
    import colors
  File "D:\testmiscdeps\nvda\source\colors.py", line 121, in <module>
    100:pgettext('color hue','white'),
NameError: name 'pgettext' is not defined
scons: *** [dist] Error 1
scons: building terminated because of errors.
Deactivating NVDA Python virtual environment

```

### Describe the solution you'd like
We should investigate how to  update the more recent version as soon as possible as to avoid being blocked on this during migration to a more recent version of Python. I haven't yet opened an issue against py2exe repository as I'd like to create a MWE reproducing this issue first.


### Describe alternatives you've considered
- Instead  of fixing this in py2exe we may consider refactoring our source to avoid these warnings. In some cases it is possible - I've started working on it but it quickly becomes rather ugly so I consider this to be a last resort.
- We may consider switching to an alternative package for freezing.

### Additional context
None


Discussion:
I think it makes sense to take this for 2022.1 as soon as a new version of Scons post 4.2.0 comes out, which will support Visual Studio 2022.
Contrary to my initial belief this cannot be worked around in our sources. Annoyingly I haven't managed to create a isolated test case which can be submitted to Py2exe developer plus their repo is very low activity.

> 
> 
> I think it makes sense to take this for 2022.1 

I agree that makes sense - would you be able to look into it - you're way more familiar with py2exe's code base?

> as soon as a new version of Scons post 4.2.0 comes out, which will support Visual Studio 2022.

These two problems  are completely independent issues and should be handled separately - nothing stops us from updating to more recent Scons though VS 2022 is a  different matter all together.

I've managed to create a minimal reproducer and reported the bug as https://github.com/py2exe/py2exe/issues/112
I've reproduced the issue and reported it as https://github.com/py2exe/py2exe/issues/113

Resolving patch:
diff --git a/source/setup.py b/source/setup.py
--- a/source/setup.py
+++ b/source/setup.py
@@ -234,6 +234,12 @@ def getRecursiveDataFiles(dest,source,excludes=()):
 		],
 		"packages": [
 			"NVDAObjects",
+			# As of py2exe 0.11.0.0 if the forcibly included package contains subpackages
+			# they need to be listed explicitly (py2exe issue 113).
+			"NVDAObjects.IAccessible",
+			"NVDAObjects.JAB",
+			"NVDAObjects.UIA",
+			"NVDAObjects.window",
 			"virtualBuffers",
 			"appModules",
 			"comInterfaces",


Test patch: