Spec-Zone.ru › NumPy 2.0

Для авторов зависимых пакетов

Этот документ призван объяснить лучшие практики для создания пакета, зависящего от NumPy.

Понимание версионирования NumPy и стабильности API/ABI

NumPy использует стандартную, совместимую с PEP 440, схему версионирования: major.minor.bugfix. Основное обновление — очень редкое событие, и если оно происходит, это, скорее всего, означает разрыв ABI. Выпуска NumPy 1.xx происходили с 2006 по 2023 год; NumPy 2.0 в начале 2024 года стал первым выпуском, изменившим ABI (небольшие разрывы ABI в особых случаях могли произойти несколько раз в обновлениях с меньшими версиями). Дополнительные версии выпускаются регулярно, обычно каждые 6 месяцев. Дополнительные версии содержат новые функции, устаревания и удаление ранее устаревшего кода. Исправления ошибок выпускаются еще чаще; они не содержат новых функций или устареваний.

Важно знать, что NumPy, как и сам Python, и большинство других известных научных проектов Python, не использует семантическое версионирование. Вместо этого, несовместимые с предыдущими версиями изменения API требуют предупреждений об устаревании как минимум на два релиза. Более подробную информацию можно найти в NEP 23 — Политика обратной совместимости и устаревания.

NumPy имеет как Python API, так и C API. C API можно использовать непосредственно или через Cython, f2py или другие подобные инструменты. Если ваш пакет использует C API, тогда стабильность ABI (интерфейса двоичного приложения) NumPy имеет значение. ABI NumPy является совместимым только в сторону увеличения версии, но не в обратном направлении. Это означает: двоичные файлы, скомпилированные с использованием определённой целевой версии C API NumPy, будут продолжать работать корректно с новыми версиями NumPy, но не со старыми.

Тестирование против основного ветвления или предварительных релизов NumPy

Для крупных, активно поддерживаемых пакетов, зависящих от NumPy, мы рекомендуем тестировать с использованием основной версии NumPy в CI. Для удобства предоставлены ежедневные сборки в виде пакетов wheel по адресу https://anaconda.org/scientific-python-nightly-wheels/. Пример команды установки:

pip install -U --pre --only-binary :all: -i https://pypi.anaconda.org/scientific-python-nightly-wheels/simple numpy

Это помогает обнаруживать регрессии в NumPy, которые необходимо исправить перед следующим выпуском NumPy. Кроме того, мы рекомендуем вызывать ошибки при появлении предупреждений в CI для этой задачи, либо все предупреждения, или по крайней мере DeprecationWarning и FutureWarning. Это дает вам раннее предупреждение об изменениях в NumPy для адаптации вашего кода.

Если вы хотите протестировать собственные сборки пакетов wheel с использованием последней ежедневной сборки NumPy, и вы используете cibuildwheel, вам может потребоваться что-то вроде этого в файле конфигурации вашей CI:

CIBW_ENVIRONMENT: "PIP_PRE=1 PIP_EXTRA_INDEX_URL=https://pypi.anaconda.org/scientific-python-nightly-wheels/simple"

Добавление зависимости от NumPy

Зависимость во время сборки

Примечание

До NumPy 1.25, API NumPy на C-уровне не экспонировался обратной совместимостью по умолчанию. Это означает, что при компиляции с версией NumPy, предшествующей 1.25, необходимо компилировать с самой старой поддерживаемой версией. Это можно сделать, используя oldest-supported-numpy. См. документацию NumPy 1.24.

Если пакет использует API NumPy на C-уровне напрямую или использует другой инструмент, который от него зависит, например, Cython или Pythran, то NumPy является зависимостью во время сборки пакета.

По умолчанию NumPy будет экспонировать API, обратной совместимой с самой старой версией NumPy, которая поддерживает текущую самую старую совместимую версию Python. NumPy 1.25.0 поддерживает Python 3.9 и выше, а NumPy 1.19 — первая версия, которая поддерживает Python 3.9. Таким образом, мы гарантируем, что при использовании значений по умолчанию NumPy 1.25 будет экспонировать C-API, совместимый с NumPy 1.19. (точная версия задаётся внутри заголовочных файлов NumPy).

NumPy также совместим с будущими версиями для всех релизов с меньшими номерами, но выпуск с новым номером версии потребует перекомпиляции (см. советы, специфичные для NumPy 2.0, ниже).

Поведение по умолчанию можно настроить, например, добавив:

#define NPY_TARGET_VERSION NPY_1_22_API_VERSION

перед включением заголовков NumPy (или эквивалентного -D флага компилятора) в каждый модуль расширения, который использует C-API NumPy. Это в основном полезно, если вам нужно использовать недавно добавленный API, но при этом не поддерживать старые версии.

Если по какой-либо причине вы хотите компилировать по умолчанию для текущей установленной версии NumPy, можно добавить:

#ifndef NPY_TARGET_VERSION
    #define NPY_TARGET_VERSION NPY_API_VERSION
#endif

Это позволяет пользователю переопределить значение по умолчанию через -DNPY_TARGET_VERSION. Это определение должно быть согласованным для каждого модуля расширения (используйте import_array()), а также применяется к модулю umath.

При компиляции с NumPy необходимо добавить соответствующие ограничения версий в свой pyproject.toml (см. PEP 517). Поскольку ваш расширение не будет совместимо с новым основным выпуском NumPy и может быть несовместимо со очень старыми версиями.

Для пакетов conda-forge, пожалуйста, обратитесь к ссылке.

На данный момент это обычно так же просто, как включение:

host:
  - numpy
run:
  - {{ pin_compatible('numpy') }}

Зависимость во время выполнения и диапазоны версий

Сам NumPy и многие основные научные пакеты Python договорились о графике прекращения поддержки старых версий Python и NumPy: NEP 29 — Рекомендация по поддержке версий Python и NumPy как стандарта политики сообщества. Мы рекомендуем всем пакетам, зависящим от NumPy, следовать рекомендациям NEP 29.

Для зависимостей во время выполнения укажите границы версий, используя install_requires в setup.py (предполагая, что вы используете numpy.distutils или setuptools для сборки).

Большинству библиотек, которые полагаются на NumPy, не нужно устанавливать верхнюю границу версии: NumPy тщательно сохраняет обратную совместимость.

Тем не менее, если вы (а) являетесь проектом, который гарантированно выпускается часто, (б) используете большую часть API NumPy, и (в) беспокоитесь о том, что изменения в NumPy могут сломать ваш код, вы можете установить верхнюю границу <MAJOR.MINOR + N с N не меньше 3, и MAJOR.MINOR — текущий релиз NumPy [*]. Если вы используете C-API NumPy (прямо или через Cython), вы также можете зафиксировать текущую основную версию, чтобы предотвратить разрывы ABI. Обратите внимание, что установка верхней границы для NumPy может влиять на возможность установки вашей библиотеки вместе с другими, более новыми пакетами.

[*]

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

Примечание

SciPy содержит больше документации о том, как он создаёт wheel-файлы и работает со своими зависимостями во время сборки и выполнения здесь.

CI сборки wheel-файлов NumPy и SciPy также могут быть полезны как справочный материал, его можно найти здесь для NumPy и здесь для SciPy.

Рекомендации, специфичные для NumPy 2.0

NumPy 2.0 — выпуск с разрывом ABI, однако он содержит поддержку создания wheel-файлов, которые работают как с версиями 2.0, так и с версиями 1.xx. Важно понимать, что:

  1. Когда вы создаёте wheel-файлы для своего пакета, используя NumPy версии 1.xx во время сборки, они не будут работать с NumPy 2.0.
  2. Когда вы создаёте wheel-файлы для своего пакета, используя NumPy версии 2.x во время сборки, они будут работать с NumPy 1.xx.

Первый выпуск NumPy ABI для 2.0, гарантированно стабильный, выйдет с первым релиз-кандидатом 2.0 (т. е. 2.0.0rc1). Вот наши рекомендации по работе с зависимостью от NumPy:

  1. В основной (разрабатываемой) ветке вашего пакета не добавляйте никаких ограничений.
  2. Если вы полагаетесь на C-API NumPy (например, при прямом использовании в C/C++, или через код Cython, использующий NumPy), добавьте требование numpy<2.0 в метаданные зависимостей вашего пакета для релизов/в ветках релизов. Делайте это до тех пор, пока numpy 2.0.0rc1 не будет выпущен, и вы сможете нацелиться на него. Обоснование: C-API NumPy изменится в версии 2.0, поэтому любые скомпилированные модули расширения, которые зависят от NumPy, сломаются; их нужно будет перекомпилировать.
  3. Если вы полагаетесь на обширную часть Python-API NumPy, также рассмотрите возможность добавления того же требования numpy<2.0 в метаданные до тех пор, пока вы не убедитесь, что ваш код обновлён для изменений в версии 2.0 (то есть когда вы проверили, что всё работает с 2.0.0rc1). Обоснование: мы проведем значительную очистку API, удалив многие псевдонимы и устаревшие/нерекомендуемые объекты (см., например, Руководство по миграции на NumPy 2.0 и NEP 52 — Очистка Python-API для NumPy 2.0), поэтому, если вы не используете только современные/рекомендуемые функции и объекты, ваш код, вероятно, потребует как минимум некоторых корректировок.
  4. Планируйте выпуск собственных пакетов, зависящих от numpy вскоре после выхода первого релиза-кандидата NumPy 2.0 (вероятно, около 1 февраля 2024 года). Обоснование: в этот момент вы сможете выпустить пакеты, которые будут работать как с 2.0, так и с 1.X, и, следовательно, ваши собственные конечные пользователи не столкнутся с существенными/какими-либо сбоями (вы хотите, чтобы pip install mypackage продолжал работать в день выхода NumPy 2.0).
  5. После того, как 2.0.0rc1 станет доступным, вы сможете внести изменения в метаданные pyproject.toml способом, описанным ниже.

Есть два случая: вам нужно сохранить совместимость с numpy 1.xx, одновременно поддерживая 2.0, или вы можете отказаться от поддержки numpy 1.xx для новых релизов своего пакета и поддерживать только >=2.0. Последнее проще, но может быть более ограничительным для ваших пользователей. В этом случае просто добавьте numpy>=2.0 (или numpy>=2.0.0rc1 в свои требования сборки и выполнения, и всё готово. Сейчас мы сосредоточимся на «сохранении совместимости с 1.xx и 2.x», что немного сложнее.

Пример для пакета, использующего C-API NumPy (через C/Cython/и т. д.), который хочет поддерживать NumPy 1.23.5 и выше:

[build-system]
build-backend = ...
requires = [
    # Note for packagers: this constraint is specific to wheels
    # for PyPI; it is also supported to build against 1.xx still.
    # If you do so, please ensure to include a `numpy<2.0`
    # runtime requirement for those binary packages.
    "numpy>=2.0.0rc1",
    ...
]

[project]
dependencies = [
    "numpy>=1.23.5",
]

Мы рекомендуем иметь как минимум одну задачу CI, которая собирает/устанавливает через wheel, а затем выполняет тесты против самой старой версии NumPy, которую поддерживает пакет. Например:

- name: Build wheel via wheel, then install it
  run: |
    python -m build  # This will pull in numpy 2.0 in an isolated env
    python -m pip install dist/*.whl

- name: Test against oldest supported numpy version
  run: |
    python -m pip install numpy==1.23.5
    # now run test suite

Вышесказанное работает только после того, как NumPy 2.0 станет доступным на PyPI. Если вы хотите протестировать wheel-файл NumPy 2.0-dev, вам нужно использовать ночные сборки NumPy (см. данный раздел выше) или собрать NumPy из исходного кода.

© 2005–2024 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/2.0/dev/depending_on_numpy.html

Spec-Zone.ru

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