Раздел Питон

mysql-python в virtualenv

В мою практику не так давно вошел такой tool как virtualenv, мне нравится для каждого проекта создовать обсалютно изолированную среду.

Всегда бывает нужен байндинг mysql-python. Если устанавливать с использованием pip надо чтобы в убунту были установлены пакеты libmysqlclient-dev и python-cxx-dev

sudo apt-get install python-cxx-dev
sudo apt-get install libmysqlclient-dev

uWSGI умирает на Ajax запросе

В общем никак не получалось отправить Ajax запрос по одному урлу. В результате пойму что дело не в урл, а в том как посылается запрос.

веб сервер

nginx -V
nginx version: nginx/0.7.65
built by gcc 4.4.1 (Ubuntu 4.4.1-4ubuntu8)
TLS SNI support enabled
configure arguments: --with-http_stub_status_module --with-http_flv_module --with-http_ssl_module --add-module=../uwsgi/nginx/ --prefix=/home/ejudge/distr/nginx

upstream uWSGI версия 0.9.7.2

На сайте есть голосования за контент, в момент нажатия на батн, отправляется ajax запрос используя jqyery

function qvote(container, direction){
    elem = $(container).parent().find(".qvote-score");
    $(elem).fadeOut();
    $.ajax({
        type: "POST",
        dataType: "json",
        cache: false,
        url: $(container).attr('href'),
        success: function(json){
            if (json != null){
                if (json.success == true){
                   $(elem).html(""+json.score.score);
                }
            }
            $(elem).fadeIn();
        },
        error: function(){
            $(elem).fadeIn();
            alert("No response :(");
        }
    });
}   

из ChromeInspector'а видно что запрос уходит, из логов видно что nginx его принимает, и ... виснит ожидая uWSGI.

смотрим в логи uWSGI видим, что worker тупо умер. Точнее сделал себе харакири

*** HARAKIRI ON WORKER 4 (pid: 6329) ***
HARAKIRI: --- uWSGI worker 4 (pid: 6329) WAS managing request /voting/blog/post/153/upvote/ since Fri Apr 22 11:22:19 2011 ---
DAMN ! process 6329 died :( trying respawn ...

после этого nginx подождал целую минуту так как uwsgi_read_timeout не был указан, а по умолчанию 60 сек.

И только потом возвращал response со статусом Bad Gateway.

Я добрую неделю пытался сделать что-то с сервером.

Решение есть

Чудеса в питоне 1

Уже не раз я получал ошибку типа ImportError: cannot import name Foo. Из своего опыта в django и python знаю, что такое происходит когда есть цикл зависимостей. То есть когда A нежен B, а B нужен A. Циклы бывают и посложнее: A нужен B, B нужен C, С нужен D, а D нужен B. Такое обычно происходит в результате нарушения логичной структуры кода. В принципе в этот раз было тоже самое, однако было это особо развратно.

Я получал эту ошибку в момент когда запускался метод перевода текста. Подумать только, как можно получить цикл зависимостей пытаясь перевести строку стандартным django'овским методом ugettext.

Оказалось что можно.

Cross post на yVision

В день отлета из Алматы мне захотелось замутить кросс-постинг на yVision со своего блога. Я подумал, что было бы здорово если бы у меня была например такая кнопочка

Попытки погуглить crossposting на yVision ничего не дали. И тогда я поискал что есть у Питона по этой теме. Остановился я на ClientCookie, ClienForm библиотеках. В тот же день добился вот такого результата, с помошью которого я смог закинуть свой первый Test Post.

#coding: utf-8
import urllib2, cookielib
import ClientCookie
from ClientForm import *

YVI_LOGIN = "your login"
YVI_PASSWORD = "and password"
# если знаете можно указать ID своего логина
# но не обязательно.
YVI_USER_ID = None

# нам надо получить куки авторизации
request = ClientCookie.Request("http://yvision.kz/auth/")
response = ClientCookie.urlopen(request)

# парсим все формы, на страничке
forms = ParseResponse(response, backwards_compat=False)
# нам нужна вторая, первая это фома поиска
form = forms[1]

# заполняем форму, меням экшн. через аякс данный отправляются именно сюда
form.action = 'http://yvision.kz/ajax/auth/login.php'
form['login'] = YVI_LOGIN
form['password'] = YVI_PASSWORD
request = form.click()
# получили куки
response = ClientCookie.urlopen(request)

# теперь идем на нашу форму добавления поста
request = ClientCookie.Request('http://%s.yvision.kz/manage/article/add' % YVI_LOGIN)

# если надо подрелактировать существующий пост, тогда идем сюда
#POST_ID = 55019
#request = ClientCookie.Request('http://%s.yvision.kz/manage/article/edit/%s' % (YVI_LOGIN,POST_ID))

response = ClientCookie.urlopen(request)
# парсим все формы, на страничке
forms = ParseResponse(response, backwards_compat=False)
# нам нужна третяя, первая это фома поиска, вторая форма логаут
form = forms[2]

# заполняем форму, меням экшн. через аякс данный отправляются именно сюда
form.action = 'http://%s.yvision.kz/ajax/post/article.php?publicate=1' % YVI_LOGIN
form['blog_title'] = "Python-Yvi Crosspost Test"
form['blog_post'] = "<p>Python-Yvi Crosspost Test</p>"
form['blog_tags'] = "test,crosspost"
if YVI_USER_ID is not None:
    form.new_control('hidden','user-id',{'id':'user-id','value':YVI_USER_ID})
form.new_control('hidden','save',{'value':'Сохранить (останется скрытой)'})
form.new_control('hidden','saveexit',{'value':'Опубликовать'})

#form.controls.remove(form.find_control('publ'))
#request.add_header('X-Requested-With', 'XMLHttpRequest')
#request.add_header('X-Prototype-Version', '1.6.0.2')

# постим
request = form.click()
response = ClientCookie.urlopen(request)

потом начал прикручивать, это дело к своему блогу и тут у меня вышли проблемы с кодировкой. когда пишешь на русском, выходит exception. И я не смог доделать эту фичу в тот же день. Мы улeтели в анкару.

И вот сегодня на работе, добравшись до интернета решил снова покопаться. очень долго сверлил гугл, надеясь нарваться на что-нибудь похожее. В результате нашел... :) причина оказалось в беспанотовости urllib.quote_plus. в общем я немного подредактировал ClientForm.py, и все заработало.

вот тут лежит архив c библиотеками и моей реализацией задачи

yvi_crosspost.tar.gz

ну вот. как-то так. вроде работает. :)

Читать далее