Package: x-bot
xbotxbot(read cross-bot), is a code generation tool for translating messaging bots from one platform to another.pip install x-botAbstractProblem: I built my bot in X (e.g. Telegram) and now I want to have it also in Y (Discord) and Z (Slack).Solution: xbot takes your code for X and generates automatically code for Y and Z, afterward you can still test it and edit it as you wish. xbot does only the boilerplate part, is up to you what you do with it.Why not having a multiplatform bot?There are some solution there around multiplatform bot, but different messaging platform offer different features, e.g. in Telegram you can have rich bot UI and in Discord you can display a "Bot is typing" message. More then that you might want to have different deployment strategies for different bot, so with we don't want to force any opinion around what you do with your code.UsageDecorate functions you want to translate with@xbot.xfunctiondefmy_telegram_bot_function(telegram_arguments):And then generate translated python code (statically) withpython-mxbotmy_telegram_bot.py--frompython-telegram-bot--todiscord.pywherepython-telegram-botis the wrapper you are using to write your Telegram bot, anddiscord.pyis the wrapper you are translating to.You will now will have a generated code file atgen__xbot.pywith the transated runnable code. You are free to do what you want with it!ExampleYou can see an example of a real translation in thetestsfolder where we translate from anorginal_code.py(that runs in Telegram) to antranslated_code__expected.py(that runs in Discord).To view it your self you can just run the tests to assert that the generated code (insidegen__xbot.py) is identical to the expected code.python -m pytest testsIf the button is green, it means the test above is passing.How does it workxbot is built around the concept that different bot APIs wrappers pretty much works the same way just with different syntax. Here is an example withpython-telegram-bot(A) anddiscord.py(B).# python-telegram-bot, (A)defadd(update,context):"""Add two numbers together."""try:message=update.message.text_,left,right=message.split(" ")result=int(left)+int(right)update.message.reply_text(result)except(IndexError,ValueError):update.message.reply_text('Usage: /add <left> <right>')# discord.py, (B)@bot.command(name='add')asyncdefadd(ctx):"""Adds two numbers together."""try:message=ctx.message.content_,left,right=message.split(" ")result=int(left)+int(right)awaitctx.send(result)except(IndexError,ValueError):awaitctx.send('Usage: /add <left> <right>')There is a bunch of differences with the two wrappers, but they practically do the same job.(A) is sync, (B) is async(A) uses plain handlers, (B) uses decorators(A) sends a message withupdate.message.reply_text, (B) withawait ctx.sendNOTE: we are not using the two wrapper in the most idiomatic way we could, but both exampls are still reasonable real-life working examples.So how can we effectively translate from (A) to (B)? We can use aJinja2 templateto generate (B)# discord.py, (B)# xbot TEMPLATE@bot.command(name='{{function_name}}')asyncdef{{function_name}}(ctx):"""{{function_docstring}}"""{{body.replace('update.message.text','ctx.message.content')}}This basic template we can easily generate the original (B) code.Given that template we just need to parse (A) (we can use itwalking the ASTfor example) to get the values like function name, arguments and body and then just pass them to (B).ContributingTo add a new translation platform this is the checklistadd aTEMPLATEfor you library atxbot/templates/WRAPPER_NAME/reply.py(to see the full lists of templates and libraries checkxbot/constants.py)add aDICTIONARYinxbot/parsers/WRAPPER_NAME/dictionary.py(that maps to theMetaDictionaryinxbot/templates.py)[optional] add aPARSERif you want to translate from your platform to another platform inxbot/parsers/WRAPPER_NAME/parser.py. You can pretty much use all the functions insidexbot/parsers/telegram/parser.py