====== Modern Python Practice ====== * nowaday, now one use python 2.x anymore, use python 3 standard, use this * use pathlib instead of os.path * use f"{keyword}" instead of "{0}".format(keyword), unless it is easier ====== Online Python run ====== * https://jupyter.org/try-jupyter/retro/notebooks/?path=notebooks/Intro.ipynb * to install locally: pip3 install --upgrade pip ====== Install related ====== ===== install Python3 on mac ===== * Mac has its own python install, very old, only for basic usage * to install Python3 from official python website, - download python 3 for mac installer - install as usual and done - run python3 in cmd - then it pops: "python3" command requires the "the commandline developer tools" to install, click install - if you already install XCode (the developer suite for mac), then no need; if not, you can just install the smaller "Command line tools" with your Apple account - go Apple developer downloads page, search command line tools for xcode, download that and install ===== Manage and handle multiple versions of python case ===== Situation: * sometimes, you may have to keep both python 2.7, python 3.x * and sometimes you want to try python with AI, and AI need to install tons of AI related python modules * sometimes you just to keep python module in the min form to test something Solution: * for those case, when install python, never add python to system path * just download and make python folder a portable folder (you can install and copy the python whole folder to other machine as a portable app, better zip to copy, faster) * then your computer cmd never know where is python and won't random get your python from somewhere * then, dynamically set python into python in cmd session or batch file, or use full path to python.exe to run your script * session based method (win as example) SET PATH=D:\App\Python;D:\App_Dev\PortableGit\bin;%PATH% * batch file method @echo off SetLocal EnableDelayedExpansion set CustPython=D:\App\Python\ call !CustPython!python.exe my_script.py ====== Python 3 Changes and How to Make 2.7 Code Works ====== * make print "" into print(""), like as a function # in code editor, using Regular Expression to replace find: (print)\s(.+) replace: $1\($2\) or \1(\2) depending on your code editor * other stuff # python 2 reload reload(myModule) # python 3 reload from imp import reload reload(myModule) # python 2 execfile execfile("testScript.py") # python 3 exec(open("testScript.py").read(), globals()) * make compatible to python 3 if sys.version_info[:3][0]>=3: import importlib reload = importlib.reload # add reload raw_input = input # add raw_input xrange = range # range long = int # int unicode = str # str * integer division difference in py3 vs py2, a/b * ref: https://blog.finxter.com/how-to-divide-two-integers-in-python/ * for safe, use 35/60 = 0 # py2 35//60 = 0 # py2 , always use // for calculate minutes and seconds 35/60 = 0.583 #py3 35//60 = 0 # py3 ====== Python basics ====== * online python code runner: https://trinket.io/ * Python download: http://www.python.org/ * a cool python shell: http://www.dreampie.org/ ** My Wiki Page related** * how to publish Python script as standalone application: [[devwiki:pyapp|Python script App]] * My App code share: [[devwiki:pyapp:mypyapp|My Py App]] * My Python GUI code template: [[devwiki:template|My generic Qt GUI templates]] ** to read: ** * https://automatetheboringstuff.com/chapter9/ * Code Like a Pythonista: Idiomatic Python http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables ===== Python vs . ===== * Python vs Swift * https://blog.michaelckennedy.net/2014/11/26/comparison-of-python-and-apples-swift-programming-language-syntax/ ===== Python Comment Tips ===== * single line comment # single comment * multiple line comment ''' line 1 line 2 ''' * block, section, partition ######################################## # a major block of asset (40x#) ######################################## #------------------------------ # a function collection (30x-) #------------------------------ # ---- section comment ---- # function section tip def ________Loading_Functions________(): # 8x_ pass ===== Launch Python script ===== * launch in windows command batch file next to it@echo off call python %~dp0\\MyPythonScript.py * launch in Mac AppleScript file (wip) set myScriptPath to path to me set myScriptFolderPath to POSIX path of (container of myScriptPath as string) -- in "/" form set myScriptName to name of myScriptPath tell application "Terminal" do script with command "python /path_to_script/myScript.py" end tell ===== OS system operation ===== * get user/home folder os.path.expanduser('~') # return home directory, in Maya it return document, in windows, it return user dir os.getenv("HOME") # return home directory os.getenv("USERPROFILE") # return user profile directory * make python code able to print unicode directly without .encode('utf-8') for text import sys import codecs sys.stdout = codecs.getwriter('utf8')(sys.stdout) * get python program pathimport sys print(sys.executable) # the python cmd or app containing the python call path * get python module path import ModuleName os.path.dirname(ModuleName.__file__) * get script path os.path.dirname(__file__) * get class path but not its super class self.location = os.path.realpath(sys.modules[self.__class__.__module__].__file__) self.location = os.path.abspath(inspect.getfile(self.__class__)) * get class name self.__class__.__name__ * get basename of folder and file os.path.basename(os.path.normpath('/folderA/folderB/folderC/folderD/')) # 'folderD' * get file name without extension file_name = os.path.basename(file_path).rsplit('.',1)[0] import pathlib file_name_2 = pathlib.Path(file_path).stem * get expanded and un-symbolic path os.path.abspath(__file__) os.path.realpath(__file__) * path comparison os.path.relpath(childPath, parentPath) # get the sub path only based on parent Path os.path.commonprefix(list_of_paths) # get the common parent path of all input pathes * python code to detect platform, python version, bit from sys import platform def get_platform(): if platform.startswith('win'): return 'windows' elif platform.startswith('darwin'): return 'mac' return 'linux' import sys pyMode = '.'.join([ str(n) for n in sys.version_info[:3] ]) print("Python: {0}".format(pyMode)) is_64bits = sys.maxsize > 2**32 print(is_64bits) * check file and path existsos.path.exists(myPath): * scan file and folder content with pattern filtering result_list = [x for x in os.listdir(scanPath) if os.path.isdir(os.path.join(scanPath,x))] # isdir for folder, isfile for file cur_pattern = re.compile('\d{3}_\d{4}') # match 000_0000 name pattern result_list = [x for x in result_list if cur_pattern.match(x)] # jpg name example jpg_list = [x.rsplit('.',1)[0] for x in os.listdir(scanPath) if os.path.isfile(os.path.join(scanPath,x)) and x.lower().endswith('.jpg')] * rename file or folder os.rename(os.path.join(parentPath,old_name), os.path.join(parentPath,new_name)) * move file (always use full path for safe, and always check source and target exist before operation) # file move within same drive os.rename("/sourcePath/fileName.ext", "/targetPath/fileName.ext") os.replace("/sourcePath/fileName.ext", "/targetPath/fileName.ext") # work for folder and file and cross disk drive shutil.move("/sourcePath/fileName.ext", "/targetPath/fileName.ext") * system cmds for each os os.system('move "%s\%s" "%s\zBk.%s"' % (rootDir,oldPreset,rootDir,oldPreset)) os.system('mklink /D "%s\%s" "%s\%s"' % (rootDir,oldPreset,resDir,newPreset)) * cross-platform delivery from source * win: frozen * mac: frozen * lin: packaged * def getSetup(): if hasattr(sys, 'frozen'): return 'frozen' elif is_packaged(): return 'packaged' return 'source' * change file permission # ref: http://stackoverflow.com/questions/16249440/changing-file-permission-in-python import os import stat os.chmod("R:\\folder\\permit.txt", stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) # user, group, other readonly * windows register operation PS_key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,"SOFTWARE\\Adobe\\Photoshop\\12.0") # may need check version no. PS_APP = _winreg.QueryValueEx(PS_key, 'ApplicationPath')[0] + 'Photoshop.exe' def ps_loc_win(): import _winreg regKey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Photoshop.exe") regPath = _winreg.QueryValueEx(regKey, 'Path')[0] + 'Photoshop.exe' return regPath * windows set default playback device subprocess.call('nircmd.exe setdefaultsounddevice "Speakers"') # need download nircmd * run python script itself as admin import ctypes, sys def is_admin(): try: return ctypes.windll.shell32.IsUserAnAdmin() except: return False if is_admin(): # Code of your program here else: # Re-run the program with admin rights ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, "", None, 1) * run cmd with admin (3rd party module) # pywin32 : sourceforge.net/projects/pywin32/files/pywin32/ import win32com.shell.shell as shell commands = 'echo hi' shell.ShellExecuteEx(lpVerb='runas', lpFile='cmd.exe', lpParameters='/c '+commands) * control, start, stop, restart service (3rd party module method) import win32serviceutil serviceName = "serviceName" win32serviceutil.RestartService(serviceName) ==== List File and sub-folders - the Correct Way ==== * in Python 3.5, scandir module is part of python, also inside os.walk() internal instead of os.listdir() old way. * so compare glob, python 2.7 os.walk() and scandir (also available as external module for previous python) * scandir is at least 10x faster than old os.walk, glob is 2x faster than old os.walk by skipping dir/file type checking * 132s (walk) / 62s (glob) / 12s (scandir) import glob def getDirData(top, maxDepth=1): res = [] for d in range( 1, maxDepth+2 ): maxGlob = "/".join( "*" * d ) topGlob = os.path.join( top, maxGlob ) allFiles = glob.glob( topGlob ) res.extend( allFiles ) #someFiles.extend( [ f for f in allFiles if fnmatch.fnmatch( os.path.basename( f ), fnMask ) ] ) return res import os def getDirData( top, maxDepth=1): # ref: https://stackoverflow.com/questions/7159607/list-directories-with-a-specified-depth-in-python # py3 option: better with scandir, # py2 has: https://github.com/benhoyt/scandir top = os.path.normpath(top) res = [] root_len = len(top) #+len(os.path.sep) for root,dirs,files in os.walk(top, topdown=True): depth = root[root_len:].count(os.path.sep) if depth < maxDepth: res += [os.path.join(root, d) for d in dirs] res += [os.path.join(root, f) for f in files] elif depth == maxDepth: res += [os.path.join(root, d) for d in dirs] res += [os.path.join(root, f) for f in files] dirs[:] = [] # Don't recurse any deeper return res # detail inf: https://benhoyt.com/writings/scandir/ # can use with maya 2017 by zip out _scandir.pyd and scandir.py: (scandir-1.10.0-cp27-cp27m-win_amd64.whl) https://pypi.org/project/scandir/1.10.0/#files tmp_path = r'D:\PyLib\scandir27x64' tmp_path in sys.path or sys.path.append(tmp_path) import scandir def getDirData(top, maxDepth=1): # py3.5 has built in, only for 2.7 # https://github.com/benhoyt/scandir top = os.path.normpath(top) res = [] root_len = len(top)#+len(os.path.sep) for root,dirs,files in scandir.walk(top, topdown=True): depth = root[root_len:].count(os.path.sep) if depth < maxDepth: res += [os.path.join(root, d) for d in dirs] res += [os.path.join(root, f) for f in files] elif depth == maxDepth: res += [os.path.join(root, d) for d in dirs] res += [os.path.join(root, f) for f in files] dirs[:] = [] # Don't recurse any deeper return res # test import time start = time.time() result = getDirData(r'R:\ServerFolder\RootDir',5) end = time.time() print('used: {}s'.format(end - start)) * other module option: https://github.com/juancarlospaco/faster-than-walk ==== Copy File - the Correct Way ==== * speed on windows: SHFileOperation (8) > win32file (8.6) > os System (9) > shutil (18) * ref: http://www.cnblogs.com/lovemo1314/archive/2010/11/11/1874975.html * use python shutil module copy, copyfile and copy2 function import shutil # copy: return target path, target can be file or folder shutil.copy('d:/z_tmp/aa.jpg','d:/z_tmp/bb.jpg') shutil.copyfile('d:/z_tmp/aa.jpg','d:/z_tmp/dd.jpg') ''' # result modified date change 02/06/2017 02:13 PM 193,399 aa.jpg 12/09/2017 12:06 PM 193,399 bb.jpg 12/09/2017 12:06 PM 193,399 dd.jpg ''' shutil.copy2('d:/z_tmp/aa.jpg','d:/z_tmp/bb.jpg') ''' # result keeps modified date 02/06/2017 02:13 PM 193,399 aa.jpg 02/06/2017 02:13 PM 193,399 cc.jpg ''' * copy folder and its content import shutil, errno def copyFolder(src, dst): try: shutil.copytree(src, dst) # folder structure only except OSError as exc: # python >2.5 if exc.errno == errno.ENOTDIR: shutil.copy2(src, dst) # file only with same date, or copy for current date else: raise # or use this distutils.dir_util.copy_tree(src_folder, tgt_folder) * python more complete version for copy folder and its content # ref: http://blog.csdn.net/liyuan_669/article/details/25346645 # folder content to target folder content. created folders seams not same date, but file same date import os import shutil def copy_tree(src, dst, symlinks=False): names = os.listdir(src) if not os.path.isdir(dst): os.makedirs(dst) errors = [] for name in names: srcname = os.path.join(src, name) dstname = os.path.join(dst, name) try: if symlinks and os.path.islink(srcname): linkto = os.readlink(srcname) os.symlink(linkto, dstname) elif os.path.isdir(srcname): copy_tree(srcname, dstname, symlinks) else: # perform overrides if os.path.isdir(dstname): os.rmdir(dstname) elif os.path.isfile(dstname): os.remove(dstname) shutil.copy2(srcname, dstname) # other case like: devices, sockets etc. except (IOError, os.error) as why: errors.append((srcname, dstname, str(why))) # catch the Error from the recursive copy_tree so that we can # continue with other files except OSError as err: errors.extend(err.args[0]) try: shutil.copystat(src, dst) except WindowsError: # can't copy file access times on Windows pass except OSError as why: errors.extend((src, dst, str(why))) if errors: raise Error(errors) copy_tree('E:/book', 'E:/newbook') * use system command to copy src = 'd:/z_tmp/aa.jpg' tgt = 'd:/z_tmp/sys_copy.jpg' os.system('copy {0} {1}'.format(os.path.normpath(src),os.path.normpath(tgt)) ) # normpath will change the slash for win from unix path os.system ("xcopy /s {0} {1}".format(src_dir, tgt_dir)) * use system file manager to copy with system progress window (windows) #ref: https://stackoverflow.com/questions/16867615/copy-using-the-windows-copy-dialog import pythoncom from win32com.shell import shell,shellcon def win_copy_process(src_files,tgt_folder): # win32com module pfo = pythoncom.CoCreateInstance(shell.CLSID_FileOperation,None,pythoncom.CLSCTX_ALL,shell.IID_IFileOperation) # Respond with Yes to All for any dialog # ref: http://msdn.microsoft.com/en-us/library/bb775799(v=vs.85).aspx pfo.SetOperationFlags(shellcon.FOF_NOCONFIRMATION) # Set the destionation folder dst = shell.SHCreateItemFromParsingName(tgt_folder,None,shell.IID_IShellItem) for f in src_files: src = shell.SHCreateItemFromParsingName(f,None,shell.IID_IShellItem) pfo.CopyItem(src,dst) # Schedule an operation to be performed # ref: http://msdn.microsoft.com/en-us/library/bb775780(v=vs.85).aspx success = pfo.PerformOperations() # ref: sdn.microsoft.com/en-us/library/bb775769(v=vs.85).aspx aborted = pfo.GetAnyOperationsAborted() return success and not aborted file_list = [r'D:\z_tmp\aa.jpg',r'D:\z_tmp\bb.jpg'] tgt_folder = r'D:\zTmp' win_copy_process(file_list,tgt_folder) * use system API (windows) #ref: http://timgolden.me.uk/python/win32_how_do_i/copy-a-file.html # win32 from win32com.shell import shell, shellcon win32file.CopyFile (filename1, filename2, 1) # win32com : with windows copy dialog shell.SHFileOperation ( (0, shellcon.FO_COPY, filename1, filename2, 0, None, None) ) # for the "0" parameter: # shellcon.FOF_RENAMEONCOLLISION: rename on collision # shellcon.FOF_NOCONFIRMATION: no confirmation dialog and always override # shellcon.FOF_NOERRORUI: no error pop dialog # shellcon.FOF_SILENT: no copying progress dialog # shellcon.FOF_NOCONFIRMMKDIR: no ask for non exist folder, create folder by default ===== string operation ===== * encode and decode Qt QString str(myQStringObj) # ascii output unicode(myQStringObj) # unicode output unicode(myQStringObj.toUtf8(), encoding="UTF-8") # decode based on utf8, then encode in utf-8 python string as unicode output * ref: * UTF-8 is an encoding used to translate numbers into binary data. * Unicode is a character set used to translate characters into numbers. * text block to clean row list data_list = [row.strip() for row in source_txt.split('\n')] * to use non-ascii character in python file, you need to put encoding in first line of code, or you will get "Non-ASCII character '\xe2' in file" error # coding: utf-8 my_special_string = u"好" print(u"好") * remove extra space from a string, also remove end single space tidy_name = ' '.join(old_name.split()) # just remove extra space tidy_name = re.sub(' +', ' ', old_name) # only space, need strip() to clear end space tidy_name = re.sub('\s{2,}', ' ', old_name) # space, tab, new line, need strip() to clear end space ===== control flow operation ===== * define function def my_fun(para1): print para1 * logic and condition and loop operation for tmpitem in tmplist: print tmpitem if tmp > 0: print 'ok' elif x == 0: print 'zero' else: print 'no' # logic operation x or y x and y not x * try operation, note try is not a block, variable is same scope before try try: val = test(A) except: pass # ref: https://teamtreehouse.com/community/scope-of-a-variable ===== data operation ===== * data type check isinstance(Vehicle(), Vehicle) # returns True type(Vehicle()) == Vehicle # returns True isinstance(Truck(), Vehicle) # returns True, takes inheritance type(Truck()) == Vehicle # returns False, take exact class type # check string, both python 2,3 isinstance(my_data, (str, unicode) ) # check list isinstance(my_data, (list, tuple) ) # check not None, note, None is its own type and has only one instance my_vec != None # sometime, it may cause error when = try to read certain way my_vec is not None # this way is preferred to be error free isinstance(my_vec, om.MVector) # this way even better, not only check it is defined and also check its type match # compare type if type(A) is type(B): print('Same Class') # note : is for same object and like pointer comparision, while == is same value comparision * data type convertion int('42') str(42) * get datetime date date_text = datetime.date.today().strftime("%Y.%m.%d") * get processing time import time start = time.time() print("hello") end = time.time() print(end - start) * wild char process import glob os.chdir(path) for file in glob.glob("*.jpg"): print file tmplist=glob.glob('*.[jJ][pP][gG]') # other method: fnmatch and re * string operation name="01_Blue_Sun_DSC08897.jpg" print name[3:-13].replace('_',' ') #Blue Sun# len(str) # string length "hello world".title() 'Hello World' # remove Whitespace on the both sides: s = " \t a string example\t " s = s.strip() # remove Whitespace on the right side: s = s.rstrip() # remove Whitespace on the left side: s = s.lstrip() Data Type * Lists []: a list of values. Each one of them is numbered, starting from zero - the first one is numbered zero, the second 1, the third 2, etc. You can remove values from the list, and add new values to the end. Example: Your many cats' names. * Tuples (): are just like lists, but you can't change their values. The values that you give it first up, are the values that you are stuck with for the rest of the program. Again, each value is numbered starting from zero, for easy reference. Example: the names of the months of the year. * Dictionaries {'':'',}are similar to what their name suggests - a dictionary. In a dictionary, you have an 'index' of words, and for each of them a definition. In python, the word is called a 'key', and the definition a 'value' * list operation (so-called array) ([[http://effbot.org/zone/python-list.htm|ref]]) [1,2,3] len(arrayName) # size of list # add value to all elements of list my_list=[1,3,5,7,8] new_list = [x+1 for x in my_list] # [2,4,6,8,9] list.append(obj) list.extend(list) list.index(obj) list.count(obj) # count appearance of obj # array to string and string to array sentence = ["there", "is", "no", "spoon"] ' '.join(sentence) #'there is no spoon' list=[3.1,121.2,34.1] ', '.join(map(str,list)) #'3.1, 121.2, 34.1' '3.1, 121.2, 34.1'.split(', ') #['3.1','121.2','34.1'] # 2nd number make how many split point '3.1, 121.2, 34.1'.split(', ',1) #['3.1','121.2, 34.1'] # list sort (modify itself) versionList.sort(reverse=1) # higher to lower versionList.sort() str([-4, -2, 0, 2, 4]) # '[-4,-2,0,2,4]' bb_str ='_'.join(map(str, bb)) # -4_-2_0_2_4 # list compare [-4, -2, 0, 2, 4] == [-4, -2, 0, 2, 3] # false # multiple list operation wMap_zero_Jnt=[x for x in wMap_All_Jnt if x not in wMap_Jnt_tgt] # remove list from list a = [1, 2, 3, 4, 5] b = [9, 8, 7, 6, 5] common = set(a) & set(b) #[5], no order applied [i for i, j in zip(a, b) if i == j] # [5] for equal-sized lists, which order matters version_list_prefix=["previous","current"] version_list_postfix=["A","B"] version_list_color=["rgb(255, 128, 128)","rgb(85, 170, 255)"] for each,post,color in zip(version_list_prefix,version_list_postfix,version_list_color): print(each+" "+post+" is "+color) # list slice operation # n = len(L) # item = L[index] # seq = L[start:stop] # seq = L[start:stop:step] seq = L[::2] # get every other item, starting with the first seq = L[1::2] # get every other item, starting with the second seq=L[::-1] # reverse reading list list(reversed(seq)) # generate a list reversed L.reverse() # reverse list, it changed original list seq=L[::-2] # reverse reading list, and get every other item list=[1,2,3,4,5,6] seq=list[::-2] # [6,4,2] # list to pair list info = ['name','John', 'age', '17', 'address', 'abc'] info_pair = zip(info[::2], info[1::2]) # [('name', 'John'), ('age', '17'), ('address', 'abc')] # list flatten, and remove duplicates nestList = [[2,3],[1,2,4],[5,6]] flatList = set(sum(nestList,[])) # for small list of 2 level nest # delete a element from list a = [1,2,3,4] del(a[2]) # [1,2,4] # for large list import itertools flatList = set( list(itertools.chain.from_iterable(nestList)) ) # for same type element list, no mix of list and element like [[5],6], as it will error import operator flatList = set( reduce(operator.add, map(list, nestList)) ) # like itertool, but it will not error for mix of list and element situation # for any mix list def flatFn(mainList): newList = [] for each in mainList: if isinstance(each, (list, tuple)): newList.extend( flatFn(each) ) else: newList.append(each) return newList flatList = set( flatFn(nestList) ) * dictionary operation # ref: http://www.dotnetperls.com/dictionary-python dict.clear() dict.get(key, default=None) # returns value or default if key not in dictionary dict.has_key(key) dict.items() # a list dict's (key, value) tuple pairs dict.keys() # a list of keys dict.values() # a list of values len(dict) # size of dict #example, obj property dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}; #example, obj list dict = {'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'} # delete key my_dict.pop(key_name, None) * set operation set( ("hello", "world", "of", "words", "of", "world") ) # set(['world', 'hello', 'words', 'of']) fib=set( [1,1,2,3,5,8,13] ) prime=set( [2,3,5,7,11,13] ) combine=fib | prime # set([1, 2, 3, 5, 7, 8, 11, 13]) common=fib & prime #set([2, 3, 5, 13]) diff = fib - prime # set([8, 1]) fib ^ prime # combine - common #set([1, 7, 8, 11]) # <, <=, >, >=, ==, !=, in, not in works in set len(fib)=6 max(fib)=13 min(fib)=1 sum(fib)=32 any(set([false,true])) # For sets, Return True if there exists any item which is True. all(set([false,true])) # For sets, Return True if there all items which is True. set.add(new) set.remove(old) * list attribute of a object object.__dict__ ===== turn a file into a module ===== * a file can be a module like import FileName FileName.functionName() # call function side that file ===== turn a folder into a module ===== * you can turn a list of python file under same folder into a module by create a empty file under the directory: __init__.py * it will automatically turn the folder into a module so that you can call each file after import folder like import FolderName from FolderName import FileName * whenever you call import FolderName, the __init__py will be run-ed first, so you can put some code inside to do some pre-run task, or append the folder into python path import os, sys my_path = os.path.dirname(__file__) my_path in sys.path or sys.path.append(my_path) ===== check module installed ===== * python code help(moduleName) dir(moduleName) #import moduleName #then type moduleName to show location * check module in shell command pydoc moduleName * change current working pathos.chdir('/my_path/') ===== cross python file reference===== * import python function from another python file import sys sys.path.append("/home/my/python_file_folder") # you need to have python path knows your file location # method 1 import sample sample.abcd() # method 2 from sample import abcd abcd() #method 3 from sample import * abcd() * run another python script execfile("testScript.py") # python 3, that one not work, use this one exec(open("testScript.py").read(), globals()) * pass parameter to a python script (ref: http://www.tutorialspoint.com/python/python_command_line_arguments.htm) # method 1: python myscript.py arg1 arg2 import sys print 'Number of arguments:', len(sys.argv), 'arguments.' print 'Argument List:', str(sys.argv) # method 2 import getopt, sys * example code for a mel file to html file process, in both module and app way * run code python viewMel.py myMelFunc.mel * run in python import viewMel viewMel.viewMel_html('myMelFunc.mel','mydoc.html') * code #view mel lib #a python tool to view mel lib file functionts import sys def viewMel(file): with open(file) as f: for line in f: lineClean=line.strip() if lineClean.startswith('//==') or lineClean.startswith('global proc') or lineClean.startswith('/**'): print lineClean.replace('{','').replace('*/','').replace('/**',' - ') def viewMel_html(melFile,htmlFile): h = open(htmlFile,'w') with open(melFile) as f: h.write('\n'+'\n') for line in f: lineClean=line.strip() if lineClean.startswith('//=='): h.write('

'+lineClean.replace('//==','').replace('=','')+'

'+'\n') elif lineClean.startswith('global proc'): h.write('
'+lineClean.replace('{','').replace('global proc ','')+'
'+'\n') elif lineClean.startswith('/**'): h.write('

'+lineClean.replace('*/','').replace('/**',' - ')+'

'+'\n') h.write(''+'\n') h.close() if __name__=="__main__": viewMel_html(sys.argv[1],sys.argv[1].replace('.mel','.html'))
===== web link operation ===== * open url in brower import webbrowser webbrowser._browsers # list registered browsers new = 2 # open in a new tab, if possible # open a public URL, in this case, the webbrowser docs url = "http://docs.python.org/library/webbrowser.html" webbrowser.open(url,new=new) # for using firefox, note, firefox needs to be default or in the system environment path webbrowser.get('firefox').open(url,new=2) # open an HTML file on my own (Windows) computer url = "file://X:/MiscDev/language_links.html" webbrowser.open(url,new=new) ===== file operation ===== * check file exists os.path.isfile(path) * access file and folder # delete a file os.remove(tmpitem) # check exist of a file if not os.path.exists(tmpJPG): print tmpitem # get file with a certain name pattern in a directory and all its sub-directories scanDir = r'D:\scanDir_start_dir' my_list = [] for (dirpath, dirnames, filenames) in os.walk(scanDir): my_list.extend( [ os.path.join(dirpath, x) for x in filenames if re.match('[a-zA-Z]+_lang_.+\.json', x) ] ) # get file with a certain name pattern in a directory [x for x in os.listdir(scanDir) if os.path.isfile(os.path.join(scanDir, x)) and re.match('MyApp_lang_.+\.json', x) ] [x for x in glob.glob(os.path.join(scanDir,'MyApp_lang_*.json')) if os.path.isfile(x) ] * lines to array with open(fname) as f: content = f.readlines() with open(fname) as f: for line in f: #do something with line * remove any non-ascii words in file names import os import urllib curdir = os.getcwd() os.chdir(parentDir) file_list_en = os.listdir('.') # this is ok ascii list file_list_cn = os.listdir(u'.') # this u fix extreme non-ascii names for i in xrange(len(file_list_en)): itemName = file_list_en[i] print(itemName) if itemName.startswith('%'): # convert %AA cn name to unicode new_fixName1 = urllib.unquote(itemName).decode('utf8').replace('+',' ') # then remove cn chars new_itemName2 = ''.join([c for c in new_fixName1 if ord(c) < 128 ]).replace('?','').replace('+',' ').strip() if itemName != new_itemName2: print([itemName,new_itemName2]) os.rename(itemName,new_itemName2) else: itemName = file_list_cn[i] # for non ascii names # just remove cn chars new_itemName = ''.join([c for c in itemName if ord(c) < 128 ]).replace('?','').replace('+',' ').strip() if itemName != new_itemName: print([itemName,new_itemName]) os.rename(itemName,new_itemName) os.chdir(curdir) * read line from a huge file by multiple process at the same time, without accident write operation import linecache linecache.getline('/path_to_file.txt', 2) # get 2nd line of text, the first line is no. 1, unlike 0 in arrary * process line by line rewrite import sys import fileinput for i, line in enumerate(fileinput.input('color_test.htm', inplace=1)): #sys.stdout.write(line.replace('colour','color')) if line.find('color') > -1: color=line.split(';',1)[0] color=color.split('color',1)[1] sys.stdout.write(line.replace(' * make sure directory is created before create file in defined path my_filePath = '/your_path/intermedia_folders/file.ext' # method 1: these 2 lines only create last leaf folder, won't deal all the inbetween folders if not os.path.isdir(os.path.dirname(my_filePath)): os.mkdir(os.path.dirname(my_filePath)) # method 2: these 2 lines create all the needed folders forming the path try: os.makedirs(os.path.dirname(my_filePath)) except OSError: pass # method 3: all in one check and create if needed, like method 2 but not need try and except since it will be ok for exist os.makedirs(os.path.dirname(output_path), exist_ok=True) * write python data # write raw data and read raw data os.getcwd() import json def writeDataFile(data, file): with open(file, 'w') as f: json.dump(data, f) def readDataFile(file): with open(file) as f: data = json.load(f) return data # write dictionary data and read dictionary data import csv def writeDictFile(dict, file): w = csv.writer(open("output.csv", "w")) for key, val in dict.items(): w.writerow([key, val]) def readDictFile(file): dict = {} for key, val in csv.reader(open(file)): dict[key] = val return dict * UTF-8 unicode file write ############### UTF-8 content write ############# import codecs txt=u"\n" i=0 for each in a: i=i+1; txt=txt+u"\n".format(link=each['link'], title=each['title'],code=each['code'], idx=i) txt=txt+u'
{title}{code}{idx}
' with codecs.open('page.htm',mode='w',encoding='utf-8') as f: f.write(txt)
* copy directory structure only for dirpath, dirnames, filenames in os.walk(srcPath): to_mkdir = os.path.join(tgtPath, dirpath[1+len(srcPath):]) if not os.path.isdir(to_mkdir): os.mkdir(to_mkdir) os.startfile(tgtPath) # show result folder ===== thread operation ===== * run a process or python service/app into another thread, so it wont block current interaction def app(opt): if opt == 'Noter': import threading th = threading.Thread(target = run_noter) th.start() def run_noter(): import Noter Noter.main() ====== module operation ====== * How to install extra module automatically with pip * download pip and use bellow method to manually install it, or run this line of command to get or update pip stuffs. python -m pip install --upgrade pip wheel setuptools * once done, you can install rest modules with cmd python -m pip install package_name * How to install wheel package REM pip app is at PythonAppDir/Scripts REM make sure that wheel is in 32/64bit matching your python 32/64bit version pip install C:/some-dir/some-file.whl * How to install extra module into seperate directory python.exe -m pip install --target=D:\my_path\plot_lib matplotlib * How to install extra modules manually - download the module source, * if it has setup.py in its directory, run python setup.py install to ask python to automatically install it into your python site-package directory * if it has no setup.py in its directory, or just a single folder or a python .py file, then just include its path in your python path under your system variable or run this command in python cmd line before you call import sys;myPath='/YourPath/ToTheFolderOrFile/';myPath in sys.path or sys.path.append(myPath) * **Ideally, if you put the Module Folder (not its parent distribution folder) under the Lib/site-package folder, it should work out of box when you type "import Module" in cmd**, of course, if you want to use specific version of the module or having the module in some other location, use the path way is more controllable to use exactly what you need. * However, if you want your Python module to be at a specific location, then add it to python path environment variable. For windows advanced system setting > environment variable set PYTHONPATH=%PYTHONPATH%;D:\Dev\PyQT - distribute your python file with module, * you can ask user to manually install those modules that used in your python program file * or just put those dependent file or folder next to your python program file * check with module info # check whether a module has that attribute if hasattr(QtGui, 'QTabWidget'): print("yes") # try get a function from a module and with fallback option resultFunc = getattr(MyClass, "function_A_name", default_function_if_not_found_A) # check imported module name dictionary if 'MyModule' in sys.modules: print('yes') * work with module using variable names # import PySide __import__('PySide') # same as from PySide import QtNetwork as Net qtModeList = ("PySide", "PyQt4", "PySide2", "PyQt5") qtMode = 0 Net = getattr( __import__(qtModeList[qtMode], fromlist=['QtNetwork']), 'QtNetwork') * import module from its parent directory import os,sys os.path.join(sys.path[0], '..') in sys.path or sys.path.insert(1, os.path.join(sys.path[0], '..')) import my_module_at_current_file_parent_dir ===== useful module list ===== ==== useful HTML modules ==== * [[devwiki:python:html|python with HTML process]] * urllib2 [[https://pypi.python.org/pypi/lxml/|lxml]] and [[https://pypi.python.org/pypi/requests|requests]] * BeautifulSoup [[http://www.crummy.com/software/BeautifulSoup/|site]] [[http://www.pythonforbeginners.com/python-on-the-web/scraping-websites-with-beautifulsoup/|tut]] * Mechanize [[http://wwwsearch.sourceforge.net/mechanize/|site]] [[https://www.ibm.com/developerworks/linux/library/l-python-mechanize-beautiful-soup/|tut]] * Scrapy [[http://scrapy.org/|site]](xpath expressions, link extractors, item loaders) * pyquery [[https://pythonhosted.org/pyquery/api.html|api]] [[http://davedash.com/tutorial/pyquery/|tut]] * dokuwiki: [[http://python-dokuwiki.readthedocs.io/en/latest/|dokuwiki interaction]] * embed code editor info: * http://eli.thegreenplace.net/2011/04/01/sample-using-qscintilla-with-pyqt * https://pypi.python.org/pypi/QScintilla#downloads * http://stackoverflow.com/questions/40002373/qscintilla-based-text-editor-in-pyqt5-with-clickable-functions-and-variables * http://pyqt.sourceforge.net/Docs/QScintilla2/ * embed python console info: * code module * http://epydoc.sourceforge.net/stdlib/code.InteractiveConsole-class.html * http://code.activestate.com/recipes/355319-using-codeinteractiveconsole-to-embed-a-python-she/ * https://docs.python.org/3/library/code.html * http://docs.cryengine.com/pages/viewpage.action?pageId=26217213 * http://www.qtcentre.org/threads/29773-Embedding-PyQt4-into-an-Application-running-Python-via-Boost-Python ==== useful automation modules ==== * a online book related: https://automatetheboringstuff.com/#toc * winsys: admin automation for windows * ref: http://timgolden.me.uk/python/winsys/index.html * pywinauto: https://github.com/pywinauto/pywinauto/wiki/UI-Automation-tools-ratings * tutorial: * DevNami - Python Pyautogui Take Screenshot : https://www.youtube.com/watch?v=a6pHYIXqqSg * SF Python - https://www.youtube.com/watch?v=dZLyfbSQPXI * https://automatetheboringstuff.com/ * additional ref: * https://www.youtube.com/watch?v=mhNIHgJPP3g * http://www.programcreek.com/python/index/322/win32gui * selenium: web browser automation * the doc: http://selenium-python.readthedocs.io/installation.html ==== useful Graphic modules ==== * numpy : numerical python * matplotlib : plot graphing tool (my note: [[devwiki:python:matplotlib|python with matplotlib]]) * xlrd : excel read tool * pandas : data structures and data analysis tools (loading datas and data operation like SQL) * http://pandas.pydata.org/ * PyQtGraph : plot graphing tool * Gnuplot : plot tool * ipython : interactive python and visualization tool * OpenEXR * IlmImf, a library that reads and writes OpenEXR images. * Half, a C++ class for manipulating half values * Imath, a math library with support for matrices, 2d- and 3d-transformations, solvers for linear/quadratic/cubic equations, and more. * exrdisplay, a sample application for viewing OpenEXR images at various exposure. * wxPython : wx GUI * PyQt/PySide : Qt GUI * pysqlite/MySQL_python : sql database * Graph (node graph): https://www.nodebox.net/code/index.php/Graph * NetworkX (node graph big): http://networkx.github.io/ ==== useful audio module ==== * pyaudio import pyaudio p = pyaudio.PyAudio() for i in range(p.get_device_count()): print p.get_device_info_by_index(i).get('name') * useful Game building modules * quick tutorial on python openGL game: http://www.youtube.com/watch?v=G0jWMoOEFxc ==== database and file modules ==== * sqlite (built-in): * additional desktop sqlite commandline tools: https://www.sqlite.org/download.html * json (built-in ascii out) * cPickle (built-in binary out) * encryption modules * hashlib (built-in) m = hashlib.md5() m.update(user_input_text) # a sample hash code example if m.hexdigest() != '88888888888888888888888888888888': return * data hashing, like compress data into a string, good for big data compare and record * hash (built-in, not need import) 64bit, take a object and get a int for quick compare * hashlib (built-in, need import) 128bit+ and more option like md5, sha for more secure and digital signiture ==== system info modules ==== * getpass (built-in, user name) getpass.getuser() * glob (built-in, wild char file list) glob.glob(os.path.join(cur_path,prefix)+'_v???.[Mm][abAB]') # get all file named prefix variable _v001 like ma/mb file * stat (built-in, file permission) # lock down file for user, group, other readonly os.chmod(filePath, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) * time (built-in, time related) time.strftime('%Y/%m/%d %H:%M') # 1980/12/31 23:55 format ==== system command modules ==== * subprocess (built-in) * subprocess.Popen don't block your main program subprocess.Popen([r'notepad.exe', r'D:\zTmp\coder.py']);print('ok') * subprocess.call will block the main program till call finish, equals subprocess.call('nircmd.exe win close class "CabinetWClass"') subprocess.call(r'notepad.exe D:\zTmp\coder.py');print('ok') subprocess.Popen([r'notepad.exe', r'D:\zTmp\coder.py']).wait();print('ok') os.system(r'notepad.exe D:\zTmp\coder.py');print('ok') * subprocess.check_call will raise an exception * both return result * Ask System to Open Folder if os.path.isdir(folderPath): if sys.platform == 'darwin': try: subprocess.check_call(['open', '--', folderPath]) except subprocess.CalledProcessError: pass # handle errors in the called executable except OSError: pass # executable not found elif sys.platform == 'linux2': try: subprocess.check_call(['xdg-open', folderPath]) except subprocess.CalledProcessError: pass # handle errors in the called executable except OSError: pass # executable not found elif sys.platform in ['win32','win64']: try: subprocess.check_call(['explorer', folderPath.replace("/","\\")]) except subprocess.CalledProcessError: pass # handle errors in the called executable except OSError: pass # executable not found * check if a process is running appName = 'googledrivesync.exe' info=subprocess.Popen('tasklist.exe /FO CSV /FI "IMAGENAME eq {0}"'.format(appName),stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) out, err = info.communicate() #out = str(out) # for py3 byte convert out = out.decode('ascii') result = [ x for x in out.replace('"','').split('\r\n') if x !='' ] if len(result)>1 and result[1].startswith(appName): print('process found: '+appName) else: subprocess.Popen([r'D:\path_to_app\googledrivesync.exe']) * ask System to open file if sys.platform in ['win32','win64']: os.startfile(filePath) elif sys.platform == 'darwin': os.open(filePath) elif sys.platform == 'linux2': os.xdg-open(filePath) * launch a subprocess to run a Bat file or python file in desktop subprocess.Popen([r'D:\App\Python27\python.exe',r'D:\Dev\Pipeline\PyDesktop\CompFolder\CompFolder.py']) subprocess.Popen([r'D:\Dev\Pipeline\PyDesktop\CompFolder\CompFolder.bat']) # force it to open in new console window instead of inside parent console window subprocess.Popen([r'D:\Dev\Pipeline\PyDesktop\CompFolder\CompFolder.bat'], creationflags=subprocess.CREATE_NEW_CONSOLE) # if above method failed because PATH or PYTHONPATH issue, especially when call like above in a mixed python environment like Maya, # you need to use a clean copy of environment, like this Example env2={} env2['PATH']='''C:\Windows\system32 D:\App\Python27 D:\App\Python27\Lib\site-packages\PyQt4 D:\App\Python27\lib\site-packages\pywin32_system32 '''.replace('\n',';') env2['PYTHONPATH']='''D:\App\Python27\python27.zip D:\App\Python27\DLLs D:\App\Python27\lib D:\App\Python27\lib\plat-win D:\App\Python27\lib\lib-tk D:\App\Python27 D:\App\Python27\lib\site-packages D:\App\Python27\lib\site-packages\win32 D:\App\Python27\lib\site-packages\win32\lib D:\App\Python27\lib\site-packages\Pythonwin '''.replace('\n',';') subprocess.Popen([r'D:\App\Python27\python.exe',r'D:\Dev\Pipeline\PyDesktop\CompFolder\CompFolder.py'], env=env2) subprocess.Popen([r'D:\Dev\Pipeline\PyDesktop\CompFolder\CompFolder.bat'], env=env2) * subprocess a console app and get return, and optionally hide the pop up console when call # hide popup console for win platform only startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= 1 #subprocess.STARTF_USESHOWWINDOW # startupinfo.wShowWindow = subprocess.SW_HIDE #(optional) info=subprocess.Popen( '{0}'.format(app_path),stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo) out, err = info.communicate() out = out.decode('ascii') #str(out) # for py3 byte convert ==== string related ==== * re (built-in, regular expression) # capture group and non-capture group: # http://stackoverflow.com/questions/3512471/what-is-a-non-capturing-group-what-does-a-question-mark-followed-by-a-colon re.findall('([a-zA-Z0-9_]+)_atn(?:Msg)?', 'test_atn') # return ['test'] re.findall('([a-zA-Z0-9_]+)_atn(?:Msg)?', 'test_atnMsg') # return ['test'] # since we only need the prefix, the Msg group is to test exisits ==== compile and de-compile module ==== **cx_Freeze**: compile to exe, app, bin * After compile, the only files need to do partial update each time is (exe + library.zip) **PyInstaller**: compile py into binary, deeper than cx_Freeze, # cmd install python -m pip install pyinstaller # compile, cd to your py file first, you may need copy your supporting folder to dist path after compile python.exe -m PyInstaller MyApp.py # no terminal version python.exe -m PyInstaller MyApp.py --noconsole # set app binary icon python.exe -m PyInstaller MyApp.py --icon=icons/MyApp.ico # exclude tk and tcl library python.exe -m PyInstaller MyApp.py --icon=icons/MyApp.ico --exclude-module=FixTk --exclude-module=tk --exclude-module=tcl --exclude-module=_tkinter --exclude-module=tkinter --exclude-module=Tkinter # for mac, if failed to build on pyconfig.h # - fix pyconfig.h; by cmd: sudo touch /Library/Python/3.8/include/pyconfig.h python.exe -m PyInstaller MyApp.py --icon=icons/MyApp.icns python.exe -m PyInstaller MyApp.py --icon=icons/MyApp.icns -w --onefile # cmd+i to check app info, and drag icns file to app/folder icon logo to set the icon # manually turn folder into app, just add .app behind folder name, folder name must be same as main binary file # when run result mac app on other computer, if security stop it run like "app is damaged", run this command on created app or app folder xattr -cr "/Applications/MyAppFileorMyAppFolder.app" **uncompyle2**: convert pyc to py (python 2.7 code support only) https://github.com/wibiti/uncompyle2 * code example # in the init file main('/pyc_file_dir/', '/pyc_file_dir_decompile_dir/', ['that_pyc_file.pyc'], []) ====== Python Important Modules ====== ===== pip ===== * pip is a quick python module get and installer module for python, it can download module for your python library. * check version python -m pip --version * update it before install other module, make sure you already in python' pip folder path sudo pip install --upgrade pip # or python -m pip install --upgrade pip ===== re ===== * regular expression pattern ^ all data file | (?!(.*[.]db)|(^Keyboard$)|(^[.].*))| ^ all maya file | [^.].+(.ma|.mb|.abc|.xml|.fbx)| * variable name case conversion * CamelCase to "snake_case" or "sentence case" * code: def convert(name, gap='_'): s1 = re.sub('(.)([A-Z][a-z]+)', r'\1'+gap+r'\2', name) # separate more generic AAAABc case to AAAA Bc return re.sub('([a-z0-9])([A-Z])', r'\1'+gap+r'\2', s1) # main conversion #get2HTTPResponseCode > get2_HTTP_Response_Code def convert2(name, gap='_'): return re.sub('((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))', gap+r'\1', name) # main conversion ===== requests ===== * 3rd party module, html get post request response operation library * header list: https://deviceatlas.com/blog/list-of-user-agent-strings * **Single Get web link content** import requests result = requests.get('http://my_site/my_page', timeout=5) print(result.text) * **Single post web link content with login info** result = requests.post('http://my_site/my_page', data={'site_username_field_name': 'your_name', 'site_password_field_name': 'your_pass'}) print(result.text) * **one-time login with continue consistent header info for session operation** with requests.Session() as session: # first time login, reply = session.post('http://site/login_page', data={'site_username_field_name': 'your_name', 'site_password_field_name': 'your_pass'}) print(reply.text) # read rest login-required pages reply = session.get('http://site/other_info_page') print(reply.text) * check send header and received header info print(session_object.headers) # user sending header info print(reply_object.headers) # server replying header info * more function explain result.content # is html in bytes result.text # is html in unicode text * disable non secure cert warning requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning) ===== PIL and Pillow===== * PIL, Python Imaging Library (Fork) = Pillow, install the lib python -m pip install Pillow * python code from PIL import Image, ImageDraw, ImageOps ===== BeautifulSoup ===== * a html info extractor, best works with another parser module "lxml" to get partial info * ref: https://beautiful-soup-4.readthedocs.io/en/latest/#installing-a-parser * parser is a html interprater, as not all html is clean format and tidy, some parser can auto fix some html tag miss match. * example code from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') # html byte from requests.get # find all title link text link_list = soup.find_all("a", {'class':['title', 'threadtitle_unread']} ) # or 'title' only if no multiple name_list = [x.string for x in link_list ] # text element extract link_list[0].attrs['href'] # link url element extract ===== selenium ===== * you need install 2 things to get it working: - Python module: - for py2.7: https://pypi.python.org/pypi/selenium/2.7.0 - for py3.x: https://pypi.python.org/pypi/selenium - system platform dependent webdriver binary: http://www.seleniumhq.org/download/ - for chrome browser automate: go above link and find 3rd binding "Google Chrome Driver" - then you can load that drive binary into python selenium module object to start from selenium import webdriver driver = webdriver.Chrome('/your_path_to_that_binary_driver/chromedriver.exe') driver.get('http://google.com') driver.implicitly_wait(20) driver.get_screenshot_as_file(r'D:\testshot.png') driver.quit() * get element # get css selector by right click browser's inspector view, right click on html element to copy css selector driver.find_element_by_css_selector('.jsb > center:nth-child(1) > input:nth-child(1)') # path method driver.find_element_by_xpath('//input[@name="btnk"]') * element operation * element.get_attribute('href') * element.get_attribute('outerHTML') * element.text * element.click() * element_input.send_keys() and webdriver.common.keys * element_form.submit() * driven_browser.back(), forward(), refresh() * additional tool: * selenium ide firefox - a all-in-one test tool for it: https://addons.mozilla.org/en-US/firefox/addon/selenium-ide/ * tutorial: http://www.seleniumeasy.com/selenium-tutorials/css-selectors-tutorial-for-selenium-with-examples ===== PyAutoGUI ===== * GUI cross-platform GUI interaction automation * ref: https://www.youtube.com/watch?v=dZLyfbSQPXI&t=392s * tutorial: https://www.youtube.com/results?search_query=PyAutoGUI * full list of library required in download page: https://pypi.python.org/pypi/PyAutoGUI * mouse control * click(), doubleClick(), rightClick() * click([x,y]) * moveTo(x,y [,duration=sec]) * moveRel(x_offset, y_offset [,duration=sec]) * dragTo(x,y [,duration=sec]) * position(), size(), * displayMousePosition() # note, that displayMousePosition require 3rd party library # * PIL (Py2.x only, adapted by Pillow) > PIL.ImageGrab > pyscreenze (edit line 309 with "from PIL import ImageGrab") > pyautogui http://www.pythonware.com/products/pil/ https://pypi.python.org/pypi/PyScreeze * keyboard control * typewrite('Text goes here', [,interval=secs]) # pyautogui.KEYBOARD_KEYS * press('pageup') * hotkey('ctrl', 'o') * note: best work with time.sleep(5) to give 5 sec for pc to respond * image recognition * pixel(x,y) # return RGB * screenshot([filename]) # return PIL,Pillow Image object [and save file] * locateOnScreen(imageFilename) # returns (x,y, w, h) or None * linux: scrot * example code import pyautogui as pui pos = pui.locateOnScreen('d:\\zTmp\\test_build.png') pui.click( (pos[0]+pos[2]*0.5 , pos[1]+pos[3]*0.5) ) ===== SikuliX ===== * SikuliX automates anything you see on the screen of your desktop computer running Windows, Mac or some Linux/Unix. Link: http://sikulix.com * tutorial: https://www.youtube.com/watch?v=VdCOg1bCmGo ===== pyautoit ===== * a python binding for AutoIt tool, a windows only automation software * https://github.com/jacexh/pyautoit * AutoIt home page: https://www.autoitscript.com/site/autoit/ * API level interaction ===== pywinauto ===== * a mostly windows only GUI automation module, with mouse, keyboard support on linux * API level interaction ===== pywin32 - win32com =====   * tip and ref: * http://timgolden.me.uk/python/index.html * http://timgolden.me.uk/pywin32-docs/html/com/win32com/HTML/QuickStartClientCom.html * COMbrowser: win32com\client\combrowse.py * install and restart computer to get dll reg refreshed https://sourceforge.net/projects/pywin32/files/pywin32/ (or) python -m pip install pypiwin32 * get windows explorer in taskbar order, return [(title, hwnd int, addressbar url, [top,left,w,h], vis)] import win32com from win32com import client def get_explorer_list(): # win32com: get folder windows in taskbar order; return [(title, hwnd int, addressbar url, [top,left,w,h], vis)] shell = client.Dispatch("Shell.Application") win_list = shell.Windows() result_list = [] for win in win_list: info = [] info.append(win.LocationName) # title name info.append(win.hwnd) # handle value as int info.append(win.LocationURL) # address bar url, eg. file:///C:/Users/Test/Downloads info.append([win.Top, win.Left, win.width, win.height]) # win pixel position info.append(win.visible) # visible info.append(win) # com object result_list.append(info) return result_list ''' full list of property ['ReadyState', 'Busy', 'Container', 'Silent', 'Top', 'RegisterAsDropTarget', 'LocationName', 'Application', 'Offline', 'Document', 'Type', 'ToolBar', 'MenuBar', 'FullScreen', 'Parent', 'TheaterMode', 'Path', 'Name', 'RegisterAsBrowser', 'StatusText', 'Left', 'TopLevelContainer', 'Resizable', 'Width', 'StatusBar', 'HWND', 'Height', 'Visible', 'FullName', 'LocationURL', 'AddressBar'] ''' * get selected item in window explorer # ref: # https://win32com.goermezer.de/microsoft/windows/find-selected-files-in-windows-explorer.html # https://msdn.microsoft.com/en-us/library/windows/desktop/bb787810(v=vs.85).aspx def get_selection_list(win): # win32com: get selection item detail from win COM object item_list = [] folderItems = win.Document.SelectedItems() for i in range(folderItems.Count): tmp_info = [] tmp_info.append(folderItems.Item(i).path) # C:\Users\Test\Downloads\example.zip tmp_info.append(folderItems.Item(i).name) tmp_info.append(folderItems.Item(i).isFolder) tmp_info.append(folderItems.Item(i).size) tmp_info.append(folderItems.Item(i).type) item_list.append(tmp_info) return item_list * explorer window COM object control # control the window COM object to go to a location win.Navigate('file:///C:/Users/Test/Desktop') win.Busy # a check for still in processing # check visibile and make full screen win.FullScreen =1 # make first windows explorer full screen * system operation # get system dir and oShell = win32com.client.Dispatch("Wscript.Shell") print(oShell.SpecialFolders("Desktop")) # change drive letter # ref: http://timgolden.me.uk/python/win32_how_do_i/change-a-drive-letter.html # create windows shortcut and read it shortcut = shell.CreateShortCut("t:\\test.lnk") shortcut.Targetpath = "D:\\tmp" shortcut.save() shortcut = shell.CreateShortCut("t:\\test.lnk") print(shortcut.Targetpath) # get single screen resolution and total screen # ref: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724385(v=vs.85).aspx import win32api w=win32api.GetSystemMetrics(0) # primary screen width h=win32api.GetSystemMetrics(1) # primary screen height vw = win32api.GetSystemMetrics(78) # total screen area width vh = win32api.GetSystemMetrics(79) # total screen area height print('screen resolution: {0}x{1}'.format(w,h)) print('virtual area resolution: {0}x{1}'.format(vw,vh)) ===== ctypes ===== * ctypes is an advanced ffi (Foreign Function Interface) package, ctypes allows to call functions in dlls/shared libraries and wrap libraries in pure Python. ctypes works cross-platform with libffi support. * ref: http://nullege.com/codes/search/ctypes * my doc on windows API and DLL functions [[devwiki:winapi|WinAPI]] * (method 1) get all windows explorer windows in Z order, return [(title, class, [x,y,w,h], hwnd int)] def get_win_order_all(): # ctype: grab folder windows in z order, return [(title, class, [x,y,w,h], hwnd int)] from ctypes import wintypes order_list = [] result_list = [] top = ctypes.windll.user32.GetTopWindow(None) if not top: return order_list length = ctypes.windll.user32.GetWindowTextLengthW(top) buff = ctypes.create_unicode_buffer(length + 1) ctypes.windll.user32.GetWindowTextW(top, buff, length + 1) class_name = ctypes.create_string_buffer(200) ctypes.windll.user32.GetClassNameA(top, ctypes.byref(class_name), 200) r=ctypes.wintypes.RECT() ctypes.windll.user32.GetWindowRect(top,ctypes.byref(r)) # class_name.value in py3 is byte, while py2 is string if isinstance(class_name.value, str): result_list.append( [buff.value, class_name.value, [r.left,r.top,r.right-r.left,r.bottom-r.top], top ]) else: result_list.append( [buff.value, class_name.value.decode('ascii'), [r.left,r.top,r.right-r.left,r.bottom-r.top], top ]) order_list.append(top) while True: next = ctypes.windll.user32.GetWindow(order_list[-1], 2) # win32con.GW_HWNDNEXT if not next: break length = ctypes.windll.user32.GetWindowTextLengthW(next) buff = ctypes.create_unicode_buffer(length + 1) ctypes.windll.user32.GetWindowTextW(next, buff, length + 1) class_name = ctypes.create_string_buffer(200) ctypes.windll.user32.GetClassNameA(next, ctypes.byref(class_name), 200) r=ctypes.wintypes.RECT() ctypes.windll.user32.GetWindowRect(next,ctypes.byref(r)) # class_name.value in py3 is byte, while py2 is string if isinstance(class_name.value, str): result_list.append( [buff.value, class_name.value, [r.left,r.top,r.right-r.left,r.bottom-r.top], next] ) else: result_list.append( [buff.value, class_name.value.decode('ascii'), [r.left,r.top,r.right-r.left,r.bottom-r.top], next] ) order_list.append(next) return result_list full_list = get_win_order_all() visible_list = [x for x in full_list if ctypes.windll.user32.IsWindowVisible(x[-1])] # visible list is actually more useful, 10+ instead 100+ items explorer_list = [x for x in visible if x[1]=='CabinetWClass'] firefox_list = [x for x in visible if x[1]=='MozillaWindowClass'] * (method 2) get all (visible) (windows explorer) windows in Z order, return [(title, class, hwnd as pointer)] def get_win_order_v2(): # ctypes # ref: https://sjohannes.wordpress.com/2012/03/23/win32-python-getting-all-window-titles/ # info (title, class_name, hwnd) window_list = [] # propare windows list passing def window_info_process(hwnd, lParam): if ctypes.windll.user32.IsWindowVisible(hwnd): length = ctypes.windll.user32.GetWindowTextLengthW(hwnd) buff = ctypes.create_unicode_buffer(length + 1) ctypes.windll.user32.GetWindowTextW(hwnd, buff, length + 1) class_name = ctypes.create_string_buffer(200) ctypes.windll.user32.GetClassNameA(hwnd, ctypes.byref(class_name), 200) t_class_name = class_name.value if not isinstance(t_class_name, str): t_class_name = class_name.value.decode('ascii') # py3 fix if t_class_name == 'CabinetWClass': window_list.append( [ buff.value, t_class_name, hwnd ]) return True procObj = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) # execute it ctypes.windll.user32.EnumWindows(procObj(window_info_process), 0) return window_list * (method 3) Break down ctypes hwnd, pid, process_handle into functions modules ''' ref: http://timgolden.me.uk/python/win32_how_do_i/find-the-window-for-my-subprocess.html Window handle → process ID: GetWindowThreadProcessId Process ID → process handle: OpenProcess Process handle → executable path: QueryFullProcessImageName (compare this with your target) Close the process handle: CloseHandle ref: http://www.mengwuji.net/forum.php?mod=viewthread&tid=1432 Windows 2000 = GetModuleFileName() Windows XP x32 = GetProcessImageFileName() Windows XP x64 = GetProcessImageFileName() Windows Vista = QueryFullProcessImageName() Windows 7 = QueryFullProcessImageName() ref: uisoup - utils : https://pypi.python.org/pypi/UISoup https://programtalk.com/python-examples/ctypes.windll.user32.GetWindowThreadProcessId/ https://pypkg.com/pypi/pywinauto/f/pywinauto/win32functions.py ''' def get_win_pid(hwnd): cur_pid = ctypes.c_long() ctypes.windll.user32.GetWindowThreadProcessId(hwnd, ctypes.byref(cur_pid)) return cur_pid def get_process_path(pid): PROCESS_QUERY_INFORMATION = 0x0400 max_unicode_path = 32767 * 2 + 200 file_path_buffer = ctypes.create_unicode_buffer(max_unicode_path) length_path = ctypes.c_ulong(max_unicode_path) pHandle = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_INFORMATION, False, pid) # won't get admin process if not as admin retval = ctypes.windll.kernel32.QueryFullProcessImageNameW(pHandle, 0, file_path_buffer, ctypes.byref(length_path)) if retval == 0: raise Exception('QueryFullProcessImageNameW failed') #ctypes.windll.kernel32.CloseHandle(pHandle) return file_path_buffer.value def get_win_path(hwnd): return get_process_path(get_win_pid(hwnd)) def get_win_rect(hwnd): from ctypes import wintypes r=ctypes.wintypes.RECT() ctypes.windll.user32.GetWindowRect(hwnd,ctypes.byref(r)) return [r.left,r.top,r.right-r.left,r.bottom-r.top] def get_win_title(hwnd): length = ctypes.windll.user32.GetWindowTextLengthW(hwnd) title_buffer = ctypes.create_unicode_buffer(length + 1) ctypes.windll.user32.GetWindowTextW(hwnd, title_buffer, length + 1) return title_buffer.value # AE CS6: AE_CApplication_11.0 def get_win_class(hwnd): class_name = ctypes.create_string_buffer(200) ctypes.windll.user32.GetClassNameA(hwnd, ctypes.byref(class_name), 200) t_class_name = class_name.value if not isinstance(t_class_name, str): t_class_name = class_name.value.decode('ascii') # py3 fix return t_class_name def is_win_top(hwnd): top_hwnd = ctypes.windll.user32.GetTopWindow(None) return hwnd == top_hwnd def get_win_list(visible=1, orderMethod=0): # both method get result # orderMethod uses : ctypes.windll.user32.GetTopWindow # callBackMethod uses: ctypes.windll.user32.EnumWindows win_list = [] if orderMethod: order_list = [] top = ctypes.windll.user32.GetTopWindow(None) if not top: return win_list visible_info = ctypes.windll.user32.IsWindowVisible(top) win_list.append( [ top, visible_info ]) order_list.append(top) while True: next = ctypes.windll.user32.GetWindow(order_list[-1], 2) # win32con.GW_HWNDNEXT if not next: break visible_info = ctypes.windll.user32.IsWindowVisible(next) win_list.append( [next, visible_info] ) # hwnd: as int order_list.append(next) else: # propare windows list passing def window_info_process(hwnd, lParam): visible_info = ctypes.windll.user32.IsWindowVisible(hwnd) win_list.append( [ hwnd, visible_info ]) #hwnd: as LP_c_long return True # ref: http://makble.com/the-story-of-lpclong # function 1: this will get as LP_c_long as hwnd #procObj = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) # function 2: this will get int as hwnd like other win32api function procObj = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_int, ctypes.POINTER(ctypes.c_int)) # execute it ctypes.windll.user32.EnumWindows(procObj(window_info_process), 0) if visible: return [x for x in win_list if x[1]] return win_list * ctypes window operation by hwnd # my_hwnd can be a int or a ctypes int pointer # full function ref: http://www.jasinskionline.com/windowsapi/ref/funca.html # bring window to bring ctypes.windll.user32.SetForegroundWindow(my_hwnd) # close window WM_CLOSE = 0x0010 ctypes.windll.user32.PostMessageA(my_hwnd, WM_CLOSE, 0, 0) # get window x,y,w,h from ctypes import wintypes r=ctypes.wintypes.RECT() ctypes.windll.user32.GetWindowRect(my_hwnd,ctypes.byref(r)) print( [r.left,r.top,r.right-r.left,r.bottom-r.top] ) # move window by x,y,w,h and refresh ctypes.windll.user32.MoveWindow(my_hwnd, 0, 0, 760, 500, True) * mouse, keyboard operation # get mouse position class POINT(ctypes.Structure): _fields_ = [("x", ctypes.c_ulong), ("y", ctypes.c_ulong)] pt = POINT() ctypes.windll.user32.GetCursorPos(ctypes.byref(pt)) print('{0} {1}'.format(pt.x,pt.y)) ctypes.windll.user32.SetCursorPos(1200, 850) # move cursor to 1200,850 (x,y) ctypes.windll.user32.mouse_event(2, 0, 0, 0,0) # left mouse button down ctypes.windll.user32.mouse_event(4, 0, 0, 0,0) # left mouse button up * get and set wallpaper in windows def getWallpaper(): SPI_GETDESKWALLPAPER = 0x0000073 # try: # win32con.SPI_GETDESKWALLPAPER # except AttributeError, attributeError: # raise WinDesktopError, "getWallpaper() not supported on this OS" wallpaper = ctypes.c_buffer("\000" * 256) ctypes.windll.user32.SystemParametersInfoA(SPI_GETDESKWALLPAPER, len(wallpaper), ctypes.byref(wallpaper), 0) return wallpaper.value def setWallpaper(wallpaperPath, conversionPath=None): # Convert to bitmap if necessary wallpaperImage = Image.open(wallpaperPath) if wallpaperImage.format != 'BMP': conversionPath = conversionPath or os.getenv('SystemRoot') wallpaperPath = os.path.join(conversionPath, os.path.splitext(os.path.split(wallpaperPath)[-1])[0] + '.bmp') wallpaperImage.save(wallpaperPath) # Set wallpaper wallpaperPath = ctypes.c_buffer(wallpaperPath) ctypes.windll.user32.SystemParametersInfoA(win32con.SPI_SETDESKWALLPAPER, 0, wallpaperPath, 0) * wallpaper set (win7) the simple version import ctypes SPI_SETDESKWALLPAPER=20 ctypes.windll.user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0, r"D:\Rec\bg2.jpg",0) * set id ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID('com.app.1.0') * get if user is admin print(ctypes.windll.shell32.IsUserAnAdmin()) * system operation # get screen count screen_cnt = ctypes.windll.user32.GetSystemMetrics(80) # get screen resolution screen_x, screen_y = ( ctypes.windll.user32.GetSystemMetrics(78), ctypes.windll.user32.GetSystemMetrics(79) ) **file and folder operation** * show drive letter in use drive_list_data = ctypes.cdll.msvcrt._getdrives() # binary mask in decimal format mask_list = list( '{0:b}'.format(drive_list) )[::-1] A_code = 65 # ascii code of letter A drive_letter_in_use = [ chr(A_code+i) for i in range(len(mask_list)) if mask_list[i]=='1' ] * show file and select file in explorer (return 42) my_filePath = u'C:\\Users\\Public\\Pictures\\Sample Pictures\\Koala.jpg' ctypes.windll.shell32.ShellExecuteW(None, u'open', u'explorer.exe', u'/n,/select,'+my_filePath, None, 1) * open file property window import time import ctypes import ctypes.wintypes SEE_MASK_NOCLOSEPROCESS = 0x00000040 SEE_MASK_INVOKEIDLIST = 0x0000000C class SHELLEXECUTEINFO(ctypes.Structure): _fields_ = ( ("cbSize",ctypes.wintypes.DWORD), ("fMask",ctypes.c_ulong), ("hwnd",ctypes.wintypes.HANDLE), ("lpVerb",ctypes.c_char_p), ("lpFile",ctypes.c_char_p), ("lpParameters",ctypes.c_char_p), ("lpDirectory",ctypes.c_char_p), ("nShow",ctypes.c_int), ("hInstApp",ctypes.wintypes.HINSTANCE), ("lpIDList",ctypes.c_void_p), ("lpClass",ctypes.c_char_p), ("hKeyClass",ctypes.wintypes.HKEY), ("dwHotKey",ctypes.wintypes.DWORD), ("hIconOrMonitor",ctypes.wintypes.HANDLE), ("hProcess",ctypes.wintypes.HANDLE), ) ShellExecuteEx = ctypes.windll.shell32.ShellExecuteEx ShellExecuteEx.restype = ctypes.wintypes.BOOL sei = SHELLEXECUTEINFO() sei.cbSize = ctypes.sizeof(sei) sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_INVOKEIDLIST sei.lpVerb = "properties" sei.lpFile = 'C:\\Users\\Public\\Pictures\\Sample Pictures\\Koala.jpg' sei.nShow = 1 ShellExecuteEx(ctypes.byref(sei)) time.sleep(5) * get clipboard data (ref: https://stackoverflow.com/questions/101128/how-do-i-read-text-from-the-windows-clipboard-from-python) import ctypes def get_clipboard_text(): ctypes.windll.kernel32.GlobalLock.argtypes = [ctypes.c_void_p] ctypes.windll.kernel32.GlobalLock.restype = ctypes.c_void_p ctypes.windll.kernel32.GlobalUnlock.argtypes = [ctypes.c_void_p] ctypes.windll.user32.GetClipboardData.restype = ctypes.c_void_p ctypes.windll.user32.OpenClipboard(0) try: if ctypes.windll.user32.IsClipboardFormatAvailable(1): data = ctypes.windll.user32.GetClipboardData(1) data_locked = ctypes.windll.kernel32.GlobalLock(data) text = ctypes.c_char_p(data_locked) value = text.value ctypes.windll.kernel32.GlobalUnlock(data_locked) return value finally: ctypes.windll.user32.CloseClipboard() # test print(get_clipboard_text()) ===== twisted ===== * network communication: * old version with python 2.7 32bit wheel: https://pypi.python.org/pypi/Twisted/15.0.0 ===== django ===== * a python web server, install by python -m pip install django ===== openpyxl===== * a new excel reader, xlsx format, not old xls format, since now everyone use new excel version * read excel as dictionary (1st key, rest data) def excel2Dict(filename): # import openpyxl # max_row = sheet.max_row # max_column = sheet.max_column wb = openpyxl.load_workbook(filename=filename, read_only=True) records = [] for sheet in wb.worksheets: count = 0 keys = [] for row in sheet.rows: temp = [] for cell in row: if count == 0: keys.append(str(cell.value)) else: temp.append(str(cell.value)) if count > 0: records.append( dict(zip(keys, temp)) ) # else: count += 1 return records * read excel as row data wo empty cell. def excel2Data(filename): # import openpyxl wb = openpyxl.load_workbook(filename=filename, read_only=True, data_only=True) sheet_data = [] for sheet in wb.worksheets: table_data = [] for row in sheet.values: row_data = [] for cell in row: if cell is not None: row_data.append(cell) if len(row_data)>0: table_data.append(row_data) sheet_data.append(table_data) return sheet_data ====== Python by Reference or by Value ====== * my experience found: "pure = assignment will not change original holder's value, but other operation will change original holder's value" * more study on Pointer vs Reference: http://www.learncpp.com/cpp-tutorial/74a-returning-values-by-value-reference-and-address/ * Python variable are all reference, so pass reference to a function, the inside function holds copy of the reference, nothing outside affected, but if inside function reference modify, outside will be affected, since they all store value at same memory location(reference to that location): http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference * http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference * and another clear explanation of python reference vs c++ reference from c++ user by code: https://hbfs.wordpress.com/2011/06/14/python-references-vs-c-and-c/ * here is my study experiment #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Example 1 dict = {} dict['seq']={} for each in 'aa bb cc dd'.split(): dict['seq'][each]=[] list_aa = dict['seq']['aa'] # passing by reference!!! for i in [1,2,3,4,5]: list_aa.append(i) print dict # affect both list_aa and dict temp_list = dict['seq']['aa'] temp_list.append(22) # you are not get a copy of dict entry, but affect orginal dict as well print temp_list print dict # changed ------- because it is a operation # ref: http://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list-in-python temp_list2 = dict['seq']['aa'][:] # actually duplicate the value out, the fastest way temp_list2.append(55) print temp_list2 print dict # stay same #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Example 2 locs = [ [1], [2] ] for loc in locs: # passing by values !!! loc = [] print locs # stay same for loc in locs: loc[0] = loc[0] * 2 print locs # changed ------- because it is a operation #~~~~~~~~~~~~~~~~~~~~~~~~ # Example 3 a=1 b=a b=2 print a # stay the same a=[1] b=a b=[2] print a # stay the same a=[1] b=a b.append(2) print a # changed ------- because it is a operation # thus: assignment will not change original one, but operation will change original one a=[1,2,3] b=a c=[4,5,6] b=c print a # stay the same a=[1,2, [3.1,3.2,3.3] ] b=a[2] c=[4,5,6] b=c print a # stay the same a=[1,2, [3.1,3.2,3.3] ] b=a[2] b=[4,5,6] print a # stay the same a={'first':[3.1,3.2,3.3] } b=a['first'] b=[4,5,6] print a # stay the same a={'first':[3.1,3.2,3.3] } b=a['first'] b[0]=4 print a # changed ------- because it is a operation a=[1,2, [3.1,3.2,3.3] ] b=a[2][:] # fast copy c=[4,5,6] b=c print a # stay the same #~~~~~~~~~~~~~~~~~~~~~~~ # example 4: # ref: http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument # explain: http://effbot.org/zone/default-values.htm def foo(a=[]): a.append(5) return a foo() # changed every time ######################################## # reference ''' # ref: http://stackoverflow.com/questions/9696495/python-when-is-a-variable-passed-by-reference-and-when-by-value Everything in Python is passed and assigned by value (like Java) Every value in Python is a reference (pointer) to an object. Objects cannot be values. Assignment always copies the value (which is a pointer); two such pointers can thus point to the same object. Objects are never copied unless you're doing something explicit to copy them. # ref: http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables ????Everything is passed by object. Rebinding and mutating are different operations ''' ====== Common Python syntax ====== * python 101 - http://www.rexx.com/~dkuhlman/python_101/python_101.html ^comment |# | ^print |print | ^string |var="string" | ^long string |%%varL='''\ whatever '''%% | ^raw string |r"Any dangerous Character here" | ^os navigation | ^file operation | ^string operation | ^lib | ^rename | ^os.chdir('/path') |cd ^tfile=open('t.txt','w') | ^str.replace('o','n') |replace ^os |system ^prefix_remove_fixed | ^os.getcwd() | ^tfile.write('hello') | ^str[2:6] |substring ^glob |wildchar list ^prefix_add_fixed | ^os.ctermid() | ^tfile.close() | ^str1+str2 |concatenate ^re |regular expression ^end_remove_fixed | ^os.uname() | ^tfile.read() | ^str(100) |string convert ^ | ^end_add_fixed | ^os.listdir('/path') | ^tfile.writeline() | ^ | ^ | ^prefix_remove_vary | ^os.mkdir('/path') | ^tfile.readline() | ^[a-c] [abc] |class ^ | ^ | ^os.removedirs('/path') | ^ | ^[%%^%% abc] |not in class ^ | ^ | ^os.rename(src,dst) | ^ | ^a* |may have ^ | ^ | ^os.getenv('HOME') | ^ | ^a+ |must have one ^ | ^ | ^ | ^ | ^a? |may have one ^ | ^ | ^ | ^ | ^a{1,3} |May 1~3 one ^ | ^ | ^ | ^ | ^r”str” |raw string ^ | ^ | ^regular expression | ^ | ^ | ^ | ^ | ^ | ^ | ^ | ^ | ^ | http://docs.python.org/howto/regex.html#regex-howto ====== Python based tool and application ====== * [[http://nadiana.com/animated-terminal-progress-bar-in-python|progress bar in terminal]] * http://sphinx.pocoo.org/ * Python documentation generator * XML to PDF generation using Python * http://www.blog.pythonlibrary.org/2012/07/18/parsing-xml-and-creating-a-pdf-invoice-with-python/ * Python add-on and libs * Python image library (PIL): http://www.pythonware.com/products/pil/ * Python EXIF.py: http://sourceforge.net/projects/exif-py/ * demo of usage: http://snippets.dzone.com/posts/show/4089 * minimal EXIF reader and writer: http://fetidcascade.com/pyexif.html#x * 50 python lib list: http://blog.sina.com.cn/s/blog_4b5039210100g8ho.html * a Chinese blog on python usage: http://blog.sina.com.cn/s/articlelist_1263548705_8_1.html ** Python web applications ** * https://wiki.python.org/moin/WebFrameworks/ * http://www.web2py.com/ * http://webpy.org/ ====== Python GUI ====== * Python GUI option list: http://wiki.python.org/moin/GuiProgramming * web platform: PyJamas * desktop platform: QT, wxWidget * GUI design: * wxGlade: http://wxglade.sourceforge.net/index.php * wxFormBuilder: http://sourceforge.net/projects/wxformbuilder/files/wxformbuilder-nightly/ * IDE: * Eric: http://eric-ide.python-projects.org/index.html ====== wxPython ====== ===== wxPython GUI concept quick guide ===== * main build block * A Frame is a top-level window. ===== wxWidget - wxPython ===== * download: http://www.wxpython.org/download.php * youtube video tutorial: http://wiki.wxpython.org/YouTubeVideoSeries * basic wxPython widget syntax and codes # get wxWidget frame work, import wx # create class, since you are doing a App or a script # inheriate a python window (so-called frame) class myApp(wx.Frame): # constructor, (so-called the initialize function) def __init__(self,parent,id): wx.Frame.__init__(self,parent,id,'My Window', size=(300,200)) panel=wx.Panel(self) #bitmap button pic=wx.Image('img.bmp', wx.BITMAP_TYPE_BMP).ConvertToBitmap() myBtn=wx.BitmapButton(panel, -1, pic, pos=(10,100)) self.Bind(wx.EVT_BUTTON,self.btnAct,myBtn) myBtn.SetDefault() #slider slider=wx.Slider(panel,-1,50,1,100,pos=(10,30), size=(250,-1),style=wx.SL_AUTOTICKS | wx.SL_LABELS) slider.SetTickFreq(5,1) # interval # spinner spinner=wx.SpinCtrl(panel,-1,'',pos=(10,1), size=(90,-1)) spinner.SetRange(1,100) spinner.SetValue(10) # checkbox wx.CheckBox(panel,-1,'Apples',pos=(100,1),size=(60,-1)) wx.CheckBox(panel,-1,'Orange',pos=(160,1),size=(60,-1)) wx.CheckBox(panel,-1,'Banana',pos=(220,1),size=(60,-1)) # combo box mylist=['Apple','Orange','Banana'] cbox=wx.ListBox(panel,-1,(300,1),(80,60),mylist,wx.LB_SINGLE) cbox.SetSelection(0) # event handlers def btnAct(self,event): self.Destroy() if __name__=='__main__': app=wx.PySimpleApp() # application obj frame=myClass(parent=None,id=-1) # frame obj frame.Show() # show frame app.MainLoop() # start app * wxWidget binding for python tutorial: http://zetcode.com/wxpython/introduction/ * 2 Panel App Flow * http://www.blog.pythonlibrary.org/2010/06/16/wxpython-how-to-switch-between-panels/ ===== Common wxPython syntax ===== * prompts #import wx.lib.agw.multidirdialog as MDD import multidirdialog as MDD def showMsg(msg): wx.MessageBox(msg, 'Info', wx.OK | wx.ICON_INFORMATION) import wx.lib.dialogs def showTxt(txt): ask = wx.lib.dialogs.ScrolledMessageDialog(None, txt, "Info") ask.ShowModal() ask.Destroy() def getInput(): tmpT="" ask = wx.TextEntryDialog( None, 'Your input:', 'Input', '1') if ask.ShowModal() == wx.ID_OK: print "Input: %s\n" % ask.GetValue() tmpT = ask.GetValue() ask.Destroy() return tmpT def getFolder(): tmpPath="" dialog = wx.DirDialog ( None, message = 'Select a directory.' ) if dialog.ShowModal() == wx.ID_OK: print 'Directory:', dialog.GetPath() tmpPath = dialog.GetPath() else: print 'No directory.' dialog.Destroy() return tmpPath def getFolders(): tmpPaths="" ask = MDD.MultiDirDialog(None, title="Select folders:", defaultPath='', agwStyle=0) if ask.ShowModal() == wx.ID_OK: tmpPaths = ask.GetPaths() print "You chose the following file(s):" for path in tmpPaths: print path ask.Destroy() return tmpPaths def getFile(): tmpPaths="" wildcard = "Python source (*.py)|*.py|" "All files (*.*)|*.*" ask = wx.FileDialog(None, message="Choose a file", defaultDir="", defaultFile="", wildcard=wildcard,style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR) if ask.ShowModal() == wx.ID_OK: tmpPaths = ask.GetPaths() print "Select file(s):" for path in tmpPaths: print path ask.Destroy() return tmpPaths def saveFile(): tmpPaths="" wildcard = "Python source (*.py)|*.py|" "All files (*.*)|*.*" ask = wx.FileDialog(None, message="Save As", defaultDir="", defaultFile="", wildcard=wildcard,style=wx.SAVE) if ask.ShowModal() == wx.ID_OK: tmpPath = ask.GetPath() print "Save file:", tmpPath ask.Destroy() return tmpPath def getColor(): ask = wx.ColourDialog(None) ask.GetColourData().SetChooseFull(True) if ask.ShowModal() == wx.ID_OK: data = ask.GetColourData() print 'You selected: %s\n' % str(data.GetColour().Get(includeAlpha=False)) ask.Destroy() return data.GetColour().Get(includeAlpha=False) def getChoice(): tmpC="" ask = wx.SingleChoiceDialog( None, "Select a choice", 'The direction', ["Up", "Down", "Left", "Right"], wx.CHOICEDLG_STYLE ) if ask.ShowModal() == wx.ID_OK: tmpC = ask.GetStringSelection() print 'Choice: %s\n' % ask.GetStringSelection() ask.Destroy() return tmpC def getChoices(): tmpCs=[] list = ["Photo", "Movie", "Docs"] ask = wx.MultiChoiceDialog( None, "Select the choices", "wx.MultiChoiceDialog", list) if (ask.ShowModal() == wx.ID_OK): selections = ask.GetSelections() strings = [list[x] for x in selections] print "You chose:" + str(strings) tmpCs = strings ask.Destroy() return tmpCs application = wx.PySimpleApp() * all dialog reference: * http://www.blog.pythonlibrary.org/2010/06/26/the-dialogs-of-wxpython-part-1-of-2/ * http://www.blog.pythonlibrary.org/2010/07/10/the-dialogs-of-wxpython-part-2-of-2/ ====== PyQt ====== * check [[devwiki:python_qt|Qt and Python]] ====== Python Portable for Windows ====== * since all mac and linux have python built-in **Workflow on portable python** - Prepare python 2.7/3.5, by download the official python exe, and install it to D drive * https://www.python.org/ * for Python3.5.2: Windows x86 executable installer * for Python2.7.12: Windows x86 MSI installer - update: for PyQt and PySide, just cd to that python directory and .\python.exe -m pip install PySide or PyQt4 to install that module with pip or ./python for mac/linux - Prepare PyQt4 library for py2.7/3.5 by download the official, and install to the correct PythonX.X folder * https://www.riverbankcomputing.com/software/pyqt/download * for Python3.5: PyQt4-4.11.4-gpl-Py3.4-Qt4.8.7-x32.exe * for python2.7: PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x32.exe - other library: * cx_Freeze ====== Python Portable for Mac ====== * Python 2.7 is built-in in Mac at /System/Library/Frameworks/Python.framework/Versions/2.7/ * There are many articles on install latest python 2.7 and 3.x version with many methods, like homebrew and offical python site, while my idea is not touch any system path or system environment, be portable means, the system dont even need to know my personal python app is there, like windows portable version * the advantage is you choose which python to run the py script * the disadvantage is you can't default python the_script.py in your command line, so you should always use a launch bash script to dynamically use which python path and open the script with it. * check my App_V9.bat launch for windows: https://github.com/shiningdesign/universal_tool_template.py/blob/master/App_V9.bat **Standard Install Python 3.8** * download and install python3 installer * download and install command line tools for xcode latest (use normal Apple acc to login) * https://developer.apple.com/download/ * install PySide2 (with user flag that fixes permission issue) pip3 install PySide2 --user * now python3 work in terminal app * when first run, allow Access folder right. * to make command extension file runable, do bash for the command extension launcher chmod 755 App_V9.command ====== Python Cool Tricks and Notes ====== * start HTML and FILE server in current directory python -m SimpleHTTPServer 8181 * decimal vs float for real life accounting usage: * decimal wont have those float annoying issue with tons of 0s after . * decimal deal number like human do instead of infinite computing accuracy * https://towardsdev.com/python-tips-decimal-vs-float-72fe72fb7086 * https://www.laac.dev/blog/float-vs-decimal-python/ * from decimal import Decimal; a = Decimal(0.01) * python and whatsapp msg * ref: https://iq.opengenus.org/python-script-to-send-whatsapp-message/ * **pywhatkit**: use web client to automate msg sending, make sure it on main screen (multi screen case) * because it use automation, so interaction with browser can be buggy, no quick repeat sending (since automate like human action, need wait response of other app update), send group chat may send to wrong group if you also interact with browser * example import pywhatkit pywhatkit.sendwhatmsg_instantly("+88123456",auto_url,10,True,3) # wait 10s to ui response, close tab true after 3s, # you need to close tab as whatsapp web only allow 1 window active * **selenium**: use selenium browser automate driver to operate, since it is linking to a dedicated browser with browser api, it is more reliable to send fast msg and maintain connection, no user interaction affection * example setup and login manually for first time my_drive = None def drive_setup(): from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.by import By my_drive = webdriver.Chrome() phone_no = "+881234567" # target phone or your own phone as target my_drive.get(f'https://web.whatsapp.com/send?phone={phone_no}&text=') def drive_msg(in_text): from selenium.webdriver.common.by import By if my_drive is None: return else: chat_box = my_drive.find_element(by=By.XPATH, value='/html/body/div[1]/div/div/div[4]/div/footer/div[1]/div/span[2]/div/div[2]/div[1]/div/div/p') chat_box.send_keys(in_text) send_button = my_drive.find_element(by=By.CSS_SELECTOR, value='[data-icon="send"]') send_button.click() ====== Python and interaction with other API ====== Telegram - search @BotFather on telegram * manual: https://core.telegram.org/bots/api - in the chat, type /newbot, then type your bot "botname", then type your bot "botusername_bot" - now, your bot api key will show up, copy and save it - now search your bot "botusername_bot" to start chat with it - in python, use requests to get the chat from the bot, try one more time if no result import requests the_key = "api_key" url = "https://api.telegram.org/bot{0}/getUpdates".format(the_key) response = requests.get(url) result = response.json() print(result) - once you got result in json, you will find the chat id. result['result'] # the list of all chat spec your bot received, yours is likely the first one. my_chat_info = result['result'] my_msg_info = my_chat_info[0]['message'] # it got info of: chat, date, from, message_id, text my_chat_id = my_msg_info['chat']['id'] - to send a text to that chat from your bot side reply_text = 'hello world' url = "https://api.telegram.org/bot{key}/sendMessage?chat_id={id}&text={reply}".format(**{'key':the_key, 'id':my_chat_id,'reply':reply_text}) response = requests.get(url) - now, you should have got the reply from your bot result = response.json() send_state = result['ok'] send_result = result['result'] # chat (first_name, id, type); date:int; message_id; text ====== Python and Networking related ====== * above is python interact with a REST API server, you can also use python to build your own REST API server to handle requests from other application, even other application over the network and internet. * implement REST API into python, you may need to use some python module like Flash, FastAPI, then you start another thread from your python application to run your REST API server. * while using Sockets method may be simpler if you just want to send some simple message between applications, as REST API, you need write all the API URL end point response. * using REST API allow your application to talk cross different application and difference device, and provide a safe gate to your important data handled by your application.