Nuitka-winsvc 1.8.6__cp312-cp312-win_amd64.whl → 1.9.3__cp312-cp312-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. {Nuitka_winsvc-1.8.6.dist-info → Nuitka_winsvc-1.9.3.dist-info}/METADATA +1 -1
  2. {Nuitka_winsvc-1.8.6.dist-info → Nuitka_winsvc-1.9.3.dist-info}/RECORD +212 -203
  3. {Nuitka_winsvc-1.8.6.dist-info → Nuitka_winsvc-1.9.3.dist-info}/WHEEL +1 -1
  4. nuitka/BytecodeCaching.py +4 -1
  5. nuitka/HardImportRegistry.py +348 -0
  6. nuitka/MainControl.py +45 -25
  7. nuitka/OptionParsing.py +31 -20
  8. nuitka/Options.py +47 -16
  9. nuitka/Progress.py +32 -2
  10. nuitka/PythonFlavors.py +1 -1
  11. nuitka/PythonVersions.py +61 -0
  12. nuitka/Tracing.py +25 -12
  13. nuitka/TreeXML.py +5 -5
  14. nuitka/Variables.py +15 -24
  15. nuitka/Version.py +16 -6
  16. nuitka/__main__.py +15 -0
  17. nuitka/__past__.py +15 -17
  18. nuitka/build/Backend.scons +44 -35
  19. nuitka/build/CCompilerVersion.scons +10 -9
  20. nuitka/build/Onefile.scons +11 -26
  21. nuitka/build/SconsCaching.py +2 -0
  22. nuitka/build/SconsCompilerSettings.py +72 -22
  23. nuitka/build/SconsHacks.py +1 -0
  24. nuitka/build/SconsInterface.py +5 -0
  25. nuitka/build/SconsSpawn.py +16 -3
  26. nuitka/build/SconsUtils.py +11 -12
  27. nuitka/build/include/nuitka/checksum_tools.h +0 -4
  28. nuitka/build/include/nuitka/compiled_asyncgen.h +1 -1
  29. nuitka/build/include/nuitka/compiled_coroutine.h +1 -1
  30. nuitka/build/include/nuitka/compiled_frame.h +7 -4
  31. nuitka/build/include/nuitka/compiled_function.h +13 -3
  32. nuitka/build/include/nuitka/compiled_generator.h +1 -1
  33. nuitka/build/include/nuitka/constants.h +2 -0
  34. nuitka/build/include/nuitka/environment_variables.h +45 -0
  35. nuitka/build/include/nuitka/exceptions.h +32 -4
  36. nuitka/build/include/nuitka/filesystem_paths.h +6 -1
  37. nuitka/build/include/nuitka/freelists.h +11 -1
  38. nuitka/build/include/nuitka/helper/dictionaries.h +1 -1
  39. nuitka/build/include/nuitka/helper/import_hard.h +3 -0
  40. nuitka/build/include/nuitka/helpers.h +2 -0
  41. nuitka/build/include/nuitka/importing.h +3 -0
  42. nuitka/build/include/nuitka/prelude.h +17 -6
  43. nuitka/build/include/nuitka/unfreezing.h +1 -1
  44. nuitka/build/inline_copy/bin/scons.py +14 -0
  45. nuitka/build/inline_copy/tqdm/tqdm/__init__.py +2 -2
  46. nuitka/build/inline_copy/tqdm/tqdm/utils.py +14 -8
  47. nuitka/build/inline_copy/zlib/LICENSE +22 -0
  48. nuitka/build/inline_copy/zlib/crc32.c +1049 -0
  49. nuitka/build/inline_copy/zlib/crc32.h +9446 -0
  50. nuitka/build/inline_copy/zlib/zconf.h +551 -0
  51. nuitka/build/inline_copy/zlib/zlib.h +1938 -0
  52. nuitka/build/inline_copy/zlib/zutil.h +275 -0
  53. nuitka/build/static_src/CompiledAsyncgenType.c +41 -41
  54. nuitka/build/static_src/CompiledCodeHelpers.c +14 -7
  55. nuitka/build/static_src/CompiledCoroutineType.c +60 -51
  56. nuitka/build/static_src/CompiledFrameType.c +12 -12
  57. nuitka/build/static_src/CompiledFunctionType.c +149 -28
  58. nuitka/build/static_src/CompiledGeneratorType.c +64 -65
  59. nuitka/build/static_src/CompiledGeneratorTypeUncompiledIntegration.c +1 -1
  60. nuitka/build/static_src/CompiledMethodType.c +5 -3
  61. nuitka/build/static_src/HelperEnvironmentVariables.c +120 -0
  62. nuitka/build/static_src/HelpersAttributes.c +1 -1
  63. nuitka/build/static_src/HelpersBuiltin.c +1 -1
  64. nuitka/build/static_src/HelpersChecksumTools.c +19 -4
  65. nuitka/build/static_src/HelpersComparisonEq.c +4 -4
  66. nuitka/build/static_src/HelpersComparisonNe.c +4 -4
  67. nuitka/build/static_src/HelpersConstantsBlob.c +40 -23
  68. nuitka/build/static_src/HelpersDictionaries.c +3 -1
  69. nuitka/build/static_src/HelpersDictionariesGenerated.c +9 -9
  70. nuitka/build/static_src/HelpersFilesystemPaths.c +12 -2
  71. nuitka/build/static_src/HelpersImport.c +29 -1
  72. nuitka/build/static_src/HelpersImportHard.c +19 -0
  73. nuitka/build/static_src/HelpersOperationInplaceAddUtils.c +5 -4
  74. nuitka/build/static_src/HelpersPythonPgo.c +5 -5
  75. nuitka/build/static_src/HelpersSafeStrings.c +2 -1
  76. nuitka/build/static_src/HelpersStrings.c +12 -10
  77. nuitka/build/static_src/HelpersTypes.c +1 -1
  78. nuitka/build/static_src/InspectPatcher.c +3 -2
  79. nuitka/build/static_src/MainProgram.c +182 -214
  80. nuitka/build/static_src/MetaPathBasedLoader.c +36 -23
  81. nuitka/build/static_src/MetaPathBasedLoaderImportlibMetadataDistribution.c +4 -2
  82. nuitka/build/static_src/MetaPathBasedLoaderResourceReaderFiles.c +38 -2
  83. nuitka/build/static_src/OnefileBootstrap.c +124 -93
  84. nuitka/code_generation/CodeGeneration.py +4 -2
  85. nuitka/code_generation/CodeObjectCodes.py +5 -1
  86. nuitka/code_generation/ConstantCodes.py +4 -0
  87. nuitka/code_generation/Contexts.py +111 -3
  88. nuitka/code_generation/DictCodes.py +5 -5
  89. nuitka/code_generation/FunctionCodes.py +4 -2
  90. nuitka/code_generation/GlobalConstants.py +10 -0
  91. nuitka/code_generation/ImportCodes.py +69 -33
  92. nuitka/code_generation/ModuleCodes.py +4 -1
  93. nuitka/code_generation/Namify.py +6 -5
  94. nuitka/code_generation/YieldCodes.py +3 -3
  95. nuitka/code_generation/templates/CodeTemplatesModules.py +61 -95
  96. nuitka/code_generation/templates_c/HelperDictionaryCopy.c.j2 +3 -3
  97. nuitka/code_generation/templates_c/HelperOperationComparisonUnicode.c.j2 +2 -2
  98. nuitka/distutils/DistutilCommands.py +3 -0
  99. nuitka/finalizations/FinalizeMarkups.py +1 -1
  100. nuitka/freezer/DependsExe.py +2 -1
  101. nuitka/freezer/DllDependenciesPosix.py +11 -1
  102. nuitka/freezer/IncludedEntryPoints.py +54 -16
  103. nuitka/freezer/Onefile.py +7 -3
  104. nuitka/freezer/Standalone.py +39 -17
  105. nuitka/importing/Importing.py +195 -62
  106. nuitka/importing/PreloadedPackages.py +2 -1
  107. nuitka/importing/Recursion.py +98 -27
  108. nuitka/importing/StandardLibrary.py +7 -4
  109. nuitka/nodes/BuiltinOpenNodes.py +28 -1
  110. nuitka/nodes/BuiltinRangeNodes.py +2 -2
  111. nuitka/nodes/BuiltinSumNodes.py +1 -1
  112. nuitka/nodes/ChildrenHavingMixins.py +326 -2
  113. nuitka/nodes/HardImportNodesGenerated.py +141 -38
  114. nuitka/nodes/ImportHardNodes.py +0 -8
  115. nuitka/nodes/ImportNodes.py +267 -361
  116. nuitka/nodes/IterationHandles.py +36 -17
  117. nuitka/nodes/LocalsScopes.py +3 -1
  118. nuitka/nodes/NodeBases.py +8 -14
  119. nuitka/nodes/OperatorNodes.py +9 -9
  120. nuitka/nodes/OutlineNodes.py +3 -3
  121. nuitka/nodes/PackageMetadataNodes.py +19 -9
  122. nuitka/nodes/SliceNodes.py +1 -1
  123. nuitka/nodes/VariableAssignNodes.py +25 -15
  124. nuitka/nodes/VariableRefNodes.py +7 -7
  125. nuitka/nodes/YieldNodes.py +2 -2
  126. nuitka/nodes/shapes/BuiltinTypeShapes.py +81 -6
  127. nuitka/nodes/shapes/ShapeMixins.py +21 -0
  128. nuitka/nodes/shapes/StandardShapes.py +9 -3
  129. nuitka/optimizations/OptimizeBuiltinCalls.py +1 -1
  130. nuitka/optimizations/TraceCollections.py +75 -0
  131. nuitka/pgo/PGO.py +14 -6
  132. nuitka/plugins/PluginBase.py +83 -11
  133. nuitka/plugins/Plugins.py +78 -35
  134. nuitka/plugins/standard/AntiBloatPlugin.py +46 -1
  135. nuitka/plugins/standard/ConsiderPyLintAnnotationsPlugin.py +1 -1
  136. nuitka/plugins/standard/DelvewheelPlugin.py +2 -1
  137. nuitka/plugins/standard/DillPlugin.py +3 -99
  138. nuitka/plugins/standard/DllFilesPlugin.py +45 -0
  139. nuitka/plugins/standard/GiPlugin.py +23 -10
  140. nuitka/plugins/standard/GlfwPlugin.py +1 -0
  141. nuitka/plugins/standard/ImplicitImports.py +267 -15
  142. nuitka/plugins/standard/KivyPlugin.py +1 -0
  143. nuitka/plugins/standard/MatplotlibPlugin.py +43 -25
  144. nuitka/plugins/standard/OptionsNannyPlugin.py +5 -6
  145. nuitka/plugins/standard/PkgResourcesPlugin.py +1 -1
  146. nuitka/plugins/standard/PmwPlugin.py +1 -1
  147. nuitka/plugins/standard/PySidePyQtPlugin.py +37 -20
  148. nuitka/plugins/standard/TkinterPlugin.py +44 -30
  149. nuitka/plugins/standard/TransformersPlugin.py +3 -1
  150. nuitka/plugins/standard/standard.nuitka-package.config.yml +522 -86
  151. nuitka/plugins/standard/stdlib3.nuitka-package.config.yml +8 -1
  152. nuitka/reports/CompilationReportReader.py +53 -0
  153. nuitka/reports/LicenseReport.rst.j2 +4 -4
  154. nuitka/reports/Reports.py +129 -47
  155. nuitka/specs/HardImportSpecs.py +6 -0
  156. nuitka/tools/data_composer/DataComposer.py +29 -17
  157. nuitka/tools/onefile_compressor/OnefileCompressor.py +173 -110
  158. nuitka/tools/podman/__main__.py +17 -2
  159. nuitka/tools/scanning/DisplayPackageDLLs.py +11 -2
  160. nuitka/tools/scanning/DisplayPackageData.py +1 -1
  161. nuitka/tools/specialize/CTypeDescriptions.py +36 -27
  162. nuitka/tools/specialize/SpecializeC.py +1 -1
  163. nuitka/tools/specialize/SpecializePython.py +16 -0
  164. nuitka/tools/testing/Common.py +3 -4
  165. nuitka/tools/testing/OutputComparison.py +23 -0
  166. nuitka/tools/testing/SearchModes.py +2 -2
  167. nuitka/tools/testing/compare_with_cpython/__main__.py +13 -4
  168. nuitka/tools/testing/measure_construct_performance/__main__.py +2 -5
  169. nuitka/tools/watch/__main__.py +194 -56
  170. nuitka/tree/Building.py +8 -2
  171. nuitka/tree/ComplexCallHelperFunctions.py +45 -15
  172. nuitka/tree/ReformulationAssignmentStatements.py +18 -12
  173. nuitka/tree/ReformulationCallExpressions.py +1 -1
  174. nuitka/tree/ReformulationClasses.py +11 -5
  175. nuitka/tree/ReformulationClasses3.py +30 -12
  176. nuitka/tree/ReformulationComparisonExpressions.py +4 -2
  177. nuitka/tree/ReformulationContractionExpressions.py +19 -11
  178. nuitka/tree/ReformulationDictionaryCreation.py +9 -3
  179. nuitka/tree/ReformulationExecStatements.py +6 -6
  180. nuitka/tree/ReformulationForLoopStatements.py +5 -5
  181. nuitka/tree/ReformulationFunctionStatements.py +6 -2
  182. nuitka/tree/ReformulationImportStatements.py +7 -2
  183. nuitka/tree/ReformulationLambdaExpressions.py +1 -1
  184. nuitka/tree/ReformulationMatchStatements.py +3 -1
  185. nuitka/tree/ReformulationNamespacePackages.py +7 -3
  186. nuitka/tree/ReformulationPrintStatements.py +1 -1
  187. nuitka/tree/ReformulationSequenceCreation.py +18 -6
  188. nuitka/tree/ReformulationWithStatements.py +8 -8
  189. nuitka/tree/ReformulationYieldExpressions.py +2 -2
  190. nuitka/tree/SourceHandling.py +27 -5
  191. nuitka/tree/VariableClosure.py +11 -1
  192. nuitka/utils/AppDirs.py +2 -2
  193. nuitka/utils/CStrings.py +39 -3
  194. nuitka/utils/CommandLineOptions.py +42 -1
  195. nuitka/utils/Distributions.py +305 -38
  196. nuitka/utils/Download.py +27 -8
  197. nuitka/utils/FileOperations.py +103 -20
  198. nuitka/utils/Hashing.py +2 -3
  199. nuitka/utils/Importing.py +60 -3
  200. nuitka/utils/InstalledPythons.py +31 -36
  201. nuitka/utils/Jinja2.py +11 -5
  202. nuitka/utils/ModuleNames.py +11 -3
  203. nuitka/utils/ReExecute.py +7 -0
  204. nuitka/utils/SharedLibraries.py +38 -14
  205. nuitka/utils/SlotMetaClasses.py +55 -0
  206. nuitka/utils/Utils.py +10 -0
  207. nuitka/utils/Yaml.py +9 -1
  208. nuitka/build/inline_copy/tqdm/tqdm/_tqdm_gui.py +0 -9
  209. nuitka/build/inline_copy/tqdm/tqdm/gui.py +0 -191
  210. {Nuitka_winsvc-1.8.6.data → Nuitka_winsvc-1.9.3.data}/scripts/nuitka-run.bat +0 -0
  211. {Nuitka_winsvc-1.8.6.data → Nuitka_winsvc-1.9.3.data}/scripts/nuitka.bat +0 -0
  212. {Nuitka_winsvc-1.8.6.dist-info → Nuitka_winsvc-1.9.3.dist-info}/LICENSE.txt +0 -0
  213. {Nuitka_winsvc-1.8.6.dist-info → Nuitka_winsvc-1.9.3.dist-info}/entry_points.txt +0 -0
  214. {Nuitka_winsvc-1.8.6.dist-info → Nuitka_winsvc-1.9.3.dist-info}/top_level.txt +0 -0
@@ -29,6 +29,11 @@ import sys
29
29
  from nuitka.Options import isStandaloneMode
30
30
  from nuitka.plugins.PluginBase import NuitkaPluginBase
31
31
  from nuitka.PythonVersions import python_version
32
+ from nuitka.utils.Distributions import (
33
+ getDistributionFromModuleName,
34
+ getDistributionName,
35
+ isDistributionSystemPackage,
36
+ )
32
37
  from nuitka.utils.FileOperations import (
33
38
  listDllFilesFromDirectory,
34
39
  listExeFilesFromDirectory,
@@ -82,6 +87,8 @@ class NuitkaPluginDllFiles(NuitkaPluginBase):
82
87
  exe = dll_config.get("executable", "no") == "yes"
83
88
 
84
89
  suffixes = dll_config.get("suffixes")
90
+ if suffixes is not None:
91
+ suffixes = tuple(suffix.lstrip(".") for suffix in suffixes)
85
92
 
86
93
  for prefix in dll_config.get("prefixes"):
87
94
  if exe:
@@ -96,6 +103,7 @@ class NuitkaPluginDllFiles(NuitkaPluginBase):
96
103
  filename,
97
104
  )
98
105
  ),
106
+ module_name=full_name,
99
107
  package_name=full_name,
100
108
  reason="Yaml config of '%s'" % full_name.asString(),
101
109
  )
@@ -111,6 +119,7 @@ class NuitkaPluginDllFiles(NuitkaPluginBase):
111
119
  filename,
112
120
  )
113
121
  ),
122
+ module_name=full_name,
114
123
  package_name=full_name,
115
124
  reason="Yaml config of '%s'" % full_name.asString(),
116
125
  )
@@ -143,6 +152,7 @@ class NuitkaPluginDllFiles(NuitkaPluginBase):
143
152
  yield self.makeExeEntryPoint(
144
153
  source_path=filename,
145
154
  dest_path=dest_path,
155
+ module_name=full_name,
146
156
  package_name=full_name,
147
157
  reason="Yaml config of '%s'" % full_name.asString(),
148
158
  )
@@ -150,6 +160,7 @@ class NuitkaPluginDllFiles(NuitkaPluginBase):
150
160
  yield self.makeDllEntryPoint(
151
161
  source_path=filename,
152
162
  dest_path=dest_path,
163
+ module_name=full_name,
153
164
  package_name=full_name,
154
165
  reason="Yaml config of '%s'" % full_name.asString(),
155
166
  )
@@ -259,6 +270,7 @@ conditions are missing, or this version of the module needs treatment added."""
259
270
  yield self.makeDllEntryPoint(
260
271
  source_path=uuid_dll_path,
261
272
  dest_path=os.path.basename(uuid_dll_path),
273
+ module_name=full_name,
262
274
  package_name=None,
263
275
  reason="needed by uuid package",
264
276
  )
@@ -271,6 +283,7 @@ conditions are missing, or this version of the module needs treatment added."""
271
283
  yield self.makeDllEntryPoint(
272
284
  source_path=xtwrapper_dll_path,
273
285
  dest_path=os.path.basename(xtwrapper_dll_path),
286
+ module_name=full_name,
274
287
  package_name=None,
275
288
  reason="needed by 'iptc'",
276
289
  )
@@ -280,6 +293,7 @@ conditions are missing, or this version of the module needs treatment added."""
280
293
  module.getCompileTimeDirectory(), "libsecp256k1.dll"
281
294
  ),
282
295
  dest_path=os.path.join(full_name.getPackageName(), "libsecp256k1.dll"),
296
+ module_name=full_name,
283
297
  package_name=full_name.getPackageName(),
284
298
  reason="needed by 'coincurve._libsecp256k1'",
285
299
  )
@@ -333,6 +347,7 @@ conditions are missing, or this version of the module needs treatment added."""
333
347
  yield self.makeDllEntryPoint(
334
348
  source_path=pythoncom_dll_path,
335
349
  dest_path=pythoncom_filename,
350
+ module_name=full_name,
336
351
  package_name=None,
337
352
  reason="needed by '%s'" % full_name.asString(),
338
353
  )
@@ -376,3 +391,33 @@ conditions are missing, or this version of the module needs treatment added."""
376
391
  return True
377
392
 
378
393
  return None
394
+
395
+ def decideAllowOutsideDependencies(self, module_name):
396
+ distribution = None
397
+
398
+ assert module_name != "_ctypes", self.config.get(
399
+ module_name, section="import-hacks"
400
+ )
401
+
402
+ while 1:
403
+ for entry in self.config.get(module_name, section="import-hacks"):
404
+ if self.evaluateCondition(
405
+ full_name=module_name, condition=entry.get("when", "True")
406
+ ):
407
+ if "package-system-dlls" in entry:
408
+ return entry["package-system-dlls"] == "yes"
409
+
410
+ if distribution is None:
411
+ distribution = getDistributionFromModuleName(module_name)
412
+
413
+ module_name = module_name.getPackageName()
414
+ if not module_name:
415
+ break
416
+
417
+ if distribution is None:
418
+ return None
419
+
420
+ if not isDistributionSystemPackage(getDistributionName(distribution)):
421
+ return False
422
+ else:
423
+ return None
@@ -15,7 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
  #
18
- """ Support for gi typelib files
18
+ """ Support for gi typelib files and DLLs
19
19
  """
20
20
  import os
21
21
 
@@ -86,16 +86,29 @@ if not os.environ.get("GI_TYPELIB_PATH"):
86
86
 
87
87
  @standalone_only
88
88
  def getExtraDlls(self, module):
89
- if module.getFullName() == "gi._gi":
90
- gtk_dll_path = self.locateDLL("gtk-3")
91
-
92
- if gtk_dll_path is None:
93
- gtk_dll_path = self.locateDLL("gtk-3-0")
89
+ def tryLocateAndLoad(dll_name):
90
+ # Support various name forms in MSYS2 over time.
91
+ dll_path = self.locateDLL(dll_name)
92
+ if dll_path is None:
93
+ dll_path = self.locateDLL("%s" % dll_name)
94
+ if dll_path is None:
95
+ dll_path = self.locateDLL("lib%s" % dll_name)
94
96
 
95
- if gtk_dll_path is not None:
97
+ if dll_path is not None:
96
98
  yield self.makeDllEntryPoint(
97
- source_path=gtk_dll_path,
98
- dest_path=os.path.basename(gtk_dll_path),
99
- package_name=None,
99
+ source_path=dll_path,
100
+ dest_path=os.path.basename(dll_path),
101
+ module_name="gi._gi",
102
+ package_name="gi",
100
103
  reason="needed by 'gi._gi'",
101
104
  )
105
+
106
+ if module.getFullName() == "gi._gi":
107
+ # TODO: Get local relevant DLL names from GI
108
+ for dll_name in (
109
+ "gtk-3-0",
110
+ "soup-2.4-1",
111
+ "soup-gnome-2.4-1",
112
+ "libsecret-1-0",
113
+ ):
114
+ yield tryLocateAndLoad(dll_name)
@@ -114,6 +114,7 @@ class NuitkaPluginGlfw(NuitkaPluginBase):
114
114
  yield self.makeDllEntryPoint(
115
115
  source_path=dll_filename,
116
116
  dest_path=os.path.join("glfw", os.path.basename(dll_filename)),
117
+ module_name="glfw",
117
118
  package_name="glfw.library",
118
119
  reason="needed by 'glfw'",
119
120
  )
@@ -22,10 +22,13 @@ be told that. This encodes the knowledge we have for various modules. Feel free
22
22
  to add to this and submit patches to make it more complete.
23
23
  """
24
24
 
25
+ import ast
25
26
  import fnmatch
26
27
  import os
27
28
 
28
29
  from nuitka.__past__ import iter_modules
30
+ from nuitka.importing.Importing import locateModule
31
+ from nuitka.importing.Recursion import decideRecursion
29
32
  from nuitka.plugins.PluginBase import NuitkaPluginBase
30
33
  from nuitka.utils.ModuleNames import ModuleName
31
34
  from nuitka.utils.Utils import isMacOS, isWin32Windows
@@ -42,6 +45,8 @@ class NuitkaPluginImplicitImports(NuitkaPluginBase):
42
45
  def __init__(self):
43
46
  self.config = getYamlPackageConfiguration()
44
47
 
48
+ self.lazy_loader_usages = {}
49
+
45
50
  @staticmethod
46
51
  def isAlwaysEnabled():
47
52
  return True
@@ -68,19 +73,22 @@ class NuitkaPluginImplicitImports(NuitkaPluginBase):
68
73
  module_name=ModuleName(current),
69
74
  )
70
75
 
71
- for sub_module in iter_modules([module_filename]):
72
- if not fnmatch.fnmatch(sub_module.name, part):
73
- continue
76
+ if module_filename is not None:
77
+ for sub_module in iter_modules([module_filename]):
78
+ if not fnmatch.fnmatch(sub_module.name, part):
79
+ continue
74
80
 
75
- if count == len(parts) - 1:
76
- yield current.getChildNamed(sub_module.name)
77
- else:
78
- child_name = current.getChildNamed(sub_module.name).asString()
81
+ if count == len(parts) - 1:
82
+ yield current.getChildNamed(sub_module.name)
83
+ else:
84
+ child_name = current.getChildNamed(
85
+ sub_module.name
86
+ ).asString()
79
87
 
80
- for value in self._resolveModulePattern(
81
- child_name + "." + ".".join(parts[count + 1 :])
82
- ):
83
- yield value
88
+ for value in self._resolveModulePattern(
89
+ child_name + "." + ".".join(parts[count + 1 :])
90
+ ):
91
+ yield value
84
92
 
85
93
  return
86
94
  else:
@@ -339,14 +347,18 @@ class NuitkaPluginImplicitImports(NuitkaPluginBase):
339
347
  ):
340
348
  yield item
341
349
 
342
- def onModuleSourceCode(self, module_name, source_code):
350
+ def onModuleSourceCode(self, module_name, source_filename, source_code):
351
+ # Too much code here, pylint: disable=too-many-branches
352
+ # TODO: Move the ones that would be possible to yaml config,
353
+ # e.g. the numexpr hack.
354
+
343
355
  if module_name == "numexpr.cpuinfo":
344
356
  # We cannot intercept "is" tests, but need it to be "isinstance",
345
357
  # so we patch it on the file. TODO: This is only temporary, in
346
358
  # the future, we may use optimization that understands the right
347
359
  # hand size of the "is" argument well enough to allow for our
348
360
  # type too.
349
- return source_code.replace(
361
+ source_code = source_code.replace(
350
362
  "type(attr) is types.MethodType", "isinstance(attr, types.MethodType)"
351
363
  )
352
364
 
@@ -365,11 +377,159 @@ __file__ = (__nuitka_binary_dir + '%ssite.py') if '__nuitka_binary_dir' in dict(
365
377
  "PREFIXES = [sys.prefix, sys.exec_prefix]", "PREFIXES = []"
366
378
  )
367
379
 
368
- return source_code
380
+ # Source code should use lazy_loader, this may not be good enough
381
+ # for all things yet.
382
+ attach_call_replacements = (
383
+ (
384
+ "lazy.attach_stub(__name__, __file__)",
385
+ "lazy.attach('%(module_name)s', %(submodules)s, %(attrs)s)",
386
+ ),
387
+ )
388
+
389
+ for attach_call, attach_call_replacement in attach_call_replacements:
390
+ if attach_call in source_code:
391
+ result = self._handleLazyLoad(
392
+ module_name=module_name,
393
+ source_filename=source_filename,
394
+ )
395
+
396
+ # Inline the values, to avoid the data files.
397
+ if result is not None:
398
+ replacement = attach_call_replacement % {
399
+ "module_name": module_name.asString(),
400
+ "submodules": tuple(
401
+ sub_module_name.asString() for sub_module_name in result[0]
402
+ ),
403
+ "attrs": dict(
404
+ (
405
+ sub_module_name.getChildNameFromPackage(
406
+ module_name
407
+ ).asString(),
408
+ module_attributes,
409
+ )
410
+ for (sub_module_name, module_attributes) in sorted(
411
+ result[1].items()
412
+ )
413
+ ),
414
+ }
415
+
416
+ source_code = source_code.replace(attach_call, replacement)
417
+
418
+ if module_name == "huggingface_hub":
419
+ # Special handling for huggingface that uses the source code variant
420
+ # of lazy module. spell-checker: ignore huggingface
421
+ if (
422
+ "__getattr__, __dir__, __all__ = _attach(__name__, submodules=[], submod_attrs=_SUBMOD_ATTRS)"
423
+ in source_code
424
+ ):
425
+ huggingface_hub_lazy_loader_info = self.queryRuntimeInformationSingle(
426
+ setup_codes="import huggingface_hub",
427
+ value="huggingface_hub._SUBMOD_ATTRS",
428
+ info_name="huggingface_hub_lazy_loader",
429
+ )
430
+
431
+ self._addLazyLoader(
432
+ module_name,
433
+ submodules=(),
434
+ submodule_attrs=dict(
435
+ ("." + submodule_name, attributes)
436
+ for (
437
+ submodule_name,
438
+ attributes,
439
+ ) in huggingface_hub_lazy_loader_info.items()
440
+ ),
441
+ )
442
+
443
+ if module_name == "pydantic":
444
+ # Pydantic has its own lazy loading, spell-checker: ignore pydantic
445
+ if "def __getattr__(" in source_code:
446
+ pydantic_info = self.queryRuntimeInformationSingle(
447
+ setup_codes="import pydantic",
448
+ value="pydantic._dynamic_imports",
449
+ info_name="pydantic_lazy_loader",
450
+ )
451
+
452
+ pydantic_lazy_loader_info = {}
453
+ for key, value in pydantic_info.items():
454
+ # Older pydantic had only a string for the attribute.
455
+ if type(value) is tuple:
456
+ value = "".join(value).rstrip(".")
457
+
458
+ if value not in pydantic_lazy_loader_info:
459
+ pydantic_lazy_loader_info[value] = []
460
+ pydantic_lazy_loader_info[value].append(key)
461
+
462
+ self._addLazyLoader(
463
+ module_name=module_name,
464
+ submodules=(),
465
+ submodule_attrs=pydantic_lazy_loader_info,
466
+ )
369
467
 
370
- # Do nothing by default.
371
468
  return source_code
372
469
 
470
+ def _addLazyLoader(self, module_name, submodules, submodule_attrs):
471
+ """Add lazy loader information for a module.
472
+
473
+ Args:
474
+ module_name: name of the module to work on
475
+ submodules: list of attributes that are known submodules
476
+ submodule_attrs: dict of module name to list of attributes
477
+
478
+ Notes:
479
+ It converts to modules names on the fly. If in submodule_attr
480
+ the module name starts with a "." then it's relative to the
481
+ module_name value.
482
+
483
+ """
484
+
485
+ submodules = tuple(ModuleName(submodule) for submodule in submodules)
486
+
487
+ submodule_attrs = dict(
488
+ (
489
+ module_name.getChildNamed(submodule[1:])
490
+ if submodule.startswith(".")
491
+ else ModuleName(submodule),
492
+ tuple(attribute_names),
493
+ )
494
+ for (submodule, attribute_names) in sorted(submodule_attrs.items())
495
+ )
496
+
497
+ self.lazy_loader_usages[module_name] = (
498
+ submodules,
499
+ submodule_attrs,
500
+ )
501
+
502
+ def _handleLazyLoad(self, module_name, source_filename):
503
+ pyi_filename = source_filename + "i"
504
+
505
+ if os.path.exists(pyi_filename):
506
+ try:
507
+ import lazy_loader
508
+ except ImportError:
509
+ pass
510
+ else:
511
+ with open(pyi_filename, "rb") as f:
512
+ stub_node = ast.parse(f.read())
513
+
514
+ # We are using private code here, to avoid use duplicating,
515
+ # pylint: disable=protected-access
516
+ visitor = lazy_loader._StubVisitor()
517
+ visitor.visit(stub_node)
518
+
519
+ self._addLazyLoader(
520
+ module_name=module_name,
521
+ submodules=visitor._submodules,
522
+ submodule_attrs=dict(
523
+ ("." + submodule_name, attributes)
524
+ for (
525
+ submodule_name,
526
+ attributes,
527
+ ) in visitor._submod_attrs.items()
528
+ ),
529
+ )
530
+
531
+ return self.lazy_loader_usages[module_name]
532
+
373
533
  def createPreModuleLoadCode(self, module):
374
534
  full_name = module.getFullName()
375
535
 
@@ -442,3 +602,95 @@ __file__ = (__nuitka_binary_dir + '%ssite.py') if '__nuitka_binary_dir' in dict(
442
602
  def decideCompilation(self, module_name):
443
603
  if module_name.hasOneOfNamespaces(self.unworthy_namespaces):
444
604
  return "bytecode"
605
+
606
+ def onModuleUsageLookAhead(
607
+ self, module_name, module_filename, module_kind, get_module_source
608
+ ):
609
+ # Getting the source code will also trigger our modification
610
+ # and potentially tell us if any lazy loading applies.
611
+ if get_module_source() is None:
612
+ return
613
+
614
+ if module_name in self.lazy_loader_usages:
615
+ from nuitka.HardImportRegistry import (
616
+ addModuleAttributeFactory,
617
+ addModuleDynamicHard,
618
+ addModuleTrust,
619
+ trust_module,
620
+ trust_node,
621
+ )
622
+
623
+ addModuleDynamicHard(module_name)
624
+
625
+ sub_module_names, sub_module_attr = self.lazy_loader_usages[module_name]
626
+
627
+ for sub_module_name in sub_module_names:
628
+ addModuleTrust(module_name, sub_module_name, trust_module)
629
+
630
+ sub_module_name = module_name.getChildNamed(sub_module_name)
631
+ addModuleDynamicHard(sub_module_name)
632
+
633
+ _lookAhead(using_module_name=module_name, module_name=sub_module_name)
634
+
635
+ for (
636
+ sub_module_name,
637
+ attribute_names,
638
+ ) in sub_module_attr.items():
639
+ addModuleDynamicHard(sub_module_name)
640
+
641
+ _lookAhead(using_module_name=module_name, module_name=sub_module_name)
642
+
643
+ for attribute_name in attribute_names:
644
+ addModuleTrust(module_name, attribute_name, trust_node)
645
+ addModuleAttributeFactory(
646
+ module_name,
647
+ attribute_name,
648
+ makeExpressionImportModuleNameHardExistsAfterImportFactory(
649
+ sub_module_name=sub_module_name,
650
+ attribute_name=attribute_name,
651
+ ),
652
+ )
653
+
654
+
655
+ def makeExpressionImportModuleNameHardExistsAfterImportFactory(
656
+ sub_module_name,
657
+ attribute_name,
658
+ ):
659
+ from nuitka.HardImportRegistry import trust_node_factory
660
+ from nuitka.nodes.ImportHardNodes import (
661
+ ExpressionImportModuleNameHardExists,
662
+ )
663
+
664
+ key = (sub_module_name, attribute_name)
665
+ if key in trust_node_factory:
666
+ return lambda source_ref: trust_node_factory[key](source_ref=source_ref)
667
+
668
+ return lambda source_ref: ExpressionImportModuleNameHardExists(
669
+ module_name=sub_module_name,
670
+ import_name=attribute_name,
671
+ module_guaranteed=False,
672
+ source_ref=source_ref,
673
+ )
674
+
675
+
676
+ def _lookAhead(using_module_name, module_name):
677
+ (
678
+ _module_name,
679
+ package_filename,
680
+ package_module_kind,
681
+ finding,
682
+ ) = locateModule(
683
+ module_name=module_name,
684
+ parent_package=None,
685
+ level=0,
686
+ )
687
+
688
+ assert module_name == _module_name
689
+
690
+ if finding != "not-found":
691
+ decideRecursion(
692
+ using_module_name=using_module_name,
693
+ module_filename=package_filename,
694
+ module_name=module_name,
695
+ module_kind=package_module_kind,
696
+ )
@@ -129,6 +129,7 @@ except ImportError:
129
129
  yield self.makeDllEntryPoint(
130
130
  source_path=full_path,
131
131
  dest_path=target_filename,
132
+ module_name=full_name,
132
133
  package_name=full_name,
133
134
  reason="needed by 'kivy'",
134
135
  )
@@ -24,6 +24,7 @@ from nuitka.plugins.Plugins import (
24
24
  getActiveQtPluginBindingName,
25
25
  hasActivePlugin,
26
26
  )
27
+ from nuitka.utils.Execution import NuitkaCalledProcessError
27
28
  from nuitka.utils.FileOperations import getFileContentByLine
28
29
  from nuitka.utils.Jinja2 import renderTemplateFromString
29
30
 
@@ -68,9 +69,10 @@ class NuitkaPluginMatplotlib(NuitkaPluginBase):
68
69
  There might exist a local version outside 'matplotlib/mpl-data' which
69
70
  we then must use instead. Determine its name by asking matplotlib.
70
71
  """
71
- info = self.queryRuntimeInformationMultiple(
72
- info_name="matplotlib_info",
73
- setup_codes="""
72
+ try:
73
+ info = self.queryRuntimeInformationMultiple(
74
+ info_name="matplotlib_info",
75
+ setup_codes="""
74
76
  from matplotlib import matplotlib_fname, get_backend, __version__
75
77
  try:
76
78
  from matplotlib import get_data_path
@@ -78,17 +80,24 @@ except ImportError:
78
80
  from matplotlib import _get_data_path as get_data_path
79
81
  from inspect import getsource
80
82
  """,
81
- values=(
82
- ("matplotlibrc_filename", "matplotlib_fname()"),
83
- ("backend", "get_backend()"),
84
- ("data_path", "get_data_path()"),
85
- ("matplotlib_version", "__version__"),
86
- (
87
- "needs_matplotlibdata_env",
88
- "'MATPLOTLIBDATA' in getsource(get_data_path) or 'MATPLOTLIBRC' in getsource(get_data_path)",
83
+ values=(
84
+ ("matplotlibrc_filename", "matplotlib_fname()"),
85
+ ("backend", "get_backend()"),
86
+ ("data_path", "get_data_path()"),
87
+ ("matplotlib_version", "__version__"),
89
88
  ),
90
- ),
91
- )
89
+ )
90
+ except NuitkaCalledProcessError:
91
+ if "MPLBACKEND" not in os.environ:
92
+ self.sysexit(
93
+ """\
94
+ Error, failed to detect matplotlib backend. Please set 'MPLBACKEND' \
95
+ environment variable during compilation.""",
96
+ mnemonic="""\
97
+ https://matplotlib.org/stable/users/installing/environment_variables_faq.html#envvar-MPLBACKEND""",
98
+ )
99
+
100
+ raise
92
101
 
93
102
  if info is None:
94
103
  self.sysexit("Error, it seems 'matplotlib' is not installed or broken.")
@@ -106,6 +115,18 @@ from inspect import getsource
106
115
  "mpl-data missing, matplotlib installation appears to be broken"
107
116
  )
108
117
 
118
+ self.info(
119
+ "Using %s backend '%s'."
120
+ % (
121
+ (
122
+ "configuration file or default"
123
+ if "MPLBACKEND" not in os.environ
124
+ else "as per 'MPLBACKEND' environment variable"
125
+ ),
126
+ matplotlib_info.backend,
127
+ )
128
+ )
129
+
109
130
  # Include the "mpl-data" files.
110
131
  yield self.makeIncludedDataDirectory(
111
132
  source_path=matplotlib_info.data_path,
@@ -133,7 +154,7 @@ from inspect import getsource
133
154
  # old config file has a backend definition
134
155
  found = True
135
156
 
136
- if not found and matplotlib_info.matplotlib_version < "3":
157
+ if not found and matplotlib_info.matplotlib_version < "4":
137
158
  # Set the backend, so even if it was run time determined, we now enforce it.
138
159
  new_lines.append("backend: %s" % matplotlib_info.backend)
139
160
 
@@ -152,12 +173,12 @@ from inspect import getsource
152
173
  # some special handling for matplotlib:
153
174
  # depending on whether 'tk-inter' resp. 'qt-plugins' are enabled,
154
175
  # their matplotlib backends are included.
155
- if hasActivePlugin("tk-inter"):
156
- if module_name in (
157
- "matplotlib.backends.backend_tk",
158
- "matplotlib.backends.backend_tkagg",
159
- "matplotlib.backend.tkagg",
160
- ):
176
+ if module_name in (
177
+ "matplotlib.backends.backend_tk",
178
+ "matplotlib.backends.backend_tkagg",
179
+ "matplotlib.backend.tkagg",
180
+ ):
181
+ if hasActivePlugin("tk-inter"):
161
182
  return True, "Needed for tkinter matplotlib backend"
162
183
 
163
184
  def createPreModuleLoadCode(self, module):
@@ -175,16 +196,13 @@ from inspect import getsource
175
196
  """
176
197
 
177
198
  # The version may not need the environment variable.
178
- if (
179
- module.getFullName() == "matplotlib"
180
- and self._getMatplotlibInfo().needs_matplotlibdata_env
181
- ):
199
+ if module.getFullName() == "matplotlib":
182
200
  code = renderTemplateFromString(
183
201
  r"""
184
202
  import os
185
203
  os.environ["MATPLOTLIBDATA"] = os.path.join(__nuitka_binary_dir, "matplotlib", "mpl-data")
186
204
  os.environ["MATPLOTLIBRC"] = os.path.join(__nuitka_binary_dir, "matplotlib", "mpl-data", "matplotlibrc")
187
- os.environ["MPLBACKEND"] = {{matplotlib_info.backend}}
205
+ os.environ["MPLBACKEND"] = "{{matplotlib_info.backend}}"
188
206
  {% if qt_binding_name %}
189
207
  os.environ["QT_API"] = "{{qt_binding_name}}"
190
208
  {% endif %}
@@ -60,9 +60,7 @@ class NuitkaPluginOptionsNanny(NuitkaPluginBase):
60
60
  return
61
61
 
62
62
  if condition != "True":
63
- problem_desc = (
64
- "incomplete support due to not passing condition %s" % condition
65
- )
63
+ problem_desc = "incomplete support due untrue condition '%s'" % condition
66
64
  else:
67
65
  problem_desc = "incomplete support"
68
66
 
@@ -105,10 +103,11 @@ Otherwise a terminal window will open"""
105
103
 
106
104
  self.info(
107
105
  """\
108
- Note, when using '%s', consider using '--disable-console' option. %s. However for \
109
- debugging, terminal output is the easiest way to see informative traceback \
106
+ Note, when using '%s', consider using '--disable-console' option. %s. However\
107
+ for debugging, terminal output is the easiest way to see informative traceback \
110
108
  and error information, so delay this until your program working and remove \
111
- once you find it non-working."""
109
+ once you find it non-working, and use '--enable-console' to make it explicit \
110
+ and not see this message."""
112
111
  % (full_name, downside_message)
113
112
  )
114
113
 
@@ -90,7 +90,7 @@ sys.exit(%(module_name)s.%(main_name)s)
90
90
  "main_name": main_name,
91
91
  }
92
92
 
93
- def onModuleSourceCode(self, module_name, source_code):
93
+ def onModuleSourceCode(self, module_name, source_filename, source_code):
94
94
  if module_name == "__main__":
95
95
  match = re.search(
96
96
  "\n# EASY-INSTALL-ENTRY-SCRIPT: '(.*?)','(.*?)','(.*?)'", source_code