Skip to content

cannot create an IDict interface that passes verifyObject on cpython and pypy #118

Closed
@mmerickel

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

# sigh, it's callable, but we don't know how to introspect it, so
# we have to give it a pass.
continue
whereas in PyPy the methods actual types.MethodType types and fail to validate properly inside
def _incompat(required, implemented):
#if (required['positional'] !=
# implemented['positional'][:len(required['positional'])]
# and implemented['kwargs'] is None):
# return 'imlementation has different argument names'
if len(implemented['required']) > len(required['required']):
return 'implementation requires too many arguments'
if ((len(implemented['positional']) < len(required['positional']))
and not implemented['varargs']):
return "implementation doesn't allow enough arguments"
if required['kwargs'] and not implemented['kwargs']:
return "implementation doesn't support keyword arguments"
if required['varargs'] and not implemented['varargs']:
return "implementation doesn't support variable arguments"
.

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:

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
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions