суббота, 7 сентября 2013 г.

Курсы во Львове

14-15 сентября буду читать немного ужатый вариант курсов по асинхронному сетевому программированию.
Подробности здесь.

суббота, 31 августа 2013 г.

Определение главного потока приложения

В многопоточной программе все потоки равны, но один всё же несколько выделяется. Это — главный поток.

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

Иногда нужно знать, код исполняется в главном потоке или нет. Например, работать с UNIX сигналами можно только из главного потока. Различные GUI библиотеки часто тоже хотят выполняться непременно в главном потоке и никаком другом.

Если мы пишем приложение, то всегда можно придумать тот или иной способ узнать главный поток. Например, при старте, когда других потоков ещё нет, узнать идентификатор потока через threading.get_ident() и запомнить его где-нибудь.

Когда создаём библиотеку такой способ не всегда подходит. А в самом питоне нет официального способа определить, главный поток это или нет.

Зато работают пара хаков.

Тест на главность потока:

isinstance(threading.current_thread(), threading._MainThread)

Идентификатор главного потока:

threading._shutdown.__self__.ident

Используются непубличные механизмы, но это всё же лучше чем ничего.

P.S. В Python 3.4 появится функция threading.main_thread(), которая возвращает объект главного потока. А до тех пор пользуемся хаками.

среда, 14 августа 2013 г.

Запуск процессов в tulip

В последнее время я работаю над запуском процессов в tulip: PEP 3156 и реализация на гуглокоде

Состояние дел на сегодня

Базовые конструкции выглядят так:

Транспорт:

class BaseTransport:
    """Base ABC for transports."""

    def get_extra_info(self, name, default=None):
        """Get optional transport information."""

    def close(self):
        """Closes the transport.

        Buffered data will be flushed asynchronously.  No more data
        will be received.  After all buffered data is flushed, the
        protocol's connection_lost() method will (eventually) called
        with None as its argument.
        """

class SubprocessTransport(BaseTransport):

    def get_pid(self):
        """Get subprocess id."""

    def get_returncode(self):
        """Get subprocess returncode.

        See also
        http://docs.python.org/3/library/subprocess#subprocess.Popen.returncode
        """

    def get_pipe_transport(self, fd):
        """Get transport for pipe with number fd."""

    def send_signal(self, signal):
        """Send signal to subprocess.

        See also:
        http://docs.python.org/3/library/subprocess#subprocess.Popen.send_signal
        """

    def terminate(self):
        """Stop the subprocess.

        Alias for close() method.

        On Posix OSs the method sends SIGTERM to the subprocess.
        On Windows the Win32 API function TerminateProcess()
         is called to stop the subprocess.

        See also:
        http://docs.python.org/3/library/subprocess#subprocess.Popen.terminate
        """

    def kill(self):
        """Kill the subprocess.

        On Posix OSs the function sends SIGKILL to the subprocess.
        On Windows kill() is an alias for terminate().

        See also:
        http://docs.python.org/3/library/subprocess#subprocess.Popen.kill
        """

Протокол:

class BaseProtocol:
    """ABC for base protocol class.

    Usually user implements protocols that derived from BaseProtocol
    like Protocol or ProcessProtocol.

    The only case when BaseProtocol should be implemented directly is
    write-only transport like write pipe
    """

    def connection_made(self, transport):
        """Called when a connection is made.

        The argument is the transport representing the pipe connection.
        To receive data, wait for data_received() calls.
        When the connection is closed, connection_lost() is called.
        """

    def connection_lost(self, exc):
        """Called when the connection is lost or closed.

        The argument is an exception object or None (the latter
        meaning a regular EOF is received or the connection was
        aborted or closed).
        """

class SubprocessProtocol(BaseProtocol):
    """ABC representing a protocol for subprocess calls."""

    def pipe_data_received(self, fd, data):
        """Called when subprocess write a data into stdout/stderr pipes.

        fd is int file dascriptor.
        data is bytes object.
        """

    def pipe_connection_lost(self, fd, exc):
        """Called when a file descriptor associated with the child process is
        closed.

        fd is the int file descriptor that was closed.
        """

    def process_exited(self):
        """Called when subprocess has exited.
        """

Нужные методы в event loop:

class AbstractEventLoop:
    """Abstract event loop."""

    def subprocess_shell(self, protocol_factory, cmd, *, stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                         **kwargs):
    """Run cmd in shell"""

    def subprocess_exec(self, protocol_factory, *args, stdin=subprocess.PIPE,
                        stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                        **kwargs):
    """Subprocess *args"""

Т.е. интерфейс запуска процесса почти повторяет subprocess.Popen за исключением того, что subprocess.PIPE теперь вариант по умолчaнию. Заодно еще избавляемся от кошмара с правильным использованием shell=True (см. пост на эту тему). Поддерживаются только байтовые потоки, как и везде в tulip.

Оно уже в целом работает на Unix, код для Windows тоже готовится.

Делает всё что можно и нужно за исключением TTY. C TTY ван Россум предложил пока не связываться, да и subprocess его не поддерживает.

Проблема

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

Но простому программисту хочется иметь что-то более удобное и привычное.

Для tulip это должен быть код на основе yield from.

Проблема в том, что для процессов мы имеем не один поток ввода-вывода, а три однонаправленных: stdin, stdout и stderr. А еще процесс может сам решить закрыться, и это тоже нужно удобно обрабатывать.

Просьба

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

Может, кто сумеет посоветовать дельную конструкцию? Или указать на готовую библиотеку, у которой можно поучиться?

среда, 26 июня 2013 г.

Начало курсов «Learn Python»

Занятия начинаются в эту субботу, 29 июня 2013.

Записавшимся должно прийти на почту письмо с местом, временем и прочими деталями.

пятница, 3 мая 2013 г.

Удаление объектов сборщиком мусора

На Хабре появилась толковая статья о неприятностях, которые может доставить Garbage Collector.

Отмечу актуальность описания проблемы и полную корректность решения для tornado.

Однако не могу не обратить внимание на слабое освещение того, как именно работает сборщик мусора в CPython.

Почему при работающем garbage collector появляется так много неудаляемых объектов?

Немного теории.

Сборщик мусора имеет три поколения (счёт начинается с нуля). При создании объекта он попадает в нулевое поколение.

У каждого поколения есть счётчик и порог. Работает эта пара так:

  • При добавлении объекта в поколение счётчик увеличивается.
  • При выбывании из поколения счётчик уменьшается.
  • Когда счётчик превысит пороговое значение — по всем объектам из поколения пройдётся сборщик мусора. Кого найдёт — удалит.
  • Все выжившие в поколении объекты перемещаются в следующее (из нулевого в первое, из первого во второе). Из второго поколения объекты никуда не попадают и остаются там навечно.
  • Перемещённые в следующее поколение объекты меняют соответствующий счетчик, и операция может повториться уже для следующего поколения.
  • Счётчик текущего поколения сбрасывается.

Объекты, подлежащие уничтожению но имеющие переопределённый метод __del__ не могут быть собраны. Причина проста: эти объекты могут ссылаться друг на друга.

Python не способен определить безопасный порядок вызова __del__. Если вызывать деструкторы в произвольном порядке, то можно получить ситуацию вида:

  • Деструктор объекта a для работы требует объект b.
  • Последний в своём деструкторе обращается к объекту a.
  • Если вызовем __del__ у a, то деструктор b не сможет отработать нормально. Ссылка на a будет иметь значение None.

Чтобы не заставлять программиста корректно разрешать такие ситуации было принято решение не уничтожать подобные объекты а просто перемещать их в gc.garbage — и дальше программист пусть сам разбирается что делать с этим мусором.

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

Перейдём к практической части.

Пример

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

Имеем классическую древовидную структуру:

class Node(object):
    parent = None

    def __init__(self, *children):
        self.children = list(children)
        for node in self.children:
            node.parent = self

    @classmethod
    def tree(cls, depth=1, numchildren=1):
        if depth == 0:
            return []
        return [cls(*cls.tree(depth-1, numchildren))
                for _ in range(numchildren)]

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

Добавляем garbage collection hook для того чтобы увидеть когда срабатывает сборщик мусора и сколько объектов он уничтожает:

import gc

def gc_cb(phase, info):
    if not info['collected'] and not info['uncollectable']:
        return
    print("{0}:\t{1[generation]}\t{1[collected]}\t{1[uncollectable]}".format(
        phase, info))

gc.callbacks.append(gc_cb)

Наконец, делаем много-много наших деревьев и смотрим как они разрушаются:

for n in range(20):
    for _ in range(n):
        Node.tree(depth=5, numchildren=6)

Пороги стоят стандартные:

>>> gc.get_threshold()
(700, 10, 10)

700 объектов в нулевом поколении и по 10 в первом и во втором.

Анализ

Теперь о том, почему образуется столько мусора.

Пример напечатает что-то вроде такого (вырезка из очень длинного результата):

...
stop:   1, 4665, 0
stop:   2, 79305, 0
stop:   1, 4665, 0
stop:   2, 79305, 0
stop:   1, 4665, 0
stop:   1, 4665, 0
stop:   1, 4665, 0
stop:   2, 97965, 0
stop:   1, 4665, 0
stop:   2, 79305, 0
stop:   1, 4665, 0
...

За один вызов Node.tree(depth=5, numchildren=6) создается 9330 тесно связанных объектов, которые нельзя разрушить в 0 поколении (помним, что порог 700). Значит они попадают в первое, а большая часть даже во второе поколение (9330>700*10). Наконец все 9330 объекта созданы, можно разрушать.

На уменьшении счётчиков ссылок на объекты ничего убрать не получится. Поэтому ждём, когда опять превысим порог в 700 (на следующем вызове Node.tree, конечно).

Собираем нулевое поколение (оно оказывается заполнено свежими данными и поживиться почти ничем не удаётся).

А сборщик мусора для поколения 1 вызовется только если туда попадут как минимум 10 объектов из поколения 0.

Хорошо, мы добрались до сбора в 1 поколении. Часть циклов можно уничтожить сразу (два поколения для анализа лучше одного), некоторые переправляются в поколение 2. В котором сборщик запускается тоже если в свою очередь превысили порог.

Что случается ещё реже и таким образом наши объекты накапливаются во втором поколении. Когда сборщик мусора доходит до него, то всё чистит.

Проблема в том, что до последнего поколения дело доходит относительно редко.

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

Чиним

Конечно, лучше всего не доводить дело до сборщика мусора вообще в случаях подобным нашему синтетическому примеру.

Разрушать ссылки вручную через вызов del или присваивания None очень неудобно, но есть и другой способ.

Воспользуемся слабыми ссылками на родителя:

import weakref

class Node(object):
    parent = None

    def __init__(self, *children):
        self.children = list(children)
        for node in self.children:
            node.parent = weakref.proxy(self)

Я предпочитаю weakref.ref как дающий больший контроль (всегда можно добавить свойство):

class Node(object):
    _parent = None

    def __init__(self, *children):
        self.children = list(children)
        for node in self.children:
            node._parent = weakref.ref(self)

    @property
    def parent(self):
        if self._parent is None:
            return None
        else:
            return self._parent()

В любом варианте дело до сборщика мусора не дойдёт и объекты будут уничтожены сразу как только перестанут быть нужны.

Если вариант со слабыми ссылками почему-то не проходит можно просто увеличить пороги. У нас создаётся за раз 9330 объектов? Поставим порог для первого поколения в 10000.

gc.set_threshold(10000, 100, 100)

Результат выглядит куда лучше:

...
stop:   0, 4665, 0
stop:   0, 4665, 0
stop:   0, 4665, 0
stop:   0, 4665, 0
stop:   0, 4665, 0
stop:   1, 919005, 0
stop:   0, 4665, 0
stop:   0, 4665, 0
stop:   0, 4665, 0
stop:   0, 4665, 0
...

Как видим сборщик мусора уничтожает почти всё на первом проходе, и лишь иногда требуется второй. Правда, смущает цифра 919005.

Именно потому что не всё прибивается на первом проходе, а второй наступает нескоро.

Уменьшаем второй порог:

gc.set_threshold(10000, 10, 10)

Ага, теперь всё красиво:

...
stop:   1, 83970, 0
stop:   0, 9330, 0
stop:   0, 4665, 0
stop:   0, 4665, 0
stop:   1, 74640, 0
stop:   0, 4665, 0
stop:   0, 4665, 0
stop:   1, 102630, 0
stop:   0, 4665, 0
stop:   0, 4665, 0
...

Выводы

В результате всё просто. Используем слабые ссылки. Если это по каким-то причинам невозможно — поднимаем пороги.

Но при этом нужно помнить, что сборщик мусора будет запускаться реже.

Установка порогов в слишком большое значение способно в нашем случае съесть память не менее успешно, чем если бы эти значения оставались установленными по умолчанию.

вторник, 23 апреля 2013 г.

Новый набор на курсы Learn Python

Объявляем набор участников на наши новые потоки курсов о Python: Aсинхронное программирование, Создание эффективных веб-приложений и Оптимизация Python кода. В этот раз потоки будут длиться по 6 занятий. Планируемая дата начала занятий: июнь 2013 года.


Асинхронное программирование


Сетевые библиотеки, например twisted, tornado, gevent, tulip — при кажущейся разнице в подходах имеют очень похожее ядро, называемое reactor, io loop, hub, event loop соответственно. Именно созданием этого ядра с нуля своими руками мы и займемся.

Цель курса: дать знания о том, как происходит работа с сетевыми подключениями (сокетами) на примере создания собственной библиотеки.

Требования к участникам: знание Python на достаточно приличном уровне. Введения в программирование не будет, с другой стороны создаваемый код не потребует чего-то сложного. Все сложности будут в работе с сетью а не в создании хитрых питоновских конструкций.

Потребуется Python 3.3. Хотя код мало зависит от версии языка, всё же в Python 3.3 появились некоторые удобные штуки которыми мы воспользуемся.

Операционная система: Linux, MacOS X или FreeBSD на выбор. Если есть сильное желание писать на Windows — тоже можно.

Коротко о чём будут занятия:


  • Написание примитивного клиент-серверного кода на потоках.
  • Объяснение почему производительные программы такой подход не используют. Нужно делать на epoll или kqueue, в крайнем случае select. Создание своего event loop. Сначала для обработки отложенных событий. Что это такое и какой должен быть интерфейс — расскажу по ходу дела.
  • Описание того, как работает select/epoll/kqueue. Добавляем к event loop работу с TCP сокетами, основанную на обратных вызовах. Правильная обработка ошибок.
  • Добавляем понятия транспорта-протокола.
  • Строим поверх этого удобный интерфейс для пользовательского кода. На yeild from или greenlets — по желанию.
  • Окончательный разбор результатов, ответы на возникшие вопросы.

Получившийся код в целом будет в основе следовать дизайну tulip в сильно упрощённом виде.

Курс состоит из шести занятий. Лектор: Андрей Светлов

Каждое занятие длится 2 часа.

Стоимость занятия: 300 грн.

Создание эффективных web-приложений


В 2013м году никого не удивишь веб-приложением, построенным при помощи Django, Pyramid или даже Flask. Однако куда сложнее удивить грамотным и эффективным web-приложением, способным одинаково успешно справлятся с нагрузкой реального мира и оставаться простым и легким для разработки.

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

На протяжении всего курса мы будем создавать веб-приложение, ориентированное на работу на ARM микро-компьютере Raspberry PI.

Требования к участникам: опыт в создании сайтов или проектов при помощи Python и популярных фреймворков. Учить создавать сайты с нуля не буду, буду помогать перейти на новый уровень и избегать довольно популярных и тем не менее назойливых ошибок.

Краткое содержания курса:


  • Архитектура высоконагруженного приложения, разделение проекта на бэкенд и фронтэнд, удаленное выполнение задач
  • Оптимизация архитектуры и оптимизация кода, что идет за чем
  • Тестирование как двигатель разработки, а не наоборот
  • Непрерывная интеграция и непрерывный деплоймент, сравнение мест для развертки проектов
  • Откуда берутся основные ошибки веб-приложений, зачем мы наступаем на одни и те же грабли

Курс состоит из шести занятий. Лектор: Игорь Давыденко

Каждое занятие длится 2 часа с перерывом в 15 минут.

Стоимость занятия: 200 грн, стоимость полного курса: 1000 грн.

Оптимизация Python кода


Чтобы делать высокоэффективный код нужно уметь пользоваться профайлером, читать байткод, выполнять алгоритмическую оптимизацию и писать Python C Extensions если алгоритмически выжать уже ничего не получается.

Всем этим мы и займемся.

Требования к участникам: уметь программировать на Python и C. Последнее очень желательно хотя бы на уровне остаточных знаний из институтского курса — половина рассматриваемого кода будет на С.

Python 3.3, операционная система любая.

Краткое содержание курса:


  • Профилирование через cProfile и timeit, анализ измеренных результатов. Рассматриваем из чего состоит функция с точки зрения Python и добираемся до байткода. Несколько простых вариантов оптимизации.
  • Создаём простейший модуль Python C Extension.
  • Учимся делать Python классы на C.
  • Теперь пишем на Cython и радуемся как легко всё получается. В нагрузку ctypes.
  • Показываю, как устроена виртуальная CPython машина изнутри. Интерпретаторы, потоки, стек. GIL. Как PyEval_EvalFrameEx исполняет байткод.

Курс состоит из пяти занятий. Лектор: Андрей Светлов.

Каждое занятие длится 2 часа.

Стоимость занятия: 300 грн.

UPD. Для тех кто ещё не понял: online версии не будет. Ни в каком виде.

среда, 17 апреля 2013 г.

Использование try-finally

Хочу обратить внимание на маленькую особенность написания конструкции try-finally.

Возьмём для примера многопоточность, а конкретно блокировки.

Где-то (наверное, в конструкторе класса) мы создали объект блокировки:

self.locker = threading.RLock()

Затем в каком-то методе мы пытаемся использовать эту блокировку в try-finally statement. Да, я знаю что RLock поддерживает context manager protocol и может использоваться в with statement. Так будет даже лучше, но мы сейчас говорим о другом варианте использования.

try:
    self.locker.acquire()
    do_some_work()
finally:
    self.locker.release()

В чём ошибка? .acquire() может выбросить исключение. Блокировка не будет захвачена и попытка её освободить в .release() выбросит новое (другое) исключение. Что крайне нежелательно. Особенно в python 2.x, где нет цепочек исключений. Т.е. ошибка в .acquire() будет просто скрыта, понять в чём было дело невозможно.

Правильно писать так:

self.locker.acquire()
try:
    do_some_work()
finally:
    self.locker.release()

Если было исключение в .acquire() — то блокировка не захвачена и освобождать её не нужно. Пусть обработка исключения разворачивается своим ходом, .release() в finally block совершенно не нужен.

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

Проблема усугубляется тем, что обычно .acquire() работает успешно, и лишь в редких случаях выбрасывает исключение. Которое мы видим в логах (все используют логи, верно?) и недоумеваем, что именно произошло.

Это замечание относится к любому коду, выполняемому в finally block.

Переменные, блокировки, захват ресурсов, открытие файлов и т.д. должны быть выполнены перед try.

P.S.

На открытие файлов хочу обратить особое внимание как на самый частый случай. Куда более частый чем работа с многопоточностью. Правильно писать:

f = open('filename')
try:
    f.read()
finally:
    f.close()

Надеюсь, последний пример запомнится хорошо и внесёт ясность в головы уважаемых молодых коллег.

вторник, 16 апреля 2013 г.

DevConf 2013 ищет докладчиков

Коллеги!

Московская конференция DevConf, которая состоится 14 июня, ищет докладчиков.

Сейчас в разделе Python всего две заявки: я и Lennart Regebro (классный дядька, с удовольствием его увижу снова и послушаю).

Неужели никто больше не желает ничего рассказать?
Темы исчерпались или порох отсырел?

P.S. Информация для иногородних: организаторы конференции берут на себя расходы по трасферу и проживанию. От вас же требуются хорошие интересные доклады.

четверг, 11 апреля 2013 г.

Pythons Innards

Перечитываю снова Pythons Innards (Yaniv Aknin).

Это — серия из нескольких статей о том, как устроен CPython изнутри.
  • Интерпретатор байткода
  • Что из себя представляет этот самый байткод
  • Что такое стек в понятии CPython, и как оно работает
  • Как устроены дескрипторы, слоты и классы на нижнем уровне
  • Пространства имен (namespaces)

Для «простых программистов, работающих работу» — наверное, ничего интересного.
Тем, кто желает разобраться в Питоне «до последнего байта» — очень рекомендую.

Вдобавок очень хочу посоветовать Ely Bendersky с его Python Internals. Эта серия статей тоже посвящена «внутреннему устройству» и прекрасно сочетается с тестами Yaniv Aknin.

  • Как создаётся объект (в деталях)
  • Что такое class и чем отличается от type
  • Как именно происходит вызов callable
  • И т.д. (symbol tables, например)

На самом деле подобного рода информации очень немного. Документация хорошо описывает CPython C API но не рассказывает о деталях, о том как это всё работает.

У меня до C кода дело доходило разве до обсуждения реализации GIL насколько я помню.

Если есть еще интересные статьи по внутреннему устройству — пишите в комментариях, я добавлю сюда. Наверняка что-то запамятовал, но в целом тема раскрыта очень скудно.

Так что если хотите узнать «как оно работает на самом деле» — читайте  статьи по ссылкам.

UPD.
По устройству типов данных:
Строки
Целые числа
Списки
Словари (для версий Python <3.3)

Лекция Larry Hastings (release manager для Python 3.4, между прочим) с US PyCon 2012 на рассматриваемую тему.


понедельник, 4 марта 2013 г.

Python Sprint во Львове


Как я уже писал, 6 апреля будет Kyiv.py #10, на который уже зарегистрировались два докладчика: Ростислав Дзинько (Sockets from the ground up) и Тарас Ляпун (Cython - close to the metal python). Приходите, будет интересно.

А 7 апреля (да-да, на следующий день) во Львове пройдёт спринт по Питону, который организовывает Юля Савьюк @juljetta. Моя роль в этом мероприятии — sprint leader.

Регистрация, место и время

UPD:
Форма регистрации: здесь.
Место проведения: офис Lohika, Лемківська 15, 3 этаж.
Начало в 11.00. Заканчиваем когда устанет последний боец. Реально, думаю, часов через шесть.

Что такое sprint?

Это практически субботник — сознательный организованный бесплатный труд на благо общества в свободное от работы время. Работать предлагается над CPython. Берем готовую issue в багтрекере или создаём свою новую. Если есть трудности с выбором — я помогу и поскажу. Когда вся работа будет сделана — я просматриваю код и, если всё хорошо, тут же делаю push в hg.python.org.

Зачем это делается? Не для того, чтобы решить большую серьёзную проблему. Главное — показать процесс работы над Питоном, объяснить и рассказать. Спринт — отличная возможность для новичка стать python contributor. 

Обычная проблема Open Source: нужно довольно долго переписываться, при этом работа может затухнуть сама собой просто потому что вам никто не отвечает.

Наличие sprint leader (т.е. меня в данном случае) позволяет максимально всё ускорить. 

В результате — приятное чувство: решил проблему (пусть и небольшую)  и принёс пользу Python Community. Хочется продолжать работать дальше в том же духе.

Инструкция

Чтобы спринт был удачным, к нему нужно подготовиться.
Приходим со своими ноутбуками (думаю, это не проблема).

На ноуте может быть любая система: Linux, Windows, Mac OS X.

Нужно установить компилятор С
- gcc на Линуксе идет в комплекте
- на Маке не знаю (там вроде бы можно еще и clang использовать, Питон должен его понимать)
- для Windows нужно установить Visual Studio, Visual Studio Express доступна для бесплатного скачивания и использования. Для работы нужны обе версии 2008 и 2010.

Также требуется Mercurial HG: http://mercurial.selenic.com/

Работа ведется над CPython repo, установленный из коробки Питон не подходит.

Подробные инструкции на английском языке здесь: http://docs.python.org/devguide/

Делаем:

$ hg clone http://hg.python.org/cpython
$ cd cpython
$ ./configure --with-pydebug
$ make -j4
make install делать не нужно

Далее. Чтобы не тратить время зря советую зарегистрироваться на bugs.python.org и просмотреть заранее список issues.
Выбирайте помеченные как easy — они как правило действительно простые.

Если у вас уже есть темы, над которыми хотите поработать — добро пожаловать.
Если не сможете определиться — тоже не беда, я подскажу.

Работа выглядит так:
- создается issue или берется готовая
- готовятся исправления
- делается патч: $ hg diff > issueXXX.diff
- он заливается через форму на bugs.python.org Там же добавляете меня (asvetlov) в nosy list
- я закачиваю патч и применяю его: $ curl http://path-to-patch|patch -p1
- если всё нормально — делаю push в repo

У Питона сейчас открыты для патчей четыре ветки: 2.7, 3.2, 3.3, default (3.4).
Новые фичи принимаются в default, баги и правки по документации могут попасть и в остальные три.
Если кто не знает как работать с ветками — я покажу на месте.

Юниттесты запускаются так:
$ make test
или
$ ./python Lib/test/regrtest.py

Отдельный тест можно запустить
$ ./python Lib/test/test_xxx.py

Перед отсылкой патча настоятельно рекомендую запускать чекер
$ make patchcheck
Эта процедура как минимум убирает лишние пробелы — постоянная головная боль при приеме патчей.

Заключение

Я буду на месте всё время, помогу вам советом, правкой кода и т.д. Все затруднения быстро порешаем.





вторник, 26 февраля 2013 г.

RU PyCon 2013

Закончился первый русский PyCon.

Было очень здорово!

Организация мероприятия выше всех похвал!

Залы просторные, еда вкусная, Wi-Fi работал.

Место проведения — за городом в сосновом лесу.

Антон Патрушев, девчонки из ITPeople и волонтёры поработали очень хорошо, большое спасибо.

Перейду с содержательной части.

Armin Ronacher говорил о Flask . Рассказчик он хороший, всё было очень доходчиво.

К сожалению меня Flask мало интересует, я его нигде не применяю. На вопрос: «Когда Flask заработает на Python 3?» получил не очень обнадеживающий ответ: когда-нибудь. Армин недолюбливает тройку, тратить время прямо сейчас на добавление поддержки Python 3 в Werkzeug не намерен. Ему это не нужно.

Куда интересней было обсуждение достоинств и недостатков Python 3. Как по мне Python 3 — замечательная штука, её стоит пытаться использовать повсеместно. Есть определенные сложности с поддержкой HTTP и WSGI, но webob успешно работает и не жужжит.

Армин же считает что юникод в Python 3 «сломан» (дословно — the unicode support is broken), что мне кажется экспрессивным преувеличением. Чтобы починить Werzeug нужно немного поменять public interface, разрушив таким образом обратную совместимость. Ничего страшного, как по мне. Весь мир успешно решает такие задачи через deprecation process в новых версиях продукта.

Некоторые участники конференции считают, что Ронахеру просто лень. Назову это по другому: он недостаточно замотивирован. Если ему самому изменения не нужны, то их и не будет. Тем более что Flask и Werkzeug — продукты одного человека с относительно небольшим количеством контрибуторов.

Возвращаясь к Питону, Армин считает что:

  1. Python 3 ломает обратную совместимость и при этом его отличия недостаточно радикальны чтобы замотивировать разработчиков переходить на тройку. Утверждение спорное: пытаясь реализовать слишком радикальные изменения мы бы на данный момент имели Python 3.0 alpha вместо Python 3.3.1 и Python 3.4 alpha. А переход библиотек был бы куда более мучительным процессом.

  2. Нужно выпустить Python 2.8 и Python 3.4, облегчающие миграцию библиотек. Я очень скептически отношусь к идее активной разработки 2.8. И, главное, без списка конкретных предложений идея ничего не стоит и скорее напоминает недовольное ворчание (даже если недовольство имеет объективые корни).

Хватит о Ронахере.

Было два отличных доклада о Redis от David Cramer и Amir Salihefendic. Особенно полезны для тех неторопливых разработчиков, кто еще не оценил Redis по достоинству. В двух словах: Redis это больше чем просто кэш. Правильное использование редисовских структур позволяет решать сложные задачи, связанные с быстрой обработкой больших объемов данных. При этом тратить минимальное количество памяти и CPU.

Russell Keith-Magee рассказал (в два приёма) об истории Django, Django community и о том куда всё идет, что нам ждать от следующий версий этого очень популярного инструмента. Любопытная информация и Рассел отличный рассказчик.

Саня Кошелев показал свои эксперименты с асинхронным сетевым кодом и замеры скорости работы при разных схемах использования. Результаты вполне ожидаемые, но подача очень хорошая.

Костя Лопухин подал стандартную задачу версионирования данных в БД с несколько неожиданной для меня стороны. Насколько я видел версионирование обычно делается на уровне кода в бизнес-логике. Косте с коллегами удалось написать вполне на первый взгляд удачную библиотеку для Django, которая экономит много кода и времени. Может, кому-то эта штука придётся очень кстати.

И, наконец, Holger Krekel. Очень мощный доклад о разрабатываемом им инструменте под названием devpi. Это реализация pypi сервера, которая может работать с upstream, выступать в роли proxy, кешировать локально устанавливаемые через нее пакеты, запускать тесты и т.д.

Масштаб задачи и элегантная простота решения меня сразила наповал. Смотрите видео (скоро обещали выложить).

Первый релиз devpi планируется на средину 2013 года, планов громадьё. Уже сейчас то что работает выглядит крайне интересно.

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

На Lighting Talks набралось пару дюжин желающих. Слушать было в целом интересно, но ничего поражающего воображение (типа презентации argparse на лайтинге в Чикаго 2009) не нашел.

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

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

Всем рекомендую не пропустить русский PyCon в следующем году.

И, пользуясь случаем, приглашаю в Киев на наш украинский PyCon в конце октября. Уверяю, у нас тоже очень здорово и интересно!

четверг, 21 февраля 2013 г.

Kyiv.py #10

В субботу 6 апреля состоится Kyiv.py #10. Начало в 11.00.

Как обычно, Циклум любезно предоставил нам своё замечательное помещение на Амосова 12.

А теперь самое главное: доклады.

Пока список пуст, так что предлагайте свои темы.

Желающих выступить прошу слать заявку на <andrew.svetlov@gmail.com>.

вторник, 12 февраля 2013 г.

RU PyCon

24-25 февраля состоится Русский PyCon — первая в России конференция по Питону с таким статусом.

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

Сам буду рассказывать о сетевом программировании и грядущем PEP 3156 — общем стандарте на асинхронное программирование для Python 3.

Уже предвкушаю встречу с коллегами, которых вижу максимум пару раз в году если не учитывать переписку по интернету.

Ребята и девчонки, приезжайте! Будет очень интересно и полезно, обещаю.

Первая польза просто от докладов — они расширяют поле внимания, позволяют отвлечься на время от ваших рабочих задач и, возможно, увидеть решение в новом: библиотеке, подходе и т.д. Поток информации большой, много можно почерпнуть.

Вторая польза — собирается несколько сотен программистов. Мы все открыты к общению. Разговоры в кулуарах-корридорах-холлах часто не менее интересны чем лекции. Тут уж приходится выбирать: остаться поговорить здесь или пойти на доклад там.

Третье: нас ищут. Хорошие специалисты нужны всем. У вас есть еще одна возможность найти интересную работу по душе.

P.S.
Да и вообще это очень классная штука — конференции.
После неё хочу работать больше, быстрее, выше — хочу писать код, хороший и красивый. 

Если кто еще не купил билет — у вас есть время это сделать .