davebshow / goblin

A Python 3.5 rewrite of the TinkerPop 3 OGM Goblin
Other
93 stars 21 forks source link

TypeError: unhashable type: 'dict' when creating an Edge #102

Closed marciodebarros closed 6 years ago

marciodebarros commented 6 years ago

Hi,

In my test app:

import asyncio

from goblin import Goblin from quart import jsonify, Quart, serving from app.models import Person, Knows`

def get_hashable_id(val):

Use the value "as-is" by default.

result = val
if isinstance(val, dict) and "@type" in val and "@value" in val:
    if val["@type"] == "janusgraph:RelationIdentifier":
        result = val["@value"]["value"]
return result

loop = asyncio.get_event_loop() goblin_app = loop.run_until_complete(Goblin.open(loop, get_hashable_id=get_hashable_id))

goblin_app = loop.run_until_complete(Goblin.open(loop, hosts = ['localhost'], port = '8182', scheme = 'ws'))

goblin_app.register(Person, Knows) print("Initialized all the goblin stuff") quart_app = Quart(name)

async def create(app, data): session = await app.session() session.add(data) await session.flush() return data

leif = Person() leif.name = 'Leif' leif.age = 28 leif = loop.run_until_complete(create(goblin_app, leif))

jon = Person() jon.name = 'Jon' jon.age = 32 jon = loop.run_until_complete(create(goblin_app, jon))

works_with = Knows() works_with.source = leif works_with.target = jon works_with = loop.run_until_complete(create(goblin_app, works_with)) `

when ever I run I get the following stack errors:

`Initialized all the goblin stuff Traceback (most recent call last): File "/Users/mdebarros/PycharmProjects/goblinpoc/run.py", line 2, in from app import quart_app File "/Users/mdebarros/PycharmProjects/goblinpoc/app/init.py", line 54, in works_with = loop.run_until_complete(create(goblin_app, works_with)) File "/usr/local/Cellar/python3/3.6.2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/base_events.py", line 467, in run_until_complete return future.result() File "/Users/mdebarros/PycharmProjects/goblinpoc/app/init.py", line 36, in create await session.flush() File "/Users/mdebarros/.virtualenvs/goblinpoc/lib/python3.6/site-packages/goblin/session.py", line 270, in flush await self.save(elem) File "/Users/mdebarros/.virtualenvs/goblinpoc/lib/python3.6/site-packages/goblin/session.py", line 312, in save result = await self.save_edge(elem) File "/Users/mdebarros/.virtualenvs/goblinpoc/lib/python3.6/site-packages/goblin/session.py", line 350, in save_edge self.current[hashable_id] = result File "/usr/local/Cellar/python3/3.6.2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/weakref.py", line 168, in setitem self.data[key] = KeyedRef(value, self._remove, key) TypeError: unhashable type: 'dict'

Process finished with exit code 1 ` I am connecting to Janusgraph version 0.2.0, and have the following packages versions installed on my IDE:

Any help or tips would be highly appreciated.

Thank you,

--MD

davebshow commented 6 years ago

This looks like it may be a version issue. Janus 0.2.0 uses TP 3.2.6, and the newest version of Goblin (2.1) can use any Gremlin Language Variant (GLV) >= 3.2.6. Have you tried Goblin 2.1 with the GLV versions that correspond to the TinkerPop version?

Try this:

  1. Get a fresh environment, or uninstall Goblin, gremlinpython, and aiogremlin. (remove Tornado and deps too if you ended up with it, you probably don't want it).

  2. Install the 3.2.6 line GLVs and the newest Goblin (in this order):

pip install gremlinpython==3.2.6 --no-deps
pip install aiogremlin==3.2.6
pip install goblin

Goblin version should be 2.1.0 (might as well double check)

See if this fixes your problem. If it doesn't, I will investigate further.

marciodebarros commented 6 years ago

Hi Dave,

I tried following the steps for re-installing the proper versions :

Here is the pip list of packaged with their versions: aenum (1.4.5) aiofiles (0.3.2) aiogremlin (3.2.6) aiohttp (2.2.5) async-timeout (2.0.0) attrs (17.4.0) blinker (1.4) chardet (3.0.4) click (6.7) goblin (2.1.0) gremlinpython (3.2.6) h11 (0.7.0) h2 (3.0.1) hpack (3.0.0) hyperframe (5.1.0) idna (2.6) idna-ssl (1.0.1) inflection (0.3.1) itsdangerous (0.24) Jinja2 (2.10) MarkupSafe (1.0) multidict (4.1.0) pip (9.0.1) PyYAML (3.12) Quart (0.4.1) setuptools (28.8.0) six (1.10.0) sortedcontainers (1.5.9) wsproto (0.11.0) yarl (1.1.1)

Still get the same error:

/Users/mdebarros/.virtualenvs/goblinpoc/bin/python /Users/mdebarros/PycharmProjects/goblinpoc/run.py Initialized all the goblin stuff Traceback (most recent call last): File "/Users/mdebarros/PycharmProjects/goblinpoc/run.py", line 2, in from app import quart_app File "/Users/mdebarros/PycharmProjects/goblinpoc/app/init.py", line 54, in works_with = loop.run_until_complete(create(goblin_app, works_with)) File "/usr/local/Cellar/python3/3.6.2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/base_events.py", line 467, in run_until_complete return future.result() File "/Users/mdebarros/PycharmProjects/goblinpoc/app/init.py", line 36, in create await session.flush() File "/Users/mdebarros/.virtualenvs/goblinpoc/lib/python3.6/site-packages/goblin/session.py", line 242, in flush await self.save(elem) File "/Users/mdebarros/.virtualenvs/goblinpoc/lib/python3.6/site-packages/goblin/session.py", line 294, in save result = await self.save_edge(elem) File "/Users/mdebarros/.virtualenvs/goblinpoc/lib/python3.6/site-packages/goblin/session.py", line 332, in save_edge self.current[hashable_id] = result TypeError: unhashable type: 'dict'

Process finished with exit code 1

davebshow commented 6 years ago

I can't seem to replicate this. I can run the following example script with no errors:

import asyncio
from goblin import Goblin, properties, element

def get_hashable_id(val):
  if isinstance(val, dict) and "@type" in val and "@value" in val:
      if val["@type"] == "janusgraph:RelationIdentifier":
          val = val["@value"]["value"]
  return val

class Person(element.Vertex):
    name = properties.Property(properties.String)
    age = properties.Property(properties.Integer)

class Knows(element.Edge):
    notes = properties.Property(properties.String)

loop = asyncio.get_event_loop()

app = loop.run_until_complete(Goblin.open(loop, get_hashable_id=get_hashable_id))

app.register(Person, Knows)

async def go(app):
    session = await app.session()
    leif = Person()
    leif.name = 'Leif'
    leif.age = 28
    jon = Person()
    jon.name = 'Jonathan'
    works_with = Knows(leif, jon)
    session.add(leif, jon, works_with)
    await session.flush()
    result = await session.g.E(works_with.id).next()
    assert result is works_with
    people = session.traversal(Person)
    async for person in people:
        print(person)

    edges = session.g.E()
    async for edge in edges:
        print(edge)

loop.run_until_complete(go(app))

This is using:

Unfortunately, I can't run your script. Could you please post a failing script that does not have external requirements?

davebshow commented 6 years ago

Also, could you please format code samples with indentation so I can read as well as cut and paste to run.

marciodebarros commented 6 years ago

Hi, here it is. I double checked the versions again and still same result. Here is a single script file that when run gives me the error.

import asyncio

from goblin import Goblin
from quart import jsonify, Quart, serving
from goblin import element, properties

class Person(element.Vertex):
    name = properties.Property(properties.String)
    age = properties.Property(properties.Integer)

class Knows(element.Edge):
    notes = properties.Property(properties.String, default='N/A')
    source = element.Vertex
    target = element.Vertex

def get_hashable_id(val):
    #Use the value "as-is" by default.
    result = val
    if isinstance(val, dict) and "@type" in val and "@value" in val:
        if val["@type"] == "janusgraph:RelationIdentifier":
            result = val["@value"]["value"]
    return result

loop = asyncio.get_event_loop()
goblin_app = loop.run_until_complete(Goblin.open(loop,
    get_hashable_id=get_hashable_id))

goblin_app = loop.run_until_complete(Goblin.open(loop,
                                                 hosts = ['localhost'],
                                                 port = '8182',
                                                 scheme = 'ws'))

goblin_app.register(Person, Knows)
print("Initialized all the goblin stuff")
quart_app = Quart(__name__)

async def create(app, data):
    session = await app.session()
    session.add(data)
    await session.flush()
    return data

leif = Person()
leif.name = 'Leif'
leif.age = 28
leif = loop.run_until_complete(create(goblin_app, leif))

jon = Person()
jon.name = 'Jon'
jon.age = 32
jon = loop.run_until_complete(create(goblin_app, jon))

works_with = Knows()
works_with.source = leif
works_with.target = jon
works_with = loop.run_until_complete(create(goblin_app, works_with))

loop.run_until_complete(quart_app)
davebshow commented 6 years ago

Could you please remove the code that calls external libraries (Quart)

marciodebarros commented 6 years ago

Here it is all without any reference to quart:

import asyncio

from goblin import Goblin, element, properties

class Person(element.Vertex):
    name = properties.Property(properties.String)
    age = properties.Property(properties.Integer)

class Knows(element.Edge):
    notes = properties.Property(properties.String, default='N/A')
    source = element.Vertex
    target = element.Vertex

def get_hashable_id(val):
    #Use the value "as-is" by default.
    result = val
    if isinstance(val, dict) and "@type" in val and "@value" in val:
        if val["@type"] == "janusgraph:RelationIdentifier":
            result = val["@value"]["value"]
    return result

loop = asyncio.get_event_loop()
app = loop.run_until_complete(Goblin.open(loop,
    get_hashable_id=get_hashable_id))

app = loop.run_until_complete(Goblin.open(loop,
                                                 hosts = ['localhost'],
                                                 port = '8182',
                                                 scheme = 'ws'))

app.register(Person, Knows)
print("Initialized all the goblin stuff")

async def create(app, data):
    session = await app.session()
    session.add(data)
    await session.flush()
    return data

leif = Person()
leif.name = 'Leif'
leif.age = 28
leif = loop.run_until_complete(create(app, leif))

jon = Person()
jon.name = 'Jon'
jon.age = 32
jon = loop.run_until_complete(create(app, jon))

works_with = Knows()
works_with.source = leif
works_with.target = jon
works_with = loop.run_until_complete(create(app, works_with))

loop.run_until_complete(app)
davebshow commented 6 years ago

You instantiate the app twice in your code. The second time you do it, you don't have pass the id hasher so you aren't using it. This works:

import asyncio

from goblin import Goblin, element, properties

class Person(element.Vertex):
    name = properties.Property(properties.String)
    age = properties.Property(properties.Integer)

class Knows(element.Edge):
    notes = properties.Property(properties.String, default='N/A')
    source = element.Vertex
    target = element.Vertex

def get_hashable_id(val):
    #Use the value "as-is" by default.
    result = val
    if isinstance(val, dict) and "@type" in val and "@value" in val:
        if val["@type"] == "janusgraph:RelationIdentifier":
            result = val["@value"]["value"]
    return result

loop = asyncio.get_event_loop()
app = loop.run_until_complete(Goblin.open(loop,
    get_hashable_id=get_hashable_id))

app.register(Person, Knows)
print("Initialized all the goblin stuff")

async def create(app, data):
    session = await app.session()
    session.add(data)
    await session.flush()
    return data

leif = Person()
leif.name = 'Leif'
leif.age = 28
leif = loop.run_until_complete(create(app, leif))

jon = Person()
jon.name = 'Jon'
jon.age = 32
jon = loop.run_until_complete(create(app, jon))

works_with = Knows()
works_with.source = leif
works_with.target = jon
works_with = loop.run_until_complete(create(app, works_with))

Please carefully debug your application code before opening future issues.

marciodebarros commented 6 years ago

Thank you so much for your help and patience Dave.

davebshow commented 6 years ago

No problem @marciodebarros I am happy to help.