IIRC the messaging from Guido and Python core dev circa PyCon 2008 and 2009 was that it was good enough for people to start thinking about how they might migrate. This resulted in experiments with different approaches to migrations, maintenance of versions for Python 2 and 3, etc, but at that time there wasn't a clear end date and no rush to migrate. It seems like a lot of people misinterpreted what was actually said. Similar misinterpretations seem to happen within the wider internet community around the GIL and perf considerations. That cliff is finally here ten years later after a lot of experience with migrations.
3.5 fixed % formatting for bytes, further making 2/3 transitions easier (or harder, depending on your use/abuse of strings vs bytes).
3.6 added the first 'exciting' new feature: f"formatted string {literals}" if you don't have an asynchronous type project that can make good use of async/await.
(Or in language-lawyer terms: CPython 3.6 introduced this behavior and documented it as an implementation detail, and for Python 3.7+ it's guaranteed a feature of the language proper.)
% python3.7 -c "import sys; print(sys.argv[1])" "$(echo -e '\xff')"
Traceback (most recent call last):
File "<string>", line 1, in <module>
UnicodeEncodeError: 'utf-8' codec can't encode character '\udcff' in position 0: surrogates not allowedThe key surprising thing that's going on here is this clever hack (clever, but a hack):
> In Python, file names, command line arguments, and environment variables are represented using the string type. On some systems, decoding these strings to and from bytes is necessary before passing them to the operating system. Python uses the file system encoding to perform this conversion ... > > On some systems, conversion using the file system encoding may fail. In this case, Python uses the surrogateescape encoding error handler, which means that undecodable bytes are replaced by a Unicode character U+DCxx on decoding, and these are again translated to the original byte on encoding.
https://docs.python.org/3/library/os.html#file-names-command...
This is meant as a way of fudging the fact that (a) for UI purposes, you want to treat filenames as text strings; (b) your Linux filenames are probably all encoded as UTF-8 (or your locale encoding); (c) but they might not be -- they could be arbitrary bytes, except only NUL; (d) and if they are, you really want to not munge the name when you go back and try to operate on the file.
The fudge is that filenames get decoded as (by default) UTF-8... but if invalid, the offending bytes get stuffed into the UTF-16 surrogate space. Then filesystem APIs encode as UTF-8, except they look for that surrogate hack and turn those to the original bytes, so it all round-trips.
It goes pretty wrong if you try to hand such a hacked-up string to something that just expects to encode normal real Unicode with UTF-8, though. That's what's happening in your example.
The magic words are `os.fsdecode` -- that's how you get back bytes round-trip clean from that hack.
I would expect any stable release of software to be "good and ready." Can you explain what was wrong with Python 3.0 and 3.1?
> core dev did not listen to any of the problems people pointed out for _years_
What problems were those?
[1]: https://bugs.python.org/issue19977
[2]: https://www.python.org/dev/peps/pep-0540/
[3]: https://docs.python.org/release/3.5.0/whatsnew/3.5.html
I appreciate the general point that that's far more recent than Python 3s initial release but it's also a large exaggeration to say "until this most current release".
Also to understand why it took so long is because Python 2 kept improving after Python 3s release. Python 2.7 was a great release and many further features from Python 3 got backported in it's 2.7.x point release.
The post you're responding to starts verbatim with `Python 2 to 3 (at least by 3.3 or so)` and your reply is about Python 3.1, released 3 years earlier. The amount of changes was quite big.
Just let it go...
1. Python core dev pretended Python 3 was good and ready by, like, 3.1. It wasn't.
2. While your problem may have been painless (I'm glad), that doesn't mean that everyone who complained was just complaining.
(I use Python 3 as the default now, but as someone intimately involved with an async IO library at the time it came out, I maintain that a) the transition was botched b) core dev did not listen to any of the problems people pointed out for _years_.)
To give you an idea of what botched means: several people, names withheld to protect the guilty, had to wade in 6 months worth of shit to get a 2.x release that made TLS vaguely OK, in, like, 2014?