Elpy, python-mode и use-package
Emacs - отличный редактор для тех, кто пишет на Python, и есть куча пакетов для поддержки этого языка. Я уже раньше писал, что теперь храню свою конфигурацию и управляю пакетами с помощью use-package, однако, долго не мог найти способ для красивого скрещивания замечательного пакета elpy cо стандартным python-mode.
Решение оказалось не очень сложным, хотя на его поиск пришлось потратить некоторое время. Ниже выкладываю кусок своего init.el.
(use-package python-mode
:mode ("\\.py\\'" . python-mode)
:init(add-hook 'python-mode-hook #'elpy-enable)
:config
(use-package elpy
:bind
("M-," . elpy-goto-definition)
:init
(elpy-enable)
(defalias 'workon 'pyvenv-workon)
:config
(add-to-list 'company-backends 'elpy-company-backend)
(elpy-enable))
(use-package py-autopep8
:hook
(python-mode . py-autopep8-enable-on-save))
(use-package py-isort
:init
(add-hook 'before-save-hook #'py-isort-before-save)))
Этот код не делает никакой магии. В общем-то, тут вообще нет ничего интересного.
Самому себе оставляю памятку: в настройках settings.el уже включена автоматическая загрузка недостающих пакетов с помощью use-package. Для всех Python'ьих файлов как major-mode указан python-mode. При его инициализации дополнительно подключаются пакеты elpy, py-autopep8 и py-isort, почти все настройки которых уже вынесены сами знаете куда. Кроме того, каждый пакет при загрузке ставит хуки на определенное действие. Например, автоматическое форматирование или упорядочение импортированных модулей.
Не уверен в том, какую строку с elpy-enable можно удалить, чтобы ничего не сломалось. Сегодня выяснять лень, потом разберусь.
CSRF-токены и CBV, требующие авторизации
Всё, что нужно знать о CSRF-токенах в Django
Ниже идёт код, который позволяет прописать в шаблон Cookies с CSRF-токеном:
from django.core.context_processors import csrf
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.views.generic import View
class Index(View):
def get(self, request):
context = {}
context.update(csrf(request))
return render_to_response(
'index.html',
RequestContext(request, context)
)
В сам шаблон нужно не забыть включить одну важную строку:
{% csrf_token %}
Без этой строки печенька покрошена на страницу НЕ БУДЕТ. Не знаю, почему, просто вот такой интересный факт.
Миксин для CBV (Class Based Views), которым нужна авторизация:
from os import path
from django.contrib.auth.decorators import login_required
from django.core.context_processors import csrf
from django.shortcuts import render_to_response
from django.template.context import RequestContext
from django.views.generic import View
class LoginRequiredMixin(object):
"""Собственно примесь """
@classmethod
def as_view(cls, **initkwargs):
view = super(LoginRequiredMixin, cls).as_view(**initkwargs)
return login_required(view, login_url='/login/')
class ProfileView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
c = {}
c.update(csrf(request))
user = request.user
template_path = path.join(
'admin',
'index.html',
)
return render_to_response(
template_path,
RequestContext(request, c)
)
EMACS для Python
Введение
Решил наконец написать статью о том, как настроить EMACS для удобной работы с Python'ом. Ниже список рассматриваемых вопросов:
- Разбиение конфигурации на части
- Пакеты
- Ergoemacs
- Anaconda-mode
Разбиение конфигурации на части
Долгое время мой .emacs представлял собой всего один файл. Естественно, править его было не очень удобно. С течением времени он рос и становился толще, наконец, в определённый момент поддерживать его стало совершенно невозможно. К счастью, я подсмотрел на StackOverflow, как можно разбить его на несколько маленьких частей.
Для подгрузки параметров из других файлов нужно в .emacs написать следующее:
;;; package --- Summary
;;; Commentary:
;;; Main EMACS settings file, load settings from parts.
;;; Code:
(load "~/.emacs.d/fonts.el")
(load "~/.emacs.d/packages.el")
(load "~/.emacs.d/ergoemacs.el")
(load "~/.emacs.d/personal.el");
(load "~/.emacs.d/keyboard.el")
(load "~/.emacs.d/variables.el")
(load "~/.emacs.d/flycheck.el")
(load "~/.emacs.d/rust.el")
(load "~/.emacs.d/python.el")
(load "~/.emacs.d/web.el")
;;; .emacs ends here
Здесь load - функция, выполняющая загрузку указанного файла. Сам файл находится в каталоге .emacs.d/ и называется fonts.el. Туда я положил настройки шрифтов. Затем идёт подгрузка файла, отвечающего за список пакетов. При необходимости недостающие пакеты будут установлены из MELPA, MELPA-STABLE или другого из указанных репозиториев, впрочем, об этом я уже писал ранее.
Я не буду давать рекомендаций по поводу того, на сколько частей нужно разбивать конфигурацию, как эти части называть и так далее, каждый решает сам, потому что, например, несколько дней назад я не видел необходимости выносить настройки шрифтов отдельно, а сейчас решил, что так будет лучше. Как видите, за настройки для разработки на Python'е отвечает файл .emacs.d/python.el, в него я поместил все нужные параметры EMACS'а.
Пакеты
Как я уже говорил, автоматическую установку пакетов я описывал в другой статье, ниже перечислю лишь те пакеты, которые понадобятся, а так же дам краткое описание того, для чего они нужны.
anaconda-mode
Данный пакет служит для поддержки функциональности IDE при работе с файлами Python'а, как то быстрый переход к декларациям, вывод документации и т.д.
company
Данный пакет рекомендуется как более современная замена пакету auto-complete. Ничего не имею против последнего, но лично мне использовать указанный приятнее.
company-anaconda
Автодополнение в режиме anaconda-mode, без этого подсказки работать не будут.
ergoemacs-mode
В общем-то, не скажу, что этот пакет жизненно необходим, но он даёт необходимые удобства, например, упрощает работу с командами, заменяя стандартные хоткеи EMACS'а на свои, более близкие к тем, которыми пользуются нормальные люди, например, комбинации Ctrl+C и Ctrl+V, а так же многие другие начинают работать так, как это принято в подавляющем большинстве современных программ, т.е. копируют и вставляют текст. Подробнее можно почитать на сайте проекта.
flycheck, flycheck-pos-tip
Стандарт де-факто для проверки синтаксиса. Какой именно синтаксис и чем будет проверяться - настраивается. По умолчанию для Python'а используются flake8, pylint и pycompile. Естественно, чтобы данные средства работали, они должны присутствовать в системе.
helm
Система подсказок. Допустим, нажали Вы Alt+X, начинаете вводить lis, а он сразу выдаёт отфильтрованные команды, в которых присутствует данная строка. Можно стрелками выбрать нужную строку и нажать Enter. Умеет подсказывать не только команды, но так же имена файлов, виртуальные окружения и многое другое, легко расширяется. Практически незаменимое средство.
neotree
Пакет просто выводит дерево файлов слева. Можно забиндить отображение / скрытие на горячую клавишу, работать станет в разы удобнее.
python-mode
Базовый пакет для поддержки EMACS'ом Python'а.
py-autopep8
Пакет позволяет применить autopep8 - средство для автоформатирования кода по стандартам. Можно настроить на автоформат кода при сохранении файла. Удобно, хотя в старых проектах, где код писан ногами, порождает тонны баттхёрта у тех, кто будет делать ревью вашего кода.
py-isort
Сортирует импортированные файлы. Можно передать разные настройки. Лично я предпочитаю импорт 1-1, т.е. одна строка - один модуль или класс. Рекомендую, т.к. в этом случае с помощью flycheck будет проще удалять неиспользованные модули - выделил строку, нажал Backspace, сохранил.
pyvenv, virtualenvwrapper
Позволяет EMACS'у видеть виртуальные окружения и нормально с ними работать.
pip-requirements
Небольшой пакет для удобного редактирования файла зависимостей. Если кто не в курсе - файл REQUIREMENTS создаётся в корне Python-проекта и позволяет в одну команду установить все нужные для работы зависимости:
pip install -r REQUIREMENTS -U
В чём плюс данного пакета? Он выдаёт подсказки по именам, подгружая список с PyPi - главного всемирного рассадника питонячьих пакетов.
Установка через pip (от имени root)
pip install autopep8 flake8 isort pylint -U
Ergoemacs
Данный пакет довольно активно развивается и предоставляет кучу удобств. Вся его конфигурация у меня вынесена в отдельный файл, и чтобы далеко не ходить, публикую его ниже:
;;; Package --- Summary
;;; Comment:
;;; Settings for ergoemacs-mode
;;; Code:
(require 'ergoemacs-mode)
;;; Ergoemacs
(setq ergoemacs-theme nil)
(setq ergoemacs-keyboard-layout "us")
(setq ergoemacs-ini-mode t)
(setq ergoemacs-use-menus t)
(setq ergoemacs-smart-paste nil)
(setq ergoemacs-ctl-c-or-ctl-x-delay 0.3)
(ergoemacs-mode 1)
;;; ergoemacs.el ends here
Anaconda-mode
Тут речь не только об anaconda-mode, ниже приводится весь файл настроек для Python. Надеюсь, комментарии помогут в понимании данных настроек
;;; Package --- Summary
;;; Commentary:
;;; Settings for Python
;;; Code:
;;; Импорт необходимых модулей
(require 'py-autopep8)
(require 'py-isort)
(require 'pip-requirements-mode)
;;; Псевдоним для команды pyvenv-workon, пользователи virtualenv оценят удобство
(defalias 'workon 'pyvenv-workon)
;;; Автоматически загружать модуль python-mode, писать в статус баре "Python-mode"
(autoload 'python-mode "python-mode" "Python mode." t)
;;; Применять python-mode для файлов с расширением .py
;;; Использовать интерпретатор python для python-mode
(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))
(add-to-list 'interpreter-mode-alist '("python" . python-mode))
(add-to-list 'auto-mode-alist '("\\REQUIREMENTS" . pip-requirements-mode))
(add-to-list 'auto-mode-alist '("\\REQUIREMENTS.txt" . pip-requirements-mode))
(add-to-list 'auto-mode-alist '("\\requirements" . pip-requirements-mode))
(add-to-list 'auto-mode-alist '("\\requirements.txt" . pip-requirements-mode))
;;; Подсвечивать строки, которые обычно используются при отладке
(defun annotate-pdb()
(interactive)
(highlight-lines-matching-regexp "import ipdb")
(highlight-lines-matching-regexp "import pdb")
(highlight-lines-matching-regexp "set_trace()")
(highlight-phrase "TODO")
(highlight-regexp "FIXME")
(highlight-regexp "BUG")
)
;;; В Python-mode автоматически включать anaconda-mode, pdb и
;;; автоматически применять autopep8 при сохранении файла
(add-hook 'python-mode-hook 'anaconda-mode)
(add-hook 'python-mode-hook 'annotate-pdb)
(add-hook 'python-mode-hook 'py-autopep8-enable-on-save)
;;; Перед сохранением так же отсортировать импортированные модули.
;;; Правило сортировки: одна строка - один модуль
(add-hook 'before-save-hook 'py-isort-before-save)
(setq py-isort-options '("-sl"))
;;; python.el ends here
Теперь следует перезапустить EMACS, чтобы он подхватил настройки, и начать работать. Ниже приводится вид моего EMACS'а, когда я пишу на Python.
Конфиг на GitHubОшибка "memmove does not exist on this platform"
Который раз вижу вот эту ошибку:
extensions/expat/lib/xmlparse.c:75:2: error: #error memmove does not exist on this platform, nor is a substitute available
Решение очень легко гуглится на StackOverflow, но для себя я решил сохранить, чтобы далеко не ходить. Проблема заключается в том, что в одном из заголовочных файлов Python 2.7 не определена константа HAVE_MEMMOVE
Решение
- Открыть файл /usr/include/python2.7/pyconfig.h
-
Добавить в его конец строку
#define HAVE_MEMMOVE 1
Послесловие: хватит уже пользоваться Python 2.7, Гвидо не для того старался с тройкой.
str object has no attribute _meta
Досадная ошибка, с которой пришлось столкнуться, вынесена в название статьи. Потратил два часа на поиски, просмотрел все файлы по нескольку раз - и ничего. Сегодня с утра (а утро вечера мудренее) обнаружил причину.
Было:class UserChangeForm(forms.ModelForm):
'''
Форма для обновления данных пользователей. Нужна только для того, чтобы не
видеть постоянных ошибок "Не заполнено поле password" при обновлении данных
пользователя.
'''
password = ReadOnlyPasswordHashField(
widget=forms.PasswordInput,
required=False
)
def clean_password(self):
return self.initial['password']
def save(self, commit=True):
user = super(UserChangeForm, self).save(commit=False)
password = self.cleaned_data["password"]
if password:
user.set_password(password)
if commit:
user.save()
return user
class Meta:
model = get_user_model()
fields = ('email')
Стало:
class UserChangeForm(forms.ModelForm):
'''
Форма для обновления данных пользователей. Нужна только для того, чтобы не
видеть постоянных ошибок "Не заполнено поле password" при обновлении данных
пользователя.
'''
password = ReadOnlyPasswordHashField(
widget=forms.PasswordInput,
required=False
)
def clean_password(self):
return self.initial['password']
def save(self, commit=True):
user = super(UserChangeForm, self).save(commit=False)
password = self.cleaned_data["password"]
if password:
user.set_password(password)
if commit:
user.save()
return user
class Meta:
model = get_user_model()
fields = ['email', ]
СУТЬ:
Если делаете перечисление полей в виде кортежа, после последнего элемента обязательно должна быть поставлена запятая. А лучше перечисляйте в квадратных скобках, как список - тогда точно не ошибётесь. Грабли, на которые наступают все новички, и я в том числе тоже.
Потенциальная возможность ошибки:class Meta:
model = get_user_model()
fields = ('email',)
Ошибки исключены
class Meta:
model = get_user_model()
fields = ['email']
Non Unicode character at position...
Введение
Как я уже писал ранее, моя компания использует множество проектов, написанных на Python. В качестве платформы для некоторых продуктов используется M3, построенная на основе популярного фреймворка Django. При первоначальной установке проектов на боевые сервера я столкнулся с тем, что при загрузке на сервер файлов, в имени которых встречается кириллица, система выдаёт невнятные сообщения. Оказалось, что проблема заключается в неправильной работе Python с кодировками, в которых хранятся имена файлов. В частности, от этого постоянно падали PIL и Pillow, а в некоторые разделы файлы не загружались вовсе.
В поисках решения
Первым делом я отправился в гугл, конечно же. Введя в поиск заголовок этой статьи, я наткнулся на кучу статей, в большинстве которых предлагались следующие варианты решения проблемы:
- Использовать в коде явное преобразование строк из одной кодировки в другую с помощью встроенных функций языка либо сторонних пакетов.
- Установить в систему нужные локали.
- Прописать настройки в конфигах Django.
- Перейти с этого вашего Python'а на PHP или Ruby On Rails.
Как выяснилось, ни один из этих путей не решает возникшую проблему, однако, второй пункт показался мне достаточно здравым.
Установка в систему нужных локалей.
При установке Debian 7 предлагается выбрать язык системы и кодировку по умолчанию. Если Вы указали свою национальную кодировку (уверен, меня читают не только жители России, но и других стран СНГ), можете этот пункт пропустить. Если же нет, то приступим к установке:
Первым делом следует войти в систему от имени root и выполнить команду по установке пакета управления локалями:
apt-get install locales
После установки этого пакета становится доступна следующая команда:
dpkg-reconfigure locales
Откроется окно, в котором нужно с помощью пробела отметить локали, которые следует держать в системе (можно выбрать вариант "Все локали", но я не рекомендую - чем меньше в системе лишнего, тем лучше). Я оставил там две локали: en_US.UTF-8 и ru_RU.UTF-8.
После нажатия кнопки OK будет предложено выбрать локаль по-умолчанию. Я использую ru_RU.UTF-8.
В самом конце система приступит к генерации недостающих локалей и их установке в систему.
Настройка окружения для работы Python
Как я писал в одной из статей, для запуска проектов на Python 2.x лучшим выбором является виртуальное окружение, созданное с помощью virtualenv, в которое установлен Gunicorn. При этом управление всем приложением осуществляется с помощью Supervisor'а. Здесь же сразу перейдём к делу.
Переходим в каталог настроек приложений Supervisor'а:
cd /etc/supervisor/conf.d/
Открываем файл настроек нашего приложения и приводим его к следующему виду:
[program:project]
environment=PROJECT_CONFIG_PATH="/var/www/project/conf/",DJANGO_SETTINGS_MODULE="project.settings",PYTHONIOENCODING="UTF-8",LANG="ru_RU.UTF-8",LC_ALL="ru_RU.UTF-8",LC_LANG="ru_RU.UTF-8"
command=/var/www/.virtualenvs/project/bin/gunicorn_django -c /var/www/project/conf/gunicorn.conf.py
user=www-data
group=www-data
daemon=false
debug=false
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/www/project/log/supervisor.log
Самая важная строка здесь - та, в которой задаётся значение параметра environment. Именно там указывается, какие локали использовать Python'у для работы с файлами, языком и т.д. Именно эта небольшая строка предотвращает ошибки вида "Non Unicode character at position..." и "Non-ASCII character at position...". Не забудьте удалить переменные окружения, которые на самом деле вам не нужны. При необходимости к окружению можно добавить новые переменные, однако, после запятых не должно быть пробелов, а все значения должны быть заключены в кавычки или апострофы.
После того, как файл настройки будет изменён, следует уведомить об этом Supervisor:
supervisorctl update
Если при этом Supervisor будет выдавать сообщения об ошибках, первым делом следует проверить правильность расстановки кавычек и запятых.
Сборка PIL с зависимостями (Debian 7)
Описание проблемы
Несмотря на то, что уже давно существует и активно развивается библиотека Pillow, импортирующая функции для обработки изображений средствами Python, в некоторых проектах до сих пор используется устаревший (последняя версия вышла в 2009 году) модуль PIL. Если Вы из тех "везунчиков", кому приходится поддерживать старые проекты, то эта статья для Вас. При установке PIL в виртуальное окружение вводится командаpip install pilПосле этого начинается процесс загрузки расширения и его сборки, выводится куча сообщений, и в самом конце можно увидеть следующий текст:
PIL 1.1.7 SETUP SUMMARY
--------------------------------------------------------------------
version 1.1.7
platform linux2 2.6.8 (unknown, Jan 26 2013, 14:35:25)
[GCC 4.7.2]
--------------------------------------------------------------------
*** TKINTER support not available (Tcl/Tk 8.5 libraries needed)
*** JPEG support not available
*** ZLIB (PNG/ZIP) support not available
*** FREETYPE2 support not available
*** LITTLECMS support not available
--------------------------------------------------------------------
To add a missing option, make sure you have the required
library, and set the corresponding ROOT variable in the
setup.py script.
Что означает примерно следующее: модуль успешно собран, но работать не будет, т.к. ни одно из требующихся расширений установлено не было.
Немного погуглив, я натолкнулся на кучу форумов, где описывалось решение, заключающееся в создании символических ссылок на нужные библиотеки в каталоге /usr/lib, однако, ни одно из этих решений не оказалось рабочим. В этой статье я описываю своё решение сборки PIL с поддержкой практически всех нужных расширений.
Установка
Для сборки и установки PIL с зависимостями нам потребуются некоторые дополнительные пакеты- python2.6-dev - заголовочные файлы для сборки Python2.6. Если используете другой - указываете другой.
- libjpeg62-dev - для поддержки JPEG (в Debian есть также libjpeg8-dev, но она не подойдёт)
- zlib1g-dev - поддержка PNG
- libfreetype6-dev - поддержка шрифтов
- liblcms1-dev - поддержка LITTLE CMS. Что это такое, я не знаю, можно не ставить.
apt-get install libjpeg62-dev zlib1g-dev libfreetype6-dev liblcms1-devВсе необходимые зависимости, в том числе GCC, если он не установлен, установятся сами. Итак, необходимые системные пакеты установлены. Теперь нужно будет сделать несколько дополнительных действий с самой библиотекой. Первым делом её нужно скачать с официального сайта.
wget http://effbot.org/downloads/Imaging-1.1.7.tar.gzРаспакуем архив:
tar xfv Imaging-1.1.7.tar.gzЗайдём в созданную папку и отредактируем файл setup.py
cd Imaging-1.1.7 nano setup.pyТут нужно внести следующие изменения:
TCL_ROOT = NONE JPEG_ROOT = NONE ZLIB_ROOT = NONE TIFF_ROOT = NONE FREETYPE_ROOT = NONE LCMS_ROOT = NONEзаменяем на
TCL_ROOT = '/usr/lib/x86_64-linux-gnu/' JPEG_ROOT = '/usr/lib/x86_64-linux-gnu/' ZLIB_ROOT = '/usr/lib/x86_64-linux-gnu/' TIFF_ROOT = '/usr/lib/x86_64-linux-gnu/' FREETYPE_ROOT = '/usr/lib/x86_64-linux-gnu/' LCMS_ROOT = '/usr/lib/x86_64-linux-gnu/'В x86-системах вместо x86_64 нужно вводить i386. Тем самым мы указываем, откуда брать библиотеки. Теперь можно попробовать собрать PIL со всеми расширениями (без реальной установки):
python setup.py build_ext -iЕсли сообщение выглядит примерно так:
--------------------------------------------------------------------
PIL 1.1.7 SETUP SUMMARY
--------------------------------------------------------------------
version 1.1.7
platform linux2 2.6.8 (unknown, Jan 26 2013, 14:35:25)
[GCC 4.7.2]
--------------------------------------------------------------------
*** TKINTER support not available (Tcl/Tk 8.5 libraries needed)
--- JPEG support available
--- ZLIB (PNG/ZIP) support available
--- FREETYPE2 support available
--- LITTLECMS support available
--------------------------------------------------------------------
To add a missing option, make sure you have the required
library, and set the corresponding ROOT variable in the
setup.py script.
можно смело устанавливать PIL в виртуальное окружение Вашего проекта. Перед этим рекомендую удалить старую версию через
pip uninstall pil -yи удалить файлы в каталоге lib/site-packages виртуального окружения:
cdsitepackages rm -rf PIL*Установка PIL:
python setup.py install
Заключение
В некоторых проектах БАРС Груп используется PIL, он прописан в зависимостях для установки их пакетов через setup-tools. В этом случае я делаю так:- Устанавливаю PIL
- Устанавливаю пакет, провожу миграции и т.д.
- Удаляю PIL и ставлю Pillow, т.к. Pillow импортирует те же самые функции и пространства имён, что и PIL.

