Python3to2 __future__.unicode_literalsをimportすると QPropertyAnimation が動かない

python,qt,PySide,maya,PySide2

ここ最近mayaがpython2からpython3についに移行ということで何かといろいろな情報が飛び交っているかと思いますがQPropertyAnimationを使っているPySideがアニメーションしないということがあったので解決策を共有します

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals


import sys
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *


class GUI(QFrame):
    def __init__(self, parent=None, *args, **kwargs):
        super(GUI, self).__init__(parent, *args, **kwargs)
        self.setWindowTitle("Animation Test")
        self.resize(500, 300)
        self.btn = QPushButton("Animation Button", self)
        self.btn.move(50, 50)

        move_anim = self.create_move_anim(self.btn)

        def start_move_anim():
            move_anim.start()

        self.btn.clicked.connect(start_move_anim)

    def create_move_anim(self, widget):
        anim = QPropertyAnimation(widget, "pos")
        anim.setDuration(1000)
        anim.setEndValue(
            QPoint(widget.x() + 100, widget.y() + 100)
        )
        return anim


def main():
    app = QApplication.instance()
    gui = GUI()
    gui.show()
    sys.exit()
    app.exec_()


if __name__ == '__main__':
    main()

上のコードは一見何の変哲もないPushButtonを押したらPushButtonが移動するだけのコードですが実はこのコード機能しません
というのもPySideなどの一部のモジュールでは、引数としてバイトオブジェクトを提供する必要がある場合があり、上のコードはPy3の挙動に一部の関数や命令の挙動を変更できるようにfutureをimportしてます
このfutureの影響で上のコードを実行することができなくなっています

Py2では、QPropertyAnimationのインスタンス化は、標準の文字列(str == bytesとして)を使用して実行できるのですが

proAnim = QPropertyAnimation("pos")
# result <<class 'PySide2.QtCore.QPropertyAnimation'>

Py3では、文字列の前に小文字の「b」または事前にインスタンス化されたバイトオブジェクトを付ける必要があります

proAnim = QPropertyAnimation(b"pos")
# result <<class 'PySide2.QtCore.QPropertyAnimation'>

つまり、最初のコードを実行できるように書き直すと
29行目のanim = QPropertyAnimation(widget, "pos")anim = QPropertyAnimation(widget, b"pos")とバイト型で扱うようにする必要があります

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals


import sys
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *


class GUI(QFrame):
    def __init__(self, parent=None, *args, **kwargs):
        super(GUI, self).__init__(parent, *args, **kwargs)
        self.setWindowTitle("Animation Test")
        self.resize(500, 300)
        self.btn = QPushButton("Animation Button", self)
        self.btn.move(50, 50)

        move_anim = self.create_move_anim(self.btn)

        def start_move_anim():
            move_anim.start()

        self.btn.clicked.connect(start_move_anim)

    def create_move_anim(self, widget):
        anim = QPropertyAnimation(widget, b"pos")
        anim.setDuration(1000)
        anim.setEndValue(
            QPoint(widget.x() + 100, widget.y() + 100)
        )
        return anim


def main():
    app = QApplication.instance()
    gui = GUI()
    gui.show()
    sys.exit()
    app.exec_()


if __name__ == '__main__':
    main()


参考
Supporting Py2 & Py3 Part 1