commands.HelpCommand implementation - python

I'm trying to customize the !help command of my Discord bot using commands.HelpCommand, but I'm note sure to understand how it works.
My actual (minimal) code is the following:
bot.remove_command("help")
#bot.command()
async def help(ctx, *, command=None):
hc = commands.HelpCommand()
await hc.command_callback(ctx, command=command)
But I encounter this exception:
Traceback (most recent call last):
File "[...]/bot.py", line 229, in help
await hc.command_callback(ctx, command=command)
File "[...]/python3.8/site-packages/discord/ext/commands/help.py", line 782, in command_callback
mapping = self.get_bot_mapping()
File "[...]/python3.8/site-packages/discord/ext/commands/help.py", line 331, in get_bot_mapping
bot = self.context.bot
AttributeError: 'NoneType' object has no attribute 'bot'
I understand that HelpCommand.command_callback needs HelpCommand.context to be set... but the doc states that
This (context) is generally set after the help command assigned, command_callback(), has been called.
That sounds like a bug for me, but I'm not sure to fully understand how to implement HelpCommand...
I tried to move it into a cog, to pass context=ctx to HelpCommand during initialization and other things, without success.
Any idea?
Thanks in advance!

Okay, if it can help anyone, I just noticed the help_command parameter of commands.Bot...
You just have to pass it your HelpCommand instance!
No need to do any tricky workaround, I was indeed misunderstanding things.

Related

Nextcord: How to pass unknown number of variable to subcommand

I'm trying to make a discord bot using subcommand,
it works fine when I do like below:
#admin.subcommand(description="Publish annoucement embed message")
async def annoucement(self, interaction: nextcord.Interaction, announce: str):
print(announce)
But since I want to input unknown number of variable to this function,
I changed my code as below:
#admin.subcommand(description="Publish annoucement embed message")
async def annoucement(self, interaction: nextcord.Interaction, *annouce):
for i in annouce:
print(i)
but after that, it shows error as below:
Ignoring exception in command <nextcord.application_command.SlashApplicationSubcommand object at
0x0000023604828D90>:
Traceback (most recent call last):
Python\Python310\site-packages\nextcord\application_command.py", line 848, in invoke_callback_with_hooks await self(interaction, *args, **kwargs)
Python\Python310\site-packages\nextcord\application_command.py", line 606, in call
return self.callback(self.parent_cog, interaction, *args, **kwargs)
TypeError: Admin_CMD.annoucement() got an unexpected keyword argument 'annouce'
The above exception was the direct cause of the following exception:
nextcord.errors.ApplicationInvokeError: Command raised an exception: TypeError: Admin_CMD.annoucement() got an unexpected keyword argument 'annouce'
I already found a workaround by passing whole string with split character and split them in the
function(ex:str1&str2&str3&...).
But I still want to know what's wrong with my code, and is there a way to pass unkown number of
variable to the subcommand function?

AttributeError: 'list' object has no attribute 'expandtabs'

So, to start, I was making a discord bot (using discord.py) and making a help command, but it shows an error when I run the python file
I have no idea what was going on about this... (\n didn't cause the problem)
code (new one):
#client.command(aliases=["commands","cmds"], description="Get command list")
async def help(ctx):
embed = discord.Embed(title="Commands",description="List of the bot's commands",color=0xFF0000)
for commands in client.commands:
embed.add_field(name=commands,value=commands.description)
await ctx.send(embed)
and full error message:
Traceback (most recent call last):
File "C:\Users\Name\Documents\Codes\Python\bot.py", line 19, in <module>
File "C:\Users\Name\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 1262, in decorator
result = command(*args, **kwargs)(func)
File "C:\Users\Name\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 1433, in decorator
return cls(func, name=name, **attrs)
File "C:\Users\Name\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 244, in __init__
self.description = inspect.cleandoc(kwargs.get('description', ''))
File "C:\Users\Name\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 632, in cleandoc
lines = doc.expandtabs().split('\n')
AttributeError: 'list' object has no attribute 'expandtabs'
would be nice if someone could help me
also, this is my first post (and I'm new here) so I don't know much about Stack Overflow
(PS: I have client.help_command = None in my code, thanks Kermit)
The description argument takes a string, not a list. So, it should look like this:
#client.command(aliases=["commands","cmds"], description="Get command list")
Also, make sure you have client.help_command = None somewhere in your code, so that the default help command provided by discord.py can be overridden.
The immediate issue is that the description kwarg of the command decorator is being given a list when it expects a string, which can be found out from the Command documentation.
However more importantly, as it appears you're trying to create your own help command, that is not the recommended way to do so since you forgo the advantages of the existing HelpCommand framework that handles argument parsing for you. If you need help with using it, check out this guide which goes through subclassing and adding it to your bot.
Sidenote: for future questions, please provide the full error message so it's easier for other users to debug.

Python3.6 AttributeError: module 'asyncio' has no attribute 'run'

I tried to read https://hackernoon.com/asynchronous-python-45df84b82434.
It's about asynchronous python and I tried the code from this, but I'm getting a weird Error.
The code is:
`
import asyncio
import aiohttp
urls = ['http://www.google.com', 'http://www.yandex.ru', 'http://www.python.org']
async def call_url(url):
print('Starting {}'.format(url))
response = await aiohttp.ClientSession().get(url)
data = await response.text()
print('{}: {} bytes: {}'.format(url, len(data), data))
return data
futures = [call_url(url) for url in urls]
asyncio.run(asyncio.wait(futures))
When I try to run it says:
Traceback (most recent call last):
File "test.py", line 15, in <module>
asyncio.run(asyncio.wait(futures))
AttributeError: module 'asyncio' has no attribute 'run'
sys:1: RuntimeWarning: coroutine 'call_url' was never awaited
I dont have any files named ayncio and I have proof:
>>> asyncio
<module 'asyncio' from '/usr/lib/python3.6/asyncio/__init__.py'>
asyncio.run is a Python 3.7 addition. In 3.5-3.6, your example is roughly equivalent to:
import asyncio
futures = [...]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(futures))
The asyncio.run() function was added in Python 3.7. From the asyncio.run() function documentation:
New in version 3.7: Important: this function has been added to asyncio in Python 3.7 on a provisional basis.
Note the provisional part; the Python maintainers forsee that the function may need further tweaking and updating, so the API may change in future Python versions.
At any rate, you can't use it on Python 3.6. You'll have to upgrade or implement your own.
A very simple approximation would be to use loop.run_until_complete():
loop = asyncio.get_event_loop()
result = loop.run_until_complete(coro)
although this ignores handling remaining tasks that may still be running. See the asyncio.runners source code for the complete asyncio.run() implementation.
Just in case this is useful to someone else but for me the issue was my file was called asyncio.py. I renamed it to asyncio_example.py and it started to work again (it was failing at the import statement for asyncio).
This issue helped me realize this: https://github.com/tornadoweb/tornado/issues/2868
If anyone is having a problem with no current loop try:
loop = asyncio.**new**_event_loop()
result = loop.run_until_complete(coro)

Discord.py check if input is int

I am trying to write a raffle command for my bot using discord.py and want it so the user can do the following command to start a raffle:
!raffle time winners title EG: !raffle 60 1 Pie
The issue I am having is creating validation to check that the first two inputs are numbers and that the title isn't blank. Currently this is the code I have for the command:
#bot.command(pass_context=True)
async def raffle(ctx, time, winners, title):
if time != int or winners != int or title != "":
await bot.say("{} raffle has been started for {} seconds and there will be {} winner(s)!".format(title, time, winners))
else:
await bot.say("Seems you went wrong! Raffle format is: !raffle time winners title")
return
However I am having no luck and am getting the following error:
Ignoring exception in command raffle
Traceback (most recent call last):
File "C:\Users\kairj\AppData\Local\Programs\Python\Python36-32\lib\site-packages\discord\ext\commands\bot.py", line 846, in process_commands
yield from command.invoke(ctx)
File "C:\Users\kairj\AppData\Local\Programs\Python\Python36-32\lib\site-packages\discord\ext\commands\core.py", line 367, in invoke
yield from self.prepare(ctx)
File "C:\Users\kairj\AppData\Local\Programs\Python\Python36-32\lib\site-packages\discord\ext\commands\core.py", line 345, in prepare
yield from self._parse_arguments(ctx)
File "C:\Users\kairj\AppData\Local\Programs\Python\Python36-32\lib\site-packages\discord\ext\commands\core.py", line 304, in _parse_arguments
transformed = yield from self.transform(ctx, param)
File "C:\Users\kairj\AppData\Local\Programs\Python\Python36-32\lib\site-packages\discord\ext\commands\core.py", line 212, in transform
raise MissingRequiredArgument('{0.name} is a required argument that is missing.'.format(param))
discord.ext.commands.errors.MissingRequiredArgument: time is a required argument that is missing.
Any help would be great as I am sure its a simple mistake somewhere!
Thanks in advance
What you are defining is actually two checks. The first is that you want to ensure there are 3 arguments to your command, and the second is to ensure that the first two are ints.
The first one is actually handled by ext.commands internally. To catch it, you will need to define an on_command_error event method.
#bot.event
def on_command_error(exc, ctx):
if isinstance(exc, commands.errors.MissingRequiredArgument):
# Send a message here
return
# If nothing is caught, reraise the error so that it goes to console.
raise exc
The second is checking the ints, which as #Luke McPuke said is simply
if not isinstance(time, int)
Try using isinstance instead:
if not isinstance(time, int)

GetAuthSubToken returns None

Hey guys, I am a little lost on how to get the auth token. Here is the code I am using on the return from authorizing my app:
client = gdata.service.GDataService()
gdata.alt.appengine.run_on_appengine(client)
sessionToken = gdata.auth.extract_auth_sub_token_from_url(self.request.uri)
client.UpgradeToSessionToken(sessionToken)
logging.info(client.GetAuthSubToken())
what gets logged is "None" so that does seem right :-(
if I use this:
temp = client.upgrade_to_session_token(sessionToken)
logging.info(dump(temp))
I get this:
{'scopes': ['http://www.google.com/calendar/feeds/'], 'auth_header': 'AuthSub token=CNKe7drpFRDzp8uVARjD-s-wAg'}
so I can see that I am getting a AuthSub Token and I guess I could just parse that and grab the token but that doesn't seem like the way things should work.
If I try to use AuthSubTokenInfo I get this:
Traceback (most recent call last):
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/__init__.py", line 507, in __call__
handler.get(*groups)
File "controllers/indexController.py", line 47, in get
logging.info(client.AuthSubTokenInfo())
File "/Users/matthusby/Dropbox/appengine/projects/FBCal/gdata/service.py", line 938, in AuthSubTokenInfo
token = self.token_store.find_token(scopes[0])
TypeError: 'NoneType' object is unsubscriptable
so it looks like my token_store is not getting filled in correctly, is that something I should be doing?
Also I am using gdata 2.0.9
Thanks
Matt
To answer my own question:
When you get the Token just call:
client.token_store.add_token(sessionToken)
and App Engine will store it in a new entity type for you. Then when making calls to the calendar service just dont set the authsubtoken as it will take care of that for you also.

Categories