Spec-Zone.ru › pandas 0.24

Содействие в разработке pandas

Содержание:

  • С чего начать?
  • Отчеты об ошибках и запросы на улучшение
  • Работа с кодом
    • Система контроля версий, Git и GitHub
    • Начало работы с Git
    • Разветвление проекта
    • Создание среды разработки
      • Установка компилятора C
      • Создание среды Python
      • Создание среды Python (pip)
    • Создание ветки
  • Содействие в разработке документации
    • О документации pandas
    • Обновление строки документации pandas
    • Как собрать документацию pandas
      • Требования
      • Сборка документации
      • Сборка документации ветки master
  • Вклад в базу кода
    • Стандарты кода
      • C (cpplint)
      • Python (PEP8)
      • Форматирование импорта
      • Обратная совместимость
    • Тестирование с непрерывной интеграцией
    • Разработка через тестирование/написание кода
      • Написание тестов
      • Переход к pytest
      • Использование pytest
      • Использование hypothesis
      • Тестирование предупреждений
    • Запуск набора тестов
    • Запуск набора тестов производительности
    • Документирование вашего кода
  • Внесение ваших изменений в pandas
    • Сохранение вашего кода
    • Отправка ваших изменений
    • Проверка вашего кода
    • Наконец, отправьте запрос на включение изменений
    • Обновление вашего запроса на включение изменений
    • Удаление объединенной ветки (необязательно)

С чего начать?

Все вклады, отчеты об ошибках, исправления ошибок, улучшения документации, улучшения и идеи приветствуются.

Если вы новичок в pandas или в разработке с открытым исходным кодом, рекомендуем посетить вкладку «Вопросы» GitHub, чтобы найти интересующие вас вопросы. Есть ряд вопросов, помеченных как Документация и хорошие вопросы для начала, где вы сможете начать. После того, как вы найдете интересный вопрос, вы можете вернуться сюда, чтобы настроить свою среду разработки.

Свободно задавайте вопросы на списке рассылки или на Gitter.

Отчеты об ошибках и запросы на улучшение

Отчеты об ошибках являются важной частью повышения стабильности pandas. Полный отчет об ошибке позволит другим воспроизвести ошибку и внести вклад в ее исправление. См. эту статью Stack Overflow и эту статью блога для советов по написанию хорошего отчета об ошибке.

Проверка кода, вызывающего ошибку, на ветке master часто является полезным упражнением для подтверждения того, что ошибка по-прежнему существует. Также стоит поискать существующие отчеты об ошибках и запросы на включение изменений, чтобы узнать, не была ли проблема уже сообщена и/или исправлена.

Отчеты об ошибках должны:

  1. Включать короткий, автономный фрагмент Python-кода, воспроизводящий проблему. Вы можете красиво отформатировать код, используя GitHub Flavored Markdown:

    ```python
    >>> from pandas import DataFrame
    >>> df = DataFrame(...)
    ...
    ```
    
  2. Включать полную версию pandas и его зависимостей. Вы можете использовать встроенную функцию:

    >>> import pandas as pd
    >>> pd.show_versions()
    
  3. Объясните, почему текущее поведение неправильное/нежелательное и что вы ожидаете вместо этого.

Затем проблема будет представлена сообществу pandas и будет открыта для комментариев/предложений от других.

Работа с кодом

Теперь, когда у вас есть проблема, которую нужно исправить, улучшение, которое нужно добавить, или документация, которую нужно улучшить, вам нужно узнать, как работать с GitHub и базой кода pandas.

Система контроля версий, Git и GitHub

Для новых пользователей работа с Git является одной из самых сложных задач при внесении вклада в pandas. Она может очень быстро стать непосильной, но придерживание приведенных ниже рекомендаций поможет сделать процесс простым и практически без проблем. Как всегда, если у вас возникнут трудности, не стесняйтесь попросить помощи.

Код размещен на GitHub. Для участия вам потребуется зарегистрироваться на бесплатном аккаунте GitHub. Мы используем Git для контроля версий, чтобы позволить многим людям работать вместе над проектом.

Некоторые отличные ресурсы для изучения Git:

  • страницы помощи GitHub.
  • документация NumPy.
  • Pydagogue Мэттью Бретта.

Начало работы с 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 по настройке для установки компилятора. Вам не нужно выполнять ни один из шагов ./configure или make; вам нужно только установить компилятор.

Для разработчиков Windows, при использовании Python 3.5 и более поздних версий, достаточно установить Visual Studio 2017 с рабочим набором Python Development и опцией Python Native Development Tools. В противном случае полезными могут оказаться следующие ссылки.

  • 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

Теперь мы начнем трехэтапный процесс:

  1. Установить зависимости сборки
  2. Собрать и установить pandas
  3. Установить дополнительные зависимости
# 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 virtulaenv
. ~/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 .

Создание ветки

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

git branch shiny-new-feature
git checkout shiny-new-feature

Вышесказанное можно упростить до:

git checkout -b shiny-new-feature

Это изменяет ваш рабочий каталог на новую ветвь shiny-new-feature. Все изменения в этой ветви должны быть специфичны для одного баг-решения или функции, чтобы было понятно, что эта ветвь вносит в pandas. У вас может быть много таких ветвей shiny-new-feature, и вы можете переключаться между ними с помощью команды git checkout.

При создании этой ветви убедитесь, что ваша ветвь master обновлена с последней версией upstream master. Чтобы обновить локальную ветвь master, вы можете сделать следующее:

git checkout master
git pull upstream master --ff-only

Когда вы захотите обновить ветвь feature изменениями из master после её создания, проверьте раздел по обновлению запроса на добавление.

Содействие развитию документации

Содействие развитию документации полезно для всех, кто использует pandas. Мы рекомендуем вам помочь нам улучшить документацию, и вам не нужно быть экспертом в pandas, чтобы сделать это! На самом деле, есть разделы документации, которые становятся хуже после того, как их написали эксперты. Если что-то в документации вам не понятно, обновить соответствующий раздел после того, как вы это выяснили, — отличный способ убедиться, что это поможет следующему человеку.

Документация:

  • О документации pandas
  • Обновление строки документации pandas
  • Как создать документацию pandas
    • Требования
    • Создание документации
    • Создание документации для ветви master

О документации pandas

Документация написана на языке reStructuredText, который почти как обычный английский язык, и построена с помощью Sphinx. Документация Sphinx имеет отличное введение в reST. Ознакомьтесь с документацией Sphinx, чтобы выполнять более сложные изменения в документации.

Некоторые другие важные моменты о документации:

  • Документация pandas состоит из двух частей: строки документации в самом коде и документация в этом каталоге pandas/doc/.

    Строки документации предоставляют чёткое объяснение использования отдельных функций, в то время как документация в этом каталоге представляет собой обзор по темам в виде учебных пособий, наряду с другой информацией (новое, установка и т. д).

  • Строки документации следуют соглашению pandas, основанному на стандарте документации Numpy. Следуйте руководству по строкам документации 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 для классов.

    1. _templates/autosummary/class.rst. Используйте этот шаблон, если хотите автоматически сгенерировать страницу для каждого публичного метода и атрибута класса. Разделы Attributes и Methods будут автоматически добавлены в сгенерированную документацию класса с помощью numpydoc. См. DataFrame в качестве примера.
    2. _templates/autosummary/class_without_autosummary. Используйте этот шаблон, если вы хотите выбрать подмножество методов/атрибутов для автоматической генерации страниц. Используя этот шаблон, вы должны включить раздел Attributes и Methods в строку документации класса. См. CategoricalIndex в качестве примера.

    Каждый метод должен быть включён в toctree в api.rst, иначе Sphinx выдаст предупреждение.

Примечание

Файлы .rst используются для автоматической генерации версий Markdown и HTML документации. По этой причине, пожалуйста, не редактируйте CONTRIBUTING.md напрямую, а вносите изменения в doc/source/contributing.rst. Затем, чтобы сгенерировать CONTRIBUTING.md, используйте pandoc со следующей командой:

pandoc doc/source/contributing.rst -t markdown_github > CONTRIBUTING.md

Утилита скрипта scripts/validate_docstrings.py может быть использована для получения сводки CSV документации API. А также для проверки распространённых ошибок в строке документации конкретного класса, функции или метода. Сводка также сравнивает список документированных методов в doc/source/api.rst (который используется для генерации страницы «Справочник API») и фактических публичных методов. Это позволит выявить методы, документированные в 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. См. раздел примеры в руководстве по строкам документации для получения советов и хитростей по прохождению doctest.

При создании PR с обновлением строки документации полезно разместить вывод скрипта проверки в комментарии на GitHub.

Как создать документацию pandas

Требования

Сначала вам нужна среда разработки, чтобы создать pandas (см. документы по созданию среды разработки выше).

Создание документации

Итак, как создать документацию? Перейдите в каталоге pandas/doc/ в консоли и выполните:

python make.py html

Затем вы можете найти HTML-вывод в папке pandas/doc/build/html/.

При первом создании документации это займёт довольно много времени, так как необходимо запустить все примеры кода и создать все сгенерированные страницы документации. При последующих вызовах 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, that which is in indexing.rst
python make.py clean
python make.py --single indexing

# compile the reference docs for a single function
python make.py clean
python make.py --single DataFrame.join

Для сравнения, полное создание документации может занять 15 минут, а создание одного раздела — 15 секунд. Последующие сборки, которые обрабатывают только изменённые вами части, будут выполняться быстрее.

Вы также можете указать использование нескольких ядер для ускорения создания документации:

python make.py html --num-jobs 4

Откройте указанный файл в веб-браузере, чтобы просмотреть всю только что созданную документацию:

pandas/docs/build/html/index.html

И вы получите удовлетворение от просмотра вашей новой и улучшенной документации!

Создание документации для ветки master

При слиянии запросов на вытягивание в ветку pandas master основные части документации также генерируются Travis-CI. Эта документация затем размещается здесь, также см. раздел Непрерывная интеграция.

Вклад в код

Код:

  • Стандарты кода
    • C (cpplint)
    • Python (PEP8)
    • Форматирование импортов
    • Обратная совместимость
  • Тестирование с непрерывной интеграцией
  • Разработка, ориентированная на тесты/написание кода
    • Написание тестов
    • Переход к pytest
    • Использование pytest
    • Использование hypothesis
    • Тестирование предупреждений
  • Запуск набора тестов
  • Запуск набора тестов производительности
  • Документирование кода

Стандарты кода

Написание хорошего кода — это не только то, что вы пишете. Это также и то, *как* вы это делаете. При тестировании с непрерывной интеграцией будут запущены несколько инструментов для проверки вашего кода на стилистические ошибки. Выдача любых предупреждений приведёт к провалу теста. Таким образом, хороший стиль — это требование для отправки кода в pandas.

В pandas есть инструмент, который помогает участникам проекта проверить свои изменения, прежде чем внести их:

./ci/code_checks.sh

Скрипт проверяет соответствие файлов кода стилистическим правилам, ищет распространённые ошибки (например, отсутствие пробелов вокруг директивы Sphinx, из-за которых документация не отображается должным образом) и также проверяет doctests. Проверки можно выполнить независимо, используя параметры lint, patterns и doctests (например, ./ci/code_checks.sh lint).

Кроме того, поскольку наше библиотеку используют многие люди, важно, чтобы мы не внесли внезапных изменений в код, которые могли бы привести к разрыву кода пользователей, то есть мы должны добиваться максимальной *обратной совместимости*, чтобы избежать массовых сбоев.

Дополнительные стандарты описаны на странице вики-справочника по стилю кода здесь.

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)

pandas использует стандарт PEP8. Есть несколько инструментов, которые помогут вам соблюдать этот стандарт. Вот *некоторые* из наиболее распространённых PEP8 проблем:

  • длина строки ограничена 79 символами для улучшения читаемости
  • при передаче аргументов должно быть пробел после запятых, например foo(arg1, arg2, kw1='bar')

Непрерывная интеграция запустит инструмент flake8 и сообщит об ошибках стиля в вашем коде. Поэтому перед отправкой кода полезно выполнить проверку на различиях:

git diff upstream/master -u -- "*.py" | flake8 --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 коммит и загрузку.

Обратная совместимость

Пожалуйста, старайтесь поддерживать обратную совместимость. У 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

Вам также нужно

  1. написать новый тест, который утверждает, что при вызове с устаревшим аргументом будет выдано предупреждение
  2. обновить все существующие тесты и код pandas, чтобы использовать новый аргумент

См. Тестирование предупреждений для получения дополнительной информации.

END_OF_DOCUMENT_MARKER

Тестирование с непрерывной интеграцией

Набор тестов pandas будет запускаться автоматически на сервисах непрерывной интеграции Travis-CI и Azure Pipelines, после того как вы отправите свой запрос на добавление изменений. Однако, если вы хотите запустить набор тестов на ветке до отправки запроса на добавление изменений, вам необходимо настроить сервисы непрерывной интеграции на подключение к вашему репозиторию GitHub. Инструкции для Travis-CI и Azure Pipelines приведены здесь.

Запрос на добавление изменений будет рассмотрен для слияния, когда у вас будет полностью «зелёный» результат сборки. Если какие-либо тесты не пройдут, вы увидите красный «Х», на который можно нажать, чтобы перейти к просмотру отдельных не пройденных тестов. Это пример зелёной сборки.

../_images/ci.png

Примечание

Каждый раз, когда вы отправляете изменения в свою вилку, на CI запускается новый набор тестов. Вы можете включить функцию автоматической отмены, которая удаляет любые неактивные тесты для того же запроса на вытягивание, в Travis-CI здесь.

Разработка с применением TDD/написание кода

Библиотека pandas серьезно относится к тестированию и настоятельно рекомендует участникам использовать разработку с применением TDD (Test-Driven Development). Этот процесс разработки «основан на повторении очень короткого цикла разработки: сначала разработчик пишет (сначала не проходящий) автоматический тест, который определяет желаемое улучшение или новую функцию, затем создаёт минимальный объём кода, чтобы пройти этот тест». Итак, перед написанием кода, необходимо написать тесты. Часто тесты могут быть взяты из исходного вопроса на GitHub. Однако всегда стоит рассмотреть дополнительные варианты использования и написать соответствующие тесты.

Добавление тестов является одним из самых распространённых запросов после отправки кода в pandas. Поэтому стоит привыкнуть к написанию тестов заранее, чтобы это никогда не было проблемой.

Как и многие пакеты, pandas использует pytest и удобные расширения в numpy.testing.

Примечание

Самая ранняя поддерживаемая версия pytest — 3.6.0.

Написание тестов

Все тесты должны располагаться в подкаталоге 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(object):
    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

Это значительно сократит время, необходимое для локального запуска тестов перед отправкой запроса на вытягивание.

Для более подробной информации см. документацию pytest.

Впервые появилась в версии 0.20.0.

Кроме того, можно запустить

pd.test()

с импортированным pandas для запуска тестов аналогичным образом.

Запуск набора тестов производительности

Производительность важна, и стоит рассмотреть, не внёс ли ваш код регрессии в производительности. pandas в процессе миграции на asv benchmarks для лёгкого мониторинга производительности критически важных операций 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 ГБ ОЗУ. Обычно достаточно вставить только подмножество результатов в запрос на вытягивание, чтобы показать, что внесённые изменения не вызывают неожиданных регрессий производительности. Вы можете запустить конкретные бенчмарки, используя флаг -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 - номер проблемы/запроса на вытягивание).

Если ваш код представляет собой улучшение, скорее всего, необходимо добавить примеры использования в существующую документацию. Это можно сделать, следуя разделу о документировании выше. Кроме того, чтобы пользователи знали, когда эта функция была добавлена, используется директива versionadded. Синтаксис Sphinx для этого:

.. versionadded:: 0.21.0

Это поместит текст Новая версия 0.21.0 туда, где вы разместите директиву Sphinx. Это также необходимо поместить в строку документации при добавлении новой функции или метода (пример) или нового ключевого аргумента (пример).

Внесение изменений в pandas

Создание коммита

Держите исправления стиля в отдельном коммите, чтобы сделать ваш запрос на вытягивание более удобочитаемым.

После внесения изменений вы можете просмотреть их, набрав:

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. Для этого необходимо отправить запрос на вытягивание на GitHub.

Проверка вашего кода

Когда вы готовы попросить код обзор, создайте запрос на вытягивание. Перед этим еще раз убедитесь, что вы выполнили все рекомендации, изложенные в этом документе, касательно стиля кода, тестов, тестов производительности и документации. Вы также должны дважды проверить изменения вашей ветки по сравнению с веткой, на основе которой она была создана:

  1. Перейдите к вашему репозиторию на GitHub – https://github.com/your-user-name/pandas
  2. Нажмите на Branches
  3. Нажмите на кнопку Compare для вашей ветки с функцией
  4. Выберите ветки base и compare, если необходимо. Это будут master и shiny-new-feature, соответственно.

Наконец, создайте запрос на вытягивание

Если все хорошо, вы готовы создать запрос на вытягивание. Запрос на вытягивание — это способ сделать код из локального репозитория доступным для сообщества GitHub, его можно просмотреть и, в конечном итоге, объединить в основную версию. Этот запрос на вытягивание и связанные с ним изменения в конечном итоге будут внесены в ветку master и станут доступными в следующем выпуске. Чтобы отправить запрос на вытягивание:

  1. Перейдите к вашему репозиторию на GitHub
  2. Нажмите на кнопку Pull Request
  3. Вы можете нажать на Commits и Files Changed, чтобы еще раз убедиться, что все выглядит правильно
  4. Напишите описание изменений во вкладке Preview Discussion
  5. Нажмите Send Pull Request

Затем этот запрос передается владельцам репозитория, и они проверят код.

Обновление запроса на вытягивание

Исходя из полученного обзора запроса на вытягивание, вам, вероятно, потребуется внести некоторые изменения в код. В этом случае вы можете внести их в свою ветку, добавить новый коммит в эту ветку, отправить его на GitHub, и запрос на вытягивание будет автоматически обновлен. Отправка на GitHub выполняется следующим образом:

git push origin shiny-new-feature

Это автоматически обновит ваш запрос на вытягивание с последним кодом и перезапустит тесты непрерывной интеграции.

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

Для этого вам нужно «объединить 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). Это эффективно сохранит ваши изменения, и их можно будет повторно применить после обновления.

После обновления локальной ветки с функцией вы можете обновить свой запрос на вытягивание, отправив ее на 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.24.2/development/contributing.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API