пятница, 25 декабря 2015 г.

формирование tiff файла в ImageMagick

У tiff для отправки через факс есть ряд требований, искать RFC про TIFF-F.
Пример конвертации в ImageMagick
convert -density 204x196 -units PixelsPerInch -resize 1728x -monochrome -compress Fax IN OUT
где IN и OUT - входной и выходной файлы.
Также можно задать photometric interpretation:
        -define quantum:polarity=min-is-black
        -define quantum:polarity=min-is-white

density может меняться, варианты смотреть в RFC (начинать с 2306), вероятно можно задать и просто -density 204 (но что тогда будет со вторым значением?)

Вообще хорошо взять пришедший тифф за основу и через identify сравнивать, что получается у нас и в готовом файле, при этом крайне желательно иметь оригинал факс-файла и конвертировать его же.

четверг, 17 декабря 2015 г.

python mailers

Совсем простой вариант - через email
https://docs.python.org/2/library/email-examples.html

Можно взять небольшую обёртку mailer, но размер кода оно сильно не уменьшит, а зависимость добавит.

Ими легко слать через системный почтовик и системные очереди. Если требуется подключаться к тому же gmail - код несколько усложняется - добавляются шаги авторизации, starttls итд, и тогда добавляется библиотека smtplib (или всякие yagmail)

Когда требуется поддержка юникода, добавляется она не сложно, только надо помнить что некоторые заголовки типа Subject, From, To требуют особого кодирования, недопустимо просто писать юникод-строку, так делают только быдлокодеры. Должно быть так:
from email.header import Header
msg = MIMEMultipart()
msg['Subject'] = "%s" % Header(subject, 'utf-8') - вообще тут надо отделить имя от адреса и преобразовать только имя, или наоборот склеивать преобразованное имя с адресом. Под рукой нет готового примера. При этом итоговый вариант будет таким:
From: =?UTF-8?B?0J0J0J0J0J0J=?= <mail@mail.me>

С текстом проще
msg.attach(MIMEText(text, 'plain', "UTF-8"))
msg.attach(MIMEText(html, 'html', 'UTF-8'))


Если используются фреймворки типа flask, там обычно есть свои обёртки/реализации, тот же flask-mailer
Также есть пакеты для более массовой рассылки, на базе шаблонов, тот же pymassmailer

среда, 16 декабря 2015 г.

decoder jpeg not available (вариант encoder libtiff not available)

доставить библиотеки
yum install libjpeg-devel
yum install freetype-devel
yum install libpng-devel

также может требоваться конкретная версия либы
yum install libjpeg-devel zlib1g-devel libpng12-devel

sudo aptitude install libjpeg62 libjpeg62-dev zlib1g-dev
sudo apt-get install libjpeg8-dev

в особо запущенных случаях
sudo ln -s /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib

pip uninstall pil
pip install pillow

если уже стояло
# reinstall pillow
pip install --no-cache-dir -I pillow

SQLAlchemy Custom Types

http://docs.sqlalchemy.org/en/latest/core/custom_types.html
http://docs.sqlalchemy.org/en/latest/orm/composites.html

Допустим, есть у нас задача - на лету переводить столбец uuid в unhex-представление.
class HashColumn(VARBINARY):
  def bind_expression(self, bindvalue):
  #bindvalue = type_coerce(bindvalue, Binary)
  return func.unhex(func.replace(bindvalue, '-', ''))

  def column_expression(self, col):
    return func.lower(func.hex(col))

def select(table_name):
  table = Table(table_name, self.metadata, Column("uuid", HashColumn(20)), autoload=True, extend_existing=True)
  select = table.select()
  ...
Казалось бы, тут был бы логичнее TypeDecorator, но..

<Elmer> oh yeah that TypeDecorator doesn't work because the process_bind_param and process_result_value methods should be Python code, func.hex/func.unhex create SQL function calls

Правильно создаём table и получаем автоматом преобразование.

http://stackoverflow.com/questions/33923914/python-sqlalchemy-binary-column-type-hex-and-unhex/33925980#33925980
http://stackoverflow.com/questions/34039039/python-sqlalchemy-binary-column-type-hex-and-unhex-with-autoloaded-table

вторник, 8 декабря 2015 г.

python: inline картинки

Суть:

msgRoot = MIMEMultipart('related')
html = """\
    <p>This is an inline image<br/>
        <img src="cid:image1">
    </p>
"""
msgHtml = MIMEText(html, 'html')

Подробнее:

пятница, 4 декабря 2015 г.

InsecureRequestWarning: Unverified HTTPS request is being made.

При использовании requests, даже когда выставляем verify=False, в логи может сыпать варнингами
InsecureRequestWarning: Unverified HTTPS request is being made.

Как отключить этот crap:
https://urllib3.readthedocs.org/en/latest/security.html#disabling-warnings

в случае прямого использования urllib3
import urllib3
urllib3.disable_warnings()

В случае requests
import requests.packages.urllib3 as urllib3
urllib3.disable_warnings()

четверг, 3 декабря 2015 г.

python+mysql

во 2 питоне есть MySQLdb, в 3 его нет. Самая простая замена:
import pymysql
pymysql.install_as_MySQLdb()

Более полный список вариантов

вторник, 11 августа 2015 г.

Делаем цветной вывод логов

Самый простой вариант -- используя цветовые коды и print
print u"\x1b[31;40mЧто-то красное на чёрном\x1b[0m"

Но использовать такую конструкцию очень сложно, особенно если цветовых вариантов больше одного. Да и замена цвета будет той ещё головной болью...
Можно составить "карту" цветов и использовать в виде переменных (или подключить colorama), но это очень неудобно. Примеры в комментах. Или.
Особенно, когда нужно несколько цветов по разным уровням ошибки, и появляется обёртка вида
def mylog-red-black(string):
    print u"\x1b[31;40m%s\x1b[0m" % (string,)
....

понедельник, 8 июня 2015 г.

python: замеряем время выполнения блока

time.time

Очень простой и вполне рабочий метод на базе time, работает даже во 2 питоне (в 3 есть ещё несколько функций в модуле, с бОльшей точностью)

вторник, 2 июня 2015 г.

python: многопоточность

Есть 2 модуля, схожие по названиям и функциям, но работающие чуть по разному, это
threading.Thread
и
multiprocessing.Process

Но threading создаёт нить внутри процесса (количество процессов не меняется), а mp - создаёт новый процесс.

https://docs.python.org/2/library/threading.html
https://docs.python.org/2/library/multiprocessing.html

В остальном использование довольно простое, делаем инстанс класса, start и при необходимости join

понедельник, 1 июня 2015 г.

Python: пишем в syslog

Хороший стартовый пример
https://gist.github.com/sweenzor/1782457

123456789101112131415161718192021
import logging
import logging.handlers
 
log = logging.getLogger(__name__)
 
log.setLevel(logging.DEBUG)
 
handler = logging.handlers.SysLogHandler(address = '/dev/log')
 
formatter = logging.Formatter('%(module)s.%(funcName)s: %(message)s')
handler.setFormatter(formatter)
 
log.addHandler(handler)
 
 
def hello():
log.debug('this is debug')
log.critical('this is critical')
 
if __name__ == '__main__':
hello()

123
matt@Jenkins:~$ tail -n 2 /var/log/syslog
Feb 9 11:56:19 Jenkins logtest.hello: this is debug
Feb 9 11:56:19 Jenkins logtest.hello: this is critical

Нюансы.
Для SysLogHandler обязателен адрес, у линукса /dev/log, у macos что-то вроде /var/run/syslog, надо уточнять.

Также можно сделать так
handler = logging.handlers.SysLogHandler(address = ('localhost',514), facility=19)
и тут localhost можно заменить на удаленный хост, хотя лучше поручить пересылку логов тому же rsyslog

Также есть менее удобный модуль syslog
import syslog
syslog.openlog( 'myTestLog', 0, syslog.LOG_LOCAL4 )
syslog.syslog( '%%TEST-6-LOG: Log msg: %s' % 'test msg' )

Ну и напоследок интересный линк
http://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-python-apps/

понедельник, 25 мая 2015 г.

python: 7 способов получить hostname

Все работают в линуксе, но далеко не все - в винде. Плюс в ряде случаев hostname и hostname -f могут не совпадать, надо проверить, что лучше подойдёт.

1) import os; print os.uname()[1]
2) import platform; print platform.uname()[1] - как 1, но более универсален, работает и в винде
3) import platform; print platform.node()
4) import socket; print socket.gethostname() (подвид: socket.gethostbyaddr(socket.gethostname())
5) import socket; print socket.getfqdn() - 4 и 5 как раз могут дать разные результаты
6 и 7) - совсем костыльные решения, os.getenv('HOSTNAME') и os.environ['HOSTNAME']

До кучи - есть всякие os.system() и os.popen(), но это совсем костыли и даже не стоят упоминания.

линки
https://wiki.python.org/moin/Powerful%20Python%20One-Liners/Hostname
http://stackoverflow.com/questions/20792499/how-to-get-fully-qualified-host-name-in-python
http://stackoverflow.com/questions/4271740/how-can-i-use-python-to-get-the-system-hostname

вторник, 19 мая 2015 г.

python и рекурсивная работа с файлами

1) os.listdir
import os
for filename in os.listdir(os.getcwd()):
if filename.endswith(".txt"):
print(os.path.join(root, file))

2) os.walk
import os
for root, dirs, files in os.walk(yourpath, topdown=False):
    for name in files:
        print(os.path.join(root, name))
        stuff
    for name in dirs:
        print(os.path.join(root, name))
        stuff

3) glob
import glob
for filename in glob.glob('*.txt'):
...

http://stackoverflow.com/questions/18262293/python-open-every-file-in-a-folder
http://stackoverflow.com/questions/3964681/find-all-files-in-directory-with-extension-txt-with-python

среда, 28 января 2015 г.

lua: получить размер файла

=========== funcs.lua
function fsize (file)
        local current = file:seek()      -- get current position
        local size = file:seek("end")    -- get file size
        file:seek("set", current)        -- restore position
        return size
end
=========== checklibs.lua
dofile("funcs.lua")

libs_file = io.open("librt.so.0","r")
print(fsize(libs_file))
libs_file:close()
===========

http://lua-users.org/lists/lua-l/2011-04/msg00785.html

Вероятный оригинал
http://www.lua.org/pil/21.3.html

В таком виде и гуляет функция fsize, даже с nginx связали
https://gist.github.com/perusio/2133228
location ~* \.(?:gif|jpe?g|png)$ {
set_by_lua $img_file_size '
function fsize (file)
local current = file:seek() -- get current position
local size = file:seek("end") -- get file size
file:seek("set", current) -- restore position
return size
end
fsize(ngx.var.request_filename)';
}

lua и sha*

В luarocks есть sha1 и sha2, в sha2 есть SHA-244, SHA-256, SHA-384, SHA-512
Требует сборки.

SHA-256 hashing algorithm by GravityScore
SHA-256 hashing algorithm by KillaVanilla
Завязаны на библиотеку bit, которая в 5.2 почему-то оказалась недоступна.

Совсем простой метод через openssl
function sysexec (str)
        local h = io.popen(str)
        local result = h:read("*a")
        h:close()
        result = string.gsub(result, "\n", "")
        return result
end

string1 = "encodeme"
run = "echo " .. string1 .. " | openssl sha256 | sed 's#(stdin)= ##'"
string2 = sysexec(run)