Re: [pysqlite] Encoding for connect to SqLite3

Roger Binns <[email protected]> Mon, 29 Jun 2009 15:08:20 -0700
Newsgroups gmane.comp.python.db.pysqlite.user
Message-ID <[email protected]>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Dinesh B Vadhia wrote:
> The questions around Unicode, utf-8 etc. appear on a regular basis on
> the Python lists and on this list too. 

Indeed they do.  I wish every person asking a question had to read the
Joel Unicode article first.

> The Python language developers
> could have made this whole area much simpler by making Unicode/utf-8 the
> default and everything else exceptions. 

Unicode and UTF8 are not the same thing.  Unicode is about representing
characters (using that term very loosely as human languages are complex)
and does so using numeric "codepoints".  UTF8 is about representing
those codepoints as bytes.  Historically codepoints and bytes have been
the same thing especially when dealing with ASCII and especially in
other programming languages.

Most developers don't want to deal with having to distinguish between
strings and bytes and so see this unicode stuff as a burden, doing the
minimum necessary in order to get the code to appear to work.

In Python (<3) the default string type (str) is really just a sequence
of bytes and Unicode was grafted on as an additional type.  (To be fair
Python existed before Unicode did.)

In Python 3 the only string type available is Unicode and there is a
separate bytes type.  There are no implicit conversions between them.
You have to do conversions explicitly and state what the encodings are.
 The Python developers have effectively fixed the issue by doing this,
but had to break backwards compatibility which is why Python 3 was the
earliest it could be done.

> The default Python encoding is
> 'ascii' which is really where (imho) the problems begin because the
> developer is lulled into a false sense of wellness until you hit the
> various encode/decode errors. 

Using 'ascii' as the default encoding in Python 2 is the right thing in
my opinion as there is a fine line between doing the right thing as
Python 3 does and not breaking existing code.  It is the least worst
solution.

> It is relatively easy to grasp what Unicode and utf-8 are and how they
> work BUT it is not easy to grasp how to make Python programs
> Unicode/utf-8 compatible as there are multiple holes that have to be
> covered to ensure that what you are processing inside a Python program
> are Unicode/utf-8 strings.

Encodings are the least of your issues.  Even if you get the whole
Unicode side of things right, other ugly issues rear their head.  For
example to do sorting requires knowing the locale.  Some even have
different sorting methods.  For example Germany has a different way of
sorting if you are doing it for a phonebook versus for a dictionary.
And when you have text from multiple locales together, then what do you
do?  For example your German phone could have people with Swedish names
in it as well as German ones.  Do you sort those Swedish names using
German or Swedish rules?  There is a UCA - Unicode Collation Algorithm -
that tries to do a good job but again it forms the least worst solution.
 The page includes lots of good examples of just how complex this stuff is:

  http://unicode.org/reports/tr10/

Python itself is actually rather basic and messy as Chris Lenz writes:

http://www.cmlenz.net/archives/2008/07/the-truth-about-unicode-in-python

My pet annoyance is the compile time option of the internal
representation using 2 or 4 bytes for unicode codepoints.  It doubles
the amount of testing I have to do for APSW as well as makes the code
more complex.  I have to use SQLite UTF8 apis for 4 byte Python strings
but the SQLite UTF16 apis for 2 byte Python strings.  (Ok I don't have
to but that is most effective.)

There are two further issues with relation to SQLite.  Firstly pysqlite
lets you fight the system and put garbage into/out of the database.
This made sense for SQLite 2 which strictly speaking was using bytes not
strings.  This gave developers enough rope to hang themselves.  In APSW
you cannot do this.

A secondary issue that SQLite does not verify that what is provided to
its APIs is actually valid UTF8, so users of the API can provide random
sequences of bytes instead.  It is debateable if the API should incur
extra overhead to defend against bad programming practise.  (Again in
APSW you cannot do this.)

Consider yourself lucky that you don't see what happens on the SQLite
mailing list.  Every month or so someone discovers that SQLite only pays
attention to ASCII characters when sorting (others are just sorted as
bytes) and this breaks on pretty much any string that contains non-ASCII
characters.  This behaviour is clearly documented and not a secret.
SQLite does let you register collations.  It also has an extension for
ICU which will give (more) correct results.  Then they'll propose some
simple allegedly space efficient mechanism that is faster and lighter
than ICU claiming ICU too big and slow.  Of course anything less than
ICU will be better than just ASCII but give pretty poor results except
maybe in a few trivial cases.  Debate proceeds around this eventually
fizzling out until the next month.

> I think that the core Python documentation set should include one on
> characters, character sets, Unicode and utf-8 and provide (Python) usage
> examples of the most common cases.

File a bug report against Python.  Documentation is one area that I
believe Python does badly because of how it can be updated.
Historically it required using Tex based tools (I believe) and was done
"cathedral" style.  Sphinx and RST is a lot nicer but there are still
barriers.  In my opinion PHP got it right - on any page on the doc you
can add a comment which others can see and can be absorbed into future
copies of the doc.  There have been various attempts to help making
updates to Python's doc as easy as PHP but none seem to have succeeded.
 The lower the barriers, the better the doc will be.

Roger
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEUEARECAAYFAkpJO1AACgkQmOOfHg372QQAnACYii+EfyHCz/X85IsH1h/tOLYl
JgCeP6nCJcIO+zrEHn6J/l0Kn1TAGnQ=
=EVLn
-----END PGP SIGNATURE-----