Python based operators (for VSE)

I would like to rewrite majority of VSE operators in python

Why

Maintenance and support
By rewriting all operators, we will greatly reduce amount of code, while keeping original functionality.

All C programmers are able to write python code. The reverse is not true.
In quite short period of time I was contacted by 2 contributors, that created operators in python:
https://developer.blender.org/D4290

Cleaner implementation
We are working with objects and python is object oriented language. We can do this in C, but this can lead to repeating of code or bloated not well readable code.

Leading examples
Currently there is no example code to learn from more quickly. If we use and maintain core python operators, there is no need to maintain examples in documentation.

Improving instead of rebuilding
Great feature of python is inheritance or use decorators to improve existing operators or those introduced in addon. This can lead to more consistent UI.

Why not

Speed?
I can not agree. If you are thinking about using operator on 10 000 strips, you are probably doing it wrong.

Conventions
https://www.youtube.com/watch?v=-QfhTWJIDCM :slight_smile:
I can see that this approach may not be OK for other editors.

On the other hand all editors should have a nice and maintained object model. Using python operators would force developers to maintain it.

How

I will be explaining this for VSE, as other editors do have different workflows and interfaces.

API
Have very simple API’s to do simple things, group them in objects and collections.
Don’t know if RNA was meant to be object model, but it’s evident, that it has evolved into one.

Strip object example:
Expose all properties, that we allow user to change directly - position, length, inputs, …
Any user controllable behavior not accessible by properties should be exposed as object methods - remove, duplicate

Selection
To work effectively with selections, well-featured(filters, iterators) python object should be provided to us. Such object can be created in C using python library functions. I would rather use a interface, to which I can register an object, that will be instantiated when accessing a selection.

To further talk about selections and UI workflow, I think that it is good to introduce a mechanism of caching and invalidating a selection, so it can be accessed quickly. There are too many workarounds because of this.

Operators

This is pretty straight forward and documented, so I have pretty much nothing to say here.

list of operators after "refactoring"
http://pasteall.org/1514744

operators accessing single property (SEQUENCER_OT_mute, SEQUENCER_OT_lock, …) can be automatically generated on UI load, so number of those will be reduced. The same goes for selection classifiers and similar code

example of refactoring cut operator
In this example cut operator was rewritten in python
âš“ T58011 Deleting the strip leading up to a crossfade was fixed
new modal mode was introduced.

simplified patch:
https://developer.blender.org/D4403

 release/scripts/startup/bl_operators/sequencer.py  | 124 ++++++++++++
 .../editors/space_sequencer/sequencer_edit.c       | 207 +--------------------
 2 files changed, 125 insertions(+), 206 deletions(-)
1 Like

If that’s possible, we’d love to contribute straight to Blender! Having a reliable back-end, and an accessible API with Python’s flexibility and readability would be amazing.

Python’s performances have never been a bottleneck for us, working on Power Sequencer.

Agreed, processing selections from Python is a little cumbersome, if not hacky at times.

Thanks for your work Richard. Looking forward to hearing what other developers have to say on this :slightly_smiling_face:

This seems generally reasonable.

Be careful renaming operators and their properties since this will break keymaps and add-ons. For example in the example patch sequencer.cut was renamed to sequencer.xcut.

Regarding selections, it’s also not clear to me what you mean by creating objects in C using Python library functions. Generally our data API is defined through RNA, not Python wrapping directly unless there is a serious limitation that makes it hard or impossible.

Caching and invalidating selections also sounds like something to avoid as much as possible or at least be very careful with. Following “single source of truth” as much as practical avoids bugs.

Sure, mentioned patch is “illustrative”.

Keymaps will IMO need some rework also. But this may be part of âš“ T54963 Industry Compatible Keymap. I see that this task have quite advanced so I may talk to billreynish regarding this.

As for addons, seems that currently there are no official addons for sequencer? That would be good news for me at least :slight_smile:
There are quite a few unofficial, not sure how many of them are maintained / working in 2.8

What I mean here is a collection rather then selection.
I am not sure if this is possible currently, but the goal is:

Imagine container class with a bunch of convenience methods:

class MyStrips(bpy.types.Strips):
    define iterators, generators, etc.

    def add(self, strips):
        return Strips(set(self.strips) | set(strips))
    def omit(self, strips):
        return Strips(set(self.strips) - set(strips))
    def intersect(self, strips):
        return Strips(set(self.strips) & set(strips.strips))
    def filter_selected(self):
        return self.intersect(self, self.selected())
    def filter_type(self, types):
        return Strips([s for s in self.strips if s.type in list(types)])
    ...

During UI initialization I would call
I guess Strips class would have to be instance of bpy.types.Strips type, that would have to be introduced
bpy.utils.register_class(Strips)

Then, every time I would access bpy.context.sequences a instance of a Strips object would be returned.

With class like this, I can write operator for deleting muted strips in one line:
context.selected_sequences.muted().delete()
Or nicer:
context.sequences.selected().muted().delete()

This will also allow addons to inherit from default MyStrips, add their own convenience methods and re-register this container class.

It is possible to use MyStrips class by instantiating it manually. In fact I haven’t seen custom container interface in any other “macro language” API.

If this is easily achievable, I would go for it, if not I will have to consider if it’s worth the effort.

Maybe I shouldn’t mention selections now/here, as I am absolutely not familiar with “under the hood” RNA code, nor ever seen cross-language templating attempted using C language (honestly I was quite stunned).

I will investigate this once I will be more familiar with underlying code…

Would rather this not be done as part of 2.8 development, since it takes time for review and probably some of the sequencer internals will have to be exposed in RNA/Python which takes time to review.

  • This is likely to add bugs or at least issues to resolve.

  • The RNA/Python API will likely need extending.

  • Don’t think meta-strip make/toggle make sense to move to Python (the way pointers are handled there would need to be a C API that Python would call).

  • Don’t think view operations like view-all or view-selected have much to gain from being rewritten in Python.

  • Not convinced wrapping context.selected_sequences is a good idea, at least in the way you have suggested. Currently this is a simple list type which all Python developers know how to use, having custom iterator types means you don’t have lots of handy methods (a in b, b.pop(i), b.copy(), b.reverse() or b[i:j] = [...]). You can implement them all but that’s not trivial. It’s a heavy solution for something you can manage by simply having a utility function that does the same thing.

    If you’re keen to have direct access to these, you could define context.selected_sequences_filtered for alternate access to the existing context.selected_sequences.

Suggest to keep core operators (select/view/mode switching) in C, these don’t change often and it’s not especially good use of time to rewrite.

Instead, port utilities - like export subtitles, enable proxies, change path, select grouped… etc. Areas that extend on the basic tool set and have more to gain from being easily modified.

please define “this” :slight_smile:

If “this” is the whole topic we can settle on abandoning this idea, otherwise we can discuss about specific sub-topics that can be done.

I am not keen nor on proposal nor on proposed solution. However I would like to use such utility function without forcing it on anyone else if that’s OK.

True this slipped through. Also applies to other meta operators and SEQUENCER_OT_sample is maybe even impossible.

Technically meta_make could be dissolved into strip_add API function returning seqbase and moving strips from original seqbase to meta seqbase.

To be as exact about this I will re-make the list and we can approve/disapprove specific items
http://pasteall.org/1517596

As for modifying RNA API
I will create a tree structure of what I plan to do and we can look at that.

I forgot to mention quite significant point to justify a change. That is getting a reference to created objects. For example, when you add or duplicate strip using operator, you have to iterate seqbase to find it relying on unique name, extrapolating from all existing names. That is as bad, as it sounds…

Blender 2.8x needs to be released, noting that I wouldn’t attempt to make this project a 2.8x target, its even a risk that these kinds of changes introduce regressions.
Also, it shouldn’t take too much time away from 2.8x development.


Sure, maybe have handy functions in bpy_extra, we use this already for handy things which can be shared but aren’t part of the core API.


Yes, but if a Python operator only exists to call some RNA function, there isn’t much point.


We can always improve the API’s, but isn’t especially related to moving operators to Python.

Ok, I expect this makes simple code more compact, but for more complicated cases I think it will either not help or become hard to understand.

Consider this example:

 context.sequences.selected().muted().delete()

Here you are deleting data while iterating over it. You risk accessing invalid memory or the abstraction data structures getting out of sync with the Blender data structures.

It may be possible to implement the abstraction in such a way that this works, but understanding or debugging if it fails is not as easy.

Regarding this, while it’s nice to use builder pattern to do chain operations in a convenient way, I don’t think these kinds of operations gain us that much compared to the long-hand version:

ed = scene.sequence_editor
for seq in context.sequences:
    if seq.select and seq.muted:
        ed.sequences.remove(seq)

It’s a bit verbose, but you only have … ~10 blocks of code like this? - maybe 30 max. If they are exact duplicates they can be wrapped into a function so it should be possible to avoid too much copy pasting.

It’s very clear whats going on to any one two wants to jump in and help develop the code, and they don’t need to understand the internal behavior of some clever chaining iterator which might be doing things like ignoring hidden or deferring some destructive operations until later.

Ok thanks for feedback
Got a point - don’t overengineer stuff. I tend to do that when thinking about design…

Now I would tackle logistics.

I guess, that Ton would like 2.8 to be out already
You admins do have a lot of bug fixing and not even thinking about introducing any big features(like this) now.

Nathan (GDquest) has goal of porting his addon to 2.8, willing to contriute to core functionality(as long as it’s done in python)
My priority is preview performance, but want to work on usability issues also.

I guess this rules out inclusion in 2.80, not sure how release schedule is looking now though.

Anyway plan is, write a list of intended changes, then work on this in a branch to get this prepared for release.
When done, I will post patch for RNA
We can look at list of operators as some of them may be not suitable for core
Post operator patches presumably grouped by functionality.
Remove C code

Nathan, do you have idea, when you want to start, and what’s your timeline?

Razvan is porting the add-on to Blender 2.8 now. As we always have plenty of work to do, as far as I’m concerned, it’s best if we can work in a continuous exchange.

I got in touch with Pablo some time ago, asked if I could come to the foundation’s office and contribute to the VSE at some point. Ton said he was ok with that. I’ll be back in Japan for a few months from April, but after that I’d like to do a video series on contributing to FOSS, probably mostly Godot and Blender. That will have to wait until summer though.

Until then I’m around on request. And I sponsor Razvan, the most experienced dev in our team, to develop tools and contribute some code to e.g. Krita some time ago.