Вклад в pandas
Содержание:
- С чего начать?
- Отчеты об ошибках и запросы на улучшение
- Работа с кодом
- Вклад в документацию
- Вклад в базу кода
- Внесение ваших изменений в pandas
С чего начать?
Все contributions, bug reports, исправления ошибок, улучшения документации, новые возможности и идеи приветствуются.
Если вы новичок в pandas или в разработке с открытым исходным кодом, мы рекомендуем просмотреть вкладку «Issues» на GitHub, чтобы найти интересующие вас вопросы. Есть ряд вопросов с метками «Docs» и «good first issue», с которых вы можете начать. После того, как вы найдёте интересный вопрос, вы можете вернуться сюда, чтобы настроить свою среду разработки.
Спрашивайте вопросы на почтовой рассылке mailing list или в Gitter.
Отчеты об ошибках и запросы на улучшение
Отчеты об ошибках важны для повышения стабильности pandas. Полный отчёт об ошибке позволит другим воспроизвести ошибку и внести вклад в её исправление. Смотрите эту статью на Stack Overflow и этот блог-пост для советов по написанию хорошего отчёта об ошибке.
Проверка кода, вызывающего ошибку, на ветке master часто полезна для подтверждения существования ошибки. Также стоит поискать существующие bug reports и pull requests, чтобы убедиться, что проблема уже не была сообщена или исправлена.
Отчеты об ошибках должны:
-
Содержать короткий, автономный фрагмент Python-кода, воспроизводящий проблему. Вы можете красиво отформатировать код, используя GitHub Flavored Markdown:
```python >>> from pandas import DataFrame >>> df = DataFrame(...) ... ```
-
Содержать полную строку версии pandas и его зависимостей. Вы можете использовать встроенную функцию:
>>> import pandas as pd >>> pd.show_versions()
- Объяснить, почему текущее поведение неверно/нежелательно и что ожидается вместо этого.
Затем вопрос будет показан сообществу pandas и будет открыт для комментариев/идей других участников.
Работа с кодом
Теперь, когда у вас есть вопрос, который вы хотите исправить, улучшение, которое нужно добавить, или документация, которую нужно улучшить, вам нужно узнать, как работать с GitHub и базой кода pandas.
Система управления версиями, Git и GitHub
Для новых пользователей работа с Git является одной из самых сложных частей вклада в pandas. Она может быстро стать непосильной, но соблюдение приведенных ниже рекомендаций поможет упростить процесс и избежать проблем. Как всегда, если у вас возникнут трудности, не стесняйтесь просить помощи.
Код размещён на GitHub. Для участия вам необходимо зарегистрироваться на бесплатной учётной записи GitHub. Мы используем Git для управления версиями, чтобы множество людей могли вместе работать над проектом.
Некоторые отличные ресурсы для изучения Git:
Начало работы с Git
GitHub предоставляет инструкции по установке Git, настройке ключа SSH и настройке Git. Все эти шаги необходимо выполнить, прежде чем вы сможете беспрепятственно работать между локальным хранилищем и GitHub.
Создание форка
Вам понадобится свой собственный форк, чтобы работать над кодом. Перейдите на страницу проекта pandas и нажмите кнопку Fork. Вы захотите клонировать свой форк на свой компьютер:
git clone https://github.com/your-user-name/pandas.git pandas-yourname cd pandas-yourname git remote add upstream https://github.com/pandas-dev/pandas.git
Это создаёт каталог pandas-yourname и соединяет ваше хранилище с исходным (главным проектом) хранилищем pandas.
Создание среды разработки
Для проверки изменений в коде вам потребуется скомпилировать pandas из исходного кода, что потребует компилятора C и среды Python. Если вы вносите изменения в документацию, вы можете перейти к Вклад в документацию, но не сможете сгенерировать документацию локально перед отправкой изменений.
Установка компилятора C
Pandas использует C-расширения (в основном написанные на Cython) для ускорения определённых операций. Для установки pandas из исходного кода необходимо скомпилировать эти C-расширения, а это означает, что вам нужен компилятор C. Этот процесс зависит от вашей платформы. Следуйте руководству по установке CPython CPython, чтобы установить компилятор. Вам не нужно выполнять шаги ./configure или make; вам нужно только установить компилятор.
Для разработчиков Windows, при использовании Python 3.5 и выше, достаточно установить Visual Studio 2017 с нагрузкой разработки Python и инструментами Python native development.
- https://blogs.msdn.microsoft.com/pythonengineering/2017/03/07/python-support-in-vs2017/
- https://blogs.msdn.microsoft.com/pythonengineering/2016/04/11/unable-to-find-vcvarsall-bat/
- https://github.com/conda/conda-recipes/wiki/Building-from-Source-on-Windows-32-bit-and-64-bit
- https://cowboyprogrammer.org/building-python-wheels-for-windows/
- https://blog.ionelmc.ro/2014/12/21/compiling-python-extensions-on-windows/
- https://support.enthought.com/hc/en-us/articles/204469260-Building-Python-extensions-with-Canopy
Дайте нам знать о любых трудностях, открыв вопрос или связавшись с нами на Gitter.
Создание среды Python
Теперь, когда у вас есть компилятор C, создайте изолированную среду разработки pandas:
- Установите Anaconda или miniconda
- Убедитесь, что ваш conda обновлён (
conda update conda) - Убедитесь, что вы клонировали репозиторий
-
cdв директорию исходного кода pandas
Теперь мы начнём трёхэтапный процесс:
- Установите зависимости сборки
- Соберите и установите pandas
- Установите необязательные зависимости
# Create and activate the build environment conda env create -f environment.yml conda activate pandas-dev # or with older versions of Anaconda: source activate pandas-dev # Build and install pandas python setup.py build_ext --inplace -j 4 python -m pip install -e .
В этот момент вы должны сможете импортировать pandas из вашей локально собранной версии:
$ python # start an interpreter >>> import pandas >>> print(pandas.__version__) 0.22.0.dev0+29.g4ad6d4d74
Это создаст новую среду и не изменит существующие среды, а также существующую установку Python.
Чтобы просмотреть ваши среды:
conda info -e
Чтобы вернуться к вашей корневой среде:
conda deactivate
Полные документы conda см. здесь.
Создание среды Python (pip)
Если вы не используете conda для своей среды разработки, следуйте этим инструкциям. Вам потребуется как минимум установленная python3.5.
# Create a virtual environment # Use an ENV_DIR of your choice. We'll use ~/virtualenvs/pandas-dev # Any parent directories should already exist python3 -m venv ~/virtualenvs/pandas-dev # Activate the virtualenv . ~/virtualenvs/pandas-dev/bin/activate # Install the build dependencies python -m pip install -r requirements-dev.txt # Build and install pandas python setup.py build_ext --inplace -j 4 python -m pip install -e .
Создание ветки
Вы хотите, чтобы ваша ветка master отражала только готовый к производству код, поэтому создайте ветку feature для внесения изменений. Например:
git branch shiny-new-feature git checkout shiny-new-feature
Вышеуказанное можно упростить до:
git checkout -b shiny-new-feature
Это переведёт вашу рабочую директорию в новую ветку shiny-new-feature. Любые изменения в этой ветке должны быть связаны с одной ошибкой или функцией, чтобы было понятно, что она приносит в pandas. Вы можете иметь множество ветвей shiny-new-features и переключаться между ними с помощью команды git checkout.
При создании этой ветки убедитесь, что ваша ветка master обновлена с последней версией upstream master. Для обновления вашей локальной ветки master вы можете сделать следующее:
git checkout master git pull upstream master --ff-only
Когда вы хотите обновить ветку feature изменениями в master после её создания, ознакомьтесь с разделом обновления PR.
Вклад в документацию
Вклад в документацию полезен всем, кто использует pandas. Мы рекомендуем вам помочь нам улучшить документацию, и вам не нужно быть экспертом в pandas, чтобы это сделать! Фактически, есть разделы документации, которые хуже после написания экспертами. Если что-то в документации не имеет смысла для вас, обновление соответствующего раздела после того, как вы это поймёте, является отличным способом обеспечить, что это поможет следующему человеку.
Документация:
О документации pandas
Документация написана на reStructuredText, что почти как писать на обычном английском языке, и построена с помощью Sphinx. Документация Sphinx содержит отличное введение в reST. Просмотрите документы Sphinx, чтобы выполнить более сложные изменения в документации.
Ещё несколько важных моментов о документации:
-
Документация pandas состоит из двух частей: строки документации в самом коде и документации в этой папке
doc/.Строки документации предоставляют чёткое объяснение использования отдельных функций, в то время как документация в этой папке состоит из обзорных статей по темам вместе с другой информацией (что нового, установка и т. д.).
-
Строки документации следуют конвенции pandas, основанной на руководстве по строкам документации pandas для подробных инструкций о том, как написать правильную строку документации.
-
Учебные материалы активно используют расширение sphinx ipython directive. Эта директива позволяет поместить код в документацию, который будет выполняться во время построения документации. Например:
.. ipython:: python x = 2 x**3будет отображено как:
In [1]: x = 2 In [2]: x**3 Out[2]: 8
Практически все примеры кода в документации выполняются (и выход сохраняется) во время построения документации. Этот подход означает, что примеры кода всегда будут актуальными, но это делает построение документации немного более сложным.
-
Наша документация API в
doc/source/api.rstсодержит автоматически сгенерированную документацию из строк документации. Для классов есть несколько нюансов, связанных с управлением страницами, которые автоматически генерируются для методов и атрибутов.У нас есть два шаблона autosummary для классов.
-
_templates/autosummary/class.rst. Используйте его, когда хотите автоматически сгенерировать страницу для каждого публичного метода и атрибута класса. РазделыAttributesиMethodsбудут автоматически добавлены в сгенерированную документацию класса библиотекой numpydoc. См.DataFrameдля примера. -
_templates/autosummary/class_without_autosummary. Используйте его, когда хотите выбрать подмножество методов/атрибутов для автоматической генерации страниц. При использовании этого шаблона вы должны включить разделыAttributesиMethodsв строке документации класса. См.CategoricalIndexдля примера.
Каждый метод должен быть включён в
toctreeвapi.rst, иначе Sphinx выведет предупреждение. -
Примечание
Файлы .rst используются для автоматической генерации Markdown и HTML версий документации. По этой причине, пожалуйста, не редактируйте CONTRIBUTING.md напрямую, а вместо этого внесите изменения в doc/source/development/contributing.rst. Затем, для генерации CONTRIBUTING.md, используйте pandoc с помощью следующей команды:
pandoc doc/source/development/contributing.rst -t markdown_github > CONTRIBUTING.md
Утилита scripts/validate_docstrings.py может быть использована для получения csv-резюме API-документации. Она также может использоваться для проверки распространённых ошибок в строках документации конкретного класса, функции или метода. Резюме также сравнивает список документированных методов в doc/source/api.rst (который используется для генерации страницы API Reference) и фактических публичных методов. Это позволит идентифицировать методы, документированные в doc/source/api.rst, которые фактически не являются методами класса, и существующие методы, которые не документированы в doc/source/api.rst.
Обновление строки документации pandas
При улучшении строки документации отдельной функции или метода не обязательно строить всю документацию (см. следующий раздел). Однако существует скрипт, который проверяет строку документации (например, для метода DataFrame.mean):
python scripts/validate_docstrings.py pandas.DataFrame.mean
Этот скрипт укажет некоторые ошибки форматирования, если они есть, и также выполнит и проверит примеры, включённые в строку документации. См. руководство по строкам документации pandas для подробного руководства по форматированию строки документации.
Примеры в строке документации («doctests») должны быть валидным кодом Python, который детерминированно возвращает представленный вывод, и который пользователи могут скопировать и запустить. Это можно проверить с помощью вышеуказанного скрипта, а также на Travis. Неудавшийся doctest будет препятствием для слияния PR. Обратитесь к разделу примеры в руководстве по строкам документации за советами и хитростями для успешного прохождения doctests.
При создании PR с обновлением строки документации рекомендуется опубликовать вывод скрипта проверки в комментарии на github.
Как построить документацию pandas
Требования
Сначала вам необходимо создать среду разработки, чтобы иметь возможность скомпилировать pandas (см. документацию по созданию среды разработки выше).
Создание документации
Как создать документацию? Перейдите в вашу локальную папку doc/ в консоли и выполните:
python make.py html
Затем вы найдете HTML-вывод в папке doc/build/html/.
В первый раз создание документации займет довольно много времени, так как необходимо запустить все примеры кода и создать все сгенерированные страницы docstring. В последующих вызовах sphinx будет пытаться скомпилировать только изменённые страницы.
Если вы хотите выполнить полную очистку и перекомпиляцию, выполните:
python make.py clean python make.py html
Вы можете указать make.py скомпилировать только один раздел документации, существенно сократив время проверки ваших изменений.
# omit autosummary and API section python make.py clean python make.py --no-api # compile the docs with only a single section, relative to the "source" folder. # For example, compiling only this guide (docs/source/development/contributing.rst) python make.py clean python make.py --single development/contributing.rst # compile the reference docs for a single function python make.py clean python make.py --single pandas.DataFrame.join
Для сравнения, полная сборка документации может занять 15 минут, а сборка одного раздела — 15 секунд. Последующие сборки, обрабатывающие только изменённые вами части, будут быстрее.
Вы также можете указать использование нескольких ядер для ускорения сборки документации:
python make.py html --num-jobs 4
Откройте следующий файл в веб-браузере, чтобы увидеть только что созданную полную документацию:
doc/build/html/index.html
И вы получите удовлетворение, увидев свою новую и улучшенную документацию!
Создание документации для ветки master
При слиянии запросов на вытягивание в ветку pandas master основные части документации также создаются Travis-CI. Затем эта документация размещается здесь, см. также раздел Непрерывная интеграция.
Вклад в базу кода
База кода:
- Стандарты кода
- Дополнительные зависимости
- Тестирование с непрерывной интеграцией
- Разработка с тестированием/написание кода
- Запуск набора тестов
- Запуск набора тестов производительности
- Документирование кода
Стандарты кода
Написание хорошего кода — это не только то, что вы пишете. Это также касается того, как вы его пишете. Во время тестирования непрерывной интеграции будут запущены несколько инструментов для проверки вашего кода на стилистические ошибки. Любые предупреждения приведут к провалу теста. Таким образом, хороший стиль — это требование для отправки кода в pandas.
В pandas есть инструмент, который поможет участникам проверить свои изменения перед тем, как внести их в проект:
./ci/code_checks.sh
Скрипт проверяет линтеры файлов кода, выявляет распространённые ошибки (например, отсутствие пробелов вокруг директив sphinx, из-за которых документация не отображается должным образом), а также проверяет doctests. Вы можете выполнить проверки независимо, используя параметры lint, patterns и doctests (например, ./ci/code_checks.sh lint).
Кроме того, поскольку много людей используют нашу библиотеку, важно, чтобы мы не вносили внезапных изменений в код, которые могут потенциально сломать код многих пользователей. То есть нам нужно, чтобы он был максимально обратно совместимым, чтобы избежать массовых сбоев.
Дополнительные стандарты приведены на странице wiki со стилем кода https://github.com/pandas-dev/pandas/wiki/Code-Style-and-Conventions.
Дополнительные зависимости
Дополнительные зависимости (например, matplotlib) должны импортироваться с помощью закрытого вспомогательного метода pandas.compat._optional.import_optional_dependency. Это гарантирует согласованное сообщение об ошибке, если зависимость не найдена.
Все методы, использующие дополнительную зависимость, должны включать тест, утверждающий, что возникает ImportError при отсутствии дополнительной зависимости. Этот тест должен быть пропущен, если библиотека присутствует.
Все дополнительные зависимости должны быть документированы в Дополнительных зависимостях, а минимально требуемая версия должна быть установлена в словаре pandas.compat._optional.VERSIONS.
C (cpplint)
pandas использует стандарт Google. Google предоставляет инструмент проверки стиля с открытым исходным кодом, называемый cpplint, но мы используем его форк, который можно найти здесь. Вот некоторые из наиболее распространённых cpplint проблем:
- мы ограничиваем длину строки 80 символами, чтобы повысить читабельность
- каждый заголовочный файл должен включать заголовочную страницу, чтобы избежать конфликтов имён при повторном включении
Непрерывная интеграция будет запускать инструмент cpplint и сообщать обо всех стилистических ошибках в вашем коде. Поэтому перед отправкой кода рекомендуется самостоятельно выполнить проверку:
cpplint --extensions=c,h --headers=h --filter=-readability/casting,-runtime/int,-build/include_subdir modified-c-file
Также можно запустить эту команду для целого каталога, если это необходимо:
cpplint --extensions=c,h --headers=h --filter=-readability/casting,-runtime/int,-build/include_subdir --recursive modified-c-directory
Для соответствия этому стандарту при совершении коммитов можно установить инструмент ClangFormat, который можно скачать здесь. Для настройки, в вашей домашней директории, выполните следующую команду:
clang-format style=google -dump-config > .clang-format
Затем измените файл, чтобы убедиться, что все параметры ширины отступов установлены как минимум в четыре. После настройки можно запустить инструмент следующим образом:
clang-format modified-c-file
Это выведет, как будет выглядеть ваш файл после внесения изменений. Для их применения выполните следующую команду:
clang-format -i modified-c-file
Для запуска инструмента для всего каталога можно запустить аналогичные команды:
clang-format modified-c-directory/*.c modified-c-directory/*.h clang-format -i modified-c-directory/*.c modified-c-directory/*.h
Обратите внимание, что этот инструмент работает с максимальной точностью, то есть он пытается исправить как можно больше ошибок, но не всегда исправит все из них. Поэтому рекомендуется запустить cpplint для двойной проверки и внесения любых других стилистических исправлений вручную.
Python (PEP8 / black)
pandas следует стандарту PEP8 и использует Black и Flake8 для обеспечения согласованного форматирования кода во всём проекте.
Непрерывная интеграция запустит эти инструменты и сообщит о любых стилистических ошибках в вашем коде. Поэтому перед отправкой кода рекомендуется самостоятельно выполнить проверку:
black pandas git diff upstream/master -u -- "*.py" | flake8 --diff
для автоматического форматирования кода. Кроме того, многие редакторы имеют плагины, которые применяют black по мере редактирования файлов.
Необязательно настроить hooks pre-commit для автоматического запуска black и flake8 при совершении git коммита. Это можно сделать, установив pre-commit:
pip install pre-commit
и затем выполнив:
pre-commit install
из корня репозитория pandas. Теперь black и flake8 будут запускаться каждый раз при коммите изменений. Вы можете пропустить эти проверки с помощью git commit --no-verify.
Эта команда позволит поймать любые стилистические ошибки в ваших изменениях, но будьте внимательны, она может не поймать все. Например, если вы удалите единственное использование импортированной функции, стилистически неверно импортировать неиспользуемую функцию. Однако, проверка стиля по diff не обнаружит этого, потому что сам импорт не является частью diff. Поэтому для полноты картины следует запустить эту команду, хотя она займет больше времени:
git diff upstream/master --name-only -- "*.py" | xargs -r flake8
Обратите внимание, что в OSX флаг -r недоступен, поэтому вы должны опустить его и запустить эту немного изменённую команду:
git diff upstream/master --name-only -- "*.py" | xargs flake8
Windows не поддерживает команду xargs (если не установлена, например, через инструмент MinGW), но можно имитировать поведение следующим образом:
for /f %i in ('git diff upstream/master --name-only -- "*.py"') do flake8 %i
Это получит все файлы, которые меняются в PR (и заканчиваются на .py), и запустит flake8 на них по одному.
Форматирование импорта
pandas использует isort для стандартизации форматирования импорта во всём коде.
Руководство по расположению импорта в соответствии с pep8 можно найти здесь.
Обзор наших текущих разделов импорта (в порядке):
- Future
- Библиотека стандартной Python
- Библиотеки сторонних производителей
-
pandas._libs,pandas.compat,pandas.util._*,pandas.errors(в основном не зависят отpandas.core) -
pandas.core.dtypes(в основном не зависит от остальной частиpandas.core) - Остальная часть
pandas.core.* - Импорты, не относящиеся к ядру
pandas.io,pandas.plotting,pandas.tseries - Импорты, специфичные для локального приложения/библиотеки
Импорты сортируются лексикографически в пределах этих разделов.
В рамках проверок непрерывной интеграции мы выполняем:
isort --recursive --check-only pandas
для проверки правильности форматирования импортов в соответствии с setup.cfg.
Если в результатах проверок непрерывной интеграции вы увидите вывод, подобный следующему:
Check import format using isort ERROR: /home/travis/build/pandas-dev/pandas/pandas/io/pytables.py Imports are incorrectly sorted Check import format using isort DONE The command "ci/code_checks.sh" exited with 1
Вы должны запустить:
isort pandas/io/pytables.py
чтобы автоматически отформатировать импорты правильно. Это изменит локальную копию файлов.
Флаг –recursive можно передать для сортировки всех файлов в каталоге.
Затем вы можете проверить, что изменения выглядят хорошо, а затем выполнить git commit и push.
Обратная совместимость
Пожалуйста, старайтесь поддерживать обратную совместимость. У pandas много пользователей с большим количеством существующего кода, поэтому не ломайте его, если это вообще возможно. Если вы считаете, что разрыв совместимости необходим, четко укажите причину в запросе на вытягивание. Также будьте внимательны при изменении сигнатур методов и добавляйте предупреждения о устаревании, где это необходимо. Также добавьте устаревшее директиву sphinx к устаревшим функциям или методам.
Если функция с теми же аргументами, что и устаревшая, существует, вы можете использовать pandas.util._decorators.deprecate:
from pandas.util._decorators import deprecate
deprecate('old_func', 'new_func', '0.21.0')
В противном случае, вам нужно сделать это вручную:
import warnings
def old_func():
"""Summary of the function.
.. deprecated:: 0.21.0
Use new_func instead.
"""
warnings.warn('Use new_func instead.', FutureWarning, stacklevel=2)
new_func()
def new_func():
pass
Вам также потребуется
- Написать новый тест, который утверждает, что при вызове с устаревшим аргументом выдается предупреждение
- Обновить все существующие тесты и код pandas для использования нового аргумента
См. Тестирование предупреждений для получения дополнительной информации.
Тестирование с непрерывной интеграцией
Набор тестов pandas будет автоматически выполняться на Travis-CI и Azure Pipelines сервисах непрерывной интеграции после отправки вашего запроса на вытягивание. Однако, если вы хотите запустить набор тестов на ветке до отправки запроса на вытягивание, то сервисы непрерывной интеграции должны быть подключены к вашему репозиторию GitHub. Инструкции для Travis-CI и Azure Pipelines находятся здесь.
Запрос на вытягивание будет рассмотрен для слияния, когда у вас будет «зелёный» сборка. Если какие-либо тесты не проходят, вы увидите красный «X», где вы можете перейти, чтобы увидеть отдельные не пройденные тесты. Это пример зелёной сборки.
Примечание
Каждый раз, когда вы отправляете изменения на свой форк, на CI запускается новый набор тестов. Вы можете включить функцию автоматической отмены, которая удаляет любые тесты, которые в данный момент не выполняются для того же запроса на вытягивание, для Travis-CI здесь.
Разработка тестами/написание кода
pandas серьезно относится к тестированию и настоятельно рекомендует участникам использовать разработку тестами (TDD). Этот процесс разработки «основан на повторении очень короткого цикла разработки: сначала разработчик пишет автоматический тестовый случай (первоначально не проходящий), определяющий желаемое улучшение или новую функцию, затем создаёт минимальное количество кода, чтобы пройти этот тест». Таким образом, перед фактическим написанием кода вы должны написать тесты. Часто тест можно взять из исходного вопроса на GitHub. Однако всегда стоит рассмотреть дополнительные варианты использования и написать соответствующие тесты.
Добавление тестов является одним из наиболее распространённых запросов после отправки кода в pandas. Поэтому стоит приучиться писать тесты заранее, чтобы этого никогда не было проблемой.
Как и многие пакеты, pandas использует pytest и удобные расширения в numpy.testing.
Примечание
Самая ранняя поддерживаемая версия pytest — 4.0.2.
Написание тестов
Все тесты должны находиться в подкаталоге tests соответствующего пакета. Эта папка содержит много текущих примеров тестов, и мы рекомендуем обращать на них внимание для вдохновения. Если ваш тест требует работы с файлами или сетевым подключением, дополнительная информация находится на странице тестирования вики.
Модуль pandas.util.testing имеет много специальных assert функций, которые упрощают создание утверждений о том, являются ли объекты Series или DataFrame эквивалентными. Самый простой способ проверить правильность вашего кода — явно создать ожидаемый результат, а затем сравнить фактический результат с ожидаемым правильным результатом:
def test_pivot(self):
data = {
'index' : ['A', 'B', 'C', 'C', 'B', 'A'],
'columns' : ['One', 'One', 'One', 'Two', 'Two', 'Two'],
'values' : [1., 2., 3., 3., 2., 1.]
}
frame = DataFrame(data)
pivoted = frame.pivot(index='index', columns='columns', values='values')
expected = DataFrame({
'One' : {'A' : 1., 'B' : 2., 'C' : 3.},
'Two' : {'A' : 1., 'B' : 2., 'C' : 3.}
})
assert_frame_equal(pivoted, expected)
Переход к pytest
Существующая структура тестов pandas в основном основана на классах, что означает, что вы обычно найдёте тесты, заключенные в класс.
class TestReallyCoolFeature:
pass
В дальнейшем мы переходим к более функциональному стилю, используя фреймворк pytest, который предлагает более богатый фреймворк для тестирования, что позволит упростить тестирование и разработку. Таким образом, вместо написания тестовых классов мы будем писать тестовые функции, например, так:
def test_really_cool_feature():
pass
Использование pytest
Вот пример самодостаточного набора тестов, иллюстрирующего множество функций, которые мы хотели бы использовать.
- функциональный стиль: тесты похожи на
test_*и только принимают аргументы, которые являются фикстурами или параметрами -
pytest.markможно использовать для задания метаданных на тестовые функции, например,skipилиxfail. - использование
parametrize: позволяет тестировать несколько случаев - для задания метки на параметре следует использовать синтаксис
pytest.param(..., marks=...) -
fixture, код для создания объекта на основе теста - использование простых
assertдля скаляров и проверки истинности -
tm.assert_series_equal(и его аналогtm.assert_frame_equal) для сравнения объектов pandas. - типичный шаблон построения
expectedи сравнения сresult
Мы назовём этот файл test_cool_feature.py и поместим его в соответствующее место в структуре pandas/tests/.
import pytest
import numpy as np
import pandas as pd
@pytest.mark.parametrize('dtype', ['int8', 'int16', 'int32', 'int64'])
def test_dtypes(dtype):
assert str(np.dtype(dtype)) == dtype
@pytest.mark.parametrize(
'dtype', ['float32', pytest.param('int16', marks=pytest.mark.skip),
pytest.param('int32', marks=pytest.mark.xfail(
reason='to show how it works'))])
def test_mark(dtype):
assert str(np.dtype(dtype)) == 'float32'
@pytest.fixture
def series():
return pd.Series([1, 2, 3])
@pytest.fixture(params=['int8', 'int16', 'int32', 'int64'])
def dtype(request):
return request.param
def test_series(series, dtype):
result = series.astype(dtype)
assert result.dtype == dtype
expected = pd.Series([1, 2, 3], dtype=dtype)
tm.assert_series_equal(result, expected)
Запуск этого теста даёт
((pandas) bash-3.2$ pytest test_cool_feature.py -v =========================== test session starts =========================== platform darwin -- Python 3.6.2, pytest-3.6.0, py-1.4.31, pluggy-0.4.0 collected 11 items tester.py::test_dtypes[int8] PASSED tester.py::test_dtypes[int16] PASSED tester.py::test_dtypes[int32] PASSED tester.py::test_dtypes[int64] PASSED tester.py::test_mark[float32] PASSED tester.py::test_mark[int16] SKIPPED tester.py::test_mark[int32] xfail tester.py::test_series[int8] PASSED tester.py::test_series[int16] PASSED tester.py::test_series[int32] PASSED tester.py::test_series[int64] PASSED
Тесты, которые у нас parametrized теперь доступны по имени теста, например, мы можем запустить их с помощью -k int8 для выбора только тех тестов, которые соответствуют int8.
((pandas) bash-3.2$ pytest test_cool_feature.py -v -k int8 =========================== test session starts =========================== platform darwin -- Python 3.6.2, pytest-3.6.0, py-1.4.31, pluggy-0.4.0 collected 11 items test_cool_feature.py::test_dtypes[int8] PASSED test_cool_feature.py::test_series[int8] PASSED
Использование hypothesis
Hypothesis — это библиотека для свойство-ориентированного тестирования. Вместо явного параметрирования теста вы можете описать все допустимые входные данные и позволить Hypothesis найти не проходящий тест. Ещё лучше, вне зависимости от того, сколько случайных примеров он попробует, Hypothesis всегда сообщает об одном минимальном контрпримере для ваших утверждений — часто это пример, о котором вы никогда не подумали бы, чтобы его протестировать.
См. Начало работы с Hypothesis для получения более подробного введения, а затем обратитесь к документации Hypothesis для получения подробной информации.
import json
from hypothesis import given, strategies as st
any_json_value = st.deferred(lambda: st.one_of(
st.none(), st.booleans(), st.floats(allow_nan=False), st.text(),
st.lists(any_json_value), st.dictionaries(st.text(), any_json_value)
))
@given(value=any_json_value)
def test_json_roundtrip(value):
result = json.loads(json.dumps(value))
assert value == result
Этот тест демонстрирует несколько полезных функций Hypothesis, а также демонстрирует хороший случай использования: проверка свойств, которые должны выполняться на большом или сложном наборе входных данных.
Чтобы набор тестов Pandas продолжал работать быстро, предпочтительно использовать параметризованные тесты, если входные данные или логика простые, а тесты с помощью Hypothesis — для случаев со сложной логикой или когда существует слишком много комбинаций вариантов или тонких взаимодействий, чтобы протестировать (или подумать об этом!).
Тестирование предупреждений
По умолчанию один из рабочих процессов CI pandas завершится неудачей, если будут выпущены какие-либо необработанные предупреждения.
Если ваше изменение включает в себя проверку того, что предупреждение действительно выводится, используйте tm.assert_produces_warning(ExpectedWarning).
import pandas.util.testing as tm
df = pd.DataFrame()
with tm.assert_produces_warning(FutureWarning):
df.some_operation()
Мы предпочитаем это менеджеру контекста pytest.warns, потому что наш проверяет, что уровень стека предупреждения установлен правильно. Уровень стека гарантирует, что имя и номер строки файла пользователя будут напечатаны в предупреждении, а не что-то внутреннее для pandas. Он представляет собой количество вызовов функций от кода пользователя (например, df.some_operation()) до функции, которая фактически выводит предупреждение. Наш линтер завершит сборку с ошибкой, если вы используете pytest.warns в тесте.
Если у вас есть тест, который выведет предупреждение, но вы не тестируете само предупреждение (скажем, потому что оно будет удалено в будущем или потому, что мы соответствуют поведению библиотеки стороннего разработчика), то используйте pytest.mark.filterwarnings для игнорирования ошибки.
@pytest.mark.filterwarnings("ignore:msg:category")
def test_thing(self):
...
Если тест генерирует предупреждение класса category, сообщение которого начинается с msg, предупреждение будет проигнорировано, и тест пройдёт.
Если вам нужен более тонкий контроль, вы можете использовать стандартный модуль предупреждений Python warnings для управления тем, игнорируется ли предупреждение/выдаётся ли оно в разных местах в рамках одного теста.
with warnings.catch_warnings():
warnings.simplefilter("ignore", FutureWarning)
# Or use warnings.filterwarnings(...)
В качестве альтернативы, рассмотрите возможность разделения модульного теста.
Запуск набора тестов
Тесты можно запустить непосредственно в вашей копии Git (без необходимости установки pandas), набрав:
pytest pandas
Набор тестов исчерпывающий и занимает около 20 минут для выполнения. Зачастую стоит сначала запустить только подмножество тестов, касающихся ваших изменений, прежде чем запускать весь набор.
Самый простой способ сделать это:
pytest pandas/path/to/test.py -k regex_matching_test_name
Или с помощью одного из следующих конструкций:
pytest pandas/tests/[test-module].py pytest pandas/tests/[test-module].py::[TestClass] pytest pandas/tests/[test-module].py::[TestClass]::[test_method]
С помощью pytest-xdist можно ускорить локальное тестирование на многоядерных машинах. Чтобы использовать эту функцию, вам нужно установить pytest-xdist следующим образом:
pip install pytest-xdist
Для помощи в этом предоставлены два скрипта. Эти скрипты распределяют тестирование по 4 потокам.
В Unix-подобных системах вы можете набрать:
test_fast.sh
В Windows можно набрать:
test_fast.bat
Это значительно сократит время локального выполнения тестов перед отправкой pull request.
Для более подробной информации см. документацию pytest.
Новое в версии 0.20.0.
Кроме того, можно запустить
pd.test()
с импортированным pandas для аналогичного выполнения тестов.
Запуск набора тестов производительности
Производительность важна, и стоит рассмотреть, не ввела ли ваша код регрессии производительности. pandas в процессе миграции к benchmarks asv для обеспечения простого мониторинга производительности критически важных операций pandas. Эти бенчмарки находятся в каталоге pandas/asv_bench. asv поддерживает как Python 2, так и Python 3.
Для использования всех функций asv, вам понадобится либо conda, либо virtualenv. Для получения более подробной информации, пожалуйста, ознакомьтесь со страницей установки asv.
Для установки asv:
pip install git+https://github.com/spacetelescope/asv
Если вам нужно запустить бенчмарк, измените директорию на asv_bench/ и запустите:
asv continuous -f 1.1 upstream/master HEAD
Вы можете заменить HEAD на имя ветки, над которой вы работаете, и отчитаться о бенчмарках, которые изменились более чем на 10%. Команда по умолчанию использует conda для создания окружений бенчмарков. Если вы хотите использовать virtualenv вместо этого, напишите:
asv continuous -f 1.1 -E virtualenv upstream/master HEAD
Опция -E virtualenv должна быть добавлена ко всем командам asv, которые запускают бенчмарки. Значение по умолчанию определяется в asv.conf.json.
Запуск полного набора тестов может занять до одного часа и использовать до 3 ГБ оперативной памяти. Обычно достаточно вставить только подмножество результатов в pull request, чтобы показать, что внесенные изменения не вызывают неожиданных регрессий производительности. Вы можете запустить определенные бенчмарки, используя флаг -b, который принимает регулярное выражение. Например, это запустит только тесты из файла pandas/asv_bench/benchmarks/groupby.py:
asv continuous -f 1.1 upstream/master HEAD -b ^groupby
Если вы хотите запустить только определенную группу тестов из файла, вы можете сделать это, используя . в качестве разделителя. Например:
asv continuous -f 1.1 upstream/master HEAD -b groupby.GroupByMethods
будет запущен только бенчмарк GroupByMethods, определенный в groupby.py.
Вы также можете запустить набор бенчмарков, используя версию pandas, уже установленную в вашей текущей среде Python. Это может быть полезно, если у вас нет virtualenv или conda, или вы используете подход setup.py develop обсуждавшийся выше; для встроенной сборки необходимо установить PYTHONPATH, например, PYTHONPATH="$PWD/.." asv [remaining arguments]. Вы можете запустить бенчмарки, используя существующую среду Python, выполнив:
asv run -e -E existing
или, чтобы использовать конкретный интерпретатор Python:
asv run -e -E existing:python3.5
Это отобразит вывод stderr из бенчмарков и воспользуется вашим локальным python, который берется из вашей $PATH.
Дополнительную информацию о написании бенчмарков и использовании asv можно найти в документации asv.
Документирование кода
Изменения должны отражаться в примечаниях к выпуску, расположенных в doc/source/whatsnew/vx.y.z.rst. Этот файл содержит непрерывный журнал изменений для каждого выпуска. Добавьте запись в этот файл, чтобы задокументировать ваш исправление, улучшение или (неизбежное) нарушение совместимости. Убедитесь, что вы включили номер проблемы GitHub при добавлении вашей записи (используя :issue:`1234`, где 1234 — номер проблемы/pull request).
Если ваш код представляет собой улучшение, скорее всего, необходимо добавить примеры использования в существующую документацию. Это можно сделать, следуя разделу о документировании, приведенному выше. Кроме того, чтобы пользователи знали, когда эта функция была добавлена, используется директива versionadded. Синтаксис Sphinx для этого:
.. versionadded:: 0.21.0
Это поместит текст Новое в версии 0.21.0, где вы поместите директиву Sphinx. Это также должно быть включено в строку документации при добавлении новой функции или метода (пример) или нового ключевого аргумента (пример).
Вклад ваших изменений в pandas
Создание коммита кода
Сохраняйте исправления стиля в отдельном коммите, чтобы сделать ваш pull request более читабельным.
После внесения изменений вы можете увидеть их, набрав:
git status
Если вы создали новый файл, он не отслеживается git. Добавьте его, набрав:
git add path/to/file-to-be-added.py
Повторный ввод ‘git status’ должен вывести что-то вроде:
# On branch shiny-new-feature # # modified: /relative/path/to/file-you-added.py #
Наконец, сохраните изменения в вашем локальном репозитории с пояснением. Pandas использует соглашение для префиксов сообщений о коммитах и структуры. Вот некоторые распространённые префиксы и общие рекомендации по их использованию:
- ENH: Улучшение, новая функциональность
- BUG: Исправление ошибки
- DOC: Дополнения/обновления документации
- TST: Дополнения/обновления тестов
- BLD: Обновления процесса/скриптов сборки
- PERF: Улучшение производительности
- CLN: Очистка кода
Следующее определяет структуру сообщения о коммите. Ссылайтесь на соответствующие проблемы GitHub в вашем сообщении о коммите с помощью GH1234 или #1234. Любой стиль подходит, но предпочтительнее первый:
- строка заголовка с
< 80символами. - Одна пустая строка.
- Необязательно, тело сообщения о коммите.
Теперь вы можете сохранить изменения в вашем локальном репозитории:
git commit -m
Отправка ваших изменений
Когда вы хотите, чтобы ваши изменения появились публично на вашей странице GitHub, отправьте коммиты вашей вилки ветки с функцией:
git push origin shiny-new-feature
Здесь origin — имя вашего удаленного репозитория на GitHub по умолчанию. Вы можете увидеть удаленные репозитории:
git remote -v
Если вы добавили репозиторий upstream как описано выше, вы увидите что-то вроде:
origin git@github.com:yourname/pandas.git (fetch) origin git@github.com:yourname/pandas.git (push) upstream git://github.com/pandas-dev/pandas.git (fetch) upstream git://github.com/pandas-dev/pandas.git (push)
Теперь ваш код находится на GitHub, но он ещё не является частью проекта pandas. Для этого необходимо отправить pull request на GitHub.
Проверка вашего кода
Когда вы готовы запросить код-ревью, создайте pull request. Прежде чем это сделать, ещё раз убедитесь, что вы соблюдаете все указанные в этом документе рекомендации по стилю кода, тестам, тестам производительности и документации. Вы также должны дважды проверить изменения в вашей ветке по отношению к ветке, на основе которой она была создана:
- Перейдите в свой репозиторий на GitHub — https://github.com/your-user-name/pandas
- Нажмите на
Branches - Нажмите кнопку
Compareдля вашей ветки с функцией - Выберите ветки
baseиcompare, если необходимо. Это будетmasterиshiny-new-feature, соответственно.
Наконец, отправьте pull request
Если все выглядит хорошо, вы готовы отправить pull request. Pull request — это способ, с помощью которого код из локального репозитория становится доступен сообществу GitHub и может быть рассмотрен, а в конечном счете, интегрирован в главную версию. Этот pull request и связанные с ним изменения в конечном итоге будут добавлены в ветку master и станут доступными в следующем выпуске. Чтобы отправить pull request:
- Перейдите в свой репозиторий на GitHub
- Нажмите кнопку
Pull Request - Вы можете нажать
CommitsиFiles Changedчтобы ещё раз убедиться в том, что всё в порядке - Напишите описание ваших изменений во вкладке
Preview Discussion - Нажмите
Send Pull Request.
Этот запрос затем передаётся администраторам репозитория, и они проверят код.
Обновление вашего pull request
В зависимости от полученного вами обзора pull request, вам, вероятно, потребуется внести некоторые изменения в код. В этом случае вы можете внести их в свою ветку, добавить к ней новый коммит, отправить его на GitHub, и pull request будет автоматически обновлён. Отправка изменений на GitHub выполняется следующим образом:
git push origin shiny-new-feature
Это автоматически обновит ваш pull request с последним кодом и перезапустит тесты непрерывной интеграции.
Другая причина, по которой вам может потребоваться обновить pull request, заключается в решении конфликтов с изменениями, которые были объединены в главную ветку с момента открытия pull request.
Для этого вам необходимо «объединить upstream master» в вашей ветке:
git checkout shiny-new-feature git fetch upstream git merge upstream/master
Если конфликтов нет (или они могут быть автоматически исправлены), откроется файл с сообщением о коммите по умолчанию, и вы можете просто сохранить и выйти из этого файла.
Если конфликты есть, вам необходимо их разрешить. Например, объяснение того, как это сделать, можно найти по адресу https://help.github.com/articles/resolving-a-merge-conflict-using-the-command-line/. После слияния конфликтов и добавления файлов, где конфликты были решены, вы можете запустить git commit для сохранения этих исправлений.
Если у вас есть несохранённые изменения в момент, когда вы хотите обновить ветку с помощью master, вам необходимо stash их до обновления (см. документацию по stash). Это фактически сохранит ваши изменения, и их можно будет применить после обновления.
После того, как ветка функции была обновлена локально, вы теперь можете обновить свой pull request, отправив его в ветку на GitHub:
git push origin shiny-new-feature
Удаление объединённой ветки (необязательно)
После того, как ваша ветка функции будет принята в upstream, вы, вероятно, захотите избавиться от неё. Сначала объедините upstream master в свою ветку, чтобы git знал, что удаление вашей ветки безопасно:
git fetch upstream git checkout master git merge upstream/master
Затем вы можете сделать:
git branch -d shiny-new-feature
Убедитесь, что вы используете строчную -d, иначе git не предупредит вас, если ваша ветка с функцией фактически не была объединена.
Ветка по-прежнему будет существовать на GitHub, поэтому, чтобы удалить её там, выполните:
git push origin --delete shiny-new-feature
© 2008–2012, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team
Licensed under the 3-clause BSD License.
https://pandas.pydata.org/pandas-docs/version/0.25.0/development/contributing.html