Bug 171246 - lang/python27: make python curses module work with unicode
Summary: lang/python27: make python curses module work with unicode
Status: Closed FIXED
Alias: None
Product: Ports & Packages
Classification: Unclassified
Component: Individual Port(s) (show other bugs)
Version: Latest
Hardware: Any Any
: Normal Affects Many People
Assignee: Danilo G. Baio
URL: https://reviews.freebsd.org/D11127
Keywords: needs-qa, patch
: 190457 196269 216482 (view as bug list)
Depends on:
Blocks:
 
Reported: 2012-09-02 11:40 UTC by Vitaly Magerya
Modified: 2017-06-28 02:49 UTC (History)
10 users (show)

See Also:


Attachments
file.diff (1.97 KB, patch)
2012-09-02 11:40 UTC, Vitaly Magerya
no flags Details | Diff
python_27_unicode_fix_11_12.patch (855 bytes, patch)
2016-11-05 22:00 UTC, Danilo G. Baio
no flags Details | Diff
svn-patch-python27-readline.patch (1.93 KB, patch)
2017-01-12 18:00 UTC, Danilo G. Baio
no flags Details | Diff
svn-patch-python27-readline.patch (1.92 KB, patch)
2017-01-14 11:53 UTC, Danilo G. Baio
no flags Details | Diff
svn-patch-python-readline.patch (5.32 KB, patch)
2017-02-16 21:33 UTC, Danilo G. Baio
no flags Details | Diff
svn-patch-python-readline-20170517.patch (5.11 KB, patch)
2017-05-18 01:05 UTC, Danilo G. Baio
no flags Details | Diff
svn-patch-python-readline-20170522.patch (5.12 KB, patch)
2017-05-22 18:25 UTC, Danilo G. Baio
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Vitaly Magerya 2012-09-02 11:40:07 UTC
I'm having a problem with Python curses module: it
won't work with unicode. Here's a test case:

    import curses
    import locale

    locale.setlocale(locale.LC_ALL, "")

    def run(win):
        win.addstr(u"\u03c0r\u00b2".encode("utf-8"))
        win.getch()

    curses.wrapper(run)

What I expect to see (and what I in fact see on e.g. Linux) is
"πr²" (that is, Greek "pi", Latin "r", superscript "2"), what I
actually get is "M-O~@rM-BM-2".

(Note that this is with LC_ALL set to "en_US.UTF-8" everywhere;
I'm seeing the same output in uxterm and putty, with and without
tmux inside of those).

I think this happens because python curses library is linked
with libncurses, not with libncursesw as it is on other platforms:

    $ ldd /usr/local/lib/python2.7/lib-dynload/_curses.so
    /usr/local/lib/python2.7/lib-dynload/_curses.so:
            libncurses.so.8 => /lib/libncurses.so.8 (0x801212000)
            libthr.so.3 => /lib/libthr.so.3 (0x80145f000)
            libc.so.7 => /lib/libc.so.7 (0x80084a000)

In fact, this appears to be intentional; here's a part of
lang/python27/files/patch-setup.py:

@@ -642,7 +642,7 @@
         # use the same library for the readline and curses modules.
         if 'curses' in readline_termcap_library:
             curses_library = readline_termcap_library
-        elif self.compiler.find_library_file(lib_dirs, 'ncursesw'):
+        elif self.compiler.find_library_file(lib_dirs, 'xxxncursesw'):
             curses_library = 'ncursesw'
         elif self.compiler.find_library_file(lib_dirs, 'ncurses'):
             curses_library = 'ncurses'
@@ -1246,12 +1248,13 @@
         # provided by the ncurses library.
         panel_library = 'panel'
         if curses_library.startswith('ncurses'):
-            if curses_library == 'ncursesw':
+            if curses_library == 'xxxncursesw':
                 # Bug 1464056: If _curses.so links with ncursesw,
                 # _curses_panel.so must link with panelw.
                 panel_library = 'panelw'

After some digging through commit logs, I found that this change
originated in [1] as a fix for ports/99496 [2].

Note that this patch is a no-op in 2.7 and in 3.2, so it can be
safely removed: a few lines above the first chunk of the patch
setup.py determines which curses library does readline use
(libncurses.so in FreeBSD), and uses that itself (unless readline
uses libtinfo, in which case python links with libncursesw).

More importantly though, if I remove all that logic and simply
set "curses_library = 'ncursesw'", thus making _curses.so link
with libncursesw.so, nothing breaks: python builds and runs fine,
and my example above works as expected too. Even if I have
devel/ncurses installed (as described in ports/99496), _curses.so
still links with libncursesw.so from base and everything seems
to work.

In short, I'm proposing a patch (it's in the attachment and also
at [3]) against lang/python{27,32} that removes all that logic
and makes _curses.so link with libncursesw from base. As you can
see from redports logs at [4], it builds fine on all releases.
I also tested patched python27 with devel/ncurses installed, and
that works too.

Final note: do contact me if there is something wrong with the
patch. I am determined to make curses work with Unicode.

[1] http://www.freebsd.org/cgi/cvsweb.cgi/ports/lang/python24/files/Attic/patch-setup.py#rev1.8
[2] http://www.freebsd.org/cgi/query-pr.cgi?pr=99496 
[3] http://redports.org/changeset/6571
[4] http://redports.org/buildarchive/20120831205350-31320/

Fix: Patch attached with submission follows:
Comment 1 Edwin Groothuis freebsd_committer freebsd_triage 2012-09-10 10:19:14 UTC
Responsible Changed
From-To: freebsd-ports-bugs->freebsd-python

Over to maintainer (via the GNATS Auto Assign Tool)
Comment 2 Kubilay Kocak freebsd_committer freebsd_triage 2013-10-24 03:04:55 UTC
Responsible Changed
From-To: freebsd-python->koobs

I'll take it.
Comment 3 koobs 2013-10-24 03:43:19 UTC
Hi Vitaly,

Firstly, thank you for the detailed report, it makes analysis an
absolute pleasure.

I'd like some clarity a few things prior to assessment:

1) Did you intend to replace 'elif' with 'if' in the first hunk of each
section in your patch? If so, why was it necessary? What happens if you
change it to match upstream sources exactly (ie; revert the patch entirely)

2) You mention that in 2.7 and 3.2, the patch is a no-op. Is this also
the case in 3.3 and 3.1? If not, why not?

In short, what I'd like to do is try our hand at reverting the existing
patches completely, in all current Python port versions.

Can you:

- Revert the ncurses patches from setup.py completely
- In lang/python{26,27,31,32,33)
- Check redports builds
- Check python test suite (python -m test.regrtest -vv test_curses)
- Check your test case

Feel free to start with python{27,33} and let me know what you find.

At best, we find no issues. At worst, we identify issues that can be
reported and fixed upstream, maintaining a local patch until the next
release.
Comment 4 Kubilay Kocak freebsd_committer freebsd_triage 2013-10-24 03:43:50 UTC
State Changed
From-To: open->feedback

Request additional information and tests from submitter
Comment 5 Vitaly Magerya 2013-10-30 21:12:53 UTC
On 10/24/2013 05:43, Kubilay Kocak wrote:
> Hi Vitaly,

Hi. Sorry for the delay, I missed your mail, and only discovered
it accidentally by visiting the bug tracker.

> Firstly, thank you for the detailed report, it makes analysis an
> absolute pleasure.
>
> I'd like some clarity a few things prior to assessment:
>
> 1) Did you intend to replace 'elif' with 'if' in the first hunk of each
> section in your patch? If so, why was it necessary? What happens if you
> change it to match upstream sources exactly (ie; revert the patch
entirely)

Yes. Let's take python 2.7 as an example, and walk through the
piece of it's setup.py that the patches touch.

So, lines 709-719 first execute 'ldd /usr/lib/libreadline.so'
and then search for 'libn?cursesw?' in the output. On FreeBSD
'libreadline.so' is linked with '/lib/libncurses.so.8', so the
script notes that and sets 'readline_termcap_library' variable
to 'ncurses'.

Then, lines 722-729 go like this:

    if 'curses' in readline_termcap_library:
        curses_library = readline_termcap_library
    elif self.compiler.find_library_file(lib_dirs, 'ncursesw'):
        curses_library = 'ncursesw'
    elif self.compiler.find_library_file(lib_dirs, 'ncurses'):
        curses_library = 'ncurses'
    elif self.compiler.find_library_file(lib_dirs, 'curses'):
        curses_library = 'curses'

As you can see, the first clause works, and 'curses_library'
gets set to the value of 'readline_termcap_library', which is
'ncurses'. This leads to python shared objects '_curses.so' and
'_curses_panel.so' to be linked with '-lncurses'.

The patch that we currently have changes 'ncursesw' to 'xxxncursesw'
in the second clause, but it doesn't matter: that clause is never
executed. This is why I said it's a no-op.

In previous versions of python the code that detected
'readline_termcap_library' was less intelligent, and the first
clause did not work; instead the second clause set curses_library
to 'ncursesw'. This is where the patch that we current have comes
in: it effectively disables the second clause, making the third
clause work, thus setting 'curses_library' to 'ncurses'.

The end result is that libraries that implement python's 'curses'
module ('_curses.so' and '_curses_panel.so') are linked with
'-lncurses', not '-lncursesw', which makes Unicode not work.

What my patch does (by changing 'elif' to 'if' in the second
clause) is to run the second clause unconditionally, thus allowing
it to set curses_library to 'ncursesw', thus linking '_curses.so'
and '_curses_panel.so' with '-lncursesw'.

Now, at first I was confused as to why python seems to go to
great lengths to avoid using '-lncursesw'. The reason for this
turned out to be another python module, 'readline.so': this
module must link with '-lreadline', but on FreeBSD 'libreadline.so'
is itself linked with 'libncurses.so', so if you link '_curses.so'
with '-lncursesw' and a python program will import both 'readline'
and 'curses' modules, the python process will end up with both
'libncurses.so' and 'libncursesw.so' loaded. Since those libraries
provide identical functions, who knows what may happen...

Well, one thing that may happen is that python may crash at some
point. This concern seems to be what triggered our current patches
to be introduced in the first place. Another thing that may
happen is nothing. Which is what I'm seeing: my code that uses
curses, even after importing readline, continues to work fine.

Ultimately the problem stems from our 'libreadline.so' being
linked with 'libncurses.so'. The proper solution (which I would
prefer to the patch I submitted) is to change the build process
of ncurses in base to produce a separate 'libtinfo.so' library
and then make 'libreadline.so' link with that.

> 2) You mention that in 2.7 and 3.2, the patch is a no-op. Is this also
> the case in 3.3 and 3.1? If not, why not?

I'll need to look into which version does what.

> In short, what I'd like to do is try our hand at reverting the existing
> patches completely, in all current Python port versions.
>
> Can you:
>
> - Revert the ncurses patches from setup.py completely
> - In lang/python{26,27,31,32,33)
> - Check redports builds
> - Check python test suite (python -m test.regrtest -vv test_curses)
> - Check your test case
>
> Feel free to start with python{27,33} and let me know what you find.

I'll try to do so shortly to verify my findings, but I'm pretty sure:
1) python{27,32,33} will build fine
2) Unicode will not work

> At best, we find no issues. At worst, we identify issues that can be
> reported and fixed upstream, maintaining a local patch until the next
> release.
Comment 6 Vitaly Magerya 2013-10-31 15:50:03 UTC
>> 2) You mention that in 2.7 and 3.2, the patch is a no-op. Is this also
>> the case in 3.3 and 3.1? If not, why not?
> 
> I'll need to look into which version does what.

It is a no-op in 2.7, 3.2 and 3.3. The patch is still relevant
in 2.6 and 3.1.

>> Can you:
>>
>> - Revert the ncurses patches from setup.py completely
>> - In lang/python{26,27,31,32,33)
>> - Check redports builds
>> - Check python test suite (python -m test.regrtest -vv test_curses)

BTW, 'python -m test.regrtest -u all -vv test_curses' seems to
be the correct command; without '-u all' python says that "Use
of the `curses' resource not enabled".

>> - Check your test case
>>
>> Feel free to start with python{27,33} and let me know what you find.

Here are my findings so far:
1) if you remove the part of the current files/patch-setup.py
   that deals ncurses, python{27,32,33} build fine; see logs at [1]
2) in all three cases 'test_curses' passes
3) in all three cases my test case fails

As a side note, it appears that if you have devel/ncurses
installed, at least python33 links '_curses.so' with 'libncurses.so'
from base, but '_curses_panel.so' with 'libncurses.so' from
devel/ncurses. If this happens, 'test_curses' segfaults. One
more thing to fix, I guess. (This behavior doesn't depend on
whether or not you removed the patches).

[1] https://redports.org/buildarchive/20131031122501-44919/
Comment 7 Vitaly Magerya 2013-11-01 16:18:50 UTC
And here's [1] a build log of python{26,31} without the current
patch and python{27,32,33} with my patch from above. In all these
cases '_curses.so' and '_curses_panel.so' link with '-lncursesw'.

In all the cases the build works fine (some results are missing
because redports has some of it's machines down, but I'd wager
they're OK too), 'test_curses' passes without problems, and my
test case works fine.

[1] http://redports.org/buildarchive/20131101112500-50583/
Comment 8 Kubilay Kocak freebsd_committer freebsd_triage 2014-07-12 03:37:24 UTC
Patches which override the relevant upstream ncurses code in setup.py will be removed in the upcoming Python 2.7.8 port update. (See bug 191405)
Comment 9 Kubilay Kocak freebsd_committer freebsd_triage 2014-07-12 03:38:47 UTC
*** Bug 190457 has been marked as a duplicate of this bug. ***
Comment 10 Kubilay Kocak freebsd_committer freebsd_triage 2014-07-28 05:59:30 UTC
See Also: http://bugs.python.org/issue7384
Comment 11 Kubilay Kocak freebsd_committer freebsd_triage 2015-01-28 03:20:39 UTC
Are there any additional changes to be made regarding unicode support out of the box for our Python ports since: https://svnweb.freebsd.org/changeset/ports/361735 ?
Comment 12 Vitaly Magerya 2015-01-29 11:59:17 UTC
The original problem is not fixed as of yet, so yes, there is
still work to be done.

Specifically, ncurses in base should be configured to install a
separate 'libtinfo.so' (currently it is installed as a symbolic
link to 'libncurses.so'; I don't think that is sufficient); and
'libreadline.so' from base should be configured to link with
that library (and not with 'libncurses.so'). Once that is done,
python build scripts will take care of the rest, and the problem
will (hopefully) be resolved.

(I may or may not have time to actually provide a patch for such
a change; testing changes to base system is painfully slow on
my hardware).
Comment 13 Kubilay Kocak freebsd_committer freebsd_triage 2015-01-29 12:30:07 UTC
Thanks for the quick response :) 

A patch would certainly be lovely, but this may require more investigation for a 'proper root cause fix' by our developers.

With that in mind, could you create a separate issue that blocks this one, that outlines the issue as you see it, and the changes you believe are required?

Something like your comment 12 + any additional information you like should be fine. You are more than welcome to contribute to that issue as you see fit, and feel free to CC me so I can track it once created.

I can take care of chasing people down to get it looked at, reviewed, debated, and ultimately resolved.
Comment 14 Vitaly Magerya 2015-01-29 13:46:31 UTC
I will do that, bug looking further into this, it seems that
libreadline was removed from 11-HEAD. I think I'll need to spin
up a virtual machine with the latest snapshot and see what it
looks like before proceeding.
Comment 15 rsos+freebsd 2016-10-25 20:28:09 UTC
*** Bug 196269 has been marked as a duplicate of this bug. ***
Comment 16 Danilo G. Baio freebsd_committer freebsd_triage 2016-11-05 22:00:06 UTC
Created attachment 176668 [details]
python_27_unicode_fix_11_12.patch

Yes, libreadline was removed on base r268461.

FreeBSD 9.3,10.3   --> readline on base is present
FreeBSD 11,current --> readline on base is NOT present

With this attachment I was able to resolve bug 213149 on FreeBSD >= 11
and Python 2.7 with unicode.

# FreeBSD 11 / current -------------------------------------------- #

# readline as it is today
ldd /usr/local/lib/libreadline.so
/usr/local/lib/libreadline.so:
	libncurses.so.8 => /lib/libncurses.so.8 (0x80124c000)
	libc.so.7 => /lib/libc.so.7 (0x800823000)

# readline (s/termcap/termcapw --> Makefile)
ldd /usr/local/lib/libreadline.so
/usr/local/lib/libreadline.so:
	libncursesw.so.8 => /lib/libncursesw.so.8 (0x80124c000)
	libc.so.7 => /lib/libc.so.7 (0x800823000)

# Python 2.7 rebuild
ldd /usr/local/lib/python2.7/lib-dynload/_curses.so
/usr/local/lib/python2.7/lib-dynload/_curses.so:
	libthr.so.3 => /lib/libthr.so.3 (0x801212000)
	libncursesw.so.8 => /lib/libncursesw.so.8 (0x801439000)
	libpython2.7.so.1 => /usr/local/lib/libpython2.7.so.1 (0x801695000)
	libc.so.7 => /lib/libc.so.7 (0x800823000)
	libintl.so.8 => /usr/local/lib/libintl.so.8 (0x801a6d000)
	libutil.so.9 => /lib/libutil.so.9 (0x801c77000)
	libm.so.5 => /lib/libm.so.5 (0x801e8a000)

# FreeBSD 9.3 / 10.3 ---------------------------------------------- #

# readline (s/termcap/termcapw --> Makefile)
ldd /usr/local/lib/libreadline.so
/usr/local/lib/libreadline.so:
	libncursesw.so.8 => /lib/libncursesw.so.8 (0x80124a000)
	libc.so.7 => /lib/libc.so.7 (0x800823000)

# Python 2.7 rebuild
ldd /usr/local/lib/python2.7/lib-dynload/_curses.so
/usr/local/lib/python2.7/lib-dynload/_curses.so:
	libthr.so.3 => /lib/libthr.so.3 (0x801213000)
	libncurses.so.8 => /lib/libncurses.so.8 (0x80143a000)
	libpython2.7.so.1 => /usr/local/lib/libpython2.7.so.1 (0x80168e000)
	libc.so.7 => /lib/libc.so.7 (0x800823000)
	libintl.so.8 => /usr/local/lib/libintl.so.8 (0x801a66000)
	libutil.so.9 => /lib/libutil.so.9 (0x801c70000)
	libm.so.5 => /lib/libm.so.5 (0x801e83000)

Still the same libncurses.so

	LDFLAGS=" -lpthread -L/usr/local/lib  -fstack-protector"

I've tried this patch on lang/python27 without successful:

# libreadline.so not in base on 11 >
.if ${OSVERSION} < 1100000
LDFLAGS+=	-lncursesw
.endif

ldd /usr/local/lib/python2.7/lib-dynload/_curses.so
/usr/local/lib/python2.7/lib-dynload/_curses.so:
	libthr.so.3 => /lib/libthr.so.3 (0x801213000)
	libncursesw.so.8 => /lib/libncursesw.so.8 (0x80143a000)
	libncurses.so.8 => /lib/libncurses.so.8 (0x801696000)
	libpython2.7.so.1 => /usr/local/lib/libpython2.7.so.1 (0x8018ea000)
	libc.so.7 => /lib/libc.so.7 (0x800823000)
	libintl.so.8 => /usr/local/lib/libintl.so.8 (0x801cc2000)
	libutil.so.9 => /lib/libutil.so.9 (0x801ecc000)
	libm.so.5 => /lib/libm.so.5 (0x8020df000)

	LDFLAGS=" -lpthread -lncursesw -L/usr/local/lib  -fstack-protector"

libncursesw.so.8 and libncurses.so.8 together... this is bad...

# ----------------------------------------------------------------- #

$ ./python Lib/test/regrtest.py -uall test___all__ test_curses
All 2 tests OK.

$ ldd ./build/lib.freebsd-12.0-CURRENT-amd64-2.7/_curses.so
./build/lib.freebsd-12.0-CURRENT-amd64-2.7/_curses.so:
	libthr.so.3 => /lib/libthr.so.3 (0x801212000)
	libncursesw.so.8 => /lib/libncursesw.so.8 (0x801439000)
	libpython2.7.so.1 => /usr/local/lib/libpython2.7.so.1 (0x801695000)
	libc.so.7 => /lib/libc.so.7 (0x800823000)
	libintl.so.8 => /usr/local/lib/libintl.so.8 (0x801a6d000)
	libutil.so.9 => /lib/libutil.so.9 (0x801c77000)
	libm.so.5 => /lib/libm.so.5 (0x801e8a000)

	
Some commits on base about termcap: base r268804, base r270651

Maybe some developer could take a look on this ?

Screenshot's of rtv with python 2.7 + unicode working fine:
http://dbaio.bs2cloud.com.br/FreeBSD/rtv/shots/rtv_python27_readline_termcapw/2016-11-05-182209_1366x768_scrot.png
http://dbaio.bs2cloud.com.br/FreeBSD/rtv/shots/rtv_python27_readline_termcapw/2016-11-05-182224_1366x768_scrot.png

Regards.
Comment 17 Danilo G. Baio freebsd_committer freebsd_triage 2016-11-07 00:30:45 UTC
If this change on devel/readline be viable, it will fix unicode on the others versions under FreeBSD 11 and current:

# deve/readline (s/termcap/termcapw --> Makefile)
/usr/local/lib/python2.7/lib-dynload/_curses.so  -->  libncursesw.so.8
/usr/local/lib/python3.3/lib-dynload/_curses.so  -->  libncursesw.so.8
/usr/local/lib/python3.4/lib-dynload/_curses.so  -->  libncursesw.so.8
/usr/local/lib/python3.5/lib-dynload/_curses.so  -->  libncursesw.so.8

# deve/readline (default)
/usr/local/lib/python2.7/lib-dynload/_curses.so  -->  libncurses.so.8
/usr/local/lib/python3.3/lib-dynload/_curses.so  -->  libncurses.so.8
/usr/local/lib/python3.4/lib-dynload/_curses.so  -->  libncurses.so.8
/usr/local/lib/python3.5/lib-dynload/_curses.so  -->  libncurses.so.8
Comment 18 Danilo G. Baio freebsd_committer freebsd_triage 2017-01-12 18:00:13 UTC
Created attachment 178799 [details]
svn-patch-python27-readline.patch

Hi.

With this new attachment is possible to use python curses with unicode without problems on FreeBSD 10.3, 11 and current.

It is necessary: 
- link devel/readline with termcapw instead of termcap
- don't let setup.py find readline shared library on base on FreeBSD < 11
- python Makefile --> USES= readline:port

I tested on FreeBSD 10.3, 11 and current + python 2.7, but I think that if this approach is accepted, it will work on all others versions of python.

# FreeBSD 11 amd64 and current - OK

~ % ldd /usr/local/lib/libreadline.so
/usr/local/lib/libreadline.so:
>  libncursesw.so.8 => /lib/libncursesw.so.8 (0x80124c000)
   libc.so.7 => /lib/libc.so.7 (0x800823000)

~ % ldd /usr/local/lib/python2.7/lib-dynload/_curses.so
/usr/local/lib/python2.7/lib-dynload/_curses.so:
   libthr.so.3 => /lib/libthr.so.3 (0x801213000)
>  libncursesw.so.8 => /lib/libncursesw.so.8 (0x80143a000)
   libpython2.7.so.1 => /usr/local/lib/libpython2.7.so.1 (0x801696000)
   libc.so.7 => /lib/libc.so.7 (0x800823000)
   libintl.so.8 => /usr/local/lib/libintl.so.8 (0x801a72000)
   libutil.so.9 => /lib/libutil.so.9 (0x801c7d000)
   libm.so.5 => /lib/libm.so.5 (0x801e90000)

~ % ldd /usr/local/lib/python2.7/lib-dynload/readline.so
/usr/local/lib/python2.7/lib-dynload/readline.so:
   libthr.so.3 => /lib/libthr.so.3 (0x801206000)
   libreadline.so.6 => /usr/local/lib/libreadline.so.6 (0x80142d000)
   libpython2.7.so.1 => /usr/local/lib/libpython2.7.so.1 (0x801679000)
   libc.so.7 => /lib/libc.so.7 (0x800823000)
>  libncursesw.so.8 => /lib/libncursesw.so.8 (0x801a55000)
   libintl.so.8 => /usr/local/lib/libintl.so.8 (0x801cb1000)
   libutil.so.9 => /lib/libutil.so.9 (0x801ebc000)
   libm.so.5 => /lib/libm.so.5 (0x8020cf000)


# FreeBSD 10.3 - OK

freebsd@digitalocean:~ % uname -a
FreeBSD digitalocean 10.3-RELEASE-p11 FreeBSD 10.3-RELEASE-p11 #0: Mon Oct 24 18:49:24 UTC 2016     root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC  amd64

freebsd@digitalocean:~ % ldd /usr/local/lib/libreadline.so
/usr/local/lib/libreadline.so:
>  libncursesw.so.8 => /lib/libncursesw.so.8 (0x80164b000)
   libc.so.7 => /lib/libc.so.7 (0x800821000)

freebsd@digitalocean:~ % ldd /usr/local/lib/python2.7/lib-dynload/_curses.so
/usr/local/lib/python2.7/lib-dynload/_curses.so:
   libthr.so.3 => /lib/libthr.so.3 (0x801612000)
>  libncursesw.so.8 => /lib/libncursesw.so.8 (0x801837000)
   libpython2.7.so.1 => /usr/local/lib/libpython2.7.so.1 (0x801a8c000)
   libc.so.7 => /lib/libc.so.7 (0x800821000)
   libintl.so.8 => /usr/local/lib/libintl.so.8 (0x801e61000)
   libutil.so.9 => /lib/libutil.so.9 (0x80206c000)
   libm.so.5 => /lib/libm.so.5 (0x80227f000)

freebsd@digitalocean:~ % ldd /usr/local/lib/python2.7/lib-dynload/readline.so
/usr/local/lib/python2.7/lib-dynload/readline.so:
   libthr.so.3 => /lib/libthr.so.3 (0x801606000)
   libreadline.so.6 => /usr/local/lib/libreadline.so.6 (0x80182b000)
   libpython2.7.so.1 => /usr/local/lib/libpython2.7.so.1 (0x801a76000)
   libc.so.7 => /lib/libc.so.7 (0x800821000)
>  libncursesw.so.8 => /lib/libncursesw.so.8 (0x801e4b000)
   libintl.so.8 => /usr/local/lib/libintl.so.8 (0x8020a0000)
   libutil.so.9 => /lib/libutil.so.9 (0x8022ab000)
   libm.so.5 => /lib/libm.so.5 (0x8024be000)


Some relevant references:

https://bugs.python.org/issue7384
Thomas Dickey pointed out that there are two ways for a distro to
deal with this problem:

  1) Link libreadline against ncursesw.

  2) Split out the termcap interface (which readline uses) as
     libtinfo. This is a configure option for ncurses and SuSE
     and Redhat are doing this.

A lot of tools replaced libncurses and libtermcap with their wide character
on base: base r268804, base r270651

Best regards.
Comment 19 Danilo G. Baio freebsd_committer freebsd_triage 2017-01-14 11:53:06 UTC
Created attachment 178880 [details]
svn-patch-python27-readline.patch

Fix a typo on comment
Comment 20 Danilo G. Baio freebsd_committer freebsd_triage 2017-01-16 13:48:08 UTC
Adding bapt@ and sunpoet@ to see their thoughts about attachment #178880 [details]
Comment 21 Petr Fischer 2017-01-27 22:29:17 UTC
*** Bug 216482 has been marked as a duplicate of this bug. ***
Comment 22 Danilo G. Baio freebsd_committer freebsd_triage 2017-02-16 21:33:46 UTC
Created attachment 180060 [details]
svn-patch-python-readline.patch

Updating patch and including other versions of python on it, except python33.

lang/python33:
  DEPRECATED= No longer receives bug fixes, only security updates. Please update to Python 3.5
  EXPIRATION_DATE=  2017-09-01
Comment 23 Petr Fischer 2017-02-17 18:01:08 UTC
Will it be available in ports soon? Thanks.
Comment 24 Tilman Keskinoz freebsd_committer freebsd_triage 2017-04-15 21:04:44 UTC
Hi, What is the state of this PR?

I have been using it for a long time, so I think it should be committed. Is there anything missing?
Comment 25 Vitaly Magerya 2017-05-17 18:26:08 UTC
> Is there anything missing?

What's missing is a committer, I think.

Save for fixing bug 197317, linking python against readline from ports (and that readline against termcapw) is the best solution. It is mildly inconvenient that the fix depends on a devel/readline port having TERMCAP option on, but this is still better than nothing.
Comment 26 Danilo G. Baio freebsd_committer freebsd_triage 2017-05-18 01:05:00 UTC
Created attachment 182678 [details]
svn-patch-python-readline-20170517.patch

Updating patch.
Comment 27 Danilo G. Baio freebsd_committer freebsd_triage 2017-05-18 01:09:11 UTC
I would like to request an exp-run, attachment 182678 [details].

If it returns OK, then I will open a review for python, sunpoet and my mentor.

Thank you.
Comment 28 Antoine Brodin freebsd_committer freebsd_triage 2017-05-18 05:56:32 UTC
Can you clarify which patch(es) needs an exp-run ?
Comment 29 Danilo G. Baio freebsd_committer freebsd_triage 2017-05-18 10:57:45 UTC
(In reply to Antoine Brodin from comment #28)

Just the attachment 182678 [details].

Patch is also here now:
https://people.freebsd.org/~dbaio/svn-patch-python-readline-20170517.patch

Thank you.
Comment 30 Antoine Brodin freebsd_committer freebsd_triage 2017-05-22 05:44:39 UTC
The post-patch are not good:  they hardcode /usr/local.
They should use ${LOCALBASE} instead.
Comment 31 Danilo G. Baio freebsd_committer freebsd_triage 2017-05-22 18:25:41 UTC
Created attachment 182815 [details]
svn-patch-python-readline-20170522.patch

Patch updated, now with ${LOCALBASE} and REINPLACE_CMD verbose.
It's attached and available here:
https://people.freebsd.org/~dbaio/svn-patch-python-readline-20170522.patch
Comment 32 Antoine Brodin freebsd_committer freebsd_triage 2017-05-27 18:34:42 UTC
Exp-run looks fine.  (Note that an exp-run only detects build failures,  not runtime failures)
Comment 33 commit-hook freebsd_committer freebsd_triage 2017-06-28 02:38:34 UTC
A commit references this bug:

Author: dbaio
Date: Wed Jun 28 02:37:54 UTC 2017
New revision: 444534
URL: https://svnweb.freebsd.org/changeset/ports/444534

Log:
  lang/python{27,33,34,35,36}: Make Python curses module work with Unicode

  Use readline from ports (USES= readline:port) and patch
  setup.py to ignore readline from base. The patch is necessary for
  FreeBSD < 1100000, as after this the readline library became an
  INTERNALLIB, see base r268461 [1]

  Link devel/readline against termcapw instead of termcap is part of
  this change, see ports r444463 [2]

  Note that this is the **ports** approach for getting Python curses
  module working with Unicode. The other way is splitting libncurses
  into separate libncurses and libtinfo in base, for which an open
  issue exists [3].

  Apart from Python language ports, at least www/rtv and
  sysutils/py-ranger ports have been tested to work correctly
  (display Unicode) after this change.

  [1] https://svnweb.freebsd.org/changeset/base/268461
  [2] https://svnweb.freebsd.org/changeset/ports/444463
  [3] https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=197317

  PR:		171246, 197317
  Reported by:	Vitaly Magerya <vmagerya gmail com>
  Reviewed by:	garga, koobs, miwi, sunpoet
  Approved by:	garga (mentor), sunpoet (python, with hat)
  Differential Revision:	https://reviews.freebsd.org/D11127

Changes:
  head/lang/python27/Makefile
  head/lang/python33/Makefile
  head/lang/python34/Makefile
  head/lang/python35/Makefile
  head/lang/python36/Makefile