Hi!
I've cooked up a new version of my 'Assign method parameters to attributes of
self' script. This one should be saner, neater, more helpful, and respectful of
indent. I'm still very thankful for any hints or comments regarding anything in
this code.
I also have a few questions:
1)
Is there some way of detecting whether or not there's a syntax error on the
current line at sript execution? In the current form my script will happily
propagate syntax errors from the def line, e.g:
class moo:
def cow(self, 1):
(gives self.1 = 1 on execution)
2) Is there a bug in getInsideParentesisToks?
If called with the string "(foo,)" then (the equivalent of) ['foo'] is
returned. If called with the string "(foo, )" then (the equivalent of) ['foo',
''] is returned. The input values are equivalent in python, so shouldn't the
returned values be equal?
The reason I ask is related to my comment at line 71 in my attached script:
# This can happen with legal def lines such as "def moo(self, ):"
3)
Right now my script activates on "Ctrl-2" followed by "a<Enter>". I think what
we initially discussed was having this as "Ctrl-2" followed by "a", which just
requires swapping the True at the final line for a False.
Which one should I use? The latter seems more convenient for me right now, but
using it makes it impossible to execute other scripts whose names begin with
"a". Is there an easy way for users to rebind script names to their needs? Who
decides which script should have what name?
Anyway, I'm really starting to like this pydev scripting thing. This'll be
good, I'm sure. :-)
Take care!
/Joel Hedlund
# This is a magic trick that tells the PyDev Extensions editor
# about the namespace provided for pydev scripts:
if False:
from org.python.pydev.editor import PyEdit [EMAIL PROTECTED]
cmd = 'command string'
editor = PyEdit
assert cmd is not None
assert editor is not None
# 'onSave' can be added to the list for developing purposes.
if cmd in ['onCreateActions']:
import re
from java.lang import StringBuffer
from org.eclipse.jface.action import Action [EMAIL PROTECTED]
from org.eclipse.jface.dialogs import MessageDialog [EMAIL PROTECTED]
from org.python.pydev.core.docutils import PySelection [EMAIL PROTECTED]
from org.python.pydev.editor.actions import PyAction [EMAIL PROTECTED]
from org.python.pydev.core.docutils import ParsingUtils [EMAIL PROTECTED]
class ScriptUnapplicableError(Exception):
"""Raised when the script is unapplicable to the current line."""
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
class AssignToAttribsOfSelf(Action):
"""Assign method parameter values to attributes with same name.
Pydev script for generating code that assigns the values of
method parameters to attributes of self with the same name.
The script will not make any changes to your code if the
current line does not contain both the def keyword and the
opening paranthesis of the parameter list of the method.
Ex:
def moo(self, cow, sheep=1, *pargs, **kwargs):
"docstring for method"
Executing this script at the method def line will generate four
lines of code, preserving the docstring. Like so:
def moo(self, cow, sheep=1, *pargs, **kwargs):
"docstring for method"
self.cow = cow
self.sheep = sheep
self.pargs = pargs
self.kwargs = kwargs
"""
_rDef = re.compile(r'^\s+def\s')
def run(self):
oSelection = PySelection(editor)
sNewLine = PyAction.getDelimiter(oSelection.getDoc())
try:
# Check applicability:
sCurrentLine = oSelection.getCursorLineContents()
if not self._rDef.match(sCurrentLine):
msg = ("The current line is not the first line of a "
"method def statement.")
raise ScriptUnapplicableError(msg)
oParamInfo = oSelection.getInsideParentesisToks(True)
if not oParamInfo:
msg = ("The parameter list does not start on the first "
"line of the method def statement.")
raise ScriptUnapplicableError(msg)
lsParams = list(oParamInfo.o1)
if not lsParams or lsParams[0] != 'self':
msg = ("The parameter list does not start with self.")
raise ScriptUnapplicableError(msg)
if '' in lsParams:
# This can happen with legal def lines such as "def moo(self, ):"
lsParams.remove('')
if not len(lsParams) > 1:
msg = ("The method has no parameters other than self.")
raise ScriptUnapplicableError(msg)
# Determine insert point:
iClosingParenOffset = oParamInfo.o2
iClosingParenLine = oSelection.getLineOfOffset(iClosingParenOffset)
iInsertAfterLine = iClosingParenLine
sPreviousIndent = PySelection.getIndentationFromLine(sCurrentLine)
sIndent = sPreviousIndent + PyAction.getStaticIndentationString()
# Is there a docstring? In that case we need to put assignments after it ends.
sDocstrFirstLine = oSelection.getLine(iClosingParenLine + 1)
sDocstrStart = sDocstrFirstLine.strip()[:2]
if sDocstrStart and (sDocstrStart[0] in ['"', "'"] or sDocstrStart in ['r"', "r'"]):
iDocstrLineOffset = oSelection.getLineOffset(iClosingParenLine + 1)
iDocstrStartCol = min([i for i in [sDocstrFirstLine.find(s) for s in ['"', "'"]] if i >= 0])
iDocstrOffset = iDocstrLineOffset + iDocstrStartCol
iDocstrEndOffset = ParsingUtils.eatLiterals(document, StringBuffer(), iDocstrOffset)
iInsertAfterLine = oSelection.getLineOfOffset(iDocstrEndOffset)
sIndent = PySelection.getIndentationFromLine(sDocstrFirstLine)
# Assemble assignment lines and insert them into the document:
sTemplate = sIndent + "self.%(name)s = %(name)s"
sAssignments = sNewLine.join([sTemplate % {'name':s.split('*')[-1]} for s in lsParams[1:]])
oSelection.addLine(sAssignments, iInsertAfterLine)
except ScriptUnapplicableError, e:
sTitle = "Script Unapplicable"
sHeader = "Script: Assign Method Parameters to Attributes of self"
sBody = "The script cannot be run due to the following error:"
sDialogText = sHeader + sNewLine * 2 + sBody + sNewLine + str(e)
MessageDialog.openInformation(editor.getSite().getShell(), sTitle, sDialogText)
description = 'Assign method parameters to attributes of self'
editor.addOfflineActionListener("a", AssignToAttribsOfSelf(), description, True)
editor.addOfflineActionListener("assign", AssignToAttribsOfSelf(), description, True)