Skip to main content

A lightweight Flask utility library providing validation, authentication decorators, and database helpers.

Project description

Ol_Utills Logo

๐Ÿ› ๏ธ Ol_Utills

A lightweight Flask utility library for validation, authentication, and database helpers.

PyPI Version Python Versions License


โœจ Features

  • Input Validation โ€” Password, email, and phone number validation using battle-tested regex patterns.
  • Auth Decorators โ€” Drop-in @login_required and @admin_required decorators for Flask routes.
  • Database Helpers โ€” Quick-connect utilities for SQLite and PostgreSQL.
  • Zero Config โ€” Works out of the box with any Flask app.

๐Ÿ—๏ธ Architecture Overview

graph LR
    A["๐Ÿ› ๏ธ Ol_Utills"] --> B["๐Ÿ”’ val"]
    A --> C["๐Ÿ›ก๏ธ req"]
    A --> D["๐Ÿ“ฆ res"]
    A --> E["๐Ÿ—„๏ธ database"]

    B --> B1["chk_p โ€” Password"]
    B --> B2["chk_e โ€” Email"]
    B --> B3["chk_ph โ€” Phone"]

    C --> C1["@login_required"]
    C --> C2["@admin_required"]

    D --> D1["success_response"]
    D --> D2["error_response"]

    E --> E1["SQLite"]
    E --> E2["PostgreSQL"]

    style A fill:#4f46e5,stroke:#4338ca,color:#fff
    style B fill:#0891b2,stroke:#0e7490,color:#fff
    style C fill:#059669,stroke:#047857,color:#fff
    style D fill:#d97706,stroke:#b45309,color:#fff
    style E fill:#7c3aed,stroke:#6d28d9,color:#fff

๐Ÿ“ฆ Installation

pip install ol-utills

Requirements

Dependency Purpose
flask Session management & JSON responses
psycopg2 PostgreSQL connectivity

Note: sqlite3 and re are part of the Python standard library and do not need to be installed.

Supported Python Versions

  • Python 3.8 and above

๐Ÿš€ Quick Start

from Ol_Utills import val, req, database

# Validate an email
if val.chk_e("user@example.com"):
    print("Valid email!")

# Connect to a SQLite database
db = database.sqlite("app.db")
db.execute("SELECT * FROM users")

๐Ÿ“– Detailed Documentation

Table of Contents

  1. val โ€” Validation
  2. req โ€” Authentication Decorators
  3. res โ€” Response Helpers
  4. database โ€” Database Connections
  5. Full Flask App Example

val โ€” Validation

The val class provides static methods for validating common user inputs using regular expressions. All methods return True on success and None on failure, making them easy to use in conditional checks.

flowchart LR
    Input["๐Ÿ“ฅ User Input"] --> Val{"val method"}
    Val -->|"chk_p"| P["Password Regex"]
    Val -->|"chk_e"| E["Email Regex"]
    Val -->|"chk_ph"| Ph["Phone Regex"]
    P --> Result{"Match?"}
    E --> Result
    Ph --> Result
    Result -->|"โœ… Yes"| True["Returns True"]
    Result -->|"โŒ No"| None["Returns None"]

    style Input fill:#f8fafc,stroke:#94a3b8,color:#334155
    style True fill:#22c55e,stroke:#16a34a,color:#fff
    style None fill:#ef4444,stroke:#dc2626,color:#fff

val.chk_p(password)

Validates password strength against a robust regex pattern.

Details
Parameter password (str) โ€” The password string to validate
Returns True if valid, None if invalid

Password Rules:

The password must satisfy all of the following criteria:

  • โœ… Minimum 7 characters long (6 + 1 trailing non-whitespace)
  • โœ… At least 1 uppercase letter (A-Z)
  • โœ… At least 1 lowercase letter (a-z)
  • โœ… At least 1 digit (0-9)
  • โœ… Must not contain whitespace
  • โœ… The last character must be a non-whitespace character

Note: Special characters (e.g. @, #, !) are allowed but not required.

Examples:

from Ol_Utills import val

# โœ… Valid passwords
val.chk_p("MyP@ss1234")    # True โ€” uppercase, lowercase, digit, special char
val.chk_p("Hello1x")        # True โ€” meets all minimum criteria
val.chk_p("Abcdef1")        # True โ€” exactly 7 chars, has upper, lower, digit

# โŒ Invalid passwords
val.chk_p("weak")            # None โ€” too short, no uppercase, no digit
val.chk_p("alllowercase1")  # None โ€” no uppercase letter
val.chk_p("ALLUPPERCASE1")  # None โ€” no lowercase letter
val.chk_p("NoDigits!")       # None โ€” no digit
val.chk_p("Ab1")             # None โ€” too short

Usage in a Flask route:

from flask import Flask, request, jsonify
from Ol_Utills import val

app = Flask(__name__)

@app.route('/register', methods=['POST'])
def register():
    password = request.form.get('password')
    
    if not val.chk_p(password):
        return jsonify({
            "error": "Password must be 7+ chars with at least 1 uppercase, 1 lowercase, and 1 digit."
        }), 400
    
    # Proceed with registration...
    return jsonify({"message": "Registration successful"}), 201

val.chk_e(email)

Validates an email address against the RFC 2822 specification using a comprehensive regex pattern.

Details
Parameter email (str) โ€” The email address string to validate
Returns True if valid, None if invalid

Validation Covers:

  • โœ… Standard emails: user@example.com
  • โœ… Subdomains: user@mail.example.com
  • โœ… Plus addressing: user+tag@example.com
  • โœ… Dots in local part: first.last@example.com
  • โœ… Quoted strings: "unusual@chars"@example.com
  • โŒ Missing @ symbol
  • โŒ Missing domain
  • โŒ Spaces in unquoted local parts
  • โŒ Control characters

Examples:

from Ol_Utills import val

# โœ… Valid emails
val.chk_e("user@example.com")          # True
val.chk_e("first.last@company.co.uk")  # True
val.chk_e("user+filter@gmail.com")     # True
val.chk_e("admin@192.168.1.1")         # True

# โŒ Invalid emails
val.chk_e("not-an-email")              # None โ€” no @ symbol
val.chk_e("@missing-local.com")        # None โ€” no local part
val.chk_e("spaces in@email.com")       # None โ€” spaces not allowed
val.chk_e("")                           # None โ€” empty string

val.chk_ph(phone)

Validates international phone numbers.

Details
Parameter phone (str) โ€” The phone number string to validate
Returns True if valid, None if invalid

Supported Formats:

  • โœ… International: +1-555-555-5555
  • โœ… With parentheses: (555) 555-5555
  • โœ… With dots: 555.555.5555
  • โœ… With spaces: +44 20 7946 0958
  • โœ… Plain digits: 5555555555

Examples:

from Ol_Utills import val

val.chk_ph("+1-800-555-0199")    # True
val.chk_ph("(555) 123-4567")     # True
val.chk_ph("+44 20 7946 0958")   # True

req โ€” Authentication Decorators

The req class provides Flask route decorators for session-based authentication. These decorators wrap your view functions and check the Flask session object before allowing access.

How It Works:

flowchart TD
    A["๐ŸŒ Client Request"] --> B["Flask Route"]
    B --> C{"Decorator Check"}
    
    C -->|"@login_required"| D{"session logged == True?"}
    C -->|"@admin_required"| E{"session admin == True?"}
    
    D -->|"โœ… Yes"| F["โœ… Execute View Function"]
    D -->|"โŒ No"| G["๐Ÿšซ Return empty jsonify response"]
    
    E -->|"โœ… Yes"| F
    E -->|"โŒ No"| G

    F --> H["๐Ÿ“ค Return Response to Client"]
    G --> H

    style A fill:#f8fafc,stroke:#94a3b8,color:#334155
    style F fill:#22c55e,stroke:#16a34a,color:#fff
    style G fill:#ef4444,stroke:#dc2626,color:#fff
    style H fill:#3b82f6,stroke:#2563eb,color:#fff

@req.login_required

Restricts a Flask route to authenticated (logged-in) users only.

Details
Session Key session['logged']
Required Value True (boolean)
On Success Executes the decorated view function normally
On Failure Returns an empty JSON response via jsonify()

Prerequisites:

You must set session['logged'] = True somewhere in your login logic (e.g., after verifying credentials).

Example:

from flask import Flask, session, request, jsonify
from Ol_Utills import req

app = Flask(__name__)
app.secret_key = 'your-secret-key'

# Login route โ€” sets session
@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('username')
    password = request.form.get('password')
    
    # ... verify credentials against database ...
    
    session['logged'] = True         # โ† Required for @login_required
    session['username'] = username   # โ† Optional: store user info
    return jsonify({"message": "Logged in successfully"})

# Protected route โ€” requires login
@app.route('/dashboard')
@req.login_required
def dashboard():
    return jsonify({"message": "Welcome to your dashboard"})

# Logout route โ€” clears session
@app.route('/logout')
def logout():
    session.pop('logged', None)
    return jsonify({"message": "Logged out"})

Behavior:

Scenario session['logged'] Result
User is logged in True View function runs normally
User is not logged in Missing or False Returns empty jsonify() response
Session expired Missing Returns empty jsonify() response

@req.admin_required

Restricts a Flask route to admin users only. Works the same as @login_required but checks a different session key.

Details
Session Key session['admin']
Required Value True (boolean)
On Success Executes the decorated view function normally
On Failure Returns an empty JSON response via jsonify()

Example:

# Admin login โ€” sets admin session
@app.route('/admin/login', methods=['POST'])
def admin_login():
    # ... verify admin credentials ...
    
    session['logged'] = True    # for general auth
    session['admin'] = True     # โ† Required for @admin_required
    return jsonify({"message": "Admin logged in"})

# Admin-only route
@app.route('/admin/users')
@req.admin_required
def manage_users():
    return jsonify({"users": ["user1", "user2", "user3"]})

Stacking Decorators:

You can combine both decorators for routes that require login and admin access:

@app.route('/admin/settings')
@req.login_required
@req.admin_required
def admin_settings():
    return jsonify({"settings": "..."})

Tip: When stacking, @req.login_required should be the outermost decorator (listed first) so the login check runs before the admin check.


res โ€” Response Helpers

๐Ÿ”œ Coming Soon โ€” This module is under active development.

The res class will provide utilities for building standardized JSON API responses.

Method Description Status
res.success_response(data) Returns a standardized success JSON response ๐Ÿ”œ Planned
res.error_response(message, code) Returns a standardized error JSON response ๐Ÿ”œ Planned

Planned usage:

from Ol_Utills import res

# Success response
return res.success_response({"user": "john"})
# Expected: {"status": "success", "data": {"user": "john"}}

# Error response
return res.error_response("Not found", 404)
# Expected: {"status": "error", "message": "Not found"}, 404

database โ€” Database Connections

The database class provides quick-connect helper functions for database setup. Each method opens a connection and returns a cursor object ready for executing queries.

flowchart LR
    App["๐Ÿ Flask App"] --> DB{"database helper"}

    DB -->|".sqlite"| SQ["๐Ÿ“ SQLite File"]
    DB -->|".postgresql"| PG["๐Ÿ˜ PostgreSQL Server"]

    SQ --> SQC["sqlite3.connect"]
    PG --> PGC["psycopg2.connect"]

    SQC --> Cursor["๐Ÿ“‹ Cursor"]
    PGC --> Cursor

    Cursor --> Ops["execute / fetchall / fetchone"]

    style App fill:#f8fafc,stroke:#94a3b8,color:#334155
    style SQ fill:#0891b2,stroke:#0e7490,color:#fff
    style PG fill:#4f46e5,stroke:#4338ca,color:#fff
    style Cursor fill:#22c55e,stroke:#16a34a,color:#fff

database.sqlite(database)

Opens a connection to a SQLite database file and returns a cursor.

Details
Parameter database (str) โ€” Path to the SQLite database file. If the file doesn't exist, SQLite will create it automatically.
Returns sqlite3.Cursor โ€” A cursor object for executing SQL queries

Examples:

from Ol_Utills import database

# Connect to (or create) a database
db = database.sqlite("app.db")

# Create a table
db.execute("""
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        username TEXT NOT NULL UNIQUE,
        email TEXT NOT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    )
""")

# Insert a record
db.execute(
    "INSERT INTO users (username, email) VALUES (?, ?)",
    ("john_doe", "john@example.com")
)
db.connection.commit()  # Don't forget to commit!

# Query records
db.execute("SELECT * FROM users")
users = db.fetchall()
for user in users:
    print(user)

# Query a single record
db.execute("SELECT * FROM users WHERE username = ?", ("john_doe",))
user = db.fetchone()

Use with Flask:

from flask import Flask, g
from Ol_Utills import database

app = Flask(__name__)

def get_db():
    if 'db' not in g:
        g.db = database.sqlite("app.db")
    return g.db

@app.route('/users')
def list_users():
    db = get_db()
    db.execute("SELECT * FROM users")
    return jsonify(db.fetchall())

database.postgresql(database, user, password, host)

Opens a connection to a PostgreSQL database and returns a cursor.

Details
Parameters
database (str) Name of the PostgreSQL database
user (str) Database username
password (str) Database password
host (str) Database host address (e.g. "localhost", "db.example.com")
Returns psycopg2.cursor โ€” A cursor object for executing SQL queries
Requires psycopg2 package (pip install psycopg2-binary)

Examples:

from Ol_Utills import database

# Connect to PostgreSQL
db = database.postgresql(
    database="myapp",
    user="admin",
    password="secure_password",
    host="localhost"
)

# Create a table
db.execute("""
    CREATE TABLE IF NOT EXISTS products (
        id SERIAL PRIMARY KEY,
        name VARCHAR(100) NOT NULL,
        price DECIMAL(10, 2),
        in_stock BOOLEAN DEFAULT TRUE
    )
""")
db.connection.commit()

# Insert a record
db.execute(
    "INSERT INTO products (name, price) VALUES (%s, %s)",
    ("Widget", 19.99)
)
db.connection.commit()

# Query records
db.execute("SELECT * FROM products WHERE in_stock = %s", (True,))
products = db.fetchall()

Important: PostgreSQL uses %s for parameter placeholders, while SQLite uses ?.


๐Ÿ”ง Full Flask App Example

A complete example showing all library features working together:

sequenceDiagram
    participant C as ๐ŸŒ Client
    participant F as ๐Ÿ Flask App
    participant V as ๐Ÿ”’ val
    participant D as ๐Ÿ—„๏ธ database
    participant S as ๐Ÿ›ก๏ธ session

    Note over C,S: Registration Flow
    C->>F: POST /register
    F->>V: val.chk_e(email)
    V-->>F: True / None
    F->>V: val.chk_p(password)
    V-->>F: True / None
    F->>D: database.sqlite("app.db")
    D-->>F: cursor
    F->>D: INSERT INTO users
    F-->>C: 201 Created

    Note over C,S: Login Flow
    C->>F: POST /login
    F->>D: SELECT FROM users
    D-->>F: user record
    F->>S: session["logged"] = True
    F-->>C: Login successful

    Note over C,S: Protected Route
    C->>F: GET /dashboard
    F->>S: Check session["logged"]
    S-->>F: True โœ…
    F-->>C: Dashboard data
from flask import Flask, session, request, jsonify
from Ol_Utills import val, req, database

app = Flask(__name__)
app.secret_key = 'your-secret-key-here'

# Initialize database
db = database.sqlite("app.db")
db.execute("""
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        username TEXT UNIQUE,
        email TEXT,
        password TEXT,
        is_admin BOOLEAN DEFAULT 0
    )
""")
db.connection.commit()


@app.route('/register', methods=['POST'])
def register():
    email = request.form.get('email')
    password = request.form.get('password')
    username = request.form.get('username')

    # Validate email
    if not val.chk_e(email):
        return jsonify({"error": "Invalid email format"}), 400

    # Validate password strength
    if not val.chk_p(password):
        return jsonify({
            "error": "Password must be 7+ chars with uppercase, lowercase, and a digit"
        }), 400

    # Insert user into database
    db = database.sqlite("app.db")
    try:
        db.execute(
            "INSERT INTO users (username, email, password) VALUES (?, ?, ?)",
            (username, email, password)
        )
        db.connection.commit()
    except Exception as e:
        return jsonify({"error": str(e)}), 500

    return jsonify({"message": "User registered successfully"}), 201


@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('username')
    password = request.form.get('password')

    db = database.sqlite("app.db")
    db.execute(
        "SELECT * FROM users WHERE username = ? AND password = ?",
        (username, password)
    )
    user = db.fetchone()

    if user:
        session['logged'] = True
        session['username'] = username
        if user[4]:  # is_admin column
            session['admin'] = True
        return jsonify({"message": "Login successful"})

    return jsonify({"error": "Invalid credentials"}), 401


@app.route('/dashboard')
@req.login_required
def dashboard():
    return jsonify({
        "message": f"Welcome, {session.get('username')}!",
        "role": "admin" if session.get('admin') else "user"
    })


@app.route('/admin/panel')
@req.admin_required
def admin_panel():
    db = database.sqlite("app.db")
    db.execute("SELECT id, username, email FROM users")
    users = db.fetchall()
    return jsonify({"users": users})


@app.route('/logout')
def logout():
    session.clear()
    return jsonify({"message": "Logged out"})


if __name__ == '__main__':
    app.run(debug=True)

๐Ÿงช Running Tests

cd tests
python test.py

๐Ÿค Contributing

Contributions are welcome! Here's how to get started:

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

๐Ÿ“„ License

Distributed under the MIT License. See LICENSE for more information.


Made with โค๏ธ by OverLimit (OL)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ol_utills-0.6.1.tar.gz (9.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ol_utills-0.6.1-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

Details for the file ol_utills-0.6.1.tar.gz.

File metadata

  • Download URL: ol_utills-0.6.1.tar.gz
  • Upload date:
  • Size: 9.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ol_utills-0.6.1.tar.gz
Algorithm Hash digest
SHA256 0467a7f7da626463764060aaad939bebc849a57c01103c35f3369170a22d1afe
MD5 026b7666348e349c35402026a7690b23
BLAKE2b-256 3fade0b94ee3ecf441528b70bda13e880ea17a63bd41672ea8aec0bcd3116bf5

See more details on using hashes here.

Provenance

The following attestation bundles were made for ol_utills-0.6.1.tar.gz:

Publisher: publish.yml on OverLimit-OL/Ol_Utills

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ol_utills-0.6.1-py3-none-any.whl.

File metadata

  • Download URL: ol_utills-0.6.1-py3-none-any.whl
  • Upload date:
  • Size: 9.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ol_utills-0.6.1-py3-none-any.whl
Algorithm Hash digest
SHA256 62b16907f5a5834544fd506e039c2f86eb84e138d14858784209c2a0e1770d61
MD5 db3b8307746a126446399fa112b7458a
BLAKE2b-256 37e77b7ba7b724cf5df42ab231afe9f7b5e346fcb97b23fd1dbba9828ef6b5e4

See more details on using hashes here.

Provenance

The following attestation bundles were made for ol_utills-0.6.1-py3-none-any.whl:

Publisher: publish.yml on OverLimit-OL/Ol_Utills

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page