Creating a Simple Pastebin Service in Python and Flask

mraza007

Muhammad

Posted on July 8, 2024

Creating a Simple Pastebin Service in Python and Flask

In this blog post, we will be building a simple Pastebin service using Python and Flask. Pastebin is a popular web application used to store plain text or code snippets for a certain period of time. We'll create a basic version that allows users to paste text, select the programming language, and get a URL to share the paste. I have also created a YouTube video about this, which you can view here.

Getting Starting

Before begin creating our application lets setup our environment and in order to setup your environment follow these steps:

  1. First, Let's create a virtual environment in the project directory.
python -m venv venv
Enter fullscreen mode Exit fullscreen mode
  1. Now, once we have created the virtual environment, let's activate it and install all the required libraries that are going to be used by this project.
pip install Flask shortuuid pygments
Enter fullscreen mode Exit fullscreen mode

We'll also use shortuuid for generating unique IDs for each paste and pygments for syntax highlighting.

  1. Now that we have installed all the required libraries, let's create the necessary files and folders.
mkdir -p pastes templates static && touch index.py templates/index.html static/styles.css
Enter fullscreen mode Exit fullscreen mode

This is how your folder structure should look:

pastebin/
│
├── app.py
├── pastes/
├── templates/
│   └── index.html
└── static/
    └── styles.css

Enter fullscreen mode Exit fullscreen mode

The pastes directory will store the text files for each paste. The templates directory contains our HTML templates, and the static directory contains CSS for styling.

Now that we have set up the environment, it's time to code.

Writing Code

Let's dive into the code. Create a file named index.py and add the following code:

from flask import Flask, request, render_template, abort
import shortuuid
import os
from pygments import highlight
from pygments.lexers import get_lexer_by_name, get_all_lexers
from pygments.formatters import HtmlFormatter

app = Flask(__name__)

# Directory to store paste files
PASTE_DIR = 'pastes'
if not os.path.exists(PASTE_DIR):
    os.makedirs(PASTE_DIR)

# Function to get available programming languages for syntax highlighting
def get_language_options():
    return sorted([(lexer[1][0], lexer[0]) for lexer in get_all_lexers() if lexer[1]])

# Route for the main page
@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        # Get content and language from the form
        content = request.form['content']
        language = request.form['language']
        # Generate a unique ID for the paste
        paste_id = shortuuid.uuid()
        # Create the file path for the paste
        file_path = os.path.join(PASTE_DIR, paste_id)

        # Save the paste content to a file
        with open(file_path, 'w') as f:
            f.write(f"{language}\n{content}")

        # Generate the URL for the new paste
        paste_url = request.url_root + paste_id
        return render_template('index.html', paste_url=paste_url, languages=get_language_options())

    # Render the form with available languages
    return render_template('index.html', languages=get_language_options())

# Route to view a specific paste by its ID
@app.route('/<paste_id>')
def view_paste(paste_id):
    # Create the file path for the paste
    file_path = os.path.join(PASTE_DIR, paste_id)
    if not os.path.exists(file_path):
        abort(404)  # Return a 404 error if the paste does not exist

    # Read the paste file
    with open(file_path, 'r') as f:
        language = f.readline().strip()  # First line is the language
        content = f.read()  # Remaining content is the paste

    # Get the appropriate lexer for syntax highlighting
    lexer = get_lexer_by_name(language, stripall=True)
    # Create a formatter for HTML output
    formatter = HtmlFormatter(linenos=True, cssclass="source")
    # Highlight the content
    highlighted_content = highlight(content, lexer, formatter)
    # Get the CSS for the highlighted content
    highlight_css = formatter.get_style_defs('.source')

    # Render the paste with syntax highlighting
    return render_template('index.html', paste_content=highlighted_content, highlight_css=highlight_css)

if __name__ == '__main__':
    app.run(debug=True)
Enter fullscreen mode Exit fullscreen mode

Once you have created the flask now let's create html template in templates/index.html and style.css in static/style.css

  • templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Pastebin Service</title>
    <link rel="stylesheet" href="{{ url_for(\'static\', filename=\'styles.css\') }}">
    {% if highlight_css %}
    <style>
        {{ highlight_css|safe }}
    </style>
    {% endif %}
</head>
<body>
    <h1>Pastebin Service</h1>
    {% if paste_url %}
        <p>Your paste URL: <a href="{{ paste_url }}">{{ paste_url }}</a></p>
    {% endif %}
    {% if paste_content %}
        <div class="highlight">
            {{ paste_content|safe }}
        </div>
    {% endif %}
    <form method="post">
        <textarea name="content" rows="10" cols="50" placeholder="Paste your text here..."></textarea><br>
        <select name="language">
            {% for code, name in languages %}
                <option value="{{ code }}">{{ name }}</option>
            {% endfor %}
        </select><br>
        <button type="submit">Submit</button>
    </form>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode
  • static/style.css
body {
    font-family: Arial, sans-serif;
    margin: 20px;
}

h1 {
    color: #333;
}

textarea {
    width: 100%;
    margin-top: 10px;
}

select, button {
    margin-top: 10px;
}

.highlight {
    background-color: #f5f5f5;
    padding: 10px;
    border: 1px solid #ccc;
    margin-top: 20px;
}
Enter fullscreen mode Exit fullscreen mode

Now that we have created our application, before we run it, let's try to understand how it works by breaking down the code.

Code Breakdown

  1. First, we import the necessary libraries and modules. Flask is our web framework, shortuuid is used for generating unique IDs, and Pygments is for syntax highlighting. We also set up a directory to store our pastes/.
from flask import Flask, request, render_template, abort
import shortuuid
import os
from pygments import highlight
from pygments.lexers import get_lexer_by_name, get_all_lexers
from pygments.formatters import HtmlFormatter

app = Flask(__name__)

PASTE_DIR = 'pastes'
if not os.path.exists(PASTE_DIR):
    os.makedirs(PASTE_DIR)
Enter fullscreen mode Exit fullscreen mode
  1. Then we write a function that retrieves all available programming languages supported by Pygments for syntax highlighting and returns them as a sorted list of tuples.
def get_language_options():
    return sorted([(lexer[1][0], lexer[0]) for lexer in get_all_lexers() if lexer[1]])
Enter fullscreen mode Exit fullscreen mode
  1. Then we write the main route for our application. If the request method is POST (i.e., when the user submits a form), it saves the content and language to a new file with a unique ID. The URL for the new paste is generated and displayed to the user. If the request method is GET, it simply renders the form.
@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        content = request.form['content']
        language = request.form['language']
        paste_id = shortuuid.uuid()
        file_path = os.path.join(PASTE_DIR, paste_id)

        with open(file_path, 'w') as f:
            f.write(f"{language}\n{content}")

        paste_url = request.url_root + paste_id
        return render_template('index.html', paste_url=paste_url, languages=get_language_options())

    return render_template('index.html', languages=get_language_options())

Enter fullscreen mode Exit fullscreen mode

This route handles viewing a specific paste. It reads the paste file, applies syntax highlighting using pygments, and renders the highlighted content.

@app.route('/<paste_id>')
def view_paste(paste_id):
    file_path = os.path.join(PASTE_DIR, paste_id)
    if not os.path.exists(file_path):
        abort(404)

    with open(file_path, 'r') as f:
        language = f.readline().strip()
        content = f.read()

    lexer = get_lexer_by_name(language, stripall=True)
    formatter = HtmlFormatter(linenos=True, cssclass="source")
    highlighted_content = highlight(content, lexer, formatter)
    highlight_css = formatter.get_style_defs('.source')

    return render_template('index.html', paste_content=highlighted_content, highlight_css=highlight_css)

Enter fullscreen mode Exit fullscreen mode

Now once we understand how everything works, now you can simply run the application using this command
python index.py

Conclusion

You've built a simple Pastebin service using Python and Flask! This service allows users to paste text, select a programming language, and share the paste via a unique URL. You can expand this project by adding features like expiration times for pastes, user authentication, or even a database to store pastes more efficiently.

If you have any feedback, please feel free to leave a comment below. If you prefer not to comment publicly, you can always send me an email.

ORIGINALLY POSTED HERE

💖 💪 🙅 🚩
mraza007
Muhammad

Posted on July 8, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related