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.
- {Nuitka_winsvc-1.8.6.dist-info → Nuitka_winsvc-1.9.3.dist-info}/METADATA +1 -1
- {Nuitka_winsvc-1.8.6.dist-info → Nuitka_winsvc-1.9.3.dist-info}/RECORD +212 -203
- {Nuitka_winsvc-1.8.6.dist-info → Nuitka_winsvc-1.9.3.dist-info}/WHEEL +1 -1
- nuitka/BytecodeCaching.py +4 -1
- nuitka/HardImportRegistry.py +348 -0
- nuitka/MainControl.py +45 -25
- nuitka/OptionParsing.py +31 -20
- nuitka/Options.py +47 -16
- nuitka/Progress.py +32 -2
- nuitka/PythonFlavors.py +1 -1
- nuitka/PythonVersions.py +61 -0
- nuitka/Tracing.py +25 -12
- nuitka/TreeXML.py +5 -5
- nuitka/Variables.py +15 -24
- nuitka/Version.py +16 -6
- nuitka/__main__.py +15 -0
- nuitka/__past__.py +15 -17
- nuitka/build/Backend.scons +44 -35
- nuitka/build/CCompilerVersion.scons +10 -9
- nuitka/build/Onefile.scons +11 -26
- nuitka/build/SconsCaching.py +2 -0
- nuitka/build/SconsCompilerSettings.py +72 -22
- nuitka/build/SconsHacks.py +1 -0
- nuitka/build/SconsInterface.py +5 -0
- nuitka/build/SconsSpawn.py +16 -3
- nuitka/build/SconsUtils.py +11 -12
- nuitka/build/include/nuitka/checksum_tools.h +0 -4
- nuitka/build/include/nuitka/compiled_asyncgen.h +1 -1
- nuitka/build/include/nuitka/compiled_coroutine.h +1 -1
- nuitka/build/include/nuitka/compiled_frame.h +7 -4
- nuitka/build/include/nuitka/compiled_function.h +13 -3
- nuitka/build/include/nuitka/compiled_generator.h +1 -1
- nuitka/build/include/nuitka/constants.h +2 -0
- nuitka/build/include/nuitka/environment_variables.h +45 -0
- nuitka/build/include/nuitka/exceptions.h +32 -4
- nuitka/build/include/nuitka/filesystem_paths.h +6 -1
- nuitka/build/include/nuitka/freelists.h +11 -1
- nuitka/build/include/nuitka/helper/dictionaries.h +1 -1
- nuitka/build/include/nuitka/helper/import_hard.h +3 -0
- nuitka/build/include/nuitka/helpers.h +2 -0
- nuitka/build/include/nuitka/importing.h +3 -0
- nuitka/build/include/nuitka/prelude.h +17 -6
- nuitka/build/include/nuitka/unfreezing.h +1 -1
- nuitka/build/inline_copy/bin/scons.py +14 -0
- nuitka/build/inline_copy/tqdm/tqdm/__init__.py +2 -2
- nuitka/build/inline_copy/tqdm/tqdm/utils.py +14 -8
- nuitka/build/inline_copy/zlib/LICENSE +22 -0
- nuitka/build/inline_copy/zlib/crc32.c +1049 -0
- nuitka/build/inline_copy/zlib/crc32.h +9446 -0
- nuitka/build/inline_copy/zlib/zconf.h +551 -0
- nuitka/build/inline_copy/zlib/zlib.h +1938 -0
- nuitka/build/inline_copy/zlib/zutil.h +275 -0
- nuitka/build/static_src/CompiledAsyncgenType.c +41 -41
- nuitka/build/static_src/CompiledCodeHelpers.c +14 -7
- nuitka/build/static_src/CompiledCoroutineType.c +60 -51
- nuitka/build/static_src/CompiledFrameType.c +12 -12
- nuitka/build/static_src/CompiledFunctionType.c +149 -28
- nuitka/build/static_src/CompiledGeneratorType.c +64 -65
- nuitka/build/static_src/CompiledGeneratorTypeUncompiledIntegration.c +1 -1
- nuitka/build/static_src/CompiledMethodType.c +5 -3
- nuitka/build/static_src/HelperEnvironmentVariables.c +120 -0
- nuitka/build/static_src/HelpersAttributes.c +1 -1
- nuitka/build/static_src/HelpersBuiltin.c +1 -1
- nuitka/build/static_src/HelpersChecksumTools.c +19 -4
- nuitka/build/static_src/HelpersComparisonEq.c +4 -4
- nuitka/build/static_src/HelpersComparisonNe.c +4 -4
- nuitka/build/static_src/HelpersConstantsBlob.c +40 -23
- nuitka/build/static_src/HelpersDictionaries.c +3 -1
- nuitka/build/static_src/HelpersDictionariesGenerated.c +9 -9
- nuitka/build/static_src/HelpersFilesystemPaths.c +12 -2
- nuitka/build/static_src/HelpersImport.c +29 -1
- nuitka/build/static_src/HelpersImportHard.c +19 -0
- nuitka/build/static_src/HelpersOperationInplaceAddUtils.c +5 -4
- nuitka/build/static_src/HelpersPythonPgo.c +5 -5
- nuitka/build/static_src/HelpersSafeStrings.c +2 -1
- nuitka/build/static_src/HelpersStrings.c +12 -10
- nuitka/build/static_src/HelpersTypes.c +1 -1
- nuitka/build/static_src/InspectPatcher.c +3 -2
- nuitka/build/static_src/MainProgram.c +182 -214
- nuitka/build/static_src/MetaPathBasedLoader.c +36 -23
- nuitka/build/static_src/MetaPathBasedLoaderImportlibMetadataDistribution.c +4 -2
- nuitka/build/static_src/MetaPathBasedLoaderResourceReaderFiles.c +38 -2
- nuitka/build/static_src/OnefileBootstrap.c +124 -93
- nuitka/code_generation/CodeGeneration.py +4 -2
- nuitka/code_generation/CodeObjectCodes.py +5 -1
- nuitka/code_generation/ConstantCodes.py +4 -0
- nuitka/code_generation/Contexts.py +111 -3
- nuitka/code_generation/DictCodes.py +5 -5
- nuitka/code_generation/FunctionCodes.py +4 -2
- nuitka/code_generation/GlobalConstants.py +10 -0
- nuitka/code_generation/ImportCodes.py +69 -33
- nuitka/code_generation/ModuleCodes.py +4 -1
- nuitka/code_generation/Namify.py +6 -5
- nuitka/code_generation/YieldCodes.py +3 -3
- nuitka/code_generation/templates/CodeTemplatesModules.py +61 -95
- nuitka/code_generation/templates_c/HelperDictionaryCopy.c.j2 +3 -3
- nuitka/code_generation/templates_c/HelperOperationComparisonUnicode.c.j2 +2 -2
- nuitka/distutils/DistutilCommands.py +3 -0
- nuitka/finalizations/FinalizeMarkups.py +1 -1
- nuitka/freezer/DependsExe.py +2 -1
- nuitka/freezer/DllDependenciesPosix.py +11 -1
- nuitka/freezer/IncludedEntryPoints.py +54 -16
- nuitka/freezer/Onefile.py +7 -3
- nuitka/freezer/Standalone.py +39 -17
- nuitka/importing/Importing.py +195 -62
- nuitka/importing/PreloadedPackages.py +2 -1
- nuitka/importing/Recursion.py +98 -27
- nuitka/importing/StandardLibrary.py +7 -4
- nuitka/nodes/BuiltinOpenNodes.py +28 -1
- nuitka/nodes/BuiltinRangeNodes.py +2 -2
- nuitka/nodes/BuiltinSumNodes.py +1 -1
- nuitka/nodes/ChildrenHavingMixins.py +326 -2
- nuitka/nodes/HardImportNodesGenerated.py +141 -38
- nuitka/nodes/ImportHardNodes.py +0 -8
- nuitka/nodes/ImportNodes.py +267 -361
- nuitka/nodes/IterationHandles.py +36 -17
- nuitka/nodes/LocalsScopes.py +3 -1
- nuitka/nodes/NodeBases.py +8 -14
- nuitka/nodes/OperatorNodes.py +9 -9
- nuitka/nodes/OutlineNodes.py +3 -3
- nuitka/nodes/PackageMetadataNodes.py +19 -9
- nuitka/nodes/SliceNodes.py +1 -1
- nuitka/nodes/VariableAssignNodes.py +25 -15
- nuitka/nodes/VariableRefNodes.py +7 -7
- nuitka/nodes/YieldNodes.py +2 -2
- nuitka/nodes/shapes/BuiltinTypeShapes.py +81 -6
- nuitka/nodes/shapes/ShapeMixins.py +21 -0
- nuitka/nodes/shapes/StandardShapes.py +9 -3
- nuitka/optimizations/OptimizeBuiltinCalls.py +1 -1
- nuitka/optimizations/TraceCollections.py +75 -0
- nuitka/pgo/PGO.py +14 -6
- nuitka/plugins/PluginBase.py +83 -11
- nuitka/plugins/Plugins.py +78 -35
- nuitka/plugins/standard/AntiBloatPlugin.py +46 -1
- nuitka/plugins/standard/ConsiderPyLintAnnotationsPlugin.py +1 -1
- nuitka/plugins/standard/DelvewheelPlugin.py +2 -1
- nuitka/plugins/standard/DillPlugin.py +3 -99
- nuitka/plugins/standard/DllFilesPlugin.py +45 -0
- nuitka/plugins/standard/GiPlugin.py +23 -10
- nuitka/plugins/standard/GlfwPlugin.py +1 -0
- nuitka/plugins/standard/ImplicitImports.py +267 -15
- nuitka/plugins/standard/KivyPlugin.py +1 -0
- nuitka/plugins/standard/MatplotlibPlugin.py +43 -25
- nuitka/plugins/standard/OptionsNannyPlugin.py +5 -6
- nuitka/plugins/standard/PkgResourcesPlugin.py +1 -1
- nuitka/plugins/standard/PmwPlugin.py +1 -1
- nuitka/plugins/standard/PySidePyQtPlugin.py +37 -20
- nuitka/plugins/standard/TkinterPlugin.py +44 -30
- nuitka/plugins/standard/TransformersPlugin.py +3 -1
- nuitka/plugins/standard/standard.nuitka-package.config.yml +522 -86
- nuitka/plugins/standard/stdlib3.nuitka-package.config.yml +8 -1
- nuitka/reports/CompilationReportReader.py +53 -0
- nuitka/reports/LicenseReport.rst.j2 +4 -4
- nuitka/reports/Reports.py +129 -47
- nuitka/specs/HardImportSpecs.py +6 -0
- nuitka/tools/data_composer/DataComposer.py +29 -17
- nuitka/tools/onefile_compressor/OnefileCompressor.py +173 -110
- nuitka/tools/podman/__main__.py +17 -2
- nuitka/tools/scanning/DisplayPackageDLLs.py +11 -2
- nuitka/tools/scanning/DisplayPackageData.py +1 -1
- nuitka/tools/specialize/CTypeDescriptions.py +36 -27
- nuitka/tools/specialize/SpecializeC.py +1 -1
- nuitka/tools/specialize/SpecializePython.py +16 -0
- nuitka/tools/testing/Common.py +3 -4
- nuitka/tools/testing/OutputComparison.py +23 -0
- nuitka/tools/testing/SearchModes.py +2 -2
- nuitka/tools/testing/compare_with_cpython/__main__.py +13 -4
- nuitka/tools/testing/measure_construct_performance/__main__.py +2 -5
- nuitka/tools/watch/__main__.py +194 -56
- nuitka/tree/Building.py +8 -2
- nuitka/tree/ComplexCallHelperFunctions.py +45 -15
- nuitka/tree/ReformulationAssignmentStatements.py +18 -12
- nuitka/tree/ReformulationCallExpressions.py +1 -1
- nuitka/tree/ReformulationClasses.py +11 -5
- nuitka/tree/ReformulationClasses3.py +30 -12
- nuitka/tree/ReformulationComparisonExpressions.py +4 -2
- nuitka/tree/ReformulationContractionExpressions.py +19 -11
- nuitka/tree/ReformulationDictionaryCreation.py +9 -3
- nuitka/tree/ReformulationExecStatements.py +6 -6
- nuitka/tree/ReformulationForLoopStatements.py +5 -5
- nuitka/tree/ReformulationFunctionStatements.py +6 -2
- nuitka/tree/ReformulationImportStatements.py +7 -2
- nuitka/tree/ReformulationLambdaExpressions.py +1 -1
- nuitka/tree/ReformulationMatchStatements.py +3 -1
- nuitka/tree/ReformulationNamespacePackages.py +7 -3
- nuitka/tree/ReformulationPrintStatements.py +1 -1
- nuitka/tree/ReformulationSequenceCreation.py +18 -6
- nuitka/tree/ReformulationWithStatements.py +8 -8
- nuitka/tree/ReformulationYieldExpressions.py +2 -2
- nuitka/tree/SourceHandling.py +27 -5
- nuitka/tree/VariableClosure.py +11 -1
- nuitka/utils/AppDirs.py +2 -2
- nuitka/utils/CStrings.py +39 -3
- nuitka/utils/CommandLineOptions.py +42 -1
- nuitka/utils/Distributions.py +305 -38
- nuitka/utils/Download.py +27 -8
- nuitka/utils/FileOperations.py +103 -20
- nuitka/utils/Hashing.py +2 -3
- nuitka/utils/Importing.py +60 -3
- nuitka/utils/InstalledPythons.py +31 -36
- nuitka/utils/Jinja2.py +11 -5
- nuitka/utils/ModuleNames.py +11 -3
- nuitka/utils/ReExecute.py +7 -0
- nuitka/utils/SharedLibraries.py +38 -14
- nuitka/utils/SlotMetaClasses.py +55 -0
- nuitka/utils/Utils.py +10 -0
- nuitka/utils/Yaml.py +9 -1
- nuitka/build/inline_copy/tqdm/tqdm/_tqdm_gui.py +0 -9
- nuitka/build/inline_copy/tqdm/tqdm/gui.py +0 -191
- {Nuitka_winsvc-1.8.6.data → Nuitka_winsvc-1.9.3.data}/scripts/nuitka-run.bat +0 -0
- {Nuitka_winsvc-1.8.6.data → Nuitka_winsvc-1.9.3.data}/scripts/nuitka.bat +0 -0
- {Nuitka_winsvc-1.8.6.dist-info → Nuitka_winsvc-1.9.3.dist-info}/LICENSE.txt +0 -0
- {Nuitka_winsvc-1.8.6.dist-info → Nuitka_winsvc-1.9.3.dist-info}/entry_points.txt +0 -0
- {Nuitka_winsvc-1.8.6.dist-info → Nuitka_winsvc-1.9.3.dist-info}/top_level.txt +0 -0
nuitka/importing/Recursion.py
CHANGED
|
@@ -28,7 +28,7 @@ from nuitka.freezer.ImportDetection import (
|
|
|
28
28
|
detectEarlyImports,
|
|
29
29
|
detectStdlibAutoInclusionModules,
|
|
30
30
|
)
|
|
31
|
-
from nuitka.importing import ImportCache,
|
|
31
|
+
from nuitka.importing import ImportCache, StandardLibrary
|
|
32
32
|
from nuitka.ModuleRegistry import addUsedModule, getRootTopModule
|
|
33
33
|
from nuitka.pgo.PGO import decideInclusionFromPGO
|
|
34
34
|
from nuitka.plugins.Plugins import Plugins
|
|
@@ -38,6 +38,13 @@ from nuitka.utils.FileOperations import listDir
|
|
|
38
38
|
from nuitka.utils.Importing import getSharedLibrarySuffixes
|
|
39
39
|
from nuitka.utils.ModuleNames import ModuleName
|
|
40
40
|
|
|
41
|
+
from .Importing import (
|
|
42
|
+
getModuleNameAndKindFromFilename,
|
|
43
|
+
isPackageDir,
|
|
44
|
+
locateModule,
|
|
45
|
+
warnAboutNotFoundImport,
|
|
46
|
+
)
|
|
47
|
+
|
|
41
48
|
|
|
42
49
|
def _recurseTo(module_name, module_filename, module_kind, reason):
|
|
43
50
|
from nuitka.tree import Building
|
|
@@ -97,9 +104,38 @@ def recurseTo(
|
|
|
97
104
|
_recursion_decision_cache = {}
|
|
98
105
|
|
|
99
106
|
|
|
107
|
+
def getRecursionDecisions():
|
|
108
|
+
"""Access to recursion decisions, intended only for reporting."""
|
|
109
|
+
return _recursion_decision_cache
|
|
110
|
+
|
|
111
|
+
|
|
100
112
|
def decideRecursion(
|
|
101
113
|
using_module_name, module_filename, module_name, module_kind, extra_recursion=False
|
|
102
114
|
):
|
|
115
|
+
package_part, _remainder = module_name.splitModuleBasename()
|
|
116
|
+
|
|
117
|
+
if package_part is not None:
|
|
118
|
+
(
|
|
119
|
+
_package_part,
|
|
120
|
+
package_filename,
|
|
121
|
+
package_module_kind,
|
|
122
|
+
package_finding,
|
|
123
|
+
) = locateModule(module_name=package_part, parent_package=None, level=0)
|
|
124
|
+
assert _package_part == package_part
|
|
125
|
+
|
|
126
|
+
# For bad decisions, this may already not work.
|
|
127
|
+
if package_finding != "not-found":
|
|
128
|
+
package_decision, package_reason = decideRecursion(
|
|
129
|
+
using_module_name=using_module_name,
|
|
130
|
+
module_filename=package_filename,
|
|
131
|
+
module_name=package_part,
|
|
132
|
+
module_kind=package_module_kind,
|
|
133
|
+
extra_recursion=extra_recursion,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
if package_decision is False:
|
|
137
|
+
return package_decision, package_reason
|
|
138
|
+
|
|
103
139
|
key = using_module_name, module_filename, module_name, module_kind, extra_recursion
|
|
104
140
|
|
|
105
141
|
if key not in _recursion_decision_cache:
|
|
@@ -111,6 +147,16 @@ def decideRecursion(
|
|
|
111
147
|
extra_recursion,
|
|
112
148
|
)
|
|
113
149
|
|
|
150
|
+
# If decided true, give the plugins a chance to e.g. add more hard
|
|
151
|
+
# module information, this indicates tentatively, that a module might
|
|
152
|
+
# get used, but it may also not happen at all.
|
|
153
|
+
if _recursion_decision_cache[key][0]:
|
|
154
|
+
Plugins.onModuleUsageLookAhead(
|
|
155
|
+
module_name=module_name,
|
|
156
|
+
module_filename=module_filename,
|
|
157
|
+
module_kind=module_kind,
|
|
158
|
+
)
|
|
159
|
+
|
|
114
160
|
return _recursion_decision_cache[key]
|
|
115
161
|
|
|
116
162
|
|
|
@@ -125,6 +171,9 @@ def _decideRecursion(
|
|
|
125
171
|
if module_kind == "extension" and not Options.isStandaloneMode():
|
|
126
172
|
return False, "Extension modules cannot be inspected."
|
|
127
173
|
|
|
174
|
+
if module_kind == "built-in":
|
|
175
|
+
return False, "Built-in modules cannot be inspected."
|
|
176
|
+
|
|
128
177
|
if module_name in detectEarlyImports():
|
|
129
178
|
return True, "Technically required for CPython library startup."
|
|
130
179
|
|
|
@@ -164,7 +213,7 @@ def _decideRecursion(
|
|
|
164
213
|
if plugin_decision and plugin_decision[0]:
|
|
165
214
|
deciding_plugins[0].sysexit(
|
|
166
215
|
"Conflict between user and plugin decision for module '%s'."
|
|
167
|
-
%
|
|
216
|
+
% module_name
|
|
168
217
|
)
|
|
169
218
|
|
|
170
219
|
return False, "Module %s instructed by user to not follow to." % reason
|
|
@@ -177,7 +226,7 @@ def _decideRecursion(
|
|
|
177
226
|
if plugin_decision and not plugin_decision[0] and deciding_plugins:
|
|
178
227
|
deciding_plugins[0].sysexit(
|
|
179
228
|
"Conflict between user and plugin decision for module '%s'."
|
|
180
|
-
%
|
|
229
|
+
% module_name
|
|
181
230
|
)
|
|
182
231
|
|
|
183
232
|
return True, "Module %s instructed by user to follow to." % reason
|
|
@@ -247,8 +296,9 @@ def isSameModulePath(path1, path2):
|
|
|
247
296
|
return os.path.abspath(path1) == os.path.abspath(path2)
|
|
248
297
|
|
|
249
298
|
|
|
250
|
-
def _addIncludedModule(module):
|
|
251
|
-
# Many branches, for the decision is very complex
|
|
299
|
+
def _addIncludedModule(module, package_only):
|
|
300
|
+
# Many branches, for the decision is very complex
|
|
301
|
+
# pylint: disable=too-many-branches
|
|
252
302
|
|
|
253
303
|
if Options.isShowInclusion():
|
|
254
304
|
recursion_logger.info(
|
|
@@ -281,16 +331,23 @@ def _addIncludedModule(module):
|
|
|
281
331
|
if Options.isShowInclusion():
|
|
282
332
|
recursion_logger.info("Package directory '%s'." % package_dir)
|
|
283
333
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
sub_path + ".py"
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
334
|
+
if not package_only:
|
|
335
|
+
for sub_path, sub_filename in listDir(package_dir):
|
|
336
|
+
if sub_filename in ("__init__.py", "__pycache__"):
|
|
337
|
+
continue
|
|
338
|
+
|
|
339
|
+
if isPackageDir(sub_path) and not os.path.exists(sub_path + ".py"):
|
|
340
|
+
checkPluginSinglePath(
|
|
341
|
+
sub_path,
|
|
342
|
+
module_package=module.getFullName(),
|
|
343
|
+
package_only=False,
|
|
344
|
+
)
|
|
345
|
+
elif sub_path.endswith(".py"):
|
|
346
|
+
checkPluginSinglePath(
|
|
347
|
+
sub_path,
|
|
348
|
+
module_package=module.getFullName(),
|
|
349
|
+
package_only=False,
|
|
350
|
+
)
|
|
294
351
|
|
|
295
352
|
elif module.isCompiledPythonModule() or module.isUncompiledPythonModule():
|
|
296
353
|
ModuleRegistry.addRootModule(module)
|
|
@@ -301,7 +358,7 @@ def _addIncludedModule(module):
|
|
|
301
358
|
assert False, module
|
|
302
359
|
|
|
303
360
|
|
|
304
|
-
def checkPluginSinglePath(plugin_filename, module_package):
|
|
361
|
+
def checkPluginSinglePath(plugin_filename, module_package, package_only):
|
|
305
362
|
# The importing wants these to be unique.
|
|
306
363
|
plugin_filename = os.path.abspath(plugin_filename)
|
|
307
364
|
|
|
@@ -311,9 +368,7 @@ def checkPluginSinglePath(plugin_filename, module_package):
|
|
|
311
368
|
% (plugin_filename, module_package)
|
|
312
369
|
)
|
|
313
370
|
|
|
314
|
-
module_name, module_kind =
|
|
315
|
-
plugin_filename
|
|
316
|
-
)
|
|
371
|
+
module_name, module_kind = getModuleNameAndKindFromFilename(plugin_filename)
|
|
317
372
|
|
|
318
373
|
module_name = ModuleName.makeModuleNameInPackage(module_name, module_package)
|
|
319
374
|
|
|
@@ -347,7 +402,7 @@ the compiled result, and therefore asking to include them makes no sense.
|
|
|
347
402
|
)
|
|
348
403
|
|
|
349
404
|
if module:
|
|
350
|
-
_addIncludedModule(module)
|
|
405
|
+
_addIncludedModule(module=module, package_only=package_only)
|
|
351
406
|
else:
|
|
352
407
|
recursion_logger.warning(
|
|
353
408
|
"Failed to include module from '%s'." % plugin_filename
|
|
@@ -367,21 +422,33 @@ def checkPluginPath(plugin_filename, module_package):
|
|
|
367
422
|
)
|
|
368
423
|
|
|
369
424
|
# Files and package directories are handled here.
|
|
370
|
-
if os.path.isfile(plugin_filename) or
|
|
371
|
-
checkPluginSinglePath(
|
|
425
|
+
if os.path.isfile(plugin_filename) or isPackageDir(plugin_filename):
|
|
426
|
+
checkPluginSinglePath(
|
|
427
|
+
plugin_filename,
|
|
428
|
+
module_package=module_package,
|
|
429
|
+
package_only=False,
|
|
430
|
+
)
|
|
372
431
|
# This effectively only covers files known to not be packages due to name
|
|
373
432
|
# or older Python version.
|
|
374
433
|
elif os.path.isdir(plugin_filename):
|
|
375
434
|
for sub_path, sub_filename in listDir(plugin_filename):
|
|
376
435
|
assert sub_filename != "__init__.py"
|
|
377
436
|
|
|
378
|
-
if
|
|
379
|
-
checkPluginSinglePath(
|
|
437
|
+
if isPackageDir(sub_path) or sub_path.endswith(".py"):
|
|
438
|
+
checkPluginSinglePath(
|
|
439
|
+
sub_path,
|
|
440
|
+
module_package=None,
|
|
441
|
+
package_only=False,
|
|
442
|
+
)
|
|
380
443
|
continue
|
|
381
444
|
|
|
382
445
|
for suffix in getSharedLibrarySuffixes():
|
|
383
446
|
if sub_path.endswith(suffix):
|
|
384
|
-
checkPluginSinglePath(
|
|
447
|
+
checkPluginSinglePath(
|
|
448
|
+
sub_path,
|
|
449
|
+
module_package=None,
|
|
450
|
+
package_only=False,
|
|
451
|
+
)
|
|
385
452
|
|
|
386
453
|
else:
|
|
387
454
|
recursion_logger.warning(
|
|
@@ -405,7 +472,11 @@ def checkPluginFilenamePattern(pattern):
|
|
|
405
472
|
continue
|
|
406
473
|
|
|
407
474
|
found = True
|
|
408
|
-
checkPluginSinglePath(
|
|
475
|
+
checkPluginSinglePath(
|
|
476
|
+
filename,
|
|
477
|
+
module_package=None,
|
|
478
|
+
package_only=False,
|
|
479
|
+
)
|
|
409
480
|
|
|
410
481
|
if not found:
|
|
411
482
|
recursion_logger.warning(
|
|
@@ -430,7 +501,7 @@ def considerUsedModules(module, pass_count):
|
|
|
430
501
|
continue
|
|
431
502
|
|
|
432
503
|
if used_module.finding == "not-found":
|
|
433
|
-
|
|
504
|
+
warnAboutNotFoundImport(
|
|
434
505
|
importing=module,
|
|
435
506
|
source_ref=used_module.source_ref,
|
|
436
507
|
module_name=used_module.module_name,
|
|
@@ -28,7 +28,6 @@ module.
|
|
|
28
28
|
|
|
29
29
|
import os
|
|
30
30
|
|
|
31
|
-
from nuitka.Options import shallUseStaticLibPython
|
|
32
31
|
from nuitka.PythonVersions import python_version
|
|
33
32
|
from nuitka.utils.FileOperations import getFileContents, isFilenameBelowPath
|
|
34
33
|
from nuitka.utils.ModuleNames import ModuleName
|
|
@@ -104,10 +103,13 @@ def getStandardLibraryPaths():
|
|
|
104
103
|
if os.path.isdir(candidate):
|
|
105
104
|
stdlib_paths.add(candidate)
|
|
106
105
|
|
|
107
|
-
if isWin32OrPosixWindows()
|
|
108
|
-
import
|
|
106
|
+
if isWin32OrPosixWindows():
|
|
107
|
+
from nuitka.Options import shallUseStaticLibPython
|
|
109
108
|
|
|
110
|
-
|
|
109
|
+
if not shallUseStaticLibPython():
|
|
110
|
+
import _ctypes
|
|
111
|
+
|
|
112
|
+
stdlib_paths.add(os.path.dirname(_ctypes.__file__))
|
|
111
113
|
|
|
112
114
|
getStandardLibraryPaths.result = [
|
|
113
115
|
os.path.normcase(os.path.normpath(stdlib_path))
|
|
@@ -358,6 +360,7 @@ _stdlib_no_auto_inclusion_list = (
|
|
|
358
360
|
"tty",
|
|
359
361
|
"termios",
|
|
360
362
|
"this",
|
|
363
|
+
"textwrap",
|
|
361
364
|
# Distribution and bytecode related stuff
|
|
362
365
|
"plistlib",
|
|
363
366
|
"distutils",
|
nuitka/nodes/BuiltinOpenNodes.py
CHANGED
|
@@ -30,7 +30,7 @@ from .shapes.BuiltinTypeShapes import tshape_file
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class ExpressionBuiltinOpenMixin(object):
|
|
33
|
-
# Mixins are required to slots
|
|
33
|
+
# Mixins are required to define empty slots
|
|
34
34
|
__slots__ = ()
|
|
35
35
|
|
|
36
36
|
@staticmethod
|
|
@@ -112,3 +112,30 @@ class ExpressionBuiltinOpenP3(
|
|
|
112
112
|
)
|
|
113
113
|
|
|
114
114
|
ExpressionBase.__init__(self, source_ref)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def makeExpressionBuiltinsOpenCall(
|
|
118
|
+
filename,
|
|
119
|
+
mode,
|
|
120
|
+
buffering,
|
|
121
|
+
encoding,
|
|
122
|
+
errors,
|
|
123
|
+
newline,
|
|
124
|
+
closefd,
|
|
125
|
+
opener,
|
|
126
|
+
source_ref,
|
|
127
|
+
):
|
|
128
|
+
"""Function reference ctypes.CDLL"""
|
|
129
|
+
|
|
130
|
+
assert str is not bytes
|
|
131
|
+
return ExpressionBuiltinOpenP3(
|
|
132
|
+
filename=filename,
|
|
133
|
+
mode=mode,
|
|
134
|
+
buffering=buffering,
|
|
135
|
+
encoding=encoding,
|
|
136
|
+
errors=errors,
|
|
137
|
+
newline=newline,
|
|
138
|
+
closefd=closefd,
|
|
139
|
+
opener=opener,
|
|
140
|
+
source_ref=source_ref,
|
|
141
|
+
)
|
|
@@ -47,7 +47,7 @@ from .shapes.BuiltinTypeShapes import tshape_xrange
|
|
|
47
47
|
class ExpressionBuiltinRangeMixin(ExpressionListShapeExactMixin):
|
|
48
48
|
"""Mixin class for range nodes with 1/2/3 arguments."""
|
|
49
49
|
|
|
50
|
-
# Mixins are required to slots
|
|
50
|
+
# Mixins are required to define empty slots
|
|
51
51
|
__slots__ = ()
|
|
52
52
|
|
|
53
53
|
builtin_spec = BuiltinParameterSpecs.builtin_range_spec
|
|
@@ -403,7 +403,7 @@ class ExpressionBuiltinRange3(
|
|
|
403
403
|
class ExpressionBuiltinXrangeMixin(object):
|
|
404
404
|
"""Mixin class for xrange nodes with 1/2/3 arguments."""
|
|
405
405
|
|
|
406
|
-
# Mixins are required to slots
|
|
406
|
+
# Mixins are required to define empty slots
|
|
407
407
|
__slots__ = ()
|
|
408
408
|
|
|
409
409
|
builtin_spec = BuiltinParameterSpecs.builtin_xrange_spec
|
nuitka/nodes/BuiltinSumNodes.py
CHANGED
|
@@ -6387,7 +6387,7 @@ class ChildHavingExpressionMixin(object):
|
|
|
6387
6387
|
# ExpressionMatchArgs
|
|
6388
6388
|
# ExpressionYield
|
|
6389
6389
|
# ExpressionYieldFrom
|
|
6390
|
-
#
|
|
6390
|
+
# ExpressionYieldFromAwaitable
|
|
6391
6391
|
|
|
6392
6392
|
def __init__(
|
|
6393
6393
|
self,
|
|
@@ -6660,7 +6660,7 @@ ChildrenExpressionAttributeLookupTypePrepareMixin = ChildHavingExpressionMixin
|
|
|
6660
6660
|
ChildrenExpressionMatchArgsMixin = ChildHavingExpressionMixin
|
|
6661
6661
|
ChildrenExpressionYieldMixin = ChildHavingExpressionMixin
|
|
6662
6662
|
ChildrenExpressionYieldFromMixin = ChildHavingExpressionMixin
|
|
6663
|
-
|
|
6663
|
+
ChildrenExpressionYieldFromAwaitableMixin = ChildHavingExpressionMixin
|
|
6664
6664
|
|
|
6665
6665
|
|
|
6666
6666
|
class ChildrenHavingExpressionLowerAutoNoneUpperAutoNoneMixin(object):
|
|
@@ -7355,6 +7355,330 @@ ChildrenExpressionLocalsMappingVariableRefOrFallbackMixin = ChildHavingFallbackM
|
|
|
7355
7355
|
ChildrenExpressionLocalsVariableRefOrFallbackMixin = ChildHavingFallbackMixin
|
|
7356
7356
|
|
|
7357
7357
|
|
|
7358
|
+
class ChildrenHavingFileModeOptionalBufferingOptionalEncodingOptionalErrorsOptionalNewlineOptionalClosefdOptionalOpenerOptionalMixin(
|
|
7359
|
+
object
|
|
7360
|
+
):
|
|
7361
|
+
# Mixins are not allowed to specify slots, pylint: disable=assigning-non-slot
|
|
7362
|
+
__slots__ = ()
|
|
7363
|
+
|
|
7364
|
+
# This is generated for use in
|
|
7365
|
+
# ExpressionBuiltinsOpen
|
|
7366
|
+
|
|
7367
|
+
def __init__(
|
|
7368
|
+
self,
|
|
7369
|
+
file,
|
|
7370
|
+
mode,
|
|
7371
|
+
buffering,
|
|
7372
|
+
encoding,
|
|
7373
|
+
errors,
|
|
7374
|
+
newline,
|
|
7375
|
+
closefd,
|
|
7376
|
+
opener,
|
|
7377
|
+
):
|
|
7378
|
+
file.parent = self
|
|
7379
|
+
|
|
7380
|
+
self.subnode_file = file
|
|
7381
|
+
|
|
7382
|
+
if mode is not None:
|
|
7383
|
+
mode.parent = self
|
|
7384
|
+
|
|
7385
|
+
self.subnode_mode = mode
|
|
7386
|
+
|
|
7387
|
+
if buffering is not None:
|
|
7388
|
+
buffering.parent = self
|
|
7389
|
+
|
|
7390
|
+
self.subnode_buffering = buffering
|
|
7391
|
+
|
|
7392
|
+
if encoding is not None:
|
|
7393
|
+
encoding.parent = self
|
|
7394
|
+
|
|
7395
|
+
self.subnode_encoding = encoding
|
|
7396
|
+
|
|
7397
|
+
if errors is not None:
|
|
7398
|
+
errors.parent = self
|
|
7399
|
+
|
|
7400
|
+
self.subnode_errors = errors
|
|
7401
|
+
|
|
7402
|
+
if newline is not None:
|
|
7403
|
+
newline.parent = self
|
|
7404
|
+
|
|
7405
|
+
self.subnode_newline = newline
|
|
7406
|
+
|
|
7407
|
+
if closefd is not None:
|
|
7408
|
+
closefd.parent = self
|
|
7409
|
+
|
|
7410
|
+
self.subnode_closefd = closefd
|
|
7411
|
+
|
|
7412
|
+
if opener is not None:
|
|
7413
|
+
opener.parent = self
|
|
7414
|
+
|
|
7415
|
+
self.subnode_opener = opener
|
|
7416
|
+
|
|
7417
|
+
def getVisitableNodes(self):
|
|
7418
|
+
"""The visitable nodes, with tuple values flattened."""
|
|
7419
|
+
|
|
7420
|
+
result = []
|
|
7421
|
+
result.append(self.subnode_file)
|
|
7422
|
+
value = self.subnode_mode
|
|
7423
|
+
if value is None:
|
|
7424
|
+
pass
|
|
7425
|
+
else:
|
|
7426
|
+
result.append(value)
|
|
7427
|
+
value = self.subnode_buffering
|
|
7428
|
+
if value is None:
|
|
7429
|
+
pass
|
|
7430
|
+
else:
|
|
7431
|
+
result.append(value)
|
|
7432
|
+
value = self.subnode_encoding
|
|
7433
|
+
if value is None:
|
|
7434
|
+
pass
|
|
7435
|
+
else:
|
|
7436
|
+
result.append(value)
|
|
7437
|
+
value = self.subnode_errors
|
|
7438
|
+
if value is None:
|
|
7439
|
+
pass
|
|
7440
|
+
else:
|
|
7441
|
+
result.append(value)
|
|
7442
|
+
value = self.subnode_newline
|
|
7443
|
+
if value is None:
|
|
7444
|
+
pass
|
|
7445
|
+
else:
|
|
7446
|
+
result.append(value)
|
|
7447
|
+
value = self.subnode_closefd
|
|
7448
|
+
if value is None:
|
|
7449
|
+
pass
|
|
7450
|
+
else:
|
|
7451
|
+
result.append(value)
|
|
7452
|
+
value = self.subnode_opener
|
|
7453
|
+
if value is None:
|
|
7454
|
+
pass
|
|
7455
|
+
else:
|
|
7456
|
+
result.append(value)
|
|
7457
|
+
return tuple(result)
|
|
7458
|
+
|
|
7459
|
+
def getVisitableNodesNamed(self):
|
|
7460
|
+
"""Named children dictionary.
|
|
7461
|
+
|
|
7462
|
+
For use in cloning nodes, debugging and XML output.
|
|
7463
|
+
"""
|
|
7464
|
+
|
|
7465
|
+
return (
|
|
7466
|
+
("file", self.subnode_file),
|
|
7467
|
+
("mode", self.subnode_mode),
|
|
7468
|
+
("buffering", self.subnode_buffering),
|
|
7469
|
+
("encoding", self.subnode_encoding),
|
|
7470
|
+
("errors", self.subnode_errors),
|
|
7471
|
+
("newline", self.subnode_newline),
|
|
7472
|
+
("closefd", self.subnode_closefd),
|
|
7473
|
+
("opener", self.subnode_opener),
|
|
7474
|
+
)
|
|
7475
|
+
|
|
7476
|
+
def replaceChild(self, old_node, new_node):
|
|
7477
|
+
value = self.subnode_file
|
|
7478
|
+
if old_node is value:
|
|
7479
|
+
new_node.parent = self
|
|
7480
|
+
|
|
7481
|
+
self.subnode_file = new_node
|
|
7482
|
+
|
|
7483
|
+
return
|
|
7484
|
+
|
|
7485
|
+
value = self.subnode_mode
|
|
7486
|
+
if old_node is value:
|
|
7487
|
+
if new_node is not None:
|
|
7488
|
+
new_node.parent = self
|
|
7489
|
+
|
|
7490
|
+
self.subnode_mode = new_node
|
|
7491
|
+
|
|
7492
|
+
return
|
|
7493
|
+
|
|
7494
|
+
value = self.subnode_buffering
|
|
7495
|
+
if old_node is value:
|
|
7496
|
+
if new_node is not None:
|
|
7497
|
+
new_node.parent = self
|
|
7498
|
+
|
|
7499
|
+
self.subnode_buffering = new_node
|
|
7500
|
+
|
|
7501
|
+
return
|
|
7502
|
+
|
|
7503
|
+
value = self.subnode_encoding
|
|
7504
|
+
if old_node is value:
|
|
7505
|
+
if new_node is not None:
|
|
7506
|
+
new_node.parent = self
|
|
7507
|
+
|
|
7508
|
+
self.subnode_encoding = new_node
|
|
7509
|
+
|
|
7510
|
+
return
|
|
7511
|
+
|
|
7512
|
+
value = self.subnode_errors
|
|
7513
|
+
if old_node is value:
|
|
7514
|
+
if new_node is not None:
|
|
7515
|
+
new_node.parent = self
|
|
7516
|
+
|
|
7517
|
+
self.subnode_errors = new_node
|
|
7518
|
+
|
|
7519
|
+
return
|
|
7520
|
+
|
|
7521
|
+
value = self.subnode_newline
|
|
7522
|
+
if old_node is value:
|
|
7523
|
+
if new_node is not None:
|
|
7524
|
+
new_node.parent = self
|
|
7525
|
+
|
|
7526
|
+
self.subnode_newline = new_node
|
|
7527
|
+
|
|
7528
|
+
return
|
|
7529
|
+
|
|
7530
|
+
value = self.subnode_closefd
|
|
7531
|
+
if old_node is value:
|
|
7532
|
+
if new_node is not None:
|
|
7533
|
+
new_node.parent = self
|
|
7534
|
+
|
|
7535
|
+
self.subnode_closefd = new_node
|
|
7536
|
+
|
|
7537
|
+
return
|
|
7538
|
+
|
|
7539
|
+
value = self.subnode_opener
|
|
7540
|
+
if old_node is value:
|
|
7541
|
+
if new_node is not None:
|
|
7542
|
+
new_node.parent = self
|
|
7543
|
+
|
|
7544
|
+
self.subnode_opener = new_node
|
|
7545
|
+
|
|
7546
|
+
return
|
|
7547
|
+
|
|
7548
|
+
raise AssertionError("Didn't find child", old_node, "in", self)
|
|
7549
|
+
|
|
7550
|
+
def getCloneArgs(self):
|
|
7551
|
+
"""Get clones of all children to pass for a new node.
|
|
7552
|
+
|
|
7553
|
+
Needs to make clones of child nodes too.
|
|
7554
|
+
"""
|
|
7555
|
+
|
|
7556
|
+
values = {
|
|
7557
|
+
"file": self.subnode_file.makeClone(),
|
|
7558
|
+
"mode": self.subnode_mode.makeClone()
|
|
7559
|
+
if self.subnode_mode is not None
|
|
7560
|
+
else None,
|
|
7561
|
+
"buffering": self.subnode_buffering.makeClone()
|
|
7562
|
+
if self.subnode_buffering is not None
|
|
7563
|
+
else None,
|
|
7564
|
+
"encoding": self.subnode_encoding.makeClone()
|
|
7565
|
+
if self.subnode_encoding is not None
|
|
7566
|
+
else None,
|
|
7567
|
+
"errors": self.subnode_errors.makeClone()
|
|
7568
|
+
if self.subnode_errors is not None
|
|
7569
|
+
else None,
|
|
7570
|
+
"newline": self.subnode_newline.makeClone()
|
|
7571
|
+
if self.subnode_newline is not None
|
|
7572
|
+
else None,
|
|
7573
|
+
"closefd": self.subnode_closefd.makeClone()
|
|
7574
|
+
if self.subnode_closefd is not None
|
|
7575
|
+
else None,
|
|
7576
|
+
"opener": self.subnode_opener.makeClone()
|
|
7577
|
+
if self.subnode_opener is not None
|
|
7578
|
+
else None,
|
|
7579
|
+
}
|
|
7580
|
+
|
|
7581
|
+
values.update(self.getDetails())
|
|
7582
|
+
|
|
7583
|
+
return values
|
|
7584
|
+
|
|
7585
|
+
def finalize(self):
|
|
7586
|
+
del self.parent
|
|
7587
|
+
|
|
7588
|
+
self.subnode_file.finalize()
|
|
7589
|
+
del self.subnode_file
|
|
7590
|
+
if self.subnode_mode is not None:
|
|
7591
|
+
self.subnode_mode.finalize()
|
|
7592
|
+
del self.subnode_mode
|
|
7593
|
+
if self.subnode_buffering is not None:
|
|
7594
|
+
self.subnode_buffering.finalize()
|
|
7595
|
+
del self.subnode_buffering
|
|
7596
|
+
if self.subnode_encoding is not None:
|
|
7597
|
+
self.subnode_encoding.finalize()
|
|
7598
|
+
del self.subnode_encoding
|
|
7599
|
+
if self.subnode_errors is not None:
|
|
7600
|
+
self.subnode_errors.finalize()
|
|
7601
|
+
del self.subnode_errors
|
|
7602
|
+
if self.subnode_newline is not None:
|
|
7603
|
+
self.subnode_newline.finalize()
|
|
7604
|
+
del self.subnode_newline
|
|
7605
|
+
if self.subnode_closefd is not None:
|
|
7606
|
+
self.subnode_closefd.finalize()
|
|
7607
|
+
del self.subnode_closefd
|
|
7608
|
+
if self.subnode_opener is not None:
|
|
7609
|
+
self.subnode_opener.finalize()
|
|
7610
|
+
del self.subnode_opener
|
|
7611
|
+
|
|
7612
|
+
def computeExpressionRaw(self, trace_collection):
|
|
7613
|
+
"""Compute an expression.
|
|
7614
|
+
|
|
7615
|
+
Default behavior is to just visit the child expressions first, and
|
|
7616
|
+
then the node "computeExpression". For a few cases this needs to
|
|
7617
|
+
be overloaded, e.g. conditional expressions.
|
|
7618
|
+
"""
|
|
7619
|
+
|
|
7620
|
+
# First apply the sub-expressions, as they are evaluated before
|
|
7621
|
+
# the actual operation.
|
|
7622
|
+
for count, sub_expression in enumerate(self.getVisitableNodes()):
|
|
7623
|
+
expression = trace_collection.onExpression(sub_expression)
|
|
7624
|
+
|
|
7625
|
+
if expression.willRaiseAnyException():
|
|
7626
|
+
sub_expressions = self.getVisitableNodes()
|
|
7627
|
+
|
|
7628
|
+
wrapped_expression = wrapExpressionWithSideEffects(
|
|
7629
|
+
side_effects=sub_expressions[:count],
|
|
7630
|
+
old_node=sub_expression,
|
|
7631
|
+
new_node=expression,
|
|
7632
|
+
)
|
|
7633
|
+
|
|
7634
|
+
return (
|
|
7635
|
+
wrapped_expression,
|
|
7636
|
+
"new_raise",
|
|
7637
|
+
lambda: "For '%s' the child expression '%s' will raise."
|
|
7638
|
+
% (self.getChildNameNice(), expression.getChildNameNice()),
|
|
7639
|
+
)
|
|
7640
|
+
|
|
7641
|
+
# Then ask ourselves to work on it.
|
|
7642
|
+
return self.computeExpression(trace_collection)
|
|
7643
|
+
|
|
7644
|
+
def collectVariableAccesses(self, emit_read, emit_write):
|
|
7645
|
+
"""Collect variable reads and writes of child nodes."""
|
|
7646
|
+
|
|
7647
|
+
self.subnode_file.collectVariableAccesses(emit_read, emit_write)
|
|
7648
|
+
subnode_mode = self.subnode_mode
|
|
7649
|
+
|
|
7650
|
+
if subnode_mode is not None:
|
|
7651
|
+
self.subnode_mode.collectVariableAccesses(emit_read, emit_write)
|
|
7652
|
+
subnode_buffering = self.subnode_buffering
|
|
7653
|
+
|
|
7654
|
+
if subnode_buffering is not None:
|
|
7655
|
+
self.subnode_buffering.collectVariableAccesses(emit_read, emit_write)
|
|
7656
|
+
subnode_encoding = self.subnode_encoding
|
|
7657
|
+
|
|
7658
|
+
if subnode_encoding is not None:
|
|
7659
|
+
self.subnode_encoding.collectVariableAccesses(emit_read, emit_write)
|
|
7660
|
+
subnode_errors = self.subnode_errors
|
|
7661
|
+
|
|
7662
|
+
if subnode_errors is not None:
|
|
7663
|
+
self.subnode_errors.collectVariableAccesses(emit_read, emit_write)
|
|
7664
|
+
subnode_newline = self.subnode_newline
|
|
7665
|
+
|
|
7666
|
+
if subnode_newline is not None:
|
|
7667
|
+
self.subnode_newline.collectVariableAccesses(emit_read, emit_write)
|
|
7668
|
+
subnode_closefd = self.subnode_closefd
|
|
7669
|
+
|
|
7670
|
+
if subnode_closefd is not None:
|
|
7671
|
+
self.subnode_closefd.collectVariableAccesses(emit_read, emit_write)
|
|
7672
|
+
subnode_opener = self.subnode_opener
|
|
7673
|
+
|
|
7674
|
+
if subnode_opener is not None:
|
|
7675
|
+
self.subnode_opener.collectVariableAccesses(emit_read, emit_write)
|
|
7676
|
+
|
|
7677
|
+
|
|
7678
|
+
# Assign the names that are easier to import with a stable name.
|
|
7679
|
+
ChildrenExpressionBuiltinsOpenMixin = ChildrenHavingFileModeOptionalBufferingOptionalEncodingOptionalErrorsOptionalNewlineOptionalClosefdOptionalOpenerOptionalMixin
|
|
7680
|
+
|
|
7681
|
+
|
|
7358
7682
|
class ChildrenHavingFilenameModeOptionalBufferingOptionalMixin(object):
|
|
7359
7683
|
# Mixins are not allowed to specify slots, pylint: disable=assigning-non-slot
|
|
7360
7684
|
__slots__ = ()
|