Category Archives: Python

Python FTP Server and Client Minimal Test

On the server side, I use pyftpdlib. The path assigned to the authorizer must exist. Server address is localhost. Port number cannot be 21 or 80.

from pyftpdlib import ftpserver

def main():
    authorizer = ftpserver.DummyAuthorizer()
    authorizer.add_anonymous("/somewhere/somedir")
    handler = ftpserver.FTPHandler
    handler.authorizer = authorizer
    address = ('127.0.0.1', 7152)
    ftpd = ftpserver.FTPServer(address, handler)
    ftpd.serve_forever()


if __name__ == '__main__':
    main()

When the server.py is running. Execute the client side. Make sure it connects to the right address and port. Retrieve test.zip stored in the authorized path, then extract it to the place where client.py is started.

from ftplib import FTP
import zipfile

def main():
    ftp = FTP()
    ftp.connect('127.0.0.1','7152')  
    ftp.login() 
    ftp.retrbinary('RETR test.zip', open('test.zip', 'wb').write)
    ftp.quit()
    
    f = zipfile.ZipFile('test.zip', 'a')
    f.extractall()

if __name__ == '__main__':
    main()

Leave a comment

Filed under Python

Use Partial To Query UI Control

from functools import partial

def foo(a, arg=None):
print ‘first’,a
print ‘2nd’,arg
b= partial(foo, ‘default’)
b()
#first default
#2nd None
b(‘addon’)
#first default
#2nd addon
b
#<functools.partial object at 0x74c60>

Partial is a way to pack a func with a preset argument.  In the example above, calling b() has the same effect of calling foo(‘default’), and calling b(‘addon’) equals foo(‘default’, ‘addon’). This is quite useful when you want to query values from UI controls in Maya. For example:

import maya.cmds as cmds
from functools import partial
def foo(inst=None, arg=None):
retrieved = cmds.floatSliderGrp(inst.aSlider, query=True, value=True)
# omitted do something with retrieved

class Bar(object):
def __init__(self):
# omitted ui setup
self.aSlider = cmds.floatSliderGrp( label=’foo value’, v=0.5, min=0, max=1, cc=partial(foo, self) )
# omitted ui setup

So aSlider is a slider control as a member of Bar, with its change command assigned to function foo(). Need to expose the control to foo(), so the value can be queried for use. Since cc flag must be assigned to a function object, cc = foo(self) cannot work. Partial packed foo(self) into an object and solved this problem.

Leave a comment

Filed under Maya API, Python

PyQt Draggable Tree

This is a minimal test about how to do drap-and-drop within a QTreeWidget.

First let the tree setAcceptDrops. Then declare mouseMoveEvent, dropEvent, dragEnterEvent, and let dragMoveEvent = dragEnterEvent. The rest is to set mimeData, by which the information can be transferred between those events. Here only a string, name of the item, will be sent.

Click LMB on an item, drag-and-drop onto another, a new item will be created and attached to the latter. The drop event must hit an item.

 

Leave a comment

Filed under Python, Qt

Module And Resources

https://github.com/spinos/aphid/blob/master/pyqtmodule/iconLabel.py

Suppose you have a file named iconLable.py like above, and someone want to use it as a module in his/her program, like:

https://github.com/spinos/aphid/blob/master/pyqtmodule/testIconLabel.py

The problem is the above file only works when started from the same folder where iconLabel.py is saved. The module file should be put away into sys.path, so Python can find and import the module no matter where the program is started. Typically module files go to C:\Python26\Lib\site-packages

To test if it works, lauch Python command line, try:

import iconLabel

Another problem is those icon images, circle and square, are lost. Relative file path like:

image= QtGui.QPixmap('./circle.png')

only works when the file is started from the same path where the images are saved. Using absolute path:

image = QtGui.QPixmap('D:/somewhere/circle.png')

still cannot work because everyone to use the module should have a copy of those images in the same path.

Resources will be the solution. Save a .qrc file, iconLabel.qrc:

<!DOCTYPE RCC><RCC version="1.0">
 <qresource>
 <file>circle.png</file>
 <file>square.png</file>
 </qresource>
 </RCC>

Run command:

pyrcc4 iconLabel.qrc -o iconLabel_rc.py

Will create a module file, iconLabel_ry.py, contains those images. Inside iconLabel.py:

import iconLabel_rc

and change all file path to start with ‘:’, i.e.

desc.image_path = ':circle.png'

Run the module file again, Python will create binary code for both iconLabel and iconLabel_rc. Copy both .pyc files to sys.path, and this module is ready to go. You can remove iconLabel.py from sys.path, just use the .pyc files. This will be helpful in case you don’t want to give up your source code.

For more details about Qt resources, go here.

Leave a comment

Filed under Python, Qt

A Few Notes About Python Static Class Member

class Vertebra(object):
    weight = 0.1
    def __init__(self):
        print 'init vertebra'
                
class Fish(Vertebra):
    def __init__(self):
        super(Fish, self).__init__()
        print 'init fish'
        
class Bird(Vertebra):
    def __init__(self):
        super(Bird, self).__init__()
        print 'init bird'
        
class Kingfisher(Bird):
    def __init__(self):
        super(Kingfisher, self).__init__()
        print 'init kingfisher'

Any variable placed right after the class definition will be kinda static. Access the variable by <Class>.<Variable>, i.e.

Vertebra.weight

Any derived class will its <Class>.<Variable>, inherited from its parent class until it has been set specifically. i.e.

Fish.weight
Bird.weight
Kingfisher.weight

Any instance of the class will have a variable of its own, <Instance>.<Variable>, which equals to the value of <Class>.<Variable> until it has been set specifically.

tuna = Fish()
tuna.weight

Any changes to <Class>.<Variable> will affect all relevant variables of all derived classes.

Vertebra.weight = 99.0
Kingfisher.weight

Any changes to <Class>.<Variable> will only affect the values of <Instance>.<Variable> of all existing instances of the class and derived classes, except those have been set specifically.

sootyTern = Bird()
yellowBill = Kingfisher()
sootyTern.weight()
yellowBill.weight()
Bird.weight = 39.1
sootyTern.weight()
yellowBill.weight()

Set value to <Class>.<Variable> will liberate it from changes of inherited class.i.e.

Fish.weight = 1405.9
Vertebra.weight = 0.74
Fish.weight

Set value to <Instance>.<Variable> will liberate it from changes of instanced class and inherited class.i.e.

yellowBill.weight = 463.3
Bird.weight = 239.1
yellowBill.weight

 

Leave a comment

Filed under Python

Hybriding Qt with PyQt

A hybrid Qt and PyQt application sounds attractive: within a Qt application, parts for duty calculation are written in C++ , and UI is written in PyQt, making the application scriptable and expandable. To create such a program, we need to know how to do two sets of things: one is to embed PyQt into a C++ application, the other is to send information from PyQt back to C++. Above is an example. First line is in C++, and second is in PyQt. When the dial or slider is changed, numbers related field will be updated.

So how does it work?

Let’s start with the central widget of the main window.

Center::Center()
{
    setObjectName("center");
    QVBoxLayout* box = new QVBoxLayout();
    LeftWidget *leftDial = new LeftWidget();
    box->addWidget(leftDial);
    ShakeHole *rightDial = new ShakeHole();
    box->addWidget(rightDial);
    setLayout(box);
}

It has two widgets: a LeftWidget and a ShakeHole. (Sorry for the confusing names.)

First, the ShakeHole:

class ShakeHole : public QWidget
{
public:
    ShakeHole();
    ~ShakeHole() {}   
};
ShakeHole::ShakeHole()
{

    int wnd = winId();
        cout<<"winid "<<wnd<<endl;

    cout<<"version "<<Py_GetVersion()<<endl;

    FILE *fin = fopen("/Users/jianzhang/aphid/hybrid_qtpyqt/foo.py","r+");
    PyRun_SimpleFile(fin,"foo");

        PyObject *mainDict = PyModule_GetDict(PyImport_Import(PyString_FromString("__main__")));

        PyObject *claus = PyDict_GetItemString(mainDict, "Ui_Form");

        PyObject* snakewig = Py_BuildValue("i", wnd);

        PyObject * pTuple = PyTuple_New (1);
        PyTuple_SetItem (pTuple, 0, snakewig);

        PyObject *clausInstance = PyObject_CallObject(claus, pTuple);

        cout<<"finished python ui!\n";

        PyErr_Print();

}

It is derived from QWidget, and hooks a PyQt widget within via Python C API.

Now LeftWidget:

class LeftWidget : public HWidget
{
public:
    LeftWidget();
    void setAttribute(const char *attributeName, int value);
private:
    QLineEdit *attributeEdit;
    QLineEdit *attribute1Edit;
};

LeftWidget::LeftWidget()
{
    setObjectName("SnakeHole");
    QHBoxLayout* box = new QHBoxLayout();
    box->addWidget(new QLabel("qt host"));
    attributeEdit = new QLineEdit();
    box->addWidget(attributeEdit);
    attribute1Edit = new QLineEdit();
    box->addWidget(attribute1Edit);
    setLayout(box);

}

void LeftWidget::setAttribute(const char *attributeName, int value)
{
    QString attr(attributeName);
    if(attr == "fieldNumber")
    {
        QString str = QString("%1")
             .arg(value);
        attributeEdit->setText(str);
    }
    else if(attr == "sliderNumber")
    {
        QString str = QString("%1")
             .arg(value);
        attribute1Edit->setText(str);
    }
}

It is a derived HWidget, and it has two QLineEdit, which will be updated by setAttribute(). OK, so what is HWidget?

class HWidget : public QWidget
{
public:
    HWidget();
    virtual ~HWidget();
    virtual void setAttribute(const char *attributeName, int value);
};
void HWidget::setAttribute(const char *attributeName, int value)
{
    qDebug()<<"beep";
}

It is a derived QWidget as well, and it has a virtual function setAttribute() to override.

Go to the PyQt side:

from PyQt4 import QtCore, QtGui
import hoatzin

class Ui_Form(QtGui.QWidget):
    def __init__(self, parentId):      
        Form = QtGui.QWidget.find(parentId)
        super(Ui_Form, self).__init__(Form)
        self.resize(400, 100)
        self.host = hoatzin.Hoatzin()
        self.boxLayout = QtGui.QHBoxLayout()
        self.boxLayout.setObjectName('ui_form_box')
        self.boxLayout.setObjectName("boxLayout")
        self.boxLayout.addWidget(QtGui.QLabel('pyqt widget'))
        self.dial = QtGui.QDial()
        self.boxLayout.addWidget(self.dial)

        self.slider = QtGui.QSlider(QtCore.Qt.Horizontal)
        self.boxLayout.addWidget(self.slider)

        self.setLayout(self.boxLayout)

        self.dial.valueChanged.connect(self.dialTest)
        self.slider.valueChanged.connect(self.sliderTest)

    def dialTest(self):
        w = self.host.set_attribute_int('SnakeHole', 'fieldNumber', self.dial.value() )
        if w != 1:
            print 'SnakeHole not found'

    def sliderTest(self):
        w = self.host.set_attribute_int('SnakeHole', 'sliderNumber', self.slider.value() )
        if w != 1:
            print 'SnakeHole not found'

OK, it is a QWidget and will be attached to a specific parent. It has a dial and a slider, each of them will trigger a function by the signal of valueChanged. Wait a second! What on earth is hoatzin?

It is a Python extension to send information back to the host C++ program:

class Hoatzin
{
public:
    Hoatzin();

    int set_attribute_int(const char *widgetName, const char *attributeName, int value);

private:

};
int Hoatzin::set_attribute_int(const char *widgetName, const char *attributeName, int value)
{
    foreach (QWidget *widget, QApplication::allWidgets())
    {
            if(widget->objectName() == QString(widgetName))
            {
                HWidget *h = (HWidget *)widget;
                h->setAttribute(attributeName, value);
                return 1;        
            }          
    }
    return 0;
}

In set_attribute_int() function, it will search the specific QWidget by objectName(). If found, cast to HWidget, and call its setAttribute(). That is why the target widget should have a specific object name. When it calls “SnakeHole” to setAttribute(), the derived LeftWidget will be called.

Now you know all the tricks necessary for this stunt. The rest is how to compile and test.

First you will need file in https://github.com/spinos/aphid/tree/master/hoatzin

Follow the readme to build the Python module of hoatzin.

Second you need files in https://github.com/spinos/aphid/tree/master/hybrid_qtpyqt

Qmake will create the project for you. It links the compiled library of hoatzin, so no need to compile the source of HWidget again.

Just a confusing example, may be helpful.

Leave a comment

Filed under C++, Python, Qt

PyQt4 Inside Maya2011

Since the version of 2011, Maya User Interface is based on Qt. Using PyQt4 inside Maya2011 should be easier. Before version 2011, PyQt4 is hooked to Maya by pumpThread, and it is not a part of Maya UI, and will always annoyingly drop to background as soon as the Maya UI is focused.  Maya2011 can parent a QMainWIndow to Maya main window, making it a part of Maya UI. Focusing problem is gone.

Like versions before it, Maya2011 installation doesn’t include PyQt4. Install PyQt4 separately, and copy PyQt4 directory and SIP files to Maya2011/Python/Lib/site-packages/. The catch is the latest build of PyQt4 won’t work. Maya2011 is compiled against a specific version of Qt (4.6?). Those Qt dlls reside in Maya2011/bin/ won’t match PyQt4 compiled agianst newer versions of Qt, you will have DLL errors! And those dlls cannot be overridden, or Maya will fail to load. The matched version of PyQt4 should be PyQt-Py2.6-gpl-4.6. I found a copy for 64-bit application here. To test if it works, open mayapy.exe in Maya2011/bin/, and run:

from PyQt4 import QtCore

If no error appears, everything will be fine.

Revised: Maya2011 is compiled against Qt4.7 per doc. So I think any PyQt4 build not newer than 4.7 will do.

Leave a comment

Filed under Maya API, Python