Архив автора: admin

Создаём QR коды на Python (Перевод)

Как-то раз я задумался: было бы забавно создать программу при помощи wxPython, которая генерирует QR коды и затем отображает их на экране. Поскольку, как понятно, я хотел написать её на Python, то после недолгих поисков я обнаружил трёх кандидатов на это дело:
Я воспользовался python-qrcode и pyqrnative, так как они прекрасно работают как на Windows, так и на Mac и Linux. Кроме того, они не требуют ничего больше, только Python Imaging Library. Проект pyqrcode требует дополнительных модулей и не работает на Windows, так что я даже не стал с ним заморачиваться. В итоге я взял старый код моего  Photo Viewer и немного его переиначил, чтобы получить генератор QR кодов. Если интересно — давайте поподробнее!

Приступаем

Как я уже упомянул в начале, Вам понадобится Python Imaging Library. Мы будем использовать wxPython для создания GUI, так что без него тоже не обойтись. И кроме того Вам понадобится загрузить python-qrcode и pyqrnative. Основное отличие, которое я обнаружил между ними — python-qrcode гораздо быстрее создаёт изображение и изображение именно привычного нам вида. По каким-то причинам, pyqrnative требует больше времени и создаёт более плотно выглядящие QR коды. Возможно, у каждого из проектов есть опции, меняющие вид кодов, но у обоих проектов отвратительная документация. В итоге пришлось копаться в исходниках больше, чем когда-либо.

Создаём QR коды

Итак, как только мы установили всё, что нам нужно, мы можем запустить следующий код и посмотреть, на что же способен Python:
import os
import wx
 
try:
import qrcode
except ImportError:
qrcode = None
 
try:
import PyQRNative
except ImportError:
PyQRNative = None
 
########################################################################
class QRPanel(wx.Panel):
""""""
 
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent=parent)
self.photo_max_size = 240
sp = wx.StandardPaths.Get()
self.defaultLocation = sp.GetDocumentsDir()
 
img = wx.EmptyImage(240,240)
self.imageCtrl = wx.StaticBitmap(self, wx.ID_ANY,
wx.BitmapFromImage(img))
 
qrDataLbl = wx.StaticText(self, label="Текст для перевода в QR код:")
self.qrDataTxt = wx.TextCtrl(self, value="http://www.mousevspython.com", size=(200,-1))
instructions = "Имя файла с QR кодом"
instructLbl = wx.StaticText(self, label=instructions)
self.qrPhotoTxt = wx.TextCtrl(self, size=(200,-1))
browseBtn = wx.Button(self, label='Изменить место для сохранения')
browseBtn.Bind(wx.EVT_BUTTON, self.onBrowse)
defLbl = "Сохраняется по умолчанию в: " + self.defaultLocation
self.defaultLocationLbl = wx.StaticText(self, label=defLbl)
 
qrcodeBtn = wx.Button(self, label="Создать QR при помощи qrcode")
qrcodeBtn.Bind(wx.EVT_BUTTON, self.onUseQrcode)
pyQRNativeBtn = wx.Button(self, label="Создать QR при помощи PyQRNative")
pyQRNativeBtn.Bind(wx.EVT_BUTTON, self.onUsePyQR)
 
# компоновщик
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
qrDataSizer = wx.BoxSizer(wx.HORIZONTAL)
locationSizer = wx.BoxSizer(wx.HORIZONTAL)
qrBtnSizer = wx.BoxSizer(wx.VERTICAL)
 
qrDataSizer.Add(qrDataLbl, 0, wx.ALL, 5)
qrDataSizer.Add(self.qrDataTxt, 1, wx.ALL|wx.EXPAND, 5)
self.mainSizer.Add(wx.StaticLine(self, wx.ID_ANY),
0, wx.ALL|wx.EXPAND, 5)
self.mainSizer.Add(qrDataSizer, 0, wx.EXPAND)
self.mainSizer.Add(self.imageCtrl, 0, wx.ALL, 5)
locationSizer.Add(instructLbl, 0, wx.ALL, 5)
locationSizer.Add(self.qrPhotoTxt, 0, wx.ALL, 5)
locationSizer.Add(browseBtn, 0, wx.ALL, 5)
self.mainSizer.Add(locationSizer, 0, wx.ALL, 5)
self.mainSizer.Add(self.defaultLocationLbl, 0, wx.ALL, 5)
 
qrBtnSizer.Add(qrcodeBtn, 0, wx.ALL, 5)
qrBtnSizer.Add(pyQRNativeBtn, 0, wx.ALL, 5)
self.mainSizer.Add(qrBtnSizer, 0, wx.ALL|wx.CENTER, 10)
 
self.SetSizer(self.mainSizer)
self.Layout()
 
#----------------------------------------------------------------------
def onBrowse(self, event):
""""""
dlg = wx.DirDialog(self, "Выберите папку:",
style=wx.DD_DEFAULT_STYLE)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
self.defaultLocation = path
self.defaultLocationLbl.SetLabel("Сохраняем в: %s" % path)
dlg.Destroy()
 
#----------------------------------------------------------------------
def onUseQrcode(self, event):
"""

https://github.com/lincolnloop/python-qrcode

"
""
qr = qrcode.QRCode(version=1, box_size=10, border=4)
qr.add_data(self.qrDataTxt.GetValue())
qr.make(fit=True)
x = qr.make_image()
 
qr_file = os.path.join(self.defaultLocation, self.qrPhotoTxt.GetValue() + ".jpg")
img_file = open(qr_file, 'wb')
x.save(img_file, 'JPEG')
img_file.close()
self.showQRCode(qr_file)
 
#----------------------------------------------------------------------
def onUsePyQR(self, event):
"""

http://code.google.com/p/pyqrnative/

"
""
qr = PyQRNative.QRCode(20, PyQRNative.QRErrorCorrectLevel.L)
qr.addData(self.qrDataTxt.GetValue())
qr.make()
im = qr.makeImage()
 
qr_file = os.path.join(self.defaultLocation, self.qrPhotoTxt.GetValue() + ".jpg")
img_file = open(qr_file, 'wb')
im.save(img_file, 'JPEG')
img_file.close()
self.showQRCode(qr_file)
 
#----------------------------------------------------------------------
def showQRCode(self, filepath):
""""""
img = wx.Image(filepath, wx.BITMAP_TYPE_ANY)
# масштабируем изображение
W = img.GetWidth()
H = img.GetHeight()
if W > H:
NewW = self.photo_max_size
NewH = self.photo_max_size * H / W
else:
NewH = self.photo_max_size
NewW = self.photo_max_size * W / H
img = img.Scale(NewW,NewH)
 
self.imageCtrl.SetBitmap(wx.BitmapFromImage(img))
self.Refresh()
 
 
########################################################################
class QRFrame(wx.Frame):
""""""
 
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="QR Code Viewer", size=(550,500))
panel = QRPanel(self)
 
if __name__ == "__main__":
app = wx.App(False)
frame = QRFrame()
frame.Show()
app.MainLoop()
Код для изменения и отображения картинки разъяснён в одной из предыдущих статей (не переведена), так что единственное, что может вызвать у Вас непонимание — два метода создания кодов: onUseQrcode и onUsePyQR. Я всего лишь взял примеры с их сайтов и немного поменял их, чтобы сгенерировать изображение с кодом. Они достаточно самоочевидны, но почти не документированны, так что я не смогу сказать Вам, что же тут происходит. И, хотя оба проекта страдают на момент написания от отсутствия документации, код, тем не менее работает:
Как можно видеть — вполне стандартный код. А этот, созданный PyQRNative, выглядит гораздо более «плотным»:
Оба кода были корректно распознаны моим телефоном на  Android. Так что если Вам надо создать для вашего проекта QR код — я надеюсь, эта статья Вам поможет!

Обновление от 21/05/2012

Один из моих читателей (Mike Farmer) сообщил мне недавно, что в PyQRNative “первый аргумент — размер контейнера, а второй — избыточность / коррекция ошибок”. У меня были такие подозрения по поводу второго аргумента, но я не знаю, что делают эти уровни коррекции ошибок. К счастью, Mr. Farmer объяснил это мне: Если уровень коррекции ошибок низкий, то смазывание кода или его намокание приведёт его в нечитабельное состоянии. Если же Вы будете использовать более высокий уровень коррекции, то за счёт добавления / дублирования данных внутри кода, он сможет пережить даже потоки слёз. Более того, при высоком уровне коррекции ошибок Вы можете даже наложить на код дополнительное изображение, и он  это переживёт. В любом случае, если Вы изменяете первый параметр, Вы можете изменить размер кода. Зачем? Ну, чем больше информации Вы хотите засунуть в код, тем больше он должен быть. Mr. Farmer предложил забавный тестовый код, который позволяет вычислить минимальный возможный для вашей информации размер кода:

import PyQRNative
 
def makeQR(data_string,path,level=1):
quality={1: PyQRNative.QRErrorCorrectLevel.L,
2: PyQRNative.QRErrorCorrectLevel.M,
3: PyQRNative.QRErrorCorrectLevel.Q,
4: PyQRNative.QRErrorCorrectLevel.H}
size=3
while 1:
try:
q = PyQRNative.QRCode(size,quality[level])
q.addData(data_string)
q.make()
im=q.makeImage()
im.save(path,format="png")
break
except TypeError:
size+=1

Исходник

Автор: Ishayahu Lastov

Говядина в томатах с вином

«КАК стать Барменом«

По этому рецепту получается безумно ароматный соус и мягкое мясо. Просто и вкусно!

Ингредиенты:

4 ст.л. несоленого сливочного масла
4 ст.л. оливкового масла
2 мелко порезанные моркови
2 мелко порезанные средние луковицы
500 г говяжья нога (голяшка)
1 зубчик чеснока
350 мл томатного пюре
120 мл белого сухого вина

Приготовление:

1. Разогрейте половину сливочного и оливкового масла в большой сковороде и обжарьте морковь и лук.

2. Сделайте небольшой надрез в мясе и вставьте туда зубчик чеснока.

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

4. Через несколько минут добавьте воды 250-500 мл, по необходимости, томатное пюре и оставшееся масло.

5. Варите на медленном огне до мягкости мяса, около 3 часов.

6. Добавьте вино, когда мясо будет готово.


Автор: Мирослав

Релиз Demakein 0.2: Шалмей (Перевод)

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

Автор: Ishayahu Lastov

Программирование работы с SSH при помощи Paramiko (Перевод)

OpenSSH — это вездесущий метод удалённого безопасного доступа к машине и передачи файлов. Многие — системные администраторы, инженеры автоматизации тестов, веб-разработчики и другие люди используют этот методы ежедневно. Написание скриптов для ssh на Python может быть тяжёлым занятием, но модуль Paramiko позволяет решить эту задачу проще.
Это репринт статьи, написанной для Python Mag­a­zine в колонку Com­pletely Dif­fer­ent и опубликованной в октябрьском выпуске 2008 года. Тут она приводится в оригинальной форме, со всеми ошибками и т.д.

Читать

Python 101: Перемещение файлов между серверами (Перевод)

Если Вам часто приходится заниматься системным администрированием, тогда Вы знаете, что иногда Вам нужен скрипт, который бы перемещал файлы с одного сервера на другой. Я не системный администратор, но мне часто приходится сталкиваться с такой задачей. У Python есть сторонний пакет для этой цели. Мы посмотрим на paramiko, который зависит от PyCrypto (скачать PyCrypto можно с PyPI).

Пишем код

Предположим, что у Вас уже всё установлено, так что мы можем приступать к работе. Вот код, основанный на том, что я сам использую на работе. Давайте посмотрим на него:
import paramiko
 
########################################################################
class SSHConnection(object):
""""""
 
#----------------------------------------------------------------------
def __init__(self, host, username, password, port=22):
"""Инициализируем и настраиваем соединение"""
self.sftp = None
self.sftp_open = False
 
# открываем поток SSH Transport
self.transport = paramiko.Transport((host, port))
 
self.transport.connect(username=username, password=password)
 
#----------------------------------------------------------------------
def _openSFTPConnection(self):
"""
Открываем SFTP соединение, если этого ещё не сделано
"
""
if not self.sftp_open:
self.sftp = paramiko.SFTPClient.from_transport(self.transport)
self.sftp_open = True
 
#----------------------------------------------------------------------
def get(self, remote_path, local_path=None):
"""
Копируем файл с удалённого хоста к нам
"
""
self._openSFTPConnection()
self.sftp.get(remote_path, local_path)
 
#----------------------------------------------------------------------
def put(self, local_path, remote_path=None):
"""
Копируем файл от нас на удалённый хост
"
""
self._openSFTPConnection()
self.sftp.put(local_path, remote_path)
 
#----------------------------------------------------------------------
def close(self):
"""
Закрываем SFTP и ssh соединения
"
""
if self.sftp_open:
self.sftp.close()
self.sftp_open = False
self.transport.close()
 
if __name__ == "__main__":
host = "myserver"
username = "mike"
pw = "dingbat!"
 
origin = '/home/mld/projects/ssh/random_file.txt'
dst = '/home/mdriscoll/random_file.txt'
 
ssh = SSHConnection(host, username, pw)
ssh.put(origin, dst)
ssh.close()
Достаточно просто, правда? В методе  __init__ нашего класса мы всего лишь задаём параметры соединения. В нашем случае нам надо указать хост, логин и пароль. После чего мы открываем потоковый объект SSH Transport. Затем мы вызываем наш метод put для отправки файла на удалённый сервер. С обратной задачей нам поможет справиться метод get. И, наконец, мы вызываем наш метод close, чтобы закрыть соединение. Можно заметить, что в наших методах put и get мы используем частный метод для проверки наличия соединения, чтобы открыть его в случае, если оно было по какой-то причине закрыто.

Итог

Paramiko реально облегчает нашу работу. Я очень рекомендую прочитать статью Jesse’а на эту тему (ссылка ниже), так как там всё это описывается более подробно. Мы интересно, как ещё можно решить эту задачу при помощи ssh и scp, так что я буду рад вашим комментариям. Сам я слышал хорошие отзывы о Fabric.

Дополнительное чтение

Автор: Ishayahu Lastov

Зачем в python with

Долгое время при работе с файлами из python я писал примерно следующий код:

Без подсветки синтаксиса

def some_func(fname):
    fd = open(fname)
    some_data_processing(fd.read())
    return result

 

def some_func(fname):
    fd = open(fname)
    some_data_processing(fd.read())
    return result

 

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

Но что будет если в some_data_processing произойдет исключение?

Например так:

Без подсветки синтаксиса

import sys

class TestClass(object):
def __del__(self):
print «I’m deleted»

def data_process():
obj = TestClass()
raise IndexError()

try:
data_process()
except:
print «In exception handler»

print «after except»

 

import sys

class TestClass(object):
def __del__(self):
print «I’m deleted»

def data_process():
obj = TestClass()
raise IndexError()

try:
data_process()
except:
print «In exception handler»

print «after except»

 

На консоли появляется:

    In exception handler
    after except
    I'm deleted

Почему-то «In exception handler» и «after except» выводятся раньше «I’m deleted».

Первая проблема в том, что вместе с исключением питон хранит и трейс стека, содержащий все фреймы вплоть до породившего исключение. А внутри фрейма живет f_locals — словарь локальных переменных, и именно он имеет ссылку на экземпляр класса TestClass. Таким образом до окончания обработки исключения obj будет жить точно. Почему же «after except» появляется раньше чем «I’m deleted»? Было бы логично чистить трейс после успешного выхода из блока try. Дело в том что 2.X питон не всегда чистит внутренние структуры после обработки исключения и в общем случае вы должны явно вызывать функцию sys.exc_clear чтобы очистить их. Когда я подошел с этим вопросом к Larry Hastings (одному из основных разработчиков ядра питона) ему потребовалось около 20ти минут, что-бы понять что происходит и найти в документации sys.exc_clear. (Правда стоит отметить, что он давно использует 3.X, где это поведение стало адекватнее.) В 3.X это поведение улучшили, и теперь sys.exc_clear автоматически вызывается окончанию обработки исключения.

Кстати, если вы напишете примерно такой код:

Без подсветки синтаксиса

try:
    data_process()
except:
    fr = sys.exc_info()[2]
    del fr

 

try:
    data_process()
except:
    fr = sys.exc_info()[2]
    del fr

 

то не забудьте удалить fr используя del, как в последней строке — иначе он образует циклическую ссылку с текущим фреймом и тогда все станет совсем плохо.

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