0

I'm currently trying to run a python script by calling the main function in a different python file. The script opens up a file, refreshes it and publishes it. I'm looking at refreshing multiple files (so essentially calling the main function multiple times from a different python file)

How can I split my main() function into one which parses the arguments, and one which actually implements some logic to process those arguments?

Thank you.

The code is the following:

import time
import os
import sys
import argparse
import psutil
from pywinauto.application import Application
from pywinauto import timings

def type_keys(string, element):
    """Type a string char by char to Element window"""
    for char in string:
        element.type_keys(char)

def main():   
    # Parse arguments from cmd
    parser = argparse.ArgumentParser()
    parser.add_argument("workbook", help = "Path to .pbix file")
    parser.add_argument("--workspace", help = "name of online Power BI service work space to publish in", default = "My workspace")
    parser.add_argument("--refresh-timeout", help = "refresh timeout", default = 30000, type = int)
    parser.add_argument("--no-publish", dest='publish', help="don't publish, just save", default = True, action = 'store_false' )
    parser.add_argument("--init-wait", help = "initial wait time on startup", default = 15, type = int)
    args = parser.parse_args()

    timings.after_clickinput_wait = 1
    WORKBOOK = args.workbook
    WORKSPACE = args.workspace
    INIT_WAIT = args.init_wait
    REFRESH_TIMEOUT = args.refresh_timeout

    # Kill running PBI
    PROCNAME = "PBIDesktop.exe"
    for proc in psutil.process_iter():
        # check whether the process name matches
        if proc.name() == PROCNAME:
            proc.kill()
    time.sleep(3)

    # Start PBI and open the workbook
    print("Starting Power BI")
    os.system('start "" "' + WORKBOOK + '"')
    print("Waiting ",INIT_WAIT,"sec")
    time.sleep(INIT_WAIT)

    # Connect pywinauto
    print("Identifying Power BI window")
    app = Application(backend = 'uia').connect(path = PROCNAME)
    win = app.window(title_re = '.*Power BI Desktop')
    time.sleep(5)
    win.wait("enabled", timeout = 300)
    win.Save.wait("enabled", timeout = 300)
    win.set_focus()
    win.Home.click_input()
    win.Save.wait("enabled", timeout = 300)
    win.wait("enabled", timeout = 300)

    # Refresh
    print("Refreshing")
    win.Refresh.click_input()
    #wait_win_ready(win)
    time.sleep(5)
    print("Waiting for refresh end (timeout in ", REFRESH_TIMEOUT,"sec)")
    win.wait("enabled", timeout = REFRESH_TIMEOUT)

    # Save
    print("Saving")
    type_keys("%1", win)
    #wait_win_ready(win)
    time.sleep(5)
    win.wait("enabled", timeout = REFRESH_TIMEOUT)

    # Publish
    if args.publish:
        print("Publish")
        win.Publish.click_input()
        publish_dialog = win.child_window(auto_id = "KoPublishToGroupDialog")
        publish_dialog.child_window(title = WORKSPACE).click_input()
        publish_dialog.Select.click()
        try:
            win.Replace.wait('visible', timeout = 10)
        except Exception:
            pass
        if win.Replace.exists():
            win.Replace.click_input()
        win["Got it"].wait('visible', timeout = REFRESH_TIMEOUT)
        win["Got it"].click_input()

    #Close
    print("Exiting")
    win.close()

    # Force close
    for proc in psutil.process_iter():
        if proc.name() == PROCNAME:
            proc.kill()

        
if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        print(e)
        sys.exit(1)
  • What is the actual problem you need help with? Your code does not appear to attempt to `import` a file and run the `main` function inside it. The Python code to do this should be trivial anyway. – tripleee Jan 25 '22 at 10:53
  • @tripleee that's what I can't figure out, I have tried to import the main python file but I don't know how to call it from my other file. It has only worked for me using the CMD. – David Gorgan Jan 25 '22 at 10:55
  • 1
    `from somewhere import main; main()` or `import something; something.main()` – tripleee Jan 25 '22 at 10:56
  • @tripleee, this question isn't about calling a function from another file, it's about separating the argument parsing from the rest of the code. – joerick Jan 25 '22 at 11:02
  • 1
    @joerick The above comment seems to confirm my understanding of the question. If the OP really has a different need, the request to [edit] to clarify what they actually want is still pertinent. – tripleee Jan 25 '22 at 11:04
  • @joerick yes exactly - I wanted to ask if there is a way of separating the argument parsing and setting up an additional file where I can call it separately rather than using the CMD. – David Gorgan Jan 25 '22 at 11:07
  • @tripleee, apologies - I'm new to this so I don't really know how to explain – David Gorgan Jan 25 '22 at 11:07
  • @tripleee well consider why it has only worked at the command line. It seems to me that even if you called main from another script, it's going to try to parse arguments. That's the issue here. – joerick Jan 25 '22 at 11:07
  • So the question is "how can I split my `main()` function into one which parses the arguments, and one which actually implements some logic to process those arguments"? I'm sure there's a duplicate for that as well. – tripleee Jan 25 '22 at 11:10
  • okay. well, that would be better than the current close at least. but I would note that you closed the question without understanding it (or giving any other users a chance to read/understand it too!) – joerick Jan 25 '22 at 11:15
  • The guidance is to close unclear questions, and reopen when the OP clarifies. Simply closing is less helpful than at least trying to find an existing question which hopefully matches what they were trying to ask, or at least help them see how their question is being understood. – tripleee Jan 25 '22 at 11:19
  • @joerick I'll reopen this and hope you will post an answer if you can guess what the OP means. We are generally not in the business of mind-reading, though. – tripleee Jan 25 '22 at 11:22

1 Answers1

1

Yes, you need to factor out the argument parsing from the actual work of the script. Something like this should work:

import time
import os
import sys
import argparse
import psutil
from pywinauto.application import Application
from pywinauto import timings

def type_keys(string, element):
    """Type a string char by char to Element window"""
    for char in string:
        element.type_keys(char)

def refresh_file(workbook, workspace, init_wait, refresh_timeout, should_publish):
    # Kill running PBI
    PROCNAME = "PBIDesktop.exe"
    for proc in psutil.process_iter():
        # check whether the process name matches
        if proc.name() == PROCNAME:
            proc.kill()
    time.sleep(3)

    # Start PBI and open the workbook
    print("Starting Power BI")
    os.system('start "" "' + workbook + '"')
    print("Waiting ",init_wait,"sec")
    time.sleep(init_wait)

    # Connect pywinauto
    print("Identifying Power BI window")
    app = Application(backend = 'uia').connect(path = PROCNAME)
    win = app.window(title_re = '.*Power BI Desktop')
    time.sleep(5)
    win.wait("enabled", timeout = 300)
    win.Save.wait("enabled", timeout = 300)
    win.set_focus()
    win.Home.click_input()
    win.Save.wait("enabled", timeout = 300)
    win.wait("enabled", timeout = 300)

    # Refresh
    print("Refreshing")
    win.Refresh.click_input()
    #wait_win_ready(win)
    time.sleep(5)
    print("Waiting for refresh end (timeout in ", refresh_timeout,"sec)")
    win.wait("enabled", timeout = refresh_timeout)

    # Save
    print("Saving")
    type_keys("%1", win)
    #wait_win_ready(win)
    time.sleep(5)
    win.wait("enabled", timeout = refresh_timeout)

    # Publish
    if should_publish:
        print("Publish")
        win.Publish.click_input()
        publish_dialog = win.child_window(auto_id = "KoPublishToGroupDialog")
        publish_dialog.child_window(title = workspace).click_input()
        publish_dialog.Select.click()
        try:
            win.Replace.wait('visible', timeout = 10)
        except Exception:
            pass
        if win.Replace.exists():
            win.Replace.click_input()
        win["Got it"].wait('visible', timeout = refresh_timeout)
        win["Got it"].click_input()

    #Close
    print("Exiting")
    win.close()

    # Force close
    for proc in psutil.process_iter():
        if proc.name() == PROCNAME:
            proc.kill()

def main():   
    # Parse arguments from cmd
    parser = argparse.ArgumentParser()
    parser.add_argument("workbook", help = "Path to .pbix file")
    parser.add_argument("--workspace", help = "name of online Power BI service work space to publish in", default = "My workspace")
    parser.add_argument("--refresh-timeout", help = "refresh timeout", default = 30000, type = int)
    parser.add_argument("--no-publish", dest='publish', help="don't publish, just save", default = True, action = 'store_false' )
    parser.add_argument("--init-wait", help = "initial wait time on startup", default = 15, type = int)
    args = parser.parse_args()

    timings.after_clickinput_wait = 1

    refresh_file(
        workbook=args.workbook, 
        workspace=args.workspace, 
        init_wait=args.init_wait, 
        refresh_timeout=args.refresh_timeout, 
        should_publish=args.publish
    )

        
if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        print(e)
        sys.exit(1)

So here I created a function called refresh_file and called it using the main() function. But now, you can call this refresh_file from elsewhere too, so if this code was in somefile.py, you could do import refresh_file from somefile in a different file and call it directly.

joerick
  • 16,078
  • 4
  • 53
  • 57