python
Уходим с телефоном, «МакБук» выключается
Причина, по которой я засел за Пайтон и стал изучать как из него работать с Bluetooth в том, что мне очень хотелось сделать следующую вещь: как только я покидаю рабочее место, мой ноутбук блокируется.
Идея выглядела просто: надо посмотреть присутствует ли в эфире мой смартфон, если нету, значит я
В общем, всё получилось у меня. Если хотите, чтобы у вас работало так же, то двигайтесь по шагам.
Шаг №1.
Нужно узнать так называемый «адрес» вашего устройства и привязать его к компьютеру. Тут ничего сложного нет, заходим в настройки «Блютуз» на «Маке» (они находятся в «Системных настройках»), привязываем его как обычно и переписываем себе 12 букв, разделённых минусами, это и есть адрес:

Шаг №2.
С этого шага потребуется уметь пользоваться терминалом. Создаём запускаемый файл
#!/usr/bin/python
import objc
import sys
from subprocess import call
objc.loadBundle('IOBluetooth', globals(), bundle_path=u'/System/Library/Frameworks/IOBluetooth.framework')
def CheckDevice(address):
dev = IOBluetoothDevice.withAddressString_(address)
if dev.isConnected():
return True
conn = dev.openConnection()
if conn == -536870185: # Bluetooth is off
return True
if conn == 0:
dev.closeConnection()
return True
return False
cmdtorun=(r'/System/Library/CoreServices/Menu Extras/User.menu/Contents/Resources/CGSession', r'-suspend')
try:
if not CheckDevice(sys.argv[1]):
call(cmdtorun)
except IndexError:
print("Usage: bt-lock <device address>")В скобках замечу, чтобы сделать файл запускаемым нужно в терминале выполнить следующую команду: chmod a+x
Шаг 3.
Создаём файл ~/Library/LaunchAgents/ru.bolknote.Bluetooth-lock.crontab.plist с таким вот содержимым:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>ru.bolknote.Bluetooth-lock.crontab</string>
<key>Program</key>
<string>/usr/local/bin/bt-lock</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/bt-lock</string>
<string>а̲д̲р̲е̲с̲ ̲в̲а̲ш̲е̲г̲о̲ ̲у̲с̲т̲р̲о̲й̲с̲т̲в̲а̲</string>
</array>
<key>Nice</key>
<integer>20</integer>
<key>StartInterval</key>
<integer>30</integer>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>И выполняем в терминале команду «launchctl load ru.bolknote.Bluetooth-lock.crontab.plist». Это всё.
Чтобы отключить всю эту марахайку, достаточно выполнить в терминале команду «launchctl unload ru.bolknote.Bluetooth-lock.crontab.plist» или выключить Bluetooth на ноуте.
Решение только для «Мака», как работать из Пайтона с Блютузом под другие операционные системы, я не знаю.
Bluetooth в Mac OS из Python
Я тут учусь работать с Блютузом из Пайтона на «Маке», пока сделал сканирование всех видимых в эфире устройств:
import objc
import time
from Foundation import NSDate, NSDefaultRunLoopMode
from AppKit import NSApplication, NSAnyEventMask
objc.loadBundle('IOBluetooth', globals(), bundle_path=u'/System/Library/Frameworks/IOBluetooth.framework')
class DeviceInquiry(NSObject):
def init(self):
self = super(DeviceInquiry, self).init()
self._inquiry = IOBluetoothDeviceInquiry.inquiryWithDelegate_(self)
self._stop = False
return self
def getfounddevices(self):
self._inquiry.start()
app = NSApplication.sharedApplication()
app.setActivationPolicy_(2)
while not self._stop:
time.sleep(.01)
app.nextEventMatchingMask_untilDate_inMode_dequeue_(NSAnyEventMask,\
NSDate.dateWithTimeIntervalSinceNow_(1), NSDefaultRunLoopMode, True)
return tuple((dev.getName(), dev.getAddressString()) for dev in self._inquiry.foundDevices())
@objc.typedSelector("v@:@@")
def deviceInquiryDeviceFound_device_(self, inquiry, device):
self._stop = True
@objc.typedSelector("v@:@iB")
def deviceInquiryComplete_error_aborted_(self, inquiry, err, aborted):
self._stop = True
print DeviceInquiry.new().getfounddevices()Модуль pyobjc (в маковском Пайтоне он уже есть) — это мост между Пайтоном
Последняя строчка — пример использования, выдаётся список списков, состоящих из двух элементов — имени устройства и его «адреса» (это шесть шестнадцатеричных чисел, разделённые минусом).
Магические методы
Что мне никогда не нравилось в Пайтоне, так это «магические» методы и свойства. Сейчас их существует за сотню:
bolk@Bolk ~ $ wget -O- http://docs.python.org/reference/datamodel.html 2>&- | egrep -o '__(\w+)__' | sort -u | wc -l
108Я, даже если очень постараюсь, вряд ли вспомню хотя бы половину. Всё «магическое» в Пайтоне начинается и заканчивается двумя подчёркиваниями, например, если сменить знак у объекта (сделать
Запомнить все эти методы, наверное, реально при помощи тщательной зубрёжки, но сделать это естетственно, во время изучения языка, нереально, по моему мнению. Причина — неинтуитивность. Я давно высказывался на тему, почему хотя бы не расширить синтаксис и некоторые методы не разрешить называть как операции, то есть «/», «+», «[]» и так далее, смутно вспоминая, что в Си++, кажется, так и сделано.
Оказывается, так в точности сделано в языке «Скала»:
trait Ord{
def < (that:Any):Boolean
def<=(that:Any):Boolean = (this < that) || (this == that)
def> (that:Any):Boolean = !(this <= that)
def>=(that:Any):Boolean = !(this < that)
}Это гораздо проще выучить, изучая язык, чем «__lt__», «__le__», «__gt__», «__ge__» (впрочем, когда перечисляешь в ряд несколько конструкций, кажется что ничего страшного в этом нет, но надо держать в голове, что их больше сотни).
У некоторых методов название упрощать не нужно, например «__unicode__» (преобразование к юникодной строке) всё равно дёргается стоит вызвать unicode(something) или «__del__» (деструктор) вызывается, в частности, если сделать «del something» (если ссылок больше нет). Они уже содержат название операции, просто оно буквенное. Есть методы, которые вряд ли вообще можно
Наверняка есть часть, которую понятнее не назовёшь. На ум сразу приходит метод «__hash__», думаю есть и ещё.
Но, бо́льшую часть, мне бы хотелось именовать
Банкоматы «Ак Барс Банка»
У меня зарплатная карточка «Ак Барс Банка», он вряд ли известен за пределами нашей республики, но в Татарстане широко распространён. Этот банк входит в организацию «Объединённая расчётная система», в которую входят ещё несколько банков, в банкоматах которых карты «Ак Барса» обслуживаются на льготных условиях.
Список
# coding: utf-8
import urllib
import re
import sys
import codecs
from itertools import ifilter
# Чтобы при перенаправлении в файл была кодировка UTF-8
sys.stdin = codecs.getreader('utf-8')(sys.stdin)
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
# Конфигурация
ORS_URL = 'http://ors.ru/cashpoints/print.asp'
ORS_CITY = u'Казань'
ORS_REGION = u'Республика Татарстан'
# Данные для оправления через POST
postdata = urllib.urlencode({
'CITY': ORS_CITY.encode('cp1251'),
'REGION': ORS_REGION.encode('cp1251'),
'CURRENCY': 'RUR',
'OPERATION': 'cash-out',
})
content = urllib.urlopen(ORS_URL, postdata).read().decode('cp1251')
# Ищем все ячейки таблицы и выбираем каждую вторую из шести
tds = re.finditer('<td[^>]*>(.+?)</td>', content, re.S | re.I)
tds = ifilter(lambda x: x[0] % 6 == 1, enumerate(tds))
# Берём только уникальные значения и рубим лишние символы
for x in set(x[1].group(1) for x in tds):
print(x.replace(' ', ' '))Выводится список банков (регион и город задаётся в коде в очевидном месте), например, на настоящий момент список выглядит вот так:
ОАО Банк ЗЕНИТ
ОАО "РГС Банк"
АКБ "Абсолют Банк" (ЗАО)
Быстробанк ОАО
ОАО "АК БАРС" БАНК
АКБ "РОСБАНК" (ОАО)
НОМОС-БАНК (ОАО)
АКБ МБРР (ОАО)
ЗАО АИБ "Ипотека-Инвест"
ОАО "АИКБ "Татфондбанк"
АКБ "БТА-Казань" (ОАО)
КБ "Юниаструм Банк" (ООО)
ОАО АКБ «Авангард»
ОАО КБ "Восточный"ChinesePython
А вы знали, что существует ChinesePython? Выглядит как настоящий, но не радует.
Язык полностью переведён на китайский, включая ключевые слова, встроенные типы и так далее, код основан на Пайтоне 2.1.3. Вот пример того как смотрится программа на этом языке:
載入 系統
文件名 = 系統.參數[1:]
定義 修正行尾(文件):
內文 = 打開(文件名).讀入()
內文 = 內文.替換('\n\r','\n')
傳回 內文
取 文件 自 文件名:
寫 修正行尾(文件)«載入 系統» — это «import sys». Эта же программа на традиционном Пайтоне выглядит вот так:
import sys
filenames = sys.argv[1:]
def fixline(filename):
text = open(filename).read()
text = text.replace('\n\r','\n')
return text
for file in filenames:
print fixline(file)Основная цель создания интерпретатора на китайском, по словам автора — популяризация программирования. Начинающий китайский программист, вместо того, чтобы учить недоанглийский, который всё равно не позволит ему говорить на этом языке, но позволит понимать слова Пайтона и называть переменные на корявеньком английском, может сосредоточиться на концепциях, алгоритмах и тому подобном.
Ерунда на itertools и генераторах
Я люблю itertools и генераторы в Пайтоне,
Прочитал тут на «Хабре», что дробь 1/998001 даёт последовательность из чисел от нуля до 997. Вот я и написал код с использованием генераторов и itertools, который берёт эту дробь и выводит из неё все числа последовательно, пока не попадутся числа с разницей не равной единице.
from decimal import Decimal, getcontext
from itertools import groupby, islice, izip, takewhile, chain, imap
getcontext().prec = 3000
n = (
groupby(
enumerate(
islice(str(1 / Decimal(998001)), 2, None)
),
lambda n: n[0] // 3)
)
n = (int(''.join(n[1] for n in n[1])) for n in n)
n = chain(*takewhile(lambda n: n[1] - n[0] == 1, izip(n, n)))
print ', '.join(imap(str, n))Кстати, для вычисления дроби с точностью до трёхтысячного знака, используется модуль decimal.
Подумалось, что многим, наверное, было интересно сравнить как выглядит эквивалентный код на Пайтоне без всех этих страшных (на взгляд большинства) ленивых выражений. А то некоторые ребята по моей вине уже думают, что Пайтон
from decimal import Decimal, getcontext
getcontext().prec = 3000
number, prev, out = str(1 / Decimal(998001)), -1, []
for i in xrange(2, len(number), 3):
curr = int(number[i:i+3])
if curr - prev != 1: break
prev = curr
out.append(str(curr))
print ', '.join(out)Стеганография и пробел нулевой длины
Болею, не спится мне. Вспомнил старую свою идею.
В Юникоде есть такой символ замечательный — пробел нулевой длины (код 0x200B), на печать не выводится, понимается всеми современными браузерами и большинством редакторов. Интервала между буквами, как следует из названия, не даёт.
Идея простая, позволяет прятать в текст другой текст, так, чтобы первый не менялся, а второй всегда копировался вместе с первым. Основная мысль — пользуясь буквами исходного текста, как разделителем, ставим между ними столько пробелов нулевой длины, чтобы их число равнялось коду скрываемого символа.
Например. Дан текст: «Болк», в нём надо скрыть короткий текст: «yes». Я взял английские символы, чтобы не заморачиватсья с кодировкой.
Коды символов «yes» — 121, 101, 115. Значит текст приобретает следующий вид:
[121 символ пробела нулевой длины]Б[101 символ пробела нулевой длины]о[115 символов пробела нулевой длины]лк
Можно, кстати, вычитать из кода символа 31, если мы не планируем использовать символы перевода строки и табуляции в скрываемом тексте. Небольшой код на Пайтоне, приведённый ниже, иллюстрирует идею.
# Example by Evgeny Stepanischev
from itertools import groupby, izip_longest
import sys
import codecs
sys.stdin = codecs.getreader('utf-8')(sys.stdin)
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
toenc = 'Evgeny Stepanischev'
input = sys.stdin.read()
def decode(input):
return ''.join(chr(31+len(list(x[1])))
for x in groupby(input, lambda x: x == u"\u200b") if x[0])
def encode(input):
if len(input) < len(toenc):
raise ValueError()
return ''.join(x[0] + x[1]
for x in izip_longest((u"\u200b" * (ord(x)-31)
for x in toenc), input, fillvalue=''))
print(encode(input) if input.find(u"\u200b") == -1 else decode(input))Если на вход ему подать текст без пробелов нулевой длины, он добавит в него скрытый текст, иначе попытается его оттуда извлечь.
В принципе, этот подход можно применять в вебе для маркировки своих текстов — браузеры, кроме вымирающих, нормально относятся к этому символу и отображают его адекватно.
Конечно, важна длина текста — таким способом не скрыть текст, длина которого много больше исходной, но способ можно и улучшить в этом смысле. Например, в качестве прерывающего символа выбрать
Обработка данных интернет-клиента «Альфа-банка»
Накидал небольшую программу для обработки данных
Программа на Пайтоне:
# coding: utf-8
import sys
import re
from datetime import date
from itertools import islice
output = []
with open(sys.argv[1], 'r') as f:
for line in islice(f, 1, None):
n, detail, arr, flow = line.decode('cp1251').split(';')[4:8]
if n[:4] == 'BERR' or n[:6] == 'CASHIN': continue
flow = float(flow.replace(',', '.'))
if flow > 0:
dates = re.findall(r'\d{2}\.\d{2}\.\d{2}', detail, re.UNICODE)
if dates:
d = min(date(*(int(x) for x in d.split('.')[::-1])) for d in dates)
output.append({
'detail': detail,
'flow': flow,
'date': d,
})
for k in sorted(output, lambda x, y: cmp(x['date'], y['date'])):
data = zip(('y', 'm', 'd',), k['date'].timetuple()[:3]) + k.items()
print "%(d)02d.%(m)02d.%(y)02d %(flow)09s %(detail)s" % dict(data)Кодировка rot13 в Пайтоне
В стандартном интерпретаторе Пайтона есть много такого, что иначе как «пасхальным яйцом» не назовёшь. Например, можно попробовать импортировать модули «__hello__», «this» или сделать «from __future__ import braces» (попробуйте), но следующее просто гениально, хотя, видимо, получилось случайно.
В файле программы на Пайтоне в специальном коментарии принято указывать кодировку файла. В случае с латиницей работает и без этого, если применяется
Вот вполне валидная программа, которая выполняется и делает нечто осмысленное:
# coding: rot13
vzcbeg __uryyb__
cevag "Zl anzr vf Ritral Fgrcnavfpuri nxn Obyx!".rapbqr("rot13")Кодируется только текст программы,
Сравнение объектов встроенных типов в Пайтоне
Некоторым ребятам показалось, что в заметке про «goatse operator» в Перле я поругал этот язык. Это не так, можно прочитать заметку от и до, чтобы в этом убедиться. Мне очень нравится Перл, но это язык не для современного продакшна. Давайте я
В Пайтоне всё что только можно — объект и нет примитивных типов. С объектами можно делать всё что хочется — сравнивать, умножать, производить битовые операции. Чтобы программист мог указать как объекту следует себя вести рядом
In [26]: "Это строка".__eq__
Out[26]: <method-wrapper '__eq__' of str object at 0x10136f770>
In [27]: "Это строка".__ne__
Out[27]: <method-wrapper '__ne__' of str object at 0x10139cf70>Сравнивать между собой можно большинство встроенных типов — список с со словарём, строку с кортежем и так далее. Есть исключения (например, set нельзя сравнить ни с чем, кроме set и frozenset), но их мало. Какой же будет результат сравнения? Давайте попробуем:
In [44]: "">()
Out[44]: False
In [45]: ""<()
Out[45]: True
In [46]: []>()
Out[46]: False
In [47]: []<()
Out[47]: True
In [48]: []<{}
Out[48]: False
In [49]: []>{}
Out[49]: TrueДаже пустые объекты разных типов не равны между собой,
In [52]: [1,2,3,4,5,6]<(0,)>[100000]
Out[52]: TrueНе знаю где это написано в документации, не искал, но я совершенно случайно,
True < {} < [] < object() < "" < () < u""
# b < d < l < o < s < t < uРешение мне кажется, мягко говоря, неудачным, но уж какое выбрали. Я не вижу ничего страшного в том, чтобы сравнение встроенных типов всегда выдавало False (попробуйте сравнить между собой два None) или выдавать исключение при попытке их сравнения (кажется
Одно из различий Python и JavaScript
Чем дальше, тем между большим количеством языков программирования мне приходится переключаться. Одно из различий объектной модели Пайтона и ДжаваСкрипта мне портит кровь (у них парадигмы ООП вообще сильно различаются), если я вовремя не соображу, что надо переключиться с одного языка на другой.
Суть в том, что в Пайтоне метод ходит в гости со своим контекстом:
class A:
test = 'A'
def show(self): print self.test
class B: test = 'B'
a, b = A(), B()
show = a.show
b.show = a.show
show() # A
b.show() # AТогда как в JavaScript такой код будет работать совершенно иначе, там методы в чужой монастырь со своим уставом не ходят (если их не попросить):
var test = 'global';
A = function () {
this.test = 'A',
this.show = function () { alert(this.test) }
};
B = function () { this.test = 'B'; }
a = new A(); b = new B();
b.show = a.show
show = a.show
show() // global
b.show() // B
b.show.apply(a) // AПоявление «global» наверное надо разъяснить тем, кто JS знает плохо. На самом деле первая строчка (в данном случае) может читаться как «window.test = ’global’», а «show = a.show» как «window.show = a.show», тогда, должно быть, всё
Пайтон: замкнувшее замыкание
Есть немало вещей, которые мне не нравятся в Пайтоне. Не так давно мы на работе наткнулись ещё на одну.
У нас есть код, который выглядит примерно так (можно написать и одну функцию, но так нагляднее):
def outer(useless = None):
def inner():
if useless is None:
print "Pichal'ka"
return inner
outer()()Ничего необычного, одна функция определяется внутри другой, использует переменную используя переменную из внешней функции. Всё логично, всё работает.
Теперь меняем код:
def outer(useless = None):
def inner():
if useless is None:
print "Pichal'ka"
# тут много кода, начало мы уже потеряли
if False: useless = None
return inner
outer()()Запускаем код и видим (Пайтон 2.6.5):
Traceback (most recent call last):
File "sample.py", line 10, in <module>
outer()()
File "sample.py", line 3, in inner
if useless is None:
UnboundLocalError: local variable 'useless' referenced before assignmentКакими бы благородными мотивами не руководствовались создатели Пайтона, мне такое поведение не нравится. Вдруг я забыл как переменная попадает в функцию, присвоил ей
Избавиться от эффекта можно, изменив прототип внутренней функции на «inner(useless=useless)».
То же, кстати, происходит при импорте модуля:
import random
def outer():
print random.choice
#import random
outer()Раскомментируйте строчку со вторым импортом и получите ошибку.
Все эти ошибки возникают
Я не придумал хороших причин так делать с точки зрения языка (может их
Небольшая задача на Пайтоне
Вот вам небольшая задача на Пайтоне, для того, чтобы понять как у вас с функциональным программированием. Выполнить надо в уме (я смог, значит это возможно). Что вернёт следующее выражение:
(lambda x:x(x))(lambda z: lambda y:z)(1)(2)(3)Добавлено позднее: если
(function (x) x(x))(function (z) function (y) z)(1)(2)(3)Epic War 4

Подсел
Но медленно наращивать мощность очень уж скучно, сделал патч, который увеличивает количество денег до двух миллионов, применив его
Для того, чтобы применить патч, найдите
Программа написана сразу на трёх языках — PowerShell (для Windows) и PHP с Python (для всех), запускайте любым из этих трёх интерпретаторов:
#!/usr/bin/env python
########################################################
# Written by Evgeny Stepanischev (//bolknote.ru) #
# Epic War 4 money patch (for PowerShell, Python, PHP) #
#<?/*
"""*/
echo str_repeat('#', 55), chr(10);
if ($_SERVER['argc'] > 1) {
$fp = @fopen($_SERVER['argv'][1], 'r+b');
if ($fp) {
$content = fread($fp, 655350);
$content = preg_replace('/(?<=stat_money).{5}/s', pack('H*', '0480C584B4'), $content);
rewind($fp);
fwrite($fp, $content);
echo 'Done.';
} else {
echo 'Invalid file.';
}
fclose($fp);
} else {
echo 'Usage: ', $_SERVER['argv'][0], '<filename>';
}
__halt_compiler();
""" + """ " | out-null
If ($args) {
[char[]] $binary = Get-Content -encoding byte $args[0]
$binary = [string]::join('', $binary) -replace`
'stat_money.{5}', `
"stat_money$([char]0x4)$([char]0x80)$([char]0xC5)$([char]0x84)$([char]0xB4)"
Set-Content $args[0] ([byte[]][char[]] $binary) -encoding byte
"Done."
} Else {
"Usage: " + $MyInvocation.MyCommand.Name +" <filename>"
}
"""
from sys import argv
from os.path import basename
if len(argv) > 1:
name = 'stat_money'
f = open(argv[1], 'r+b')
binary = bytearray(f.read())
try:
index = binary.index(name) + 1 + len(name)
binary[index:index+4] = '\x80\xc5\x84\xb4'
f.seek(0)
f.write(binary)
f.close()
print('Done.')
except:
print('Invalid file.')
else:
print('Usage: %s <filename>' % basename(argv[0]))
# " | out-nullpython patch.ps1 DEF4_SAVE.sol или powershell -Command .\patch.ps1 DEF4_SAVE.sol или php patch.ps1 DEF4_SAVE.sol
Жаль расцветить три языка в одном файле можно только вручную.
Собеседование
У нас с Сергеем Чистовичем сейчас проходит примерно по 1—2 собеседования в день. Для оптимизации (чтобы быстрее понять что знает кандидат, а что нет), приходится придумывать вопросы с подвохом.
Например (это Python), что будет тут — True или False и почему:
u'ВАС' == 'ВАС'
str('') == str('')
object() == object()Добавлено через несколько часов: ребята из комментариев, вы что правда считаете этот элементарнейший тест «тонкостями» и «хитростями» языка? То есть вы в коде никогда не сравниваете два объекта? Два числа, например, да что числа, просто любые два объекта?
А такие вещи как разное поведение наследования у «классических» и «новых» классов, наверное, вообще у вас считается заумью?
Никто ещё не выпустил пиво Python?
Сейчас сижу на кухне, а перед глазами стоит соседская литровая банка пива, подумалось, что если бы
Не все знают Пайтон, поэтому придётся разъяснить шутку. «1L» — так в Пайтоне записывается число «1» типа «long» (антизанудская мантра: знаю, long — это
Невнятный exception у xml.sax
import xml.sax as sax
sax.parseString(u'<r/>', sax.ContentHandler())Вот этот код выдаёт совершенно невразумительный exception: «xml.sax._exceptions.SAXParseException:
Зависание _mysql (mysqldb)
Судя по strace, модуль
Добавлено чуть позже: да что ж такое! Опять висит. И с указанием кодировки — тоже. В интернете ничего нет, что же я не так делаю?
Через _mysql — висит, через MySQLdb — тоже, через execute — висит, через курсор — тоже. Что ж это
Добавлено ещё позже: вот весь код:
import MySQLdb as mysql
db = mysql.connect(\
host = 'localhost',
user = 'log',
passwd = 'xxx',
db = 'log',
use_unicode = True,
charset='utf8'
)
c = db.cursor()
c.execute("SELECT * FROM wp_4_posts")Вот так уже висит. Не знаю что с этим делать, пойду домой.
PyPy 1.2
Вышел PyPy 1.2, это интерпретатор Пайтона, написанный на Пайтоне. Из интересного: появился
Django выполняется под ним быстрее в 2,86 раз быстрее, чем под CPython. Смущает только:
PyPy does not support the CPython C API, which means that third party libraries for python, written in C, will not work.
Придётся использовать биндинги, написанные на чистом Python, для MySQL, например, такой есть.
30 января: я в Киеве, на PyCamp

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