Fixed a number of PEP warnings

Most of these are just assert statements to silence the warnings for accessing optionals
This commit is contained in:
Colin Basnett
2025-09-20 12:34:35 -07:00
parent 33e7862288
commit 240b79d374
11 changed files with 71 additions and 22 deletions

View File

@@ -103,6 +103,10 @@ def _get_pose_bone_location_and_rotation(
def build_psa(context: Context, options: PsaBuildOptions) -> Psa:
assert context.scene
assert context.window_manager
psa = Psa()
armature_objects_for_bones = options.armature_objects
@@ -224,6 +228,7 @@ def build_psa(context: Context, options: PsaBuildOptions) -> Psa:
export_bones.append(PsaExportBone(None, None, Vector((1.0, 1.0, 1.0))))
continue
assert armature_object.pose
pose_bone = armature_object.pose.bones[psx_bone.name.decode('windows-1252')]
export_bones.append(PsaExportBone(pose_bone, armature_object, armature_scales[armature_object]))
@@ -321,6 +326,7 @@ def build_psa(context: Context, options: PsaBuildOptions) -> Psa:
# Restore the previous actions & frame.
for armature_object, action in saved_armature_object_actions.items():
assert armature_object.animation_data
armature_object.animation_data.action = action
context.scene.frame_set(saved_frame_current)

View File

@@ -462,6 +462,9 @@ class PSA_OT_export(Operator, ExportHelper):
if animation_data is None:
raise RuntimeError(f'No animation data for object \'{animation_data_object.name}\'')
if context.active_object is None:
raise RuntimeError('No active object')
export_sequences: List[PsaBuildSequence] = []
match pg.sequence_source:

View File

@@ -132,6 +132,7 @@ sampling_mode_items = (
def sequence_source_update_cb(self: 'PSA_PG_export', context: Context) -> None:
armature_objects = []
assert context.view_layer
for dfs_object in dfs_view_layer_objects(context.view_layer):
if dfs_object.obj.type == 'ARMATURE' and dfs_object.is_selected:
armature_objects.append(dfs_object.obj)

View File

@@ -13,6 +13,7 @@ from ..reader import PsaReader
def psa_import_poll(cls, context: Context):
assert context.view_layer and context.view_layer.objects.active
active_object = context.view_layer.objects.active
if active_object is None or active_object.type != 'ARMATURE':
cls.poll_message_set('The active object must be an armature')
@@ -32,10 +33,12 @@ class PSA_OT_import_sequences_select_from_text(Operator):
return len(pg.sequence_list) > 0
def invoke(self, context, event):
assert context.window_manager
return context.window_manager.invoke_props_dialog(self, width=256)
def draw(self, context):
layout = self.layout
assert layout
pg = getattr(context.scene, 'psa_import')
layout.label(icon='INFO', text='Each sequence name should be on a new line.')
layout.prop(pg, 'select_text', text='')
@@ -134,6 +137,8 @@ class PSA_OT_import_drag_and_drop(Operator, PsaImportMixin):
warnings = []
sequences_count = 0
assert context.view_layer and context.view_layer.objects.active
for file in self.files:
psa_path = str(os.path.join(self.directory, file.name))
psa_reader = PsaReader(psa_path)
@@ -157,12 +162,14 @@ class PSA_OT_import_drag_and_drop(Operator, PsaImportMixin):
def invoke(self, context: Context, event):
# Make sure the selected object is an obj.
assert context.view_layer and context.view_layer.objects.active
active_object = context.view_layer.objects.active
if active_object is None or active_object.type != 'ARMATURE':
self.report({'ERROR_INVALID_CONTEXT'}, 'The active object must be an armature')
return {'CANCELLED'}
# Show the import operator properties in a pop-up dialog (do not use the file selector).
assert context.window_manager
context.window_manager.invoke_props_dialog(self)
return {'RUNNING_MODAL'}
@@ -250,6 +257,8 @@ class PSA_OT_import_all(Operator, PsaImportMixin):
translation_scale=self.translation_scale
)
assert context.view_layer
assert context.view_layer.objects.active
result = _import_psa(context, options, self.filepath, context.view_layer.objects.active)
if len(result.warnings) > 0:
@@ -308,12 +317,13 @@ class PSA_OT_import(Operator, ImportHelper, PsaImportMixin):
def invoke(self, context: Context, event: Event):
# Attempt to load the PSA file for the pre-selected file.
load_psa_file(context, self.filepath)
assert context.window_manager
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
def draw(self, context: Context):
layout = self.layout
assert layout
pg = getattr(context.scene, 'psa_import')
sequences_header, sequences_panel = layout.panel('sequences_panel_id', default_closed=False)
@@ -434,8 +444,8 @@ class PSA_FH_import(FileHandler): # TODO: rename and add handling for PSA expor
bl_file_extensions = '.psa'
@classmethod
def poll_drop(cls, context: Context):
return context.area and context.area.type == 'VIEW_3D'
def poll_drop(cls, context: Context) -> bool:
return context.area is not None and context.area.type == 'VIEW_3D'
_classes = (

View File

@@ -145,6 +145,9 @@ def _resample_sequence_data_matrix(sequence_data_matrix: np.ndarray, frame_step:
def import_psa(context: Context, psa_reader: PsaReader, armature_object: Object, options: PsaImportOptions) -> PsaImportResult:
assert context.window_manager
result = PsaImportResult()
sequences = [psa_reader.sequences[x] for x in options.sequence_names]
armature_data = typing_cast(Armature, armature_object.data)
@@ -259,6 +262,7 @@ def import_psa(context: Context, psa_reader: PsaReader, armature_object: Object,
case 'CUSTOM':
target_fps = options.fps_custom
case 'SCENE':
assert context.scene
target_fps = context.scene.render.fps
case 'SEQUENCE':
target_fps = sequence.fps

View File

@@ -1,7 +1,7 @@
import bmesh
import bpy
import numpy as np
from bpy.types import Armature, Collection, Context, Depsgraph, Object, ArmatureModifier
from bpy.types import Armature, Collection, Context, Depsgraph, Object, ArmatureModifier, Mesh
from mathutils import Matrix
from typing import Dict, Iterable, List, Optional, Set, cast as typing_cast
from .data import Psk
@@ -94,9 +94,9 @@ def get_psk_input_objects_for_collection(collection: Collection) -> PskInputObje
class PskBuildResult(object):
def __init__(self):
self.psk = None
self.warnings: List[str] = []
def __init__(self, psk: Psk, warnings: list[str]):
self.psk: Psk = psk
self.warnings: List[str] = warnings
def _get_mesh_export_space_matrix(armature_object: Optional[Object], export_space: str) -> Matrix:
@@ -137,9 +137,12 @@ def _get_material_name_indices(obj: Object, material_names: List[str]) -> Iterab
def build_psk(context: Context, input_objects: PskInputObjects, options: PskBuildOptions) -> PskBuildResult:
assert context.window_manager
armature_objects = list(input_objects.armature_objects)
result = PskBuildResult()
warnings: list[str] = []
psk = Psk()
psx_bone_create_result = create_psx_bones(
@@ -208,7 +211,8 @@ def build_psk(context: Context, input_objects: PskInputObjects, options: PskBuil
# Temporarily force the armature into the rest position.
# We will undo this later.
for armature_object in armature_objects:
armature_object.data.pose_position = 'REST'
armature_data = typing_cast(Armature, armature_object.data)
armature_data.pose_position = 'REST'
material_names = [m.name if m is not None else 'None' for m in materials]
@@ -232,7 +236,7 @@ def build_psk(context: Context, input_objects: PskInputObjects, options: PskBuil
match options.object_eval_state:
case 'ORIGINAL':
mesh_object = obj
mesh_data = obj.data
mesh_data = typing_cast(Mesh, obj.data)
case 'EVALUATED':
# Create a copy of the mesh object after non-armature modifiers are applied.
depsgraph = context.evaluated_depsgraph_get()
@@ -299,7 +303,7 @@ def build_psk(context: Context, input_objects: PskInputObjects, options: PskBuil
mesh_data.calc_loop_triangles()
if mesh_data.uv_layers.active is None:
result.warnings.append(f'"{mesh_object.name}" has no active UV Map')
warnings.append(f'"{mesh_object.name}" has no active UV Map')
# Build a list of non-unique wedges.
wedges = []
@@ -423,13 +427,12 @@ def build_psk(context: Context, input_objects: PskInputObjects, options: PskBuil
# Restore the original pose position of the armature objects.
for armature_object, pose_position in original_armature_object_pose_positions.items():
armature_object.data.pose_position = pose_position
armature_data = typing_cast(Armature, armature_object.data)
armature_data.pose_position = pose_position
# https://github.com/DarklightGames/io_scene_psk_psa/issues/129.
psk.sort_and_normalize_weights()
context.window_manager.progress_end()
result.psk = psk
return result
return PskBuildResult(psk, warnings)

View File

@@ -3,7 +3,7 @@ from typing import Iterable, List, Optional, cast as typing_cast
import bpy
from bpy.props import BoolProperty, StringProperty
from bpy.types import Collection, Context, Depsgraph, Material, Object, Operator, SpaceProperties, Scene
from bpy.types import Context, Depsgraph, Material, Object, Operator, Scene
from bpy_extras.io_utils import ExportHelper
from .properties import PskExportMixin
@@ -91,6 +91,7 @@ class PSK_OT_populate_material_name_list(Operator):
self.report({'ERROR_INVALID_CONTEXT'}, 'No valid export operator found in context')
return {'CANCELLED'}
depsgraph = context.evaluated_depsgraph_get()
assert context.collection
input_objects = get_psk_input_objects_for_collection(context.collection)
try:
populate_material_name_list(depsgraph, [x.obj for x in input_objects.mesh_dfs_objects], export_operator.material_name_list)
@@ -115,6 +116,7 @@ class PSK_OT_material_list_name_add(Operator):
name: StringProperty(search=material_list_names_search_cb, name='Material Name', default='None')
def invoke(self, context, event):
assert context.window_manager
return context.window_manager.invoke_props_dialog(self)
def execute(self, context):
@@ -266,7 +268,10 @@ class PSK_OT_export_collection(Operator, ExportHelper, PskExportMixin):
collection: StringProperty(options={'HIDDEN'})
def execute(self, context):
collection = bpy.data.collections.get(self.collection)
collection = bpy.data.collections.get(self.collection, None)
if collection is not None:
return {'CANCELLED'}
try:
input_objects = get_psk_input_objects_for_collection(collection)
@@ -295,6 +300,8 @@ class PSK_OT_export_collection(Operator, ExportHelper, PskExportMixin):
def draw(self, context: Context):
layout = self.layout
assert layout is not None
flow = layout.grid_flow(row_major=True)
flow.use_property_split = True
flow.use_property_decorate = False
@@ -376,6 +383,8 @@ class PSK_OT_export_collection(Operator, ExportHelper, PskExportMixin):
flow.enabled = False
case 'CUSTOM':
transform_source = self
case _:
assert False, f'Invalid transform source: {self.transform_source}'
flow.prop(transform_source, 'scale')
flow.prop(transform_source, 'forward_axis')
@@ -414,6 +423,7 @@ class PSK_OT_export(Operator, ExportHelper):
self.report({'ERROR_INVALID_CONTEXT'}, str(e))
return {'CANCELLED'}
assert context.window_manager
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
@@ -421,6 +431,8 @@ class PSK_OT_export(Operator, ExportHelper):
def draw(self, context):
layout = self.layout
assert layout
pg = getattr(context.scene, 'psk_export')
# Mesh
@@ -490,6 +502,8 @@ class PSK_OT_export(Operator, ExportHelper):
def execute(self, context):
pg = getattr(context.scene, 'psk_export')
assert context.scene
input_objects = get_psk_input_objects_for_context(context)
options = get_psk_build_options_from_property_group(context.scene, pg)

View File

@@ -52,7 +52,7 @@ class PskExportMixin(ExportSpaceMixin, TransformMixin, PsxBoneExportMixin):
material_name_list: CollectionProperty(type=PSK_PG_material_name_list_item)
material_name_list_index: IntProperty(default=0)
should_export_vertex_normals: BoolProperty(
'Export Vertex Normals',
name='Export Vertex Normals',
default=False,
description='Export VTXNORMS section.'
)

View File

@@ -9,6 +9,7 @@ from ..importer import PskImportOptions, import_psk
from ..properties import PskImportMixin
from ..reader import read_psk
def get_psk_import_options_from_properties(property_group: PskImportMixin):
options = PskImportOptions()
options.should_import_mesh = property_group.should_import_mesh
@@ -109,6 +110,7 @@ class PSK_OT_import(Operator, ImportHelper, PskImportMixin):
return {'FINISHED'}
def draw(self, context):
assert self.layout
psk_import_draw(self.layout, self)
@@ -122,13 +124,15 @@ class PSK_OT_import_drag_and_drop(Operator, PskImportMixin):
files: CollectionProperty(type=OperatorFileListElement, options={'SKIP_SAVE', 'HIDDEN'})
@classmethod
def poll(cls, context):
return context.area and context.area.type == 'VIEW_3D'
def poll(cls, context) -> bool:
return context.area is not None and context.area.type == 'VIEW_3D'
def draw(self, context):
assert self.layout
psk_import_draw(self.layout, self)
def invoke(self, context, event):
assert context.window_manager
context.window_manager.invoke_props_dialog(self)
return {'RUNNING_MODAL'}
@@ -167,8 +171,8 @@ class PSK_FH_import(FileHandler):
bl_file_extensions = '.psk;.pskx'
@classmethod
def poll_drop(cls, context: Context):
return context.area and context.area.type == 'VIEW_3D'
def poll_drop(cls, context: Context) -> bool:
return context.area is not None and context.area.type == 'VIEW_3D'
_classes = (

View File

@@ -62,6 +62,9 @@ def import_psk(psk: Psk, context: Context, name: str, options: PskImportOptions)
armature_object = None
mesh_object = None
assert context.scene
assert bpy.context.view_layer
if options.should_import_armature:
# Armature
armature_data = bpy.data.armatures.new(name)

View File

@@ -15,6 +15,7 @@ class PSK_PT_material(Panel):
def draw(self, context):
layout = self.layout
assert layout is not None
layout.use_property_split = True
layout.use_property_decorate = False
material = context.material