How to test a REST API that saves data outside of the ZODB in a RDBMS

Over the years, I heavily mutilated example.trajectory from its original and ended up with the following in my db.py module to be able to reuse a database session. My issue was that a new session would attempt to remap an already mapped SQLAlchemy Table object.

FWIW maybe you can use below as inspiration...


class ErpEdiemSession(object):
    """Reusing a single instance of the database session client
    The session itself is not persisted, according to
    https://github.com/zopefoundation/zope.sqlalchemy/tree/1.6
    """

    # Enforce UTC as our base timezone. See UTCDateTime class below.
    os.putenv("PGTZ", "UTC")
    _instance = None
    _mapped_classes = {}

    def __new__(cls):
        """This code brought to you by ChatGPT
        using a singleton pattern
        """
        if cls._instance is None:
            cls._instance = super(ErpEdiemSession, cls).__new__(cls)
            initializeSession()  # Initialize the session
            # log.info('Initializing erpediem session object')
        else:
            # log.info('Not initializing session again')
            pass

        return cls._instance

    def __call__(self, dbconnection):
        """Always returns the scoped session
        <sqlalchemy.orm.scoping.scoped_session object at 0x7f9a708d5950>
        so that we can use self.session.get_bind() in the view
        """
        global _PROFILE_ENGINE
        global _PROFILE_SESSION
        global DEBUG

        """
        if _PROFILE_SESSION:
            log.info('Calling erpediem session object %s %s %s' % (self, dbconnection, _PROFILE_SESSION, ))
            log.info(self._mapped_classes)
        else:
            log.info('no profile session yet')
        """

        portal = api.portal.get()
        saconnect = ISQLAlchemyConnectionStrings(portal)
        self.dsn = saconnect[dbconnection]

        # log.info('erpediem profile engine %s' % _PROFILE_ENGINE)
        # log.info('erpediem profile session %s' % _PROFILE_SESSION)

        if not (_PROFILE_ENGINE and _PROFILE_SESSION):
            '''
            eleddy: since we moved this code out of the actual init, so that we can
            have a sane configuration setup, we MUST do this with a lock. Otherwise sql
            alchemy loses its shit and goes on a 'fuck your multi-threading - I'll eat
            pancakes on your grave!' tirade. Then you spend your friday
            night sober and staring at an abyss of configuration headaches and
            infinite loops usually reserved for Mondays.
            '''
            with _DB_CONFIG_LOCK:
                if not _PROFILE_ENGINE:
                    _create_database_if_missing(self.dsn)
                    _PROFILE_ENGINE = create_engine(
                        self.dsn,
                        pool_size=5,
                        pool_recycle=3600,
                        convert_unicode=True,
                        echo=DEBUG,
                    )
                    # reflect existing tables
                    Base.metadata.reflect(_PROFILE_ENGINE)

                    # create new tables
                    Base.metadata.create_all(_PROFILE_ENGINE)

                    """
                    for _t in Base.metadata.tables:
                        columns =  Table(_t, Base.metadata).columns
                        log.info("Table: %s" % columns)
                    """

                if not _PROFILE_SESSION:
                    _PROFILE_SESSION = scoped_session(sessionmaker(bind=_PROFILE_ENGINE))

        return _PROFILE_SESSION

    def map_class(self, class_to_map, table, primary_key):
        """This code brought to you by ChatGPT
        using a registry of mapped classes
        """
        # log.info('Mapped classes: %s' % self._mapped_classes)
        if class_to_map not in self._mapped_classes.keys():
            # log.info('Attempting to map: %s' % class_to_map)
            mapper(class_to_map, table, primary_key=primary_key)
            self._mapped_classes[class_to_map] = True
        else:
            # log.info('Not mapping: %s again' % class_to_map)
            pass
1 Like