Pyrun: Execute Python inside your Twitter, Facebook, Linkedin

Pyrun
Extracts data from tweets and runs Python code inside Twitter

Stack: Typescript, React, Browser Extension, Pyodide

Running Python inside Twitter with a single click

👨🏻‍💻 Pyrun integrates a small IDE window in your feed, so you can execute Python code with a single button!

🤔 Why execute Python inside Twitter?

At this point probably you might know I'm a huge fan of making learning interactive and engaging.

That's how my brain works. I see then I try then I understand.

I believe that shallow consumption without action prevents us from learning. Reading without practice is not good enough.

Here's where this extension comes in, I frequently write tweets that teach some Python:

👤 Who's this for?

It's for content creators who believe talk is cheap and want to improve their engagement with their audience.

It's for the avid learners who want to execute, edit and feel the code!

Pyrun Working Demo

✍️ I'm a creator, how can I produce Python tweets that my audience can execute?

💁‍♂️ Easy:

  • Post an image from carbon, snappify, or anything else as you normally would
  • Put the raw code as your image's ALT keeping all white spaces, comments, etc.
  • When posting make sure to include the #pyrun tag anywhere in your tweet

That's it. People who don't use the extension can still consume your content as before (static boring images), and extension users can now EXECUTE IT!

🧐 How to run Python inside other pages?

The proposal is simple:

Tweets and Posts teaching Python can be executed with a single click. No installs. No manual typing.

This idea struck me randomly during a night stay in São Paulo at 4 am.

What do you do when you have a stupid idea that you don't even know if it works?

You spend the next hours trying to implement it of course!

👓 Reading the Python Code

The first challenge was: How to read the Python code?

I thought it would be easy to use OCR to read images with monospace fonts. Unfortunately, it didn't work.

The OCR tools I used had to be in Javascript since I'm injecting code into the browser. Such tools aren't built to "read code", but actual words and sentences.

So it's extremely tricky for these tools to recognize: def func: because it doesn't make much sense when read by a human.

Let's not even mention spaces, tabs, and line breaks.

The best I could do is extract code from the ALT which preserves the original content and all characters.

Tweet's ALT Example

Next I had to:

  • Find relevant tweets
  • Read image alt's

to be able to capture it.

🕵️ Getting relevant tweets

Finding the correct tweet seemed hard at first. How can I know the content (1) is about Python, (2) has code, and that (3) the image's alt is properly set?

The best approach I could do is to enforce tweets to have some specific tag #pyrun. This is both a technical limitation and a feature.

Now your audience can filter every tweet that can be executed!

I wrote an xpath query to look for:

const TARGET_TWEET_TAG = "#pyrun";
const xpath = `//a[text()='${TARGET_TWEET_TAG}']`;

I also added some simple styling to make it stand out and appended an execute button right after it.

Tweet standing out with #pyrun tag

Then it worked and it was awesome!

"I nailed it" - I thought...

Until I realized that Twitter loads tweets as you scroll. So I need to keep "listening" for new tweets to inject my code into.

Finding new tweets as you scroll

Once I figured it out it was easy.

You can notice that as you scroll some logs are being emitted counting how many tweets it finds.

It works the same for other tools:

🐍 Run Pyodide inside a Chrome Extension

This issue took me 2 months due to my lack of experience building Chrome Extensions 🙈 (Hey, better late than never).

I learned that I can't just follow Pyodide's tutorial to get it to work. It fails miserably. Installing the npm package didn't work either.

Then I decided to find who else did something similar before and I stumbled on Swindle.

Swindle is an open-source extension that allows you to run Python (powered by Pyodide) inside the DevTools.

I noticed it has its own "Pyodide bootstrap flow" and I realized I would probably have to do the same...

It was not a pleasant experience. I opened the original Pyodide's file on Github and replicated every line, recompiled, repackaged, and retested it.

It's surprising that it took me only 2 months 😅.

Then I learned that the recent Chrome manifest v3 forbids the usage of Javascript's eval inside extensions and guess what? I also found out that Pyodide uses Javascript's eval.

😮‍💨 That was a nightmare. It cost me so much to get it working and then this...

Looks like the manifest v3 requires you to run eval code inside an iframed sandbox.

That's how you can imagine it:

Main window and sandbox communicating

Effectively, that's what you can find in your DOM if you install the extension and inspect the page:

IDE and Sandbox in DOM

The <div id="pyrun-container"> holds a React rendered IDE while the <iframe id="pyrun-sandbox"> is an invisible element responsible only for listening to posted messages, executing the code, and emitting outputs back to the main window.

🧑‍💻 Editor area and Output console

It was simple to set up an editor. I just had to install react-ace.

I didn't have the same luck with the console though.

I tried many but none of them was simple enough for my needs: a styled output that I can jot many lines.

I ended up building a simple div that keeps adding lines as <p> inside. It works fine:

Output example

🧑‍💻 What about the future?

Content creators are everywhere and the Social media tools share some "common features".
They allow posts with tags and images and images with ALT.
This is enough to get this extension up and running anywhere.

Take LinkedIn as an example:

I imagine supporting more Social Media tools depending on the audience feedback.

Today this extension supports just Python, but it should be quite easy to support Javascript since it requires no setup/preparation!

Make sure to follow me on Twitter to know if any of these will ever happen.

🌟 Tips

I never built a chrome extension before. I had many challenges and wanted to develop one fast.

I abused on many different open source projects to learn how they solve similar problems.

I'm going to list some of them for reference (and also to say thanks to the maintainers!):

Manifest v3 + Sandboxes

I learned more about web3 and sandboxes by looking at how this project worked

GitHub - jorgenbuilder/chrome-dfinity-decoder: Decode responses from the Dfinity blockchain in chrome devtools
Decode responses from the Dfinity blockchain in chrome devtools - GitHub - jorgenbuilder/chrome-dfinity-decoder: Decode responses from the Dfinity blockchain in chrome devtools

Even though I couldn't take any meaningful piece of code, both projects helped me understand that I had to define a custom bootstrapping for Pyodide.

GitHub - grimmer0125/embedded-pydicom-react-viewer: Medical DICOM file P10 Viewer/Chrome Extension + Python Code In Browser (-Pyodide-> WebAssembly) + Pydicom parser + TypeScript React App (CRA). Use d4c-queue npm lib.
Medical DICOM file P10 Viewer/Chrome Extension + Python Code In Browser (-Pyodide-&gt; WebAssembly) + Pydicom parser + TypeScript React App (CRA). Use d4c-queue npm lib. - GitHub - grimmer0125/embe...
GitHub - Mario2334/swindle
Contribute to Mario2334/swindle development by creating an account on GitHub.
GitHub - alexmojaki/futurecoder: 100% free and interactive Python course for beginners
100% free and interactive Python course for beginners - GitHub - alexmojaki/futurecoder: 100% free and interactive Python course for beginners