четверг, 22 октября 2015 г.

Пара годных практик

Instead of writing methods without return values, make them return self

# Instead of this
self.release_water()
self.shutdown()
self.alarm()

class Reactor:
    ...
    def release_water(self):
        self.valve.open()
        return self

self.release_water().shutdown().alarm()   

Enumeration (iteration) method

# Bad
# Can't change type of collection
#     e.g. can't change employees from a list to a set
class Department:
    def __init__(self, *employees):
        self.employees = employees

for employee in department.employees:
    ...
   
# Better
class Department:
    def __init__(self, *employees):
        self._employees = employees

    def __iter__(self):
        return iter(self._employees)

for employee in department:  # More readable, more composable


Оригинал старьи

пятница, 15 августа 2014 г.

exrex генератор данных по регулярным выражениям

Всем привет!

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

API крайне простой
count - возвращет количество возможных вариаций
parse - парсер регулярных выражений
getone - возвращает псевдо-рандомное значение
generate - возвражает генератор со всеми вариантами

Примеры использования

На всякий замечу, что у вас по некоторым примером вывод может быть другим

>>> print exrex.getone('[A-Z][a-z]{1,10} [A-Z][a-z]{1,10}')
Boris Yeltsin

>>> print exrex.getone('\+[0-9]\([0-9]{3}\) [0-9]{3}-[0-9]{2}-[0-9]{2}')
+5(777) 790-68-69

>>> print [r for r in exrex.generate('|'.join(str(i) for i in range(5)))]
[u'0', u'1', u'2', u'3', u'4']

>>> exrex.count('[0-9]{1}')
10

>>> print exrex.parse('[0-9]{1,100}')
[('max_repeat', (1, 100, [('in', [('range', (48, 57))])]))]

Есть также возможность запуска из консоли

>>> python -m exrex -r [0-9]{2}
31
Возвращает псевдо-рандомное число из 2 цифр

За более подробной информацией в ссылки.


Ссылки

https://github.com/asciimoo/exrex
http://exrex.readthedocs.org/

пятница, 11 июля 2014 г.

python кодировка исходников

Всем привет!

Я думаю каждый из нас ловил что-то подобное:

 File "python_coding_style.py", line 2
SyntaxError: Non-ASCII character '\xd0' in file python_coding_style.py on line 3, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details

Проблема в том что интерпретатор не знает в какой кодировке у нас файлы исходников. Проблема решается явным указанием их кодировки:
# coding: utf8

Чаще на практике встречаются следующие варианты

# -*- coding: utf8 -*-
# coding: utf8
# coding=utf8

В PEP-0263 декларируется, что для определения кодировки исходников годится все что подпадет под регулярку coding[:=]\s*([-\w.]+)
Например, #This Python file uses the following encoding: utf-8 !!!

Ссылки

http://legacy.python.org/dev/peps/pep-0263/

четверг, 10 июля 2014 г.

Часть 4. py.test debug

Мы уже рассмотрели основные принципы написание тестов, но один важный момент упустили, а именно дебаг тестов.


Использование print

Часто люди пользующие питон дебажат свои скрипты с помощью использования принтов. По умолчанияю pytest пишет весь stout и stderr. В предыдущем посте эта тема рассматривалась. Для отключения этой особенности нужно использовать параметр --capture или маску -s. 
Посмотрим на небольшой (надуманный) пример:

# use_debug.py
@py.test.mark.parametrize("v", range(1, 5))
def test_parity(v):
    print("Value: %d" % v)
    assert v % 2

>>>py.test use_debug.py -s -v --tb line

============================= test session starts =============================
platform win32 -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- C:\Python27\python.exe
plugins: teamcity-messages, rerunfailures
collected 4 items

use_debug.py:40: test_parity[1] Value: 1
PASSED
use_debug.py:40: test_parity[2] Value: 2
FAILED
use_debug.py:40: test_parity[3] Value: 3
PASSED
use_debug.py:40: test_parity[4] Value: 4
FAILED

================================== FAILURES ===================================
c:\JOB\3_TestSolution\Blog\use_debug.py:43: assert (2 % 2)
c:\JOB\3_TestSolution\Blog\use_debug.py:43: assert (4 % 2)
===================== 2 failed, 2 passed in 0.03 seconds ======================

Как видим в консоли напечатались входные значения. 



Автовключение дебага

Для этого предусмотрен флаг --pdb. Если тест пофелился, то py.test прогонит его на тех же данных, но уже с включенным питоновским дебагером pdb.

>>>py.test use_debug.py -s -v --tb line --pdb

platform win32 -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- C:\Python27\python.exe
plugins: teamcity-messages, rerunfailures
collected 4 items

use_debug.py:64: test_parity[1]
>>>>>>>>>>>>>>>>>>> PDB set_trace (IO-capturing turned off) >>>>>>>>>>>>>>>>>>>
> c:\job\3_testsolution\blog\use_debug.py(67)test_parity()
-> assert v % 2
(Pdb)

Брейкпоинты


Из коробки py.test предоставляет возможность в коде явно указать брекпоинт.

# use_debug.py
@py.test.mark.parametrize("v", range(1, 5))
def test_parity(v):
    py.test.set_trace()
    assert v % 2

При каджом вызове тестовой функции test_parity в месте устанвки брейкпоинта py.test будет запускать pdb

>>>py.test use_debug.py -s -v --tb line

use_debug.py:62: test_v[1]
>>>>>>>>>>>>>>>>>>> PDB set_trace (IO-capturing turned off) >>>>>>>>>>>>>>>>>>>
> c:\job\3_testsolution\blog\use_debug.py(65)test_v()
-> assert v % 2
(Pdb)


Ссылки

http://pytest.org/latest/usage.html#dropping-to-pdb-python-debugger-on-failures
http://pytest.org/latest/usage.html#setting-a-breakpoint-aka-set-trace