I'm trying to create a debug console for the main console I'm writing using Cmd module.
The debug console should have all the main console attributes and ontop some more extentions used for debug and advanced users.
The best answer to fir my needs was the second answer of the following post:
object inheritance and nested cmd
My implementation currently looks like this:
class MainConsole(cmd.Cmd):
def __init__(self):
cmd.Cmd.__init__(self)
def do_something(self, line):
print "do something!"
return
def do_something2(self, line):
print "do something2!"
return
class SubConsole1(cmd.Cmd):
def __init__(self, maincon):
cmd.Cmd.__init__(self)
self.maincon = maincon
self.register_main_console_methods()
def register_main_console_methods(self):
main_names = self.maincon.get_names()
for name in main_names:
if (name[:3] == 'do_') or (name[:5] == 'help_') or (name[:9] == 'complete_'):
self.__dict__[name] = getattr(self.maincon, name)
Observation:
When I hit "help", I indeed see all the upper console methods and I'm able to invoke them.
Problem:
The autocompletion of the actual commands is not available.
The expected behaviour of the shell when hitting "some" and tab would be to autocomplete it to "something". This doesn't happen.
When I tried to debug the issue, I found out that self.get_names() method which is used by the self.completenames() function returns the list of methods before the registration.
So what's actually happening is that the newly added methods are "removed" from the nested console, although I can invoke them.
I'd love some insights on that.
Thanks!
You can solve your problem by extending get_names method
import cmd
class MainConsole(cmd.Cmd):
def __init__(self,console_id):
cmd.Cmd.__init__(self)
self.console_id = console_id
def do_something(self, line):
print "do something!",self.console_id
return
def do_something2(self, line):
print "do something2!",self.console_id
return
class SubConsole1(cmd.Cmd):
def __init__(self, maincon):
cmd.Cmd.__init__(self)
self.maincon = maincon
self.register_main_console_methods()
def do_super_commands(self,line):
print "do supercommand",self.maincon
def register_main_console_methods(self):
main_names = dir(self.maincon)
for name in main_names:
for prefix in 'do_','help_','complete_', :
if name.startswith(prefix) and name not in dir(self):
self.__dict__[name] = getattr(self.maincon, name)
def get_names(self):
result = cmd.Cmd.get_names(self)
result+=self.maincon.get_names()
return result
SubConsole1(MainConsole("mainconsole")).cmdloop()
it is not guaranteed to work on subsequence version of python as it is undocumented behavior of python 2.7
EDIT: replacing the subclassing method by mainconsole as a member as required in comment
EDIT 2: don't replace the existing methods in SubConsole to keep method as do_help
Related
Am struggling to comprehend how to split code in (Py)Qt. The aim is to have the design & navigation tabs in QMainWindow, each tab triggering code in other files. So far it only launches with the ActionClass in the same document / putting in an external document causes 'app not defined' when clicking the tab. The below works without errors, but is clunky.
class Main(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.u = Ui_MainWindow()
self.u.setupUi(self)
self.u.tabs.currentChanged.connect(self.TabsChanged)
def TabsChanged(self, i):
if i == self.u.tabs.indexOf(self.u.tabFirst): ActionClass.__init__
class ActionClass(Main):
def __init__(self):
app.u.lineEdit.setText("test")
app = Main()
app.show()
sys.exit(app.exec_())
The examples I keep seeing have all code in one document. Is there another way to do this e.g. where the ActionClass is in another file/writing u.lineEdit.setText instead of app.u.lineEdit.setText. It seems inheritance & an instance of Main can't be accessed from the ActionClasses doc, so I can't see how they would communicate back to the Main?
Much appreciated
As suggest #M4rtini you can separate your code into python modules. And then import them (use them) in your main module.
For instance the code you posted can be separated in to files:
# actions_class.py
class ActionClass(Main):
def __init__(self):
app.u.lineEdit.setText("test")
and
# main.py
from action_class import ActionClass # This line no need much explanation ;)
class Main(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.u = Ui_MainWindow()
self.u.setupUi(self)
self.u.tabs.currentChanged.connect(self.TabsChanged)
def TabsChanged(self, i):
if i == self.u.tabs.indexOf(self.u.tabFirst): ActionClass.__init__
app = Main()
app.show()
sys.exit(app.exec_())
In order to understand how import works see the link I left you above.
More explanation
Lest's see:
The correct way of executin code inside a __init__ method is creating an instance. See the example below.
class A:
def __init__(self):
print("Executing A.__init__")
print("Doing things wrong")
A.__init__ # This don't print enything
print("Doing things well")
A() # This works as expected.
So, you line reads:
if i == self.u.tabs.indexOf(self.u.tabFirst): ActionClass.__init__
and should reads:
if i == self.u.tabs.indexOf(self.u.tabFirst): ActionClass()
On the other hand, is a bad practice put code that's not for initialize the instance inside the __init__ methods.
If you don't need the instance but yet you want to store the functions inside a class (something like a c++ namespace) you creating
use #staticmethod decorator.
class A:
#staticmethod
def foo():
print("Oh, wow, a static method in Python!")
A.foo()
So, your ActionClass could be rewritten as:
class ActionClass(Main):
#staticmethod
def do_action:
app.u.lineEdit.setText("test")
ans then you can use it like this:
if i == self.u.tabs.indexOf(self.u.tabFirst): ActionClass.do_action()
#!/usr/bin/env python2.7
##-*- mode:python;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t;python-indent:2 -*-'
import noesy
import argparse
import library
parser =argparse.ArgumentParser(description="read pdb file",
add_help=True)
parser.add_argument("file",help="protein pdb file")
library.add_standard_args( parser )
args = parser.parse_args()
def read_structure(pdbfile):
struct=[]
for line in pdbfile:
if len(line):
struct.append(PDBAttributes.read_from_line(line))
return struct
pdb=read_structure(open(args.file,'r'))
class PDBAttributes:
def __init__(self, atomindex=1, atom=noesy.Atom(), atomx=1, atomy=1, atomz=1):
self._atomindex=atomindex
self._atom=atom
self._atomx=atomx
self._atomy=atomy
self._atomz=atomz
def __str__(self):
s='ATOM %(_atomindex)d %(_atom)s at %(_atomx)8.3f %(_atomy)8.3f %(_atomz)8.3f'%self.__dict__
return s
def atom(self):
return self._atom
def atomindex(self):
return self._atomindex
def atomx(self):
return self._atomx
def atomy(self):
return self._atomy
def atomz(self):
return self._atomz
#classmethod
def read_from_line(obj,line):
tags=line.split()
atomindex=int(tags[1])
atom=noesy.Atom(tags[2],int(tags[5]))
atomx=float(tags[6])
atomy=float(tags[7])
atomz=float(tags[8])
obj=PDBAttributes(atomindex, atom, atomx, atomy, atomz)
print obj
class AtomDistance(PDBAttributes):
def distance(self, atom1,atom2):
pass
The NameError you are getting is due to the order you have placed the code in your file.
When you call read_structure to create a value for the pdb variable, it tries to look for PDBAttributes, but it has not been defined yet. If you move that line lower down in the file (below the class definition) you'll avoid that error. Note that it is OK to have the declaration of read_structure above the PDBAttributes class definition, though you might want to move it lower too to make the code easier to understand.
Here's a very simple bit of code that demonstrates the same error:
def foo():
print(foo_text)
foo() # raises a NameError
foo_text = "foo"
Here's a fixed version:
def foo():
print(foo_text)
foo_text = "foo"
foo() # no error, prints "foo"
Move your call of read_structure to follow the definition of the PDBAttributes class.
Also, in the process of reformatting your post, I see that you have mixed tabs and spaces for your indentation. Try reformatting your code to use all spaces for indentation, the recommended form is 4-space indents.
Your definition of all those getter functions looks like Java written in Python - this is a lot of extra code that is often unnecessary in Python. The recommended approach is to omit these all-they-do-is-assign-a-value-to-an-attribute-with-the-same-name-but-with-a-leading-underscore methods and just use attributes with the public names. See Python is Not Java.
I make use of PyCLIPS to integrate CLIPS into Python. Python methods are registered in CLIPS using clips.RegisterPythonFunction(method, optional-name). Since I have to register several functions and want to keep the code clear, I am looking for a decorator to do the registration.
This is how it is done now:
class CLIPS(object):
...
def __init__(self, data):
self.data = data
clips.RegisterPythonFunction(self.pyprint, "pyprint")
def pyprint(self, value):
print self.data, "".join(map(str, value))
and this is how I would like to do it:
class CLIPS(object):
...
def __init__(self, data):
self.data = data
#clips.RegisterPythonFunction(self.pyprint, "pyprint")
#clips_callable
def pyprint(self, value):
print self.data, "".join(map(str, value))
It keeps the coding of the methods and registering them in one place.
NB: I use this in a multiprocessor set-up in which the CLIPS process runs in a separate process like this:
import clips
import multiprocessing
class CLIPS(object):
def __init__(self, data):
self.environment = clips.Environment()
self.data = data
clips.RegisterPythonFunction(self.pyprint, "pyprint")
self.environment.Load("test.clp")
def Run(self, cycles=None):
self.environment.Reset()
self.environment.Run()
def pyprint(self, value):
print self.data, "".join(map(str, value))
class CLIPSProcess(multiprocessing.Process):
def run(self):
p = multiprocessing.current_process()
self.c = CLIPS("%s %s" % (p.name, p.pid))
self.c.Run()
if __name__ == "__main__":
p = multiprocessing.current_process()
c = CLIPS("%s %s" % (p.name, p.pid))
c.Run()
# Now run CLIPS from another process
cp = CLIPSProcess()
cp.start()
it should be fairly simple to do like this:
# mock clips for testing
class clips:
#staticmethod
def RegisterPythonFunction(func, name):
print "register: ", func, name
def clips_callable(fnc):
clips.RegisterPythonFunction(fnc, fnc.__name__)
return fnc
#clips_callable
def test(self):
print "test"
test()
edit: if used on a class method it will register the unbound method only. So it won't work if the function will be called without an instance of the class as the first argument. Therefore this would be usable to register module level functions, but not class methods. To do that, you'll have to register them in __init__.
It seems that the elegant solution proposed by mata wouldn't work because the CLIPS environment should be initialized before registering methods to it.
I'm not a Python expert, but from some searching it seems that combination of inspect.getmembers() and hasattr() will do the trick for you - you could loop all members of your class, and register the ones that have the #clips_callable attribute to CLIPS.
Got it working now by using a decorator to set an attribute on the method to be registered in CLIPS and using inspect in init to fetch the methods and register them. Could have used some naming strategy as well, but I prefer using a decorator to make the registering more explicit. Python functions can be registered before initializing a CLIPS environment. This is what I have done.
import inspect
def clips_callable(func):
from functools import wraps
#wraps(func)
def wrapper(*__args,**__kw):
return func(*__args,**__kw)
setattr(wrapper, "clips_callable", True)
return wrapper
class CLIPS(object):
def __init__(self, data):
members = inspect.getmembers(self, inspect.ismethod)
for name, method in members:
try:
if method.clips_callable:
clips.RegisterPythonFunction(method, name)
except:
pass
...
#clips_callable
def pyprint(self, value):
print self.data, "".join(map(str, value))
For completeness, the CLIPS code in test.clp is included below.
(defrule MAIN::start-me-up
=>
(python-call pyprint "Hello world")
)
If somebody knows a more elegant approach, please let me know.
I've been working on a class with properties but we ran into a nasty problem with pylint (0.25.1) In the code below we are defining a class with a property which were introduced in python 2.6
However, pylint whines about the fact that in the __init__ method self.aProperty will overwrite the defined method named aProperty. I've also pasted the output from the console and the output of the pylint messages.
Is this a case of 'please report to the pylint devs' or is this piece of (example) code wrong?
"""example module"""
class Example(object):
"""example class"""
#property
def aProperty(self):
"""get"""
print "using getter"
return self._myPropertyValue
#aProperty.setter
def aProperty(self, value):
"""set"""
print "using setter"
self._myPropertyValue = value
def secondPublicMethodToIgnorePylintWarning(self):
"""dummy"""
return self.aProperty
def __init__(self):
"""init"""
self._myPropertyValue = None
self.aProperty = "ThisStatementWillRaise E0202"
anExample = Example()
print anExample.aProperty
anExample.aProperty = "Second binding"
print anExample.aProperty
Console Output:
using setter
using getter
ThisStatementWillRaise E0202
using setter
using getter
Second binding
Pylint Output:
E0202: 7,4:Example.aProperty: An attribute affected in test1 line 26 hide this method
E0202: 13,4:Example.aProperty: An attribute affected in test1 line 26 hide this method
see http://www.logilab.org/ticket/89092, a patch will soon be integrated into pylint to fix this pb
As I work and update a class, I want a class instance that is already created to be updated. How do I go about doing that?
class MyClass:
""" """
def __init__(self):
def myMethod(self, case):
print 'hello'
classInstance = MyClass()
I run Python inside of Maya and on software start the instance is created. When I call classInstance.myMethod() it always prints 'hello' even if I change this.
Thank you,
/Christian
More complete example:
class MayaCore:
'''
Super class and foundational Maya utility library
'''
def __init__(self):
""" MayaCore.__init__(): set initial parameters """
#maya info
self.mayaVer = self.getMayaVersion()
def convertToPyNode(self, node):
"""
SYNOPSIS: checks and converts to PyNode
INPUTS: (string?/PyNode?) node: node name
RETURNS: (PyNode) node
"""
if not re.search('pymel', str(node.__class__)):
if not node.__class__ == str and re.search('Meta', str(node)): return node # pass Meta objects too
return PyNode(node)
else: return node
def verifyMeshSelection(self, all=0):
"""
SYNOPSIS: Verifies the selection to be mesh transform
INPUTS: all = 0 - acts only on the first selected item
all = 1 - acts on all selected items
RETURNS: 0 if not mesh transform or nothing is selected
1 if all/first selected is mesh transform
"""
self.all = all
allSelected = []
error = 0
iSel = ls(sl=1)
if iSel != '':
if self.all: allSelected = ls(sl=1)
else:
allSelected.append(ls(sl=1)[0])
if allSelected:
for each in allSelected:
if nodeType(each) == 'transform' and nodeType(each.getShape()) == 'mesh':
pass
else: error = 1
else: error = 1
else: error = 1
if error: return 0
else: return 1
mCore = MayaCore()
The last line is inside the module file (mCore = MayaCore()).
There are tons of methods inside the class so I have removed them to shorten the scrolling :-)
Also there are import statements above the class but they screw up the formatting for some reason. Here they are:
from pymel.all import *
import re
from maya import OpenMaya as om
from our_libs.configobj import ConfigObj
if getMelGlobal('float', "mVersion") >= 2011:
from PyQt4 import QtGui, QtCore, uic
import sip
from maya import OpenMayaUI as omui
Inside Maya, we import this and subclasses of this class upon program start:
from our_maya.mayaCore import *
In other tools we write, we then call mCore.method() on a need basis.
The caveat I am running into is that when I am going back to modify the mCore method and the instance call is already in play, I have to restart Maya for all the instances to get updated with the method change (they will still use the un-modified method).
Alright, trying again, but with a new understanding of the question:
class Foo(object):
def method(self):
print "Before"
f = Foo()
f.method()
def new_method(self):
print "After"
Foo.method = new_method
f.method()
will print
Before
After
This will work with old style classes too. The key is modifying the class, not overriding the class's name.
You'll have to provide more details about what you are doing, but Python instances don't store methods, they always get them from their class. So if you change the method on the class, existing instances will see the new method.
My other answer answers your original question, so I'm leaving it there, but I think what you really want is the reload function.
import our_maya.mayaCore
reload(our_maya.mayaCore)
from our_maya.mayaCore import *
Do that after you change the class definition. Your new method ought to show up and be used by all the existing instances of your class.