-
Notifications
You must be signed in to change notification settings - Fork 0
Description
If there is nothing specifically registered to externalize an object, and the object itself doesn't have a usable toExternalObject() method, we go through a set of other steps to try to externalize it. One of the last is recoginizing something as a sequence, which we will externalize as a LocatedExternalList:
That checks for the (old) zope.interface.common.sequence.IFiniteSequence interface, or a specific list of types:
This can surprise people that write sequence-like objects, especially if they extend collections.abc.Sequence: they don't get externalized, and the reason isn't obvious (especially if the sequence-like object is just replacing a plain list or tuple). The solution right now is to declare the type as @implementer(IFiniteSequence) but that shouldn't be necessary.
We could either add collections.abc.Sequence to that list (but checking for abstract types is relatively slow, and isinstance is O(n) in the list of types), or we could take advantage of the new-and-improved ABC interfaces in zope.interface:
>>> from zope.interface.common.collections import ISequence
>>> ISequence.__sro__
(<ABCInterfaceClass zope.interface.common.collections.ISequence>,
<ABCInterfaceClass zope.interface.common.collections.IReversible>,
<ABCInterfaceClass zope.interface.common.collections.ICollection>,
<ABCInterfaceClass zope.interface.common.collections.ISized>,
<ABCInterfaceClass zope.interface.common.collections.IIterable>,
<ABCInterfaceClass zope.interface.common.collections.IContainer>,
<ABCInterfaceClass zope.interface.common.ABCInterface>,
<InterfaceClass zope.interface.Interface>)
>>> ISequence.providedBy([])
True
>>> from persistent.list import PersistentList
>>> ISequence.providedBy(PersistentList())
True
>>> ISequence.providedBy(())
TrueUnfortunately, that doesn't automatically pick up new subclasses of Sequence defined after ISequence was imported, so that's not a complete solution currently:
>>> from collections.abc import Sequence
>>> class S(Sequence):
... __getitem__ = __len__ = lambda self: None
...
>>> ISequence.providedBy(S())
False