автордың кітабынан сөз тіркестері Путь Python. Черный пояс по разработке, масштабированию, тестированию и развертыванию
logging обеспечивает доступ к встроенной функциональности для логирования;
• multiprocessing позволяет запускать несколько подпроцессов из программы, обеспечивая API, которое представляет их как потоки;
1 Ұнайды
Абстрактное синтаксическое дерево (АСД) — это выражение структуры исходного кода, встречающееся в любом языке программирования. В любом языке и, конечно же, в Python имеется АСД: в Python АСД собирается путем анализа (парсинга) исходного файла. Как и любое дерево, оно состоит из связанных узлов. Каждый узел — это операция, утверждение, выражение или даже модуль. Каждый узел содержит ссылки на другие узлы. Так и формируется дерево.
>>> inspect.getgeneratorstate(gen)
❶ 'GEN_CREATED'
>>> next(gen)
1
>>> inspect.getgeneratorstate(gen)
❷ 'GEN_SUSPENDED'
>>> next(gen)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> inspect.getgeneratorstate(gen)
❸ 'GEN_CLOSED'
Это позволяет определить, ждет генератор запуска впервые(GEN_CREATED) ❶, ждет вызова next() для продолжения работы(GEN_SUSPENDED) ❷ или закончил выполнение (GEN_CLOSED) ❸. Это может быть полезным для отладки генераторов.
Еще одно возможное применение для декоратора класса — оборачивание функции или класса другими классами. Например, декоратор класса часто используется для функции-обертки, которая сохраняет состояние. Следующий пример демонстрирует оборачивание функции print() для проверки количества ее вызовов за сессию:
class CountCalls(object):
def __init__(self, f):
self.f = f
self.called = 0
def __call__(self, *args, **kwargs):
self.called += 1
return self.f(*args, **kwargs)
@CountCalls
def print_hello():
print("hello")
Теперь можно использовать ее для проверки количества вызовов функции print_hello():
>>> print_hello.called
0
>>> print_hello()
hello
>>> print_hello.called
1
Листинг 6.10. Вызов методов проверки
>>> from unittest import mock
>>> m = mock.Mock()
❶ >>> m.some_method('foo', 'bar')
<Mock name='mock.some_method()' id='26144272'>
❷ >>> m.some_method.assert_called_once_with('foo', 'bar')
>>> m.some_method.assert_called_once_with('foo', ❸mock.ANY)
>>> m.some_method.assert_called_once_with('foo', 'baz')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/dist-packages/mock.py", line 846, in assert_called_
once_with
return self.assert_called_with(*args, **kwargs)
File "/usr/lib/python2.7/dist-packages/mock.py", line 835, in assert_called_
with
raise AssertionError(msg)
AssertionError: Expected call: some_method('foo', 'baz')
Actual call: some_method('foo', 'bar')
Мы создали методы с аргументами foo и bar в качестве тестов, вызвав метод ❶. Простой способ проверить вызовы к объектам-пустышкам — использовать методы assert_called(), такие как assert_called_once_with() ❷. Для этих методов необходимо передать значения, которые, как вы ожидаете, будут использованы при вызове метода-пустышки. Если переданные значения отличаются от используемых, то mock вызывает исключение AssertionError. Если вы не знаете, какие аргументы могут быть переданы, используйте mock.ANY в качестве значения ❸; он заменит любой аргумент, передаваемый в метод-пустышку.
Библиотека mock также может быть использована для замены функции, метода или объекта из внешнего модуля. В листинге 6.11 мы заменили функцию os.unlink() собственной функцией-пустышкой.
Создание метода для объекта mock.Mock с побочным эффектом
>>> from unittest import mock
>>> m = mock.Mock()
>>> def print_hello():
... print("hello world!")
... return 43
...
❶ >>> m.some_method.side_effect = print_hello
>>> m.some_method()
hello world!
43
❷ >>> m.some_method.call_count
1
Мы присвоили целую функцию атрибуту some_method ❶. Технически это позволяет реализовать более сложный сценарий в тесте, благодаря тому что можно включить любой необходимый для теста код в объект-пустышку. Далее нужно передать этот объект в функцию, которая его ожидает.
Атрибут ❷ call_count — это простой способ проверки количества раз, когда метод был вызван.
Библиотека mock использует паттерн «действие — проверка»: это значит, что после тестирования нужно убедиться, что действия, замененные на пустышки, были выполнены корректно.
План нового проекта
Начало нового проекта — та еще задача. Вы еще не знаете, как он будет структурирован, и поэтому могут возникнуть трудности с организацией файлов. Но как только вы поймете, как применить лучшие практики, то сможете определиться, с какой базовой структуры начать. В этом разделе я дам несколько советов, как планировать проект.
Что делать
Для начала рассмотрим структуру проекта: она должна быть как можно более простой. Осторожно используйте пакеты и иерархию: слишком глубокая иерархия затруднит перемещение, а слишком широкая будет неоправданно раздутой.
Избегайте распространенной ошибки по хранению модульных тестов вне директории с пакетом. Эти тесты определенно стоит включить в подпакет вашей программы, чтобы избежать их случайной автоматической установки в виде модуля верхнего уровня tests при использовании setuptools (или аналогичных библиотек разработки пакетов). Размещение их в подпакете гарантирует возможность установки и использования другими пакетами, что позволит остальным пользователям разрабатывать свои собственные модульные тесты.
На рис. 1.2 показана иерархия стандартного файла.
В директории docs должна быть документация о пакете в формате reStructuredText,
В Unix стандартные функции для создания такого событийного цикла — системные вызовы select(2) и poll(2). Эти функции ожидают список дескрипторов и возвращают значение, как только хотя бы один из файловых дескрипторов готов к чтению или записи.
В Python можно получить доступ к этим системным вызовам через модуль select. Построить событийно-ориентированную систему с помощью этих вызовов просто, хотя и утомительно. Листинг 11.3 показывает событийно-ориентированную систему, которая следит за сокетом и обрабатывает любые полученные соединения.
