Чтобы добавлять сообщения и комментарии, .

@hizel:
hizel

"The future of Pylon-style web application development is Pyramid." WTF!?

@Kxepal:
Kxepal

вот и вышел первый релиз pyramid 1.0
groups.google.com

@rakoth:
rakoth

Я не понял, pylons что, мёртв? Новостей с лета нет, в вике ещё дольше без изменений. Панике! А хотел посмотреть как у него с питоном3...

@iorlas:
iorlas

Отрефакторил тучу кода, переделал немного модели, изменил некоторые части системы, добавил пару моделей, имплементировал систему ивентов.
Вот с последним всё оказалось очень и очень фигово. Класс системы ивентов, который принимает контекст, пользователя и соединение с бд, должен был импортироваться в куче классов, при этом сам должен иметь возможность импортировать другие классы для хендлеров ивентов. В общем, циклическая зависимость. Тучи их. Пришлось отказаться и сделать более прозрачно. С другой стороны, достаточно логично.
С написанием больших приложений на пайтоне, проблема циклических зависимостей встаёт всё острее и острее. Стоит помнить одно — нужно проектировать систему на БУМАГЕ перед имплементацией и сразу выделять где есть кольца. Не всегда это "плохой дизайн", но решать лучше проблемы до написания сотен строк кода.
Кстати говоря, для решения проблемы циклических зависимостей можно использовать Слабые ссылки (Weak References). Как я понял их суть(хотя я пока о них не читал почти ничего) в создании ссылок на первые объекты в циклической зависимости. Т.е. тогда она станет линейной. Потому почитаю о них и попробую что и как.

@iorlas:
iorlas

Общее впечатление от pyramid — хорошее, очень хорошее. Главное — это проект, который создавался с идеями. Это не какой-то проект "вот давайте сделаем, а потом всё придумаем", это действительно философия и новый взгляд на разработку.
Главный недостаток всего этого — документация. Её хоть и много, но примеров не достаточно, не везде и не всё изложено как надо, слишком много информации разбросано, слишком мало информации по некоторым частям. Трудно всё понять сразу.
Пока всё идёт к разделению разработки проекта на такие части:
1) Реализация видов(бывшие экшны в контроллерах). К слову, виды можно реализовывать в группах — классами-хендлерами(http://docs.pylonshq.com/pyramid/dev/narr/handlers.html), что позволяет реализовывать большие проекты без дискомфорта, который бы возник, будь только одна возможность добавления видов — через добавление каждого вида по отдельности.
2) Конфигурация видов. Достаточно просто. Добавил вид, указал и забыл.
3) Реализация фабрики, методов __getitem__. Это и есть новый, мало знакомый элемент, который ещё только предстоит изучить.
4) Подписывание на ивенты(http://docs.pylonshq.com/pyramid/dev/narr/events.html), через которые, к слову, можно всё реализовать, в т.ч. подключить миддлвари, препроцессинг, постпроцессинг etc. Именно этот элемент Pyramid позволяет сделать всю настройку приложения более централизованной, без потери гибкости. Т.е. теперь не нужно лезть в middleware.py и добавлять всё своё чудо в функцию пайлонсов, не нужно редактировать базовый класс контроллера. Всё делается очень и очень просто!
5) Реализация моделей графов(те что в models.py), которые, судя по всему, должны являться только адаптерами между графом объектов и БД(хотя может быть и не бд, например).
etc.
Все пункты хороши, вот только 3 и 5 пока только появились и их особо никто не успел распробовать, нет юз-кейсов, нет никаких указаний как это лучше использовать. Трудно сказать как оно всё отразится на программировании, но разграничение на такие части должно хорошо сказаться на результате.

@iorlas:
iorlas

У многих могут возникнуть вопросы на счёт этого примера docs.pylonshq.com .
"Что это за PersistentApplicationFinder? Судя по всему, он сам генерирует фабрику!"
С виду, можно подумать и так, но на самом деле это просто прослойка между фабрикой и приложением. Цель прослойки — открыть коннект к бд и передать его в фабрику.
Иначе говоря, appmaker это и есть get_root, просто он обёрнут в класс, который поднимает коннект к ZODB. Никакой магии, просто пример того, как можно это использовать.
Вообще, я не понимаю зачем создан ZODB, какие задачи выполняет и нужен ли он для чего-то бОльшего чем просто демонстрация.

@iorlas:
iorlas

Итак, начинаем привыкать к тому, что экшны в контроллерах пайлонс(или просто контроллер как реализация во многих фреймворках) — ВИД! Это одна функция. Вне класса(контроллера в пайлонс, например). Это одна функция, которая имеет имя, которое никак не влияет на поведение приложения. На имя функции не накладываются ограничения кроме тех, что дают логика мозга и вообще пайтон.
Сделав функцию-обработчик запроса(вид), мы должны его настроить так, чтобы траверсал его находил когда нам нужно, а мы акцентировали своё внимание только на нужном нам коде, который мы пишем.
docs.pylonshq.com
docs.pylonshq.com
Я не зря хайлайчу слово view_config. В Pyramid есть два варианта настройки вида:
1) Через __init__.py(где производится настройка приложения).
2) Через декоратор view_config.
Первый вариант позволяет спрятать конфигурацию вида так, что ты будешь писать код и не думать о том, что и как у тебя с текущим видом, грубо говоря.
Второй вариант более привычный и лучше подойдёт для больших приложений.
Собственно, что есть настройка вида: указание какой рендерер использовать(вообще, это сразу строка с путём до темплейта), имя функции(а вот это — самое интересное, ибо по нему ищутся методы и это значение не обязано быть уникальным для проекта), контекст(об этом чуть позже) и ещё тучу всяких плюшек, о которых потом может быть напишу.
Стоит отметить, что разрешается использование нескольких декораторов для одной функции:http://docs.pylonshq.com/pyramid/dev/narr/views.html?highlight=view_config#view-config-placement
More than one pyramid.view.view_config decorator can be stacked on top of any number of others. Each decorator creates a separate view registration.
Нас в первую очередь интересуют 2 параметра настройки вида: name, context. Если name и так понятно, по нему будет искаться 'delete' метод из предыдущей заметки, то с контекстом не всё так просто.
Контекстом может быть:
1) Адрес до класса, инстансом которого должен быть контекст
2) Родитель класса, инстансом которого должен быть контекст
3) Веб-эксепшн
Возможно, что-то не совсем так, возможно, есть ещё возможные варианты контекстов, но суть должна быть понятна: в параметре вида context мы указываем тип контекста, который поддерживается видом, который обрабатывается видом.
К слову, здесь есть полная поддержка zope.interfaces. Можно сделать 3 класса от одного родителя(или 3 имплементации одного интерфейса) и отдавать из через фабрику, а в настройке нашего вида указывать родителя. Таким образом вид будет матчиться под все три класса если они будут контекстами.
Если мы не указали контекст в параметрах, то матчиться будет по имени.
И на последок, 2 настройки вида для матчинга первого примера и второго:
#('delete', User, '/lol')
@view_config(context="proj.models.User", name="delete") #хотя фиг знает, лучше фигурировать инстансами, а не классами, предположим что мы в графе отдаём инстанс
def delete_all(context, request):
....context.delete_all()

#('delete', SqlUser(id=10), '')
@view_config(context="proj.models.SqlUser", name="delete")
def delete_by_id(context, request):
....context.delete()

@iorlas:
iorlas

Пол-дня разбирались в доках Pyramid, но всё-таки добрались до истины.
Главной и самой интересной частью пирамиды является траверсал, а точнее модели и траверсал. Очень трудно понять с ходу что же такое "модель" в данной системе, что такое корневая фабрика, что такое граф моделей, как вообще работает траверсал, зачем и как это правильно использовать.
Что же такое "фабрика моделей" и вообще траверсал?
Траверсал — модуль пайтона из комплекта repoze, который позволяет определять контекст, контроллер и дополнительные параметры запроса по url path БЕЗ необходимости в "обычном" маппинге, как мы привыкли в пайлонс или где-либо ещё.
Вся логика его работы здесь:
docs.pylonshq.com
Как он работает:
After the path info is converted, a lookup is performed against the object graph for each path segment. Each lookup uses the __getitem__ method of an object in the graph.
Traversal pops the first element (a) from the path segment sequence and attempts to call the root object’s __getitem__ method using that value (a) as an argument; we’ll presume it succeeds.
When the root object’s __getitem__ succeeds it will return an object, which we’ll call “A”. The context temporarily becomes the “A” object.
...
This process continues until the path segment sequence is exhausted or a lookup for a path element fails. In either case, a context is found.
В результате, последний найденный объект в графе становится контекстом, следующий(текущий в поиске, который провалился) — именем контроллера, а остальное — дополнительной частью пути, которая добавляется в запрос как параметр.
Пример:
/user/delete/lol
Вызываем фабрику — получаем саму фабрику как контекст.
Запрашиваем у фабрики объект по имени user. Нам возвращают модель User(чтобы быть ближе к тому что делали с разными ORM, предположим что это не инстанс, а ссылка на класс).
У полученного объекта запрашивается следующий объект — 'delete'. Этот объект не был найден, ибо контекстом стал объект, у которого даже нет метода __getitem__, т.е. это даже не фабрика.
Контекст не меняется(последним контекстом была ссылка на класс User). Названием контроллера для поиска стало delete, а остаток от пути — '/lol'.
Ещё пример:
/user/10/delete
context = get_root() #fabric
context = context.__getitem__('user') #User class
context = context.__getitem__('10') #Вот здесь интересно! Допустим, что мы сделали статичную функцию __getitem__ у класса User, которая принимает аргумент name(искомое имя). В этой функции мы вызываем метод get_by_id этого же класса User(однако, можем вообще сделать прямой запрос через pymongo или SA, или вообще вызвать метод другого класса). Как результат, мы возвращаем инстанс модели SqlUser(например, хотя можно инстанс этого же класса или вообще что угодно, как хочется), поле id которого равно 10.
#User instance with id 10
context = context.__getitem__('delete') #Exception
return ('delete', context, subpath)
Напомню результаты обоих примеров:
('delete', User, '/lol')
('delete', SqlUser(id=10), '')
Как видно из этих примеров, огромную часть логики можно переложить в отдельное место, а разработка теперь ещё больше разделена на части, что упрощает всё, позволяет акцентироваться на нужном в нужное время. Разработка состоит и из построение этого графа.
Следует отметить тот факт, что если корневой фабрикой ничего не указано или None, то она становится пустым классом, т.е. контекстом становится сам пустой класс, а именем для поиска контроллера — первый же элемент в url path. docs.pylonshq.com
Нужно добавить, что я употреблял слово "контроллер" только для обратной совместимости с пайлонс и вообще для людей, которые привыкли называть хендлеры путей в вебе контроллерами.

@iorlas:
iorlas

Первое впечатление о Pyramid было достаточно плохим. Очень плохим, я бы сказал. Чуть лучше чем о repoze.bfg, когда он только вышел. Куча документации, в которой мало конкретики, странные новые вещи, которые используются не так как привычно etc.
Сейчас посмотрел ещё раз и, в общем то, оно мне нравится. Не всё, конечно, но общие концепции хороши.
Из непонятных мне вещей:
1) Причина отказа от создания директорий для контроллеров и моделей.
Зачем? Они что, решили ориентироваться на столь малые приложения, где всё может уместиться в один файл? Бред и ужас. Если "рыба" Pylons выглядит как нормальный проект, в котором можно сделать свой фейс-бук, то после создания проекта через темплейты Pyramid, я могу предположить что мне предлагают написать веб-морду для пиджина, трансмишшн или просто написать хомяк/гостевушку. Я бы мог понять если бы они решили сделать как в Django, т.е. чтобы была необходимость создавать вложенные приложения, т.е. создавая дерево приложений, которые имплементируют свою, определённую функциональность, цель, задачу. НО, как мы видим, ничего такого нет. Хотите что-то бОльшее — сами создавайте и контроллер(простите, вид), и новый конфиг, и модели.
2) Идеология контекста, моделей.
Сказано что это не те модели, к которым мы привыкли. Однако, толком не рассказано что это теперь это такое. Сказано что теперь контекстом становится МОДЕЛЬ. При этом, контекст формируется АВТОМАТИЧЕСКИ, из ПУТИ. При этом само выбирает какую модель использовать.
Новый маппер(роутер) — Траверсал. Это круто, в нём заложена и великая цель — определять какую модель нужно достать и какой вид дёрнуть.
Как это делает Траверсал:
путь: site/bar/foo
bar — название модели
foo — вид
путь: site/cor/snor/bar/buz/foo
buz — название модели
foo — вид
И что это за бред? Куда это? Как это вообще правильно использовать чтобы если кто-то ввёл /user/buy вместо item/buy, то всё не упало к чертям?

@iorlas:
iorlas

cd34.com Пара заметок о переходе с пайлонс на пирамиду

@iorlas:
iorlas

docs.pylonshq.com Until the end of 2010, Pyramid was known as repoze.bfg; it was merged into the Pylons project as Pyramid in November of that year.
А люди то и не знали!

@iorlas:
iorlas

А завтра нужно будет подключать гугл... Привет github.com ! Конечно, немного быдлокод, но надо будет заюзать, своё писать всё-равно лень, кекеке.

@iorlas:
iorlas

Переписал старый модуль авторизации. Теперь у меня есть один аутентификатор с челленджером, который делает всю работу + идентификаторы для каждого тима систем авторизации. Как же просто всё пишется на пайтоне! Как же хороша система repoze.who+what!
Конечно, я пока не доволен своей имплементацией универсальных плагинов для repoze, но оно меня радует, очень радует.

@Kxepal:
Kxepal

интересные новости принес @odin в #1032105 : repoze.bfg + Pylons = Pyramid.
Переписывая ядро Pylons для 2.0 они поняли, что изобретают тоже самое, чем является repoze.bfg и решили вместо дублирования функционала смержиться с repoze.bfg. Таким образом, repoze.bfg с версии 1.4 становится ядром Pyramid(repoze.bfg-1.3 будет получать только багфиксы), Pylons 1.x останется на поддержке, а все новые фичи и улучшения Pylons будут уже реализованы в рамках Pyramid, тем самым воплощая идеи версии 2.0...
...и вместо yaml конфигов нам достается zcml, чудесно!

@demiazz:
demiazz

а есть ли такая же хорошая структурированная документация по сабжам, как и по Django? Для начального въезжания так сказать

@eigenein:
eigenein

Итак... заработала обёртка над WebSocket, заработал протокол чата веб-сокетах с прикруткой к фреймворку, киданием друг в друга json'ами. Заработала авторизация, которую было сделать не очень просто... Неприятно, что кода получилось многовато... Хм. Надо прикрутить гуй к тому, что реализовано в протоколе, и потом заняться расширением и/или оптимизацией...

@derFeniX:
derFeniX

Попробуем этот фреймворк... а то django меня как-то не вдохновляет совсем...

@hizel:
hizel

внедрять
cascade="all, delete, delete-orphan"
в relationship неудачная идея для меня :}

@mc:
mc

смотрю python pylons, там шаблоны с расширением mako. Привет, Мако ^^

@hizel:
hizel

1.0 Release pylonshq.com
точно напьюсь :)

@kb:
kb

кстати, оказалось таки зря я грешил когда-то, что сервер перезапускается целых 20 секунд (или больше). Оказалось, что мы выгребали все категории товаров, а их 26000 с лишним штук (или около того). Потом начали выгребать в redis как-то ловко и из него читать, скорость стала около 15 секунд. Сейчас, с новым редисом это время — 5-7 секунд. Viva la redis!

@kawaikunee:
kawaikunee

Python, Pylons, good!

@gvard:
gvard

Еще одна вариация того способа, которым я в Джанго делаю картинки на лету: wiki.pylonshq.com
Тут те же самые canvas.tostring_rgb() и PIL.Image.fromstring(), но чуть иная система работы с канвасом бекэнда Agg. Почему никому (судя по выдаче гугла) не приходила идея не делать тустринг, фромстринг, а сразу матплотлибом сохранить картинку? Это работает (и результат мне нравится больше), но почему возникает потеря производительности?

@binary:
binary

Цитата из учебника по pylons:
request.params
This is a dictionary-like object with a combination of everything in request.GET and request.POST. You will generally use request.params rather than request.GET or request.POST, although they all share the same API. I’ll cover request.params more closely in a minute because it is the main object you will use to deal with form submissions.
pylonsbook.com

я, видимо, что-то не так понимаю. зачем при обработке форм юзать сразу и GET, и POST? Привет грабли, на которые не так давно наступал жуйк?