英文:
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()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论