#๐Ÿ”’ Calculator issue with eval, big expressions

27 messages ยท Page 1 of 1 (latest)

proven trail
#

Okay, so I have a simple issue, I have a calculator command, which uses eval, how can I make my bot not crash when someone does 9^9^9^9 or maybe something bigger? I don't want a limit on it where they can only have this amount of exponents, but I want it to return a custom error if the eval failed, but I don't want my bot to go offline either, how can I prevent this?

    @discord.ui.button(label='=', style=discord.ButtonStyle.green, custom_id="=", row=4)
    async def equal(self, interaction: discord.Interaction, button: discord.ui.Button):
        if interaction.user.id != self.ctx.author.id:
            await interaction.response.send_message("This button isn't for you. Just run the command yourself goober.", ephemeral=True)
            return

        if interaction.user.id == self.ctx.author.id and not self.disabled:
            expression = self.value.replace('x', '*').replace('รท', '/').replace('^', '**')
            try:
                try:
                    result = str(eval(expression))
                    self.value = f"{self.value} = {result}"
                    self.clear_on_next_input = True
                except Exception:
                    self.value = "The provided equation is invalid!"
                    self.clear_on_next_input = True
            except ZeroDivisionError:
                self.value = 'Infinity'
                self.clear_on_next_input = True
            except Exception as e:
                self.value = "The provided equation is invalid!"
                self.clear_on_next_input = True
            embed = await self.update_embed(interaction)
            await interaction.response.edit_message(embed=embed, view=self)```
radiant juncoBOT
#

@proven trail

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

true pawn
#

My approach would be to run the evaluation in a separate process, which'd allow to kill it if it times out.

#

(threads can't be killed in such a way)

#

(It'd also make it more secure, if you use something that's not python's eval for the evaluation - e.g. some CLI calculator)

proven trail
#

Something like this, which makes the eval safe.

#

But I fixed it, its working now, using multiprocessing

tawdry charm
#

an alternative solution would be to write a custom evaluation engine for your expressions. it doesn't sound like you have to worry about parsing at all, so you could just build up the ast of the expression and then evaluate it, bailing out if the value goes over a certain number (like 2**64)

abstract pulsar
#

waiting for the moment when self.value = 'import os; os.system('<MALICIOUS_COMMAND>')

tawdry charm
#

you could also just make all your arithmetic be floating point

proven trail
#

it would be impossible

abstract pulsar
tawdry charm
#

now when you're writing it, but generally those sorts of things get introduced when someone's adding new features or refactoring and they either forget about or are unaware of the eval

graceful elm
proven trail
proven trail
tawdry charm
#

at the very least i'd write an assertion that all the characters in your string are [0-9()+*/%\.=] or perhaps [^a-zA-Z_]

true pawn
#

There's a library, py-expression-eval or something

proven trail
#

Okay so my solution was to just use an API for it

#
    @discord.ui.button(label='=', style=discord.ButtonStyle.green, custom_id="=", row=4)
    async def equal(self, interaction: discord.Interaction, button: discord.ui.Button):
        if interaction.user.id != self.ctx.author.id:
            await interaction.response.send_message("This button isn't for you. Just run the command yourself goober.",
                                                    ephemeral=True)
            return

        if interaction.user.id == self.ctx.author.id and not self.disabled:
            expression = self.value.replace('x', '*').replace('รท', '/').replace('+', '%2B')
            try:
                async with aiohttp.ClientSession() as session:
                    async with session.get(f'https://api.mathjs.org/v4/?expr={expression}') as response:
                        if response.status != 200:
                            self.value = "The provided equation is invalid!"
                            self.clear_on_next_input = True
                        else:
                            result = await response.text()
                            self.value = f"{self.value} = {result}"
                            self.clear_on_next_input = True
            except Exception as e:
                self.value = "The provided equation is invalid!"
                self.clear_on_next_input = True
            embed = await self.update_embed(interaction)
            await interaction.response.edit_message(embed=embed, view=self)```
#

The best way of doing it

#

!solved

radiant juncoBOT
#
Python help channel closed

This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.