Python Script не работает в crontab, вызывающем pysaunter

Я прочитал несколько сообщений и много статей, в которых рассказывается о том, что для работы в cron необходимо, чтобы переменные среды, необходимые для запуска внутри самого script из-за открытия оболочек внутри cron. Моя ситуация уникальна тем, что мои переменные пути все заданы, как обсуждалось, что, в свою очередь, успешно вызовет pysaunter python egg, используя subprocess.call(), но, похоже, он отрывается оттуда. Это заставляет весь процесс ломаться в задании cron.

Для ясности здесь описаны шаги, которые я называю:

1) cronjob calls run_test.py -n foo
2) run_test.py sets the environment variables correctly 
(cur_shell_path=sys.path (converted to proper path string, not shown here)
 my_env= os.environ.copy()
 my_env["PATH"] = my_env["PATH"] + cur_shell_path)
3) run_test.py calls subprocess.call("pysaunter -m foo -v", env=my_env, shell=True)

Результат шага 3 показывает, что он находит яйцо и успешно начинает загружать необходимые модули из pysaunter, но затем он ломается при попытке найти каталог, используемый для изменения pysaunter. Ошибка читается:

ImportError: no module named helpers

Я попытался добавить этот путь к среде несколько раз, но никогда не нашел каталог, содержащий helpers.py. Команда pysaunter -m foo -v работает нормально при вызове из интерактивной оболочки.

Я не мог найти большую помощь в pysaunter, поэтому я предполагаю, что слишком много особенностей pysaunter здесь не будет ненужным. Если, однако, вы знаете больше о pysaunter, пожалуйста, дайте мне знать, если вам нужна дополнительная информация. Я не уверен, что поделиться.

Я также прочитал много сообщений, в которых обсуждается возможность изменения поведения оболочки по умолчанию путем редактирования .profile/.bash_profile. Я попытался найти место, которое сделало бы мои переменные пути глобально доступными, но я ничего не мог найти. Я не уверен, как это делается, и это может решить мою проблему, поэтому, если вы знаете что-нибудь об этом, сообщите мне.

Заключительное примечание: это работает на Mac 10.7.5.

Ответ 1

После долгих проб и ошибок и многих, многих статей stackoverflow.com и других учебных пособий в Интернете, и с помощью Perl script я обнаружил, что сделал что-то подобное, я смог выяснить, что нужно сделать чтобы это работало.

Вот шаги, необходимые для правильной настройки:

  • Убедитесь, что у вас есть переменные, которые вам нужны в PYTHONPATH (найдено здесь и здесь и для получения дополнительной информации. здесь) внутри .profile или .bash_profile для любой оболочки, которую вы хотите протестировать script, чтобы убедиться, что он работает.

  • Отредактируйте свой crontab, чтобы включить каталоги, необходимые для запуска вашего script в задании cron (найдено здесь и here).

    a) Обязательно укажите корневой каталог в переменной PATH (.), как описано здесь. В принципе, если вы выполняете исполняемый файл с помощью своей команды, он должен иметь возможность находить корень или каталог, в котором хранится исполняемый файл, а также, возможно, следующие: (/sbin:/bin:/usr/sbin:/usr/bin).

  • В вашем файле crontab создайте cronjob, который изменит текущий каталог в каталог, в котором вы успешно выполнили script раньше (например,/Users/user/Documents/foo).

    a) Это будет выглядеть следующим образом:

    * * * * cd /Users/user/Documents/foo; bar -l doSomething -v 
    
  • Поскольку моя проблема касалась конкретно вызова исполняемого файла, необходимо отметить, что существует несколько способов записи запускаемого Python script (хотя в процессе обнаружения я узнал, что это работает для любого вызова сделанный с использованием подпроцесса в cron).

    Первый метод выглядит следующим образом:

    ... #some script calls
    my_env = os.environ.copy()
    my_env["PYTHONPATH"] = "{}:{}".format(os.environ["PATH"] ,"<path you want to include>")
    os.chdir("<path/to/desired/directory>")
    subprocess.Popen(<call_as_string>, env=my_env, shell=True)
    

    И второе выглядит так:

    ... #some script calls
    os.environ["PYTHONPATH"] = "{}:{}".format(os.environ["PATH"] ,"<path you want to include>")
    os.chdir("<path/to/desired/directory>")
    subprocess.Popen(<call_as_list_of_arguments)
    

    Поскольку исполняемому файлу нужен путь к каталогу помощников, включенному в оболочку, откуда он был вызван, необходимо передать переменную окружения в исполняемый файл, как описано здесь. Однако я обнаружил, что изменение переменной PATH в среде не работало для задания cron, но установка PYTHONPATH выполнялась. Я читаю здесь, что переменная PATH используется оболочкой только для поиска исполняемых файлов, поэтому для новой оболочки внутри cronjob вам нужно передать оболочке PYTHONPATH, чтобы посмотреть для новых модулей Python. (Это также объясняется в документах Python.)

    Различия между двумя различными методами объясняются в документации к подпроцессу, указанной в вопросе, но хороший учебник по этому модулю можно найти здесь.

Ответ 2

То, что вы сказали, не имеет смысла.

Вы говорите shell_env = sys.path. sys.path - это список папок для python для поиска модулей, а не для сопоставления переменных среды.

Затем вы используете это в subprocess.call. Возможно, вы хотели написать env=my_env.

Это следующая проблема. Во-первых, PATH должен быть списком папки, разделенной ':'. Вы просто привязываете shell_path к последней папке.

Наконец, python использует PYTHONPATH как список для поиска модулей python (что, похоже, является той проблемой, с которой вы сталкиваетесь.)