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 preved
Preved, 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 preved
Preved, medved
$ run preved-w anti-medved
Preved, anti-medved
Зверніть увагу, як функція main отримала параметри командного рядка — у вигляді звичайних іменованих параметрів. Завжди потрібно вказувати **kwargs т. к. крім потрібних вам параметрів, що передаються значення всіх глобальних для утитилы run параметрів (читайте про них нижче).

Активація Django
Якщо ви намагалися використовувати фреймворк Django у ваших консольних скриптах, то знаєте, що потрібно зробити дещо, інакше нічого не буде. Дещо полягає у створенні environment змінної DJANGO_SETTINGS_MODULE, що містить шлях до модуля з налаштуваннями. Зазвичай в 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/<script_name>.prof.out, так що не забудьте створити цей каталог. Також потрібно встановити модуль pyprof2calltree, який потрібен, щоб зберегти результат профілювання в форматі kcachegrind.

$ run preved --profile
Preved, 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] 25277
Trying to lock file: var/run/the-anti-medved-lock.lock
Preved, anti-medved
Trying to lock file: var/run/the-anti-medved-lock.lock
File var/run/the-anti-medved-lock.lock is already locked. Terminating.
[1]+ Done run preved-w anti-medved


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

У разі запитань щодо роботи бібліотеки завжди можна подивитися в вихідний код, який на даний момент досить маленький: github.com/lorien/runscript/краплі/master/runscript/cli.py

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.