devwiki:python

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

Python notebook

online:

local

  • pip install jupyterlab
  • go scripts folder, there is a binary file to run,
    jupyter lab

Install related

  • Mac has its own python install, very old, only for basic usage
  • to install Python3 from official python website,
    1. download python 3 for mac installer
    2. install as usual and done
    3. run python3 in cmd
    4. then it pops: “python3” command requires the “the commandline developer tools” to install, click install
    5. 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
    6. go Apple developer downloads page, search command line tools for xcode, download that and install

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
      test.batch
      @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

Python basics

My Wiki Page related

to read:

  • 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 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
  • 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 path
    import 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 exists
    os.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)
  • 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))
  • 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
  • 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
  • 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 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) (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__
  • a file can be a module like
    import FileName
    FileName.functionName() # call function side that file
  • 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 initpy 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
      __init__.py
      import os, sys
      my_path = os.path.dirname(__file__)
      my_path in sys.path or sys.path.append(my_path)
  • python code
    help(moduleName)
    dir(moduleName)
    #import moduleName
    #then type moduleName to show location
  • check module in shell command
    pydoc moduleName
  • change current working path
    os.chdir('/my_path/')
  • 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('<html><head><link rel="stylesheet" type="text/css" href="s1.css"></head>\n<body>'+'\n')
              for line in f:
                  lineClean=line.strip()
                  if lineClean.startswith('//=='):
                      h.write('<h1>'+lineClean.replace('//==','').replace('=','')+'</h1>'+'\n')
                  elif lineClean.startswith('global proc'):
                       h.write('<h5>'+lineClean.replace('{','').replace('global proc ','')+'</h5>'+'\n')
                  elif lineClean.startswith('/**'):
                       h.write('<p>'+lineClean.replace('*/','').replace('/**',' - ')+'</p>'+'\n')
              h.write('</body></html>'+'\n')
          h.close()
       
      if __name__=="__main__":
          viewMel_html(sys.argv[1],sys.argv[1].replace('.mel','.html'))
  • 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)
  • 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('</span',(color+'</span')))
      else:
        sys.stdout.write(line)
  • 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"<table border=1>\n"
    i=0
    for each in a:
        i=i+1;
        txt=txt+u"<tr><td><a href='{link}'>{title}</a></td><td>{code}</td><td>{idx}</td><tr>\n".format(link=each['link'], title=each['title'],code=each['code'], idx=i)
     
    txt=txt+u'</table>'
     
    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
  • 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
    1. 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
    2. 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
  • numpy : numerical python
  • matplotlib : plot graphing tool (my note: python with matplotlib)
  • xlrd : excel read tool
  • pandas : data structures and data analysis tools (loading datas and data operation like SQL)
  • 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
  • NetworkX (node graph big): http://networkx.github.io/
  • 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
  • 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
  • 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
  • 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
  • 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

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 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 
  • 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
  • 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, Python Imaging Library (Fork) = Pillow, install the lib
    python -m pip install Pillow
  • python code
    from PIL import Image, ImageDraw, ImageOps
  • a html info extractor, best works with another parser module “lxml” to get partial info
    • 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
  • you need install 2 things to get it working:
    1. Python module:
    2. system platform dependent webdriver binary: http://www.seleniumhq.org/download/
      1. for chrome browser automate: go above link and find 3rd binding “Google Chrome Driver”
    3. 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()
  • 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) )
  • a mostly windows only GUI automation module, with mouse, keyboard support on linux
    • API level interaction

  * tip and ref:

  • 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 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.
  • (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())
  • a python web server, install by
    python -m pip install django
  • 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”
  • 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

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

Python GUI

wxPython

  • main build block
    • A Frame is a top-level window.
  • 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/
  • 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:

PyQt

Python Portable for Windows

  • since all mac and linux have python built-in

Workflow on portable python

  1. Prepare python 2.7/3.5, by download the official python exe, and install it to D drive
      • for Python3.5.2: Windows x86 executable installer
      • for Python2.7.12: Windows x86 MSI installer
  2. 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
  3. Prepare PyQt4 library for py2.7/3.5 by download the official, and install to the correct PythonX.X folder
  4. 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

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)
  • 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

  • python and whatsapp msg
    • 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

  1. search @BotFather on telegram
  2. in the chat, type /newbot, then type your bot “botname”, then type your bot “botusername_bot”
  3. now, your bot api key will show up, copy and save it
  4. now search your bot “botusername_bot” to start chat with it
  5. 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)
  6. 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']
  7. 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)
  8. 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.
  • devwiki/python.txt
  • Last modified: 2024/06/20 07:24
  • by ying