Как я могу исправить эту ошибку, работая с клиентом Discord и asyncio? - PullRequest
0 голосов
/ 07 ноября 2019

Короче говоря, я новичок в API и асинхронном программировании. Я пытаюсь создать бота Discord, который публикует статус вашей платформы Steam на экране состояния бота (по крайней мере, на данный момент), но я получаю эту ошибку, когда запускаю Discord_Bot.py. Не знаю, что это значит и почему, но это касается меня, потому что ошибка, кажется, найдена в одном из файлов Discord (который я не написал).

Сначала я получил эту ошибку сразу после запуска Discord_Bot.py:

 Ignoring exception in on_ready
Traceback (most recent call last):
  File "C:\Users\Mira\Anaconda3\lib\site-packages\discord\client.py", line 307, in _run_event
    yield from getattr(self, event)(*args, **kwargs)
TypeError: on_ready() missing 1 required positional argument: 'self'


  File "C:\Users\USER\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 705, in runfile
    execfile(filename, namespace)

  File "C:\Users\USER\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 102, in execfile
    exec(compile(f.read(), filename, 'exec'), namespace)

  File "C:/Users/USER/Documents/GitHub/Discord_Steam_Interface/Discord_Bot.py", line 83, in <module>
    b.run_the_bot()

  File "C:/Users/USER/Documents/GitHub/Discord_Steam_Interface/Discord_Bot.py", line 75, in run_the_bot
    self.client.run(self.__BOT_TOKEN)

  File "C:\Users\USER\Anaconda3\lib\site-packages\discord\client.py", line 534, in run
    self.loop.close()

  File "C:\Users\USER\Anaconda3\lib\asyncio\selector_events.py", line 107, in close
    raise RuntimeError("Cannot close a running event loop")

RuntimeError: Cannot close a running event loop

Затем я применил патч nest_asyncio, который можно найти здесь: https://github.com/erdewit/nest_asyncio

Это, похоже, решило проблему, так как я больше не получил 'RuntimeError: Не удается закрытьОшибка запуска цикла обработки событий сразу после запуска скрипта. Однако сейчас я замечаю, что, если я оставлю его на 5 минут, он появится снова. Кроме того, ошибка ниже продолжает появляться сразу после запуска скрипта. Я в пути над своей головой, помогите?

Ignoring exception in on_ready
Traceback (most recent call last):
  File "C:\Users\USER\Anaconda3\lib\site-packages\discord\client.py", line 307, in _run_event
    yield from getattr(self, event)(*args, **kwargs)
TypeError: on_ready() missing 1 required positional argument: 'self'

Вот Discord_Bot.py: (мой файл)

import time
import win32gui
import psutil
import subprocess
import discord
import asyncio
import get_steam_info
import nest_asyncio

# Applies a patch which allows asyncio's event loop to be nested. 
nest_asyncio.apply()

class Bot_handler():

    # Define the Client object for this session.
    client = discord.Client()

    def __init__(self, program_name, steam_id, api_key, bot_token):
        self.program_name = program_name
        self.process = self.program_name + '.exe'
        self.__program_running = self.get_program_running(self.process)
        self.__STEAM_ID = STEAM_ID
        self.__API_KEY = API_KEY
        self.__BOT_TOKEN = BOT_TOKEN

    def get_program_running(self, process_str):
        '''Determine whether the specified process_str is running.'''
        if process_str in (process.name() for process in psutil.process_iter()):
            self.__program_running = True
            print(self.program_name,"is currently running.")
        else:
            self.__program_running = False
            print(self.program_name,"is not currently running.")
        return self.__program_running

    @client.event
    async def on_ready(self):
        '''Called automatically when client is done preparing data from Discord.
        Schedules coroutine on_ready using Task client.loop.create_task.'''
        self.__client.loop.create_task(self.status_task())
        print('Logged in as')
        print(self.__client.user.name)
        print(self.__client.user.id)
        print('------')

    async def status_task(self):
        while True:
            if self.__program_running:
                self.__player_info = get_steam_info.get_player_info(self.__API_KEY, self.__STEAM_ID)
                self.__player_status = get_steam_info.get_player_status(self.__player_info)
                self.__ingame = get_steam_info.get_ingame_name(self.__player_info)

                if self.__ingame:
                    await self.__client.change_presence(status = discord.Status.online, game = discord.Game(name = str(self.__ingame)), afk=False)
                    await asyncio.sleep(3)
                else:
                    await self.__client.change_presence(status = discord.Status.dnd, game = discord.Game(name = 'nothing at the moment'))
                    await asyncio.sleep(3)
            else:
                self.get_active_window()

    def get_active_window(self):
        '''Return the title of the active window as a string.'''
        self.__active_window = win32gui.GetWindowText(win32gui.GetForegroundWindow())
        return self.__active_window    

    def run_the_bot(self):
        # Activates the bot.
        self.client.run(self.__BOT_TOKEN)


PROGRAM_NAME = 'Steam'

# Real values are present in the code 
STEAM_ID = 'ZZZZZZZZZ'
API_KEY = 'XXXXXXXX'
BOT_TOKEN = 'YYYYYYYYYY'       
b = Bot_handler(PROGRAM_NAME, STEAM_ID, API_KEY, BOT_TOKEN)
b.run_the_bot()

get_steam_info.py (мойфайл)

import requests

class Info_handler():
    '''Keep track of a player's information in real time.'''
    def __init__(self, steam_ID, API_key):

        self.__steam_ID = steam_ID
        self.__API_key = API_key        
        self.__API_url = 'https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/?key=' \
        + self.__API_key +'&steamids=' + self.__steam_ID
        self.statuslist = {0: 'offline', 1: 'online', 3: 'dnd', 4: 'idle', 5: 'idle', 6: 'online', 7: 'online'}
        # call status

        # profile_url = 'https://steamcommunity.com/profiles/' + steam_ID

        self.__player_info = self.get_player_info()
        self.__player_status = self.get_player_status(self.__player_info)

    def get_player_info(self):
        '''Returns a dict containing Steam information for one player using the
        Steam API. Requires the desired player's user ID and a valid API key.'''
        self.response = requests.get(self.__API_url)

        if self.response.status_code != 200:
            raise Exception('Request unsuccessful; returned code ' + str(self.response.status_code) \
            + ': ' + str(requests.status_codes._codes[self.response.status_code][0]))
        else:
            print('Success! API responded to call.')
            self.__player_info = self.response.json()['response']['players'][0]
        return self.__player_info

    def get_player_status(self, player_info_dict):
        '''Returns the player's Steam status as a Discord status type.

        STEAM STATUS        | STEAM STATE | DISCORD STATUS
        'Offline'           |      0      | 'Offline'
        'Online'            |      1      | 'Online'
        'Busy'              |      2      | 'dnd'
        'Away'              |      3      | 'Idle'
        'Snooze'            |      4      | 'Idle'
        'Looking to trade'  |      5      | 'Online'
        'Looking to play'   |      6      | 'Online'
        '''
        self.__steam_state = player_info_dict['personastate']

        self.__player_status = self.statuslist[self.__steam_state]
        return self.__player_status

# Is it better to use 'self.__steam_state' since when this variable will never 
# called outside the function? Or shall I use simply 'steam_state?'

    def get_ingame_name(self, player_info_dict):
        '''Returns the name of the Steam game player is playing. 
        If player is logged into Steam, but not currently playing anything,
        return False.'''
        self.__player_name = player_info_dict['personaname']
        try:
            self.__game = player_info_dict['gameextrainfo']
            print('Player ',self.__player_name,' is playing ',self.__game,'.',sep='')
            return self.__game
        except KeyError:  
            print('Player',self.__player_name,'is not currently in a game.')
            return False

    def get_player_name(self):
        return self.__player_name

steam_ID = 'ZZZZZZZZZ'
API_key = 'XXXXXXXX'

instance = Info_handler(steam_ID, API_key)
info = instance.get_player_info()
print(info)
status = instance.get_player_status(info)
print(status)
game = instance.get_ingame_name(info)
print(game)
...