Page MenuHome

Support for int, float types in BlendFileBlock.set
ClosedPublic

Authored by William Harrell (ProphetOfXenu) on Mar 18 2022, 4:26 AM.

Details

Summary

The blendfile module within BAT supports reading data from structs, such
as the Count property on an array modifier. However, blendfile only
supports modifying structs with type "char". This patch adds support for
writing structs of more types in blendfile blocks. Now, writing is
supported for ushort, short, uint, int, float, and ulong types.

The use case that inspired this patch was an instance where a file had
several array modifiers that prevented the file from being opened in
Blender on machines without large amounts of RAM. A solution using the
blendfile module may look like:

from blender_asset_tracer import blendfile
from pathlib import Path

b = blendfile.open_cached(Path('flag.blend'), mode='rb+')

for block in b.blocks:
    if 'ArrayModifierData' in block.__str__():
        try:
            print('previous:', block.get(b'count'))
            block.set(b'count', 1)
            print('current:', block.get(b'count'))
        except KeyError:
            continue

b.close()

This would fail with the exception
`blender_asset_tracer.blendfile.exceptions.NoWriterImplemented: Setting
type Struct(b'int') is not supported for ArrayModifierData.count`. With
this patch, the above code succeeds and the count struct can be set to
a lower number that allows the file to be opened.

This solution implements missing functionality without adding any new
interfaces. A few details are:

  • When deciding what type to write to the struct, the value is inferred

from what is given by the caller. If the caller gives a Python int, the
exact type is inferred from the DNA type ID. If they give a float, a
float is written. Otherwise, the existing logic is used to determine
whether to write a string or byte sequence.

  • A \_write method was added to dna\_io.py that takes a Python struct

object and a value to write a byte sequence to the file object. This
method is used by public methods appropriately named to indicate what
type they will write.

  • The check for whether the caller is trying to write an unsupported

type is left in place, but it has been changed to include types which
are now supported.

  • Tests have been added that provide a mock file object, call the new

methods, and confirm that the correct bytes were written.

Diff Detail

Repository
rBAST Blender Asset Tracer
Branch
dnaio-newtypes (branched from master)
Build Status
Buildable 21098
Build 21098: arc lint + arc unit

Event Timeline

William Harrell (ProphetOfXenu) requested review of this revision.Mar 18 2022, 4:26 AM
William Harrell (ProphetOfXenu) created this revision.
Sybren A. Stüvel (sybren) requested changes to this revision.Mar 18 2022, 11:51 AM

Thanks for the patch! It looks good to me, just a few smaller things to consider.

blender_asset_tracer/blendfile/dna.py
327–338

This is now rather tightly coupled with the if/elif-chain below. I think it would be better to have some dict with a mapping from dna_type_id to the write_xxx function that matches it. That dict can then be used here for this check, as well as to remove the if-chain below.

349–352

There is no need to set the variable to an empty string, because it's always set immediately below anyway.

350

isinstance can take a tuple of types, so this can be replaced by if isinstance(value, (int, float)):

351

You can remove "utf-8", as it's the default anyway.

blender_asset_tracer/blendfile/dna_io.py
52

Which line in the try block will raise this error? Only put that line into the try block, and the other outside it.

This revision now requires changes to proceed.Mar 18 2022, 11:51 AM
  • Refactoring for previous commit
Sybren A. Stüvel (sybren) requested changes to this revision.Mar 18 2022, 3:55 PM
Sybren A. Stüvel (sybren) added inline comments.
blender_asset_tracer/blendfile/dna.py
327–336

I think this belongs to the EndianIO class. After all, the only thing it references are attributes of endian.

This revision now requires changes to proceed.Mar 18 2022, 3:55 PM
William Harrell (ProphetOfXenu) marked an inline comment as done.
  • Moved accepted_types dict to dna_io.py
blender_asset_tracer/blendfile/dna_io.py
199

Is there a better way to serve this dictionary? I tried just making it a property on the class, but I kept getting the error "TypeError: 'classmethod' object is not callable" when trying to lookup a function and call it.

Just a few small notes. I want to release a new version of BAT right now, so I'll accept the patch as-is and add some comments when I commit it. Thanks for the work!

blender_asset_tracer/blendfile/dna_io.py
199

You can't use @classmethod on a property, because it's meant to go onto methods (i.e. functions defined on a class).

I think this approach is fine, though, as it will also work with the different subclasses.

199

This function does need a docstring, to explain its use.

This revision is now accepted and ready to land.Mar 25 2022, 11:58 AM

Your patch was just released as part of BAT 1.12 :)