Files
UtilityPole_Info/.venv/lib/python3.12/site-packages/pyproj/utils.py
2025-11-15 15:59:49 +09:00

155 lines
4.4 KiB
Python

"""
Utility functions used within pyproj
"""
import json
from array import array
from enum import Enum, auto
from typing import Any
def is_null(value: Any) -> bool:
"""
Check if value is NaN or None
"""
# pylint: disable=comparison-with-itself
return value != value or value is None
def strtobool(value: Any) -> bool:
"""
https://docs.python.org/3.9/distutils/apiref.html#distutils.util.strtobool
Here since distutils is deprecated.
Convert a string representation of truth to True or False.
"""
value = str(value).lower()
if value in ("y", "yes", "t", "true", "on", "1"):
return True
if value in ("n", "no", "f", "false", "off", "0"):
return False
raise ValueError(f"invalid truth value: '{value}'")
class NumpyEncoder(json.JSONEncoder):
"""
Handle numpy types when dumping to JSON
"""
def default(self, obj): # pylint: disable=arguments-renamed
try:
return obj.tolist()
except AttributeError:
pass
try:
# numpy scalars
if obj.dtype.kind == "f":
return float(obj)
if obj.dtype.kind == "i":
return int(obj)
except AttributeError:
pass
return json.JSONEncoder.default(self, obj)
class DataType(Enum):
"""
Data type for copy to buffer and convertback operations
"""
FLOAT = auto()
LIST = auto()
TUPLE = auto()
ARRAY = auto()
def _copytobuffer_return_scalar(xxx: Any) -> tuple[array, DataType]:
"""
Prepares scalar for PROJ C-API:
- Makes a copy because PROJ modifies buffer in place
- Make sure dtype is double as that is what PROJ expects
- Makes sure object supports Python Buffer API
Parameters
-----------
xxx: float or 0-d numpy array
Returns
-------
tuple[Any, DataType]
The copy of the data prepared for the PROJ API & Python Buffer API.
"""
try:
return array("d", (float(xxx),)), DataType.FLOAT
except Exception:
raise TypeError("input must be a scalar") from None
def _copytobuffer(xxx: Any, inplace: bool = False) -> tuple[Any, DataType]:
"""
Prepares data for PROJ C-API:
- Makes a copy because PROJ modifies buffer in place
- Make sure dtype is double as that is what PROJ expects
- Makes sure object supports Python Buffer API
If the data is a numpy array, it ensures the data is in C order.
Parameters
----------
xxx: Any
A scalar, list, tuple, numpy.array,
pandas.Series, xaray.DataArray, or dask.array.Array.
inplace: bool, default=False
If True, will return the array without a copy if it
meets the requirements of the Python Buffer API & PROJ C-API.
Returns
-------
tuple[Any, DataType]
The copy of the data prepared for the PROJ API & Python Buffer API.
"""
# check for pandas.Series, xarray.DataArray or dask.array.Array
# also handle numpy masked Arrays; note that pandas.Series also has a
# "mask" attribute, hence checking for simply the "mask" attr in that
# case isn't sufficient
if (
not hasattr(xxx, "hardmask")
and hasattr(xxx, "__array__")
and callable(xxx.__array__)
):
xxx = xxx.__array__()
# handle numpy data
if hasattr(xxx, "shape"):
if xxx.shape == ():
# convert numpy array scalar to float
# (array scalars don't support buffer API)
return _copytobuffer_return_scalar(xxx)
# Use C order when copying to handle arrays in fortran order
return xxx.astype("d", order="C", copy=not inplace), DataType.ARRAY
data_type = DataType.ARRAY
if isinstance(xxx, array):
if not inplace or xxx.typecode != "d":
xxx = array("d", xxx)
elif isinstance(xxx, list):
xxx = array("d", xxx)
data_type = DataType.LIST
elif isinstance(xxx, tuple):
xxx = array("d", xxx)
data_type = DataType.TUPLE
else:
return _copytobuffer_return_scalar(xxx)
return xxx, data_type
def _convertback(data_type: DataType, inx: Any) -> Any:
# if inputs were lists, tuples or floats, convert back to original type.
if data_type == DataType.FLOAT:
return inx[0]
if data_type == DataType.LIST:
return inx.tolist()
if data_type == DataType.TUPLE:
return tuple(inx)
return inx