cannot create an IDict interface that passes verifyObject on cpython and pypy #118
Closed
Description
class IDict(Interface):
def get(k, default=None):
pass
def pop(k, default=None):
pass
It doesn't appear possible to describe the dict as an interface using z.i. The only reason it works on CPython is because it hits
zope.interface/src/zope/interface/verify.py
Lines 86 to 88 in c1b436d
types.MethodType
types and fail to validate properly inside zope.interface/src/zope/interface/verify.py
Lines 107 to 120 in c1b436d
In the example below for test_default_kw
the required
and implemented
parameters for pop
are:
>>> required
{'positional': ('k', 'default'), 'required': ('k',), 'optional': {'default': None}, 'varargs': None, 'kwargs': None}
>>> implemented
{'positional': ('key', 'default'), 'required': ('key', 'default'), 'optional': {}, 'varargs': None, 'kwargs': None}
I have not yet figured out how PyPy is specifying default
as required when it is not actually required, however they closed the bitbucket issue as "a known difference between cpython and pypy" and so I think z.i or pyramid needs a way to work around it.
Related issues:
- pyramid's IDict interface is incorrect for pop. Pylons/pyramid#3237
- https://bitbucket.org/pypy/pypy/issues/2685/regression-with-pyramid-zopeinterface
Example:
from zope.interface import (
implementer,
Interface,
)
from zope.interface.verify import verifyObject
def check_iface(iface):
@implementer(iface)
class Dict(dict):
pass
d = Dict()
verifyObject(iface, d)
def test_star_args():
class IDict(Interface):
def get(k, *args):
pass
def pop(k, *args):
pass
check_iface(IDict) # get implementation doesn't support variable arguments.
def test_star_args_kwargs():
class IDict(Interface):
def get(k, *args, **kwargs):
pass
def pop(k, *args, **kwargs):
pass
check_iface(IDict) # get implementation doesn't support keyword arguments.
def test_default_kw(): # this is also the version used in pyramid
class IDict(Interface):
def get(k, default=None):
pass
def pop(k, default=None):
pass
check_iface(IDict) # pop implementation requires too many arguments.
def test_default_marker():
marker = object()
class IDict(Interface):
def get(k, default=marker):
pass
def pop(k, default=marker):
pass
check_iface(IDict) # pop implementation requires too many arguments.
Metadata
Assignees
Labels
No labels