python - 我在调整旧模块以使 sopel 与 python 3.7 不和谐运行时遇到问题
问题描述
我一直在努力将 python 3.2 模块迁移到 3.7,以便我可以将我的 Sopel 机器人带到 Discord。我目前遇到的问题是我的功能有RuntimeError: set_wakeup_fd only works in main thread
错误setup(bot)
。
我尝试asyncio
在函数内部创建一个循环,但是它只遍历通道连接,并没有做太多其他事情。我知道我遗漏了一些明显的东西,但我过去几天的研究似乎都没有真正解决它。由于这不是我的代码,而且我仍然是一个相当新的 python 人,其中一些似乎并没有真正映射到我,因此我无法修复它。
这是代码:
# -*- coding: utf-8 -*-
#pylint: disable = C0103, C0116, C0115, C0114, R0903
from __future__ import (
unicode_literals,
absolute_import,
division,
print_function
)
import asyncio
import threading
import re
from sopel import module
from sopel.config.types import (
StaticSection, ValidatedAttribute, BaseValidated, NO_DEFAULT
)
from sopel.tools import get_input
import discord
import requests
from requests.exceptions import HTTPError
discord_api_url = 'https://discordapp.com/api'
client = discord.Client()
valid_message_pattern = r'^(?![.!?]\s*\w+)'
@client.event
async def on_ready():
print('Logged into Discord as')
print(client.user.name)
print(client.user.id)
print('----')
@client.event
async def on_message(message):
content = message.clean_content
if message.channel.id in client.channel_mappings \
and not message.author.bot \
and re.match(valid_message_pattern, content):
irc_channel = client.channel_mappings[message.channel.id]
content = re.sub(r'<(:\w+:)\d+>', r'\1', content)
if message.attachments:
extra = []
if content:
extra.append(content)
for attachment in message.attachments:
extra.append(attachment.get('url'))
content = ' '.join(extra)
content = content.replace('\n', ' ').strip()
if content:
if re.match(r'^_.+_$', content) and not message.attachments:
# Discord uses markdown italics to denote /me action messages
irc_message = '{} {}'.format(
message.author.name,
content[1:-1]
)
client.irc_bot.action(irc_message, irc_channel)
else:
irc_message = '<{}> {}'.format(message.author.name, content)
client.irc_bot.msg(irc_channel, irc_message)
class DictAttribute(BaseValidated):
'''Config attribute containing a list of key: value pairs.
Key: value pairs are saved to the file as a comma-separated list.
The spaces before and after each item are stripped.
'''
def __init__(self, name, default=None):
default = default or {}
super(DictAttribute, self).__init__(name, default=default)
def parse(self, value):
pairs = value.split(',')
value = {}
for item in pairs:
k, v = item.split(':')
value[k.strip()] = v.strip()
return value
def serialize(self, value):
if not isinstance(value, dict):
raise ValueError('DictAttribute value must be a dict')
return ','.join(['{}:{}'.format(k, v) for k, v in value.items()])
def configure(self, prompt, default, parent, section_name):
each_prompt = '?'
if isinstance(prompt, tuple):
each_prompt = prompt[1]
prompt = prompt[0]
if default is not NO_DEFAULT:
prompt = '{} [{}]'.format(prompt, default)
else:
default = ''
values = []
value = get_input(each_prompt + ' ') or default
while value:
values.append(value)
value = get_input(each_prompt + ' ')
return self.parse(','.join(values))
class DiscordSection(StaticSection):
discord_token = ValidatedAttribute('discord_token')
channel_mappings = DictAttribute('channel_mappings')
def _setup_webhooks(bot):
bot.memory['webhooks'] = {}
headers = {
'Authorization': 'Bot {}'.format(bot.config.discord.discord_token)
}
for k, channel_id in bot.memory['channel_mappings'].items():
try:
r = requests.get(
'{}/channels/{}/webhooks'.format(discord_api_url, channel_id),
headers=headers
)
bot.memory['webhooks'][channel_id] = {}
r.raise_for_status()
for hook in r.json():
if hook['name'] == 'discord-irc':
bot.memory['webhooks'][channel_id] = hook
if not bot.memory['webhooks'][channel_id]:
payload = {'name': 'discord-irc'}
r = requests.post(
'{}/channels/{}/webhooks'.format(
discord_api_url,
channel_id
),
headers=headers,
json=payload
)
r.raise_for_status()
bot.memory['webhooks'][channel_id] = r.json()
except HTTPError as e:
print('Could not access webhook API for channel {}.'.format(
channel_id))
print('Make sure the bot user has the "Manage webhooks" permission'
'on the specified discord channel.')
print(e)
def configure(config):
config.define_section('discord', DiscordSection)
config.discord.configure_setting(
'discord_token',
'Discord token for the app bot user'
)
config.discord.configure_setting(
'channel_mappings',
('Comma-separated list of Discord channel to IRC channel mappings'
' (ex: #discord-channel1: #irc-channel1,'
' #discord-channel2: #irc-channel2)')
)
def setup(bot):
bot.config.define_section('discord', DiscordSection)
client.irc_bot = bot
client.channel_mappings = bot.config.discord.channel_mappings
print(client.channel_mappings)
# config order maps discord: IRC, invert the map for the IRC bot
bot.memory['channel_mappings'] = {
v: k for k, v in client.channel_mappings.items()
}
_setup_webhooks(bot)
# only start the asyncio thread once (the discord thread can survive sopel
# restarts)
if not asyncio.get_event_loop().is_running():
targs = (bot.config.discord.discord_token,)
t = threading.Thread(target=client.run, args=targs)
t.start()
# Match all messages except for those which start with common bot command
# prefixes
@module.require_chanmsg
@module.rule(valid_message_pattern)
def irc_message(bot, trigger):
if not trigger.is_privmsg \
and trigger.sender in bot.memory['channel_mappings']:
discord_channel = bot.memory['channel_mappings'][trigger.sender]
hook = bot.memory['webhooks'].get(discord_channel, {})
if hook:
headers = {
'Authorization': 'Bot {}'.format(
bot.config.discord.discord_token)
}
content = trigger.match.string
if trigger.tags.get('intent') == 'ACTION':
content = '_{}_'.format(content)
payload = {
'content': content,
'username': '{} (IRC)'.format(trigger.nick),
}
try:
r = requests.post('{}/webhooks/{}/{}'.format(
discord_api_url, hook['id'], hook['token']
),
headers=headers,
json=payload,
)
r.raise_for_status()
except HTTPError as e:
pass
编辑以添加回溯:
Traceback (most recent call last):
File "/usr/lib/python3.7/asyncio/unix_events.py", line 92, in add_signal_handler
signal.set_wakeup_fd(self._csock.fileno())
ValueError: set_wakeup_fd only works in main thread
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.7/threading.py", line 926, in _bootstrap_inner
self.run()
File "/usr/lib/python3.7/threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "/home/junya/.local/lib/python3.7/site-packages/discord/client.py", line 614, in run
loop.add_signal_handler(signal.SIGINT, lambda: loop.stop())
File "/usr/lib/python3.7/asyncio/unix_events.py", line 94, in add_signal_handler
raise RuntimeError(str(exc))
RuntimeError: set_wakeup_fd only works in main thread
解决方案
我放弃了,开始从头开始重新编码。试图将 sopel 机器人与不和谐联系起来太麻烦了,我已经完成了重写。
推荐阅读
- asp.net - Visual Studio:新安装后的智能感知问题
- html - 网格在 HTML CSS 中制作盒子?
- mongodb - MopngoDb 单节点副本集与 docker 容器
- mpandroidchart - 如何在数据中定位MPandroid图表条形图的数据标签
- string - Scala通过反引号拆分字符串
- c# - 无法在 macOS Monterey 上启动 Kestrel
- node.js - mongoose - 我想查找包含嵌套引用的文档?
- c++ - 如何在不同的框架中重新发布里程计?
- web - Web OTP 中是否支持传输“电子邮件”?
- typescript - web3Modal 在初始化 web3Modal 实例时给出“未定义窗口”错误