Skip to content

Commit 1dc89b9

Browse files
committed
feat: added attribute value list type with NumPy-style fancy indexing
1 parent 8c81b31 commit 1dc89b9

File tree

8 files changed

+949
-138
lines changed

8 files changed

+949
-138
lines changed

.coveragerc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ omit = src/codegen/*
44
[report]
55
exclude_lines =
66
pragma: no cover
7-
if TYPE_CHECKING:
7+
if TYPE_CHECKING:
8+
^\s*\.\.\.$
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from .handler import AttributeHandler
2+
from .storage import AttributeStorage
3+
from .value_list import AttributeValueList
4+
5+
__all__ = (
6+
"AttributeHandler",
7+
"AttributeStorage",
8+
"AttributeValueList",
9+
)

src/igraph_ctypes/_internal/attributes.py renamed to src/igraph_ctypes/_internal/attributes/handler.py

Lines changed: 27 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
1-
from abc import ABC, abstractmethod
2-
from ctypes import (
3-
pointer,
4-
py_object,
5-
)
6-
from dataclasses import dataclass, field
1+
from ctypes import pointer
72
from math import nan
8-
from typing import Any, Callable, MutableMapping, Optional
3+
from typing import Any, Callable, Optional
94

10-
from .conversion import igraph_vector_int_t_to_numpy_array_view
11-
from .lib import (
5+
from igraph_ctypes._internal.conversion import igraph_vector_int_t_to_numpy_array_view
6+
from igraph_ctypes._internal.lib import (
127
igraph_error,
138
igraph_vector_resize,
149
igraph_vector_set,
@@ -19,14 +14,20 @@
1914
igraph_strvector_resize,
2015
igraph_strvector_set,
2116
)
22-
from .refcount import incref, decref
23-
from .types import igraph_attribute_table_t, IntArray
24-
from .utils import nop, protect_with
25-
26-
__all__ = ("AttributeHandlerBase", "AttributeHandler", "AttributeStorage")
27-
17+
from igraph_ctypes._internal.types import igraph_attribute_table_t
18+
from igraph_ctypes._internal.utils import nop, protect_with
19+
20+
from .storage import (
21+
DictAttributeStorage,
22+
assign_storage_to_graph,
23+
detach_storage_from_graph,
24+
get_storage_from_graph,
25+
)
2826

29-
################################################################################
27+
__all__ = (
28+
"AttributeHandlerBase",
29+
"AttributeHandler",
30+
)
3031

3132

3233
def _trigger_error(error: int) -> int:
@@ -66,130 +67,20 @@ def _as_parameter_(self):
6667
return self._table_ptr
6768

6869

69-
class AttributeStorage(ABC):
70-
"""Interface specification for objects that store graph, vertex and edge
71-
attributes.
72-
"""
73-
74-
@abstractmethod
75-
def add_vertices(self, graph, n: int) -> None:
76-
"""Notifies the attribute storage object that the given number of
77-
new vertices were added to the graph.
78-
"""
79-
raise NotImplementedError
80-
81-
@abstractmethod
82-
def add_edges(self, graph, edges) -> None:
83-
"""Notifies the attribute storage object that the given edges were
84-
added to the graph.
85-
"""
86-
raise NotImplementedError
87-
88-
@abstractmethod
89-
def clear(self):
90-
"""Clears the storage area, removing all attributes."""
91-
raise NotImplementedError
92-
93-
@abstractmethod
94-
def copy(
95-
self,
96-
copy_graph_attributes: bool = True,
97-
copy_vertex_attributes: bool = True,
98-
copy_edge_attributes: bool = True,
99-
):
100-
"""Creates a shallow copy of the storage area."""
101-
raise NotImplementedError
102-
103-
@abstractmethod
104-
def get_graph_attribute_map(self) -> MutableMapping[str, Any]:
105-
"""Returns a mutable mapping into the storage area that stores the graph
106-
attributes.
107-
"""
108-
raise NotImplementedError
109-
110-
111-
@dataclass(frozen=True)
112-
class DictAttributeStorage(AttributeStorage):
113-
"""dictionary-based storage area for the graph, vertex and edge attributes
114-
of a graph.
115-
"""
116-
117-
graph_attributes: dict[str, Any] = field(default_factory=dict)
118-
vertex_attributes: dict[str, list[Any]] = field(default_factory=dict)
119-
edge_attributes: dict[str, list[Any]] = field(default_factory=dict)
120-
121-
def add_vertices(self, graph, n: int) -> None:
122-
pass
123-
124-
def add_edges(self, graph, edges: IntArray) -> None:
125-
pass
126-
127-
def clear(self) -> None:
128-
self.graph_attributes.clear()
129-
self.vertex_attributes.clear()
130-
self.edge_attributes.clear()
131-
132-
def copy(
133-
self,
134-
copy_graph_attributes: bool = True,
135-
copy_vertex_attributes: bool = True,
136-
copy_edge_attributes: bool = True,
137-
):
138-
return self.__class__(
139-
self.graph_attributes.copy() if copy_graph_attributes else {},
140-
self.vertex_attributes.copy() if copy_vertex_attributes else {},
141-
self.edge_attributes.copy() if copy_edge_attributes else {},
142-
)
143-
144-
def get_graph_attribute_map(self) -> MutableMapping[str, Any]:
145-
return self.graph_attributes
146-
147-
148-
def _assign_storage_to_graph(graph, storage: Optional[AttributeStorage] = None) -> None:
149-
"""Assigns an attribute storage object to a graph, taking care of
150-
increasing or decreasing the reference count of the storage object if needed.
151-
"""
152-
try:
153-
old_storage = graph.contents.attr
154-
except ValueError:
155-
# No storage yet, this is OK
156-
old_storage = None
157-
158-
if old_storage is storage:
159-
# Nothing to do
160-
return
161-
162-
if old_storage is not None:
163-
decref(old_storage)
164-
165-
if storage is not None:
166-
graph.contents.attr = py_object(incref(storage))
167-
else:
168-
graph.contents.attr = py_object()
169-
170-
171-
def _get_storage_from_graph(graph) -> AttributeStorage:
172-
return graph.contents.attr
173-
174-
175-
def _detach_storage_from_graph(graph) -> None:
176-
return _assign_storage_to_graph(graph, None)
177-
178-
17970
class AttributeHandler(AttributeHandlerBase):
18071
"""Attribute handler implementation that uses a DictAttributeStorage_
18172
as its storage backend.
18273
"""
18374

18475
def init(self, graph, attr):
185-
_assign_storage_to_graph(graph, DictAttributeStorage())
76+
assign_storage_to_graph(graph, DictAttributeStorage())
18677

18778
def destroy(self, graph) -> None:
188-
storage = _get_storage_from_graph(graph)
79+
storage = get_storage_from_graph(graph)
18980
if storage:
19081
storage.clear()
19182

192-
_detach_storage_from_graph(graph)
83+
detach_storage_from_graph(graph)
19384

19485
def copy(
19586
self,
@@ -199,11 +90,11 @@ def copy(
19990
copy_vertex_attributes: bool,
20091
copy_edge_attributes: bool,
20192
):
202-
storage = _get_storage_from_graph(graph)
93+
storage = get_storage_from_graph(graph)
20394
new_storage = storage.copy(
20495
copy_graph_attributes, copy_vertex_attributes, copy_edge_attributes
20596
)
206-
_assign_storage_to_graph(to, new_storage)
97+
assign_storage_to_graph(to, new_storage)
20798

20899
def add_vertices(self, graph, n: int, attr) -> None:
209100
# attr will only ever be NULL here so raise an error if it is not
@@ -214,7 +105,7 @@ def add_vertices(self, graph, n: int, attr) -> None:
214105
)
215106

216107
# Extend the existing attribute containers
217-
_get_storage_from_graph(graph).add_vertices(graph, n)
108+
get_storage_from_graph(graph).add_vertices(graph, n)
218109

219110
def permute_vertices(self, graph, to, mapping):
220111
pass
@@ -232,7 +123,7 @@ def add_edges(self, graph, edges, attr) -> None:
232123

233124
# Extend the existing attribute containers
234125
edge_array = igraph_vector_int_t_to_numpy_array_view(edges).reshape((-1, 2))
235-
_get_storage_from_graph(graph).add_edges(graph, edge_array)
126+
get_storage_from_graph(graph).add_edges(graph, edge_array)
236127

237128
def permute_edges(self, graph, to, mapping):
238129
pass
@@ -264,7 +155,7 @@ def get_numeric_graph_attr(self, graph, name, value):
264155
vec,
265156
0,
266157
self._to_numeric(
267-
_get_storage_from_graph(graph).get_graph_attribute_map()[name]
158+
get_storage_from_graph(graph).get_graph_attribute_map()[name]
268159
),
269160
)
270161

@@ -275,7 +166,7 @@ def get_string_graph_attr(self, graph, name, value):
275166
vec,
276167
0,
277168
self._to_bytes(
278-
_get_storage_from_graph(graph).get_graph_attribute_map()[name]
169+
get_storage_from_graph(graph).get_graph_attribute_map()[name]
279170
),
280171
)
281172

@@ -285,7 +176,7 @@ def get_bool_graph_attr(self, graph, name, value):
285176
igraph_vector_bool_set(
286177
vec,
287178
0,
288-
bool(_get_storage_from_graph(graph).get_graph_attribute_map()[name]),
179+
bool(get_storage_from_graph(graph).get_graph_attribute_map()[name]),
289180
)
290181

291182
def get_numeric_vertex_attr(self, graph, name, vs, value):

0 commit comments

Comments
 (0)