Runscript — утилита для запуска python скриптов

Думаю многим знакома следующая ситуация. В вашем проекте есть различные действия, которые нужно выполнять время от времени. Для каждого действия вы создаёте отдельный скрипт на питоне. Чтобы далеко не лазить, скрипт кладёте в корень проекта. Через некоторое время вся корневая директория проекта замусоривается этими скриптами и вы решаете сложить их в отдельную директорию. Теперь начинаются проблемы. Если указать интерпретатору python путь до скрипта, включающий эту новую директорию, то внутри скрипта не будут работать импорты пакетов, находящися в корне проекта т.к. корня проекта не будет в sys.path. Эту проблему можно решить несколькими способами. Можно изменять sys.path в каждом скрипте, добавляя туда корень проекта. Можно написать утилитку для запуска ваших скриптов, которая будет изменять sys.path перед запуском скрипта или просто будет лежать в корне проекта. Можно ещё что-то придумать. Мне надоело каждый раз изобретать колесо и я создал велосипед runscript на котором с удовольствием катаюсь.Установить библиотеку можно с помощью pip:

$ pip install runscript

После установки библиотеки runscript, вы получаете в вашей системе новую консольную команду run с помощью которой можно запускать скрипты. По-умолчанию, команда run ищет скрипты в под-каталоге script текущего каталога.Давайте рассмотрим простой пример. Создадим каталог script. Создадим пустой файл script/__init__.py, превратив этот каталог в python-пакет. Теперь создадим файл script/preved.py со следующим содержимым:

def main (**kwargs): print («Preved, medved!») Скрипт готов. Теперь мы можем его запустить:

$ run prevedPreved, medved!

Ура! Скрипт работает. Вот собственно и всё, что делает библиотека runscript. Я серьёзно :) Команда run запускает функцию main из файла, имя которого вы ей передали в командной строке. Оказалось, что даже такой простой фунционал очень удобен. Я с удивлением заметил, что пользуюсь утилиткой run в каждом своём проекте т.к. везде есть простенькие скрипты, которые нужно запускать.Со временем утилита run обросла рядом полезных полезностей, о которых я сейчас расскажу.

Получение параметров через командную строку Чтобы передать вашему скрипту какие-либо параметры через командную строку, вам нужно описать эти параметры в функции setup_arg_parser внутри вашего скрипта. Эта функция получает на вход объект ArgumentParser, в который вы можете добавить нужные опции. Далее, когда скрипт будет вызван, значения параметров командной строки будут переданы фунции main. Пример скрипта: def setup_arg_parser (parser): parser.add_argument (»-w»,»--who», default=«medved»)

def main (who, **kwargs): print («Preved, {}».format (who)) Запускаем: $ run prevedPreved, medved$ run preved -w anti-medvedPreved, anti-medved

Обратите внимание, как фунция main получила параметры командной строки — в виде обычных именованных параметров. Всегда нужно указывать **kwargs т.к. кроме нужных вам параметров, передаются значения всех глобальных для утитилы run параметров (читайте о них ниже).Активация Django Если вы пытались использовать фреймворк Django в ваших консольных скриптах, то знаете, что нужно сделать кое-что, иначе ничего не будет. Кое-что заключается в создании environment переменной DJANGO_SETTINGS_MODULE, cодержащей путь до модуля с настройками. Обычно в python скрипт добавляют следующие строки: import os os.environ[«DJANGO_SETTINGS_MODULE»] = «settings» Начиная с django 1.7 нужно также выполнить import django django.setup () Для того чтобы выполнять автоматически эти действия в скриптах, запускаемых через run, нужно создать в корне проекта файл с именем run.ini, содержащим следующие настройки: [global] django_settings_module = settings django_setup = yes Профилирование Добавив ключик --profile при вызове скрипта, получим файл с результатами профилирования работы нашего скрипта, который можно посмотреть в kcachegrind. Результат сохраняется в каталог var/.prof.out, так что не забудьте создать этот каталог. Также нужно установить модуль pyprof2calltree, который нужен, чтобы сохранить результат профилирования в формате kcachegrind. $ run preved --profilePreved, medved$ ls var/preved.prof.out

Настройка мест поиска скриптов По-умолчанию, утилита run ищет скрипт в двух пакетах: grab.script и script. Пакет grab.script добавлен в этот список, потому что во многих проектах парсинга сайтов я запускаю команду crawl из grab.script пакета. Если вам нужно изменить места для поиска скриптов, создайте следующую настройку в run.ini файле: [global] search_path = package1.script, foo, bar Теперь если мы выполним команду `run preved`, то утилита run попытается импортировать модуль preved в следующем порядке: package1.script.preved foo.preved bar.preved Использование lock-файлов Иногда бывает нужно запретить одновременную работу нескольких экземпляров скрипта. Например, мы вызываем скрипт каждую минуту с помощью cron и хотим не допустить одновременной работы нескольких копий скрипта, что может произойти, если работа одной из копий затянется больше, чем на минуту. С помощью опции --lock-key мы можем передать имя lock-файла, который будет создан в каталоге var/run. Например, --lock-key foo приведёт к созданию файла var/run/foo.lock.Другой способ задать имя lock-файла — создание функции get_lock_key внутри вашего скрипта. Результат её работы будет использован утилитой run, для формирования имени lock-файла. Фунция будет полезна на тот, случай, если вы хотите генерировать имя lock-файла в зависимости от параметров, передаваемых скрипту.

import time

def get_lock_key (who, **kwargs): return 'the-{}-lock'.format (who)

def setup_arg_parser (parser): parser.add_argument ('-w', '--who', default='medved')

def main (who, **kwargs): print ('Preved, {}'.format (who)) time.sleep (1) Запускаем одновременно две копии скрипта и видим: $ run preved -w anti-medved & run preved -w anti-medved[1] 25277Trying to lock file: var/run/the-anti-medved-lock.lockPreved, anti-medvedTrying to lock file: var/run/the-anti-medved-lock.lockFile var/run/the-anti-medved-lock.lock is already locked. Terminating.[1]+ Done run preved -w anti-medved

Я рассказал об основных возможностях библиотеки runscript. Надеюсь, она окажется вам полезной.

В случае вопросов по поводу работы библиотеки можно всегда посмотреть в исходный код, который на данный момент довольно маленький: github.com/lorien/runscript/blob/master/runscript/cli.py

© Habrahabr.ru