<div dir="ltr"><div class="markdown-here-wrapper" style=""><p style="margin:1.2em 0px!important">Hi Phil,</p>
<p style="margin:1.2em 0px!important">Do you have any recommendations for alternatives to pyqtWrapperType when it comes to metaclasses? I was using it to dynamically add signals to a QObject.</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code class="hljs language-python" style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline;white-space:pre;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important;display:block;overflow-x:auto;padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,248)"><span class="hljs-class"><span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">class</span> <span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold;color:rgb(68,85,136);font-weight:bold">PropertyType</span><span class="hljs-params">(QtCore.pyqtWrapperType)</span>:</span>
    <span class="hljs-string" style="color:rgb(221,17,68)">"""Metaclass for converting class attributes into pyqtProperties"""</span>

    prefix = <span class="hljs-string" style="color:rgb(221,17,68)">"__pyqtproperty__"</span>

    <span class="hljs-function"><span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">def</span> <span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">__new__</span><span class="hljs-params">(cls, name, bases, attrs)</span>:</span>
        <span class="hljs-string" style="color:rgb(221,17,68)">"""Convert class properties into pyqtProperties"""</span>

        <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">for</span> key, value <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">in</span> attrs.copy().items():
            <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">if</span> key.startswith(<span class="hljs-string" style="color:rgb(221,17,68)">"__"</span>):
                <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">continue</span>

            notify = QtCore.pyqtSignal()

            <span class="hljs-function"><span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">def</span> <span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">set_data</span><span class="hljs-params">(key, value)</span>:</span>
                <span class="hljs-function"><span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">def</span> <span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">set_data</span><span class="hljs-params">(self, value)</span>:</span>
                    setattr(self, cls.prefix + key, value)
                    getattr(self, key + <span class="hljs-string" style="color:rgb(221,17,68)">"Changed"</span>).emit()
                    self.__datachanged__.emit(self)
                <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">return</span> set_data

            attrs[key + <span class="hljs-string" style="color:rgb(221,17,68)">"Changed"</span>] = notify
            attrs[key] = QtCore.pyqtProperty(
                type(value) <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">if</span> value <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">is</span> <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">not</span> <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">None</span> <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">else</span> QtCore.QVariant,
                fget=<span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">lambda</span> self, k=key: getattr(self, cls.prefix + k, <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">None</span>),
                fset=set_data(key, value),
                notify=notify)

        <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">return</span> super(PropertyType, cls).__new__(cls, name, bases, attrs)

<span class="hljs-class"><span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">class</span> <span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold;color:rgb(68,85,136);font-weight:bold">AbstractItem</span><span class="hljs-params">(QtCore.QObject)</span>:</span>
    __metaclass__ = PropertyType
    __datachanged__ = QtCore.pyqtSignal(QtCore.QObject)

    <span class="hljs-function"><span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">def</span> <span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">__str__</span><span class="hljs-params">(self)</span>:</span>
        <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">return</span> <a href="http://self.name">self.name</a>

    <span class="hljs-function"><span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">def</span> <span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">__repr__</span><span class="hljs-params">(self)</span>:</span>
        <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">return</span> <span class="hljs-string" style="color:rgb(221,17,68)">"%s.%s(%r)"</span> % (__name__, type(self).__name__, self.__str__())
</code></pre>
<p style="margin:1.2em 0px!important">Using <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">type</code> in place of <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">pyqtWrapperType</code> results in a:</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline;white-space:pre;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important">TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
</code></pre><p style="margin:1.2em 0px!important">Production code <a href="https://github.com/pyblish/pyblish-qml/blob/7c20ef38837cfbe91b28cb5c6a708c3c5aae96da/pyblish_qml/models.py#L94">here</a>.</p>
<p style="margin:1.2em 0px!important">Any ideas?</p>
<p style="margin:1.2em 0px!important">Thanks.</p>
<div title="MDH:SGkgUGhpbCw8ZGl2Pjxicj48L2Rpdj48ZGl2PkRvIHlvdSBoYXZlIGFueSByZWNvbW1lbmRhdGlv
bnMgZm9yIGFsdGVybmF0aXZlcyB0byBweXF0V3JhcHBlclR5cGUgd2hlbiBpdCBjb21lcyB0byBt
ZXRhY2xhc3Nlcz8gSSB3YXMgdXNpbmcgaXQgdG8gZHluYW1pY2FsbHkgYWRkIHNpZ25hbHMgdG8g
YSBRT2JqZWN0LjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+YGBgcHl0aG9uPC9kaXY+PGRpdj48
ZGl2PmNsYXNzIFByb3BlcnR5VHlwZShRdENvcmUuPHdicj5weXF0V3JhcHBlclR5cGUpOjxicj48
L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgIiIiTWV0YWNsYXNzIGZvciBjb252ZXJ0aW5nIGNsYXNz
IGF0dHJpYnV0ZXMgaW50byBweXF0UHJvcGVydGllcyIiIjwvZGl2PjxkaXY+PGJyPjwvZGl2Pjxk
aXY+Jm5ic3A7ICZuYnNwOyBwcmVmaXggPSAiX19weXF0cHJvcGVydHlfXyI8L2Rpdj48ZGl2Pjxi
cj48L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgZGVmIF9fbmV3X18oY2xzLCBuYW1lLCBiYXNlcywg
YXR0cnMpOjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICIiIkNvbnZlcnQg
Y2xhc3MgcHJvcGVydGllcyBpbnRvIHB5cXRQcm9wZXJ0aWVzIiIiPC9kaXY+PGRpdj48YnI+PC9k
aXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgZm9yIGtleSwgdmFsdWUgaW4gYXR0
cnMuY29weSgpLml0ZW1zKCk6PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsg
Jm5ic3A7ICZuYnNwOyBpZiBrZXkuc3RhcnRzd2l0aCgiX18iKTo8L2Rpdj48ZGl2PiZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgY29udGludWU8
L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJz
cDsgJm5ic3A7IG5vdGlmeSA9IFF0Q29yZS5weXF0U2lnbmFsKCk8L2Rpdj48ZGl2Pjxicj48L2Rp
dj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IGRlZiBzZXRf
ZGF0YShrZXksIHZhbHVlKTo8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgZGVmIHNldF9kYXRhKHNlbGYsIHZhbHVlKTo8L2Rp
dj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyBzZXRhdHRyKHNlbGYsIGNscy5wcmVmaXggKyBrZXksIHZhbHVl
KTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IGdldGF0dHIoc2VsZiwga2V5ICsgIkNoYW5nZWQiKS5l
bWl0KCk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7
ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBzZWxmLl9fZGF0YWNoYW5nZWRfXy5lbWl0KDx3
YnI+c2VsZik8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgcmV0dXJuIHNldF9kYXRhPC9kaXY+PGRpdj48YnI+PC9kaXY+PGRp
dj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBhdHRyc1trZXkgKyAi
Q2hhbmdlZCJdID0gbm90aWZ5PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsg
Jm5ic3A7ICZuYnNwOyBhdHRyc1trZXldID0gUXRDb3JlLnB5cXRQcm9wZXJ0eSg8L2Rpdj48ZGl2
PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsg
dHlwZSh2YWx1ZSkgaWYgdmFsdWUgaXMgbm90IE5vbmUgZWxzZSBRdENvcmUuUVZhcmlhbnQsPC9k
aXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsg
Jm5ic3A7IGZnZXQ9bGFtYmRhIHNlbGYsIGs9a2V5OiBnZXRhdHRyKHNlbGYsIGNscy5wcmVmaXgg
KyBrLCBOb25lKSw8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsg
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgZnNldD1zZXRfZGF0YShrZXksIHZhbHVlKSw8L2Rpdj48ZGl2
PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsg
bm90aWZ5PW5vdGlmeSk8L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5i
c3A7ICZuYnNwOyByZXR1cm4gc3VwZXIoUHJvcGVydHlUeXBlLCBjbHMpLl9fbmV3X18oY2xzLCBu
YW1lLCBiYXNlcywgYXR0cnMpPC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRp
dj5jbGFzcyBBYnN0cmFjdEl0ZW0oUXRDb3JlLlFPYmplY3QpOjwvZGl2PjxkaXY+Jm5ic3A7ICZu
YnNwOyBfX21ldGFjbGFzc19fID0gUHJvcGVydHlUeXBlPGJyPjwvZGl2PjxkaXY+Jm5ic3A7ICZu
YnNwOyBfX2RhdGFjaGFuZ2VkX18gPSBRdENvcmUucHlxdFNpZ25hbChRdENvcmUuPHdicj5RT2Jq
ZWN0KTwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyBkZWYgX19zdHJfXyhz
ZWxmKTo8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyByZXR1cm4gPGEgaHJl
Zj0iaHR0cDovL3NlbGYubmFtZSIgdGFyZ2V0PSJfYmxhbmsiPnNlbGYubmFtZTwvYT48L2Rpdj48
ZGl2Pjxicj48L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgZGVmIF9fcmVwcl9fKHNlbGYpOjwvZGl2
PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IHJldHVybiAiJXMuJXMoJXIpIiAlIChf
X25hbWVfXywgdHlwZShzZWxmKS5fX25hbWVfXywgc2VsZi5fX3N0cl9fKCkpPC9kaXY+PC9kaXY+
PGRpdj5gYGA8L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PlVzaW5nIGB0eXBlYCBpbiBwbGFjZSBv
ZiBgcHlxdFdyYXBwZXJUeXBlYCByZXN1bHRzIGluIGE6PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRp
dj5gYGA8L2Rpdj48ZGl2PlR5cGVFcnJvcjogbWV0YWNsYXNzIGNvbmZsaWN0OiB0aGUgbWV0YWNs
YXNzIG9mIGEgZGVyaXZlZCBjbGFzcyBtdXN0IGJlIGEgKG5vbi1zdHJpY3QpIHN1YmNsYXNzIG9m
IHRoZSBtZXRhY2xhc3NlcyBvZiBhbGwgaXRzIGJhc2VzPGJyPjwvZGl2PjxkaXY+YGBgPC9kaXY+
PGRpdj48YnI+PC9kaXY+PGRpdj5Qcm9kdWN0aW9uIGNvZGUgW2hlcmVdKGh0dHBzOi8vZ2l0aHVi
LmNvbS9weWJsaXNoL3B5Ymxpc2gtcW1sL2Jsb2IvN2MyMGVmMzg4MzdjZmJlOTFiMjhjYjVjNmE3
MDhjM2M1YWFlOTZkYS9weWJsaXNoX3FtbC9tb2RlbHMucHkjTDk0KS48L2Rpdj48ZGl2Pjxicj48
L2Rpdj48ZGl2PkFueSBpZGVhcz88L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PlRoYW5rcy48L2Rp
dj4=" style="height:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0">​</div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On 18 January 2017 at 22:17, Phil Thompson <span dir="ltr"><<a href="mailto:phil@riverbankcomputing.com" target="_blank">phil@riverbankcomputing.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On 18 Jan 2017, at 6:51 pm, Cody Scott <<a href="mailto:cody@perspexis.com">cody@perspexis.com</a>> wrote:<br>
><br>
> I'm looking at this code for inspiration on testing QML and I ran into this error.<br>
><br>
> <a href="https://github.com/pyblish/pyblish-qml/blob/635c82d75fa5d5e294339bf8265f05eb5ca3b5d3/pyblish_qml/models.py#L94" rel="noreferrer" target="_blank">https://github.com/pyblish/<wbr>pyblish-qml/blob/<wbr>635c82d75fa5d5e294339bf8265f05<wbr>eb5ca3b5d3/pyblish_qml/models.<wbr>py#L94</a><br>
><br>
> AttributeError: module 'PyQt5.QtCore' has no attribute 'pyqtWrapperType'<br>
><br>
> It doesn't appear to be available in PyQt5==5.7.1<br>
><br>
> It is available in PyQt5==5.6<br>
<br>
</div></div>It was an undocumented implementation detail that was removed as part of the adoption of the limited API.<br>
<br>
If code wants to get the meta-type used by PyQt then it should call type() on a PyQt type object.<br>
<br>
Phil<br>
______________________________<wbr>_________________<br>
PyQt mailing list    <a href="mailto:PyQt@riverbankcomputing.com">PyQt@riverbankcomputing.com</a><br>
<a href="https://www.riverbankcomputing.com/mailman/listinfo/pyqt" rel="noreferrer" target="_blank">https://www.<wbr>riverbankcomputing.com/<wbr>mailman/listinfo/pyqt</a></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><font size="1"><b>Marcus Ottosson</b><br><a href="mailto:konstruktion@gmail.com" target="_blank">konstruktion@gmail.com</a></font><font size="1"><br></font></div></div>
</div>