Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 2 Sep 2012 10:35:58 GMT
From:      Vitaly Magerya <vmagerya@gmail.com>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   ports/171246: [patch] make python curses module work with unicode
Message-ID:  <201209021035.q82AZwdJ017319@red.freebsd.org>
Resent-Message-ID: <201209021040.q82Ae7ur089686@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         171246
>Category:       ports
>Synopsis:       [patch] make python curses module work with unicode
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Sep 02 10:40:07 UTC 2012
>Closed-Date:
>Last-Modified:
>Originator:     Vitaly Magerya
>Release:        FreeBSD 9.1-RC1 amd64
>Organization:
>Environment:
>Description:
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
"&#960;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/
>How-To-Repeat:

>Fix:


Patch attached with submission follows:

Index: /magv/lang/python32/files/patch-setup.py
===================================================================
--- /magv/lang/python32/files/patch-setup.py	(revision 6570)
+++ /magv/lang/python32/files/patch-setup.py	(revision 6571)
@@ -15,5 +15,5 @@
              curses_library = readline_termcap_library
 -        elif self.compiler.find_library_file(lib_dirs, 'ncursesw'):
-+        elif self.compiler.find_library_file(lib_dirs, 'XXXncursesw'):
++        if self.compiler.find_library_file(lib_dirs, 'ncursesw'):
              curses_library = 'ncursesw'
          elif self.compiler.find_library_file(lib_dirs, 'ncurses'):
@@ -32,6 +32,5 @@
          panel_library = 'panel'
          if curses_library.startswith('ncurses'):
--            if curses_library == 'ncursesw':
-+            if curses_library == 'XXXncursesw':
+             if curses_library == 'ncursesw':
                  # Bug 1464056: If _curses.so links with ncursesw,
                  # _curses_panel.so must link with panelw.
Index: /magv/lang/python27/files/patch-setup.py
===================================================================
--- /magv/lang/python27/files/patch-setup.py	(revision 6570)
+++ /magv/lang/python27/files/patch-setup.py	(revision 6571)
@@ -15,5 +15,5 @@
              curses_library = readline_termcap_library
 -        elif self.compiler.find_library_file(lib_dirs, 'ncursesw'):
-+        elif self.compiler.find_library_file(lib_dirs, 'xxxncursesw'):
++        if self.compiler.find_library_file(lib_dirs, 'ncursesw'):
              curses_library = 'ncursesw'
          elif self.compiler.find_library_file(lib_dirs, 'ncurses'):
@@ -50,6 +50,5 @@
          panel_library = 'panel'
          if curses_library.startswith('ncurses'):
--            if curses_library == 'ncursesw':
-+            if curses_library == 'xxxncursesw':
+             if curses_library == 'ncursesw':
                  # Bug 1464056: If _curses.so links with ncursesw,
                  # _curses_panel.so must link with panelw.


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201209021035.q82AZwdJ017319>