读取一行时,从 AppleScript 启动 Python 脚本会产生 EOFError 简单示例验证示例运行

问题描述

我希望使用 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 脚本的一种方式。

作为一种变通方法,我创建了一个带有文本 ExecutePythonScript.sh 的 shell 脚本 (python3 /PythonScript.py),然后调整了我的 AppleScript 以启动 shell 脚本:

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 并不熟悉,但这里有几个例子需要考虑。

简单示例

考虑以下简单的 .py 示例,该示例通过 AppleScript 提示输入并将该输入传递回 Python 脚本。

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作为分隔符,然后访问数组中的第一项(即在索引{{1 }}),然后检查该值是否为空字符串 (0)。我们这样做是为了确保如果用户要么;点击取消按钮,或点击继续按钮而不输入值,我们使用您的默认日期值(即今天/现在)

注意:上述脚本的主要问题是我们不以任何方式验证用户输入。例如,他们可以;输入 "",然后单击 Continue 按钮,我们的脚本会很高兴地假定分配给 foo bar quux 变量的值是一个有效日期。最终导致我们的程序在我们开始使用该值时在某处崩溃。


验证示例

以下更全面的示例 userDate 额外验证用户输入的值是否是符合 .py 的有效日期。

python-script.py

YYYY-DD-MM

说明

  • 这基本上与前面的(简单)示例相同,但它提供了额外的验证,所有验证都通过 AppleScript 处理。
  • 根据前面的示例,我们提示用户通过 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',error = proc.communicate(userDatePrompt) userDate = userDate.split("\n")[0] if userDate != "": dateStamp = userDate 函数输入日期。这次 取消 按钮已更改为 使用默认日期 以更好地表明它的实际作用。
  • 随后,我们通过 getDateFromUser 函数验证用户输入。此函数利用 shells date 实用程序/命令来检查日期是否符合 dateIsValid
  • 通过 repeat 语句,我们基本上反复提示用户,直到提供有效日期为止 - 仅在遇到有效日期时退出。

运行

  • 通过 AppleScript:

    类似于您的示例,要通过 AppleScript 运行 YYYY-DD-MM,请使用以下 do shell script 命令

    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 部分并不是绝对必要的。