SurrealDB setup using asyncio tasks/run_until_complete works on Windows, but not on Linux.

huangapple go评论62阅读模式
英文:

SurrealDB setup using asyncio tasks/run_until_complete works on Windows, but not on Linux

问题

我理解了你的要求,以下是你提供的代码的翻译:

@dataclass
class NoResultError(Exception):
    """上一次查询没有返回结果。"""

    query: str = None


@dataclass
class Resource:
    # SNIP
    async def store(self):
        """将对象存储到数据库中。"""
        global connection
        log.debug("正在存储 %s", self)
        if old := await get(self.__class__, self.id):
            old_ser = ser(old)
            differences = {k: v for k, v in ser(self).items() if v != old_ser[k]}
            record = await connection.update(self.id, data=differences)
            log.debug("已更新 %s", record)
        else:
            record = await connection.create(self.id, data=ser(self))
            log.debug("已插入 %s", record)


async def asetup():
    """连接并对本地数据库进行身份验证。"""
    global connection
    log.info("正在设置 SurrealDB 数据库...")
    connection = Surreal("ws://localhost:8000/rpc")
    await connection.connect()
    await connection.signin({"user": secrets['db_username'], "pass": secrets['db_password']})
    await connection.use("foo", "bar")
    log.info("数据库设置完成!")

def setup():
    t = asyncio.get_event_loop().run_until_complete(asetup())

async def ateardown():
    global connection
    log.info("正在关闭 SurrealDB 数据库...")
    await connection.close()
    log.info("数据库已关闭!")

def teardown(bot: discord.Bot):
    t = asyncio.get_event_loop().run_until_complete(ateardown())

# SNIP

async def get(obj_type: type[R], obj_id: str) -> R:
    global connection
    assert (
        obj_type.__name__ == obj_id.split(":")[0]
    ), "该对象ID与预期类型不匹配."
    log.debug("正在获取 %s", obj_id)
    obj = deser(obj_type, await connection.select(obj_id))
    log.debug("已找到 %s", obj)
    return obj


async def run_query(obj_type: type[R], query: str, **params) -> list[R]:
    """对数据库运行查询,并返回查询结果中的最后一行。"""
    global connection
    log.debug("正在运行查询 %s,参数 %s", query, params)
    try:
        results = (await connection.query(query, params))[-1]["result"]
    except (IndexError, KeyError) as e:
        raise NoResultError(query) from e
    else:
        log.debug("已找到 %s", results)
        return deser(list, results)

请注意,我只对Python代码进行了翻译,其中的注释也进行了相应的翻译。如果你需要关于代码的进一步解释或帮助,请随时告诉我。

英文:

I'm working on a bot using SurrealDB, with a set of helper functions to abstract the process of storing and fetching data.

The framework I'm using (Pycord) has an extension mechanism, where it automatically imports a module like this one, and runs a synchronous setup function. The setup function is responsible for setting up the database connection, which depends on a series of async coroutines.

This is the code I have for my DB helpers:

@dataclass
class NoResultError(Exception):
    """No results were returned from the last line of a query."""

    query: str = None


@dataclass
class Resource:
    # SNIP
    async def store(self):
        """Stores the object in the database."""
        global connection
        log.debug("Storing %s", self)
        if old := await get(self.__class__, self.id):
            old_ser = ser(old)
            differences = {k: v for k, v in ser(self).items() if v != old_ser[k]}
            record = await connection.update(self.id, data=differences)
            log.debug("Updated %s", record)
        else:
            record = await connection.create(self.id, data=ser(self))
            log.debug("Inserted %s", record)


async def asetup():
    """Connects and authenticates with the local database."""
    global connection
    log.info("Setting up SurrealDB database...")
    connection = Surreal("ws://localhost:8000/rpc")
    await connection.connect()
    await connection.signin({"user": secrets['db_username'], "pass": secrets['db_password']})
    await connection.use("foo", "bar")
    log.info("Database setup complete!")

def setup():
    t = asyncio.get_event_loop().run_until_complete(asetup())

async def ateardown():
    global connection
    log.info("Closing SurrealDB database...")
    await connection.close()
    log.info("Database closed!")

def teardown(bot: discord.Bot):
    t = asyncio.get_event_loop().run_until_complete(ateardown())

# SNIP

async def get(obj_type: type[R], obj_id: str) -> R:
    global connection
    assert (
        obj_type.__name__ == obj_id.split(":")[0]
    ), "That object ID does not match the expected type."
    log.debug("Getting %s", obj_id)
    obj = deser(obj_type, await connection.select(obj_id))
    log.debug("Found %s", obj)
    return obj


async def run_query(obj_type: type[R], query: str, **params) -> list[R]:
    """Runs a query against the database, and returns the results from the last line.

    Args:
        obj_type (Type[R]): The object type to expect.
        query (str): The query to run.
        **params: Parameters to use in the query.

    Returns:
        list[R]: A list of objects returned from the last line of the query.

    Raises:
        NoResultError: No results or an error was returned from the last line.
    """
    global connection
    log.debug("Running query %s with params %s", query, params)
    try:
        results = (await connection.query(query, params))[-1]["result"]
    except (IndexError, KeyError) as e:
        raise NoResultError(query) from e
    else:
        log.debug("Found %s", results)
        return deser(list, results)

Since Pycord doesn't support async setup functions, I tried creating a task on the event loop, then I tried run_until_complete, but none of them worked: when I try to run a query via the run_query() coro, something absolutely bizarre happens: It returns the data just fine on my development PC, which runs Windows 11; but on the production system, which runs Ubuntu 22.04 LTS, I keep encountering this exception:

...in run_query
results = (await connection.query(query, params))[-1]["result"]
^^^^^^^^^^
NameError: name 'connection' is not defined

I tried installing the latest version of Python from source--just like my dev setup--I tried putting global connection at the top of every function concerning it, nothing works. I am at my wit's absolute end. What is going on here, and, far more importantly, how do I fix it?

答案1

得分: 0

Sure, here is the translated code:

关于创建一个处理连接的类怎么样

class DatabaseConnection:
    def __init__(self):
        self.connection = None

    async def asetup(self):
        log.info("设置 SurrealDB 数据库中...")
        self.connection = Surreal("ws://localhost:8000/rpc")
        await self.connection.connect()
        await self.connection.signin({"user": secrets['db_username'], "pass": secrets['db_password']})
        await self.connection.use("foo", "bar")
        log.info("数据库设置完成!")

    async def ateardown(self):
        log.info("关闭 SurrealDB 数据库中...")
        await self.connection.close()
        log.info("数据库已关闭!")

    async def get(self, obj_type: type[R], obj_id: str) -> R:
        log.debug("获取 %s", obj_id)
        obj = deser(obj_type, await self.connection.select(obj_id))
        log.debug("找到 %s", obj)
        return obj

    async def run_query(self, obj_type: type[R], query: str, **params) -> list[R]:
        log.debug("运行查询 %s,参数为 %s", query, params)
        try:
            results = (await self.connection.query(query, params))[-1]["result"]
        except (IndexError, KeyError) as e:
            raise NoResultError(query) from e
        else:
            log.debug("找到 %s", results)
            return deser(list, results)

# 用法
db = DatabaseConnection()
await db.asetup()
results = await db.run_query(obj_type, query, **params)
await db.ateardown()

Please note that the translated code retains the same structure and variable names as in the original code.

英文:

What about making a class to handle the connection?

class DatabaseConnection:
def __init__(self):
self.connection = None
async def asetup(self):
log.info("Setting up SurrealDB database...")
self.connection = Surreal("ws://localhost:8000/rpc")
await self.connection.connect()
await self.connection.signin({"user": secrets['db_username'], "pass": secrets['db_password']})
await self.connection.use("foo", "bar")
log.info("Database setup complete!")
async def ateardown(self):
log.info("Closing SurrealDB database...")
await self.connection.close()
log.info("Database closed!")
async def get(self, obj_type: type[R], obj_id: str) -> R:
log.debug("Getting %s", obj_id)
obj = deser(obj_type, await self.connection.select(obj_id))
log.debug("Found %s", obj)
return obj
async def run_query(self, obj_type: type[R], query: str, **params) -> list[R]:
log.debug("Running query %s with params %s", query, params)
try:
results = (await self.connection.query(query, params))[-1]["result"]
except (IndexError, KeyError) as e:
raise NoResultError(query) from e
else:
log.debug("Found %s", results)
return deser(list, results)
# Usage
db = DatabaseConnection()
await db.asetup()
results = await db.run_query(obj_type, query, **params)
await db.ateardown()

huangapple
  • 本文由 发表于 2023年5月14日 04:03:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76244664.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定