Running a cmd command in Python - python-3.x

I am having a problem that I have been spending quite a lot of time on. I have a few lines of code that I run through a bat file, that I would like to run from a Python script instead. This is so that I can feed in variables and create the cmd string throug Python code.
The code is used to run Tableau bridge client to sync a data extract. This is the code and it works when I run it from a BAT file:
#echo off
cd C:\Program Files\Tableau\Tableau 10.3\bin
tableau refreshextract --server https://dub01.online.tableau.com --username "username" --password "password" --site "sitename" --project "project name" --datasource "datasource name" --source-username sql_backend_username --source-password sql_backend_password
I understand that the first line sets the working directory to the folder where Tableau is installed. And the second line does the refreshing.
I have been trying to make this work in Python by just doing something like this:
import os
os.chdir("C:\\Program Files\\Tableau\\Tableau 10.3\\bin")
os.system("tableau -cmd_string_from_above
but all that this does is run the Tableau client, and not the process running the extract. I have been looking at some examples using popen but all of that code is so complex that I dont understand how it actually works.
Hope someone can help me out.

If it works as a bat file, try running that from python.
os.system("start mybatch.bat")

I would recommend you look at the module subprocess
as and example:
subprocess.call(["C:\\Program Files\\Tableau\\Tableau 10.3\\bintableau", "refreshextract", "etc. etc."])
a simpler example:
from subprocess import call
call(["ping", "localhost"])

Ok so building on the code/methods other sugested here I did manage to get it working. It might be kind if a "hacky" solution, but it looks like it is working ok. Here is the example
import json
import os
import subprocess
def refresh_extract(project_name, datasource_name):
#Json file containing most of the variables used
params = json.load(open('all_paths.json'))
server = params['tableau']['server']
username = params['tableau']['username']
password = params['tableau']['password']
site = params['tableau']['site']
source_username = params['tableau']['source-username']
source_password = params['tableau']['source-password']
filepath = "Path to bat file that is called"
executable = os.path.join(filepath, 'tableau_refresh.bat')
#Set the working dir to dir where tableau files used for the call is stored, this is the "hacky" part, needed for the bat to find tableau
os.chdir("C:\\Program Files\\Tableau\\Tableau 10.3\\bin")
p = subprocess.Popen([executable, '%s' %server, '%s' %username, '%s' %password, '%s' %site, '%s' %project_name, '%s' %datasource_name, '%s' %source_username, '%s' %source_password])
return 0
if __name__ == "__main__":
project_name = "project_name"
datasource_name = "data_source_name"
run = refresh_extract(project_name, datasource_name)
Thanks a lot to everyone that helped me figure it out!
This is the code for the bat file just in case it could help someone else
#echo off
#this seems not to be working, therefore I set the working did using
#os.chdir
cd C:\Program Files\Tableau\Tableau 10.3\bin
tableau refreshextract --server %1 --username %2 --password %3 --site %4 --
project %5 --datasource %6 --source-username %7 --source-password %8
PAUSE

Related

Python 3.8: How does one pass a variable to a Windows CMD subprocess?

Up front confession... I'm a python neophyte. Please forgive any ignorance on my part.
As just a way to learn more, I'm trying to write a script that will take my latest Quicken backup and with 7-Zip, create a compressed and encrypted file with a timestamp in the name. I then want to copy it two two locations.
I have succeeded up the the name part. I've created a variable for the time the script starts and I want to append this to a base file name, but I don't seem to be able to do it. When I've tried, the script runs, but nothing is ever created, no compressed file that is. If I remove what I have with regard to the variable for the filename, I do get a compressed and encrypted file as expected.
Here is what I have so far. The print commands are just there for me making sure I've done the 'today' and 'newfile' variables correctly. Also, I'm doing the testing with just an empty .docx file so that it processes quicker.
Thanks in advance for any/all help or suggestions. I really appreciate it.
from datetime import datetime
from pathlib import Path
today = datetime.now()
print(today.strftime('%Y-%m-%d %H:%M:%S'))
newfile = 'Q2020_' + (today.strftime('%m-%d-%Y_%H%M%S'))
print(newfile)
os.chdir('D:/Quicken Backups')
print(os.getcwd())
import subprocess
cmd= ['C:\\Program Files\\7-Zip\\7z.exe', 'a', '-t7z', '-mx9', '"D:\\Quicken Backups\\Quicken2020\\" + newfile ".7z"', '-ppassword', '-mhe', 'D:\\Quicken Backups\\test.docx']
subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
Have you thought about using a python package made for zipping, like zipfile?
This way you dont need to deal with opening a subprocess
import zipfile
dest_zip_folder = '2020_backup.zip' # new file name
file_to_zip = 'D:\\Quicken Backups\\test.docx'
zipfile.ZipFile(dest_zip_folder, mode='w').write(file_to_zip)
If you dont want to use that way, I see an error in your code.
You are missing a + after newfile
cmd = [ ...., .... + newfile + '.7zip', ... ]
Also give subprocess.call() a try
import subproccess
cmd = [. . . . . .]
subprocess.call(cmd)
It took a LOT of mucking around with Windows variables syntax and running the subprocess a little differently, but I finally got the thing working, outputting an encrypted file with a date/time stamp in the file name.
For troubleshooting I added the /K to the cmd command so that the window would not close upon completion. This was a HUGE help in trouble shooting this.
Thanks to everyone who even looked at my posted. I hope someday this thread will help someone else!
import os
from pathlib import Path
os.chdir('D:/Quicken Backups')
print(os.getcwd())
import subprocess
cmd = subprocess.Popen('cmd.exe /K ""C:\\Program Files\\7-Zip\\7z.exe" a -t7z -mx9 "D:\\Quicken Backups\\Quicken2020\\Q2020_%DATE:~4,2%-%DATE:~7,2%-%DATE:~-4%_%TIME:~0,2%%TIME:~3,2%%TIME:~8%.7z" -ppassword -mhe "D:\\Quicken Backups\\test.docx"')

Start EXE-file with parameters via Groovy (problems with return value)

I am trying to start an external executable file via Groovy but got some problems with it! I just want to start the rs.exe with several parameters to create a PDF-file using the SSRS.
But as soon as I try to get the return value/exit-code it doesn't work anymore! But I want to grab the generated file and add it to a database, so I need a return value to know when its generated. This works totally fine for generating:
def id = 1
def cmd = """ C://Program Files (x86)//...//rs.exe
-i C:\\export.rss
-s http://localhost/ReportServer_SQLEXPRESS
-v ID=${id}
-e Exec2005 """
def proc = cmd.execute()
But I don't get any return value/exit-code. I already tried different way, e.g.
proc.waitFor()
but I or
cmd.execute().value
but nothing worked. When I start the rs.exe with all my provided data in Windows I get the return "Process succesfully ended". Any Groovy-specialists here that can help me out?
Try executing command when it's defined in the following way:
def cmd = ['cmd', '/c', 'C://Program Files (x86)//...//rs.exe', '-i', 'C:\\export.rss', '-s', 'http://localhost/ReportServer_SQLEXPRESS', '-v', "ID=${id}", '-e', 'Exec2005']
def proc = cmd.execute()
I was able to run it now and get the exit-code. But without those escape forward-slashes I wasn't able to let it run. To get the exit-codes I just used "proc.text" and it works perfectly now.
It was working before but I didn't know how to get the exit-codes, ".text" solved it completely. Thanks for your help!

Shell reading and saveing to config.cfg file?

I am still very new to shell since I have been using it with linux recently, and I tried to mess with a game called garrysmod and make a little script that will ask for information to run the server, its IP, playerslots, etc. Now I somewhat got this working, but I want to be able to save and load this to a config file. I figure out how to get it load from the config, but I want to be able to edit it from the command prompt when it asks you if you would like to edit it.
This is what I have so far as an example:
setup.sh
source config.cfg
echo "Servers current name is $name"
echo
echo "What would you like the name to be?"
read $name
read "The new name is $name"\
config.cfg
name='ServerName'
address=127.0.0.1
port=27015
map='ttt_mapnamehere.bsp'
playercap=32
Now it works after you change it, but I don't know how to get it to save to the .cfg file. The reason of this is because several .sh files will run in order as you go through the steps, and at the end the file one will pull data from the config file being the IP, port, map name, player count, etc. If someone can show me how to do this (examples as Im a visual learner) that would be great!
Simply write it back:
...
printf "name='%s'\naddress='%s'\nport=%s\nmap='%s'\nplayercap=%s\n" \
"$name" "$address" "$port" "$map" "$playercap" > config.cfg

How to convert Balsamiq mockups to text strings txt with Python34 script on Windows XP

I've been trying to run these scripts https://github.com/balsamiq/mockups-strings-extractor within XP. I'm getting errors per this screenshot https://www.dropbox.com/s/rlbqp1iytkwvq3m/Screenshot%202014-05-30%2011.57.48.png
Also I tried CD into my test directory and although a text output file is generated it is empty and I still get these errors https://www.dropbox.com/s/odjfbr97e5i4gnn/Screenshot%202014-05-30%2012.09.31.png
Is anybody running Balsamiq on windows able to make this work ?
1) From the looks of the first error pic you included, you were trying to execute a Windows Shell command inside of a Python Interpreter. If you've still got the window open, type quit() before attempting your command again.
2) Your script was written for Python 2.x. If you're using Python 3.x, you'll need to add parentheses to the print lines in the script file and change urllib to urllib.parse. I made the changes below:
import os
import glob
import re
import urllib.parse
for infile in glob.glob( os.path.join(".", '*.bmml') ):
print("STRINGS FOUND IN " + infile)
print("===========================================================")
f = open (infile,"r")
data = f.read()
p = re.compile("<text>(.*?)</text>")
textStrings = p.findall(data)
print(urllib.parse.unquote('\n'.join(textStrings))+"\n")
f.close()
Hope this helps.

Testing python programs without using python shell

I would like to easily test my python programs without constantly using the python shell since each time the program is modified you have to quit, re-enter the python shell and import the program again. I am using a 2012 Macbook pro with OSX. I have the following code:
import sys
def read_strings(filename):
with open(filename) as file:
return file.read().split('>')[1:0]
file1 = sys.argv[1]
filename = read_strings(file1)
Essentially I would like to read into and split a txt file containing:
id1>id2>id3>id4
I am entering this into my command line:
pal-nat184-102-127:python_stuff ceb$ python3 program.py string.txt
However when I try the sys.argv approach on the command line my program returns nothing. Is this a good approach to testing code, could anyone point me in the correct direction?
This is what I would like to happen:
pal-nat184-102-127:python_stuff ceb$ python3 program.py string.txt
['id1', 'id2', 'id3', 'id4']
Let's take this a piece at a time:
However when I try the sys.argv approach on the command line my
program returns nothing
The final result of your program is that it writes a string into the variable filename. It's a little strange to have a program "return" a value. Generally, you want a program to print it's something out or save something to a file. I'm guessing it would ease your debugging if you modified your program by adding,
print (filename)
at the end: you'd be able to see the result of your program.
could anyone point me in the correct direction?
One other debugging note: It can be useful to write your .py files so that they can be run both independently at the command line or in a python shell. How you've currently structured your code, this will work semi-poorly. (Starting a shell and then importing your file will cause an error because sys.argv[1] isn't defined.)
A solution to this is to change your the bottom section of your code as follows:
if __name__ == '__main__':
file1 = sys.argv[1]
filename = read_strings(file1)
The if guard at the top says, "If running as a standalone script, then run what's below me. If you imported me from some place else, then do not execute what's below me."
Feel free to follow up below if I misinterpreted your question.
You never do anything with the result of read_strings. Try:
print(read_strings(file1))

Resources