From 24f80f2c47eddc004ed203857573f3454c412e03 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Sat, 29 Oct 2022 09:03:32 +0200 Subject: [PATCH] BUG: move weakref-able implementation to base C extension type (fix PyPy) (#1577) --- .github/workflows/tests.yml | 5 +++++ shapely/geometry/base.py | 2 +- shapely/tests/geometry/test_geometry_base.py | 5 +++++ src/pygeom.c | 5 +++++ src/pygeom.h | 5 ++++- 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 831068926..51f896974 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -58,6 +58,11 @@ jobs: python: 3.9 geos: 3.10.3 numpy: 1.19.5 + # pypy + - os: ubuntu-latest + python: "pypy3.8" + geos: 3.11.0 + numpy: 1.23.3 env: GEOS_VERSION: ${{ matrix.geos }} diff --git a/shapely/geometry/base.py b/shapely/geometry/base.py index 33011260b..657ec491e 100644 --- a/shapely/geometry/base.py +++ b/shapely/geometry/base.py @@ -81,7 +81,7 @@ class BaseGeometry(shapely.Geometry): """ - __slots__ = ["__weakref__"] + __slots__ = [] def __new__(self): warn( diff --git a/shapely/tests/geometry/test_geometry_base.py b/shapely/tests/geometry/test_geometry_base.py index 1c434b951..74c0d9d45 100644 --- a/shapely/tests/geometry/test_geometry_base.py +++ b/shapely/tests/geometry/test_geometry_base.py @@ -1,3 +1,4 @@ +import platform import weakref import numpy as np @@ -45,6 +46,10 @@ def test_geometry_collection(): ] +@pytest.mark.skipif( + platform.python_implementation() == "PyPy", + reason="Setting custom attributes doesn't fail on PyPy", +) @pytest.mark.parametrize("geom", geometries_all_types) def test_setattr_disallowed(geom): with pytest.raises(AttributeError): diff --git a/src/pygeom.c b/src/pygeom.c index ca97db097..faa8030d9 100644 --- a/src/pygeom.c +++ b/src/pygeom.c @@ -38,11 +38,15 @@ PyObject* GeometryObject_FromGEOS(GEOSGeometry* ptr, GEOSContextHandle_t ctx) { } else { self->ptr = ptr; self->ptr_prepared = NULL; + self->weakreflist = (PyObject *)NULL; return (PyObject*)self; } } static void GeometryObject_dealloc(GeometryObject* self) { + if (self->weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject *)self); + } if (self->ptr != NULL) { // not using GEOS_INIT, but using global context instead GEOSContextHandle_t ctx = geos_context[0]; @@ -396,6 +400,7 @@ PyTypeObject GeometryType = { .tp_repr = (reprfunc)GeometryObject_repr, .tp_hash = (hashfunc)GeometryObject_hash, .tp_richcompare = (richcmpfunc)GeometryObject_richcompare, + .tp_weaklistoffset = offsetof(GeometryObject, weakreflist), .tp_str = (reprfunc)GeometryObject_str, }; diff --git a/src/pygeom.h b/src/pygeom.h index 10fc5371e..6335b00f2 100644 --- a/src/pygeom.h +++ b/src/pygeom.h @@ -6,8 +6,11 @@ #include "geos.h" typedef struct { - PyObject_HEAD void* ptr; + PyObject_HEAD + void* ptr; void* ptr_prepared; + /* For weak references */ + PyObject *weakreflist; } GeometryObject; extern PyTypeObject GeometryType;