[Redirecting a private conversation to python-dev] On Sat, Jun 10, 2000 at 11:31:24AM -0400, Eric S. Raymond wrote:
I found a workaround. The two curses enhancements (traceback wrapper and text pad) are now working and ready to be integrated into the 1.6 library. How should we proceed?
OK; python-dev has discussed creating a curses package, and reaction seemed favorable. So, my plan of action is: 1) Rename cursesmodule.c to _cursesmodule.c. (Barry, can you do a 'mv' inside the SourceForge CVS repository so the complete history of the module doesn't get lost with the renaming?) 2) Create a Lib/curses/ directory; __init__.py does 'from _curses import *'. 3) The traceback wrapper can then be put into __init__.py, since I assume it's fairly small and everyone should use it. The text pad stuff could then go in another module in the curses package. Seem reasonable to everyone? --amk
Andrew Kuchling <akuchlin@cnri.reston.va.us>:
OK; python-dev has discussed creating a curses package, and reaction seemed favorable. So, my plan of action is:
1) Rename cursesmodule.c to _cursesmodule.c. (Barry, can you do a 'mv' inside the SourceForge CVS repository so the complete history of the module doesn't get lost with the renaming?)
2) Create a Lib/curses/ directory; __init__.py does 'from _curses import *'.
3) The traceback wrapper can then be put into __init__.py, since I assume it's fairly small and everyone should use it. The text pad stuff could then go in another module in the curses package.
Seem reasonable to everyone?
Works for me. -- <a href="http://www.tuxedo.org/~esr">Eric S. Raymond</a> We shall not cease from exploration, and the end of all our exploring will be to arrive where we started and know the place for the first time. -- T.S. Eliot
On Sat, 10 Jun 2000, Andrew Kuchling wrote:
OK; python-dev has discussed creating a curses package, and reaction seemed favorable. So, my plan of action is:
1) Rename cursesmodule.c to _cursesmodule.c. (Barry, can you do a 'mv' inside the SourceForge CVS repository so the complete history of the module doesn't get lost with the renaming?)
2) Create a Lib/curses/ directory; __init__.py does 'from _curses import *'.
3) The traceback wrapper can then be put into __init__.py, since I assume it's fairly small and everyone should use it. The text pad stuff could then go in another module in the curses package.
Seem reasonable to everyone?
I'm +1, except for some nagging doubt about the traceback wrapper. Why not put it in its own (small, granted) module? There are no backward compatabilities to worry here, so there shouldn't be any excuse to put code in __init__.py. But it is so small, that I don't really feel strongly about it. i'll-be-+1-on-the-text-pad-stuff-when-you-get-it-ready-eric-ly y'rs, Z. -- Moshe Zadka <moshez@math.huji.ac.il> http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com
Moshe Zadka <moshez@math.huji.ac.il>:
I'm +1, except for some nagging doubt about the traceback wrapper. Why not put it in its own (small, granted) module?
I don't understand. Whuy do you want to do this?
i'll-be-+1-on-the-text-pad-stuff-when-you-get-it-ready-eric-ly y'rs, Z.
You can try it out now: # # Curses extensions -- these are expected to be in the 1.6 Python library # import sys, curses, ascii def wrapper(func, *rest): "Wrapper function that restores normal keyboard/screen behavior on error." res = None try: # Initialize curses stdscr=curses.initscr() # Turn off echoing of keys, and enter cbreak mode, # where no buffering is performed on keyboard input curses.noecho() ; curses.cbreak() # In keypad mode, escape sequences for special keys # (like the cursor keys) will be interpreted and # a special value like curses.KEY_LEFT will be returned stdscr.keypad(1) res = apply(func, (stdscr,) + rest) except: # In the event of an error, restore the terminal # to a sane state. stdscr.keypad(0) curses.echo() ; curses.nocbreak() curses.endwin() # Pass the exception upwards (exc_type, exc_value, exc_traceback) = sys.exc_info() raise exc_type, exc_value, exc_traceback else: # Set everything back to normal stdscr.keypad(0) curses.echo() ; curses.nocbreak() curses.endwin() # Terminate curses return res def rectangle(win, uly, ulx, lry, lrx): "Draw a rectangle." win.vline(uly+1, ulx, curses.ACS_VLINE, lry - uly - 1) win.hline(uly, ulx+1, curses.ACS_HLINE, lrx - ulx - 1) win.hline(lry, ulx+1, curses.ACS_HLINE, lrx - ulx - 1) win.vline(uly+1, lrx, curses.ACS_VLINE, lry - uly - 1) win.addch(uly, ulx, curses.ACS_ULCORNER) win.addch(uly, lrx, curses.ACS_URCORNER) win.addch(lry, lrx, curses.ACS_LRCORNER) win.addch(lry, ulx, curses.ACS_LLCORNER) class textbox: """Editing widget using the interior of a window object. Supports the following Emacs-like key bindings: Ctrl-A Go to left edge of window. Ctrl-B Cursor left, wrapping to previous line if appropriate. Ctrl-D Delete character under cursor. Ctrl-E Go to right edge (nospaces off) or end of line (nospaces on). Ctrl-F Cursor right, wrapping to next line when appropriate. Ctrl-G Terminate, returning the window contents. Ctrl-J Terminate if the window is 1 line, otherwise insert newline. Ctrl-K If line is blank, delete it, otherwise clear to end of line. Ctrl-L Refresh screen Ctrl-N Cursor down; move down one line. Ctrl-O Insert a blank line at cursor location. Ctrl-P Cursor up; move up one line. Move operations do nothing if the cursor is at an edge where the movement is not possible. The following synonyms are supported where possible: KEY_LEFT = Ctrl-B, KEY_RIGHT = Ctrl-F, KEY_UP = Ctrl-P, KEY_DOWN = Ctrl-N """ def __init__(self, win): self.win = win (self.maxy, self.maxx) = win.getmaxyx() self.maxy = self.maxy - 1 self.maxx = self.maxx - 1 self.stripspaces = 1 win.keypad(1) def firstblank(self, y): "Go to the location of the first blank on the given line." (oldy, oldx) = self.win.getyx() self.win.move(y, self.maxx-1) last = self.maxx-1 while 1: if last == 0: break if ascii.ascii(self.win.inch(y, last)) != ascii.SP: last = last + 1 break last = last - 1 self.win.move(oldy, oldx) return last def do_command(self, ch): "Process a single editing command." (y, x) = self.win.getyx() if ascii.isprint(ch): if y < self.maxy or x < self.maxx: # The try-catch ignores the error we trigger from some curses # versions by trying to write into the lowest-rightmost spot # in the self.window. try: self.win.addch(ch) except ERR: pass elif ch == ascii.SOH: # Ctrl-a self.win.move(y, 0) elif ch in (ascii.STX, curses.KEY_LEFT): # Ctrl-b if x > 0: self.win.move(y, x-1) elif y == 0: pass elif self.stripspaces: self.win.move(y-1, self.firstblank(y-1)) else: self.win.move(y-1, self.maxx) elif ch == ascii.EOT: # Ctrl-d self.win.delch() elif ch == ascii.ENQ: # Ctrl-e if self.stripspaces: self.win.move(y, self.firstblank(y, maxx)) else: self.win.move(y, self.maxx) elif ch in (ascii.ACK, curses.KEY_RIGHT): # Ctrl-f if x < self.maxx: self.win.move(y, x+1) elif y == self.maxx: pass else: self.win.move(y+1, 0) elif ch == ascii.BEL: # Ctrl-g return 0 elif ch == ascii.NL: # Ctrl-j if self.maxy == 0: return 0 elif y < self.maxy: self.win.move(y+1, 0) elif ch == ascii.VT: # Ctrl-k if x == 0 and self.firstblank(y) == 0: self.win.deleteln() else: self.win.clrtoeol() elif ch == ascii.FF: # Ctrl-l self.win.refresh() elif ch in (ascii.SO, curses.KEY_DOWN): # Ctrl-n if y < self.maxy: self.win.move(y+1, x) elif ch == ascii.SI: # Ctrl-o self.win.insertln() elif ch in (ascii.DLE, curses.KEY_UP): # Ctrl-p if y > 0: self.win.move(y-1, x) self.win.refresh() return 1 def gather(self): "Collect and return the contents of the window." result = "" for y in range(self.maxy+1): self.win.move(y, 0) stop = self.firstblank(y) if stop == 0 and self.stripspaces: continue for x in range(self.maxx+1): if self.stripspaces and x == stop: break result = result + chr(ascii.ascii(self.win.inch(y, x))) if self.maxy > 0: result = result + "\n" return result def edit(self, validate=None): "Edit in the widget window and collect the results." while 1: ch = self.win.getch() if self.validate: ch = validate(ch) if not self.do_command(ch): break return self.gather() if __name__ == '__main__': def test_editbox(stdscr): win = curses.newwin(4, 9, 15, 20) rectangle(stdscr, 14, 19, 19, 29) stdscr.refresh() return textbox(win).edit() str = wrapper(test_editbox) print str -- <a href="http://www.tuxedo.org/~esr">Eric S. Raymond</a> The danger (where there is any) from armed citizens, is only to the *government*, not to *society*; and as long as they have nothing to revenge in the government (which they cannot have while it is in their own hands) there are many advantages in their being accustomed to the use of arms, and no possible disadvantage. -- Joel Barlow, "Advice to the Privileged Orders", 1792-93
[Moshe Zadka]
I'm +1, except for some nagging doubt about the traceback wrapper. Why not put it in its own (small, granted) module?
[Eric S. Raymond]
I don't understand. Why do you want to do this?
I have religious beliefs, and I follow them without thinking. Like "HTTP good, FTP bad". "Python good, C++ bad". Or, in that case "Putting real code in __init__.py bad". (I think that should go in the package style guide, BTW) religions-are-bad-of-course-ly y'rs, Z. -- Moshe Zadka <moshez@math.huji.ac.il> http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com
Moshe Zadka <moshez@math.huji.ac.il>:
[Eric S. Raymond]
I don't understand. Why do you want to do this?
I have religious beliefs, and I follow them without thinking. Like "HTTP good, FTP bad". "Python good, C++ bad". Or, in that case "Putting real code in __init__.py bad".
I'm even more confused now. Why would the traceback wrapper I'm proposing go in __init__.py? -- <a href="http://www.tuxedo.org/~esr">Eric S. Raymond</a> The Bible is not my book, and Christianity is not my religion. I could never give assent to the long, complicated statements of Christian dogma. -- Abraham Lincoln
On Sat, 10 Jun 2000, Eric S. Raymond wrote:
I'm even more confused now. Why would the traceback wrapper I'm proposing go in __init__.py?
Maybe I'm confused here. I thought that was what AMK suggested, no? Where would you want it to go? There are currently 3 planned files in the curses package: __init__.py: apparently not textpad.py: why here? it has nothing to do with text pads _curses.so: certainly not here...you don't want to code in C more then you have to I'm proposing: wrapper.py: put it here i-hope-i-managed-to-confuse-everyone-further-ly y'rs, Z. -- Moshe Zadka <moshez@math.huji.ac.il> http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com
On Sat, Jun 10, 2000 at 11:21:57PM +0300, Moshe Zadka wrote:
Maybe I'm confused here. I thought that was what AMK suggested, no?
I did in fact suggest that, since the wrapper is small, and we ideally want every Python/curses application using it, so they don't leave the terminal in a wacky state if they raise an exception. But it's not a big deal and could easily go in wrapper.py, though __init__.py might still import it automatically. --amk
On Sat, Jun 10, 2000 at 06:25:14PM -0400, Andrew Kuchling wrote:
On Sat, Jun 10, 2000 at 11:21:57PM +0300, Moshe Zadka wrote:
Maybe I'm confused here. I thought that was what AMK suggested, no?
I did in fact suggest that, since the wrapper is small, and we ideally want every Python/curses application using it, so they don't leave the terminal in a wacky state if they raise an exception. But it's not a big deal and could easily go in wrapper.py, though __init__.py might still import it automatically.
Yes, I think we'd want it to import the stuff; just organizationally to place the source code outside of __init__.py I'd agree that real code should not go into __init__. It should preload some standard modules, maybe expose some symbols, but otherwise no code. Cheers, -g -- Greg Stein, http://www.lyra.org/
Andrew Kuchling <akuchlin@cnri.reston.va.us>:
On Sat, Jun 10, 2000 at 11:21:57PM +0300, Moshe Zadka wrote:
Maybe I'm confused here. I thought that was what AMK suggested, no?
I did in fact suggest that, since the wrapper is small, and we ideally want every Python/curses application using it, so they don't leave the terminal in a wacky state if they raise an exception. But it's not a big deal and could easily go in wrapper.py, though __init__.py might still import it automatically.
The traceback wrapper is not the only Python code I'll be supplying... -- <a href="http://www.tuxedo.org/~esr">Eric S. Raymond</a> I do not find in orthodox Christianity one redeeming feature. -- Thomas Jefferson
"AK" == Andrew Kuchling <akuchlin@cnri.reston.va.us> writes:
AK> 1) Rename cursesmodule.c to _cursesmodule.c. (Barry, can you AK> do a 'mv' inside the SourceForge CVS repository so the AK> complete history of the module doesn't get lost with the AK> renaming?) Not easily (IOW, I have to play several rounds of ugly loginfo games which are hard to get right). Best thing to do would be to submit a SF admin request, which I think since you're a developer you can do. -Barry
On Sat, Jun 10, 2000 at 01:58:04PM -0400, Barry A. Warsaw wrote:
which are hard to get right). Best thing to do would be to submit a SF admin request, which I think since you're a developer you can do.
I've submitted a support request to rename the file, and checked in the Lib/curses subdirectory, containing only __init__.py and wrapper.py, along with the required Makefile.in and Setup.in changes. If you compile the CVS tree right now, you'll need to rename cursesmodule.c to _cursesmodule.c manually. The textbox stuff poses two problems. First, it requires ascii.py, and wasn't the decision to wait for GvR on adding that module? Second, Eric, I'm not sure what you want as the module name for the textbox stuff: textbox.py? Your call... (I'll check it in, and if ascii.py is vetoed, it can be rewritten to not require ascii.py, or we can have curses.ascii.) --amk
Andrew Kuchling <akuchlin@cnri.reston.va.us>:
The textbox stuff poses two problems. First, it requires ascii.py, and wasn't the decision to wait for GvR on adding that module? Second, Eric, I'm not sure what you want as the module name for the textbox stuff: textbox.py? Your call... (I'll check it in, and if ascii.py is vetoed, it can be rewritten to not require ascii.py, or we can have curses.ascii.)
I thought it was going to become part of curses from the user's point of view, so that "import curses" brings it in. That seemed to be the intent of the request at the end of the curses HOWTO. -- <a href="http://www.tuxedo.org/~esr">Eric S. Raymond</a> "Taking my gun away because I might shoot someone is like cutting my tongue out because I might yell `Fire!' in a crowded theater." -- Peter Venetoklis
On Sat, Jun 10, 2000 at 07:50:27PM -0400, Eric S. Raymond wrote:
I thought it was going to become part of curses from the user's point of view, so that "import curses" brings it in. That seemed to be the intent of the request at the end of the curses HOWTO.
Ooh, no; that text is saying that an editor would make a good example to put in the HOWTO. I'd rather have the curses module contain only a fairly close mapping of the C API, and extensions written in Python would be in submodules like curses.editor, curses.textbox, whatever. Similar to how socketmodule.c is a thin veneer over the BSD socket API, and the spiffy extensions are in asyncore.py, httplib.py, &c. --amk
participants (5)
-
Andrew Kuchling
-
bwarsaw@python.org
-
Eric S. Raymond
-
Greg Stein
-
Moshe Zadka