2025, Nov 12 00:02

TypeError в pysheds с NumPy 2: nodata value not representable in dtype of array — что делать

Разбираем TypeError в pysheds с NumPy 2 (nodata value not representable in dtype of array), причину из-за NEP 50 и простое решение: использовать NumPy 1.x.

Запускаете pysheds на современной сборке и натыкаетесь на TypeError: nodata value not representable in dtype of array? Вы не одни. Сбой обычно проявляется при вычислении направлений стока и связан с изменениями поведения в NumPy 2, а не с вашим растром или настройками алгоритма.

Минимальный пример

Сценарий ниже показывает проблему от начала до конца. Логика проста: загрузить DEM, устранить плоские участки, вычислить направления стока, затем — накопление. Имена переменных произвольны; ход вычислений тот же.

import numpy as np
from pysheds.grid import Grid as PsGrid

# Загрузка DEM из GeoTIFF
source_path = 'CLSA_LiDAR.tif'
mesh = PsGrid.from_raster(source_path)
heightmap = mesh.read_raster(source_path)

# Разрешение плоских участков и расчёт направлений стока
heightmap_adj = mesh.resolve_flats(heightmap)
directions = mesh.flowdir(heightmap_adj)

# Накопление стока
accum_map = mesh.accumulation(directions)

В NumPy 2 сбой обычно сопровождается трассировкой, где встречается проверка наподобие np.can_cast(viewfinder.nodata, obj.dtype, casting='safe'), после чего возникает описанный TypeError о nodata.

Что происходит на самом деле

Ошибка — симптом несовместимости между pysheds и NumPy 2. В трассировке есть ключевая подсказка:

Это изменение было частью внедрения NEP 50, возможно, в будущем мы снова явно разрешим их.

NumPy 2 внедряет NEP 50, который меняет поведение некоторых правил продвижения скаляров и семантики приведения типов. В этом участке кода проверка безопасного приведения, связанная с nodata, под NumPy 2 приводит к TypeError и, как следствие, к сообщению о том, что значение nodata не может быть представлено в текущем dtype массива.

Исправление

Практичное решение — запускать pysheds с релизом NumPy 1.x. На практике проблему устраняет NumPy 1.22. Подходят и другие сборки 1.x, например 1.26.x; при необходимости выберите более консервативную версию 1.x, пока среда не станет стабильной. После перехода на NumPy 1.x тот же скрипт выполняется без изменений в коде.

import numpy as np
from pysheds.grid import Grid as PsGrid

# Загрузка DEM
src = 'CLSA_LiDAR.tif'
grid_obj = PsGrid.from_raster(src)
dem_arr = grid_obj.read_raster(src)

# Подготовка и анализ стока
dem_adj = grid_obj.resolve_flats(dem_arr)
flow_dir = grid_obj.flowdir(dem_adj)
accumulated = grid_obj.accumulation(flow_dir)

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

Почему это важно

Крупные обновления зависимостей вроде NumPy 2 могут менять поведение низкоуровневых операций, на которых держатся геопространственные стеки. Если библиотека ещё не адаптирована к новой семантике, на первый взгляд незначительные шаги — например, проверки nodata внутри представлений растра — способны нарушить ключевые процессы, такие как вычисление направлений стока и накопления. Понимание того, что причина в окружении, а не в алгоритме, помогает быстрее перейти к правильному решению.

Выводы

Если при работе с pysheds вы видите nodata value not representable in dtype of array, приведите окружение к релизу NumPy 1.x. Известно, что работают версии вроде 1.22; жизнеспособен и ряд 1.26.x. Как только NumPy закреплён на совместимой сборке 1.x, запускайте тот же код — алгоритм и API менять не нужно. В дальнейшем следите за заметками по переходу на NumPy 2 и за ходом адаптации pysheds, чтобы обновиться без риска для гидрологических пайплайнов.

Статья основана на вопросе с StackOverflow от Kay Khaing Kyaw и ответе от wp78de.