2015-11-26

Python 3.5 + Docker

Один из самых удобных и современных способов деплоя рабочего окружения является Docker. В предыдущих постах мы устанавливали свежий Python из исходников, но если у вас несколько серверов, да еще и с разными версиями ОС, то этот процесс может отличаться. К тому же это безумие в чистом виде. Как вариант предлагают использование virtualenv, но он тоже не чистая песочница, и использует часть библиотек окружения, что может иметь последствия. Короче, Docker - идеальная изоляция не в ущерб производительности, не зависящая от версии ОС и установленных в ней библиотек. На DockerHub уже есть готовые образы, часть из них официальные, часть от частных лиц. Мы возьмем официальный Python 3.5 и добавим нужные нам пакеты. Минимум телодвижений - и набор готов.

Будем использовать скрипт автоматизации, который называется Dockerfile. Для создания нужного образа достаточно будет выполнить команду в каталоге с Dockerfile:


docker build -t python35 .

А вот примерное содержимое этого конфигурационного файла:


FROM python:3.5
MAINTAINER Main Tainer maintainer@email.com

# Update and install needed packaged:
# libblas-dev and liblapack-dev for matplotlib, gfortran for scipy
RUN apt-get -y update && apt-get install -y libblas-dev liblapack-dev gfortran

# Install packages for DataScience
RUN pip3 install numpy scipy sklearn pandas matplotlib seaborn nltk ipython[all] jupyter

# Web frameworks
RUN pip3 install tornado flask flask-admin flask-login flask-restful
RUN pip3 install django django-bootstrap3 django-admin-bootstrapped

# Databases: psycopg2 (Postgres), pika (RabbitMQ), sqlalchemy (ORM)
RUN pip3 install psycopg2 sqlalchemy pymongo pika redis elasticsearch

# HTTP-requests http://docs.python-requests.org/en/latest/
RUN pip3 install requests requests_oauthlib

# Image manipulations https://pillow.readthedocs.org/en/3.0.x/
RUN pip3 install pillow

# Make C-modules http://cython.org/
RUN pip3 install cython

# Scheduler https://apscheduler.readthedocs.org/en/latest/
RUN pip3 install apscheduler

Вот и все, можно запускать!


docker run -ti python35 python

Python 3.5.0 (default, Nov 20 2015, 06:18:32)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

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


docker run -v /path/outside:/path/inside python35 python /path/inside/code.py

Ура, теперь то мы знаем, что их всего 55252.

2015-11-24

Python3.5 + PyQt5 - The Hard Way

Сегодня мы, в продолжение предыдущей статьи, установим библиотеку PyQt5 для собранного из исходников Python3.5. Для версии Python3, идущей в репозитории дистрибутива есть простой путь, и в общем случае лучше придерживаться его - он проще и дает аналогичный результат.


sudo apt-get install python3-pyqt5 pyqt5-dev-tools

Маководам тоже повезло, им также хватит одной строки (если стоит Homebrew, а куда ж без него?):


brew install pyqt5

Тех же, кто не ищет легких путей или кому нужна именно собственноручно собранная версия, милости прошу к прочтению.

Итак, поехали. Для начала, скачиваем подходящий установщик Qt5, мне нужен был для Linux x64, запускаем и устанавливаем, можно в каталог по умолчанию ~/Qt.

Качаем и распаковываем свежие версии PyQt5 и sip отсюда: http://sourceforge.net/projects/pyqt/files/. Помним, что мы установили python в локальный каталог ~/local. В каталоге с распакованным sip конфигурируем и устанавливаем:


python3 configure.py -d ~/local/lib/python3.5/site-packages/
make
make install

Для успешной сборки GUI модулей PyQt5 (типа PyQt5.QtWidgets) пришлось установить пакетик с исходниками mesa:


sudo apt-get install libgl1-mesa-dev

Теперь в каталоге с распакованным PyQt5 конфигурируем и устанавливаем:


python3 configure.py --destdir ~/local/lib/python3.5/site-packages/\
 --qmake ~/Qt/5.5/gcc_64/bin/qmake --disable QtPositioning
make
make install

Почему здесь фигурирует "--disable QtPositioning"? Потому что иначе не собирается, выбрасывая сообщение "qgeolocation.h: No such file or directory". Да и шут с ним. Вот собственно и всё, можно начинать писать код.


from PyQt5.QtWidgets import QApplication, QWidget
app = QApplication([])
w = QWidget()
w.resize(300, 200)
w.move(400, 400)
w.setWindowTitle('PyQt5 installed')
w.show()

Получите, распишитесь.

2015-11-19

Setup Python3.5 for DataScience

Цель - установить локальную версию свежего дистрибутива Python 3.5 и группу пакетов, полезных для ковыряния в данных. Платформа - Linux Mint 17.2 x64. Устанавливаем пакет с компиляторами на все случаи жизни, скачиваем с официального сайта архив с исходниками и распаковываем его, скажем, в каталог ~/Python-3.5.0. В терминале перемещаемся в него и начинаем.


sudo apt-get install build-essential git git-core xz-utils
wget https://www.python.org/ftp/python/3.5.0/Python-3.5.0.tar.xz
tar -xpJf Python-3.5.0.tar.xz
cd Python-3.5.0

Для начала нам нужно установить зависомости, без которых в дальнейшем не соберутся некоторые пакеты. Не буду приводить, какие для чего, оставлю для любознательных. Скажу лишь, что первая пара команд - для того, чтобы при компиляции Python не предупреждал нас о пропуске некоторых пакетов ввиду отсутствия библиотек. Это не повлияет на итоговый успех установки, но может всплыть позже.


sudo apt-get install tk-dev libsqlite3-dev libbz2-dev libfreetype6-dev
sudo apt-get install liblzma-dev libgdmb-dev libreadline-dev
sudo apt-get install lib32ncurses5-dev libpng12-dev libjpeg-dev tk
sudo apt-get install liblapack-dev libplas-dev gfortran libpq-dev

В среде Google Cloud в Ubuntu 15.04 пакеты libgdmb-dev и libplas-dev не находятся, возможно есть замена, но я не разбирался, не очень то и нужны.

Теперь собственно, сборка и проверка. Предварительно создадим каталог для локальной версии Python, у меня это ~/local.


./configure --prefix=$HOME/local
make -j4
make test
make install

У меня не установился модуль _ctypes, и непонятно, чего ему не хватило. Если знаете, в чем дело, напишите в комментариях. Стоит добавить в файл ~/.bashrc несколько строк, чтобы оболочка была в курсе, где наш новый Python и его библиотеки живут.


export PATH=$HOME/local/bin:$PATH
export LD_LIBRARY_PATH=$HOME/local/lib:$LD_LIBRARY_PATH
export C_INCLUDE_PATH=$HOME/local/include/:$C_INCLUDE_PATH

Теперь настало время для наших изыскательских (и просто ежедневно полезных) пакетов. Первая строка - mast have для исследователя, остальные - не обязательно, они просто хорошие :)


pip3 install numpy scipy sklearn pandas matplotlib seaborn ipython[all] jupyter
pip3 install tornado pillow psycopg2 sqlalchemy cython nltk
pip3 install requests requests_oauthlib elasticsearch
pip3 install django django-bootstrap3 django-admin-bootstrapped
pip3 install flask flask-admin flask-login apscheduler pymongo pika redis

С matplotlib могут возникнуть сложности, а именно - без выбрасывания ошибок не показывает окно с результатом. Чтобы этого не происходило мы и установили tk и собрали Python с tk-dev. Стоит проверить, что в файле с настройками matplotlib (у меня это '~/local/lib/python3.5/site-packages/matplotlib/mpl-data/matplotlibrc') выставлен верный параметр backend: TkAgg. Можно выставить его и прямо в коде. Также, можно попробовать установить matplotlib с github:


pip3 install git+https://github.com/matplotlib/matplotlib.git

Кроме того, при сборке matplotlib может ругнуться на отсутствие freetype, даже если установлен libfreetype6-dev. Такое я наблюдал, когда собирал Docker контейнер с основой на ubuntu:trusty. Помогло создание ссылки:


ln -s /usr/include/freetype2/ft2build.h /usr/include/

import numpy as np
import matplotlib.pyplot as plt
import matplotlib

matplotlib.use("TkAgg")
plt.imshow(np.random.random((10, 10)))
plt.show()

Красивая калякамаляка получилась!

2015-11-13

Custom Search Engine + Python

Использование Custom Search Engine API от Google из Python мне показалось несколько запутанным, поэтому опишу это пошагово, возможно кому-нибудь пригодится. Для начала, нам понадобится библиотека API Client Library for Python, установить которую не представляет труда:


sudo pip install --upgrade google-api-python-client

Во вторых, нам будет нужен идентификатор CSE, который мы для себя создадим на официальной странице. Добавьте в список сайтов для поиска "google.com", а переключатель "Поиск изображений" установите в положение ВКЛ. После того, как сохраним результаты, нажатие кнопки "Идентификатор поисковой системы" покажет нам то, для чего мы прошли все эти мытарства. Это будет похоже на "01345678901234567890:qwer23tyu_i".

Теперь отправляемся в консоль разработчика, а именно в раздел "APIs & auth/APIs". Найдите в списке "Custom Search API" и подключите его.

Там же в консоли переходим в пункт "Credentials", жмем "Add credntials", выбираем "API Key", затем жмем "Server key", даем ему имя и сохраняем. Забираем ключик, он будет похож на "QWerTyQWerTyQWe-QWerTyQWerTyQWerTyQWerTy".

На этом с ключами всё, пишем код на Python. В примере мы получаем все уникальные изображения пляжа, которые может позволить этот API:


from apiclient.discovery import build

service = build('customsearch', 'v1', developerKey="QWerTyQWerTyQWe-QWerTyQWerTyQWerTyQWerTy")

start = 1

while True:

    res = service.cse().list(
        q='beach',
        cx='01345678901234567890:qwer23tyu_i',
        fileType="png,jpg",  # bmp, gif, png, jpg, svg, pdf, ...
        imgColorType="color",  # mono, gray, color
        imgSize="medium",  # icon, small, medium, large, xlarge, xxlarge, huge
        imgType="photo",  # clipart, face, lineart, news, photo
        safe="high",  # high, medium, off
        searchType="image",
        start=start
    ).execute()

    for img in res["items"]:
        print(img["link"])

    if "nextPage" not in res["queries"]:
        break

    start = res["queries"]["nextPage"][0]["startIndex"]

2015-11-09

Выбор инструмента для быстрых микросервисов

Как известно, идеальных технологий не существует. Есть популярные в силу ряда причин (первые на рынке, удачный PR, хорошие менеджеры по продажам, даже реально классный код), есть незаслуженно забытые, есть продвинутые, но не для "простых смертных". Подбирая инструмент для решения какой-то задачи, мы обычно опираемся на собственный опыт (если есть) и на мнения других людей, желательно экспертов в исследуемой области. Проходя этот путь поиска я каждый раз ищу совершенство и каждый раз убеждаюсь, что его нет. Даже самый могучий ЯП и растопырчатый фреймворк имеют критиков с вескими аргументами.

Для реализации микросервисов, работа которых в том, чтобы пропускать через себя множество однотипных заданий и делать это быстро, я остановился на Go. Перечитал и пересмотрел много всего. Как питонщику он мне импонирует простотой и наличием встроенных батареек для решения повседневных задач, таких как работа с CSV и JSON, обработка HTTP-запросов и т.п. Авторы не ставили перед собой цель написать что-то концептуально новое, но сделать простой и годный инструмент, на котором писать просто, и работает быстро. Оно еще и компилируется моментально, что в процессе разработки чрезвычайно важно.

Что еще понравилось - так это статическая линковка, благодаря которой никаких зависимостей при деплое. Сервер с демонами может выглядеть как каталог с кучей бинарных файлов, файлом настроек и скриптом старта screen. Утрирую конечно, но как аккуратно получается! Вобщем, понравилось. Несколько экспериментов даже выложил на github: