def diffRecursive(dir1, dir2): done = set() result = False for path1, filename in listDir(dir1): path2 = os.path.join(dir2, filename) done.add(path1) # Skip these binary files and scons build database of course. if filename.endswith((".o", ".os", ".obj", ".dblite")): continue # Skip if filename == ".sconsign": continue if not os.path.exists(path2): sys.exit("Only in %s: %s" % (dir1, filename)) if os.path.isdir(path1): r = diffRecursive(path1, path2) if r: result = True elif os.path.isfile(path1): fromdate = time.ctime(os.stat(path1).st_mtime) todate = time.ctime(os.stat(path2).st_mtime) diff = difflib.unified_diff( a = readSource(path1).splitlines(), b = readSource(path2).splitlines(), fromfile = path1, tofile = path2, fromfiledate = fromdate, tofiledate = todate, n = 3 ) diff_list = list(diff) if diff_list : for line in diff_list : my_print(line) result = True else: assert False, path1 for path1, filename in listDir(dir2): path2 = os.path.join(dir2, filename) if path1 in done: continue if not os.path.exists(path1): sys.exit("Only in %s: %s" % (dir2, filename)) return result
def _getNumpyCoreBinaries(numpy_dir): """Return any binaries in numpy package. Notes: This covers the special cases like MKL binaries. Returns: tuple of abspaths of binaries. """ numpy_core_dir = os.path.join(numpy_dir, "core") # first look in numpy/.libs for binaries libdir = os.path.join(numpy_dir, ".libs" if not isMacOS() else ".dylibs") if os.path.isdir(libdir): for full_path, filename in listDir(libdir): yield full_path, filename # Then look for libraries in numpy.core package path # should already return the MKL files in ordinary cases re_anylib = re.compile(r"\w+\.(?:dll|so|dylib)", re.IGNORECASE) for full_path, filename in listDir(numpy_core_dir): if not re_anylib.match(filename): continue yield full_path, filename # Also look for MKL libraries in folder "above" numpy. # This should meet the layout of Anaconda installs. base_prefix = getSystemPrefixPath() if isWin32Windows(): lib_dir = os.path.join(base_prefix, "Library", "bin") else: lib_dir = os.path.join(base_prefix, "lib") if os.path.isdir(lib_dir): re_mkllib = re.compile(r"^(?:lib)?mkl\w+\.(?:dll|so|dylib)", re.IGNORECASE) for full_path, filename in listDir(lib_dir): if isWin32Windows(): if not ( filename.startswith(("libi", "libm", "mkl")) and filename.endswith(".dll") ): continue else: if not re_mkllib.match(filename): continue yield full_path, filename
def detectPthImportedPackages(): if not hasattr(sys.modules["site"], "getsitepackages"): return () pth_imports = set() for prefix in sys.modules["site"].getsitepackages(): if not os.path.isdir(prefix): continue for path, filename in listDir(prefix): if filename.endswith(".pth"): try: for line in getFileContentByLine(path, "rU"): if line.startswith("import "): if ";" in line: line = line[:line.find(";")] for part in line[7:].split(","): pth_imports.add(part.strip()) except OSError: warning( "Python installation problem, cannot read file '%s'.") return tuple(sorted(pth_imports))
def compileAndCompareWith(nuitka): if "PYTHONHASHSEED" not in os.environ: os.environ["PYTHONHASHSEED"] = '0' base_dir = os.path.join("..", "..") for package in PACKAGE_LIST: package = package.replace('/', os.path.sep) source_dir = os.path.join(base_dir, package) for path, filename in listDir(source_dir): if not filename.endswith(".py"): continue if filename.startswith(".#"): continue path = os.path.join(source_dir, filename) if filename != "__init__.py": my_print("Compiling '%s'." % path) target = filename.replace(".py", ".build") target_dir = os.path.join(tmp_dir, target) removeDirectory( path = target_dir, ignore_errors = False ) command = [ nuitka, "--module", "--recurse-none", "--plugin-enable=pylint-warnings", "--output-dir=%s"% tmp_dir, "--no-pyi-file", path ] command += os.environ.get("NUITKA_EXTRA_OPTIONS", "").split() result = subprocess.call( command ) if result != 0: sys.exit(result) diffRecursive(os.path.join(package, target), target_dir) shutil.rmtree(target_dir) if os.name == "nt": target_filename = filename.replace(".py", ".pyd") else: target_filename = filename.replace(".py", ".so") os.unlink(os.path.join(tmp_dir, target_filename))
def checkPluginPath(plugin_filename, module_package): debug( "Checking top level plug-in path %s %s", plugin_filename, module_package ) plugin_info = considerFilename( module_filename = plugin_filename ) if plugin_info is not None: # File or package makes a difference, handle that if os.path.isfile(plugin_info[0]) or \ Importing.isPackageDir(plugin_info[0]): _checkPluginPath(plugin_filename, module_package) elif os.path.isdir(plugin_info[0]): for sub_path, sub_filename in listDir(plugin_info[0]): assert sub_filename != "__init__.py" if Importing.isPackageDir(sub_path) or \ sub_path.endswith(".py"): _checkPluginPath(sub_path, None) else: warning("Failed to include module from '%s'.", plugin_info[0]) else: warning("Failed to recurse to directory '%s'.", plugin_filename)
def _packagePmw(self, pmw_path): # From the "__init__.py" of Pwm: def _hasLoader(dirname): # @ReservedAssignment # Only accept Pmw_V_R_P with single digits, since ordering will # not work correctly with multiple digits (for example, Pmw_10_0 # will be before Pmw_9_9). if re.search("^Pmw_[0-9]_[0-9](_[0-9])?$", dirname) is not None: for suffix in (".py", ".pyc", ".pyo"): path = os.path.join(pmw_path, dirname, "lib", "PmwLoader" + suffix) if os.path.isfile(path): return 1 return 0 # This mimics the scan the __init__.py does. candidates = [] for _fullpath, candidate in listDir(pmw_path): if _hasLoader(candidate): candidates.append(candidate) candidates.sort() candidates.reverse() if not candidates: sys.exit("Error, cannot find any Pmw versions.") candidate = os.path.join(pmw_path, candidates[0], "lib") version = candidates[0][4:].replace("_", ".") return self._packagePmw2(candidate, version)
def _packagePmw(self, pmw_path): # From the "__init__.py" of Pwm: def _hasLoader(dirname): # @ReservedAssignment # Only accept Pmw_V_R_P with single digits, since ordering will # not work correctly with multiple digits (for example, Pmw_10_0 # will be before Pmw_9_9). if re.search("^Pmw_[0-9]_[0-9](_[0-9])?$", dirname) is not None: for suffix in (".py", ".pyc", ".pyo"): path = os.path.join(pmw_path, dirname, "lib", "PmwLoader" + suffix) if os.path.isfile(path): return 1 return 0 # This mimicks the scan the __init__.py does. candidates = [] for _fullpath, candidate in listDir(pmw_path): if _hasLoader(candidate): candidates.append(candidate) candidates.sort() candidates.reverse() if not candidates: sys.exit("Error, cannot find any Pmw versions.") candidate = os.path.join(pmw_path, candidates[0], "lib") version = candidates[0][4:].replace('_', '.') return self._packagePmw2(candidate, version)
def getModuleImportableFilesHash(full_name): package_name = full_name.getPackageName() paths = getPackageSearchPath(None) if package_name is not None: paths += getPackageSearchPath(package_name) all_suffixes = getAllModuleSuffixes() result_hash = hashlib.md5() for count, path in enumerate(paths): if not os.path.isdir(path): continue for fullname, filename in listDir(path): if isPackageDir(fullname) or filename.endswith(all_suffixes): entry = "%s:%s" % (count, filename) if str is not bytes: entry = entry.encode("utf8") result_hash.update(entry) return result_hash.hexdigest()
def detectPthImportedPackages(): if not hasattr(sys.modules["site"], "getsitepackages"): return () # TODO: Move hard import config to elsewhere. from nuitka.nodes.ImportNodes import isHardModuleWithoutSideEffect pth_imports = set() for prefix in sys.modules["site"].getsitepackages(): if not os.path.isdir(prefix): continue for path, filename in listDir(prefix): if filename.endswith(".pth"): try: for line in getFileContentByLine(path, "rU"): if line.startswith("import "): if ";" in line: line = line[:line.find(";")] for part in line[7:].split(","): pth_import = part.strip() if not isHardModuleWithoutSideEffect( pth_import): pth_imports.add(pth_import) except OSError: recursion_logger.warning( "Python installation problem, cannot read file '%s'.") return tuple(sorted(pth_imports))
def checkPluginPath(plugin_filename, module_package): plugin_filename = os.path.normpath(plugin_filename) if Options.isShowInclusion(): recursion_logger.info("Checking top level plug-in path %s %s" % (plugin_filename, module_package)) plugin_info = considerFilename(module_filename=plugin_filename) if plugin_info is not None: # File or package makes a difference, handle that if os.path.isfile(plugin_info[0]) or Importing.isPackageDir( plugin_info[0]): checkPluginSinglePath(plugin_filename, module_package=module_package) elif os.path.isdir(plugin_info[0]): for sub_path, sub_filename in listDir(plugin_info[0]): assert sub_filename != "__init__.py" if Importing.isPackageDir(sub_path) or sub_path.endswith( ".py"): checkPluginSinglePath(sub_path, module_package=None) else: recursion_logger.warning("Failed to include module from %r." % plugin_info[0]) else: recursion_logger.warning("Failed to recurse to directory %r." % plugin_filename)
def getScanDirectories(package_name, original_dir): # Many cases, pylint: disable=too-many-branches cache_key = package_name, original_dir if cache_key in _scan_dir_cache: return _scan_dir_cache[cache_key] scan_dirs = [sys.prefix] if package_name is not None: scan_dirs.extend(_getPackageSpecificDLLDirectories(package_name)) if original_dir is not None: scan_dirs.append(original_dir) scan_dirs.extend(getSubDirectories(original_dir)) if (Utils.isWin32Windows() and package_name is not None and package_name.isBelowNamespace("win32com")): pywin32_dir = getPyWin32Dir() if pywin32_dir is not None: scan_dirs.append(pywin32_dir) for path_dir in os.environ["PATH"].split(";"): if not os.path.isdir(path_dir): continue if areSamePaths(path_dir, os.path.join(os.environ["SYSTEMROOT"])): continue if areSamePaths(path_dir, os.path.join(os.environ["SYSTEMROOT"], "System32")): continue if areSamePaths(path_dir, os.path.join(os.environ["SYSTEMROOT"], "SysWOW64")): continue scan_dirs.append(path_dir) result = [] # Remove directories that hold no DLLs. for scan_dir in scan_dirs: sys.stdout.flush() # These are useless, but plenty. if os.path.basename(scan_dir) == "__pycache__": continue scan_dir = getDirectoryRealPath(scan_dir) # No DLLs, no use. if not any(entry[1].lower().endswith(".dll") for entry in listDir(scan_dir)): continue result.append(os.path.realpath(scan_dir)) _scan_dir_cache[cache_key] = result return result
def considerDataFiles(self, module): # Many cases to deal with, pylint: disable=too-many-branches module_name = module.getFullName() module_folder = module.getCompileTimeDirectory() if module_name in self.known_data_files: for target_dir, filename in self.known_data_files[module_name]: source_path = os.path.join(module_folder, filename) if os.path.isfile(source_path): if target_dir is None: target_dir = module_name.asPath() yield ( source_path, os.path.normpath(os.path.join(target_dir, filename)), ) if module_name in self.known_data_dirs: data_dirs = self.known_data_dirs[module_name] if type(data_dirs) is not tuple: data_dirs = (data_dirs, ) for data_dir in data_dirs: yield makeIncludedDataDirectory( os.path.join(module_folder, data_dir), os.path.join(module_name.asPath(), data_dir), "package data for %r" % module_name.asString(), ) if module_name in self.known_data_dir_structure: empty_dirs = self.known_data_dir_structure[module_name] yield _getSubDirectoryFolders(module, empty_dirs) if module_name in self.generated_data_files: for target_dir, filename, func in self.generated_data_files[ module_name]: if target_dir is None: target_dir = module_name.replace(".", os.path.sep) yield (func, os.path.normpath(os.path.join(target_dir, filename))) if module_name == "lib2to3.pgen2": # TODO: Support patterns of files in known_data_files as # that would cover this. for source_path, filename in listDir( os.path.join(module_folder, "..")): if not filename.endswith(".pickle"): continue yield makeIncludedDataFile( source_path, os.path.join("lib2to3", filename), "package data for %r" % module_name.asString(), )
def cleanSourceDirectory(source_dir): extensions = (".bin", ".c", ".cpp", ".exp", ".h", ".lib", ".manifest", ".o", ".obj", ".os", ".rc", ".res", ".S") if os.path.isdir(source_dir): for path, _filename in listDir(source_dir): if hasFilenameExtension(path, extensions): deleteFile(path, must_exist=True) else: makePath(source_dir)
def cleanSconsDirectory(source_dir): """Clean scons build directory.""" extensions = ( ".bin", ".c", ".cpp", ".exp", ".h", ".lib", ".manifest", ".o", ".obj", ".os", ".rc", ".res", ".S", ".txt", ".const", ".gcda", ".pgd", ".pgc", ) def check(path): if hasFilenameExtension(path, extensions): deleteFile(path, must_exist=True) if os.path.isdir(source_dir): for path, _filename in listDir(source_dir): check(path) static_dir = os.path.join(source_dir, "static_src") if os.path.exists(static_dir): for path, _filename in listDir(static_dir): check(path) plugins_dir = os.path.join(source_dir, "plugins") if os.path.exists(plugins_dir): for path, _filename in listDir(plugins_dir): check(path)
def scanConstFiles(build_dir): result = [] for fullpath, filename in listDir(build_dir): if not filename.endswith(".const"): continue result.append((fullpath, filename)) return result
def getScanDirectories(package_name, original_dir): cache_key = package_name, original_dir if cache_key in _scan_dir_cache: return _scan_dir_cache[cache_key] scan_dirs = [sys.prefix] if package_name is not None: from nuitka.importing.Importing import findModule package_dir = findModule(None, package_name, None, 0, False)[1] if os.path.isdir(package_dir): scan_dirs.append(package_dir) scan_dirs.extend(getSubDirectories(package_dir)) if original_dir is not None: scan_dirs.append(original_dir) scan_dirs.extend(getSubDirectories(original_dir)) for path_dir in os.environ["PATH"].split(";"): if not os.path.isdir(path_dir): continue if areSamePaths(path_dir, os.path.join(os.environ["SYSTEMROOT"])): continue if areSamePaths(path_dir, os.path.join(os.environ["SYSTEMROOT"], "System32")): continue if areSamePaths(path_dir, os.path.join(os.environ["SYSTEMROOT"], "SysWOW64")): continue scan_dirs.append(path_dir) result = [] # Remove directories that hold no DLLs. for scan_dir in scan_dirs: sys.stdout.flush() # These are useless, but plenty. if os.path.basename(scan_dir) == "__pycache__": continue # No DLLs, no use. if not any(entry[1].lower().endswith(".dll") for entry in listDir(scan_dir)): continue result.append(scan_dir) _scan_dir_cache[cache_key] = result return result
def _getScipyCoreBinaries(scipy_dir): """Return binaries from the extra-dlls folder (Windows only).""" for dll_dir_name in ("extra_dll", ".libs"): dll_dir_path = os.path.join(scipy_dir, dll_dir_name) if os.path.isdir(dll_dir_path): for source_path, source_filename in listDir(dll_dir_path): if source_filename.lower().endswith(".dll"): yield source_path, os.path.join( "scipy", dll_dir_name, source_filename )
def detectEarlyImports(): encoding_names = [ filename[:-3] for _path, filename in listDir( os.path.dirname(sys.modules["encodings"].__file__)) if filename.endswith(".py") if "__init__" not in filename ] if Utils.getOS() != "Windows": for encoding_name in ("mbcs", "cp65001", "oem"): if encoding_name in encoding_names: encoding_names.remove(encoding_name) import_code = ';'.join("import encodings.%s" % encoding_name for encoding_name in encoding_names) import_code += ";import locale;" # For Python3 we patch inspect without knowing if it is used. if python_version >= 300: import_code += "import inspect;" result = _detectImports(command=import_code, user_provided=False, technical=True) if Options.shallFreezeAllStdlib(): stdlib_modules = set() # Scan the standard library paths (multiple in case of virtualenv. for stdlib_dir in getStandardLibraryPaths(): for module_name in scanStandardLibraryPath(stdlib_dir): stdlib_modules.add(module_name) import_code = "imports = " + repr(sorted(stdlib_modules)) + '\n'\ "for imp in imports:\n" \ " try:\n" \ " __import__(imp)\n" \ " except (ImportError, SyntaxError):\n" \ " pass\n" early_names = [module.getFullName() for module in result] result += [ module for module in _detectImports( command=import_code, user_provided=False, technical=False) if module.getFullName() not in early_names ] debug("Finished detecting early imports.") return result
def runPy2dsc(filename, new_name): check_call(["py2dsc", new_name]) # Fixup for py2dsc not taking our custom suffix into account, so we need # to rename it ourselves. before_deb_name = filename[:-7].lower().replace("-", "_") after_deb_name = before_deb_name.replace("rc", "~rc") os.rename( "deb_dist/%s.orig.tar.gz" % before_deb_name, "deb_dist/%s+ds.orig.tar.gz" % after_deb_name, ) check_call(["rm -f deb_dist/*_source*"], shell=True) # Remove the now useless input, py2dsc has copied it, and we don't # publish it. os.unlink(new_name) # Assert that the unpacked directory is there and find it. Otherwise fail badly. entry = None for fullname, entry in listDir("deb_dist"): if ( os.path.isdir(fullname) and entry.startswith("nuitka") and not entry.endswith(".orig") ): break if entry is None: assert False # Import the "debian" directory from above. It's not in the original tar and # overrides fully what py2dsc did. check_call(["rm -r deb_dist/%s/debian/*" % entry], shell=True) check_call( [ "rsync", "-a", "--exclude", "pbuilder-hookdir", "../debian/", "deb_dist/%s/debian/" % entry, ] ) check_call(["rm deb_dist/*.dsc deb_dist/*.debian.tar.xz"], shell=True) return entry
def considerDataFiles(self, module): # This is considering many options, pylint: disable=too-many-branches module_name = module.getFullName() module_folder = module.getCompileTimeDirectory() if module_name in self.known_data_files: for target_dir, filename in self.known_data_files[module_name]: source_path = os.path.join(module_folder, filename) if os.path.isfile(source_path): if target_dir is None: target_dir = module_name.asPath() yield ( source_path, os.path.normpath(os.path.join(target_dir, filename)), ) if module_name in self.known_data_folders: func, subdir, folders_only = self.known_data_folders[module_name] if folders_only: yield func(module, subdir, folders_only) else: for item in func(module, subdir, folders_only): yield item if module_name in self.generated_data_files: for target_dir, filename, func in self.generated_data_files[ module_name]: if target_dir is None: target_dir = module_name.replace(".", os.path.sep) yield (func, os.path.normpath(os.path.join(target_dir, filename))) if module_name == "lib2to3.pgen2": for source_path, filename in listDir( os.path.join(module_folder, "..")): if not filename.endswith(".pickle"): continue yield (source_path, os.path.normpath(os.path.join("lib2to3", filename)))
def checkPluginPath(plugin_filename, module_package): plugin_filename = os.path.normpath(plugin_filename) debug("Checking top level plug-in path %s %s", plugin_filename, module_package) plugin_info = considerFilename(module_filename=plugin_filename) if plugin_info is not None: # File or package makes a difference, handle that if os.path.isfile(plugin_info[0]) or Importing.isPackageDir(plugin_info[0]): checkPluginSinglePath(plugin_filename, module_package) elif os.path.isdir(plugin_info[0]): for sub_path, sub_filename in listDir(plugin_info[0]): assert sub_filename != "__init__.py" if Importing.isPackageDir(sub_path) or sub_path.endswith(".py"): checkPluginSinglePath(sub_path, None) else: warning("Failed to include module from '%s'.", plugin_info[0]) else: warning("Failed to recurse to directory '%s'.", plugin_filename)
def considerDataFiles(self, module): module_name = module.getFullName() module_folder = module.getCompileTimeDirectory() if module_name in known_data_files: for target_dir, filename in known_data_files[module_name]: source_path = os.path.join(module_folder, filename) if os.path.isfile(source_path): if target_dir is None: target_dir = module_name.replace(".", os.path.sep) yield ( source_path, os.path.normpath(os.path.join(target_dir, filename)), ) if module_name in known_data_folders: func, subdir, folders_only = known_data_folders[module_name] for item in func(module, subdir, folders_only): yield item if module_name in generated_data_files: for target_dir, filename, func in generated_data_files[ module_name]: if target_dir is None: target_dir = module_name.replace(".", os.path.sep) yield (func, os.path.normpath(os.path.join(target_dir, filename))) if module_name == "lib2to3.pgen2": for source_path, filename in listDir( os.path.join(module_folder, "..")): if not filename.endswith(".pickle"): continue yield (source_path, os.path.normpath(os.path.join("lib2to3", filename)))
def getModuleImportableFilesHash(full_name): """Calculate hash value of packages importable for a module of this name.""" package_name = full_name.getPackageName() paths = getPackageSearchPath(None) if package_name is not None: paths += getPackageSearchPath(package_name) all_suffixes = getAllModuleSuffixes() result_hash = Hash() for path in paths: if not os.path.isdir(path): continue for fullname, filename in listDir(path): if isPackageDir(fullname) or filename.endswith(all_suffixes): result_hash.updateFromValues(filename, b"\0") return result_hash.asHexDigest()
def runPy2dsc(filename, new_name): assert os.system("py2dsc " + new_name) == 0 # Fixup for py2dsc not taking our custom suffix into account, so we need # to rename it ourselves. before_deb_name = filename[:-7].lower().replace("-", "_") after_deb_name = before_deb_name.replace("rc", "~rc") assert (os.system( "mv 'deb_dist/%s.orig.tar.gz' 'deb_dist/%s+ds.orig.tar.gz'" % (before_deb_name, after_deb_name)) == 0) assert os.system("rm -f deb_dist/*_source*") == 0 # Remove the now useless input, py2dsc has copied it, and we don't # publish it. os.unlink(new_name) # Assert that the unpacked directory is there and find it. Otherwise fail badly. entry = None for fullname, entry in listDir("deb_dist"): if (os.path.isdir(fullname) and entry.startswith("nuitka") and not entry.endswith(".orig")): break if entry is None: assert False # Import the "debian" directory from above. It's not in the original tar and # overrides fully what py2dsc did. assert os.system("rm -r deb_dist/%s/debian/*" % entry) == 0 assert (os.system( "rsync -a --exclude pbuilder-hookdir ../debian/ deb_dist/%s/debian/" % entry) == 0) assert os.system("rm deb_dist/*.dsc deb_dist/*.debian.tar.xz") == 0 return entry
def _packagePmw(self, pmw_path): self.info("Packaging Pmw into single module fpor freezing.") # Algorithm is from the "__init__.py" of Pwm: def _hasLoader(dirname): # Only accept Pmw_V_R_P with single digits, since ordering will # not work correctly with multiple digits (for example, Pmw_10_0 # will be before Pmw_9_9). if re.search("^Pmw_[0-9]_[0-9](_[0-9])?$", dirname) is not None: for suffix in (".py", ".pyc", ".pyo"): path = os.path.join(pmw_path, dirname, "lib", "PmwLoader" + suffix) if os.path.isfile(path): return 1 return 0 # This mimics the scan the __init__.py does. candidates = [] for _fullpath, candidate in listDir(pmw_path): if _hasLoader(candidate): candidates.append(candidate) candidates.sort() candidates.reverse() if not candidates: self.sysexit("Error, cannot find any Pmw versions.") self.info("Found the following Pmw version candidates %s." % ",".join(candidates)) candidate = os.path.join(pmw_path, candidates[0], "lib") version = candidates[0][4:].replace("_", ".") self.info("Picked version %s." % version) return self._packagePmw2(candidate, version)
def cleanSourceDirectory(source_dir): extensions = ( ".bin", ".c", ".cpp", ".exp", ".h", ".lib", ".manifest", ".o", ".obj", ".os", ".rc", ".res", ".S", ".txt", ) if os.path.isdir(source_dir): for path, _filename in listDir(source_dir): if hasFilenameExtension(path, extensions): deleteFile(path, must_exist=True) else: makePath(source_dir)
def detectPthImportedPackages(): if not hasattr(sys.modules["site"], "getsitepackages"): return () pth_imports = set() for prefix in sys.modules["site"].getsitepackages(): if not os.path.isdir(prefix): continue for path, filename in listDir(prefix): if filename.endswith(".pth"): try: for line in getFileContentByLine(path, "rU"): if line.startswith("import "): if ";" in line: line = line[: line.find(";")] for part in line[7:].split(","): pth_imports.add(part.strip()) except OSError: warning("Python installation problem, cannot read file '%s'.") return tuple(sorted(pth_imports))
def executePASS1(): my_print("PASS 1: Compiling from compiler running from .py files.") base_dir = os.path.join("..", "..") for package in PACKAGE_LIST: package = package.replace('/', os.path.sep) source_dir = os.path.join(base_dir, package) target_dir = package removeDirectory( path = target_dir, ignore_errors = False ) os.mkdir(target_dir) for path, filename in listDir(target_dir): if filename.endswith(".so"): os.unlink(path) for path, filename in listDir(source_dir): if not filename.endswith(".py"): continue if filename.startswith(".#"): continue if filename != "__init__.py": my_print("Compiling '%s'." % path) command = [ os.environ["PYTHON"], nuitka_main_path, "--module", "--plugin-enable=pylint-warnings", "--output-dir=%s" % target_dir, "--no-pyi-file", path ] command += os.environ.get("NUITKA_EXTRA_OPTIONS", "").split() result = subprocess.call( command ) if result != 0: sys.exit(result) else: shutil.copyfile(path, os.path.join(target_dir, filename)) my_print("Compiling '%s'." % nuitka_main_path) shutil.copyfile(nuitka_main_path, "nuitka-runner.py") command = [ os.environ["PYTHON"], nuitka_main_path, "--nofollow-imports", "--plugin-enable=pylint-warnings", "--output-dir=.", "--python-flag=-S", "nuitka-runner.py" ] command += os.environ.get("NUITKA_EXTRA_OPTIONS", "").split() result = subprocess.call( command ) if result != 0: sys.exit(result) shutil.move("nuitka-runner" + exe_suffix, "nuitka" + exe_suffix) scons_inline_copy_path = os.path.join( base_dir, "nuitka", "build", "inline_copy" ) if os.path.exists(scons_inline_copy_path): shutil.copytree( scons_inline_copy_path, os.path.join("nuitka", "build", "inline_copy") ) shutil.copyfile( os.path.join(base_dir, "nuitka", "build", "SingleExe.scons"), os.path.join("nuitka", "build", "SingleExe.scons") ) shutil.copytree( os.path.join(base_dir, "nuitka", "build", "static_src"), os.path.join("nuitka", "build", "static_src") ) shutil.copytree( os.path.join(base_dir, "nuitka", "build", "include"), os.path.join("nuitka", "build", "include") )
def _detectBinaryPathDLLsWindows(is_main_executable, source_dir, original_dir, binary_filename, package_name): # This is complex, as it also includes the caching mechanism # pylint: disable=too-many-locals result = set() cache_filename = _getCacheFilename(is_main_executable, source_dir, original_dir, binary_filename) if os.path.exists(cache_filename ) and not Options.shallNotUseDependsExeCachedResults(): for line in open(cache_filename): line = line.strip() result.add(line) return result # User query should only happen once if at all. with _withLock(): depends_exe = getDependsExePath() scan_dirs = [sys.prefix] if package_name is not None: from nuitka.importing.Importing import findModule package_dir = findModule(None, package_name, None, 0, False)[1] if os.path.isdir(package_dir): scan_dirs.append(package_dir) scan_dirs.extend(getSubDirectories(package_dir)) if original_dir is not None: scan_dirs.append(original_dir) scan_dirs.extend(getSubDirectories(original_dir)) with _withLock(): # The search order by default prefers the system directory, where a # wrong "PythonXX.dll" might be living. with open(binary_filename + ".dwp", 'w') as dwp_file: dwp_file.write( """\ KnownDLLs %(original_dirs)s SysPath 32BitSysDir 16BitSysDir OSDir AppPath SxS """ % { "original_dirs": '\n'.join("UserDir %s" % dirname for dirname in scan_dirs if not os.path.basename(dirname) == "__pycache__" if any(entry[1].lower().endswith(".dll") for entry in listDir(dirname))), }) # Starting the process while locked, so file handles are not duplicated. depends_exe_process = subprocess.Popen( (depends_exe, "-c", "-ot%s" % binary_filename + ".depends", "-d:%s" % binary_filename + ".dwp", "-f1", "-pa1", "-ps1", binary_filename)) # TODO: Exit code should be checked. depends_exe_process.wait() # Opening the result under lock, so it is not getting locked by new processes. with _withLock(): _parseDependsExeOutput(binary_filename + ".depends", result) deleteFile(binary_filename + ".depends", must_exist=True) deleteFile(binary_filename + ".dwp", must_exist=True) if not Options.shallNotStoreDependsExeCachedResults(): with open(cache_filename, 'w') as cache_file: for dll_filename in result: print(dll_filename, file=cache_file) return result
def detectEarlyImports(): encoding_names = [ filename[:-3] for _path, filename in listDir( os.path.dirname(sys.modules["encodings"].__file__)) if filename.endswith(".py") if "__init__" not in filename ] if Utils.getOS() != "Windows": for encoding_name in ("mbcs", "cp65001", "oem"): if encoding_name in encoding_names: encoding_names.remove(encoding_name) import_code = ';'.join("import encodings.%s" % encoding_name for encoding_name in encoding_names) import_code += ";import locale;" # For Python3 we patch inspect without knowing if it is used. if python_version >= 300: import_code += "import inspect;" result = _detectImports(command=import_code, user_provided=False, technical=True) if Options.shallFreezeAllStdlib(): stdlib_modules = set() # Scan the standard library paths (multiple in case of virtualenv. for stdlib_dir in getStandardLibraryPaths(): for module_name in scanStandardLibraryPath(stdlib_dir): stdlib_modules.add(module_name) # Put here ones that should be imported first. first_ones = ("Tkinter", ) # We have to fight zombie modules in this, some things, e.g. Tkinter # on newer Python 2.7, comes back after failure without a second error # being raised, leading to other issues. So we fight it after each # module that was tried, and prevent re-try by adding a meta path # based loader that will never load it again, and remove it from the # "sys.modules" over and over, once it sneaks back. The root cause is # that extension modules sometimes only raise an error when first # imported, not the second time around. # Otherwise this just makes imports of everything so we can see where # it comes from and what it requires. import_code = """ imports = %r failed = set() class ImportBlocker(object): def find_module(self, fullname, path = None): if fullname in failed: return self return None def load_module(self, name): raise ImportError("%%s has failed before" %% name) sys.meta_path.insert(0, ImportBlocker()) for imp in imports: try: __import__(imp) except (ImportError, SyntaxError): failed.add(imp) for fail in failed: if fail in sys.modules: del sys.modules[fail] """ % sorted(stdlib_modules, key=lambda name: (name not in first_ones, name)) early_names = [module.getFullName() for module in result] result += [ module for module in _detectImports( command=import_code, user_provided=False, technical=False) if module.getFullName() not in early_names ] debug("Finished detecting early imports.") return result
def _findModuleInPath2(module_name, search_path): """ This is out own module finding low level implementation. Just the full module name and search path are given. This is then tasked to raise "ImportError" or return a path if it finds it, or None, if it is a built-in. """ # We have many branches here, because there are a lot of cases to try. # pylint: disable=too-many-branches # We may have to decide between package and module, therefore build # a list of candidates. candidates = oset.OrderedSet() considered = set() for entry in search_path: # Don't try again, just with an entry of different casing or complete # duplicate. if os.path.normcase(entry) in considered: continue considered.add(os.path.normcase(entry)) package_directory = os.path.join(entry, module_name) # First, check for a package with an init file, that would be the # first choice. if os.path.isdir(package_directory): for suffix in (".py", ".pyc"): package_file_name = "__init__" + suffix file_path = os.path.join(package_directory, package_file_name) if os.path.isfile(file_path): candidates.add( (entry, 1, package_directory) ) break else: if python_version >= 330: candidates.add( (entry, 2, package_directory) ) # Then, check out suffixes of all kinds. for suffix, _mode, _type in imp.get_suffixes(): file_path = os.path.join(entry, module_name + suffix) if os.path.isfile(file_path): candidates.add( (entry, 1, file_path) ) break if _debug_module_finding: print("Candidates", candidates) if candidates: # Ignore lower priority matches from package directories without # "__init__.py" file. min_prio = min(candidate[1] for candidate in candidates) candidates = [ candidate for candidate in candidates if candidate[1] == min_prio ] # On case sensitive systems, no resolution needed. if case_sensitive: return candidates[0][2] else: for candidate in candidates: for fullname, _filename in listDir(candidate[0]): if fullname == candidate[2]: return candidate[2] # Only exact case matches matter, all candidates were ignored, # lets just fall through to raising the import error. # Nothing found. raise ImportError
def diffRecursive(dir1, dir2): # Complex in nature, pylint: disable=too-many-branches done = set() result = False for path1, filename in listDir(dir1): if "cache-" in path1: continue path2 = os.path.join(dir2, filename) done.add(path1) # Skip these binary files and scons build database of course. # TODO: Temporary ignore ".bin", until we have something better than marshal which behaves # differently in compiled Nuitka: if filename.endswith( ( ".o", ".os", ".obj", ".dblite", ".tmp", ".sconsign", ".txt", ".bin", ".const", ".exp", ) ): continue if not os.path.exists(path2): my_print("Only in %s: %s" % (dir1, filename)) result = False continue if os.path.isdir(path1): r = diffRecursive(path1, path2) if r: result = True elif os.path.isfile(path1): fromdate = time.ctime(os.stat(path1).st_mtime) todate = time.ctime(os.stat(path2).st_mtime) diff = difflib.unified_diff( a=readSource(path1).splitlines(), b=readSource(path2).splitlines(), fromfile=path1, tofile=path2, fromfiledate=fromdate, tofiledate=todate, n=3, ) diff_list = list(diff) if diff_list: for line in diff_list: try: my_print(line) except UnicodeEncodeError: my_print(repr(line)) result = True else: assert False, path1 for path1, filename in listDir(dir2): if "cache-" in path1: continue path2 = os.path.join(dir2, filename) if path1 in done: continue if not os.path.exists(path1): my_print("Only in %s: %s" % (dir2, filename)) result = False continue return result
def _findModuleInPath2(module_name, search_path): """ This is out own module finding low level implementation. Just the full module name and search path are given. This is then tasked to raise "ImportError" or return a path if it finds it, or None, if it is a built-in. """ # We have many branches here, because there are a lot of cases to try. # pylint: disable=too-many-branches,too-many-locals # We may have to decide between package and module, therefore build # a list of candidates. candidates = OrderedSet() considered = set() for entry in search_path: # Don't try again, just with an entry of different casing or complete # duplicate. if os.path.normcase(entry) in considered: continue considered.add(os.path.normcase(entry)) package_directory = os.path.join(entry, module_name) # First, check for a package with an init file, that would be the # first choice. if os.path.isdir(package_directory): for suffix, _mode, mtype in imp.get_suffixes(): if mtype == imp.C_EXTENSION: continue package_file_name = "__init__" + suffix file_path = os.path.join(package_directory, package_file_name) if os.path.isfile(file_path): candidates.add((entry, 1, package_directory)) break else: if python_version >= 300: candidates.add((entry, 2, package_directory)) # Then, check out suffixes of all kinds. for suffix, _mode, _type in imp.get_suffixes(): file_path = os.path.join(entry, module_name + suffix) if os.path.isfile(file_path): candidates.add((entry, 1, file_path)) break if _debug_module_finding: print("Candidates", candidates) if candidates: # Ignore lower priority matches from package directories without # "__init__.py" file. min_prio = min(candidate[1] for candidate in candidates) candidates = [candidate for candidate in candidates if candidate[1] == min_prio] # On case sensitive systems, no resolution needed. if case_sensitive: return candidates[0][2] else: for candidate in candidates: for fullname, _filename in listDir(candidate[0]): if fullname == candidate[2]: return candidate[2] # Only exact case matches matter, all candidates were ignored, # lets just fall through to raising the import error. # Nothing found. raise ImportError
def executePASS1(): my_print("PASS 1: Compiling from compiler running from .py files.") base_dir = os.path.join("..", "..") for package in PACKAGE_LIST: package = package.replace('/', os.path.sep) source_dir = os.path.join(base_dir, package) target_dir = package removeDirectory( path = target_dir, ignore_errors = False ) os.mkdir(target_dir) for path, filename in listDir(target_dir): if filename.endswith(".so"): os.unlink(path) for path, filename in listDir(source_dir): if not filename.endswith(".py"): continue if filename.startswith(".#"): continue if filename != "__init__.py": my_print("Compiling '%s'." % path) command = [ os.environ["PYTHON"], nuitka_main_path, "--module", "--recurse-none", "--plugin-enable=pylint-warnings", "--output-dir=%s" % target_dir, "--no-pyi-file", path ] command += os.environ.get("NUITKA_EXTRA_OPTIONS", "").split() result = subprocess.call( command ) if result != 0: sys.exit(result) else: shutil.copyfile(path, os.path.join(target_dir, filename)) my_print("Compiling '%s'." % nuitka_main_path) shutil.copyfile(nuitka_main_path, "nuitka-runner.py") command = [ os.environ["PYTHON"], nuitka_main_path, "--recurse-none", "--plugin-enable=pylint-warnings", "--output-dir=.", "--python-flag=-S", "nuitka-runner.py" ] command += os.environ.get("NUITKA_EXTRA_OPTIONS", "").split() result = subprocess.call( command ) if result != 0: sys.exit(result) shutil.move("nuitka-runner.exe", "nuitka.exe") scons_inline_copy_path = os.path.join( base_dir, "nuitka", "build", "inline_copy" ) if os.path.exists(scons_inline_copy_path): shutil.copytree( scons_inline_copy_path, os.path.join("nuitka", "build", "inline_copy") ) shutil.copy( os.path.join(base_dir, "nuitka", "build", "SingleExe.scons"), os.path.join("nuitka", "build", "SingleExe.scons") ) shutil.copytree( os.path.join(base_dir, "nuitka", "build", "static_src"), os.path.join("nuitka", "build", "static_src") ) shutil.copytree( os.path.join(base_dir, "nuitka", "build", "include"), os.path.join("nuitka", "build", "include") )
def compileAndCompareWith(nuitka): if "PYTHONHASHSEED" not in os.environ: os.environ["PYTHONHASHSEED"] = "0" base_dir = os.path.join("..", "..") for package in PACKAGE_LIST: package = package.replace("/", os.path.sep) source_dir = os.path.join(base_dir, package) for path, filename in listDir(source_dir): if not filename.endswith(".py"): continue if filename.startswith(".#"): continue path = os.path.join(source_dir, filename) if filename != "__init__.py": my_print("Compiling '%s'." % path) target = filename.replace(".py", ".build") target_dir = os.path.join(tmp_dir, target) removeDirectory(path=target_dir, ignore_errors=False) command = [ nuitka, "--module", "--plugin-enable=pylint-warnings", "--output-dir=%s" % tmp_dir, "--no-pyi-file", path, ] command += os.environ.get("NUITKA_EXTRA_OPTIONS", "").split() my_print("Command: ", " ".join(command)) result = subprocess.call(command) if result != 0: sys.exit(result) has_diff = diffRecursive(os.path.join(package, target), target_dir) # TODO: Temporary, until we have something better than marshal which behaves # differently in compiled Nuitka: if has_diff and filename not in ( "Contexts.py", "Whitelisting.py", "ImplicitImports.py", ): sys.exit("There were differences!") shutil.rmtree(target_dir) if os.name == "nt": target_filename = filename.replace(".py", ".pyd") else: target_filename = filename.replace(".py", ".so") os.unlink(os.path.join(tmp_dir, target_filename))
def compileAndCompareWith(nuitka): if "PYTHONHASHSEED" not in os.environ: os.environ["PYTHONHASHSEED"] = '0' base_dir = os.path.join("..", "..") for package in PACKAGE_LIST: package = package.replace('/', os.path.sep) source_dir = os.path.join(base_dir, package) for path, filename in listDir(source_dir): if not filename.endswith(".py"): continue if filename.startswith(".#"): continue path = os.path.join(source_dir, filename) if filename != "__init__.py": my_print("Compiling '%s'." % path) target = filename.replace(".py", ".build") target_dir = os.path.join(tmp_dir, target) removeDirectory( path = target_dir, ignore_errors = False ) command = [ nuitka, "--module", "--plugin-enable=pylint-warnings", "--output-dir=%s"% tmp_dir, "--no-pyi-file", path ] command += os.environ.get("NUITKA_EXTRA_OPTIONS", "").split() result = subprocess.call( command ) if result != 0: sys.exit(result) has_diff = diffRecursive(os.path.join(package, target), target_dir) if has_diff: sys.exit("There were differences!") shutil.rmtree(target_dir) if os.name == "nt": target_filename = filename.replace(".py", ".pyd") else: target_filename = filename.replace(".py", ".so") os.unlink(os.path.join(tmp_dir, target_filename))
def checkPluginSinglePath(plugin_filename, module_package): # Many branches, for the decision is very complex, pylint: disable=too-many-branches debug("Checking detail plug-in path '%s' '%s':", plugin_filename, module_package) module_name, module_kind = Importing.getModuleNameAndKindFromFilename( plugin_filename ) if module_kind is not None: decision, reason = decideRecursion( module_filename=plugin_filename, module_name=module_name, module_package=module_package, module_kind=module_kind, extra_recursion=True, ) if decision: module_relpath = relpath(plugin_filename) module, is_added = recurseTo( module_filename=plugin_filename, module_relpath=module_relpath, module_package=module_package, module_kind=module_kind, reason=reason, ) if module: if not is_added: warning( "Recursed to %s '%s' at '%s' twice.", "package" if module.isCompiledPythonPackage() else "module", module.getName(), plugin_filename, ) if not isSameModulePath(module.getFilename(), plugin_filename): warning( "Duplicate '%s' of '%s' ignored .", plugin_filename, module.getFilename(), ) return debug( "Recursed to %s %s %s", module.getName(), module.getPackage(), module, ) ImportCache.addImportedModule(module) if module.isCompiledPythonPackage(): package_filename = module.getFilename() if os.path.isdir(package_filename): # Must be a namespace package. assert python_version >= 300 package_dir = package_filename # Only include it, if it contains actual modules, which will # recurse to this one and find it again. else: package_dir = os.path.dirname(package_filename) # Real packages will always be included. ModuleRegistry.addRootModule(module) debug("Package directory %s", package_dir) for sub_path, sub_filename in listDir(package_dir): if sub_filename in ("__init__.py", "__pycache__"): continue assert sub_path != plugin_filename if Importing.isPackageDir(sub_path) or sub_path.endswith(".py"): checkPluginSinglePath(sub_path, module.getFullName()) elif module.isCompiledPythonModule(): ModuleRegistry.addRootModule(module) else: warning("Failed to include module from '%s'.", plugin_filename)
def _checkPluginPath(plugin_filename, module_package): # Many branches, for the decision is very complex, pylint: disable=too-many-branches debug("Checking detail plug-in path '%s' '%s':", plugin_filename, module_package) module_name, module_kind = Importing.getModuleNameAndKindFromFilename( plugin_filename) if module_kind is not None: decision, reason = decideRecursion(module_filename=plugin_filename, module_name=module_name, module_package=module_package, module_kind=module_kind, extra_recursion=True) if decision: module_relpath = relpath(plugin_filename) module, is_added = recurseTo(module_filename=plugin_filename, module_relpath=module_relpath, module_package=module_package, module_kind="py", reason=reason) if module: if not is_added: warning( "Recursed to %s '%s' at '%s' twice.", "package" if module.isCompiledPythonPackage() else "module", module.getName(), plugin_filename) if not isSameModulePath(module.getFilename(), plugin_filename): warning("Duplicate '%s' of '%s' ignored .", plugin_filename, module.getFilename()) return debug("Recursed to %s %s %s", module.getName(), module.getPackage(), module) ImportCache.addImportedModule(module) if module.isCompiledPythonPackage(): package_filename = module.getFilename() if os.path.isdir(package_filename): # Must be a namespace package. assert python_version >= 330 package_dir = package_filename # Only include it, if it contains actual modules, which will # recurse to this one and find it again. else: package_dir = os.path.dirname(package_filename) # Real packages will always be included. ModuleRegistry.addRootModule(module) debug("Package directory %s", package_dir) for sub_path, sub_filename in listDir(package_dir): if sub_filename in ("__init__.py", "__pycache__"): continue assert sub_path != plugin_filename if Importing.isPackageDir(sub_path) or \ sub_path.endswith(".py"): _checkPluginPath(sub_path, module.getFullName()) elif module.isCompiledPythonModule(): ModuleRegistry.addRootModule(module) else: warning("Failed to include module from '%s'.", plugin_filename)
def _findModuleInPath2(package_name, module_name, search_path): """This is out own module finding low level implementation. Just the full module name and search path are given. This is then tasked to raise "ImportError" or return a path if it finds it, or None, if it is a built-in. """ # We have many branches here, because there are a lot of cases to try. # pylint: disable=too-many-branches,too-many-locals # We may have to decide between package and module, therefore build # a list of candidates. candidates = OrderedSet() considered = set() # Higher values are lower priority. priority_map = { imp.PY_COMPILED: 3, imp.PY_SOURCE: 0 if Options.shallPreferSourcecodeOverExtensionModules() else 2, imp.C_EXTENSION: 1, } for count, entry in enumerate(search_path): # Don't try again, just with an entry of different casing or complete # duplicate. if os.path.normcase(entry) in considered: continue considered.add(os.path.normcase(entry)) package_directory = os.path.join(entry, module_name.asPath()) # First, check for a package with an init file, that would be the # first choice. if os.path.isdir(package_directory): found = False for suffix, _mode, mtype in imp.get_suffixes(): if mtype == imp.C_EXTENSION: continue package_file_name = "__init__" + suffix file_path = os.path.join(package_directory, package_file_name) if os.path.isfile(file_path): candidates.add( ImportScanFinding( found_in=entry, priority=priority_map[mtype], full_path=package_directory, search_order=count, )) found = True if not found and python_version >= 0x300: candidates.add( ImportScanFinding( found_in=entry, priority=10, full_path=package_directory, search_order=count + len(search_path), )) # Then, check out suffixes of all kinds, but only for one directory. last_mtype = 0 for suffix, _mode, mtype in imp.get_suffixes(): # Use first match per kind only. if mtype == last_mtype: continue full_path = os.path.join(entry, module_name + suffix) if os.path.isfile(full_path): candidates.add( ImportScanFinding( found_in=entry, priority=priority_map[mtype], full_path=full_path, search_order=count, )) last_mtype = mtype if _debug_module_finding: print("Candidates:", candidates) if candidates: # Sort by priority, with entries from same path element coming first, then desired type. candidates = sorted(candidates, key=lambda c: (c.search_order, c.priority)) # On case sensitive systems, no resolution needed. if case_sensitive: _reportCandidates( module_name=package_name.getChildNamed(module_name) if package_name is not None else module_name, candidate=candidates[0], candidates=candidates, ) return candidates[0].full_path else: for candidate in candidates: for fullname, _filename in listDir(candidate[0]): if fullname == candidate.full_path: _reportCandidates(module_name, candidate, candidates) return candidate.full_path # Only exact case matches matter, all candidates were ignored, # lets just fall through to raising the import error. # Nothing found. raise ImportError