Skip to content
This repository was archived by the owner on Dec 22, 2023. It is now read-only.

Added a telegram bot which runs python code #624

Merged
merged 6 commits into from
Oct 31, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Scripts/Bots/runPython_bot/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
token.txt
__pycache__
*.pyc
11 changes: 11 additions & 0 deletions Scripts/Bots/runPython_bot/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
hi:
@echo hi

requirements:
rm -rf venv
python3.8 -m venv venv
. venv/bin/activate && python3.8 -m pip install -r requirements.txt -U
clear

start:
. venv/bin/activate && python3.8 start.py
94 changes: 94 additions & 0 deletions Scripts/Bots/runPython_bot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# runPython_bot

Run python code from your telegram chat !

[![GitHub license](https://img.shields.io/github/license/aahnik/lovely-telegram)](https://github.com/aahnik/lovely-telegram/blob/main/LICENSE)
[![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg)](https://www.python.org/)
[![Maintenance Yes](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://gitHub.com/aahnik/REPO/graphs/commit-activity)

![RunPythonBot](https://user-images.githubusercontent.com/66209958/97750350-9d773d80-1b16-11eb-89a5-7626f5547a10.png)

<!-- A simple bot that runs python code. Free and Open Source. For more info visit http://bit.ly/runPython -->

## Find on Telegram

You can find this bot on Telegram: click on this [link](https://t.me/@runPython_bot) or search `@runPython_bot` on telegram. The spelling is case sensitive.

This bot is deployed on [Python Anywhere](https://www.pythonanywhere.com/) free Beginner Account.
You may check whether the bot is alive or not, by clicking on the start command. If the bot responds, it is alive.

## Example Use

You may use pythonic expressions to easily calculate any complex problem. Or you may test your algorithms on the go.

![runPython_bot](https://user-images.githubusercontent.com/66209958/97753037-1e383880-1b1b-11eb-863e-bcf82006820b.gif)

## Deploy

You can easily *deploy this bot* on [Python Anywhere](https://www.pythonanywhere.com/) or your **local machine** by following the below steps:

> Note: While pasting on your machine terminal you should use `Ctrl+Shift+V` but make sure to use `Ctrl+V` to paste in the Python Anywhere bash console from the browser.

Create a free Python Anywhere account and open a Bash Console, which has everything pre-loaded.

If you are planning to deploy on your **own machine**, make sure to have `Python3+`, `pip`, and `make`.

The following instructions will work smoothly on *Linux* and *Mac*. If you are on Windows, you may have to make slight modifications. Google is your best friend here.

- Create a `projects` directory and move into it

mkdir projects && cd projects

- Clone this repository containing the collection of bots

git clone https://github.com/aahnik/lovely-telegram.git

- Delete all other folders except the folder containing this bot

find ./lovely-telegram -mindepth 1 ! -regex '^./lovely-telegram/runPython_bot\(/.*\)?' -delete

- Now move into the directory which contains this README file, you are reading now.

cd lovely-telegram/runPython_bot

- Now add the token in the first line of `token.txt`.Run `cat > token.txt` -> Paste the token -> Press `Ctrl+D`

- To install all dependencies. Simply run `make requirements`

- Activate the bot by running `make start`

- You may now close the Python Anywhere bash console window from your browser, but the bot will continue running.

Your bot is now up and running, Enjoy ! 😊

To stop the bot, Press `Ctrl+C`. To restart the bot run `make start`

## Limitations

Currently, the bot is deployed on a Free Tier account of Python Anywhere.

For security and performance reasons, you **cannot** do the following with the bot:

- import any package
- run the `input()` function
- run the `open()` function
- Execute a piece of code which takes longer than 30 seconds to execute.

You may overcome these limitations by tweaking the code a little bit and running the bot on your own server.

## The Shameless Plug

Authored by **Aahnik Daw**.

You may connect with me by clicking on any of the icons below !

<a href = "https://medium.com/@aahnikdaw" > <img src = "https://github.com/aahnik/aahnik/blob/master/social_media_logos/medium.png?raw=true" alt = "medium" > </a >
<a href = "https://www.facebook.com/aahnik.daw" > <img src = "https://github.com/aahnik/aahnik/blob/master/social_media_logos/facebook.png?raw=true" alt = "facebook" > </a >
<a href = "https://www.linkedin.com/in/aahnik-daw-067a011b3/" > <img src = "https://github.com/aahnik/aahnik/blob/master/social_media_logos/linkedin.png?raw=true" alt = "linkedin" > </a >
<a href = "https://t.me/AahniKDaw" > <img src = "https://github.com/aahnik/aahnik/blob/master/social_media_logos/telegram.png?raw=true" alt = "telegram" > </a >
<a href = "https://twitter.com/AahnikD" > <img src = "https://github.com/aahnik/aahnik/blob/master/social_media_logos/twitter.png?raw=true" alt = "twitter" > </a >
<a href = "https://www.quora.com/profile/Aahnik-Daw" > <img src = "https://github.com/aahnik/aahnik/blob/master/social_media_logos/quora.png?raw=true" alt = "quora" > </a >
<a href = "https://www.youtube.com/channel/UCcEbN0d8iLTB6ZWBE_IDugg" > <img src = "https://github.com/aahnik/aahnik/blob/master/social_media_logos/youtube.png?raw=true" alt = "youtube" > </a >
<a href = "https://stackoverflow.com/users/13523305/aahnik-daw" > <img src = "https://github.com/aahnik/aahnik/blob/master/social_media_logos/stackOverflow.png?raw=true" alt = "stackOverflow" > </a >
<a href = "https://dev.to/aahnik" > <img src = "https://github.com/aahnik/aahnik/blob/master/social_media_logos/dev.png?raw=true" alt = "dev" > </a >

1 change: 1 addition & 0 deletions Scripts/Bots/runPython_bot/bot/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
'''Run Python Code on Telegram [BOT]'''
59 changes: 59 additions & 0 deletions Scripts/Bots/runPython_bot/bot/execute_code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
'''
This module is responsible for handling the execution of python code given by the telegram user.
'''


import subprocess
from subprocess import TimeoutExpired


def run(update):
'''
This function takes an Telegram `update` object, passed by the `reply` function in runPython_bot module, and returns the result after executing update.message.text.
'''

def execute_py(code):
'''
This function takes a string of python code and executes it in a subprocess of timeout 30s, and returns the standard out and standard error.

Learn more about subprocesses from the official docs of Python
https://docs.python.org/3/library/subprocess.html

For a shorter intro read this stack overflow answer
https://stackoverflow.com/questions/64606880/how-to-get-the-python-interactive-shell-output-of-a-python-code-in-a-variable
'''

proc = subprocess.Popen(['/usr/bin/python3.8', '-c', code],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
try:
stdout, stderr = proc.communicate(timeout=30)
except TimeoutExpired:
return '', '😢 Timeout is 30s. I have limited resources. You may increase the timeout and run this bot on your own server if required.'
return stdout.decode('utf-8'), stderr.decode('utf-8')

def func(input_text):
'''
This function is a helper function which does some validation job before passing the code to execute_py.
'''

restricted_words = ['quit', 'input', 'open', 'import']
if any(word in input_text for word in restricted_words):
# block usage of this words for security and performance issues
out = f'☹️ SECURITY ISSUE: You have used a restricted word \n {restricted_words}'
return out
stdout, stderr = execute_py(input_text)
if str(stdout) or str(stderr):
out = f'{stdout} \n{stderr}'
return out
return None

input_text = update.message.text
out = func(input_text)
if not out:
try:
out = str(eval(input_text))
# if there is no output, it may be due to the fact that the code does not have print and is a python expression.
# so the bot evaluates it using eval()
except Exception as e:
out = f'''😔 If you are planning to write lines after this line then try writing them in a single message. \n**To print something, try using print function**\n Executing your code gave no stdout or stderr. \nSo I tried to evaluate it by using eval(). That raised the following error \n {e}'''
return out
75 changes: 75 additions & 0 deletions Scripts/Bots/runPython_bot/bot/runPython_bot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
'''
I'm the *Python Runner* bot 😀

I have been created by Aahnik Daw and you may see my [source code](http://bit.ly/runPython) on GitHub.

I am currently *alive and kicking* on a free tier server of Python Anywhere.

😁 Sometimes I behave quite differently from a regular python interactive shell.
Certain things are not allowed to prevent horrible consequences.

_Start using me to figure out more about me_.

Every message is executed freshly. Suppose you define a variable in one message, you wont be able to access it in the next message.

But you can write _multiline code in one message_
->Tab is 4 spaces
-> Newline is a newline in the same message body

If I am being used by too many people, there may be delay in response as I am deployed on a free tier server.
'''

# the module docstring will be sent to the user if the bot is alive

from telegram.ext import CommandHandler, MessageHandler, Filters, Updater
# python-telegram-bot is a Pythonic Wrapper to the core Telegram API
# it helps us to be DRY by giving us convinient wrapper functions to deal with Telegram API
# you can install it by pip install python-telegram-bot --upgrade
# learn more about it here https://github.com/python-telegram-bot/python-telegram-bot


from .execute_code import run

# read the token for authenticating our bot
with open('token.txt') as f:
tok = f.readline().strip()


def bot():
'''
Running this function runs the bot
You may learn more from this tutorial
https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions-%E2%80%93-Your-first-Bot
'''

updater = Updater(token=tok)

dispatcher = updater.dispatcher

def start(update, context):
'''
This fuction replies to the start command
'''

context.bot.send_message(
chat_id=update.effective_chat.id, text=f'{__doc__}\n', parse_mode='Markdown')
# for more info on parse modes see https://python-telegram-bot.readthedocs.io/en/stable/telegram.parsemode.html

def reply(update, context):
'''
This function replies to any non-command messages
'''
returned_val = run(update)
context.bot.send_message(
chat_id=update.effective_chat.id, text=returned_val)

start_handler = CommandHandler('start', start)
message_handler = MessageHandler(Filters.text & (~Filters.command), reply)

dispatcher.add_handler(start_handler)
dispatcher.add_handler(message_handler)

updater.start_polling()
# Search google to know what is polling...
# i came to know while building this project
# this can be stopped by interrupting the terminal by `Ctrl+C`
15 changes: 15 additions & 0 deletions Scripts/Bots/runPython_bot/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
APScheduler==3.6.3
autopep8==1.5.4
certifi==2020.6.20
cffi==1.14.3
cryptography==3.2.1
decorator==4.4.2
pycodestyle==2.6.0
pycparser==2.20
python-telegram-bot==13.0
pytz==2020.1
PyYAML==5.3.1
six==1.15.0
toml==0.10.1
tornado==6.0.4
tzlocal==2.1
6 changes: 6 additions & 0 deletions Scripts/Bots/runPython_bot/start.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from bot import runPython_bot
import logging

logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
runPython_bot.bot()