I just updated to Python 3.5 (plus a lot of other things, so this might be a library problem) and this function stopped working:
@mybot.command(help="Posts an xkcd comic and hovertext")
async def xkcd(number:str=""):
page = requests.get('http://xkcd.com/{}'.format(number))
tree = html.fromstring(page.content)
comic = tree.xpath('//div[@id="comic"]/img/attribute::src')[0]
hover = tree.xpath('//div[@id="comic"]/img/attribute::title')[0]
comic = requests.get("http:{}".format(comic))
await mybot.upload(comic.content, "xkcd-{}.png".format(number))
await mybot.say("_{}_".format(hover))
it now gives:
Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/discord/client.py", line 283, in _run_event
yield from getattr(self, event)(*args, **kwargs)
File "/usr/local/lib/python3.5/dist-packages/discord/ext/commands/bot.py", line 601, in on_message
yield from self.process_commands(message)
File "/usr/local/lib/python3.5/dist-packages/discord/ext/commands/bot.py", line 593, in process_commands
yield from command.invoke(ctx)
File "/usr/local/lib/python3.5/dist-packages/discord/ext/commands/core.py", line 342, in invoke
yield from injected(*ctx.args, **ctx.kwargs)
File "/usr/local/lib/python3.5/dist-packages/discord/ext/commands/core.py", line 46, in wrapped
ret = yield from coro(*args, **kwargs)
File "mybot.py", line 215, in xkcd
await mybot.upload(comic.content, "xkcd-{}.png".format(number))
File "/usr/local/lib/python3.5/dist-packages/discord/ext/commands/bot.py", line 296, in upload
result = yield from self.send_file(destination, fp, name)
File "/usr/local/lib/python3.5/dist-packages/discord/client.py", line 1072, in send_file
with open(fp, 'rb') as f:
ValueError: embedded null byte
I think this is because send_file doesn't catch the ValueError and thus interpret the fp parameter as a file-like object.
I think your issue is that comic.content is a string or bytes (or anything that isn't a file object), and thus is assumed to be a filename. You will need to wrap it in an something that acts like a file object rather than a string (for example, use SrtingIO or BytesIO: https://docs.python.org/3/library/io.html#io.BytesIO )
Ah, yeah, it was bytes. Wrapping it in BytesIO solved the issue, thanks. I do wonder why it worked before, then...
Most helpful comment
I think your issue is that
comic.contentis a string or bytes (or anything that isn't a file object), and thus is assumed to be a filename. You will need to wrap it in an something that acts like a file object rather than a string (for example, use SrtingIO or BytesIO: https://docs.python.org/3/library/io.html#io.BytesIO )