PyQt6: QEvent.type() returns int instead of QEvent.Type
Florian Bruhin
me at the-compiler.org
Tue May 3 14:22:48 BST 2022
On Sun, May 01, 2022 at 03:13:12PM +0100, Phil Thompson wrote:
>
> On 28/04/2022 20:16, Florian Bruhin wrote:
> > On Thu, Apr 28, 2022 at 09:42:46AM +0100, Phil Thompson wrote:
> > > So if we can solve the pickle problem I think I'd be Ok to take this
> > > approach.
> >
> > I think the most elegant way to do this is via the _missing_ classmethod
> > on enums. This is public API:
> > https://docs.python.org/3/library/enum.html#supported-sunder-names
> >
> > The drawback about the approach is that it's possible to do
> > SomePyQtEnum(1337) and that happily returns a value, so at this point,
> > the cpp2py() can probably just be implemented in _missing_ altogether.
> >
> > See the attached file. The _missing_ method needs to use cpp2py so that
> > even values which haven't been passed through cpp2py before work fine.
> >
> > This means I had to rewrite cpp2py slightly to avoid triggering
> > _missing_. The __members__ attribute is documented too:
> > https://docs.python.org/3/library/enum.html#iteration
> >
> > Alternatively, "if cpp in list(etype):" could be used, but that builds
> > up an unnecessary list ("cpp in etype" will not work, raising a
> > TypeError).
> >
> > If we didn't want to use missing (so that SomePyQtEnum(1337) does not
> > work), I suppose it can be solved by defining __reduce_ex__ on the enum
> > type somehow, but I tried, and it never was called (only enum.py's was).
>
> I had come to the same conclusion that the only way to support pickle was to
> use a sub-class of Enum and re-implement _missing_. I had hoped to be able
> to use a regular Enum (and IntEnum).
You can register a pickle function via copyreg.pickle instead:
https://docs.python.org/3/library/copyreg.html#copyreg.pickle
This seems to work:
copyreg.pickle(SomePyQtEnum, lambda py: (cpp2py, (SomePyQtEnum, py2cpp(py))))
It's the equivalent of defining an equivalent __reduce__ on the class:
SomePyQtEnum now gets pickled in a way that
cpp2py(SomePyQtEnum, raw_value) is called when unpickling, where
raw_value is py2cpp(py).
See the attached file for a complete example.
Florian
--
me at the-compiler.org | https://www.qutebrowser.org
https://bruhin.software/ | https://github.com/sponsors/The-Compiler/
GPG: 916E B0C8 FD55 A072 | https://the-compiler.org/pubkey.asc
I love long mails! | https://email.is-not-s.ms/
-------------- next part --------------
import copyreg
import pickle
from enum import Enum
class SomePyQtEnum(Enum):
one = 1
two = 2
def cpp2py(etype, cpp):
print(f"cpp2py {etype=} {cpp=}")
if cpp in etype.__members__:
return etype(cpp)
try:
return etype._sip_unknowns[cpp]
except KeyError:
pass
except AttributeError:
etype._sip_unknowns = {}
member = object.__new__(etype)
member._name_ = f"sip_unknown_{cpp}"
member._value_ = cpp
etype._sip_unknowns[cpp] = member
return member
def py2cpp(py):
return py.value
e1 = cpp2py(SomePyQtEnum, 1)
e2 = cpp2py(SomePyQtEnum, 2)
e3minus = cpp2py(SomePyQtEnum, -3)
e4 = cpp2py(SomePyQtEnum, 4)
e4a = cpp2py(SomePyQtEnum, 4)
print(e1)
print(e2)
print(e3minus)
print(e4)
print(e4a)
print(e4 is e4a)
print(py2cpp(e1))
print(py2cpp(e2))
print(py2cpp(e3minus))
print(py2cpp(e4))
copyreg.pickle(SomePyQtEnum, lambda py: (cpp2py, (SomePyQtEnum, py2cpp(py))))
dump = pickle.dumps(cpp2py(SomePyQtEnum, 4))
print(pickle.loads(dump))
# Try loading a value that has not been passed through cpp2py first.
# Generated via print(pickle.dumps(cpp2py(SomePyQtEnum, 5)))
print(pickle.loads(b'\x80\x04\x950\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x06cpp2py\x94\x93\x94h\x00\x8c\x0cSomePyQtEnum\x94\x93\x94K\x05\x86\x94R\x94.'))
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20220503/82bf47ad/attachment.sig>
More information about the PyQt
mailing list