Showing posts with label Python. Show all posts
Showing posts with label Python. Show all posts

Thursday, May 28, 2009

[Python & PyQt] Python Loader

Download: PyQtLoader.zip
Introduction

It's wired that Python don't have the feature that can compile python code as binary file. Thus, I plan to write a simple program as python loader generator.

The technique of this program is quite low level, I just create a "c language" based binary file to execute the target python script.

Below are the core python script for this project
#! /usr/bin/python

######################################################################
#
# Project: PyQtLoader
# Version: 1.0
# Date: Thu May 28 00:00:00 2009
# Author: Xin-Yu Lin
# E-mail: nxforce@yahoo.com
# WebSite: http://nxforce.blogspot.com
# Description: Python Code Loader
#
######################################################################

############### import modules #######################################

import os
import py_compile
import Ui_PyQtLoaderClass
from PyQt4 import QtCore, QtGui

############### PyQtLoaderClass Start ################################

class PyQtLoaderClass(QtGui.QWidget):
    def __init__(self, parent = None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_PyQtLoaderClass.Ui_PyQtLoaderClass()
        self.ui.setupUi(self)
        self.filePath = ''
        
    def onGenerateClicked(self):
        if(self.filePath == ''):
            self.onExportClicked()
        else:
            #py_compile.compile(self.filePath)
            
            splitext = os.path.splitext(self.filePath)
            srcFileName = splitext[0]+'.c'
            file = open(srcFileName, 'w')
            file.write("#include <stdio.h>\nint main(void){ system(\"python ./" + os.path.basename(self.filePath) + "\");return 0;}\n")
            file.close()
            os.system("gcc -o "+splitext[0]+" "+srcFileName)
            os.remove(srcFileName)
            
            QtGui.QMessageBox.information(self, 'Message', " Done! ", QtGui.QMessageBox.Ok)
            
    def onExportClicked(self):
        filePath = self.ui.fileDialog_export.getOpenFileName(self, 'Open File', QtCore.QDir.homePath()+'/Desktop', "python(*.py)")
        self.ui.lineEdit_path.setText(filePath)
        self.filePath = str(filePath)
        
        
############### PyQtLoaderClass End ##################################

As you can see, all coding, compiling processes can be done in runtime. After the processing completed, you will see a binary file which has the same filename with your python script.

Screenshot

The usage is very very simple, just click the left-hand side's button to load your python script, and than click the 'Generate' to create the binary loader.

#For each loader, it will takes about 60 KBs of memory.

[Python] py2exe

For most of windows users, they don't like to install several packages for only one program. In this way, programmers might distribute their software as an executable file for windows platform. In python, we can use py2exe to convert our project as win32 application.

py2exe official website

http://www.py2exe.org/


Before running py2exe, you should install .net framework in your system

Microsoft .NET Framework 3.5 Service Pack 1


Here I take "PyQtCodeGenerator" for example:
setup.py
#! /usr/bin/python

from distutils.core import setup
import py2exe

setup(windows=[{"script":"PyQtCodeGenerator.py"}], options={"py2exe":{"includes":["sip"]}})


Put the 'setup.py' under 'PyQtCodeGenerator' folder, and typing following command for converting

python setup.py install

After waiting fews seconds, you will see lots of runtime essential files inside the 'dist' folder.

So far, py2exe can only support windows platform, so please do not use it on your linux system.

Or, you can write a py2bin for lots of python programmers.

Tuesday, May 26, 2009

[Python & PyQt] PyQt Code Generator

Download: PyQtCodeGenerator.zip

Introduction

If you are a python programmer, you might like to hear the news. Today I would like to show you an awesome tool which was created by me. ''PyQt Code Generator''.
To make the GUI coding more efficient, I write a program to help programmers to generate the basic PyQt code quickly, thus programmers don't need to waste their time on such kind of routine jobs. They can devoted their time on core algorithm design.

This tool is quite simple and easy to use, just follow few steps, and you will see a basic GUI program.
  • Open the PyQt Code Generator program
  • Enter the project name
  • Choose the UI type
  • Check the modules
  • Add the comment if needed
  • Specify the export location and generate it
Below are the detailed development information for this project:
  • Project: PyQt Code Generator
  • Version 1.0
  • Python:2.6
  • PyQt: 4.4.4
  • Ubuntu 9.04/WinXP sp3
Features

1. To separate 'Main Code', 'UI Code' and 'Main Class Code' into three individual files

2. Supporting QWidget, QMainWindow and customize ui file (which be created by Qt-Designer)

3. Pre-defined Modules

4. Comment section

5. Remember last time setting

Screenshopt


Notes

Due to the source code are too large to post on the blog, so please download it if you are interesting in this project.

Any suggestions would be appreciated!!!

Sunday, May 24, 2009

[Python & PyQt] Code Formatter

Download: CodeFormatter.zip

Introduction
In order to solve the layout problem of google code prettify in blogspot, I try to write a simple but useful tool for source code formating. So far, this program is only fully support python. For other programming languages, you can still get a little benefit from this tool.

This program will replace tab or white space with fixed size tab character. Besides, the special character '<' and '>' will be replaced by html code.

Code
UI
#! /usr/bin/python

##################################################################
# Project: Python Code Formatter
# Filename: ui_codeformatter.py
# Description: User interface for source code formatting
# Date: 2009.05.24
# Programmer: Lin Xin Yu
# E-mail: nxforce@yahoo.com
# Website:http://importcode.blogspot.com
##################################################################

#================= import modules ================================

from PyQt4 import QtCore, QtGui

#================= Ui_CodeFormatterClass Start ===================

class Ui_CodeFormatterClass(object):
    def setupUi(self, CodeFormatterClass):
        CodeFormatterClass.setObjectName("CodeFormatterClass")
        CodeFormatterClass.resize(800, 630)
        
        # plain text editor
        self.textEdit_raw = QtGui.QTextEdit(CodeFormatterClass)
        self.textEdit_raw.setGeometry(QtCore.QRect(10, 10, 780, 285))
        self.textEdit_raw.setObjectName("textEdit_raw")
        self.textEdit_raw.setTabStopWidth(20)
        
        # formatted text editor
        self.textEdit_fmt = QtGui.QTextEdit(CodeFormatterClass)
        self.textEdit_fmt.setGeometry(QtCore.QRect(10, 305, 780, 285))
        self.textEdit_fmt.setObjectName("textEdit_raw")
        self.textEdit_fmt.setTabStopWidth(20)
        
        # language type
        self.comboBox_langMode = QtGui.QComboBox(CodeFormatterClass)
        self.comboBox_langMode.setGeometry(QtCore.QRect(10, 600, 120, 25))
        self.comboBox_langMode.setObjectName("comboBox_langMode")
        self.comboBox_langMode.insertItem(0, 'Python')
        self.comboBox_langMode.insertItem(1, 'Other')
        
        # Tab Width label
        self.label_tabWidth = QtGui.QLabel(CodeFormatterClass)
        self.label_tabWidth.setGeometry(QtCore.QRect(140, 600, 70, 25))
        self.label_tabWidth.setObjectName("label_tabWidt")
        
        # Tab Width lineEdit
        self.lineEdit_tabWidth = QtGui.QLineEdit(CodeFormatterClass)
        self.lineEdit_tabWidth.setGeometry(QtCore.QRect(210, 600, 30, 25))
        self.lineEdit_tabWidth.setObjectName("lineEdit_tabWidth")
        self.lineEdit_tabWidth.setText('4')
        
        # 'Convert' button
        self.pushButton_convert = QtGui.QPushButton(CodeFormatterClass)
        self.pushButton_convert.setGeometry(QtCore.QRect(250, 600, 90, 25))
        self.pushButton_convert.setObjectName("pushButton_convert")
        
        # 'clear all' button
        self.pushButton_clear = QtGui.QPushButton(CodeFormatterClass)
        self.pushButton_clear.setGeometry(QtCore.QRect(350, 600, 90, 25))
        self.pushButton_clear.setObjectName("pushButton_clear")
        
        # 'Open' button
        self.pushButton_open = QtGui.QPushButton(CodeFormatterClass)
        self.pushButton_open.setGeometry(QtCore.QRect(450, 600, 90, 25))
        self.pushButton_open.setObjectName("pushButton_open")
        
        # 'SaveAs' button
        self.pushButton_saveAs = QtGui.QPushButton(CodeFormatterClass)
        self.pushButton_saveAs.setGeometry(QtCore.QRect(550, 600, 90, 25))
        self.pushButton_saveAs.setObjectName("pushButton_saveAs")
        
        # 'Copy to clipboard' button
        self.pushButton_clipboard = QtGui.QPushButton(CodeFormatterClass)
        self.pushButton_clipboard.setGeometry(QtCore.QRect(650, 600, 140, 25))
        self.pushButton_clipboard.setObjectName("pushButton_clipboard")
        
        # Open fileDialog
        self.fileDialog_open = QtGui.QFileDialog(CodeFormatterClass)
        
        # SaveAs fileDialog
        self.fileDialog_saveAs = QtGui.QFileDialog(CodeFormatterClass)
        
        self.retranslateUi(CodeFormatterClass)
        QtCore.QObject.connect(self.pushButton_convert, QtCore.SIGNAL("clicked()"), CodeFormatterClass.onConvertClicked)
        QtCore.QObject.connect(self.pushButton_clear, QtCore.SIGNAL("clicked()"), CodeFormatterClass.onClearAllClicked)
        QtCore.QObject.connect(self.pushButton_open,QtCore.SIGNAL("clicked()"),CodeFormatterClass.onOpenClicked)
        QtCore.QObject.connect(self.pushButton_saveAs, QtCore.SIGNAL("clicked()"), CodeFormatterClass.onSaveAsClicked)
        QtCore.QObject.connect(self.pushButton_clipboard, QtCore.SIGNAL("clicked()"), CodeFormatterClass.onCpClipboardClicked)
        QtCore.QObject.connect(self.lineEdit_tabWidth,QtCore.SIGNAL("returnPressed()"),CodeFormatterClass.onTabWidthSeted)
        QtCore.QMetaObject.connectSlotsByName(CodeFormatterClass)
        
    def retranslateUi(self, CodeFormatterClass):
        CodeFormatterClass.setWindowTitle(QtGui.QApplication.translate("CodeFormatterClass", "Code Formatter", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButton_convert.setText(QtGui.QApplication.translate("CodeFormatterClass", "Convert", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButton_clipboard.setText(QtGui.QApplication.translate("CodeFormatterClass", "Copy to Clipboard", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButton_saveAs.setText(QtGui.QApplication.translate("CodeFormatterClass", "Save As...", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButton_clear.setText(QtGui.QApplication.translate("CodeFormatterClass", "Clear All", None, QtGui.QApplication.UnicodeUTF8))
        self.label_tabWidth.setText(QtGui.QApplication.translate("CodeFormatterClass", "Tab width:", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButton_open.setText(QtGui.QApplication.translate("CodeFormatterClass", "Open...", None, QtGui.QApplication.UnicodeUTF8))
        
#================= Ui_CodeFormatterClass Start ===================

Main Program
#! /usr/bin/python

################################################################
# Project: Python Code Formatter
# Filename: CodeFormatter.py
# Description: An useful tool for source code formatting
# Date: 2009.05.24
# Programmer: Lin Xin Yu
# E-mail: nxforce@yahoo.com
# Website:http://importcode.blogspot.com
################################################################

#================= import modules ==============================
import re
import sys
import ui_codeformatter
from PyQt4 import QtCore, QtGui

#================= CodeFormatter Class Start ===================

class CodeFormatter(QtGui.QMainWindow):
    def __init__(self, parent = None):
        QtGui.QMainWindow.__init__(self, parent)
        self.ui = ui_codeformatter.Ui_CodeFormatterClass()
        self.ui.setupUi(self)
        
        self.ui.textEdit_fmt.setEnabled(False)
        
        # default tab width is 4 for all language
        self.tabWidth = 4
        
        # init raw text
        self.rawText = ''
        
        # init formated text
        self.fmtText = ''
        
    # other code phrasing
    def otherCodePhrasing(self):
        # add the start css tag of google code prettify
        self.fmtText = '<code class="prettyprint">'
        
        for line in self.rawText:
            self.fmtText += line.replace('<', '&lt;').replace('>','&gt;') + '\n'
            
        # add the end css tag of google code prettify
        self.fmtText += '</code>'
        
        self.ui.textEdit_fmt.setPlainText(self.fmtText)
        
    # python source code phrasing
    def pythonCodePhrasing(self):
        numOfTabs = 0
        numOfSpaces = 0
        
        # list for recording the white spaces
        list = [0]
        
        # add the start css tag of google code prettify
        self.fmtText = '<code class="prettyprint">'
        
        for line in self.rawText:
            numOfChrs = 0
            nSpaces = 0
            
            matchAnySpace = re.match('[\s]+', line)
            if(matchAnySpace):
                nSpaces = matchAnySpace.group().count('\t') * self.tabWidth
                nSpaces += matchAnySpace.group().count(' ')
                numOfChrs += len(matchAnySpace.group())
                
            tmpLine = line[numOfChrs:].replace('<', '&lt;').replace('>','&gt;')
            
            # if this line is newline only
            if(tmpLine == ''):
                self.fmtText += ' ' * (numOfTabs * self.tabWidth) + '\n'
                continue
                
            ### reserved function for worst case ###
            # if this line is commecnt
            #matchComment = re.match('^#', tmpLine)
            #if(matchComment):
            # self.fmtText += ' ' * (numOfTabs * self.tabWidth) + tmpLine + '\n'
            # continue
            
            # update tab character count by verifying the white spaces
            if(nSpaces > numOfSpaces):
                list.append(nSpaces)
                numOfTabs += 1
            elif(nSpaces < numOfSpaces):
                while list[len(list)-1] != nSpaces:
                    list.pop()
                    numOfTabs -= 1
                    
            numOfSpaces = nSpaces
            
            # when the line is a new class or function, reset all counts
            if(numOfChrs == 0):
                numOfSpaces = numOfTabs = 0
                
            self.fmtText += ' ' * (numOfTabs * self.tabWidth) + tmpLine + '\n'
            
        # add the end css tag of google code prettify
        self.fmtText += '</code>'
        
        self.ui.textEdit_fmt.setPlainText(self.fmtText)
        
    # SLOT for convert button
    def onConvertClicked(self):
        self.ui.textEdit_fmt.setEnabled(True)
        self.rawText = str(self.ui.textEdit_raw.toPlainText()).split('\n')
        
        if(self.ui.comboBox_langMode.currentIndex() == 0):
            self.pythonCodePhrasing()
            return True
            
        if(self.ui.comboBox_langMode.currentIndex() == 1):
            self.otherCodePhrasing()
            return True
            
    def onClearAllClicked(self):
        self.ui.textEdit_raw.setText('')
        self.ui.textEdit_fmt.setText('')
        self.ui.textEdit_raw.setFocus()
        
    def onCpClipboardClicked(self):
        self.ui.textEdit_fmt.selectAll()
        self.ui.textEdit_fmt.copy()
        mimeData = QtGui.QApplication.clipboard().mimeData();
        
    def onOpenClicked(self):
        filename = self.ui.fileDialog_open.getOpenFileName(self, 'Open file', QtCore.QDir.homePath()+'/Desktop')
        if(filename):
            fileIn = open(filename, 'r')
            rawText = fileIn.read()
            fileIn.close()
            self.ui.textEdit_raw.setPlainText(rawText)
            
    def onSaveAsClicked(self):
        filename = self.ui.fileDialog_saveAs.getSaveFileName(self, 'Save file', QtCore.QDir.homePath()+'/Desktop')
        if(filename):
            fileOut = open(filename, 'w')
            fileOut.write(self.fmtText)
            fileOut.close()
            
    def onTabWidthSeted(self):
        self.tabWidth = int(self.ui.lineEdit_tabWidth.text())
        
        
#================= CodeFormatter Class End ===================

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    codeFormatter = CodeFormatter()
    codeFormatter.show()
    sys.exit(app.exec_())

Screenshot

Please make sure the tab width is correct before converting.

Thursday, May 21, 2009

[Python & PyQt] Ftp Client

Download:FtpClient.zip

Introduction

Recently, I'm looking for the suitable script language for GUI design. It seems Python will be the first candidate among those competitive programming languages(ex. Perl, Tcl, Awk...). Here I would like to show you a GUI-based ftp client with the combination of Python and PyQt

Project - Ftp Client

Language: Python 2.6.2
GUI: PyQt 4.4.4
OS: Ubuntu 8.04
Modules: ftplib

Pre-works

Even though this project didn't involved any difficult algorithm or complicated techniques, the program still needs lots of package for running. If you are really interest in this program, please install follow packages.

It's not too difficult to install those packages on your system. But there is an important thing I want to remind you. Don't forget to add the PyQt modules's path into your python. Below is a simple way to add the system path to your python. (For example, my PyQt modules' location is '/usr/local/lib/python2.6/site-package')

import sys
sys.path.append('/usr/local/lib/python2.6/site-package')

Maybe someone can help us to write a GUI-based environment path manager.

Coding

I split the whole source code into three parts, UiFtpCli, FileTransfer and FtpClient.

UiFtpCli
#! /usr/local/bin/python

###############################################################
# Project: Python Ftp Client
# Filename: UiFtpCli.py
# Description: The Qt-based GUI for ftp client
# Date: 2009.05.21
# Programmer: Lin Xin Yu
# E-mail: nxforce@yahoo.com
# Website: http://importcode.blogspot.com
###############################################################

#================= import modules =============================
import os
from PyQt4 import QtCore, QtGui

#================= Ui_FtpClientClass Class Begin ==============
class Ui_FtpClientClass(object):
def setupUi(self, FtpClientClass):
# MainWindow Widget
FtpClientClass.setObjectName("FtpClientClass")
FtpClientClass.resize(QtCore.QSize(QtCore.QRect(0,0,800,500).size()).expandedTo(FtpClientClass.minimumSizeHint()))
self.moveToCenter(FtpClientClass)

# Centeral Widget for containing all widgets except for menubar and statusbar
self.centralwidget = QtGui.QWidget(FtpClientClass)
self.centralwidget.setObjectName("centralwidget")

# Ftp Host label
self.label_address = QtGui.QLabel(self.centralwidget)
self.label_address.setGeometry(QtCore.QRect(10,10,70,25))
self.label_address.setObjectName("label_address")

# Ftp Host input
self.lineEdit_address = QtGui.QLineEdit(self.centralwidget)
self.lineEdit_address.setGeometry(QtCore.QRect(80,10,510,25))
self.lineEdit_address.setObjectName("lineEdit_address")

# Port Label
self.label_port = QtGui.QLabel(self.centralwidget)
self.label_port.setGeometry(QtCore.QRect(600,10,30,25))
self.label_port.setObjectName("label_port")

# Port input
self.lineEdit_port = QtGui.QLineEdit(self.centralwidget)
self.lineEdit_port.setGeometry(QtCore.QRect(640,10,50,25))
self.lineEdit_port.setObjectName("lineEdit_port")

# Ftp tranfer mode
self.transferMode = QtGui.QComboBox(self.centralwidget)
self.transferMode.setGeometry(QtCore.QRect(700,10,90,25))
self.transferMode.insertItem(0, 'Passive')
self.transferMode.insertItem(1, 'Active')

# Username label
self.label_username = QtGui.QLabel(self.centralwidget)
self.label_username.setGeometry(QtCore.QRect(10,40,70,25))
self.label_username.setObjectName("label_username")

# Username input
self.lineEdit_username = QtGui.QLineEdit(self.centralwidget)
self.lineEdit_username.setGeometry(QtCore.QRect(80,40,270,25))
self.lineEdit_username.setObjectName("lineEdit_username")

# Password label
self.label_password = QtGui.QLabel(self.centralwidget)
self.label_password.setGeometry(QtCore.QRect(360,40,70,25))
self.label_password.setObjectName("label_password")

# Password input
self.lineEdit_password = QtGui.QLineEdit(self.centralwidget)
self.lineEdit_password.setGeometry(QtCore.QRect(430,40,260,25))
self.lineEdit_password.setObjectName("lineEdit_password")
self.lineEdit_password.setEchoMode(QtGui.QLineEdit.Password)

# Connect/Disconnect button
self.pushButton_connect = QtGui.QPushButton(self.centralwidget)
self.pushButton_connect.setGeometry(QtCore.QRect(700,40,90,25))
self.pushButton_connect.setObjectName("pushButton_connect")

# TreeWidget for local file system
self.sysTree = QtGui.QTreeWidget(self.centralwidget)
self.sysTree.setGeometry(QtCore.QRect(400,75,390,400))
self.sysTree.setHeaderLabels(QtCore.QStringList(['Name', 'Size', 'Owner', 'Group','Path']));
self.sysTree.setObjectName("sysTree")
self.sysTree.setEnabled(False)
self.sysTree.setRootIsDecorated(False)
self.sysTree.header().setStretchLastSection(False)

# TreeWidget for remote file system
self.ftpTree = QtGui.QTreeWidget(self.centralwidget)
self.ftpTree.setGeometry(QtCore.QRect(10,75,390,400))
self.ftpTree.setObjectName("ftpTree")
self.ftpTree.setEnabled(False)
self.ftpTree.setRootIsDecorated(False)
self.ftpTree.setHeaderLabels(QtCore.QStringList(['Name', 'Size', 'Owner', 'Group', 'Premission']));
self.ftpTree.header().setStretchLastSection(False)

# Predefined icons
self.folderIconBlue = QtGui.QIcon("icon/folder1.png")
self.fileIconBlue = QtGui.QIcon("icon/file1.png")
self.folderIconGreen = QtGui.QIcon("icon/folder2.png")
self.fileIconGreen = QtGui.QIcon("icon/file2.png")

# Download/Upload PorgressBar
self.progressBar = QtGui.QProgressDialog(self.centralwidget)
self.progressBar.setGeometry(QtCore.QRect(200,200,200,50))
self.progressBar.setObjectName("progressBar")
self.progressBar.setMaximum(100)
self.progressBar.setMinimum(0)
self.moveToCenter(self.progressBar)

# MessageBox for welcome message
self.msgBox = QtGui.QMessageBox(self.centralwidget)
self.msgBox.setGeometry(QtCore.QRect(200,200,400,300))
self.msgBox.setObjectName("msgBox")
self.msgBox.setStandardButtons(QtGui.QMessageBox.Ok)
self.moveToCenter(self.msgBox)

# MessageBox for About
self.aboutMsg = QtGui.QMessageBox(self.centralwidget)
self.aboutMsg.setGeometry(QtCore.QRect(200,200,400,300))
self.aboutMsg.setObjectName("aboutMsg")
self.aboutMsg.setWindowTitle("Ftp Client 1.0")
self.aboutMsg.setStandardButtons(QtGui.QMessageBox.Ok)
self.aboutMsg.setInformativeText(QtGui.QApplication.translate("FtpClientClass", "Ftp Client 1.0\nAuthor: Lin Xin Yu\nE-mail:nxforce.yahoo.com\nBlog:http://importcode.blogspot.com", None, QtGui.QApplication.UnicodeUTF8))
self.moveToCenter(self.aboutMsg)

FtpClientClass.setCentralWidget(self.centralwidget)

# Menubar & actions
self.menubar = QtGui.QMenuBar(FtpClientClass)
self.menubar.setGeometry(QtCore.QRect(0, 0, 600, 22))
self.menubar.setObjectName("menubar")
self.menuFile = QtGui.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
self.menuHelp = QtGui.QMenu(self.menubar)
self.menuHelp.setObjectName("menuHelp")
FtpClientClass.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(FtpClientClass)
self.statusbar.setObjectName("statusbar")
self.statusbar.showMessage('Disconnect')
FtpClientClass.setStatusBar(self.statusbar)
self.actionConnect = QtGui.QAction(FtpClientClass)
self.actionConnect.setObjectName("actionConnect")
self.actionDisconnect = QtGui.QAction(FtpClientClass)
self.actionDisconnect.setObjectName("actionDisconnect")
self.actionQuit = QtGui.QAction(FtpClientClass)
self.actionQuit.setObjectName("actionQuit")
self.actionAbout = QtGui.QAction(FtpClientClass)
self.actionAbout.setObjectName("actionAbout")
self.menuFile.addAction(self.actionConnect)
self.menuFile.addAction(self.actionDisconnect)
self.menuFile.addSeparator()
self.menuFile.addAction(self.actionQuit)
self.menuHelp.addAction(self.actionAbout)
self.menubar.addAction(self.menuFile.menuAction())
self.menubar.addAction(self.menuHelp.menuAction())

self.retranslateUi(FtpClientClass)

# Signal & Slot
QtCore.QObject.connect(self.lineEdit_address,QtCore.SIGNAL("returnPressed()"),FtpClientClass.onSetAddress)
QtCore.QObject.connect(self.lineEdit_username,QtCore.SIGNAL("returnPressed()"),FtpClientClass.onSetUsername)
QtCore.QObject.connect(self.lineEdit_password,QtCore.SIGNAL("returnPressed()"),FtpClientClass.onSetPassword)
QtCore.QObject.connect(self.lineEdit_port,QtCore.SIGNAL("returnPressed()"),FtpClientClass.onSetPort)
QtCore.QObject.connect(self.pushButton_connect,QtCore.SIGNAL("clicked()"),FtpClientClass.onConnect)
QtCore.QObject.connect(self.sysTree,QtCore.SIGNAL("itemDoubleClicked(QTreeWidgetItem*,int)"),FtpClientClass.onSysItemDoubleClicked)
QtCore.QObject.connect(self.ftpTree,QtCore.SIGNAL("itemDoubleClicked(QTreeWidgetItem*,int)"),FtpClientClass.onFtpItemDoubleClicked)
QtCore.QObject.connect(self.transferMode, QtCore.SIGNAL("currentIndexChanged(int)"), FtpClientClass.onTransferModeChanged)
QtCore.QObject.connect(self.actionConnect, QtCore.SIGNAL('triggered(bool)'), FtpClientClass.onConnect)
QtCore.QObject.connect(self.actionDisconnect, QtCore.SIGNAL('triggered(bool)'), FtpClientClass.onConnect)
QtCore.QObject.connect(self.actionQuit, QtCore.SIGNAL('triggered(bool)'), FtpClientClass.close)
QtCore.QObject.connect(self.actionAbout, QtCore.SIGNAL('triggered(bool)'), FtpClientClass.onAboutTriggered)
QtCore.QMetaObject.connectSlotsByName(FtpClientClass)

# Text Translation for international format - UTF8
def retranslateUi(self, FtpClientClass):
FtpClientClass.setWindowTitle(QtGui.QApplication.translate("FtpClientClass", "Ftp Client", None, QtGui.QApplication.UnicodeUTF8))
self.label_address.setText(QtGui.QApplication.translate("FtpClientClass", "Ftp Host:", None, QtGui.QApplication.UnicodeUTF8))
self.label_port.setText(QtGui.QApplication.translate("FtpClientClass", "Port:", None, QtGui.QApplication.UnicodeUTF8))
self.lineEdit_port.setText(QtGui.QApplication.translate("FtpClientClass", "21", None, QtGui.QApplication.UnicodeUTF8))
self.label_username.setText(QtGui.QApplication.translate("FtpClientClass", "Username:", None, QtGui.QApplication.UnicodeUTF8))
self.label_password.setText(QtGui.QApplication.translate("FtpClientClass", "Password:", None, QtGui.QApplication.UnicodeUTF8))
self.pushButton_connect.setText(QtGui.QApplication.translate("FtpClientClass", "Connect", None, QtGui.QApplication.UnicodeUTF8))
self.progressBar.setWindowTitle(QtGui.QApplication.translate("FtpClientClass", "File Transfer", None, QtGui.QApplication.UnicodeUTF8))
self.menuFile.setTitle(QtGui.QApplication.translate("FtpClientClass", "File", None, QtGui.QApplication.UnicodeUTF8))
self.menuHelp.setTitle(QtGui.QApplication.translate("FtpClientClass", "Help", None, QtGui.QApplication.UnicodeUTF8))
self.actionConnect.setText(QtGui.QApplication.translate("FtpClientClass", "Connect", None, QtGui.QApplication.UnicodeUTF8))
self.actionDisconnect.setText(QtGui.QApplication.translate("FtpClientClass", "Disconnect", None, QtGui.QApplication.UnicodeUTF8))
self.actionQuit.setText(QtGui.QApplication.translate("FtpClientClass", "Quit", None, QtGui.QApplication.UnicodeUTF8))
self.actionAbout.setText(QtGui.QApplication.translate("FtpClientClass", "About", None, QtGui.QApplication.UnicodeUTF8))

# widget alignment
def moveToCenter(self, widget):
screen = QtGui.QDesktopWidget().screenGeometry()
size = widget.geometry()
widget.move((screen.width()-size.width())/2, (screen.height()-size.height())/2)

#================= Ui_FtpClientClass Class End ================

As you can see, everything just like C++, because I follow the original Qt style. Thus, it will be much easier to handle the source code.

FileTransfer
#! /usr/local/bin/python

###############################################################
# Project: Python Ftp Client
# Filename: FileTransfer.py
# Description: A TransferProgress class for displaing download
# or upload progress.
# Date: 2009.05.21
# Programmer: Lin Xin Yu
# E-mail: nxforce@yahoo.com
# Website:http://importcode.blogspot.com
###############################################################

#================= TransferProgress Class Start ===============

class TransferProgress:
def __init__(self, pBar, filename, filesize, msg, file=None):

# file descriptor will be used while downloding
self.file = file

# cause the value of TreeWidgetItem are all string, so typecast it
self.totalSize = int(filesize)
self.recvSize = 0

# QProgressBar
self.pBar = pBar
self.pBar.setWindowTitle(msg+filename)
self.pBar.show()

def uploadProgress(self, data):
self.recvSize += len(data)
self.pBar.setValue(self.recvSize*100 /self.totalSize)

def downloadProgress(self, data):
self.recvSize += len(data)
self.file.write(data)
self.pBar.setValue(self.recvSize*100 /self.totalSize)

#================= TransferProgress Class End =================

Displaying the downloading/uploading progress will be the most difficult part in this project. In order to get the filesize and received size, we need to create some callback functions for storbinary() and retrbinary(). uploadProgress() is the callback function for storbinary(). downloadProgress() is the callback function for retrbinary(). So, here I put all essential variables and functions into TransferProgress object.

FtpClient
#! /usr/local/bin/python

###############################################################
# Project: Python Ftp Client
# Filename: FtpClient.py
# Description: A very simple ftp client via PyQt
# Date: 2009.05.21
# Programmer: Lin Xin Yu
# E-mail: nxforce@yahoo.com
# Website:http://importcode.blogspot.com
###############################################################

#================= import modules =============================
import os
import sys
import ftplib
import UiFtpCli
import FileTransfer
from PyQt4 import QtCore, QtGui, QtNetwork

#================= FtpClient Class Start ======================

class FtpClient(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self, parent)
self.ui = UiFtpCli.Ui_FtpClientClass()
self.ui.setupUi(self)

self.username = None
self.password = None
self.address = None
self.port = 21
self.ftp = None
self.passiveMode = True

# record current root location for local filelist
# default path is your 'Dekstop'
self.sysRootPath = QtCore.QDir.homePath()+"/Desktop"

# Update treewdiget for local filelist
self.updateSysFileList()

#=== SLOT for ftp host address input ===
def onSetAddress(self):
self.address = str(self.ui.lineEdit_address.text())

#=== SLOT for username input ===
def onSetUsername(self):
self.username = str(self.ui.lineEdit_username.text())

#=== SLOT for password input ===
def onSetPassword(self):
self.password = str(self.ui.lineEdit_password.text())

#=== SLOT for password input ===
def onSetPort(self):
self.port = str(self.ui.lineEdit_port.text())

#=== SLOT for connect/disconnect button ===
def onConnect(self):
if(self.ftp == None):
self.connectToHost()
else:
self.disconnectFromHost()

#=== connect ===
def connectToHost(self):
self.ui.lineEdit_address.emit(QtCore.SIGNAL("returnPressed()"), None)
self.ui.lineEdit_username.emit(QtCore.SIGNAL("returnPressed()"), None)
self.ui.lineEdit_password.emit(QtCore.SIGNAL("returnPressed()"), None)
self.ui.lineEdit_port.emit(QtCore.SIGNAL("returnPressed()"), None)

# user should at least enter the ftp host
if(self.address == ''):
self.ui.statusbar.showMessage('Please enter ftp host address!')
self.ui.lineEdit_address.setFocus()
return False

# username & password are not required for anonymous server

#if(self.username == ''):
# self.ui.statusbar.showMessage('Please enter username!')
# self.ui.lineEdit_username.setFocus()
# return False

#if(self.password == ''):
# self.ui.statusbar.showMessage('Please enter password!')
# self.ui.lineEdit_password.setFocus()
# return False

# Connect to ftp host
self.ftp = ftplib.FTP(self.address)

# set tranfer mode
self.ftp.set_pasv(self.passiveMode)

# login
self.ftp.login(self.username, self.password)

# Show welcome message
self.ui.msgBox.setWindowTitle(self.address)
self.ui.msgBox.setInformativeText(QtGui.QApplication.translate("FtpClientClass", self.ftp.getwelcome(), None, QtGui.QApplication.UnicodeUTF8))
self.ui.msgBox.show()

self.ui.statusbar.showMessage('Connect to '+self.address+' ...')

# update remote filelist
self.updateFtpFileList()

self.ui.sysTree.setEnabled(True)
self.ui.ftpTree.setEnabled(True)

self.ui.transferMode.setEnabled(False)
self.ui.lineEdit_address.setEnabled(False)
self.ui.lineEdit_port.setEnabled(False)
self.ui.lineEdit_username.setEnabled(False)
self.ui.lineEdit_password.setEnabled(False)
self.ui.pushButton_connect.setText('Disconnect')

return True

#=== disconnect ===
def disconnectFromHost(self):
# close ftp
self.ftp.close()

# empty object
self.ftp = None


self.ui.sysTree.setEnabled(False)
self.ui.ftpTree.setEnabled(False)

self.ui.transferMode.setEnabled(True)
self.ui.lineEdit_address.setEnabled(True)
self.ui.lineEdit_port.setEnabled(True)
self.ui.lineEdit_username.setEnabled(True)
self.ui.lineEdit_password.setEnabled(True)
self.ui.pushButton_connect.setText('Connect')
self.ui.statusbar.showMessage('Disconnected from '+self.address+' ...')

#=== upload ===
def upload(self, filename, fullname):
# open file for reading
fileout = open(fullname, "rb")

# get filesize
statinfo = os.stat(fullname)
filesize = statinfo.st_size

# create a FileTransfer object for displaying upload progress
tp = FileTransfer.TransferProgress(self.ui.progressBar, filename, filesize, 'Upload: ')

# send data to server
self.ftp.storbinary("STOR " + filename, fileout, 1024, tp.uploadProgress)

# close file
fileout.close()

#=== download ===
def download(self, filename, filesize):
# open file for writing
filein = open(self.sysRootPath+'/'+filename, "wb")

# create a FileTransfer object for displaying download progress
tp = FileTransfer.TransferProgress(self.ui.progressBar, filename, filesize, 'Download: ', filein)

# get data from server
self.ftp.retrbinary("RETR " + filename, tp.downloadProgress, 1024)

# close file
filein.close()


#=== Update treewidget for remote filelist ===
def updateFtpFileList(self):
# clear treewidget
self.ui.ftpTree.clear()

# get filelist from server
data = []
self.ftp.dir(data.append)

# re-format the structure and send into ftpTree
for line in data:
spline = line.split()
item = QtGui.QTreeWidgetItem()
item.setText(0, spline[8])
item.setText(1, spline[4])
item.setText(2, spline[2])
item.setText(3, spline[3])
item.setText(4, spline[0])

if(spline[0][0] == 'd'):
item.setIcon(0, self.ui.folderIconBlue)
else:
item.setIcon(0, self.ui.fileIconBlue)

self.ui.ftpTree.addTopLevelItem(item)


#=== Update treewidget for local filelist ===
def updateSysFileList(self):
# clear treewidget
self.ui.sysTree.clear()

# get local directory path
sysDir = QtCore.QDir(self.sysRootPath)
sysDir.setFilter(QtCore.QDir.Files | QtCore.QDir.Dirs | QtCore.QDir.NoSymLinks)
sysDir.setSorting(QtCore.QDir.DirsFirst | QtCore.QDir.Name)

# retrive the file info and pack into sysTree
fileList = sysDir.entryInfoList();
for i in range(0,len(fileList)):
fileInfo = fileList[i]
item = QtGui.QTreeWidgetItem()
item.setText(0, fileInfo.fileName())
item.setText(1, QtCore.QString.number(fileInfo.size()/1024, 10)+' KB')
item.setText(2, fileInfo.owner())
item.setText(3, fileInfo.group())
item.setText(4, fileInfo.filePath())

if(fileInfo.isDir()):
item.setIcon(0, self.ui.folderIconGreen)
else:
item.setIcon(0, self.ui.fileIconGreen)

self.ui.sysTree.addTopLevelItem(item)

#=== SLOT for ftpTree ===
def onFtpItemDoubleClicked(self, item):
permission = str(item.text(4))
if(permission[0] == 'd'):
self.ftp.cwd(str(item.text(0)))
self.updateFtpFileList()
else:
self.download(str(item.text(0)), str(item.text(1)))

#=== SLOT for sysTree ===
def onSysItemDoubleClicked(self, item):
path = str(item.text(4))
if(QtCore.QFileInfo(path).isDir()):
self.sysRootPath = path
self.updateSysFileList()
else:
self.upload(str(item.text(0)) ,path)

#=== SLOT for transfer mode combobox ===
def onTransferModeChanged(self, index):
if(index == 0):
self.passiveMode = True
else:
self.passiveMode = False

#=== SLOT for menubar's actions ===
def onAboutTriggered(self):
self.ui.aboutMsg.show()

#=== SLOT for close window ===
def closeEvent(self, event):
if(self.ftp != None):
self.ftp.close()

#================= FtpClient Class End ======================

if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
ftpClient = FtpClient()
ftpClient.show()
sys.exit(app.exec_())

I spend almost over 90 percent coding time on graphic user interface design, only 10 percent is core algorithm. So if you don't really understand the detailed concept of the source code. Don't worry about it, practice makes perfect.

Demo


Conclusion
I didn't implement too many function for this program, so ... maybe it's your turn.
  • If you are C++ & Qt expertise, don't try to switch to PyQt if no necessary.
  • There are too many Qt classes that overlap with python classes. Before using Qt class, please make sure the implementation is stable and completed
  • Interpreted language is much faster than compiled language while compiling.
  • For small-scale, non-commercial, client oriented software, python is still good for programmers.

Sunday, May 10, 2009

[Python] Python Socket Tutorial

Introduction:
This is my first socket program in python.

server.py
#! /usr/bin/python
################################################################################
# Name:Python Server Socket
# Description: A simple implementation for chat one to one in python socket.
# Date: 2009/5/10
# Programmer: Hsiang Hsien Hsiang
# Website:http://importcode.blogspot.com
###############################################################################

import socket
import threading

class serverThread(threading.Thread):
def __init__(self, connection, address):
self.connection = connection
self.address = address
self.onConnect = True
threading.Thread.__init__(self)
def run(self):
while self.onConnect:
recvData = self.connection.recv(1024)
if recvData != ":exit" and recvData != '':
print 'Client:' + recvData
else:
break
self.connection.close()
print "Connection Close"
def close(self):
self.onConnect = False

class server:
def __init__(self):
self.host = 'localhost' #host = 127.0.0.1
self.port = 8001 #port = 8001
self.onConnect = True
self.serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.serverSocket.bind((self.host, self.port))
self.serverSocket.listen(5)
self.connection, self.address = self.serverSocket.accept()
def serverRun(self):
print "Enter :exit to disconnect"
print 'Connected by', self.address
thread = serverThread(self.connection, self.address)
thread.start()
while 1:
sendData = raw_input()
try:
self.connection.send(sendData)
except socket.error:
print "No Body Online, Offline Now"
break
if sendData == ":exit":
thread.close()
break

if __name__ == '__main__':
server().serverRun()

client.py

#! /usr/bin/python
#############################################################################################
# Name:Python Client Socket
# Description: A simple implementation for chat one to one in python socket.
# Date: 2009/5/10
# Programmer: Hsiang Hsien Hsiang
# Website:http://importcode.blogspot.com
############################################################################################

import socket
import threading

class clientThread(threading.Thread):
def __init__(self, connection, address, client):
self.connection = connection
self.address = address
self.onConnect = True
self.client = client
threading.Thread.__init__(self)
def run(self):
while self.onConnect:
recvData = self.connection.recv(1024)
if recvData != ":exit" and recvData != '':
print 'Server:' + recvData
else:
print recvData
self.onConnect = False
self.client.close()
self.connection.close()
def close(self):
self.onConnect = False

class client:
def __init__(self):
self.onConnect = True
self.host = 'localhost' #host = 127.0.0.1
self.port = 8001 #port = 8001
self.clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.clientSocket.connect((self.host, 8001))
self.address = (self.host, 8001)
def clientRun(self):
print "Enter :exit to disconnect"
print 'Link to', self.address
thread = clientThread(self.clientSocket, self.address, self)
thread.start()
while self.onConnect:
sendData = raw_input()
try:
self.clientSocket.send(sendData)
except socket.error:
print "Server Offline, Disconnect Now"
break
if sendData == ':exit':
thread.close()
break
def close(self):
self.onConnect = False

if __name__ == '__main__':
client().clientRun()

Note:
There are many bug in this program.
Maybe you can improve it.



Monday, May 4, 2009

[Python] Typical Triangle

Coding:

File name "triangleTest.py"
x = int (raw_input("Enter the edge of triangle: "))
edge = x + 1
i = '*'
for y in range(1,edge):
print (i * y).ljust(x), (i * (edge-y)).ljust(x)

print

for y in range(1,edge):
print (i * y).rjust(x), (i * (edge-y)).rjust(x)

Run:


Method 1

Typing "python " in your console to start python and then you can typing your code follow.


Method 2

Type "python triangleTest.py" will help you get the job done more quickly.


Result:

Wow, is this "cpu fan" ?
Have fun!!


[Eclipse] Integrated with Pydev

Introduction

Truth be told, I have never used eclipse for python. but it would be great to integrate all popular programming languages into one IDE.

Installation

Pydev is a plugin that enables users to use Eclipse for Python and Jython development. It distributed under the EPL license.

Before getting started, please make sure you have following software installed in your system:
Just follow few steps, and you will never need to compile your python program in terminal.
  • Start your eclipse
  • Click "Help" -> "Software Updates"
  • In "Available Software" section, press "Add Site" button
  • add the url "http://pydev.sourceforge.net/updates/" and click "OK"
  • Check and install the Pydev
Configuration

After the installation, you probably need to given a path of python interpreter in eclipse's "Preference".
  • in eclipse, click "Window" -> "Preference"
  • expend the "Pydev", click "Interpreter - Python"
  • in "Python interpreter" section, click "New" button
  • setup a location of the python interpreter.
For example, my python interpreter is located at "/usr/bin/python".


Create a python project
  • in eclipse, click "File" -> "New" -> "Other"
  • expand the "Pydev", click "Pydev Project"
  • given a project name and click "Finish"
Create a python module
  • in eclipse's Package Explorer, click your python project's "src"
  • click "File" -> "New" -> "Other"
  • expand the "Pydev", click "Pydev Module"
  • click "Next" to continue
  • given a module name and leave the template <Empty>
  • click "Finish"
Coding

Below is a very trivial example to output an inverse triangular shape.

# An ugly recursive method
def star(start, end ,step, pat, pre):
if(start < end): star(start + step, end, step, pat, pre + pat)
print pre.center(end * len(pat))

height = int(raw_input("Please enter a height:"))
star(1, height, 1, "* ", "* ")

Compile and Run

Just press the "Run As" and choose the "Python Run", you will see a BEAUTIFUL pattern.

* * * * *
* * * *
* * *
* *
*

(Your output might different with mine. If you are really confused about it. You must be a ...... idiot!)

Conclusion

For the newer, Pydev could be your first choice for python programming.