Refactor: make "sys_info" an internal module, rename for clarity
- Move sys_info into an internal module to avoid having so many top level modules for Blender's internal functionality. - Rename system_info sub-modules that pre-fill URL's for clarity. - Move top-level exception handling into the operator. - Report an error if an unexpected exception occurs. - Use `Exception` instead of `BaseException` as there is no reason to catch the additional exceptions. - Remove use of sys_info from the command line example, replace with in-lined system info.
This commit is contained in:
@@ -5,25 +5,74 @@ Registering commands makes it possible to conveniently expose command line
|
||||
functionality via commands passed to (``-c`` / ``--command``).
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
def sysinfo_print():
|
||||
"""
|
||||
Report basic system information.
|
||||
"""
|
||||
|
||||
import pprint
|
||||
import platform
|
||||
import textwrap
|
||||
|
||||
width = 80
|
||||
indent = 2
|
||||
|
||||
print("Blender {:s}".format(bpy.app.version_string))
|
||||
print("Running on: {:s}-{:s}".format(platform.platform(), platform.machine()))
|
||||
print("Processors: {!r}".format(os.cpu_count()))
|
||||
print()
|
||||
|
||||
# Dump `bpy.app`.
|
||||
for attr in dir(bpy.app):
|
||||
if attr.startswith("_"):
|
||||
continue
|
||||
# Overly verbose.
|
||||
if attr in {"handlers", "build_cflags", "build_cxxflags"}:
|
||||
continue
|
||||
|
||||
value = getattr(bpy.app, attr)
|
||||
if attr.startswith("build_"):
|
||||
pass
|
||||
elif isinstance(value, tuple):
|
||||
pass
|
||||
else:
|
||||
# Otherwise ignore.
|
||||
continue
|
||||
|
||||
if isinstance(value, bytes):
|
||||
value = value.decode("utf-8", errors="ignore")
|
||||
|
||||
if isinstance(value, str):
|
||||
pass
|
||||
elif isinstance(value, tuple) and hasattr(value, "__dir__"):
|
||||
value = {
|
||||
attr_sub: value_sub
|
||||
for attr_sub in dir(value)
|
||||
# Exclude built-ins.
|
||||
if not attr_sub.startswith(("_", "n_"))
|
||||
# Exclude methods.
|
||||
if not callable(value_sub := getattr(value, attr_sub))
|
||||
}
|
||||
value = pprint.pformat(value, indent=0, width=width)
|
||||
else:
|
||||
value = pprint.pformat(value, indent=0, width=width)
|
||||
|
||||
print("{:s}:\n{:s}\n".format(attr, textwrap.indent(value, " " * indent)))
|
||||
|
||||
|
||||
def sysinfo_command(argv):
|
||||
import tempfile
|
||||
import sys_info
|
||||
|
||||
if argv and argv[0] == "--help":
|
||||
print("Print system information & exit!")
|
||||
return 0
|
||||
|
||||
with tempfile.TemporaryDirectory() as tempdir:
|
||||
filepath = os.path.join(tempdir, "system_info.txt")
|
||||
sys_info.write_sysinfo(filepath)
|
||||
with open(filepath, "r", encoding="utf-8") as fh:
|
||||
sys.stdout.write(fh.read())
|
||||
sysinfo_print()
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
BASE_DIR=$(dirname "$0")
|
||||
|
||||
PYTHON_BIN="$BASE_DIR/@BLENDER_VERSION@/python/bin/@PYTHON_EXECUTABLE_NAME_ONLY@"
|
||||
SYSTEM_INFO_STARTUP_PY="$BASE_DIR/@BLENDER_VERSION@/scripts/modules/_bpy_internal/system_info/startup.py"
|
||||
SYSTEM_INFO_STARTUP_PY="$BASE_DIR/@BLENDER_VERSION@/scripts/modules/_bpy_internal/system_info/url_prefill_startup.py"
|
||||
if test -f "$PYTHON_BIN"; then
|
||||
exec "$PYTHON_BIN" -I "$SYSTEM_INFO_STARTUP_PY"
|
||||
fi
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
BASE_DIR=$(dirname "$0")
|
||||
|
||||
PYTHON_BIN="$BASE_DIR/@BLENDER_VERSION@/python/bin/@PYTHON_EXECUTABLE_NAME_ONLY@"
|
||||
SYSTEM_INFO_STARTUP_PY="$BASE_DIR/@BLENDER_VERSION@/scripts/modules/_bpy_internal/system_info/startup.py"
|
||||
SYSTEM_INFO_STARTUP_PY="$BASE_DIR/@BLENDER_VERSION@/scripts/modules/_bpy_internal/system_info/url_prefill_startup.py"
|
||||
if test -f "$PYTHON_BIN"; then
|
||||
exec "$PYTHON_BIN" -I "$SYSTEM_INFO_STARTUP_PY"
|
||||
fi
|
||||
|
||||
@@ -5,7 +5,7 @@ set BLENDER_VERSION_FOLDER=%BLENDER_INSTALL_DIRECTORY%@BLENDER_VERSION@
|
||||
set PYTHON_BIN=%BLENDER_VERSION_FOLDER%\python\bin\@PYTHON_EXECUTABLE_NAME_ONLY@
|
||||
|
||||
if exist "%PYTHON_BIN%" (
|
||||
"%PYTHON_BIN%" -I "%BLENDER_VERSION_FOLDER%\scripts\modules\_bpy_internal\system_info\startup.py"
|
||||
"%PYTHON_BIN%" -I "%BLENDER_VERSION_FOLDER%\scripts\modules\_bpy_internal\system_info\url_prefill_startup.py"
|
||||
exit /b
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
# SPDX-FileCopyrightText: 2010-2023 Blender Authors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# Function for extracting info from Blenders system information
|
||||
# (sometimes useful to include in bug reports).
|
||||
# Called by the operator `WM_OT_sysinfo`.
|
||||
|
||||
__all__ = (
|
||||
"write",
|
||||
)
|
||||
|
||||
|
||||
def write(output):
|
||||
# Writes into `output`, a file-like object.
|
||||
|
||||
import sys
|
||||
import platform
|
||||
|
||||
import subprocess
|
||||
|
||||
import bpy
|
||||
import gpu
|
||||
|
||||
# pretty repr
|
||||
def prepr(v):
|
||||
r = repr(v)
|
||||
vt = type(v)
|
||||
if vt is bytes:
|
||||
r = r[2:-1]
|
||||
elif vt is list or vt is tuple:
|
||||
r = r[1:-1]
|
||||
return r
|
||||
|
||||
header = "= Blender {:s} System Information =\n".format(bpy.app.version_string)
|
||||
lilies = "{:s}\n\n".format((len(header) - 1) * "=")
|
||||
output.write(lilies[:-1])
|
||||
output.write(header)
|
||||
output.write(lilies)
|
||||
|
||||
def title(text):
|
||||
return "\n{:s}:\n{:s}".format(text, lilies)
|
||||
|
||||
# build info
|
||||
output.write(title("Blender"))
|
||||
output.write(
|
||||
"version: {:s}, branch: {:s}, commit date: {:s} {:s}, hash: {:s}, type: {:s}\n".format(
|
||||
bpy.app.version_string,
|
||||
prepr(bpy.app.build_branch),
|
||||
prepr(bpy.app.build_commit_date),
|
||||
prepr(bpy.app.build_commit_time),
|
||||
prepr(bpy.app.build_hash),
|
||||
prepr(bpy.app.build_type),
|
||||
)
|
||||
)
|
||||
|
||||
output.write("build date: {:s}, {:s}\n".format(prepr(bpy.app.build_date), prepr(bpy.app.build_time)))
|
||||
output.write("platform: {:s}\n".format(prepr(platform.platform())))
|
||||
output.write("binary path: {:s}\n".format(prepr(bpy.app.binary_path)))
|
||||
output.write("build cflags: {:s}\n".format(prepr(bpy.app.build_cflags)))
|
||||
output.write("build cxxflags: {:s}\n".format(prepr(bpy.app.build_cxxflags)))
|
||||
output.write("build linkflags: {:s}\n".format(prepr(bpy.app.build_linkflags)))
|
||||
output.write("build system: {:s}\n".format(prepr(bpy.app.build_system)))
|
||||
|
||||
# Windowing Environment (include when dynamically selectable).
|
||||
from _bpy import _ghost_backend
|
||||
ghost_backend = _ghost_backend()
|
||||
if ghost_backend not in {'NONE', 'DEFAULT'}:
|
||||
output.write("windowing environment: {:s}\n".format(prepr(ghost_backend)))
|
||||
del _ghost_backend, ghost_backend
|
||||
|
||||
# Python info.
|
||||
output.write(title("Python"))
|
||||
output.write("version: {:s}\n".format(sys.version.replace("\n", " ")))
|
||||
output.write("file system encoding: {:s}:{:s}\n".format(
|
||||
sys.getfilesystemencoding(),
|
||||
sys.getfilesystemencodeerrors(),
|
||||
))
|
||||
output.write("paths:\n")
|
||||
for p in sys.path:
|
||||
output.write("\t{!r}\n".format(p))
|
||||
|
||||
output.write(title("Python (External Binary)"))
|
||||
output.write("binary path: {:s}\n".format(prepr(sys.executable)))
|
||||
try:
|
||||
py_ver = prepr(subprocess.check_output([
|
||||
sys.executable,
|
||||
"--version",
|
||||
]).strip())
|
||||
except Exception as ex:
|
||||
py_ver = str(ex)
|
||||
output.write("version: {:s}\n".format(py_ver))
|
||||
del py_ver
|
||||
|
||||
output.write(title("Directories"))
|
||||
output.write("scripts:\n")
|
||||
for p in bpy.utils.script_paths():
|
||||
output.write("\t{!r}\n".format(p))
|
||||
output.write("user scripts: {!r}\n".format(bpy.utils.script_path_user()))
|
||||
output.write("pref scripts:\n")
|
||||
for p in bpy.utils.script_paths_pref():
|
||||
output.write("\t{!r}\n".format(p))
|
||||
output.write("datafiles: {!r}\n".format(bpy.utils.user_resource('DATAFILES')))
|
||||
output.write("config: {!r}\n".format(bpy.utils.user_resource('CONFIG')))
|
||||
output.write("scripts: {!r}\n".format(bpy.utils.user_resource('SCRIPTS')))
|
||||
output.write("extensions: {!r}\n".format(bpy.utils.user_resource('EXTENSIONS')))
|
||||
output.write("tempdir: {!r}\n".format(bpy.app.tempdir))
|
||||
|
||||
output.write(title("FFmpeg"))
|
||||
ffmpeg = bpy.app.ffmpeg
|
||||
if ffmpeg.supported:
|
||||
for lib in ("avcodec", "avdevice", "avformat", "avutil", "swscale"):
|
||||
output.write(
|
||||
"{:s}:{:s}{!r}\n".format(
|
||||
lib,
|
||||
" " * (10 - len(lib)),
|
||||
getattr(ffmpeg, lib + "_version_string"),
|
||||
)
|
||||
)
|
||||
else:
|
||||
output.write("Blender was built without FFmpeg support\n")
|
||||
|
||||
if bpy.app.build_options.sdl:
|
||||
output.write(title("SDL"))
|
||||
output.write("Version: {:s}\n".format(bpy.app.sdl.version_string))
|
||||
output.write("Loading method: ")
|
||||
if bpy.app.build_options.sdl_dynload:
|
||||
output.write("dynamically loaded by Blender (WITH_SDL_DYNLOAD=ON)\n")
|
||||
else:
|
||||
output.write("linked (WITH_SDL_DYNLOAD=OFF)\n")
|
||||
if not bpy.app.sdl.available:
|
||||
output.write("WARNING: Blender could not load SDL library\n")
|
||||
|
||||
output.write(title("Other Libraries"))
|
||||
ocio = bpy.app.ocio
|
||||
output.write("OpenColorIO: ")
|
||||
if ocio.supported:
|
||||
if ocio.version_string == "fallback":
|
||||
output.write("Blender was built with OpenColorIO, "
|
||||
"but it currently uses fallback color management.\n")
|
||||
else:
|
||||
output.write("{:s}\n".format(ocio.version_string))
|
||||
else:
|
||||
output.write("Blender was built without OpenColorIO support\n")
|
||||
|
||||
oiio = bpy.app.oiio
|
||||
output.write("OpenImageIO: ")
|
||||
if ocio.supported:
|
||||
output.write("{:s}\n".format(oiio.version_string))
|
||||
else:
|
||||
output.write("Blender was built without OpenImageIO support\n")
|
||||
|
||||
output.write("OpenShadingLanguage: ")
|
||||
if bpy.app.build_options.cycles:
|
||||
if bpy.app.build_options.cycles_osl:
|
||||
from _cycles import osl_version_string
|
||||
output.write("{:s}\n".format(osl_version_string))
|
||||
else:
|
||||
output.write("Blender was built without OpenShadingLanguage support in Cycles\n")
|
||||
else:
|
||||
output.write("Blender was built without Cycles support\n")
|
||||
|
||||
opensubdiv = bpy.app.opensubdiv
|
||||
output.write("OpenSubdiv: ")
|
||||
if opensubdiv.supported:
|
||||
output.write("{:s}\n".format(opensubdiv.version_string))
|
||||
else:
|
||||
output.write("Blender was built without OpenSubdiv support\n")
|
||||
|
||||
openvdb = bpy.app.openvdb
|
||||
output.write("OpenVDB: ")
|
||||
if openvdb.supported:
|
||||
output.write("{:s}\n".format(openvdb.version_string))
|
||||
else:
|
||||
output.write("Blender was built without OpenVDB support\n")
|
||||
|
||||
alembic = bpy.app.alembic
|
||||
output.write("Alembic: ")
|
||||
if alembic.supported:
|
||||
output.write("{:s}\n".format(alembic.version_string))
|
||||
else:
|
||||
output.write("Blender was built without Alembic support\n")
|
||||
|
||||
usd = bpy.app.usd
|
||||
output.write("USD: ")
|
||||
if usd.supported:
|
||||
output.write("{:s}\n".format(usd.version_string))
|
||||
else:
|
||||
output.write("Blender was built without USD support\n")
|
||||
|
||||
if not bpy.app.build_options.sdl:
|
||||
output.write("SDL: Blender was built without SDL support\n")
|
||||
|
||||
if bpy.app.background:
|
||||
output.write("\nGPU: missing, background mode\n")
|
||||
else:
|
||||
output.write(title("GPU"))
|
||||
output.write("renderer:\t{!r}\n".format(gpu.platform.renderer_get()))
|
||||
output.write("vendor:\t\t{!r}\n".format(gpu.platform.vendor_get()))
|
||||
output.write("version:\t{!r}\n".format(gpu.platform.version_get()))
|
||||
output.write("device type:\t{!r}\n".format(gpu.platform.device_type_get()))
|
||||
output.write("backend type:\t{!r}\n".format(gpu.platform.backend_type_get()))
|
||||
output.write("extensions:\n")
|
||||
|
||||
glext = sorted(gpu.capabilities.extensions_get())
|
||||
|
||||
for l in glext:
|
||||
output.write("\t{:s}\n".format(l))
|
||||
|
||||
output.write(title("Implementation Dependent GPU Limits"))
|
||||
output.write("Maximum Batch Vertices:\t{:d}\n".format(
|
||||
gpu.capabilities.max_batch_vertices_get(),
|
||||
))
|
||||
output.write("Maximum Batch Indices:\t{:d}\n".format(
|
||||
gpu.capabilities.max_batch_indices_get(),
|
||||
))
|
||||
|
||||
output.write("\nGLSL:\n")
|
||||
output.write("Maximum Varying Floats:\t{:d}\n".format(
|
||||
gpu.capabilities.max_varying_floats_get(),
|
||||
))
|
||||
output.write("Maximum Vertex Attributes:\t{:d}\n".format(
|
||||
gpu.capabilities.max_vertex_attribs_get(),
|
||||
))
|
||||
output.write("Maximum Vertex Uniform Components:\t{:d}\n".format(
|
||||
gpu.capabilities.max_uniforms_vert_get(),
|
||||
))
|
||||
output.write("Maximum Fragment Uniform Components:\t{:d}\n".format(
|
||||
gpu.capabilities.max_uniforms_frag_get(),
|
||||
))
|
||||
output.write("Maximum Vertex Image Units:\t{:d}\n".format(
|
||||
gpu.capabilities.max_textures_vert_get(),
|
||||
))
|
||||
output.write("Maximum Fragment Image Units:\t{:d}\n".format(
|
||||
gpu.capabilities.max_textures_frag_get(),
|
||||
))
|
||||
output.write("Maximum Pipeline Image Units:\t{:d}\n".format(
|
||||
gpu.capabilities.max_textures_get(),
|
||||
))
|
||||
output.write("Maximum Image Units:\t{:d}\n".format(
|
||||
gpu.capabilities.max_images_get(),
|
||||
))
|
||||
|
||||
if bpy.app.build_options.cycles:
|
||||
import cycles
|
||||
output.write(title("Cycles"))
|
||||
output.write(cycles.engine.system_info())
|
||||
|
||||
import addon_utils
|
||||
addon_utils.modules()
|
||||
output.write(title("Enabled add-ons"))
|
||||
for addon in bpy.context.preferences.addons.keys():
|
||||
addon_mod = addon_utils.addons_fake_modules.get(addon, None)
|
||||
if addon_mod is None:
|
||||
output.write("{:s} (MISSING)\n".format(addon))
|
||||
else:
|
||||
output.write(
|
||||
"{:s} (version: {:s}, path: {!r})\n".format(
|
||||
addon,
|
||||
str(addon_mod.bl_info.get("version", "UNKNOWN")),
|
||||
addon_mod.__file__,
|
||||
)
|
||||
)
|
||||
@@ -4,7 +4,12 @@
|
||||
|
||||
# Keep the information collected in this script synchronized with `startup.py`.
|
||||
|
||||
def url_prefill_from_blender(*, addon_info=None):
|
||||
__all__ = (
|
||||
"url_from_blender",
|
||||
)
|
||||
|
||||
|
||||
def url_from_blender(*, addon_info=None):
|
||||
import bpy
|
||||
import gpu
|
||||
import struct
|
||||
@@ -5,7 +5,15 @@
|
||||
|
||||
# Keep the information collected in this script synchronized with `runtime.py`.
|
||||
|
||||
def prefill_bug_report_info() -> int:
|
||||
# NOTE: this can run as a standalone script, called directly from Python
|
||||
# (even though it's located inside a package).
|
||||
|
||||
__all__ = (
|
||||
"url_from_blender",
|
||||
)
|
||||
|
||||
|
||||
def url_from_blender() -> str:
|
||||
from typing import (
|
||||
Dict,
|
||||
Optional,
|
||||
@@ -15,7 +23,7 @@ def prefill_bug_report_info() -> int:
|
||||
import struct
|
||||
import platform
|
||||
import subprocess
|
||||
import webbrowser
|
||||
import sys
|
||||
import urllib.parse
|
||||
from pathlib import Path
|
||||
|
||||
@@ -54,7 +62,7 @@ def prefill_bug_report_info() -> int:
|
||||
)
|
||||
except Exception as ex:
|
||||
sys.stderr.write("{:s}\n".format(str(ex)))
|
||||
return 1
|
||||
return ""
|
||||
|
||||
text = blender_output.stdout
|
||||
|
||||
@@ -78,7 +86,7 @@ def prefill_bug_report_info() -> int:
|
||||
# No valid Blender info could be found.
|
||||
print("Blender did not provide any build information. Blender may be corrupt or blocked from running.")
|
||||
print("Please try reinstalling Blender and double check your anti-virus isn't blocking it from running.")
|
||||
return 1
|
||||
return ""
|
||||
|
||||
query_params["broken_version"] = (
|
||||
"{version:s}, branch: {branch:s}, commit date: {commit_date:s} {commit_time:s}, hash `{build_hash:s}`".format(
|
||||
@@ -86,12 +94,19 @@ def prefill_bug_report_info() -> int:
|
||||
)
|
||||
)
|
||||
|
||||
query_str = urllib.parse.urlencode(query_params)
|
||||
webbrowser.open("https://redirect.blender.org/?{:s}".format(query_str))
|
||||
return "https://redirect.blender.org/?{:s}".format(urllib.parse.urlencode(query_params))
|
||||
|
||||
|
||||
def main() -> int:
|
||||
import webbrowser
|
||||
|
||||
if not (url := url_from_blender()):
|
||||
return 1
|
||||
|
||||
webbrowser.open(url)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
sys.exit(prefill_bug_report_info())
|
||||
sys.exit(main())
|
||||
@@ -1,259 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2010-2023 Blender Authors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# classes for extracting info from blenders internal classes
|
||||
|
||||
|
||||
def write_sysinfo(filepath):
|
||||
import sys
|
||||
import platform
|
||||
|
||||
import subprocess
|
||||
|
||||
import bpy
|
||||
import gpu
|
||||
|
||||
# pretty repr
|
||||
def prepr(v):
|
||||
r = repr(v)
|
||||
vt = type(v)
|
||||
if vt is bytes:
|
||||
r = r[2:-1]
|
||||
elif vt is list or vt is tuple:
|
||||
r = r[1:-1]
|
||||
return r
|
||||
|
||||
with open(filepath, 'w', encoding="utf-8") as output:
|
||||
try:
|
||||
header = "= Blender {:s} System Information =\n".format(bpy.app.version_string)
|
||||
lilies = "{:s}\n\n".format((len(header) - 1) * "=")
|
||||
output.write(lilies[:-1])
|
||||
output.write(header)
|
||||
output.write(lilies)
|
||||
|
||||
def title(text):
|
||||
return "\n{:s}:\n{:s}".format(text, lilies)
|
||||
|
||||
# build info
|
||||
output.write(title("Blender"))
|
||||
output.write(
|
||||
"version: {:s}, branch: {:s}, commit date: {:s} {:s}, hash: {:s}, type: {:s}\n".format(
|
||||
bpy.app.version_string,
|
||||
prepr(bpy.app.build_branch),
|
||||
prepr(bpy.app.build_commit_date),
|
||||
prepr(bpy.app.build_commit_time),
|
||||
prepr(bpy.app.build_hash),
|
||||
prepr(bpy.app.build_type),
|
||||
)
|
||||
)
|
||||
|
||||
output.write("build date: {:s}, {:s}\n".format(prepr(bpy.app.build_date), prepr(bpy.app.build_time)))
|
||||
output.write("platform: {:s}\n".format(prepr(platform.platform())))
|
||||
output.write("binary path: {:s}\n".format(prepr(bpy.app.binary_path)))
|
||||
output.write("build cflags: {:s}\n".format(prepr(bpy.app.build_cflags)))
|
||||
output.write("build cxxflags: {:s}\n".format(prepr(bpy.app.build_cxxflags)))
|
||||
output.write("build linkflags: {:s}\n".format(prepr(bpy.app.build_linkflags)))
|
||||
output.write("build system: {:s}\n".format(prepr(bpy.app.build_system)))
|
||||
|
||||
# Windowing Environment (include when dynamically selectable).
|
||||
from _bpy import _ghost_backend
|
||||
ghost_backend = _ghost_backend()
|
||||
if ghost_backend not in {'NONE', 'DEFAULT'}:
|
||||
output.write("windowing environment: {:s}\n".format(prepr(ghost_backend)))
|
||||
del _ghost_backend, ghost_backend
|
||||
|
||||
# Python info.
|
||||
output.write(title("Python"))
|
||||
output.write("version: {:s}\n".format(sys.version.replace("\n", " ")))
|
||||
output.write("file system encoding: {:s}:{:s}\n".format(
|
||||
sys.getfilesystemencoding(),
|
||||
sys.getfilesystemencodeerrors(),
|
||||
))
|
||||
output.write("paths:\n")
|
||||
for p in sys.path:
|
||||
output.write("\t{!r}\n".format(p))
|
||||
|
||||
output.write(title("Python (External Binary)"))
|
||||
output.write("binary path: {:s}\n".format(prepr(sys.executable)))
|
||||
try:
|
||||
py_ver = prepr(subprocess.check_output([
|
||||
sys.executable,
|
||||
"--version",
|
||||
]).strip())
|
||||
except BaseException as ex:
|
||||
py_ver = str(ex)
|
||||
output.write("version: {:s}\n".format(py_ver))
|
||||
del py_ver
|
||||
|
||||
output.write(title("Directories"))
|
||||
output.write("scripts:\n")
|
||||
for p in bpy.utils.script_paths():
|
||||
output.write("\t{!r}\n".format(p))
|
||||
output.write("user scripts: {!r}\n".format(bpy.utils.script_path_user()))
|
||||
output.write("pref scripts:\n")
|
||||
for p in bpy.utils.script_paths_pref():
|
||||
output.write("\t{!r}\n".format(p))
|
||||
output.write("datafiles: {!r}\n".format(bpy.utils.user_resource('DATAFILES')))
|
||||
output.write("config: {!r}\n".format(bpy.utils.user_resource('CONFIG')))
|
||||
output.write("scripts: {!r}\n".format(bpy.utils.user_resource('SCRIPTS')))
|
||||
output.write("extensions: {!r}\n".format(bpy.utils.user_resource('EXTENSIONS')))
|
||||
output.write("tempdir: {!r}\n".format(bpy.app.tempdir))
|
||||
|
||||
output.write(title("FFmpeg"))
|
||||
ffmpeg = bpy.app.ffmpeg
|
||||
if ffmpeg.supported:
|
||||
for lib in ("avcodec", "avdevice", "avformat", "avutil", "swscale"):
|
||||
output.write(
|
||||
"{:s}:{:s}{!r}\n".format(
|
||||
lib,
|
||||
" " * (10 - len(lib)),
|
||||
getattr(ffmpeg, lib + "_version_string"),
|
||||
)
|
||||
)
|
||||
else:
|
||||
output.write("Blender was built without FFmpeg support\n")
|
||||
|
||||
if bpy.app.build_options.sdl:
|
||||
output.write(title("SDL"))
|
||||
output.write("Version: {:s}\n".format(bpy.app.sdl.version_string))
|
||||
output.write("Loading method: ")
|
||||
if bpy.app.build_options.sdl_dynload:
|
||||
output.write("dynamically loaded by Blender (WITH_SDL_DYNLOAD=ON)\n")
|
||||
else:
|
||||
output.write("linked (WITH_SDL_DYNLOAD=OFF)\n")
|
||||
if not bpy.app.sdl.available:
|
||||
output.write("WARNING: Blender could not load SDL library\n")
|
||||
|
||||
output.write(title("Other Libraries"))
|
||||
ocio = bpy.app.ocio
|
||||
output.write("OpenColorIO: ")
|
||||
if ocio.supported:
|
||||
if ocio.version_string == "fallback":
|
||||
output.write("Blender was built with OpenColorIO, "
|
||||
"but it currently uses fallback color management.\n")
|
||||
else:
|
||||
output.write("{:s}\n".format(ocio.version_string))
|
||||
else:
|
||||
output.write("Blender was built without OpenColorIO support\n")
|
||||
|
||||
oiio = bpy.app.oiio
|
||||
output.write("OpenImageIO: ")
|
||||
if ocio.supported:
|
||||
output.write("{:s}\n".format(oiio.version_string))
|
||||
else:
|
||||
output.write("Blender was built without OpenImageIO support\n")
|
||||
|
||||
output.write("OpenShadingLanguage: ")
|
||||
if bpy.app.build_options.cycles:
|
||||
if bpy.app.build_options.cycles_osl:
|
||||
from _cycles import osl_version_string
|
||||
output.write("{:s}\n".format(osl_version_string))
|
||||
else:
|
||||
output.write("Blender was built without OpenShadingLanguage support in Cycles\n")
|
||||
else:
|
||||
output.write("Blender was built without Cycles support\n")
|
||||
|
||||
opensubdiv = bpy.app.opensubdiv
|
||||
output.write("OpenSubdiv: ")
|
||||
if opensubdiv.supported:
|
||||
output.write("{:s}\n".format(opensubdiv.version_string))
|
||||
else:
|
||||
output.write("Blender was built without OpenSubdiv support\n")
|
||||
|
||||
openvdb = bpy.app.openvdb
|
||||
output.write("OpenVDB: ")
|
||||
if openvdb.supported:
|
||||
output.write("{:s}\n".format(openvdb.version_string))
|
||||
else:
|
||||
output.write("Blender was built without OpenVDB support\n")
|
||||
|
||||
alembic = bpy.app.alembic
|
||||
output.write("Alembic: ")
|
||||
if alembic.supported:
|
||||
output.write("{:s}\n".format(alembic.version_string))
|
||||
else:
|
||||
output.write("Blender was built without Alembic support\n")
|
||||
|
||||
usd = bpy.app.usd
|
||||
output.write("USD: ")
|
||||
if usd.supported:
|
||||
output.write("{:s}\n".format(usd.version_string))
|
||||
else:
|
||||
output.write("Blender was built without USD support\n")
|
||||
|
||||
if not bpy.app.build_options.sdl:
|
||||
output.write("SDL: Blender was built without SDL support\n")
|
||||
|
||||
if bpy.app.background:
|
||||
output.write("\nGPU: missing, background mode\n")
|
||||
else:
|
||||
output.write(title("GPU"))
|
||||
output.write("renderer:\t{!r}\n".format(gpu.platform.renderer_get()))
|
||||
output.write("vendor:\t\t{!r}\n".format(gpu.platform.vendor_get()))
|
||||
output.write("version:\t{!r}\n".format(gpu.platform.version_get()))
|
||||
output.write("device type:\t{!r}\n".format(gpu.platform.device_type_get()))
|
||||
output.write("backend type:\t{!r}\n".format(gpu.platform.backend_type_get()))
|
||||
output.write("extensions:\n")
|
||||
|
||||
glext = sorted(gpu.capabilities.extensions_get())
|
||||
|
||||
for l in glext:
|
||||
output.write("\t{:s}\n".format(l))
|
||||
|
||||
output.write(title("Implementation Dependent GPU Limits"))
|
||||
output.write("Maximum Batch Vertices:\t{:d}\n".format(
|
||||
gpu.capabilities.max_batch_vertices_get(),
|
||||
))
|
||||
output.write("Maximum Batch Indices:\t{:d}\n".format(
|
||||
gpu.capabilities.max_batch_indices_get(),
|
||||
))
|
||||
|
||||
output.write("\nGLSL:\n")
|
||||
output.write("Maximum Varying Floats:\t{:d}\n".format(
|
||||
gpu.capabilities.max_varying_floats_get(),
|
||||
))
|
||||
output.write("Maximum Vertex Attributes:\t{:d}\n".format(
|
||||
gpu.capabilities.max_vertex_attribs_get(),
|
||||
))
|
||||
output.write("Maximum Vertex Uniform Components:\t{:d}\n".format(
|
||||
gpu.capabilities.max_uniforms_vert_get(),
|
||||
))
|
||||
output.write("Maximum Fragment Uniform Components:\t{:d}\n".format(
|
||||
gpu.capabilities.max_uniforms_frag_get(),
|
||||
))
|
||||
output.write("Maximum Vertex Image Units:\t{:d}\n".format(
|
||||
gpu.capabilities.max_textures_vert_get(),
|
||||
))
|
||||
output.write("Maximum Fragment Image Units:\t{:d}\n".format(
|
||||
gpu.capabilities.max_textures_frag_get(),
|
||||
))
|
||||
output.write("Maximum Pipeline Image Units:\t{:d}\n".format(
|
||||
gpu.capabilities.max_textures_get(),
|
||||
))
|
||||
output.write("Maximum Image Units:\t{:d}\n".format(
|
||||
gpu.capabilities.max_images_get(),
|
||||
))
|
||||
|
||||
if bpy.app.build_options.cycles:
|
||||
import cycles
|
||||
output.write(title("Cycles"))
|
||||
output.write(cycles.engine.system_info())
|
||||
|
||||
import addon_utils
|
||||
addon_utils.modules()
|
||||
output.write(title("Enabled add-ons"))
|
||||
for addon in bpy.context.preferences.addons.keys():
|
||||
addon_mod = addon_utils.addons_fake_modules.get(addon, None)
|
||||
if addon_mod is None:
|
||||
output.write("{:s} (MISSING)\n".format(addon))
|
||||
else:
|
||||
output.write(
|
||||
"{:s} (version: {:s}, path: {!r})\n".format(
|
||||
addon,
|
||||
str(addon_mod.bl_info.get("version", "UNKNOWN")),
|
||||
addon_mod.__file__,
|
||||
)
|
||||
)
|
||||
except BaseException as ex:
|
||||
output.write("ERROR: {:s}\n".format(str(ex)))
|
||||
@@ -1086,8 +1086,8 @@ class WM_OT_url_open_preset(Operator):
|
||||
)
|
||||
|
||||
def _url_from_bug(self, _context):
|
||||
from _bpy_internal.system_info.runtime import url_prefill_from_blender
|
||||
return url_prefill_from_blender()
|
||||
from _bpy_internal.system_info.url_prefill_runtime import url_from_blender
|
||||
return url_from_blender()
|
||||
|
||||
def _url_from_release_notes(self, _context):
|
||||
return "https://www.blender.org/download/releases/{:d}-{:d}/".format(*bpy.app.version[:2])
|
||||
@@ -2197,8 +2197,18 @@ class WM_OT_sysinfo(Operator):
|
||||
)
|
||||
|
||||
def execute(self, _context):
|
||||
import sys_info
|
||||
sys_info.write_sysinfo(self.filepath)
|
||||
from _bpy_internal.system_info.text_generate_runtime import write
|
||||
with open(self.filepath, "w", encoding="utf-8") as output:
|
||||
try:
|
||||
write(output)
|
||||
except Exception as ex:
|
||||
# Not expected to occur, simply forward the exception.
|
||||
self.report({'ERROR'}, str(ex))
|
||||
|
||||
# Also write into the file (to avoid confusion).
|
||||
output.write("ERROR: {:s}\n".format(str(ex)))
|
||||
return {'CANCELLED'}
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, _event):
|
||||
|
||||
Reference in New Issue
Block a user