Reputation: 345
I am hoping to use AppleScript to launch a Python script which has as its first few lines:
x = datetime.datetime.now()
varyear = str(x.year)
varday = str(x.day).zfill(2)
varmonth = str(x.month).zfill(2)
dateStamp = varyear + '-' + varday + '-' + varmonth
userDate = ""
userDate = input("Enter date of Bookmap replay data as YYYY-DD-MM: ")
if userDate != "":
dateStamp=userDate
When running the Python script from Terminal (on a Mac), I have no problems: I am prompted for a date and if I do not provide one, the script uses the current date.
However, when initiating the Python script from AppleScript I am unable to provide input, as the EOF error is thrown immediately.
My entire AppleScript consists of
do shell script "source ~/.bash_profile; python3 /PythonScript.py"
and is used simply as a way to launch the Python script.
As a work around, I created a shell script (ExecutePythonScript.sh
) with the text python3 /PythonScript.py
and then adjusted my AppleScript to launch the shell script:
do shell script "/ExecutePythonScript.sh"
Unfortunately, this additional step of distance between AppleScript and Python did not help.
Is there any way to allow input via Terminal, even though launching from AppleScript?
If not, is there a way to ask for input via AppleScript and pass that input to the Python script?
For the curious, I am using AppleScript to execute other functions (via Hammerspoon) prior to launching Python. So AppleScript is functioning as sort of central command for the various things that need to happen.
Thanks for any help.
Upvotes: 0
Views: 144
Reputation: 25002
I'm not familiar with Hammerspoon, however here are a couple of examples to consider.
Consider the following simple .py
example that prompts for input via AppleScript and passes that input back to the Python script.
python-script.py
import datetime
from subprocess import Popen, PIPE
x = datetime.datetime.now()
varyear = str(x.year)
varday = str(x.day).zfill(2)
varmonth = str(x.month).zfill(2)
dateStamp = varyear + '-' + varday + '-' + varmonth
userDate = ""
userDatePrompt = """
on getDateFromUser()
tell application "System Events"
activate
set mssg to "Enter date of Bookmap replay data as YYYY-DD-MM:"
set usrPrompt to display dialog mssg default answer "" buttons {"Cancel", "Continue"} default button "Continue"
return text returned of usrPrompt
end tell
end getDateFromUser
return getDateFromUser()
"""
proc = Popen(['osascript', '-'], stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True)
userDate, error = proc.communicate(userDatePrompt)
userDate = userDate.split("\n")[0]
if userDate != "":
dateStamp = userDate
Explanation
This utilizes Python's Popen.communicate()
to essentially spawn a new processes that invokes an AppleScript dialog - prompting the user to input a date.
The AppleScript utilized for the prompt dialog is assigned to the userDatePrompt
variable.
After the user has input some value, (which is assumed to be a date), it is passed back to the Python script and assigned to the userData
variable.
Note the line that reads:
userDate = userDate.split("\n")[0]
We firstly split
the string assigned to the userDate
variable, using a newline character \n
as a delimiter and then access the first item in the Array (i.e. at index 0
), before checking that the value is not an empty string (""
). We do this to ensure that if the user either; clicks the Cancel button, or clicks the Continue button without entering a value, we use your default date value (i.e. Today/Now)
Note: The main issue with the aforementioned script is that we do not in any way validate the user input. They could for example; enter foo bar quux
, then click the Continue button, and our script will happily assume the value assigned to the userDate
variable is a valid date. Ultimately resulting in our program breaking somewhere down the line when we come to use the value.
The following somewhat more comprehensive example .py
additionally validates whether the value entered by the user is a valid date conforming to YYYY-DD-MM
.
python-script.py
import datetime
from subprocess import Popen, PIPE
x = datetime.datetime.now()
varyear = str(x.year)
varday = str(x.day).zfill(2)
varmonth = str(x.month).zfill(2)
dateStamp = varyear + '-' + varday + '-' + varmonth
userDate = ""
userDatePrompt = """
on dateIsValid(givenDate)
set statusCode to do shell script "date -j -f \\"%Y-%d-%m\\" " & quoted form of givenDate & " > /dev/null 2>&1; echo $?"
if statusCode is equal to "0" then
return true
else
return false
end if
end dateIsValid
on getDateFromUser()
tell application "System Events"
activate
set mssg to "Enter date of Bookmap replay data as YYYY-DD-MM:"
set usrPrompt to display dialog mssg default answer "" buttons {"Use Default Date", "Continue"} default button "Continue" cancel button "Use Default Date"
return text returned of usrPrompt
end tell
end getDateFromUser
repeat
set dateReceived to my getDateFromUser()
set isValidDate to dateIsValid(dateReceived)
try
if isValidDate then
exit repeat
else
error
end if
on error
tell application "System Events"
activate
display dialog quote & dateReceived & quote & " is not a valid date." & return & return & "Please try again." buttons {"OK"} default button 1 with icon caution
end tell
end try
end repeat
return dateReceived
"""
proc = Popen(['osascript', '-'], stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True)
userDate, error = proc.communicate(userDatePrompt)
userDate = userDate.split("\n")[0]
if userDate != "":
dateStamp = userDate
Explanation
getDateFromUser
function. This time the Cancel button has been changed to a Use Default Date to better indicate what it actually does.dateIsValid
function. This function utilizes the shells date
utility/command to check the date conforms to YYYY-DD-MM
.repeat
statement we essentially repeatedly prompt the user until a valid date is provided - only exiting when a valid date is encountered.Via AppleScript:
Similar your example, to run python-script.py
via AppleScript utilize the following do shell script
command
do shell script "source ~/.bash_profile; python3 ~/Desktop/python-script.py"
Via Terminal:
Or via the Terminal run:
source ~/.bash_profile; python3 ~/Desktop/python-script.py
Note: The pathname; ~/Desktop/python-script.py
, in both examples will need to be redefined as necessary. Also given the examples provided in my answer the source ~/.bash_profile;
part is not strictly necessary.
Upvotes: 1
Reputation: 823
I'm not sure what's happening when running your py script from AppleScript. It's most likely an environmental issue. Try reading this: https://developer.apple.com/library/archive/technotes/tn2065/_index.html
EDIT: what happens if you try:
do shell script "/full/path/to/python3 /full/path/to/pythonScript.py"
To answer another of your questions, you can pass data from AppleScript to other scripts. Suppose you read a value into the variable input
and you want to supply this as an argument to a script pyScript.py
you could do:
do shell script "pyScript.py " & input
[NOTE: the space in the string is needed.]
Another way to do this is to build the script executing string and run that:
set shellScript to "pyScript.py " & input
do shell script "shellScript"
Upvotes: 0