I have got a PyQT widget interpreter working, the code picked up from here is as follows:
import os
import re
import sys
import code
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class MyInterpreter(QWidget):
def __init__(self, parent):
super(MyInterpreter, self).__init__(parent)
hBox = QHBoxLayout()
self.setLayout(hBox)
self.textEdit = PyInterp(self)
# this is how you pass in locals to the interpreter
self.textEdit.initInterpreter(locals())
self.resize(650, 300)
self.centerOnScreen()
hBox.addWidget(self.textEdit)
hBox.setMargin(0)
hBox.setSpacing(0)
def centerOnScreen(self):
# center the widget on the screen
resolution = QDesktopWidget().screenGeometry()
self.move((resolution.width() / 2) - (self.frameSize().width() / 2),
(resolution.height() / 2) - (self.frameSize().height() / 2))
class PyInterp(QTextEdit):
class InteractiveInterpreter(code.InteractiveInterpreter):
def __init__(self, locals):
code.InteractiveInterpreter.__init__(self, locals)
def runIt(self, command):
code.InteractiveInterpreter.runsource(self, command)
def __init__(self, parent):
super(PyInterp, self).__init__(parent)
sys.stdout = self
sys.stderr = self
self.refreshMarker = False # to change back to >>> from ...
self.multiLine = False # code spans more than one line
self.command = '' # command to be ran
self.printBanner() # print sys info
self.marker() # make the >>> or ... marker
self.history = [] # list of commands entered
self.historyIndex = -1
self.interpreterLocals = {}
# setting the color for bg and text
palette = QPalette()
palette.setColor(QPalette.Base, QColor(0, 0, 0))
palette.setColor(QPalette.Text, QColor(0, 255, 0))
self.setPalette(palette)
self.setFont(QFont('Courier', 12))
# initilize interpreter with self locals
self.initInterpreter(locals())
def printBanner(self):
self.write(sys.version)
self.write(' on ' + sys.platform + '\n')
self.write('PyQt4 ' + PYQT_VERSION_STR + '\n')
msg = 'Type !hist for a history view and !hist(n) history index recall'
self.write(msg + '\n')
def marker(self):
if self.multiLine:
self.insertPlainText('... ')
else:
self.insertPlainText('>>> ')
def initInterpreter(self, interpreterLocals=None):
if interpreterLocals:
# when we pass in locals, we don't want it to be named "self"
# so we rename it with the name of the class that did the passing
# and reinsert the locals back into the interpreter dictionary
selfName = interpreterLocals['self'].__class__.__name__
interpreterLocalVars = interpreterLocals.pop('self')
self.interpreterLocals[selfName] = interpreterLocalVars
else:
self.interpreterLocals = interpreterLocals
self.interpreter = self.InteractiveInterpreter(self.interpreterLocals)
def updateInterpreterLocals(self, newLocals):
className = newLocals.__class__.__name__
self.interpreterLocals[className] = newLocals
def write(self, line):
self.insertPlainText(line)
self.ensureCursorVisible()
def clearCurrentBlock(self):
# block being current row
length = len(self.document().lastBlock().text()[4:])
if length == 0:
return None
else:
# should have a better way of doing this but I can't find it
[self.textCursor().deletePreviousChar() for x in xrange(length)]
return True
def recallHistory(self):
# used when using the arrow keys to scroll through history
self.clearCurrentBlock()
if self.historyIndex <> -1:
self.insertPlainText(self.history[self.historyIndex])
return True
def customCommands(self, command):
if command == '!hist': # display history
self.append('') # move down one line
# vars that are in the command are prefixed with ____CC and deleted
# once the command is done so they don't show up in dir()
backup = self.interpreterLocals.copy()
history = self.history[:]
history.reverse()
for i, x in enumerate(history):
iSize = len(str(i))
delta = len(str(len(history))) - iSize
line = line = ' ' * delta + '%i: %s' % (i, x) + '\n'
self.write(line)
self.updateInterpreterLocals(backup)
self.marker()
return True
if re.match('!hist\(\d+\)', command): # recall command from history
backup = self.interpreterLocals.copy()
history = self.history[:]
history.reverse()
index = int(command[6:-1])
self.clearCurrentBlock()
command = history[index]
if command[-1] == ':':
self.multiLine = True
self.write(command)
self.updateInterpreterLocals(backup)
return True
return False
def keyPressEvent(self, event):
if event.key() == Qt.Key_Escape:
# proper exit
self.interpreter.runIt('exit()')
if event.key() == Qt.Key_Down:
if self.historyIndex == len(self.history):
self.historyIndex -= 1
try:
if self.historyIndex > -1:
self.historyIndex -= 1
self.recallHistory()
else:
self.clearCurrentBlock()
except:
pass
return None
if event.key() == Qt.Key_Up:
try:
if len(self.history) - 1 > self.historyIndex:
self.historyIndex += 1
self.recallHistory()
else:
self.historyIndex = len(self.history)
except:
pass
return None
if event.key() == Qt.Key_Home:
# set cursor to position 4 in current block. 4 because that's where
# the marker stops
blockLength = len(self.document().lastBlock().text()[4:])
lineLength = len(self.document().toPlainText())
position = lineLength - blockLength
textCursor = self.textCursor()
textCursor.setPosition(position)
self.setTextCursor(textCursor)
return None
if event.key() in [Qt.Key_Left, Qt.Key_Backspace]:
# don't allow deletion of marker
if self.textCursor().positionInBlock() == 4:
return None
if event.key() in [Qt.Key_Return, Qt.Key_Enter]:
# set cursor to end of line to avoid line splitting
textCursor = self.textCursor()
position = len(self.document().toPlainText())
textCursor.setPosition(position)
self.setTextCursor(textCursor)
line = str(self.document().lastBlock().text())[4:] # remove marker
line.rstrip()
self.historyIndex = -1
if self.customCommands(line):
return None
else:
try:
line[-1]
self.haveLine = True
if line[-1] == ':':
self.multiLine = True
self.history.insert(0, line)
except:
self.haveLine = False
if self.haveLine and self.multiLine: # multi line command
self.command += line + '\n' # + command and line
self.append('') # move down one line
self.marker() # handle marker style
return None
if self.haveLine and not self.multiLine: # one line command
self.command = line # line is the command
self.append('') # move down one line
self.interpreter.runIt(self.command)
self.command = '' # clear command
self.marker() # handle marker style
return None
if self.multiLine and not self.haveLine: # multi line done
self.append('') # move down one line
self.interpreter.runIt(self.command)
self.command = '' # clear command
self.multiLine = False # back to single line
self.marker() # handle marker style
return None
if not self.haveLine and not self.multiLine: # just enter
self.append('')
self.marker()
return None
return None
# allow all other key events
super(PyInterp, self).keyPressEvent(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyInterpreter(None)
win.show()
sys.exit(app.exec_())
Is there an easy way of getting some tab completion going just for local symbols ?
Do one of the following: Click the Python Interpreter selector and choose Add New Interpreter. Press Ctrl+Alt+S to open the project Settings/Preferences and go to Project: <project name> | Python Interpreter. Click the Add Interpreter link next to the list of the available interpreters.
Embedding provides your application with the ability to implement some of the functionality of your application in Python rather than C or C++. This can be used for many purposes; one example would be to allow users to tailor the application to their needs by writing some scripts in Python.
The interpreter operates somewhat like the Unix shell: when called with standard input connected to a tty device, it reads and executes commands interactively; when called with a file name argument or with a file as standard input, it reads and executes a script from that file.
Python interpreters in PyCharmA virtual environment consists of a base interpreter and installed packages. With PyCharm Professional, you can also configure interpreters to execute your Python code on remote environments: SSH, Vagrant, WSL (only for Windows), Docker, and Docker Compose.
I think you are referring to rlcompleter's Completer object.
You can used it like so:
from rlcompleter import Completer
line = str(...)
completer = Completer(self.interpreter.locals)
suggestion = completer.complete(line, 0)
self.insertPlainText(suggestion)
The numeric argument indicates the n-th suggestion, and you can iterate over it until it returns None
.
For example, say we have
>>> my_data = '012345'
then
>>> completer.complete('my_', 0)
'my_data'
>>> completer.complete('my_data.s', 0)
'my_data.split('
>>> completer.complete('my_data.s', 1)
'my_data.splitlines('
Note that while the code above uses interpreter.locals
, you can apply a wider search (but be sure to provide a dictionary).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With