Tuesday, January 13, 2015

Clarifying one issue with cxfreeze

Continuing the prior post...

The cx_Freeze-bundled writer produced settings that neither the CPython- nor the cx_Frozen reader could read. Under CPython, the writer produced settings that the CPython-reader could read. Clearly the output of the two writers was different; in what way?

cx_Frozen writer settings plist:
0000: 62 70 6C 69 73 74 30 30 D3 01 02 03 04 05 06 51  bplist00.......Q
0010: 63 51 69 51 62 5A 63 68 61 72 61 63 74 65 72 73  cQiQbZcharacters
0020: 11 0F FF 5F 10 24 40 56 61 72 69 61 6E 74 28 00  ..._.$@Variant(.
0030: 00 00 7F 00 00 00 0E 50 79 51 74 5F 50 79 4F 62  ......PyQt_PyOb
0040: 6A 65 63 74 00 00 00 00 00 29 08 0F 11 13 15 20  ject.....)..... 
0050: 23 00 00 00 00 00 00 01 01 00 00 00 00 00 00 00  #...............
0060: 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0070: 4A                                               J
CPython writer settings plist:
0000: 62 70 6C 69 73 74 30 30 D3 01 02 03 04 05 06 51  bplist00.......Q
0010: 63 51 69 51 62 5A 63 68 61 72 61 63 74 65 72 73  cQiQbZcharacters
0020: 11 0F FF 6F 10 2F 00 40 00 56 00 61 00 72 00 69  ...o./.@.V.a.r.i
0030: 00 61 00 6E 00 74 00 28 00 00 00 00 00 00 00 7F  .a.n.t.(.......
0040: 00 00 00 00 00 00 00 0E 00 50 00 79 00 51 00 74  .........P.y.Q.t
0050: 00 5F 00 50 00 79 00 4F 00 62 00 6A 00 65 00 63  ._.P.y.O.b.j.e.c
0060: 00 74 00 00 00 00 00 00 00 00 00 0B 00 80 00 03  .t..............
0070: 00 43 00 04 00 DE 00 AD 00 BE 00 EF 00 71 00 00  .C...........q..
0080: 00 2E 00 29 08 0F 11 13 15 20 23 00 00 00 00 00  ...)..... #.....
0090: 00 01 01 00 00 00 00 00 00 00 07 00 00 00 00 00  ................
00A0: 00 00 00 00 00 00 00 00 00 00 84                 ...........

The writer program, when cx_Frozen, writes strings in Latin-1. The CPython writer, writes what I assume are UTF-16 character strings. At least, how else to explain "@Variant" and "PyQt_PyObject" being spaced out with \x00 bytes?

However, remember the behaviour.

[12:44:30 pyinst] rm /Users/dcortesi/Library/Preferences/com.bogosity.BOGUS.plist
[12:45:39 pyinst] writer.dist/writer
[12:45:43 pyinst] python reader.py c
key c value characters
[12:45:48 pyinst] python reader.py i
key i value 4095
[12:45:53 pyinst] python reader.py b
Traceback (most recent call last):
  File "reader.py", line 12, in 
    value = settings.value(sys.argv[1],"?")
TypeError: unable to convert a QVariant back to a Python object

The reader is not bothered when fetching the "c" characters or the "i" integer. But! The three keys (QcQiQb) and the values for "c" ("characters") and for "i" (int 4095, visible at 00021-2) all precede the point where the UTF-16 strings begin. So the CPython reader execution can get those without trouble. It only runs into a problem when it has to decode what I assume is the header for a QVariant.

So: character encoding of the QSettings plist changes when the code is cx_Frozen. Does the Nuitka-compiled writer also do this?

Nuitka writer settings plist:
0000: 62 70 6C 69 73 74 30 30 D3 01 02 03 04 05 06 51  bplist00.......Q
0010: 63 51 69 51 62 5A 63 68 61 72 61 63 74 65 72 73  cQiQbZcharacters
0020: 11 0F FF 6F 10 2F 00 40 00 56 00 61 00 72 00 69  ...o./.@.V.a.r.i
0030: 00 61 00 6E 00 74 00 28 00 00 00 00 00 00 00 7F  .a.n.t.(.......
0040: 00 00 00 00 00 00 00 0E 00 50 00 79 00 51 00 74  .........P.y.Q.t
0050: 00 5F 00 50 00 79 00 4F 00 62 00 6A 00 65 00 63  ._.P.y.O.b.j.e.c
0060: 00 74 00 00 00 00 00 00 00 00 00 0B 00 80 00 03  .t..............
0070: 00 43 00 04 00 DE 00 AD 00 BE 00 EF 00 71 00 00  .C...........q..
0080: 00 2E 00 29 08 0F 11 13 15 20 23 00 00 00 00 00  ...)..... #.....
0090: 00 01 01 00 00 00 00 00 00 00 07 00 00 00 00 00  ................
00A0: 00 00 00 00 00 00 00 00 00 00 84                 ...........

No. The writer compiled by Nuitka produces the exact same bytes that the CPython writer produces. The Nuitka-compiled reader segfaults reading what I assume is the "correct" way to encode a settings plist.

Could it be that the Nuitka reader doesn't expect UTF-16?

[12:45:57 pyinst] rm /Users/dcortesi/Library/Preferences/com.bogosity.BOGUS.plist
[12:54:02 pyinst] writer.dist/writer
[12:54:06 pyinst] ../nk/reader.dist/reader.exe b
Traceback (most recent call last):
  File "reader.py", line 12, in 
    value = settings.value(sys.argv[1],"?")
TypeError: unable to convert a QVariant back to a Python object

No! The Nuitka-compiled reader produces a reasonable exception when reading the not-UTF plist format.

So I see either two or three problems.

One, the writer code, when frozen by cx_Freeze, writes QSettings plists incorrectly, not using UTF-16 (which is probably just a dump of a Qt QString literal).

Two, the cx_Frozen reader gets an exception converting a QVariant no matter how encoded.

Three, the Nuitka-compiled reader segfaults converting a QVariant properly(?) encoded.

back to mulling....

No comments: