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

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

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

问题

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

  1. @dataclass
  2. class NoResultError(Exception):
  3. """上一次查询没有返回结果。"""
  4. query: str = None
  5. @dataclass
  6. class Resource:
  7. # SNIP
  8. async def store(self):
  9. """将对象存储到数据库中。"""
  10. global connection
  11. log.debug("正在存储 %s", self)
  12. if old := await get(self.__class__, self.id):
  13. old_ser = ser(old)
  14. differences = {k: v for k, v in ser(self).items() if v != old_ser[k]}
  15. record = await connection.update(self.id, data=differences)
  16. log.debug("已更新 %s", record)
  17. else:
  18. record = await connection.create(self.id, data=ser(self))
  19. log.debug("已插入 %s", record)
  20. async def asetup():
  21. """连接并对本地数据库进行身份验证。"""
  22. global connection
  23. log.info("正在设置 SurrealDB 数据库...")
  24. connection = Surreal("ws://localhost:8000/rpc")
  25. await connection.connect()
  26. await connection.signin({"user": secrets['db_username'], "pass": secrets['db_password']})
  27. await connection.use("foo", "bar")
  28. log.info("数据库设置完成!")
  29. def setup():
  30. t = asyncio.get_event_loop().run_until_complete(asetup())
  31. async def ateardown():
  32. global connection
  33. log.info("正在关闭 SurrealDB 数据库...")
  34. await connection.close()
  35. log.info("数据库已关闭!")
  36. def teardown(bot: discord.Bot):
  37. t = asyncio.get_event_loop().run_until_complete(ateardown())
  38. # SNIP
  39. async def get(obj_type: type[R], obj_id: str) -> R:
  40. global connection
  41. assert (
  42. obj_type.__name__ == obj_id.split(":")[0]
  43. ), "该对象ID与预期类型不匹配."
  44. log.debug("正在获取 %s", obj_id)
  45. obj = deser(obj_type, await connection.select(obj_id))
  46. log.debug("已找到 %s", obj)
  47. return obj
  48. async def run_query(obj_type: type[R], query: str, **params) -> list[R]:
  49. """对数据库运行查询,并返回查询结果中的最后一行。"""
  50. global connection
  51. log.debug("正在运行查询 %s,参数 %s", query, params)
  52. try:
  53. results = (await connection.query(query, params))[-1]["result"]
  54. except (IndexError, KeyError) as e:
  55. raise NoResultError(query) from e
  56. else:
  57. log.debug("已找到 %s", results)
  58. 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:

  1. @dataclass
  2. class NoResultError(Exception):
  3. """No results were returned from the last line of a query."""
  4. query: str = None
  5. @dataclass
  6. class Resource:
  7. # SNIP
  8. async def store(self):
  9. """Stores the object in the database."""
  10. global connection
  11. log.debug("Storing %s", self)
  12. if old := await get(self.__class__, self.id):
  13. old_ser = ser(old)
  14. differences = {k: v for k, v in ser(self).items() if v != old_ser[k]}
  15. record = await connection.update(self.id, data=differences)
  16. log.debug("Updated %s", record)
  17. else:
  18. record = await connection.create(self.id, data=ser(self))
  19. log.debug("Inserted %s", record)
  20. async def asetup():
  21. """Connects and authenticates with the local database."""
  22. global connection
  23. log.info("Setting up SurrealDB database...")
  24. connection = Surreal("ws://localhost:8000/rpc")
  25. await connection.connect()
  26. await connection.signin({"user": secrets['db_username'], "pass": secrets['db_password']})
  27. await connection.use("foo", "bar")
  28. log.info("Database setup complete!")
  29. def setup():
  30. t = asyncio.get_event_loop().run_until_complete(asetup())
  31. async def ateardown():
  32. global connection
  33. log.info("Closing SurrealDB database...")
  34. await connection.close()
  35. log.info("Database closed!")
  36. def teardown(bot: discord.Bot):
  37. t = asyncio.get_event_loop().run_until_complete(ateardown())
  38. # SNIP
  39. async def get(obj_type: type[R], obj_id: str) -> R:
  40. global connection
  41. assert (
  42. obj_type.__name__ == obj_id.split(":")[0]
  43. ), "That object ID does not match the expected type."
  44. log.debug("Getting %s", obj_id)
  45. obj = deser(obj_type, await connection.select(obj_id))
  46. log.debug("Found %s", obj)
  47. return obj
  48. async def run_query(obj_type: type[R], query: str, **params) -> list[R]:
  49. """Runs a query against the database, and returns the results from the last line.
  50. Args:
  51. obj_type (Type[R]): The object type to expect.
  52. query (str): The query to run.
  53. **params: Parameters to use in the query.
  54. Returns:
  55. list[R]: A list of objects returned from the last line of the query.
  56. Raises:
  57. NoResultError: No results or an error was returned from the last line.
  58. """
  59. global connection
  60. log.debug("Running query %s with params %s", query, params)
  61. try:
  62. results = (await connection.query(query, params))[-1]["result"]
  63. except (IndexError, KeyError) as e:
  64. raise NoResultError(query) from e
  65. else:
  66. log.debug("Found %s", results)
  67. 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:

  1. ...in run_query
  2. results = (await connection.query(query, params))[-1]["result"]
  3. ^^^^^^^^^^
  4. 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:

  1. 关于创建一个处理连接的类怎么样
  2. class DatabaseConnection:
  3. def __init__(self):
  4. self.connection = None
  5. async def asetup(self):
  6. log.info("设置 SurrealDB 数据库中...")
  7. self.connection = Surreal("ws://localhost:8000/rpc")
  8. await self.connection.connect()
  9. await self.connection.signin({"user": secrets['db_username'], "pass": secrets['db_password']})
  10. await self.connection.use("foo", "bar")
  11. log.info("数据库设置完成!")
  12. async def ateardown(self):
  13. log.info("关闭 SurrealDB 数据库中...")
  14. await self.connection.close()
  15. log.info("数据库已关闭!")
  16. async def get(self, obj_type: type[R], obj_id: str) -> R:
  17. log.debug("获取 %s", obj_id)
  18. obj = deser(obj_type, await self.connection.select(obj_id))
  19. log.debug("找到 %s", obj)
  20. return obj
  21. async def run_query(self, obj_type: type[R], query: str, **params) -> list[R]:
  22. log.debug("运行查询 %s,参数为 %s", query, params)
  23. try:
  24. results = (await self.connection.query(query, params))[-1]["result"]
  25. except (IndexError, KeyError) as e:
  26. raise NoResultError(query) from e
  27. else:
  28. log.debug("找到 %s", results)
  29. return deser(list, results)
  30. # 用法
  31. db = DatabaseConnection()
  32. await db.asetup()
  33. results = await db.run_query(obj_type, query, **params)
  34. 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?

  1. class DatabaseConnection:
  2. def __init__(self):
  3. self.connection = None
  4. async def asetup(self):
  5. log.info("Setting up SurrealDB database...")
  6. self.connection = Surreal("ws://localhost:8000/rpc")
  7. await self.connection.connect()
  8. await self.connection.signin({"user": secrets['db_username'], "pass": secrets['db_password']})
  9. await self.connection.use("foo", "bar")
  10. log.info("Database setup complete!")
  11. async def ateardown(self):
  12. log.info("Closing SurrealDB database...")
  13. await self.connection.close()
  14. log.info("Database closed!")
  15. async def get(self, obj_type: type[R], obj_id: str) -> R:
  16. log.debug("Getting %s", obj_id)
  17. obj = deser(obj_type, await self.connection.select(obj_id))
  18. log.debug("Found %s", obj)
  19. return obj
  20. async def run_query(self, obj_type: type[R], query: str, **params) -> list[R]:
  21. log.debug("Running query %s with params %s", query, params)
  22. try:
  23. results = (await self.connection.query(query, params))[-1]["result"]
  24. except (IndexError, KeyError) as e:
  25. raise NoResultError(query) from e
  26. else:
  27. log.debug("Found %s", results)
  28. return deser(list, results)
  29. # Usage
  30. db = DatabaseConnection()
  31. await db.asetup()
  32. results = await db.run_query(obj_type, query, **params)
  33. 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:

确定