1# Copyright 2021, Kay Hayen, mailto:kay.hayen@gmail.com 2# 3# Part of "Nuitka", an optimizing Python compiler that is compatible and 4# integrates with CPython, but also works on its own. 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18""" 19Namespace packages of Python3.3 or higher 20 21""" 22 23import os 24 25from nuitka import Options 26from nuitka.nodes.AssignNodes import StatementAssignmentVariableName 27from nuitka.nodes.AttributeNodes import ExpressionAttributeLookup 28from nuitka.nodes.CallNodes import ExpressionCallNoKeywords 29from nuitka.nodes.ConstantRefNodes import makeConstantRefNode 30from nuitka.nodes.ContainerMakingNodes import ( 31 makeExpressionMakeList, 32 makeExpressionMakeTuple, 33 makeExpressionMakeTupleOrConstant, 34) 35from nuitka.nodes.DictionaryNodes import StatementDictOperationSet 36from nuitka.nodes.FutureSpecs import FutureSpec 37from nuitka.nodes.ImportNodes import ( 38 ExpressionImportModuleNameHard, 39 ExpressionImportName, 40 makeExpressionAbsoluteImportNode, 41) 42from nuitka.nodes.ModuleAttributeNodes import ( 43 ExpressionModuleAttributeFileRef, 44 ExpressionNuitkaLoaderCreation, 45) 46from nuitka.nodes.ModuleNodes import CompiledPythonPackage 47from nuitka.nodes.SubscriptNodes import ExpressionSubscriptLookup 48from nuitka.nodes.VariableRefNodes import ExpressionVariableNameRef 49from nuitka.PythonVersions import python_version 50 51from .TreeHelpers import makeStatementsSequenceFromStatement 52from .VariableClosure import completeVariableClosures 53 54 55def _makeCall(module_name, import_name, attribute_name, source_ref, *args): 56 return ExpressionCallNoKeywords( 57 called=ExpressionAttributeLookup( 58 expression=ExpressionImportModuleNameHard( 59 module_name=module_name, import_name=import_name, source_ref=source_ref 60 ), 61 attribute_name=attribute_name, 62 source_ref=source_ref, 63 ), 64 args=makeExpressionMakeTupleOrConstant( 65 elements=args, user_provided=True, source_ref=source_ref 66 ), 67 source_ref=source_ref, 68 ) 69 70 71def getNameSpacePathExpression(package, source_ref): 72 """Create the __path__ expression for a package.""" 73 74 reference_mode = Options.getFileReferenceMode() 75 76 if reference_mode == "original": 77 return makeConstantRefNode( 78 constant=[package.getCompileTimeDirectory()], 79 source_ref=source_ref, 80 ) 81 elif reference_mode == "frozen": 82 return makeConstantRefNode( 83 constant=[], 84 source_ref=source_ref, 85 ) 86 else: 87 elements = [ 88 ExpressionCallNoKeywords( 89 called=ExpressionAttributeLookup( 90 expression=ExpressionImportModuleNameHard( 91 module_name="os", import_name="path", source_ref=source_ref 92 ), 93 attribute_name="dirname", 94 source_ref=source_ref, 95 ), 96 args=makeExpressionMakeTuple( 97 elements=( 98 ExpressionModuleAttributeFileRef( 99 variable=package.getVariableForReference("__file__"), 100 source_ref=source_ref, 101 ), 102 ), 103 source_ref=source_ref, 104 ), 105 source_ref=source_ref, 106 ) 107 ] 108 109 if package.canHaveExternalImports(): 110 parts = package.getFullName().asString().split(".") 111 112 for count in range(len(parts)): 113 path_part = _makeCall( 114 "os", 115 "environ", 116 "get", 117 source_ref, 118 makeConstantRefNode( 119 constant="NUITKA_PACKAGE_%s" % "_".join(parts[: count + 1]), 120 source_ref=source_ref, 121 ), 122 makeConstantRefNode(constant="/notexist", source_ref=source_ref), 123 ) 124 125 if parts[count + 1 :]: 126 path_part = _makeCall( 127 "os", 128 "path", 129 "join", 130 source_ref, 131 path_part, 132 makeConstantRefNode( 133 constant=os.path.join(*parts[count + 1 :]), 134 source_ref=source_ref, 135 ), 136 ) 137 138 elements.append(path_part) 139 140 return makeExpressionMakeList(elements=elements, source_ref=source_ref) 141 142 143def createPathAssignment(package, source_ref): 144 return StatementAssignmentVariableName( 145 provider=package, 146 variable_name="__path__", 147 source=getNameSpacePathExpression(package=package, source_ref=source_ref), 148 source_ref=source_ref, 149 ) 150 151 152def createPython3NamespacePath(package, source_ref): 153 return StatementAssignmentVariableName( 154 provider=package, 155 variable_name="__path__", 156 source=ExpressionCallNoKeywords( 157 called=ExpressionImportName( 158 module=makeExpressionAbsoluteImportNode( 159 module_name="_frozen_importlib" 160 if python_version < 0x350 161 else "_frozen_importlib_external", 162 source_ref=source_ref, 163 ), 164 import_name="_NamespacePath", 165 level=0, 166 source_ref=source_ref, 167 ), 168 args=makeExpressionMakeTupleOrConstant( 169 elements=( 170 makeConstantRefNode( 171 constant=package.getFullName().asString(), 172 user_provided=True, 173 source_ref=source_ref, 174 ), 175 getNameSpacePathExpression(package=package, source_ref=source_ref), 176 makeConstantRefNode(constant=None, source_ref=source_ref), 177 ), 178 user_provided=True, 179 source_ref=source_ref, 180 ), 181 source_ref=source_ref, 182 ), 183 source_ref=source_ref, 184 ) 185 186 187def createNamespacePackage(module_name, is_top, source_ref): 188 package = CompiledPythonPackage( 189 module_name=module_name, 190 is_top=is_top, 191 mode="compiled", 192 future_spec=FutureSpec(), 193 source_ref=source_ref, 194 ) 195 196 if python_version >= 0x300: 197 statement = createPython3NamespacePath(package=package, source_ref=source_ref) 198 else: 199 statement = createPathAssignment(package, source_ref) 200 201 package.setChild("body", makeStatementsSequenceFromStatement(statement=statement)) 202 203 completeVariableClosures(package) 204 205 return package 206 207 208def createImporterCacheAssignment(package, source_ref): 209 return StatementDictOperationSet( 210 dict_arg=ExpressionImportModuleNameHard( 211 module_name="sys", import_name="path_importer_cache", source_ref=source_ref 212 ), 213 key=ExpressionSubscriptLookup( 214 expression=ExpressionVariableNameRef( 215 provider=package, variable_name="__path__", source_ref=source_ref 216 ), 217 subscript=makeConstantRefNode(constant=0, source_ref=source_ref), 218 source_ref=source_ref, 219 ), 220 value=ExpressionNuitkaLoaderCreation(provider=package, source_ref=source_ref), 221 source_ref=source_ref, 222 ) 223