Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

embedded request breaking with TypeError: unhashable type: 'dict' #1394

Open
YunnXairou opened this issue May 25, 2020 · 4 comments
Open

embedded request breaking with TypeError: unhashable type: 'dict' #1394

YunnXairou opened this issue May 25, 2020 · 4 comments

Comments

@YunnXairou
Copy link

This issue tracker is a tool to address bugs in Eve itself.
Please use Stack Overflow for general questions about using Eve or issues not
related to Eve (see http://python-eve.org/support).

If you'd like to report a bug in Eve, fill out the template below. Provide
any any extra information that may be useful / related to your problem.
Ideally, create an MCVE, which helps us
understand the problem and helps check that it is not caused by something in
your code.


Expected Behavior

I have created 3 shemas with some embedded fields.

classes = {
    "schema": {
        "id": {
            "type": "string",
            "default_setter": lambda doc: doc["name"].lower(),
            "dependencies": "name",
            "required": True,
            "unique": True,
        },
        "name": {"type": "string", "required": True, "unique": True},
        "description": {"type": "string"},
        "article": {
            "type": "objectid",
            "data_relation": {"resource": "articles", "embeddable": True},
        },
        "table": {"type": "markdown"},
        "hit_die": {
            "type": "string",
            "data_relation": {"resource": "dice", "field": "text", "embeddable": True},
        },
        "armor": {"type": "list", "schema": {"type": "string"}},
        "weapons": {"type": "list", "schema": {"type": "string"}},
        "tools": {"type": "list", "schema": {"type": "string"}},
        "saves": {
            "type": "list",
            "schema": {
                "type": "string",
                "allowed": [
                    "Strength",
                    "Charisma",
                    "Dexterity",
                    "Wisdom",
                    "Intelligence",
                    "Constitution",
                ],
            },
        },
        "max_skills": {"type": "integer"},
        "skills": {"type": "list", "schema": {"type": "string"}},
        "equipment": {"type": "list", "schema": {"type": "string"}},
        "features": {
            "type": "list",
            "schema": {
                "type": "objectid",
                "data_relation": {"resource": "articles", "embeddable": True},
            },
        },
    },
    "additional_lookup": {"url": 'regex("[\w_-]+")', "field": "id"},
}
articles = {
    "schema": {
        "title": {"type": "string", "required": True},
        "content": {"type": "markdown", "required": True},
        "class": {"type": "string"},
        "children": {
            "type": "list",
            "schema": {
                "type": "objectid",
                "data_relation": {"resource": "articles", "embeddable": True},
            },
        },
        "next": {
            "type": "objectid",
            "data_relation": {"resource": "articles", "embeddable": True},
        },
    }
}
dice = {
    "schema": {
        "text": {
            "type": "string",
            "unique": True,
            "default_setter": lambda doc: d.dice_to_text(doc["dice"]),
        },
        "min": {
            "type": "integer",
            "readonly": True,
            "dependencies": "dice",
            "default_setter": lambda doc: d.compute_min(doc["dice"]),
        },
        "max": {
            "type": "integer",
            "readonly": True,
            "dependencies": "dice",
            "default_setter": lambda doc: d.compute_max(doc["dice"]),
        },
        "median": {
            "type": "integer",
            "readonly": True,
            "dependencies": "dice",
            "default_setter": lambda doc: d.compute_median(doc["dice"]),
        },
        "dice": {
            "type": "list",
            "schema": {
                "anyof": [
                    {"type": "string"},
                    {
                        "type": "dict",
                        "schema": {
                            "number": {"type": "integer"},
                            "die": {
                                "type": "integer",
                                "allowed": [4, 6, 8, 10, 12, 20, 100],
                            },
                        },
                    },
                ]
            },
            "default_setter": lambda doc: d.text_to_dice(doc["text"]),
        },
    },
    "item_methods": ["GET"],
}

When i use the following request, I expect to have all my data returned.

classes/<id>?embedded={
  "article": 1,
  "article.children": 1,
  "article.children.children": 1,
  "hit_die": 1,
  "features": 1,
  "features.children": 1,
  "features.next": 1,
  "features.next.children": 1,
  "features.next.children.children": 1
}

Actual Behavior

Eve return a 500 error and print the following traceback in the console:

Traceback (most recent call last):
File "/api/eve/flaskapp.py", line 1109, in __call__
  return super(Eve, self).__call__(environ, start_response)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2464, in __call__
  return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2450, in wsgi_app
  response = self.handle_exception(e)
File "/usr/local/lib/python3.7/site-packages/flask_cors/extension.py", line 161, in wrapped_function
  return cors_after_request(app.make_response(f(*args, **kwargs)))
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1867, in handle_exception
  reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
  raise value
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
  response = self.full_dispatch_request()
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
  rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.7/site-packages/flask_cors/extension.py", line 161, in wrapped_function
  return cors_after_request(app.make_response(f(*args, **kwargs)))
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
  reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
  raise value
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
  rv = self.dispatch_request()
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
  return self.view_functions[rule.endpoint](**req.view_args)
File "/api/eve/endpoints.py", line 94, in item_endpoint
  response = getitem(resource, **lookup)
File "/api/eve/methods/common.py", line 318, in rate_limited
  return f(*args, **kwargs)
File "/api/eve/auth.py", line 80, in decorated
  return f(*args, **kwargs)
File "/api/eve/methods/common.py", line 1362, in decorated
  r = f(resource, **combined_args)
File "/api/eve/methods/get.py", line 321, in getitem
  return getitem_internal(resource, **lookup)
File "/api/eve/methods/get.py", line 414, in getitem_internal
  build_response_document(document, resource, embedded_fields, latest_doc)
File "/api/eve/methods/common.py", line 666, in build_response_document
  resolve_embedded_documents(document, resource, embedded_fields)
File "/api/eve/methods/common.py", line 1106, in resolve_embedded_documents
  subdocument[last_field] = getter(subdocument[last_field])
File "/api/eve/methods/common.py", line 1099, in <lambda>
  getter = lambda ref: embedded_document(ref, data_relation, field)  # noqa
File "/api/eve/methods/common.py", line 919, in embedded_document
  embedded_docs, id_value_to_sort, list_of_id_field_name
File "/api/eve/methods/common.py", line 951, in sort_db_response
  id_field_name,
File "/api/eve/methods/common.py", line 975, in sort_per_resource
  if id_value_ in id2dict:
TypeError: unhashable type: 'dict'

after some debug print, it seems that in the embeddement process of one of the articles object, the resources given to embedded_document is a Dict insted of the ObjectId

To be precise, this Dict is the object to embed as it in the data base.

As if the already embedded document tried to re-embed itselft.

Environment

  • Python version: 3.7.2
  • Eve version: 1.1
@stale
Copy link

stale bot commented Dec 19, 2020

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

@stale stale bot added the stale label Dec 19, 2020
@ssantiago88
Copy link

ssantiago88 commented Apr 13, 2022

I am running into this same issue currently. Was there ever a determined cause? I am running these versions:

Cerberus==1.3.2
Eve==1.1.1
Flask==1.1.2
Werkzeug==1.0.1

in the Docker image python:3.9.4. This has been working fine previously. Here's the call stack:

Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/eve/flaskapp.py", line 1109, in call
return super(Eve, self).call(environ, start_response)
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2464, in call
return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2450, in wsgi_app
response = self.handle_exception(e)
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1867, in handle_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.9/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.9/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1936, in dispatch_request
return self.view_functionsrule.endpoint
File "/usr/local/lib/python3.9/site-packages/eve/endpoints.py", line 56, in collections_endpoint
response = get(resource, lookup)
File "/usr/local/lib/python3.9/site-packages/eve/methods/common.py", line 318, in rate_limited
return f(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/eve/auth.py", line 80, in decorated
return f(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/eve/methods/common.py", line 1361, in decorated
r = f(resource, **combined_args)
File "/usr/local/lib/python3.9/site-packages/eve/methods/get.py", line 51, in get
return get_internal(resource, **lookup)
File "/usr/local/lib/python3.9/site-packages/eve/methods/get.py", line 125, in get_internal
return _perform_find(resource, lookup)
File "/usr/local/lib/python3.9/site-packages/eve/methods/get.py", line 270, in perform_find
build_response_document(document, resource, embedded_fields)
File "/usr/local/lib/python3.9/site-packages/eve/methods/common.py", line 666, in build_response_document
resolve_embedded_documents(document, resource, embedded_fields)
File "/usr/local/lib/python3.9/site-packages/eve/methods/common.py", line 1105, in resolve_embedded_documents
subdocument[last_field] = getter(subdocument[last_field])
File "/usr/local/lib/python3.9/site-packages/eve/methods/common.py", line 1099, in
getter = lambda ref: embedded_document(ref, data_relation, field) # noqa
File "/usr/local/lib/python3.9/site-packages/eve/methods/common.py", line 921, in embedded_document
embedded_docs = sort_db_response(
File "/usr/local/lib/python3.9/site-packages/eve/methods/common.py", line 951, in sort_db_response
sort_per_resource(
File "/usr/local/lib/python3.9/site-packages/eve/methods/common.py", line 977, in sort_per_resource
if id_value
in id2dict:
TypeError: unhashable type: 'dict'

@stale stale bot removed the stale label Apr 13, 2022
@ssantiago88
Copy link

The cause of this error is a documented limitation of Embedded documents with Eve. See documentation:

https://docs.python-eve.org/en/stable/features.html#limitations

Limitations

Currently we support embedding of documents by references located in any subdocuments (nested dicts and lists). For example, a query /invoices/?embedded={"user.friends":1} will return a document with user and all his friends embedded, but only if user is a subdocument and friends is a list of reference (it could be a list of dicts, nested dict, etc.). This feature is about serialization on GET requests. There’s no support for POST, PUT or PATCH of embedded documents.

@Push-singhh
Copy link

Push-singhh commented Oct 6, 2022

Eve-1.1.5
Cerberus-1.3.4
Flask-2.2.2

Traceback (most recent call last):
File "D:\rr\venv\lib\site-packages\eve\flaskapp.py", line 1110, in call
return super(Eve, self).call(environ, start_response)
File "D:\rr\venv\lib\site-packages\flask\app.py", line 2548, in call
return self.wsgi_app(environ, start_response)
File "D:\rr\venv\lib\site-packages\flask\app.py", line 2528, in wsgi_app
response = self.handle_exception(e)
File "D:\rr\venv\lib\site-packages\flask_cors\extension.py", line 165, in wrapped_function
return cors_after_request(app.make_response(f(*args, **kwargs)))
File "D:\rr\venv\lib\site-packages\flask\app.py", line 2525, in wsgi_app
response = self.full_dispatch_request()
File "D:\rr\venv\lib\site-packages\flask\app.py", line 1822, in full_dispatch_request
rv = self.handle_user_exception(e)
File "D:\rr\venv\lib\site-packages\flask_cors\extension.py", line 165, in wrapped_function
return cors_after_request(app.make_response(f(*args, **kwargs)))
File "D:\rr\venv\lib\site-packages\flask\app.py", line 1820, in full_dispatch_request
rv = self.dispatch_request()
File "D:\rr\venv\lib\site-packages\flask\app.py", line 1796, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "D:\rr\venv\lib\site-packages\eve\endpoints.py", line 56, in collections_endpoint
response = get(resource, lookup)
File "D:\rr\venv\lib\site-packages\eve\methods\common.py", line 325, in rate_limited
return f(*args, **kwargs)
File "D:\rr\venv\lib\site-packages\eve\auth.py", line 80, in decorated
return f(*args, **kwargs)
File "D:\rr\venv\lib\site-packages\eve\methods\common.py", line 1373, in decorated
r = f(resource, **combined_args)
File "D:\rr\venv\lib\site-packages\eve\methods\get.py", line 51, in get
File "D:\rr\venv\lib\site-packages\eve\methods\common.py", line 1111, in
getter = lambda ref: embedded_document(ref, data_relation, field) # noqa
File "D:\rr\venv\lib\site-packages\eve\methods\common.py", line 929, in embedded_document
embedded_docs = sort_db_response(
File "D:\rr\venv\lib\site-packages\eve\methods\common.py", line 959, in sort_db_response
sort_per_resource(
File "D:\rr\venv\lib\site-packages\eve\methods\common.py", line 985, in sort_per_resource
if id_value_ in id2dict:
TypeError: unhashable type: 'dict'

I am also facing same issue.

Temporary Solution:
If I try to query like this: &embedded={"created_by":1,"movies.movie.created_by":1}
then it will give above error if "movies" field is not existing in database. But if I add "movies" key in database then error is not occuring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants