Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0

- uses: r-lib/actions/setup-pandoc@v2

- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v7
with:
python-version: '3.11'
python-version: '3.14'
cache: 'pip'

- name: Install docs requirements
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/pre-commit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ jobs:
name: "pre-commit"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v7
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-python@v4
- uses: actions/setup-python@v7
- name: pre-commit (cache)
uses: actions/cache@v3
uses: actions/cache@v6
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
Expand Down
58 changes: 9 additions & 49 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14']

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
Expand Down Expand Up @@ -58,77 +58,37 @@ jobs:
pytest geoarrow-pandas/tests -v -s

- name: Run doctests (geoarrow-pyarrow)
if: success() && matrix.python-version == '3.13'
if: success() && matrix.python-version == '3.14'
run: |
cd geoarrow-pyarrow
pytest --pyargs geoarrow.pyarrow --doctest-modules --import-mode=importlib

- name: Run doctests (geoarrow-types)
if: success() && matrix.python-version == '3.13'
if: success() && matrix.python-version == '3.14'
run: |
cd geoarrow-types
pytest --pyargs geoarrow.types --doctest-modules --import-mode=importlib

- name: Run doctests (geoarrow-pandas)
if: success() && matrix.python-version == '3.13'
if: success() && matrix.python-version == '3.14'
run: |
cd geoarrow-pandas
pytest --pyargs geoarrow.pandas --doctest-modules --import-mode=importlib

# This is a test of geoarrow-types on Python 3.7 (which implies pyarrow 12
# since this is the last supported version there). Python 3.7 is still the
# runtime available on some hosted platforms (e.g., it is the minimum required
# version for apache-sedona Python)
oldest-supported:
runs-on: ubuntu-latest
container:
image: python:3.7

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true

- name: Check git setup
run: |
git config --global --add safe.directory "$(pwd)"
git describe --long --match='geoarrow-types-*'

# setuptools_scm available for Python 3.7 does not support version_file
# (it can still be installed on Python 3.7, it just can't be built there
# without this modification)
- name: Patch pyproject.toml
run: |
cd geoarrow-types
sed -i.bak '/^version_file/d' pyproject.toml
echo '__version__ = "0.0.0"' > src/geoarrow/types/_version.py
echo '__version_tuple__ = (0, 0, 0)' >> src/geoarrow/types/_version.py

- name: Install (geoarrow-types)
run: |
pip install --upgrade setuptools setuptools_scm
cd geoarrow-types
pip install ".[test]"

- name: Run tests (geoarrow-types)
run: |
pytest geoarrow-types/tests -v -s

coverage:
needs: [test]

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v7
with:
python-version: '3.13'
python-version: '3.14'
cache: 'pip'

- name: Install (geoarrow-pyarrow)
Expand Down
2 changes: 1 addition & 1 deletion geoarrow-pandas/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ dynamic = ["version"]
description = ""
authors = [{name = "Dewey Dunnington", email = "dewey@dunnington.ca"}]
license = {text = "Apache-2.0"}
requires-python = ">=3.8"
requires-python = ">=3.9"
dependencies = ["geoarrow-pyarrow", "pandas", "pyarrow"]

[project.optional-dependencies]
Expand Down
52 changes: 43 additions & 9 deletions geoarrow-pandas/src/geoarrow/pandas/lib.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import re as _re
import pandas as _pd
import pyarrow as _pa
import numpy as _np
from geoarrow.types import TypeSpec, type_spec, Encoding

import geoarrow.pyarrow as _ga
import numpy as _np
import pyarrow as _pa
from geoarrow.types import Encoding, TypeSpec, type_spec

import pandas as _pd


class GeoArrowExtensionScalar(bytes):
Expand Down Expand Up @@ -79,6 +81,10 @@ class GeoArrowExtensionArray(_pd.api.extensions.ExtensionArray):
not instantiate this class directly.
"""

# Added to pandas' ExtensionArray base class in pandas 3.0. Defining it
# here keeps the behavior consistent when using older pandas versions.
_readonly = False

def __init__(self, obj, type=None):
if type is not None:
self._dtype = GeoArrowExtensionDtype(type)
Expand All @@ -105,10 +111,12 @@ def __getitem__(self, item):
else:
return None
elif isinstance(item, slice):
return GeoArrowExtensionArray(self._data[item])
elif isinstance(item, list):
return self.take(item)
elif hasattr(item, "dtype") and item.dtype.kind == "i":
result = GeoArrowExtensionArray(self._data[item])
result._readonly = self._readonly
return result
elif (
isinstance(item, list) or hasattr(item, "dtype") and item.dtype.kind == "i"
):
return self.take(item)
elif hasattr(item, "dtype") and item.dtype.kind == "b":
if len(item) != len(self):
Expand All @@ -127,6 +135,32 @@ def __getitem__(self, item):
"only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boolean arrays are valid indices"
)

def __setitem__(self, key, value):
if self._readonly:
raise ValueError("Cannot modify read-only array")

values = list(self)
indices = _np.arange(len(self))[key]

if _np.isscalar(indices):
values[int(indices)] = value
else:
indices = indices.tolist()
if _pd.api.types.is_scalar(value):
for index in indices:
values[index] = value
else:
replacements = list(value)
if len(replacements) != len(indices):
raise ValueError(
"Length of values does not match length of indexer"
)
for index, replacement in zip(indices, replacements):
values[index] = replacement

replacement = self._from_sequence(values, dtype=self.dtype)
self._data = replacement._data

def __contains__(self, item: object):
for scalar in self:
if scalar == item:
Expand Down Expand Up @@ -362,7 +396,7 @@ def construct_from_string(cls, string):
) from e

def __repr__(self):
return f"{type(self).__name__}({repr(self._parent)})"
return f"{type(self).__name__}({self._parent!r})"

def __str__(self):
ext_name = self._parent.extension_name
Expand Down
23 changes: 18 additions & 5 deletions geoarrow-pandas/tests/test_geoarrow_pandas_suite.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import pytest
from pandas.tests.extension import base
import geoarrow.pandas as gapd
import geoarrow.pyarrow as ga
import operator

import geoarrow.pandas as gapd
import geoarrow.pyarrow as ga
import pandas as pd
import pytest
from pandas import (
Series,
options,
)
from pandas.tests.extension import base


@pytest.fixture
Expand All @@ -24,7 +25,9 @@ def data():
* data[0] and data[1] should both be non missing
* data[0] and data[1] should not be equal
"""
strings = [f"POINT ({i} {i + 1})" for i in range(100)]
# pandas 3.0 changed the required fixture length from 100 to 10.
fixture_size = 10 if int(pd.__version__.split(".")[0]) >= 3 else 100
strings = [f"POINT ({i} {i + 1})" for i in range(fixture_size)]
return gapd.GeoArrowExtensionArray(ga.array(strings))


Expand Down Expand Up @@ -209,6 +212,16 @@ def using_copy_on_write() -> bool:
return options.mode.copy_on_write and options.mode.data_manager == "block"


@pytest.fixture(params=[True, False])
def using_nan_is_na(request):
"""Whether pandas considers NaN and NA equivalent."""
if int(pd.__version__.split(".")[0]) >= 3:
with pd.option_context("future.distinguish_nan_and_na", not request.param):
yield request.param
else:
yield request.param


class TestGeoArrowDtype(base.BaseDtypeTests):
pass

Expand Down
2 changes: 1 addition & 1 deletion geoarrow-pyarrow/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ dynamic = ["version"]
description = ""
authors = [{name = "Dewey Dunnington", email = "dewey@dunnington.ca"}]
license = {text = "Apache-2.0"}
requires-python = ">=3.8"
requires-python = ">=3.9"
dependencies = ["pyarrow >= 14.0.2", "geoarrow-types >= 0.3.0", "geoarrow-c >= 0.3.0"]

[project.optional-dependencies]
Expand Down
Loading
Loading