# SPDX-License-Identifier: MIT OR GPL-3.0-or-later import contextlib import datetime import getpass import platform import sys import sysconfig from collections.abc import Sequence from collections.abc import Set as AbstractSet from pathlib import Path from typing import TYPE_CHECKING, Union import bpy from bpy.props import CollectionProperty, IntProperty, StringProperty from bpy.types import ( Context, Event, Operator, PropertyGroup, UILayout, UIList, ) from bpy_extras.io_utils import ExportHelper from ..common import ops from ..common.logger import get_logger from ..common.version import get_addon_version from ..editor.ops import VRM_OT_open_url_in_web_browser, layout_operator from ..editor.property_group import CollectionPropertyProtocol logger = get_logger(__name__) def show_error_dialog( title: str, lines: Union[str, Sequence[str]], *, append_environment: bool = True, ) -> set[str]: if isinstance(lines, str): lines = list(map(str.rstrip, lines.splitlines())) while lines and not lines[0].strip(): del lines[0] while lines and not lines[-1].strip(): del lines[-1] else: lines = list(lines) if not lines: return {"CANCELLED"} if append_environment: if lines: lines[0] = f"Python: {lines[0]}" os_name = None platform_system, _, _ = platform.system_alias( platform.system(), platform.release(), platform.version() ) if sys.version_info >= (3, 10) and platform_system not in ["Windows", "Darwin"]: # https://github.com/python/cpython/blob/v3.10.18/Doc/library/platform.rst?plain=1#L271-L272 with contextlib.suppress(OSError): os_name = platform.freedesktop_os_release().get("PRETTY_NAME") if not os_name: os_name = platform_system python_version = ( platform.python_implementation() + " " + ".".join(map(str, sys.version_info[:3])) ) runtime_platform = os_name + " " + platform.machine() build_platform = sysconfig.get_platform() lines.insert( 0, "Environment: Blender {} / VRM Add-on {} / {} / {} ({})".format( bpy.app.version_string, ".".join(map(str, get_addon_version())), python_version, runtime_platform, build_platform, ), ) return ops.wm.vrm_error_dialog( "INVOKE_DEFAULT", title=title, lines=[ { "name": f"error_line_{i}", "line": mask_private_string(line), } for i, line in enumerate(lines) ], ) def mask_private_string(message: str) -> str: script_path = Path(__file__).parent.parent.parent.parent.parent if len(script_path.parts) > 3: message = message.replace(str(script_path), "