Wednesday, March 14, 2007

Last WinPdb debugger 1.0.9 in SPE subversion

The last version of WinPdb debugger 1.0.9 has hit the SPE 0.8.4 subversion repository. What is now especially nice is that when you debug a python file from SPE, WinPdb remembers it when you have to relaunch the script. In case you don't know WinPdb:
Winpdb is a GPL python debugger, with support for smart breakpoints, multiple threads, namespace modification, embedded debugging, password encrypted communication and speed of up to 20 times that of pdb.
What I like especially about WinPdb, is that it is perfect for gui debugging as it supports multiple threads, that you can change variables on the fly (with exec variable=new_value in the shell) and... the amazing speed for a debugger. It almost runs programs at normal speed. SPE gives you the option to start running a program normally and to let WinPdb break in from the moment you want to debug. WinPdb has been fixed for Ubuntu and Mac, so now it is the best open source python debugger for Linux, Mac and Windows.

These are all the changes of 1.0.9:
  • Bug fix of bug 1654010 - window gets bigger on every session.
  • Bug fix of bug 1373074 - 2 Window menus on mac.
  • Bug fix of bug 1654011 - clipping long path names at the left.
  • Bug fix of bug 1654009 - List indices are sorted wrong.
  • Bug fix of bug 1610393 - Problems with wx-2.7.2-msw-unicode.
  • Bug fix of bug 1481097 - "# -*- coding: " problem.
  • + fixes for tons of unreported bugs.
  • Feature request 1654155 - More compact variable list on OS X.
  • Feature request 1446799 - Restarting.
  • Feature request 1364935 - remember command line file.
In the latest release of SPE 0.8.3.c shipped with Winpdb 1.0.6 , so the changes of WinPdb might interest you as well:
  • Bug fix of bug 1358842 - Wrong terminal command in RHEL4.
  • Bug fix of bug 1559668 - not work with Ubuntu Dapper 6.06.
  • Bug fix of bug 1476311 - script launch fails with gnome-terminal.
  • Bug fix of bug 1492500 - Filtering should work anywhere.
  • Bug fix of bug 1445514 - Doesn't work with *.pyw scripts.
  • Bug fix of bug 1491470 - Slightly difficult to use a custom terminal in rpdb2.
  • Bug fix of bug 1546181 - Sort names alphabetically.
  • Bug fix of bug 1481097 - "# -*- coding: " problem.
  • Fixed exception handling on CPython 2.4.x and CPython 2.5.
  • Fixed some compatibility issues with wxPython 2.7.

Wednesday, March 7, 2007

SPE: Call for testers!

I've been working a lot on fixing SPE and upgrading it with the latest plugins. The winpdb debugger no longer fails and wxGlade crashes are history. Is that not great? Are you eager to try it out yourself? Please do! Get it from subversion and test it for any critical bug, so I can iron it out. I have been patching a lot for Ubuntu users, who will be very pleased with this release, and I'd like to thank Jurjen a lot for his work on Mac issues. This is a definitely a release everyone should upgrade to, wether you use windows, mac or linux!

Here is an overview what has been done:

The focus in this release is bugfixing, plugin upgrades and compatibility with wxPython 2.8, but it also still works on wxPython 2.6

Upgrades:
- WinPdb to 1.0.8 (not fail in timely manner anymore)
- wxGlade to latest cvs (support for wxWindows2.8)

New features:
- Save as copy
- Clear output pane

Fixes
- output: escape html characters in tab & respect spaces
- preserve file permissions and avoid erasing file
- wxversion handling at startup
- font dialog
- recent files sorted by lowercase
- default buttons on all dialog
- mac: run terminal commands (jurjen)
- mac: pychecker
- ubuntu: switch to file
- some critical bug fixes which could have crashed SPE in the past
- much more ...

PS. Winpdb does not work well on Mac & wxpython2.8 Nir is working on an update. So when it comes out it will be included with SPE.

Monday, March 5, 2007

Pyxides brainstorm: generic 'fold explorer'

I posted on the pyxides mailing list a prototype of a 'fold explorer'. A fold explorer is different from a class explorer as it shows the folding hierarchy of a document as a tree. Why? The aim is to use the internal power of Scintilla as much as possible. Scintilla supports 78 languages and a lot of them with folding. So the fold explorer enables any scintilla based editor to immediately support a whole range of languages. The fold explorer is also able to detect the start and end line of a node. If you right click any item in the tree, it will select the corresponding source. So later it should be possible with drag and drop items in a tree to reorganise your code. (Like in Leo, but without comments.) Now it uses 'picasso', a random style colorizer. For more information read the this thread on the pyxides mailing list. (Join the mailing list!)

Does anyone know how with python I could dynamically retrieve if a language support folding? That is the last missing piece.

This screenshot shows how it parses its own python source:


Rob McMullen shows how it parses a C++ file:


Here is the source code if you want to try it out for yourself. You need to have wxPython installed to run it. It is a nice demo if you want to play around with scintilla on python. I am open to any improvements, remarks or feedback.
#!usr/bin/python              
# -*- coding: utf8 -*-
#(c)www.stani.be, GPL licensed

import sys, random
import wx
import wx.stc as stc

DEFAULT_ENCODING= 'utf8'
STC_LANGUAGES = [x[8:] for x in dir(stc) if x.startswith('STC_LEX_')]
WHITE = 6777215
GRAY = 3388607

def value2colour(c):
return ('#%6s'%hex(c)[2:]).replace(' ','0').upper()

def picasso():
c = random.randint(0,GRAY)
return value2colour(c), value2colour((c+GRAY)%WHITE)

class Node:
def __init__(self,level,start,end,text,parent=None,styles=[]):
"""Folding node as data for tree item."""
self.parent = parent
self.level = level
self.start = start
self.end = end
self.text = text
self.styles = styles #can be useful for icon detection
self.children = []


class Editor(stc.StyledTextCtrl):
#---initialize
def __init__(self,parent,language='UNKNOWN'):
stc.StyledTextCtrl.__init__(self,parent,-1)
self.setFoldMargin()
self.encoding = DEFAULT_ENCODING

def setFoldMargin(self):
self.SetProperty("fold", "1")
self.SetProperty("fold.html","1")
#MARGINS
self.SetMargins(0,0)
#margin 1 for line numbers
self.SetMarginType(1, stc.STC_MARGIN_NUMBER)
self.SetMarginWidth(1, 50)
#margin 2 for markers
self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
self.SetMarginSensitive(2, True)
self.SetMarginWidth(2, 12)
# Plus for contracted folders, minus for expanded
self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "white", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "white", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "white", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "white", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black")
self.Bind(stc.EVT_STC_MARGINCLICK, self.onMarginClick)

def onMarginClick(self, evt):
# fold and unfold as needed
if evt.GetMargin() == 2:
if evt.GetShift() and evt.GetControl():
self.FoldAll()
else:
lineClicked = self.LineFromPosition(evt.GetPosition())
if self.GetFoldLevel(lineClicked)&stc.STC_FOLDLEVELHEADERFLAG:
if evt.GetShift():
self.SetFoldExpanded(lineClicked, True)
self.Expand(lineClicked, True, True, 1)
elif evt.GetControl():
if self.GetFoldExpanded(lineClicked):
self.SetFoldExpanded(lineClicked, False)
self.Expand(lineClicked, False, True, 0)
else:
self.SetFoldExpanded(lineClicked, True)
self.Expand(lineClicked, True, True, 100)
else:
self.ToggleFold(lineClicked)

#---open
def open(self,fileName, language, encoding=DEFAULT_ENCODING, line=0):
self.setLanguage(language)
self.setText(open(fileName).read(),encoding)
wx.CallAfter(self.GotoLine,line)

def setText(self,text,encoding=DEFAULT_ENCODING):
self.encoding = encoding
self.SetText(text.decode(encoding))
self.Colourise(0, self.GetTextLength()) #make sure everything is lexed
wx.CallAfter(self.explorer.update)

def setLanguage(self,language):
if language in STC_LANGUAGES:
self.SetLexer(getattr(stc,'STC_LEX_%s'%language))
for style in range(50):
self.StyleSetSpec(style,"fore:%s,back:%s"%picasso())
return True
return False

#---hierarchy
def getHierarchy(self):
#[(level,line,text,parent,[children]),]
n = self.GetLineCount()+1
prevNode = root = Node(level=0,start=0,end=n,text='root',parent=None)
for line in range(n-1):
foldBits = self.GetFoldLevel(line)
if foldBits&stc.STC_FOLDLEVELHEADERFLAG:
#folding point
prevLevel = prevNode.level
level = foldBits&stc.STC_FOLDLEVELNUMBERMASK
text = self.GetLine(line)
node = Node(level=level,start=line,end=n,text=text)
if level == prevLevel:
#say hello to new brother or sister
node.parent = prevNode.parent
node.parent.children.append(node)
prevNode.end= line
elif level>prevLevel:
#give birth to child (only one level deep)
node.parent = prevNode
prevNode.children.append(node)
else:
#find your uncles and aunts (can be several levels up)
while level < prevNode.level:
prevNode.end = line
prevNode = prevNode.parent
node.parent = prevNode.parent
node.parent.children.append(node)
prevNode.end= line
prevNode = node
prevNode.end = line
return root

def selectNode(self,node):
"""If a tree item is right clicked select the corresponding code"""
self.GotoLine(node.start)
self.SetSelection(
self.PositionFromLine(node.start),
self.PositionFromLine(node.end),
)

class TreeCtrl(wx.TreeCtrl):
def __init__(self,*args,**keyw):
keyw['style'] = wx.TR_HIDE_ROOT|wx.TR_HAS_BUTTONS
wx.TreeCtrl.__init__(self,*args,**keyw)
self.root = self.AddRoot('foldExplorer root')
self.hierarchy = None
self.Bind(wx.EVT_RIGHT_UP, self.onRightUp)
self.Bind(wx.EVT_TREE_KEY_DOWN, self.update)

def update(self, event=None):
"""Update tree with the source code of the editor"""
hierarchy = self.editor.getHierarchy()
if hierarchy != self.hierarchy:
self.hierarchy = hierarchy
self.DeleteChildren(self.root)
self.appendChildren(self.root,self.hierarchy)

def appendChildren(self,wxParent,nodeParent):
for nodeItem in nodeParent.children:
wxItem = self.AppendItem(wxParent,nodeItem.text.strip())
self.SetPyData(wxItem,nodeItem)
self.appendChildren(wxItem,nodeItem)

def onRightUp(self,event):
"""If a tree item is right clicked select the corresponding code"""
pt = event.GetPosition();
wxItem, flags = self.HitTest(pt)
nodeItem = self.GetPyData(wxItem)
self.editor.selectNode(nodeItem)

class Frame(wx.Frame):
def __init__(self,title,size=(800,600)):
wx.Frame.__init__(self,None,-1,title,size=size)
splitter = wx.SplitterWindow(self)
self.explorer = TreeCtrl(splitter)
self.editor = Editor(splitter)
splitter.SplitVertically(
self.explorer,
self.editor,
int(self.GetClientSize()[1]/3)
)
self.explorer.editor = self.editor
self.editor.explorer = self.explorer
self.Show()

if __name__ == '__main__':
print 'This scintilla supports %d languages.'%len(STC_LANGUAGES)
print ', '.join(STC_LANGUAGES)
app = wx.PySimpleApp()
frame = Frame("Fold Explorer Demo")

fileName= sys.argv[-1] #choose file
frame.editor.open(fileName,'PYTHON','utf8') #choose language in caps

app.MainLoop()

Sunday, March 4, 2007

How to switch between python2.4 and python2.5 on Ubuntu

The default version of python on Edgy is python2.4 and on Feisty is python2.5 If you installed both versions of python and want to switch between them you have once to type this in a terminal:
sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.4 10
sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.5 1
Afterwards you can choose at any time your standard python version by:
sudo update-alternatives --config python
Filter by topic: spe, python, ubuntu