feat: Change EntityCollection.remove() to accept Entity objects

Previously, EntityCollection.remove() required an integer index, which was
inconsistent with Python's list.remove(item) behavior and the broader
Python ecosystem conventions.

Changes:
- remove() now accepts Entity object directly instead of index
- Searches collection by comparing C++ shared_ptr identity
- Raises ValueError if entity not found in collection
- More Pythonic API matching Python's list.remove() semantics

This aligns with Issue #73 and improves API consistency across the
collection system.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
John McCardle 2025-10-23 13:17:45 -04:00
parent 1149111f2d
commit 327da3622a
1 changed files with 32 additions and 19 deletions

View File

@ -1772,33 +1772,46 @@ PyObject* UIEntityCollection::append(PyUIEntityCollectionObject* self, PyObject*
PyObject* UIEntityCollection::remove(PyUIEntityCollectionObject* self, PyObject* o) PyObject* UIEntityCollection::remove(PyUIEntityCollectionObject* self, PyObject* o)
{ {
if (!PyLong_Check(o)) // Type checking - must be an Entity
if (!PyObject_IsInstance(o, PyObject_GetAttrString(McRFPy_API::mcrf_module, "Entity")))
{ {
PyErr_SetString(PyExc_TypeError, "EntityCollection.remove requires an integer index to remove"); PyErr_SetString(PyExc_TypeError, "EntityCollection.remove requires an Entity object");
return NULL;
}
long index = PyLong_AsLong(o);
// Handle negative indexing
while (index < 0) index += self->data->size();
if (index >= self->data->size())
{
PyErr_SetString(PyExc_ValueError, "Index out of range");
return NULL; return NULL;
} }
// Get iterator to the entity to remove // Get the C++ object from the Python object
auto it = self->data->begin(); PyUIEntityObject* entity = (PyUIEntityObject*)o;
std::advance(it, index); if (!entity->data) {
PyErr_SetString(PyExc_RuntimeError, "Invalid Entity object");
return NULL;
}
// Clear grid reference before removing // Get the underlying list
auto list = self->data.get();
if (!list) {
PyErr_SetString(PyExc_RuntimeError, "The collection store returned a null pointer");
return NULL;
}
// Search for the entity by comparing C++ pointers
auto it = list->begin();
while (it != list->end()) {
if (it->get() == entity->data.get()) {
// Found it - clear grid reference before removing
(*it)->grid = nullptr; (*it)->grid = nullptr;
// release the shared pointer at correct part of the list // Remove from the list
self->data->erase(it); self->data->erase(it);
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
}
++it;
}
// Entity not found - raise ValueError
PyErr_SetString(PyExc_ValueError, "Entity not in EntityCollection");
return NULL;
} }
PyObject* UIEntityCollection::extend(PyUIEntityCollectionObject* self, PyObject* o) PyObject* UIEntityCollection::extend(PyUIEntityCollectionObject* self, PyObject* o)