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: def build_psa(context: Context, options: PsaBuildOptions) -> Psa:
assert context.scene
assert context.window_manager
psa = Psa() psa = Psa()
armature_objects_for_bones = options.armature_objects 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)))) export_bones.append(PsaExportBone(None, None, Vector((1.0, 1.0, 1.0))))
continue continue
assert armature_object.pose
pose_bone = armature_object.pose.bones[psx_bone.name.decode('windows-1252')] pose_bone = armature_object.pose.bones[psx_bone.name.decode('windows-1252')]
export_bones.append(PsaExportBone(pose_bone, armature_object, armature_scales[armature_object])) 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. # Restore the previous actions & frame.
for armature_object, action in saved_armature_object_actions.items(): for armature_object, action in saved_armature_object_actions.items():
assert armature_object.animation_data
armature_object.animation_data.action = action armature_object.animation_data.action = action
context.scene.frame_set(saved_frame_current) context.scene.frame_set(saved_frame_current)

View File

@@ -462,6 +462,9 @@ class PSA_OT_export(Operator, ExportHelper):
if animation_data is None: if animation_data is None:
raise RuntimeError(f'No animation data for object \'{animation_data_object.name}\'') 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] = [] export_sequences: List[PsaBuildSequence] = []
match pg.sequence_source: 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: def sequence_source_update_cb(self: 'PSA_PG_export', context: Context) -> None:
armature_objects = [] armature_objects = []
assert context.view_layer
for dfs_object in dfs_view_layer_objects(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: if dfs_object.obj.type == 'ARMATURE' and dfs_object.is_selected:
armature_objects.append(dfs_object.obj) armature_objects.append(dfs_object.obj)

View File

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

View File

@@ -1,7 +1,7 @@
import bmesh import bmesh
import bpy import bpy
import numpy as np 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 mathutils import Matrix
from typing import Dict, Iterable, List, Optional, Set, cast as typing_cast from typing import Dict, Iterable, List, Optional, Set, cast as typing_cast
from .data import Psk from .data import Psk
@@ -94,9 +94,9 @@ def get_psk_input_objects_for_collection(collection: Collection) -> PskInputObje
class PskBuildResult(object): class PskBuildResult(object):
def __init__(self): def __init__(self, psk: Psk, warnings: list[str]):
self.psk = None self.psk: Psk = psk
self.warnings: List[str] = [] self.warnings: List[str] = warnings
def _get_mesh_export_space_matrix(armature_object: Optional[Object], export_space: str) -> Matrix: 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: def build_psk(context: Context, input_objects: PskInputObjects, options: PskBuildOptions) -> PskBuildResult:
assert context.window_manager
armature_objects = list(input_objects.armature_objects) armature_objects = list(input_objects.armature_objects)
result = PskBuildResult() warnings: list[str] = []
psk = Psk() psk = Psk()
psx_bone_create_result = create_psx_bones( 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. # Temporarily force the armature into the rest position.
# We will undo this later. # We will undo this later.
for armature_object in armature_objects: 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] 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: match options.object_eval_state:
case 'ORIGINAL': case 'ORIGINAL':
mesh_object = obj mesh_object = obj
mesh_data = obj.data mesh_data = typing_cast(Mesh, obj.data)
case 'EVALUATED': case 'EVALUATED':
# Create a copy of the mesh object after non-armature modifiers are applied. # Create a copy of the mesh object after non-armature modifiers are applied.
depsgraph = context.evaluated_depsgraph_get() depsgraph = context.evaluated_depsgraph_get()
@@ -299,7 +303,7 @@ def build_psk(context: Context, input_objects: PskInputObjects, options: PskBuil
mesh_data.calc_loop_triangles() mesh_data.calc_loop_triangles()
if mesh_data.uv_layers.active is None: 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. # Build a list of non-unique wedges.
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. # Restore the original pose position of the armature objects.
for armature_object, pose_position in original_armature_object_pose_positions.items(): 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. # https://github.com/DarklightGames/io_scene_psk_psa/issues/129.
psk.sort_and_normalize_weights() psk.sort_and_normalize_weights()
context.window_manager.progress_end() context.window_manager.progress_end()
result.psk = psk return PskBuildResult(psk, warnings)
return result

View File

@@ -3,7 +3,7 @@ from typing import Iterable, List, Optional, cast as typing_cast
import bpy import bpy
from bpy.props import BoolProperty, StringProperty 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 bpy_extras.io_utils import ExportHelper
from .properties import PskExportMixin 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') self.report({'ERROR_INVALID_CONTEXT'}, 'No valid export operator found in context')
return {'CANCELLED'} return {'CANCELLED'}
depsgraph = context.evaluated_depsgraph_get() depsgraph = context.evaluated_depsgraph_get()
assert context.collection
input_objects = get_psk_input_objects_for_collection(context.collection) input_objects = get_psk_input_objects_for_collection(context.collection)
try: try:
populate_material_name_list(depsgraph, [x.obj for x in input_objects.mesh_dfs_objects], export_operator.material_name_list) 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') name: StringProperty(search=material_list_names_search_cb, name='Material Name', default='None')
def invoke(self, context, event): def invoke(self, context, event):
assert context.window_manager
return context.window_manager.invoke_props_dialog(self) return context.window_manager.invoke_props_dialog(self)
def execute(self, context): def execute(self, context):
@@ -266,7 +268,10 @@ class PSK_OT_export_collection(Operator, ExportHelper, PskExportMixin):
collection: StringProperty(options={'HIDDEN'}) collection: StringProperty(options={'HIDDEN'})
def execute(self, context): 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: try:
input_objects = get_psk_input_objects_for_collection(collection) 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): def draw(self, context: Context):
layout = self.layout layout = self.layout
assert layout is not None
flow = layout.grid_flow(row_major=True) flow = layout.grid_flow(row_major=True)
flow.use_property_split = True flow.use_property_split = True
flow.use_property_decorate = False flow.use_property_decorate = False
@@ -376,6 +383,8 @@ class PSK_OT_export_collection(Operator, ExportHelper, PskExportMixin):
flow.enabled = False flow.enabled = False
case 'CUSTOM': case 'CUSTOM':
transform_source = self transform_source = self
case _:
assert False, f'Invalid transform source: {self.transform_source}'
flow.prop(transform_source, 'scale') flow.prop(transform_source, 'scale')
flow.prop(transform_source, 'forward_axis') flow.prop(transform_source, 'forward_axis')
@@ -414,6 +423,7 @@ class PSK_OT_export(Operator, ExportHelper):
self.report({'ERROR_INVALID_CONTEXT'}, str(e)) self.report({'ERROR_INVALID_CONTEXT'}, str(e))
return {'CANCELLED'} return {'CANCELLED'}
assert context.window_manager
context.window_manager.fileselect_add(self) context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'} return {'RUNNING_MODAL'}
@@ -421,6 +431,8 @@ class PSK_OT_export(Operator, ExportHelper):
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
assert layout
pg = getattr(context.scene, 'psk_export') pg = getattr(context.scene, 'psk_export')
# Mesh # Mesh
@@ -490,6 +502,8 @@ class PSK_OT_export(Operator, ExportHelper):
def execute(self, context): def execute(self, context):
pg = getattr(context.scene, 'psk_export') pg = getattr(context.scene, 'psk_export')
assert context.scene
input_objects = get_psk_input_objects_for_context(context) input_objects = get_psk_input_objects_for_context(context)
options = get_psk_build_options_from_property_group(context.scene, pg) 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: CollectionProperty(type=PSK_PG_material_name_list_item)
material_name_list_index: IntProperty(default=0) material_name_list_index: IntProperty(default=0)
should_export_vertex_normals: BoolProperty( should_export_vertex_normals: BoolProperty(
'Export Vertex Normals', name='Export Vertex Normals',
default=False, default=False,
description='Export VTXNORMS section.' description='Export VTXNORMS section.'
) )

View File

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

View File

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

View File

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