快捷搜索:  汽车  科技

python嵌入式开发学习流程(Python实用案例编程入门)

python嵌入式开发学习流程(Python实用案例编程入门)from PyQt5.uic import loadUi logui = resource_path(os.path.join("res" "bookingtestline.ui")) loadUi(logui self)上面代码片段就是我们的程序用于加载界面文件的代码,可以看出是完全加载了一个ui文件,使界面和程序代码完全分离,互不影响,更多详细信息可以参考下面的链接。PyQt5模块将是我们创建程序GUI界面使用的库,通过名字我们可以猜出其是QT的Python版本。它将QT和Python融合在了一起,很完美的为熟悉QT的开发者提供了Python版本的GUI。并且我们可以通过QT designer工具进行界面的设计,只需要拖拽相应的组件即可,界面的设计可以与代码功能实现完全分离。也就意味着,即使修改了界面文件,程序功能无需进行改变的情况下,不需要重新编译或

20.3.12 winshell模块

winshell模块是一个能够支持在Python中执行windows shell脚本的库。能够很方便的访问特定目录,使用shell的文件复制,重命名和删除功能。我们的程序里会进行创建程序桌面快捷方式的操作,将使用winshell获取桌面文件夹的路径。

import winshell desktop = winshell.desktop() path = os.path.join(desktop os.path.splitext(os.path.basename(abs_path))[0] '.lnk') #列出所有回收站里的文件 all_deleted_files = list(winshell.recycle_bin()) print(all_deleted_files)

以上代码用户获取桌面快捷图标的地址,想了解更详细的信息可以参考下面的链接。

20.3.13 pathlib模块

pathlib模块也非常好用,我们程序中多少都难免需要处理一些文件,而pathlib库正是用来进行类似操作的库。我们的程序中将使用该库进行文件的删除操作。

from pathlib import Path def clean(extend): path = Path.cwd() # Path('.') for p in path.glob(f"*.{extend}"): p.unlink()

更多详细信息可以参考下面的链接。

20.3.14 subprocess模块

subprocess模块可以用于创建子程序,同时可以将特定参数传递给子程序,并通过管道与标准输入,标准输出和错误输出相连接。这样在子程序外部就可以获取程序的输入输出和错误输出,以及程序返回值。我们程序中将使用Popen()接口来启动我们的升级后处理程序,以及通过调用一些命令行程序来启动远程桌面。

具体代码片段如下。

from subprocess import Popen self.mstsc_handle = Popen('cmdkey /delete:{0}'.format(self.url)).wait() self.mstsc_handle = Popen('cmdkey /delete:TERMSRV/{0}'.format(self.url)).wait() self.mstsc_handle = Popen('cmdkey /generic:{0} /user:{1} /pass:{2}'.format(self.url self.username self.password)).wait() self.mstsc_handle = Popen('mstsc /v:{0} /w:1600 /h:768'.format(self.url))

当然,subprocess模块还有其它很多接口,我们这里只使用了Popen()接口。如果读者有不同需求,或者希望了解更多,可以参考如下链接。

20.3.15 PyQt5模块

PyQt5模块将是我们创建程序GUI界面使用的库,通过名字我们可以猜出其是QT的Python版本。它将QT和Python融合在了一起,很完美的为熟悉QT的开发者提供了Python版本的GUI。并且我们可以通过QT designer工具进行界面的设计,只需要拖拽相应的组件即可,界面的设计可以与代码功能实现完全分离。也就意味着,即使修改了界面文件,程序功能无需进行改变的情况下,不需要重新编译或打包。

from PyQt5.uic import loadUi logui = resource_path(os.path.join("res" "bookingtestline.ui")) loadUi(logui self)

上面代码片段就是我们的程序用于加载界面文件的代码,可以看出是完全加载了一个ui文件,使界面和程序代码完全分离,互不影响,更多详细信息可以参考下面的链接。

20.3.16 paramiko模块

paramiko模块是SSHv2协议的Python实现,提供了客户端和服务端功能。是一个纯Python语言实现的模块,我们这里只使用其中的SSHClient,Transport和AutoAddPolicy。由于我们需要想服务器端上传文件和下载文件,因此这里需要实现一个ssh客户端。另外也利用Transport子模块,让我们可以打开一个会话来在远端服务器端执行命令,我们程序中使用到的相关代码片段如下所示。

from paramiko import SSHClient Transport AutoAddPolicy def open_ssh_client(server user password port=22): ssh = SSHClient() # ssh.load_system_host_keys() # ssh.load_host_keys(os.path.expanduser(os.path.join("~" ".ssh" "known_hosts"))) # 这行代码的作用是允许连接不在know_hosts文件中的主机。 ssh.set_missing_host_key_policy(AutoAddPolicy()) try: ssh.connect(server port user password timeout=3) except: ssh = None return ssh def open_ssh_channel(server user password port=22): """ This API is for creating ssh channel """ trans = Transport((server 22)) trans.start_client() trans.auth_password(userName=user password=password) channel = trans.open_session(window_size=10000) channel.get_pty() channel.invoke_shell() return trans channel

更多关于该模块的详细信息,我们可以通过下面的链接进行学习。

20.3.17 scp模块

scp模块实现了scp的相关功能,我们这里仅仅使用了其SCPClient子模块及其异常定义。

from scp import SCPClient from scp import SCPException with SCPClient(ssh.get_transport() progress=self.progress) as scp: try: # getting the total_size of all files for file in files_list: local_file converted_flag = self.get_local_file(file) self.total_size = os.path.getsize(local_file) if self.total_size > 0: self.sync_progress_maxi_signal.emit(int(self.total_size)) for file in files_list: # This line will change local file if it is a windows format with trailing local_file converted_flag = self.get_local_file(file) scp.put(local_file self.remote_code_dir file) # recursive=True self.size_count = os.path.getsize(local_file) self.show_trace_log_signal.emit(str(file)) if converted_flag is True: os.unlink(local_file) # self.sync_progress_update_signal.emit(int(i 1)) except SCPException as e: err_message = e.args[0] self.show_trace_log_signal.emit(str("[End] Failed sync files to compiler:" err_message)) if 'DOT' not in err_message: logging.error("Failed sync files to compiler:" err_message) self.exit(1)20.3.18 win32com.client模块

win32com.client是一个非常强大的模块,如果需要在windows做一些事情,比如对word/excel文件等进行操作,或其他windows上的程序,那么这个模块将会很有用处。我们这里使用该模块为我们的程序创建快捷图标。

from win32com.client import Dispatch shell = Dispatch('WScript.Shell') #确认要创建的是否存在,存在的情况下判断目标是否一致 if os.path.exists(path): if target == shell.CreateShortCut(path).Targetpath: return else: os.unlink(path) #创建快捷图标 shortcut = shell.CreateShortCut(path) shortcut.Targetpath = target shortcut.WorkingDirectory = wDir shortcut.IconLocation = icon shortcut.save()

该模块还有更强大的功能,只不过我们程序中没有涉及其他功能,因此不做过多介绍。感兴趣的读者可以利用百度进行查阅学习。

20.4 代码实现

到现在我们简单了解了会使用到的所有相关模块,接下来,我们就将实现具体代码。

20.4.1 编写伪码

这里我们进行必要的伪码,以帮助我们更好的理解程序整体实现。

# 首先,定义必要的字符串常量,用于解析配置文件 # 实现一个解析配置文件的函数parser_config_file() # 定义一系列接口用于打开ssh客户端及ssh会话的接口 # 定义class AutoBuildingGui类,作为程序的主界面类 # 在该类的__init__中调用loadUi()进行加载我们程序界面ui文件 # 为按钮设置具体的响应函数 # 定义相关的signal用于程序和界面进行通信 # 将每一个操作实现为一个线程,并在点击start按钮后将所有需要执行的线程加入线程池 # 为每一个操作定义相应的线程,每个都是一个线程类,这样的好处是便于复用且互不影响 if __name__ == "__main__": # 实例化界面类 # 显示界面20.4.2 Python代码

程序的界面如下图20-1所示,该界面是用Qt Designer进行设计而成。界面的左边是相应的功能选项,可以选择我们要执行的具体步骤,点击按钮"Start building"后,程序将开始根据已选择的操作逐个执行。还有一个"GDB core dump analysis"按钮,点击后会弹出一个文本文件,我们只需要将core dump的信息填入,关闭该文件后,程序将自动帮助进行core dump解析,并返回解析结果。界面的右边是一个输出文本框,用于显示程序执行的过程信息,比如正在同步哪些文件,编译的过程信息等待。

python嵌入式开发学习流程(Python实用案例编程入门)(1)

图20-1 嵌入式软件开发助手程序界面

该界面的源码文件名为auto-building.ui,下面是该界面文件的源码。可以看出,其内容实际上是一个xml格式的文件。建议安装一个Qt Designer,然后再打开这个文件,进行修改或者设计自己想要的界面。

接下来,这里就可以开始Python代码实现了,程序文件auto-building-gui.py的内容如下所示,我们所有Python代码实现都在这个文件中。

# -*- coding: utf-8 -*- """ Created on Wed Apr 3 18:21:30 2019 @author: ggang.liu """ 20.4.3 打包为exe安装文件进行发布

接下来,我们需要将Python代码进行打包,生成exe进行方便使用。

将Python代码转换为exe程序,我们使用的是pyinstaller,具体的转换代码我实现为python代码。只需要执行下面的Python代码,就会调用pyinstaller生成一个单独的exe文件。这种形式的优点是只有一个exe文件,其他所有的依赖的Python环境文件都被打包在该exe文件中。而缺点就是由此导致该文件比较大,而且每次执行都相当于有一个解压到临时目录的过程,所以执行比较慢。

import os import sys import shutil from subprocess import Popen if os.path.exists('dist'): shutil.rmtree("dist") if os.path.exists('build'): shutil.rmtree("build") if os.path.exists('__pycache__'): shutil.rmtree("__pycache__") def modify_version_num(file version_num): with open(file) as fd: for line in fd.readline(): if "Auto building" in line: pass print(version_num) if "__main__" == __name__: version_num = 0 if len(sys.argv) >= 2: version_num = sys.argv[1] #modify_version_num(version_num) handle = Popen("pyinstaller -F -w --add-data res;res -i res/ab.ico auto-building-gui.py") handle.wait()

个人推荐将其打包为目录,而不是单个exe文件。这样的好处就是不需要每次执行都进行解压到临时目录,而是直接在同目录下调用执行,因此比较快。而为了更方便,我们这里会介绍如何将该目录打包为安装文件,这样在给别人用的时候,只需要给一个安装文件。用户拿到该安装文件后,安装上之后就可以使用了,且使用感受更好。

下面就是打包为目录的代码,跟上面有区别,其中一个打包参数为-D。

import os import sys import shutil from subprocess import Popen if os.path.exists('dist'): shutil.rmtree("dist") if os.path.exists('build'): shutil.rmtree("build") if os.path.exists('__pycache__'): shutil.rmtree("__pycache__") def modify_version_num(file version_num): with open(file) as fd: for line in fd.readline(): if "Auto building" in line: pass print(version_num) if "__main__" == __name__: version_num = 0 if len(sys.argv) >= 2: version_num = sys.argv[1] #modify_version_num(version_num) handle = Popen("pyinstaller -D -w --add-data res;res -i res/ab.ico auto-building-gui.py") handle.wait()

正如上面提到的,我们这里介绍一个将目录打包为安装文件的工具程序。该工具程序名为Inno Setup,是一个免费的工具软件,网站主页如下图20-2所示。可以点击Download Inno Setup链接进行下载,详细信息可以登陆网站()进行了解。

python嵌入式开发学习流程(Python实用案例编程入门)(2)

图20-2 Inno Setup主页

这里,我们要创建服务的安装程序,完整的文件如下,大部分是Inno Setup自动生成的。

; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #define MyAppName "auto-building-gui" #define MyAppVersion "3.1" #define MyAppPublisher "ggang.liu Inc." #define MyAppExeName "auto-building-gui.exe" [Setup] ; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. ; (To generate a new GUID click Tools | Generate GUID inside the IDE.) AppId={{B6A555B3-39E3-4838-A4CD-CC7023AD328A} AppName={#MyAppName} AppVersion={#MyAppVersion} ;AppVerName={#MyAppName} {#MyAppVersion} AppPublisher={#MyAppPublisher} DefaultDirName={autopf}\{#MyAppName} DisableProgramGroupPage=yes ; The [Icons] "quicklaunchicon" entry uses {userappdata} but its [Tasks] entry has a proper IsAdminInstallMode Check. UsedUserAreasWarning=no InfoAfterFile=C:\Users\tool\auto-building-gui\release\readme.txt ; Remove the following line to run in administrative install mode (install for all users.) PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog OutputDir=C:\Users\tool\auto-building-gui\release OutputBaseFilename=auto-building-gui-setup SetupIconFile=C:\Users\tool\auto-building-gui\res\ab.ico Password=dot Compression=lzma SolidCompression=yes WizardStyle=modern [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" [Tasks] Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 6.1; Check: not IsAdminInstallMode [Files] Source: "C:\Users\tool\auto-building-gui\dist\auto-building-gui\auto-building-gui.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "C:\Users\tool\auto-building-gui\dist\auto-building-gui\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs ; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Icons] Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon [Run] Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram {#StringChange(MyAppName '&' '&&')}}"; Flags: nowait postinstall skipifsilent

这里打包生成的安装文件是一个exe文件,我们双击执行安装时会出现如图20-3所示界面,可以看出是一个很常见的程序安装界面,跟其他程序安装没有什么区别,看起来更专业,使用过程中程序启动速度也很快。

python嵌入式开发学习流程(Python实用案例编程入门)(3)

图20-3 服务程序安装界面

到这里,程序的打包安装就介绍完毕,具体选择哪种方式进行打包,可以根据具体情况而定。

20.5 本章小结

本章介绍了一个对嵌入式开发者来说比较有用的工具程序,但也对其他读者提供了一种思路。我们很多具有固定步骤或者反复重复执行的动作,我们都可以用程序来完成它,从而来提升我们的工作效率。

在本章我们也涉及了很多第三方库,这些库提供给我们很多选择,也帮助我们完成了很多工作。最重要的是我需要知道这些库的存在,以及它给我们提供了什么功能,在我们需要的时候可以去查阅使用我们需要的功能,从而大大提高编程效率。

猜您喜欢: