neithere Python, Music, Laziness en-us Sat, 23 Jan 2016 00:00:00 +0000 <![CDATA[Стихотвари]]>


Заново опубликовал подборку стихотварей, исчезнувших в 2013 при миграции на Tinkerer.

Sat, 23 Jan 2016 00:00:00 +0000 <![CDATA[Argh and Monk Moved to Github]]>

Argh and Monk Moved to Github

TL;DR:My Argh library has been moved from Bitbucket to Github.

I’m hosting my Python stuff at Bitbucket since early 2009 (with the oldest repo created on 2009-02-20).

Bitbucket is a great alternative to Github: it provides unlimited free private repositories (including sanely defined conditions for teams); it supports both Mercurial and Git. Pull requests and many other features popular on Github are also present. Why would one want to move from this excellent SaaS to another one, equally non-free?

Two things: Community and CI.


Github is no doubt more popular, even being inferiour to Bitbucket is some aspects. Maybe because it was the first Google Code killer; or maybe because Bitbucket was a “github for Mercurial” until it became clear that Git was the choice of the majority and the niche was occupied. I don’t think features or usability matter that much.

A popular code hosting service means a huge community.

There were cases (definitely more than one) when people would register on Bitbucket only to file an issue; who knows how many times they simply wouldn’t bother to register. Also, their contributions were of lower quality because they were unfamiliar with the site and the VCS. They could add a pull request but they failed to figure out how to do it and simply posted an issue (hopefully with a patch).

Bitbucket is by no means a marginal service. Nevertheless, by hosting my active projects there I prevented them from receiving a certain amount of care from the community. It is also possible that some developers simply missed them while searching on GH.

Continuous Integration

This was actually the migration trigger for me. I was waiting and waiting for an adequate CI solution available for Bitbucket. A simple solution that just works, you know. And that’s free because I’m not going to pay for such a service if its sole purpose is to test software that I support without any monetary profit (haven’t got not a single cent, actually — and never tried).

The only thing that I could find recently for BB was It’s fine but makes little sense for me because the Python version can be specified in project settings, period. You can test against py26 OR py27 OR py32, etc. But what I need — and why I need a CI in the first place — is something that would ensure that my commit passes all tests in all environments that I’m willing to support. For example, Argh must be continuously tested against py26, py27, py32, py33 and pypy. I could run tox locally but it’s very slow and still allows a certain degree of machine-dependent floating bugs.

So, having Travis CI freely available for any repo at Github was enough to finally convince me to move.

Mercurial vs. Git

I’ve been using Mercurial for five years. Yes, I did try Git. And again. And then again. And all the time Mercurial was flat out better: easier and more intuitive, or at least good enough. This was my major point re I-dont-wanna-even-touch-that-github.

My new job, however, required me to use Git. At some point I tried HgGit but it was a disaster. So, okay, let’s play this Git game. Why not. Aaand, well, I like it. Mercurial has indeed a much better UI: more concise, more intuitive (this doesn’t really depend on experience), better thought-out. But Git’s staging area and light branches are very practical, and when you come back to Mercurial, you miss them much more than Hg’s CLI in Git. By the way, Git’s enigmatic and cumbersome interface can be partially “fixed” by aliases:

unstage = reset HEAD --
last = log -1 HEAD

To sum up:

  • Git is quite OK, just like Hg.
  • Github is quite OK, just like Bitbucket.


There’s probably no need to move my rather popular and stable projects like django-autoslug: the community has already helped to polish the library and has it in bookmarks. By moving the code to another site I would only break people’s bookmarks and confuse them. There would be not much profit from CI either as the code has stabilized and it is highly doubtful that any significant changes are to be expected any soon. So old stuff stays where it is regardless on how popular it is.

Most private projects won’t profit from public interest and don’t need testing anywhere but on my own machine(s). So they stay, too.

However, my actively developed projects that can be useful to the community and can profit from public interest are to be moved. The first two are Argh and Monk. You can subscribe if interested. :-)

Fri, 23 Aug 2013 00:00:00 +0000 <![CDATA[Languages in Europe]]>

Languages in Europe

Found an interesting article Europeans And Their Languages.

It turns out that only half the European population can use a foreign language in communication.

English is, of course, the most popular L2; the role of German and French languages is now less important than it used to be.

What’s also interesting is that Russian language is among three most popular FLs in five EU countries, of which three were part of USSR (LT, LV, EE) and one was part of Russian Empire a hundred of years ago (PL), while BG was only politically associated with USSR some fifty years ago.

Mon, 04 Mar 2013 00:00:00 +0000 <![CDATA[ArchLinux + Brother MFC 7860DW]]>

ArchLinux + Brother MFC 7860DW

First shalt thou take out the Holy Pin, then shalt thou count to three, no more, no less. Three shall be the number thou shalt count, and the number of the counting shall be three. Four shalt thou not count, neither count thou two, excepting that thou then proceed to three. Five is right out. Once the number three, being the third number, be reached, then lobbest thou thy Holy Hand Grenade of Antioch towards thy foe, who being naughty in My sight, shall snuff it. – Monty Python

I bet you came here because you have a Brother MFC 7860DW (or similar) and it doesn’t work with your ArchLinux box. It is common to spend more time than needed on such tasks because an average human being doesn’t solve them on a daily basis. Below I’ll describe the short path to success (which I wish I had followed from the very beginning) and highlight problems that may arise.


Mon, 18 Feb 2013 00:00:00 +0000 <![CDATA[Procrastination]]>


A selection of (not necessarily) funny and (in varying degrees) recent posts addressing the topic.

Working remotely:

Mon, 04 Feb 2013 00:00:00 +0000 <![CDATA[Tinkerer]]>


My old website had been out of date for a long time. A couple of years ago I decided to refurbish it and replace Django with Sphinx (as the site is indeed completely static). This attempt resulted in two branches of the repo being developed simultaneously – at an incredibly slow pace, because vanilla Sphinx is not very suitable for personal websites. There is a variety of Sphinx-based tools. Choosing between them was a challenge, too.

Anyway, today I decided to try Tinkerer. Scrapped old stuff, copied some of it; mostly starting from scratch. Will see if it works.


After some fiddling with Fabric the site is finally up and running. Nice workflow.

Tue, 29 Jan 2013 00:00:00 +0000 <![CDATA[Workflow]]>




Действие:Action, Activity


Набор условий, по которым возможны:

  • отбор подмножества сущностей
  • валидация конкретной сущности


Динамические компоненты (выполнение действия):

  • сущность и набор ее атрибутов
  • актор (пользователь)

Статические компоненты (определение действия):

  • начальное состояние
    • проверяет, соответствует ли ему сущность до трансформации
  • конечное состояние
    • проверяет, соответствует ли ему сущность после трансформации
  • описание трансформаций (если действие автоматическое)
    • декларативное (описание соответствий атрибутов между состояниями)
    • императивное (набор команд)
  • актор (пользователь или группа пользователей, которым доступно данное действие) – не обязательно

Валидация полностью ложится на состояния.

Действие выполняется как транзакция: изменения в объекте не сохраняются, если после выполнения действия конечное состояние не прошло валидацию.

Занятно, что действие не накладывает ограничений на типы сущностей – их обрабатывают состояния.


Агрегирующие действия

Содержат не состояния, но цепочки обычных действий.


Вышеописанная простая схема реализует простой WF, когда требуется взять одну сущность и как-то ее обработать. На практике встречается необходимость проверять более одной сущности, т.е. может быть более одного входного состояния, причем они могут сочетаться как AND, так и OR.

См. Notations and Workflow Patterns (PDF) – спасибо xzzr за линк.

Fri, 20 Feb 2009 00:00:00 +0000 <![CDATA[О базах данных]]>

О базах данных

2009-02-13, UPD: 2009-02-21.
see also – duck typing for data

В заметке приводятся рассуждения об имеющихся на данный момент основных подходах к хранению данных и связанных с ними проблемах. Кратко рассматриваются реляционные БД, хранилища триплетов и документоориентированные хранилища. Предлагается считать последние наиболее перспективным решением.

Реляционные СУБД

Реляционная модель позволяет сконцентрировать информацию о неком объекте в виде ячеек одной строки таблицы и установить связи между строками разных таблиц. Модель имеет серьезный недостаток: заранее жестко фиксируется и типизируется набор свойств объекта. В результате сфера применения такой модели относительно узка. Тем не менее, на практике реляционные СУБД используются повсеместно ценой значительной костылеёмкости (к которой мы настолько привыкли, что не осознаем всей нелепости универсального применения этой модели). Иногда для повышения гибкости БД практикуется создание EAV-хранилищ поверх реляционной СУБД. Таким образом значительно снижается производительность, но обеспечивается гибкость.


Хранилище фактов (triplestore) в виде триплетов (объект,предикат,субъект) – очень гибкий способ управляемого хранения данных. Факты образуют семантическую сеть. С помощью правил нетрудно автоматически вывести новые факты из имеющихся. Если в реляционных СУБД строка таблицы содержит в себе данные, то в семантической сети узел не содержит ничего кроме идентификатора. Зато можно найти факты, ссылающиеся на данный узел: эти факты и есть описание узла.

Выборка данных представляется весьма удобной. Более не нужно комбинировать таблицы, достаточно указать несколько фактов, где нам известна лишь часть данных (нотация условная):

? В каком году родился Джон? : (john born_in ?) ? Кто родился в 1900 году? : (? born_in 1900) ? Когда кто родился? : (? born_in ?) ? Что происходило в 1900 году? : (? ? 1900)

Итак, мы используем простой шаблон и получаем по нему набор фактов. Что характерно, при составлении запроса мы не обязаны учитывать особенности распределения этих данных по таблицам. Нормализация данных вообще не требуется, поэтому структура “идеальна” и способна вместить любую информацию. Нет ограничений на количество свойств узла и количество значений свойства (если только это явным образом не указано в метаданных). Безусловно, это очень удобно.

Впрочем, за абсолютную гибкость приходится платить. Вышеуказанные запросы являются, фактически, фактами с одним или более неизвестными параметрами (обозначенных знаком ?). Ответ хранилища, соответственно, будет содержать факты, соответствующие этим шаблонам. Но эти факты не содержат полного описания искомых узлов графа.

Например, нам нужно узнать имена родившихся в 1900 году. Запрос (? born_in 1900) вернет нам факты с искомыми идентификаторами объектов:

(john born_in 1900), (mary born_in 1900), ..., где john и mary – идентификаторы.

Затем нужно будет сделать целый ряд дальнейших запросов для получения дополнительных свойств этих объектов:

name_facts = []
for birth_fact in get_facts('? born_in 1900'):
    name_facts += get_facts('%s name ?', birth_fact._id)
names = [f.object for f in name_facts]

Для сокращения числа запросов следует внедрить в нотацию переменные:

(?person born_in 1900)-->(?person name ?)

Это эквивалентно join’ам или подзапросам в SQL. Уже в таком базовом случае мы отходим от полностью декларативной нотации. Сложность запросов возрастает в соответствии с количеством узлов и свойств, по которым проводится отбор данных. Приведем один из компактных, но трудных случаев. Запрос на русском языке: “Как люди с фамилией Джонсон связаны с городом Нью-Йорк?”. Тот же запрос в виде триплетов с промежуточными переменными:

(?person ? ?city) where
(?person type 'person'; last_name 'Johnson')
(?city type 'city'; name 'New York')

Ответом будет набор фактов, где искомым параметром является тип связи.

Языки запросов. SQL рожден мертвым

Очевидно, было бы полезно как уменьшить количество отдельных запросов к серверу, так и обеспечить приемлемую форму записи запросов. Для этого есть несколько вариантов:

  • декларативный язык запросов (à la SQL) с поддержкой промежуточных переменных;
  • обработка данных средствами высокоуровневых языков общего назначения:
    • на стороне сервера или
    • на стороне клиента.

Усилия по адаптации SQL к триплетам привели к появлению, например, SPARQL. Им можно пользоваться, но трудно утверждать, что он достаточно прост. В целом он весьма близок к последнему примеру, но добавьте туда указание пространств имен для каждого элемента и получите весьма непростой для чтения синтаксис. Кроме того, параллельное существование одних нотаций для записи данных (таких как N-Triples, N3, Turtle) и совершенно иных для их поиска (SPARQL) вызывает сомнения в уместности как тех, так и других.

Следует отметить, что и сам SQL трудно назвать удачным языком. Целевая аудитория не пишет запросы, она пользуется ссылками и кнопками. А программисты предпочли бы написать запрос на языке программы, над которой работают. Попытка создать универсальный и понятный всем язык напоминает рассказы середины прошлого века, где умная машина в две тысячи энном году общается с человеком путем распечатки рубленых фраз на бумаге. Нет, всё не так. SQL слишком примитивен для разработчика и слишком сложен для пользователя. Поэтому пользователь вообще его игнорирует, а разработчик возводит леса костылей.

Автор заметки полагает, что наиболее перспективной является разработка хорошего API для полноценных языков программирования (как на стороне клиента, так и на стороне сервера) в сочетании с сериализацией данных в JSON.

Сериализация данных


Наиболее популярными языками сериализации данных являются XML и JSON. Они описывают ориентированные графы.

XML для сериализации является, возможно, чересчур гибким, поскольку невозможна однозначная интерпретация (литерал может быть атрибутом узла или вложенным узлом). Для устранения этой проблемы используются <> схемы.

JSON представляется более практичным средством сериализации данных: он не только компактнее, но, что важнее, сохраняет тип данных (строка, число, список, хэш). Однако, поскольку оба языка не имеют средств описания неориентированных графов, обоим необходимы метаданные. Между прочим, YAML, подмножеством которого является JSON, такие средства имеет.


Сериализация таблиц реляционных баз данных требует полного структурного соответствия источника получателю (или механизмов трансляции <,_transform,_load>); кроме того, важны соглашения о том, где при сериализации по внешнему ключу произойдет агрегация, а где ключ останется в виде числа.

Сериализация триплетов значительно проще. Граф заведомо смешанный, поэтому есть смысл в следующих вариантах:

  1. список фактов, где каждый факт состоит из трех URI (напр. в виде пар namespace+id) – удобно для передачи атомарных изменений при регулярной синхронизации;
  2. список узлов, где в информацию об узле входит не только ключ, но и все свойства, включая исходящие связи (т.е. факты, где данный узел является объектом).

Интересно, что второй пункт точно соответствует принципам документных (document-oriented) баз данных. Более того, указанная структура данных в формате JSON лежит в основе одной из _реализаций_ этих принципов.


Документоориентированная база данных – компромиссная модель, сочетающая гибкость триплетов с ёмкостью реляционных кортежей.

Документ содержит произвольное число свойств. Через концепцию документа можно выразить как столбцы таблицы, так и исходящие связи узла (правда, нет возможности специально помечать некоторые свойства как логически выведенные). Поиск узла по свойству и выборка всех свойств узла возможна одним запросом, а не двумя, как при работе с триплетами. Соответственно, при необходимости получить расширенную информацию о цепочке узлов документоориентированная модель оказывается вдвое эффективнее, чем триплетная (если связи в цепочке не транзитивные). Документоориентированная модель отлично сочетается с ООП.

Одной из перспективных реализаций документоориентированного подхода является CouchDB. Что характерно, она позволяет проводить выборку средствами любого языка программирования на стороне сервера БД. Это означает, что можно использовать весьма выразительные средства обработки данных. Другие реализации, достойные упоминания – MongoDB и StrokeDB. К числу ДОБД можно отнести и Tokyo Cabinet/Tyrant при условии, что используется тип хранилища “table”.

Различные нотации для описания триплетов вполне могут использоваться и с документоориентированной моделью как язык сериализации.

В документоориентированной базе данных не существует таблицы фактов, поэтому при необходимости хранения метаданных о фактах (автор, время добавления; для синхронизации также время удаления) потребуется подобную таблицу построить. Впрочем, возможно, более разумным решением был бы журнал изменений. Частично он реализован существующими DODB в виде ревизий документов. Чтобы вести его в явном виде, достаточно написать и подключить компактный middleware-компонент.

Схемы для “бессхемных” хранилищ


(см. мой пост о динамической типизации данных и представлении их в моделях.)


– Да это всё понятно; ты мне лучше скажи, как повидло в конфеты засовывают!

Дальнейшие темы

В заметке не затронута проблема описания сложных концептов. Например, “кот Васька сидит на коврике” или “Первые опыты по хромированию собак провел румынский академик Петрович”. Затруднительно выразить эти мысли триплетами, документами и так далее. Одно из решений – концепт-графы (см. также работы John Sowa: Conceptual Graphs including Examples).

Fri, 13 Feb 2009 00:00:00 +0000 <![CDATA[Nginx + FastCGI + Django]]>

Nginx + FastCGI + Django

Updates: 2008-12-13, 2009-07-19


In late 2008 I was migrating a couple of Django sites from Apache to nginx. I had chosen FastCGI as the glue between the framework and the web server.

Tested software versions:

  • Django (1.0+, pre-1.1)
  • flup (1.0.1, 1.0.3)
  • nginx (0.6.35, 0.7.26, 0.7.61, 0.8.5)

Everything was OK except for one thing:


Django would:

  1. display homepage regardless of the real path, or even
  2. fall into an endless loop.

...which was tracked down to the more concrete problem:

Django could not determine the PATH_INFO environment variable.


No problem-related information could be found in logs.

Quickly I found out that Django needs PATH_INFO to be set to $fastcgi_script_name, but strangely adding this param had no impact on Django’s behaviour.

After hours and hours of extensive googling and intensive playing with various combinations of settings I came up with the solution (or rather a workaround) that worked on any system. Add this to nginx config:

fastcgi_param SCRIPT_NAME "";
fastcgi_param PATH_INFO $fastcgi_script_name;

I.e. if you don’t reset SCRIPT_NAME, then PATH_INFO will not be set. I don’t know why.

One more quirk

Sometimes you can face another problem: nginx cannot serve static files (returns 403 Forbidden). The solution is to ensure that it can read all directories in the absolute path (i.e. you must set +x for each directory level).

A couple of hints

Sat, 13 Dec 2008 00:00:00 +0000