Архив метки: Python

pytest продолжение

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

В личных беседах и по почте поступил ряд вопросов и предложений, поэтому продолжению быть. В этой и последующих статьях погрузимся глубже в возможности pytest. Новый материал предлагаю выкладывать в виде поваренной книги — проблема, рецептура, ингредиенты, 5 минут готовки, наслаждение.

Последовательно выполнение тестовых сценариев


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

В следующих статьях мы посмотрим как можно избежать этой ситуации пользуясь стандартными средствами пайтеста.

Например, тестируемая программа при первом запуске накатывает схему базы (sqlite чтобы не морочиться) и заполняет её некоторой служебной информацией. Допустим перед нами стоит задача «дешево» протестировать этот модуль. Сходу задачу модно разбить на 2 подзадачи — проверка создания файла базы, затем проверка схемы и в конце проверка данных.

Самый простой вариант — нумерация в названии тестов

# conftest.py
import os
import pytest
import sqlite3


def pytest_configure(config):

    config.DB_PATH = «db.sqlite»


@pytest.fixture(scope=»module»)
def creator(request):
    DB_PATH = request.config.DB_PATH
    con = sqlite3.connect(DB_PATH)
    cur = con.cursor()
    cur.executescript(«»»
        create table person(
            firstname,
            lastname,
            age
        );

        create table book(
            title,
            author,
            published
        );

        insert into book(title, author, published)
        values (
            'Dirk Gently''s Holistic Detective Agency',
            'Douglas Adams',
            1987
        );
        «»»)
    con.commit()
    con.close()
    return DB_PATH


@pytest.fixture
def cursor(request):
    class cursor:

        def __init__(self, dbpath):
            self.dbpath = dbpath
            self.conn = sqlite3.connect(self.dbpath)

        def table_exists(self, table):
            cursor = self.conn.cursor()
            cursor.execute(
                «SELECT name FROM sqlite_master WHERE type = «table»»)
            tables = cursor.fetchall()
            for each in tables:
                if table in each:
                    return True
            return False

        def getrows(self, table):
            cursor = self.conn.cursor()
            cursor.execute(«SELECT * FROM %s;» % (table))
            return cursor.fetchall()

    return cursor(request.config.DB_PATH)

# test.py
def test_1_db_exists(creator):
    assert os.path.exists(creator)


@pytest.mark.parametrize(«table», [«person», «book»])
def test_2_check_scheme(table, creator, cursor):
    result = cursor.table_exists(table)
    assert result


@pytest.mark.parametrize(«table», [«book»])
def test_3_check_rows(table, creator, cursor):
    assert cursor.getrows(table)


Спасибо документации питона за готовые примеры.

У такого подхода есть ряд недостатков.
1. В названии теста появляется нумерация — это лишняя мета информация. (Это может сказаться на тестовом отчете или билд логе CI сервера)
2. Название теста усложняется
3. Вставка нового элемента в середину приведет к смене нумерации всех последующих тестов

Вариант посложнее — маркеры


Свои маркеры мы реализовывать не будем, а используем готовый плагин pytest-ordering. В принципе вся реализация такого плагина составит не больше 100 строчек кода.

# test.py
@pytest.mark.order1
def test_db_exists(creator):
    assert os.path.exists(creator)


@pytest.mark.order2
@pytest.mark.parametrize(«table», [«person», «book»])
def test_check_scheme(table, creator, cursor):
    result = cursor.table_exists(table)
    assert result


@pytest.mark.order3
@pytest.mark.parametrize(«table», [«book»])
def test_check_rows(table, creator, cursor):
    assert cursor.getrows(table)


Наши тестовые функции преобразились, стали более понимаемы для чтения.
Из коробки плагин содержит создание цепочек выполнения, более понятные маркеры (pytest.mark.run('first'), pytest.mark.run('second')) и прочее. Более подробно в микро доку плагина.

Ссылки
[1] https://docs.python.org/2/library/sqlite3.html
[2] http://pytest-ordering.readthedocs.org/en/develop/

Автор: Евгений Курочкин

{} vs dict()


В питоне предусмотрена возможность создать словарь двумя способами — через фигурные скобки {} и через конструктор dict(). В чем разница и что лучше использовать в коде?


Код

a = dict(one=1, two=2, three=3)
b = {'one': 1, 'two': 2, 'three': 3}

Пример наглядно демонстрирует что при статическом определении атрибутов количество кода практически одинаковое (скобки больше всего лишь на 2 символа). 

Инициализация

Конструктор словаря предлагает расширенный функционал для инициализации словаря.

d = dict((str(v),v) for v in range(10))
dict(zip(['one', 'two', 'three'], [1, 2, 3]))


Скорость работы

Выполним в консоли следующие выражения

>>python -m timeit «{}»
10000000 loops, best of 3: 0.034 usec per loop

>>python -m timeit «dict()»

10000000 loops, best of 3: 0.127 usec per loop

Почему такая существенная разница в скорости? Все просто, смотрим что выдает диассемблер

>>import dis

>>def d(): t = {}

>>dis.dis(d)

  1           0 BUILD_MAP                0
              3 STORE_FAST               0 (t)
              6 LOAD_CONST               0 (None)

              9 RETURN_VALUE

>>def d(): t = dict()
>>dis.dis(d)

  1           0 LOAD_GLOBAL              0 (dict)

              3 CALL_FUNCTION            0
              6 STORE_FAST               0 (t)
              9 LOAD_CONST               0 (None)
             12 RETURN_VALUE



При вызове конструктора dict() выполняется большее количество инструкций питона.

Вывод

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

PS. Все выводы актуальны и для списков


Ссылки

https://docs.python.org/2/library/stdtypes.html#mapping-types-dict
http://stackoverflow.com/questions/6610606/dict-literal-vs-dict-constructor-any-preferred

Автор: Евгений Курочкин

Топ 10 вопросов по python на stackoverflow

What does the yield keyword do in Python?
What is a metaclass in Python?
How to check whether a file exists using Python
Does Python have a ternary conditional operator?
Calling an external command in Python
How can I make a chain of function decorators in Python?
What does `if __name__ == “__main__”:` do?
How can I merge two Python dictionaries in a single expression?
Sort a Python dictionary by value
How do I install pip on Windows?

Довольно ожидаемо

[1] stackoverflow.com

Автор: Евгений Курочкин

MagicPython — Syntax Highlighter для SublimeText

Мой приятель Юра Селиванов попросил написать рекламный пост о его новом проекте MagicPython.

Это syntax highlighter для Sublime Text и Atom, который поддерживает все новые языковые конструкции Python 3.5 (async def и await например) плюс type annotations, string formatting и регулярные выражения.

Sublime поддерживает Python из коробки, но с Python 3 (а особенно с Python 3.5) у него проблемы. MagicPython понимает всё.
Разметка шаблонов для форматирования строк и регулярок заслуживает отдельного упоминания — выглядит прекрасно и заметно облегчает жизнь.

Я сам использую ортодоксальный Emacs и переходить (пока) не собираюсь, но MagicPython работает исключительно хорошо и заслуживает доброго слова.

К слову, Юра (https://twitter.com/1st1) Python Core Developer и автор PEP 492 aka async/await — т.е. очень грамотный спец, который знает как делать качественные продукты.

Пользуйтесь с удовольствием.

P.S.

О редакторе Atom узнал только на этой неделе.
На первый взгляд выглядит как Sublime но при этом Open Source.
Уважаемые читатели, кто-нибудь его использует? Какие ваши впечатления?

Автор: Andrew Svetlov

Видеоуроки курса Python 2015

Курс ориентирован на людей, уже знакомых с каким-либо языком программирования, например, Java или C++.

Лектор: Сергей Лебедев.

Домашние задания

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

Хорошие книги про Python

  1. David M. Beazley, Python Essential Reference, 2009.
  2. Mark Lutz, Learning Python, 5th edition, 2013 (значительная часть 4-го издания также будет релевантной).
  3. David M. Beazley, Brian K. Jones, Python Cookbook, 3rd edition, 2013.

Лекция 1. Начало.

Кто, когда и зачем придумал язык Python. Интерпретаторы языка. Синтаксис языка с высоты птичьего полёта. Интерактивная оболочка IPython.

Дополнительные материалы

Лекция 2. Всё, что вы хотели знать о функциях в Python.

Синтаксис объявления функций. Упаковка и распаковка аргументов. Ключевые аргументы и аргументы по умолчанию. Распаковка и оператор присваивания. Области видимости, правило LEGB, операторы global и nonlocal. Функциональное программирование, анонимные функции. Функции map, filter и zip. Генераторы списков, множеств и словарей. Немного о PEP 8.

Дополнительные материалы

Лекция 3. Декораторы и модуль functools.

Синтаксис декораторов. Декораторы с аргументами, без аргументов. Примеры использования декораторов. Модуль functools.

Дополнительные материалы

Лекция 4. Строки, байты, файлы и ввод/вывод.

Строковые литералы и сырые строки. Строки и Юникод. Основные методы работы со строками. Модуль string. Байты. Кодировки. Файлы и файловые объекты. Методы работы с файлами. Модуль io.

Дополнительные материалы

Лекция 5. Встроенные коллекции и модуль collections.

И снова встроенные коллекции: кортеж, список, множество, словарь — обход в глубину, обзор методов, примеры. Почти всё про модуль collections: именованные кортежи, счётчики, defaultdict, OrderedDict.

Дополнительные материалы

Лекция 6. Классы 1.

Синтаксис объявления классов. Атрибуты, связанные и несвязанные методы, __dict__, __slots__< /code>. Статические методы и методы класса. Свойства, декоратор @property. Наследование, перегрузка методов и функция super. Декораторы классов. Магические методы.

Дополнительные материалы

Лекция 7. Исключения и менеджеры контекста.

Исключения, зачем они нужны и как их обрабатывать. Встроенные исключения и базовые классы BaseException и Exception. Операторы try...except..else..finally. Менеджеры контекста и модуль contextlib.

Дополнительные материалы

Лекция 8. Итераторы, генераторы и модуль itertools.

Два протокола итераторов: __next__ + __iter__ и __getitem__. Итераторы и цикл for, а также операторы in и not in. Генераторы, оператор-выражение yield. Генераторы как: итераторы, сопрограммы, менеджеры контекста. Модуль itertools.

Дополнительные материалы

Лекция 9. Модули, пакеты и система импорта.

Модули. Операторы import и from ... import. Пакеты. Относительный и абсолютный импорт. __init__-фасад. И снова оператор import - обход в глубину.

Дополнительные материалы

Лекция 10. Классы 2.

Дескрипторы: что-как-зачем. Конструктор __new__, класс type и метаклассы. Наследование встроенных типов. Модули abc и collections.abc.

Дополнительные материалы

Лекция 11. Тестирование.

Зачем тестировать? Тестирование в интерпретаторе и доктесты. Модуль unittest. Пакет py.test - на порядок лучше. Тестирование свойств и пакет hypothesis.

Дополнительные материалы

Лекция 12. Быстрее, Python, ещё быстрее.

Измерение времени работы кода на Python с помощью модулей timeit, cProfile и line_profiler. Немного о NumPy. JIT и AOT компиляция кода на Python на примере Numba и Cython.

Дополнительные матер