neo4j-contrib / neomodel

An Object Graph Mapper (OGM) for the Neo4j graph database.
https://neomodel.readthedocs.io
MIT License
967 stars 232 forks source link

NodeClassAlreadyDefined Exception in Streamlit Application due to Repeated Class Registration #826

Open muelldlr opened 3 months ago

muelldlr commented 3 months ago

Expected Behavior (Mandatory)

When repeatedly reloading a Streamlit application, classes should not be registered multiple times in the neomodel library in order to avoid a NodeClassAlreadyDefined exception. The application should be executed without errors, even if it is reloaded several times.

Actual Behavior (Mandatory)

When the Streamlit page is reloaded, a NodeClassAlreadyDefined exception occurs because the classes are registered again. This leads to an error and prevents the application from continuing to run.

How to Reproduce the Problem

Create a simple Streamlit application that uses neomodel classes. Reload the Streamlit page several times. Observe that a NodeClassAlreadyDefined exception is thrown on each reload.

Simple Example

import streamlit as st
from neomodel import StructuredNode, StringProperty, UniqueIdProperty, config

config.DATABASE_URL = 'bolt://neo4j:neo4j@localhost:7687'

class Component(StructuredNode):
    uid = UniqueIdProperty()
    name = StringProperty(unique_index=True)
    version = StringProperty()

st.write("This is a test application")

Screenshots (where it's possibile)

grafik

Specifications (Mandatory)

Currently used versions

Versions

miguelfg commented 1 month ago

Same here using Django running python manage.py runserver also with any of its parameters --noreload --nothreading.

Using:

mruge-shr commented 3 weeks ago

with a little help from GPT4 i found this workaround that seems to work on mine

from neomodel.sync_.core import db  # Import the Neo4j Database singleton instance

def get_or_create_entity_node_class():
    """
    Retrieve the EntityNode class from the registry or define it if not present.
    """
    # Check if 'EntityNode' is already registered in the registry
    registry = db._NODE_CLASS_REGISTRY  # Access the internal registry
    for labels, node_class in registry.items():
        if 'EntityNode' in labels:
            print("EntityNode found in registry.")
            return node_class

    # If not found, define and register the EntityNode class
    class EntityNode(StructuredNode):
        """Top-level Neo4j node class for storing UUIDs and relationships."""
        uuid = UniqueIdProperty()
        related_to = RelationshipTo('EntityNode', 'RELATED_TO')

    # Register the new class in the registry
    db._NODE_CLASS_REGISTRY[frozenset(['EntityNode'])] = EntityNode
    print("EntityNode registered.")
    return EntityNode

# Usage:
EntityNode = get_or_create_entity_node_class()