提问人:ZwiTrader 提问时间:6/28/2021 更新时间:6/29/2021 访问量:132
从 AppleScript 启动 Python 脚本在读取行时生成 EOFError
Initiating Python script from AppleScript yields EOFError when reading a line
问:
我希望使用 AppleScript 启动一个 Python 脚本,该脚本的前几行:
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
从终端(在 Mac 上)运行 Python 脚本时,我没有问题:系统会提示我输入日期,如果我没有提供日期,脚本将使用当前日期。
但是,当从AppleScript启动Python脚本时,我无法提供输入,因为会立即抛出EOF错误。
我的整个AppleScript包括
do shell script "source ~/.bash_profile; python3 /PythonScript.py"
并仅用作启动 Python 脚本的一种方式。
作为解决方法,我创建了一个带有文本的 shell 脚本 (),然后调整了我的 AppleScript 以启动 shell 脚本:ExecutePythonScript.sh
python3 /PythonScript.py
do shell script "/ExecutePythonScript.sh"
不幸的是,AppleScript 和 Python 之间的这一额外距离步骤无济于事。
有没有办法允许通过终端输入,即使从AppleScript启动?
如果没有,有没有办法通过 AppleScript 请求输入并将该输入传递给 Python 脚本?
出于好奇,在启动 Python 之前,我正在使用 AppleScript 执行其他功能(通过 Hammerspoon)。因此,AppleScript正在充当各种需要发生的事情的中央命令。
感谢您的帮助。
答:
我不确定从 AppleScript 运行 py 脚本时会发生什么。这很可能是一个环境问题。试着读这个: https://developer.apple.com/library/archive/technotes/tn2065/_index.html
编辑:如果您尝试以下情况,会发生什么:
do shell script "/full/path/to/python3 /full/path/to/pythonScript.py"
要回答您的另一个问题,您可以将数据从 AppleScript 传递到其他脚本。假设您在变量中读出一个值,并且想要将其作为参数提供给脚本,您可以执行以下操作:input
pyScript.py
do shell script "pyScript.py " & input
[注意:字符串中的空格是必需的。
另一种方法是构建执行字符串的脚本并运行它:
set shellScript to "pyScript.py " & input
do shell script "shellScript"
评论
我不熟悉 Hammerspoon,但这里有几个例子可以考虑。
简单示例
请考虑以下简单示例,该示例通过 AppleScript 提示输入,并将该输入传递回 Python 脚本。.py
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
解释
这利用了 Python 的
Popen.communicate()
来生成一个调用 AppleScript 对话框的新进程 - 提示用户输入日期。用于提示对话框的 AppleScript 将分配给该变量。
userDatePrompt
在用户输入某个值(假定为日期)后,该值将传递回 Python 脚本并分配给变量。
userData
请注意以下行:
userDate = userDate.split("\n")[0]
我们首先使用换行符作为分隔符,将字符串分配给变量,然后访问数组中的第一项(即在索引处),然后检查该值是否为空字符串()。我们这样做是为了确保如果用户;单击按钮,或单击按钮而不输入值,我们将使用您的默认日期值(即今天/现在)
split
userDate
\n
0
""
CancelContinue
注意:上述脚本的主要问题是我们不以任何方式验证用户输入。例如,他们可以;输入 foo bar quux
,然后单击 Continue 按钮,我们的脚本将愉快地假设分配给 userDate
变量的值是有效日期。最终导致我们的程序在使用该值时在某个地方崩溃。
验证示例
以下更全面的示例还验证了用户输入的值是否为符合 的有效日期。.py
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
解释
- 这基本上与前面的(简单)示例相同,但它提供了额外的验证,这些验证都是通过 AppleScript 处理的。
- 根据前面的示例,我们通过函数提示用户输入日期。这一次,该按钮已更改为 a,以更好地指示它的实际作用。
getDateFromUser
CancelUse Default Date - 随后,我们通过函数验证用户输入。此函数利用 shells
date
实用程序/命令来检查日期是否符合 。dateIsValid
YYYY-DD-MM
- 通过
repeat
语句,我们基本上会重复提示用户,直到提供有效日期 - 只有在遇到有效日期时才退出。
运行
通过 AppleScript:
与您的示例类似,要通过AppleScript运行,请使用以下
do shell脚本
命令python-script.py
do shell script "source ~/.bash_profile; python3 ~/Desktop/python-script.py"
通过终端:
或通过终端运行:
source ~/.bash_profile; python3 ~/Desktop/python-script.py
注意:路径名;~/Desktop/python-script.py
,在这两个示例中都需要根据需要重新定义。此外,鉴于我的回答中提供的例子,源 ~/.bash_profile;
部分并不是绝对必要的。
评论